diff options
820 files changed, 41531 insertions, 26471 deletions
diff --git a/Documentation/ABI/testing/sysfs-tty b/Documentation/ABI/testing/sysfs-tty index a2ccec35ffc..ad22fb0ee76 100644 --- a/Documentation/ABI/testing/sysfs-tty +++ b/Documentation/ABI/testing/sysfs-tty @@ -3,8 +3,7 @@ Date: Nov 2010 Contact: Kay Sievers <kay.sievers@vrfy.org> Description: Shows the list of currently configured - tty devices used for the console, - like 'tty1 ttyS0'. + console devices, like 'tty1 ttyS0'. The last entry in the file is the active device connected to /dev/console. The file supports poll() to detect virtual diff --git a/Documentation/PCI/MSI-HOWTO.txt b/Documentation/PCI/MSI-HOWTO.txt index a8d01005f48..10a93696e55 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/devicetree/bindings/arm/omap/omap.txt b/Documentation/devicetree/bindings/arm/omap/omap.txt index 34dc40cffdf..af9b4a0d902 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/dma/fsl-imx-sdma.txt b/Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt index 68b83ecc385..ee9be996152 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/net/sti-dwmac.txt b/Documentation/devicetree/bindings/net/sti-dwmac.txt new file mode 100644 index 00000000000..3dd3d0bf112 --- /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/networking/3c505.txt b/Documentation/networking/3c505.txt deleted file mode 100644 index 72f38b13101..00000000000 --- 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/MAINTAINERS b/MAINTAINERS index 9e484c081b8..c3ff6236fca 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -538,7 +538,7 @@ F: arch/alpha/ 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 @@ -1860,6 +1860,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 @@ -2408,8 +2409,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 @@ -2608,9 +2611,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.* @@ -2845,12 +2848,22 @@ 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> @@ -3324,6 +3337,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 @@ -5487,6 +5511,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> @@ -8435,8 +8464,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/ @@ -9721,7 +9750,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 @@ -1,7 +1,7 @@ VERSION = 3 PATCHLEVEL = 14 SUBLEVEL = 0 -EXTRAVERSION = -rc3 +EXTRAVERSION = -rc5 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. diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index 6d1e43d4618..032030361be 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -209,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 \ diff --git a/arch/arm/boot/dts/am335x-evmsk.dts b/arch/arm/boot/dts/am335x-evmsk.dts index 4718ec4a4db..486880b7483 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 66609684d41..9480cf891f8 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 = ð3; }; 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/dove.dtsi b/arch/arm/boot/dts/dove.dtsi index 2b76524f4aa..187fd46b7b5 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-babbage.dts b/arch/arm/boot/dts/imx51-babbage.dts index be1407cf5ab..6ff15a0eacb 100644 --- a/arch/arm/boot/dts/imx51-babbage.dts +++ b/arch/arm/boot/dts/imx51-babbage.dts @@ -21,7 +21,7 @@ reg = <0x90000000 0x20000000>; }; - display@di0 { + display0: display@di0 { compatible = "fsl,imx-parallel-display"; crtcs = <&ipu 0>; interface-pix-fmt = "rgb24"; @@ -43,7 +43,7 @@ }; }; - display@di1 { + display1: display@di1 { compatible = "fsl,imx-parallel-display"; crtcs = <&ipu 1>; interface-pix-fmt = "rgb565"; @@ -81,6 +81,12 @@ }; }; + imx-drm { + compatible = "fsl,imx-drm"; + crtcs = <&ipu 0>, <&ipu 1>; + connectors = <&display0>, <&display1>; + }; + sound { compatible = "fsl,imx51-babbage-sgtl5000", "fsl,imx-audio-sgtl5000"; diff --git a/arch/arm/boot/dts/imx53-m53evk.dts b/arch/arm/boot/dts/imx53-m53evk.dts index 7d304d02ed3..ee6107b6484 100644 --- a/arch/arm/boot/dts/imx53-m53evk.dts +++ b/arch/arm/boot/dts/imx53-m53evk.dts @@ -21,7 +21,7 @@ }; soc { - display@di1 { + display1: display@di1 { compatible = "fsl,imx-parallel-display"; crtcs = <&ipu 1>; interface-pix-fmt = "bgr666"; @@ -53,6 +53,12 @@ default-brightness-level = <6>; }; + imx-drm { + compatible = "fsl,imx-drm"; + crtcs = <&ipu 1>; + connectors = <&display1>; + }; + leds { compatible = "gpio-leds"; pinctrl-names = "default"; diff --git a/arch/arm/boot/dts/imx53-mba53.dts b/arch/arm/boot/dts/imx53-mba53.dts index a6309026794..9b6e76980a7 100644 --- a/arch/arm/boot/dts/imx53-mba53.dts +++ b/arch/arm/boot/dts/imx53-mba53.dts @@ -43,6 +43,12 @@ status = "disabled"; }; + imx-drm { + compatible = "fsl,imx-drm"; + crtcs = <&ipu 1>; + connectors = <&disp1>, <&tve>; + }; + reg_3p2v: 3p2v { compatible = "regulator-fixed"; regulator-name = "3P2V"; diff --git a/arch/arm/boot/dts/imx53-qsb.dts b/arch/arm/boot/dts/imx53-qsb.dts index 91a5935a4aa..3cb4f7791a9 100644 --- a/arch/arm/boot/dts/imx53-qsb.dts +++ b/arch/arm/boot/dts/imx53-qsb.dts @@ -21,7 +21,7 @@ reg = <0x70000000 0x40000000>; }; - display@di0 { + display0: display@di0 { compatible = "fsl,imx-parallel-display"; crtcs = <&ipu 0>; interface-pix-fmt = "rgb565"; @@ -72,6 +72,12 @@ }; }; + imx-drm { + compatible = "fsl,imx-drm"; + crtcs = <&ipu 0>; + connectors = <&display0>; + }; + leds { compatible = "gpio-leds"; pinctrl-names = "default"; diff --git a/arch/arm/boot/dts/imx6dl-hummingboard.dts b/arch/arm/boot/dts/imx6dl-hummingboard.dts index fd8fc7cd53f..5bfae54fb78 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 9e8ae118fdd..6dc39702221 100644 --- a/arch/arm/boot/dts/imx6dl.dtsi +++ b/arch/arm/boot/dts/imx6dl.dtsi @@ -88,3 +88,8 @@ crtcs = <&ipu1 0>, <&ipu1 1>; }; }; + +&hdmi { + compatible = "fsl,imx6dl-hdmi"; + crtcs = <&ipu1 0>, <&ipu1 1>; +}; diff --git a/arch/arm/boot/dts/imx6q-sabresd.dts b/arch/arm/boot/dts/imx6q-sabresd.dts index 9cbdfe7a093..66f220a82e4 100644 --- a/arch/arm/boot/dts/imx6q-sabresd.dts +++ b/arch/arm/boot/dts/imx6q-sabresd.dts @@ -20,6 +20,10 @@ compatible = "fsl,imx6q-sabresd", "fsl,imx6q"; }; +&imx_drm { + crtcs = <&ipu1 0>, <&ipu1 1>, <&ipu2 0>, <&ipu2 1>; +}; + &sata { status = "okay"; }; diff --git a/arch/arm/boot/dts/imx6q.dtsi b/arch/arm/boot/dts/imx6q.dtsi index f024ef28b34..187fe33ba51 100644 --- a/arch/arm/boot/dts/imx6q.dtsi +++ b/arch/arm/boot/dts/imx6q.dtsi @@ -159,3 +159,8 @@ crtcs = <&ipu1 0>, <&ipu1 1>, <&ipu2 0>, <&ipu2 1>; }; }; + +&hdmi { + compatible = "fsl,imx6q-hdmi"; + crtcs = <&ipu1 0>, <&ipu1 1>, <&ipu2 0>, <&ipu2 1>; +}; diff --git a/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi b/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi index 64daa3b311f..c2a24888a27 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-sabresd.dtsi b/arch/arm/boot/dts/imx6qdl-sabresd.dtsi index e75e11b36df..dfca3e00139 100644 --- a/arch/arm/boot/dts/imx6qdl-sabresd.dtsi +++ b/arch/arm/boot/dts/imx6qdl-sabresd.dtsi @@ -62,6 +62,12 @@ }; }; + imx_drm: imx-drm { + compatible = "fsl,imx-drm"; + crtcs = <&ipu1 0>, <&ipu1 1>; + connectors = <&ldb>; + }; + sound { compatible = "fsl,imx6q-sabresd-wm8962", "fsl,imx-audio-wm8962"; diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi index fb28b2ecb1d..930ebe0c293 100644 --- a/arch/arm/boot/dts/imx6qdl.dtsi +++ b/arch/arm/boot/dts/imx6qdl.dtsi @@ -1368,6 +1368,15 @@ }; }; + hdmi: hdmi@0120000 { + reg = <0x00120000 0x9000>; + interrupts = <0 115 0x04>; + gpr = <&gpr>; + clocks = <&clks 123>, <&clks 124>; + clock-names = "iahb", "isfr"; + status = "disabled"; + }; + dcic1: dcic@020e4000 { reg = <0x020e4000 0x4000>; interrupts = <0 124 0x04>; diff --git a/arch/arm/boot/dts/omap3-gta04.dts b/arch/arm/boot/dts/omap3-gta04.dts index b9b55c95a56..c551e4af4d8 100644 --- a/arch/arm/boot/dts/omap3-gta04.dts +++ b/arch/arm/boot/dts/omap3-gta04.dts @@ -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-n9.dts b/arch/arm/boot/dts/omap3-n9.dts index 39828ce464e..9938b5dc190 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 6fc85f96353..0bf40c90fab 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 b076a526b99..261c5589bfa 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 00000000000..966b5c9cd96 --- /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 7e4ad2aec37..4edc013a91c 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 00000000000..de5653e1b5c --- /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 a461d2fd1fb..597099907f8 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/tegra114.dtsi b/arch/arm/boot/dts/tegra114.dtsi index 389e987ec28..44ec401ec36 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 480ecda3416..48d2a7f4d0c 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 9104224124e..1e156d9d050 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 ed8e7700b46..19a84e933f4 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 3f123ecc9dd..00000000000 --- 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 f43907c40c9..65f65771132 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/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h index e9a49fe0284..8b8b61685a3 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/pgtable-3level.h b/arch/arm/include/asm/pgtable-3level.h index 03243f7eedd..85c60adc8b6 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 ef3c6072aa4..ac4bfae2670 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/kernel/setup.c b/arch/arm/kernel/setup.c index b0df9761de6..1e8b030dbef 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/kvm/arm.c b/arch/arm/kvm/arm.c index 1d8248ea566..bd18bb8b277 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/interrupts.S b/arch/arm/kvm/interrupts.S index ddc15539bad..0d68d407306 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/mach-imx/Makefile b/arch/arm/mach-imx/Makefile index befcaf5d057..ec419649320 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/common.h b/arch/arm/mach-imx/common.h index 59c3b9b26bb..baf439dc22d 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-omap1/board-nokia770.c b/arch/arm/mach-omap1/board-nokia770.c index 91449c5cb70..85089d82198 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 e2ce4f8366a..0af7ca02314 100644 --- a/arch/arm/mach-omap2/Kconfig +++ b/arch/arm/mach-omap2/Kconfig @@ -50,6 +50,7 @@ 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 @@ -63,6 +64,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 +74,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 +83,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 @@ -268,9 +272,6 @@ config MACH_OMAP_3430SDP default y select OMAP_PACKAGE_CBB -config MACH_NOKIA_N800 - bool - config MACH_NOKIA_N810 bool @@ -281,7 +282,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/gpmc.c b/arch/arm/mach-omap2/gpmc.c index d24926e6340..ab43755364f 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 d408b15b4fb..af432b19125 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-pxa/mioa701.c b/arch/arm/mach-pxa/mioa701.c index f70583fee59..29997bde277 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-tegra/pm.c b/arch/arm/mach-tegra/pm.c index 4ae0286b468..f55b05a29b5 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 303a285d80f..6191603379e 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/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index 1a77450e728..11b3914660d 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -1358,7 +1358,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); /* diff --git a/arch/arm/mm/mm.h b/arch/arm/mm/mm.h index d5a982d15a8..7ea641b7aa7 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 4f08c133cc2..a623cb3ad01 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 45dc29f85d5..32b3558321c 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 bd1781979a3..74f6033e76d 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/arm64/include/asm/percpu.h b/arch/arm64/include/asm/percpu.h index 13fb0b3efc5..453a179469a 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.h b/arch/arm64/include/asm/pgtable.h index b524dcd1724..aa3917c8b62 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) \ diff --git a/arch/arm64/kernel/stacktrace.c b/arch/arm64/kernel/stacktrace.c index c3b6c63ea5f..38f0558f0c0 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/kvm/hyp.S b/arch/arm64/kvm/hyp.S index 3b47c36e10f..2c56012cb2d 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/avr32/Makefile b/arch/avr32/Makefile index 22fb66590dc..dba48a5d5bb 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/fram.c b/arch/avr32/boards/mimc200/fram.c index 9764a1a1073..c1466a872b9 100644 --- a/arch/avr32/boards/mimc200/fram.c +++ b/arch/avr32/boards/mimc200/fram.c @@ -11,6 +11,7 @@ #define FRAM_VERSION "1.0" #include <linux/miscdevice.h> +#include <linux/module.h> #include <linux/proc_fs.h> #include <linux/mm.h> #include <linux/io.h> diff --git a/arch/avr32/include/asm/Kbuild b/arch/avr32/include/asm/Kbuild index cfb9fe1b8df..c7c64a63c29 100644 --- a/arch/avr32/include/asm/Kbuild +++ b/arch/avr32/include/asm/Kbuild @@ -17,5 +17,6 @@ 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 generic-y += hash.h diff --git a/arch/avr32/include/asm/io.h b/arch/avr32/include/asm/io.h index fc6483f83cc..4f5ec2bb717 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/m68k/include/asm/Kbuild b/arch/m68k/include/asm/Kbuild index 7cc8c364924..6fb9e813a91 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 @@ -18,6 +19,7 @@ generic-y += local.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 +33,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 15c5f77c161..00000000000 --- 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 014f288fc81..9d38b73989e 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 625f321001d..b932dd47004 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/syscalltable.S b/arch/m68k/kernel/syscalltable.S index 3f04ea0ab80..b6223dc41d8 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/powerpc/include/asm/compat.h b/arch/powerpc/include/asm/compat.h index 84fdf6857c3..a613d2c82fd 100644 --- a/arch/powerpc/include/asm/compat.h +++ b/arch/powerpc/include/asm/compat.h @@ -200,10 +200,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/eeh.h b/arch/powerpc/include/asm/eeh.h index 9e39ceb1d19..d4dd41fb951 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/hugetlb.h b/arch/powerpc/include/asm/hugetlb.h index d750336b171..623f2971ce0 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/opal.h b/arch/powerpc/include/asm/opal.h index 40157e2ca69..ed82142a325 100644 --- a/arch/powerpc/include/asm/opal.h +++ b/arch/powerpc/include/asm/opal.h @@ -816,8 +816,8 @@ 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); diff --git a/arch/powerpc/include/asm/pgtable-ppc64.h b/arch/powerpc/include/asm/pgtable-ppc64.h index bc141c950b1..eb9261024f5 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 f83b6f3e1b3..3ebb188c3ff 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/ptrace.h b/arch/powerpc/include/asm/ptrace.h index becc08e6a65..279b80f3bb2 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/vdso.h b/arch/powerpc/include/asm/vdso.h index 0d9cecddf8a..c53f5f6d176 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/crash_dump.c b/arch/powerpc/kernel/crash_dump.c index 11c1d069d92..7a13f378ca2 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/eeh.c b/arch/powerpc/kernel/eeh.c index 148db72a8c4..e7b76a6bf15 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/ftrace.c b/arch/powerpc/kernel/ftrace.c index 9b27b293a92..b0ded97ee4e 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); diff --git a/arch/powerpc/kernel/misc_32.S b/arch/powerpc/kernel/misc_32.S index 879f09620f8..7c6bb4b17b4 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/signal_64.c b/arch/powerpc/kernel/signal_64.c index e35bf773df7..8d253c29649 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/vdso32/vdso32_wrapper.S b/arch/powerpc/kernel/vdso32/vdso32_wrapper.S index 79683d0393f..6ac107ac402 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/vdso64_wrapper.S b/arch/powerpc/kernel/vdso64/vdso64_wrapper.S index 8df9e246300..df60fca6a13 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/mm/pgtable_64.c b/arch/powerpc/mm/pgtable_64.c index 65b7b65e870..62bf5e8e78d 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); @@ -708,7 +710,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 +837,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 a770df2dae7..6c0b1f5f8d2 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/platforms/powernv/eeh-ioda.c b/arch/powerpc/platforms/powernv/eeh-ioda.c index e1e71618b70..253fefe3d1a 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 a79fddc5e74..a59788e83b8 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-xscom.c b/arch/powerpc/platforms/powernv/opal-xscom.c index 4fbf276ac99..4cd2ea6c0db 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/pci.c b/arch/powerpc/platforms/powernv/pci.c index 95633d79ef5..8518817dcdf 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]); } } diff --git a/arch/powerpc/platforms/pseries/eeh_pseries.c b/arch/powerpc/platforms/pseries/eeh_pseries.c index 9ef3cc8ebc1..8a8f0472d98 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 82789e79e53..0ea99e3d481 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"); diff --git a/arch/powerpc/platforms/pseries/pci.c b/arch/powerpc/platforms/pseries/pci.c index 70670a2d9cf..c413ec158ff 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/s390/kernel/compat_wrapper.S b/arch/s390/kernel/compat_wrapper.S index 59c8efce1b9..0248949a756 100644 --- a/arch/s390/kernel/compat_wrapper.S +++ b/arch/s390/kernel/compat_wrapper.S @@ -1421,5 +1421,5 @@ ENTRY(sys_sched_setattr_wrapper) ENTRY(sys_sched_getattr_wrapper) lgfr %r2,%r2 # pid_t llgtr %r3,%r3 # const char __user * - llgfr %r3,%r3 # unsigned int + llgfr %r4,%r4 # unsigned int jg sys_sched_getattr diff --git a/arch/s390/pci/pci_dma.c b/arch/s390/pci/pci_dma.c index 60c11a629d9..f91c0311980 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/sparc/Kconfig b/arch/sparc/Kconfig index c51efdcd07a..7d8b7e94b93 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/mm/srmmu.c b/arch/sparc/mm/srmmu.c index 869023abe5a..cfbe53c17b0 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/x86/boot/compressed/aslr.c b/arch/x86/boot/compressed/aslr.c index 90a21f43011..4dbf967da50 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/include/asm/tsc.h b/arch/x86/include/asm/tsc.h index 57ae63cd6ee..94605c0e9ce 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/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c index b88645191fe..79f9f848bee 100644 --- a/arch/x86/kernel/cpu/perf_event.c +++ b/arch/x86/kernel/cpu/perf_event.c @@ -1192,6 +1192,9 @@ static void x86_pmu_del(struct perf_event *event, int flags) for (i = 0; i < cpuc->n_events; i++) { if (event == cpuc->event_list[i]) { + if (i >= cpuc->n_events - cpuc->n_added) + --cpuc->n_added; + if (x86_pmu.put_event_constraints) x86_pmu.put_event_constraints(cpuc, event); @@ -1521,6 +1524,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 +1539,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) @@ -1820,9 +1824,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 c1a861829d8..4972c244d0b 100644 --- a/arch/x86/kernel/cpu/perf_event.h +++ b/arch/x86/kernel/cpu/perf_event.h @@ -409,6 +409,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 0fa4f242f05..aa333d96688 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 29c248799ce..c88f7f4b03e 100644 --- a/arch/x86/kernel/cpu/perf_event_intel_uncore.c +++ b/arch/x86/kernel/cpu/perf_event_intel_uncore.c @@ -501,8 +501,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 +1181,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), diff --git a/arch/x86/kernel/cpu/perf_event_p6.c b/arch/x86/kernel/cpu/perf_event_p6.c index b1e2fe11532..7c1a0c07b60 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/machine_kexec_64.c b/arch/x86/kernel/machine_kexec_64.c index 4eabc160696..679cef0791c 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/pci-dma.c b/arch/x86/kernel/pci-dma.c index 872079a67e4..f7d0672481f 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/tsc.c b/arch/x86/kernel/tsc.c index acb3b606613..cfbe99f8883 100644 --- a/arch/x86/kernel/tsc.c +++ b/arch/x86/kernel/tsc.c @@ -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(); diff --git a/arch/x86/kernel/tsc_msr.c b/arch/x86/kernel/tsc_msr.c index 8b5434f4389..92ae6acac8a 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/kvm/mmu.c b/arch/x86/kvm/mmu.c index e50425d0f5f..9b531351a58 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; diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index a06f101ef64..39275283475 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -6688,7 +6688,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)); diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 39c28f09dfd..2b8578432d5 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -6186,7 +6186,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. */ diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig index ba56e11cbf7..c87ae7c6e5f 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 46b4f5eab42..e7370b11348 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/io.h b/arch/xtensa/include/asm/io.h index 2a042d430c2..74944207167 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 8c194f6af45..677bfcf4ee5 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 5791b45d5a5..f74ddfbb92e 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 51940fec699..b9395529f02 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 21dbe6bdb8e..ef7f4990722 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/setup.c b/arch/xtensa/kernel/setup.c index 7d12af1317f..84fe931bb60 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 08b769d3b3a..2a1823de69c 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 cb8fd44caab..f9e1ec346e3 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 74a60c7e085..80b33ed51f3 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 479d7537a32..aff108df92d 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 36ec171698b..861203e958d 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 800227862fe..57fd08b36f5 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 bf4020116df..244cdea4dee 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/drivers/acpi/ac.c b/drivers/acpi/ac.c index e7515aa43d6..6f190bc2b8b 100644 --- a/drivers/acpi/ac.c +++ b/drivers/acpi/ac.c @@ -243,6 +243,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); diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 018a4288370..797a6938d05 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -841,6 +841,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/blacklist.c b/drivers/acpi/blacklist.c index 10e4964d051..afec4526c48 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/button.c b/drivers/acpi/button.c index 11c11f6b8fa..714e957a871 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); diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index e9b3081c4fe..5bfd769fc91 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -713,13 +713,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); diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c index 1fb62900f32..09e423f3d8a 100644 --- a/drivers/acpi/fan.c +++ b/drivers/acpi/fan.c @@ -55,6 +55,9 @@ 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); +#else +#define acpi_fan_suspend NULL +#define acpi_fan_resume NULL #endif static SIMPLE_DEV_PM_OPS(acpi_fan_pm, acpi_fan_suspend, acpi_fan_resume); diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c index 52d45ea2bc4..361b40c10c3 100644 --- a/drivers/acpi/pci_irq.c +++ b/drivers/acpi/pci_irq.c @@ -430,6 +430,7 @@ int acpi_pci_irq_enable(struct pci_dev *dev) pin_name(pin)); } + kfree(entry); return 0; } diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c index 28baa05b801..84243c32e29 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, ¤t->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/sbs.c b/drivers/acpi/sbs.c index d465ae6cdd0..dbd48498b93 100644 --- a/drivers/acpi/sbs.c +++ b/drivers/acpi/sbs.c @@ -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/thermal.c b/drivers/acpi/thermal.c index 8349a555b92..08626c851be 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -102,6 +102,8 @@ MODULE_DEVICE_TABLE(acpi, thermal_device_ids); #ifdef CONFIG_PM_SLEEP static int acpi_thermal_resume(struct device *dev); +#else +#define acpi_thermal_resume NULL #endif static SIMPLE_DEV_PM_OPS(acpi_thermal_pm, NULL, acpi_thermal_resume); diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index b727d105046..b6ba88ed31a 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -81,11 +81,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 +232,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 +407,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 +457,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 +814,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 +845,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 a697b77b886..19080c8e2f2 100644 --- a/drivers/acpi/video_detect.c +++ b/drivers/acpi/video_detect.c @@ -168,22 +168,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 4e737728aee..868429a47be 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -247,6 +247,7 @@ config SATA_HIGHBANK config SATA_MV tristate "Marvell SATA support" + select GENERIC_PHY help This option enables support for the Marvell Serial ATA family. Currently supports 88SX[56]0[48][01] PCI(-X) chips, diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index dc2756fb6f3..c81d809c111 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -61,6 +61,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 +122,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 +460,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 }, @@ -1170,8 +1184,10 @@ static int ahci_init_interrupts(struct pci_dev *pdev, unsigned int n_ports, nvec = rc; rc = pci_enable_msi_block(pdev, nvec); - if (rc) + if (rc < 0) goto intx; + else if (rc > 0) + goto single_msi; return nvec; diff --git a/drivers/ata/libata-pmp.c b/drivers/ata/libata-pmp.c index 20fd337a573..7ccc084bf1d 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/pata_imx.c b/drivers/ata/pata_imx.c index 26386f0b89a..b0b18ec5465 100644 --- a/drivers/ata/pata_imx.c +++ b/drivers/ata/pata_imx.c @@ -119,7 +119,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) { @@ -212,7 +214,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/sata_mv.c b/drivers/ata/sata_mv.c index 52b8181ddaf..05c8a44adf8 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; @@ -4132,13 +4131,18 @@ static int mv_platform_probe(struct platform_device *pdev) rc = PTR_ERR(hpriv->port_phys[port]); hpriv->port_phys[port] = NULL; if (rc != -EPROBE_DEFER) - dev_warn(&pdev->dev, "error getting phy %d", - rc); + 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. */ @@ -4176,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_sil.c b/drivers/ata/sata_sil.c index d67fc351343..b7695e80463 100644 --- a/drivers/ata/sata_sil.c +++ b/drivers/ata/sata_sil.c @@ -157,6 +157,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/base/dma-buf.c b/drivers/base/dma-buf.c index 1e16cbd61da..61d6d62cc0d 100644 --- a/drivers/base/dma-buf.c +++ b/drivers/base/dma-buf.c @@ -616,36 +616,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 8a97ddfa612..c30df50e444 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c @@ -1580,6 +1580,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/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 08ca8c9f41c..cb003a6b72c 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1323,8 +1323,7 @@ static int __cpufreq_remove_dev_prepare(struct device *dev, 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) { diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index c788abf1c45..2cd36b9297f 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) { @@ -357,7 +360,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) @@ -367,6 +370,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; @@ -469,7 +479,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, }, @@ -547,18 +557,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 = div64_u64(sample->aperf * 100, sample->mperf); + 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); + + 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) @@ -570,6 +582,10 @@ static inline void intel_pstate_sample(struct cpudata *cpu) rdmsrl(MSR_IA32_MPERF, mperf); tsc = native_read_tsc(); + aperf = aperf >> FRAC_BITS; + mperf = mperf >> FRAC_BITS; + tsc = tsc >> FRAC_BITS; + cpu->sample_ptr = (cpu->sample_ptr + 1) % SAMPLE_COUNT; cpu->samples[cpu->sample_ptr].aperf = aperf; cpu->samples[cpu->sample_ptr].mperf = mperf; @@ -601,7 +617,8 @@ static inline int32_t intel_pstate_get_scaled_busy(struct cpudata *cpu) core_busy = cpu->samples[cpu->sample_ptr].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) diff --git a/drivers/cpufreq/powernow-k8.c b/drivers/cpufreq/powernow-k8.c index e10b646634d..6684e034279 100644 --- a/drivers/cpufreq/powernow-k8.c +++ b/drivers/cpufreq/powernow-k8.c @@ -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,6 +1157,7 @@ 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; @@ -1165,7 +1168,8 @@ static int powernowk8_cpu_exit(struct cpufreq_policy *pol) 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/dma/imx-sdma.c b/drivers/dma/imx-sdma.c index 4e7918339b1..19041cefabb 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 87529181efc..4e3549a1613 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 11fb877ddca..e982f00a984 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 5d3affe7e97..8d1058085ee 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 820817e97e6..b9b38a1cf92 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/ste_dma40.c b/drivers/dma/ste_dma40.c index 00a2de957b2..bf18c786ed4 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/i7300_edac.c b/drivers/edac/i7300_edac.c index d63f4798f7d..57e96a3350f 100644 --- a/drivers/edac/i7300_edac.c +++ b/drivers/edac/i7300_edac.c @@ -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, diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 87533ca7752..d871275196f 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -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) { diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c index c20602f601e..98a14f6143a 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/fmc/fmc-write-eeprom.c b/drivers/fmc/fmc-write-eeprom.c index ee5b4790413..9bb2cbd5c9f 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/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c index dffc836144c..f4dc9b7a383 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/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c index fa18cf37447..faa77f543a0 100644 --- a/drivers/gpu/drm/i2c/tda998x_drv.c +++ b/drivers/gpu/drm/i2c/tda998x_drv.c @@ -1151,8 +1151,10 @@ tda998x_encoder_init(struct i2c_client *client, priv->current_page = 0xff; priv->cec = i2c_new_dummy(client->adapter, 0x34); - if (!priv->cec) + 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/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 9fa24347963..4c167280949 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -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 2f517b85b3f..57552eb386b 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -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 diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index b7f1742caf8..31b36c5ac89 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 71a73f4fe25..0b243ce3371 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/nouveau/Makefile b/drivers/gpu/drm/nouveau/Makefile index e88145ba1bf..d310c195bdf 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 1b653dd74a7..08b88591ed6 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 940eaa5d8b9..9ad722e4e08 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 9a850fe1951..54c1b5b471c 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 30ed19c52e0..7a367c40297 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 adc88b73d91..3c6738edd12 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 aa0fbbec7f0..ef0c9c4a8cc 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 9159a5ccee9..265d1253624 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 b0d5c31606c..81a408e7d03 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 3bfee5c6c4f..cc4d0d2d886 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 00000000000..a75c35ccf25 --- /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 4ef83df2b24..83face3f608 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 488686d490c..4aed1714b9a 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 78c8e7146d5..89c484d8ac2 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); diff --git a/drivers/gpu/drm/nouveau/nouveau_vga.c b/drivers/gpu/drm/nouveau/nouveau_vga.c index 81638d7f2ef..471347edc27 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 a9338c85630..daa4dd375ab 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 a42d61571f4..2cec2ab02f8 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: diff --git a/drivers/gpu/drm/radeon/dce6_afmt.c b/drivers/gpu/drm/radeon/dce6_afmt.c index 713a5d35990..94e85875199 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 f2b9e21ce4d..8a2c010b7dc 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; } @@ -5475,9 +5475,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 0c6d5cef4cf..05b0c95813f 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/ni_dpm.c b/drivers/gpu/drm/radeon/ni_dpm.c index 1217fbcbdcc..ca814276b07 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++) { diff --git a/drivers/gpu/drm/radeon/r600_audio.c b/drivers/gpu/drm/radeon/r600_audio.c index 47fc2b88697..bffac10c429 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 3016fc14f50..85a2bb28aed 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 4a8ac1cd6b4..e887d027b6d 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_atpx_handler.c b/drivers/gpu/drm/radeon/radeon_atpx_handler.c index 485848f889f..fa9a9c02751 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_display.c b/drivers/gpu/drm/radeon/radeon_display.c index d680608f6f5..fbd8b930f2b 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_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c index 114d1672d61..2aecd6dc261 100644 --- a/drivers/gpu/drm/radeon/radeon_kms.c +++ b/drivers/gpu/drm/radeon/radeon_kms.c @@ -537,6 +537,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 +548,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 1b783f0e6d3..15e44a7281a 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 2b42aa1914f..9006b32d5ee 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_uvd.c b/drivers/gpu/drm/radeon/radeon_uvd.c index 6781fee1eaa..3e6804b2b2e 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/rv770.c b/drivers/gpu/drm/radeon/rv770.c index 6c772e58c78..4e37a42305d 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -1955,9 +1955,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 5b2ea8ac073..b5f63f5e22a 100644 --- a/drivers/gpu/drm/radeon/rv770_dpm.c +++ b/drivers/gpu/drm/radeon/rv770_dpm.c @@ -2526,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_dpm.c b/drivers/gpu/drm/radeon/si_dpm.c index eafb0e6bc67..0a2f5b4bca4 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++) { diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c index 88a529008ce..c71594754f4 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 338f7f6561d..0266fb40479 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 3302f99e749..764be36397f 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/vmwgfx/svga3d_reg.h b/drivers/gpu/drm/vmwgfx/svga3d_reg.h index b645647b777..f58dc7dd15c 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 8369c3ba10f..ef338509614 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 71defa4d2d7..11323dd5196 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 9426c53fb48..1e80152674b 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 3bdc0adc656..0083cbf99ed 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 ecaa302a615..07831554dad 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 269b85cc875..efb575a7996 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 f9881f9e62b..47b70949bf3 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 d4a5a19cb8c..04a64b8cd3c 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 2aa4bc6a4d6..9757b57f838 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 217d941b817..ee3856578a1 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/host1x/job.c b/drivers/gpu/host1x/job.c index 1146e3bba6e..112f27e51bc 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/hid-apple.c b/drivers/hid/hid-apple.c index 497558127bb..f822fd2a1ad 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 3bfac3accd2..cc32a6f96c6 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1679,6 +1679,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) }, @@ -1779,6 +1780,8 @@ 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_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) }, diff --git a/drivers/hid/hid-hyperv.c b/drivers/hid/hid-hyperv.c index 8fae6d1414c..c24908f1493 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", diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 5a5248f2cc0..22f28d6b33a 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -135,6 +135,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 +241,7 @@ #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_RADIO_SI4713 0x8244 @@ -451,6 +453,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 @@ -619,6 +624,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 +651,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 diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index d50e7313b17..a713e621141 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -1178,7 +1178,7 @@ 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; diff --git a/drivers/hid/hid-microsoft.c b/drivers/hid/hid-microsoft.c index c6ef6eed309..404a3a8a82f 100644 --- a/drivers/hid/hid-microsoft.c +++ b/drivers/hid/hid-microsoft.c @@ -208,6 +208,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 f134d73beca..221d503f1c2 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -1166,6 +1166,11 @@ static const struct hid_device_id mt_devices[] = { 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, diff --git a/drivers/hid/hid-sensor-hub.c b/drivers/hid/hid-sensor-hub.c index 46f4480035b..9c22e14c57f 100644 --- a/drivers/hid/hid-sensor-hub.c +++ b/drivers/hid/hid-sensor-hub.c @@ -665,6 +665,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/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c index d1f81f52481..42eebd14de1 100644 --- a/drivers/hid/i2c-hid/i2c-hid.c +++ b/drivers/hid/i2c-hid/i2c-hid.c @@ -582,7 +582,7 @@ static void i2c_hid_request(struct hid_device *hid, struct hid_report *rep, int ret; int len = i2c_hid_get_report_length(rep) - 2; - buf = kzalloc(len, GFP_KERNEL); + buf = hid_alloc_report_buf(rep, GFP_KERNEL); if (!buf) return; diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index 175ec0afb70..dbd83878ff9 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/hwmon/max1668.c b/drivers/hwmon/max1668.c index a7626358c95..029b65e6c58 100644 --- a/drivers/hwmon/max1668.c +++ b/drivers/hwmon/max1668.c @@ -243,7 +243,7 @@ static ssize_t set_temp_min(struct device *dev, data->temp_min[index] = clamp_val(temp/1000, -128, 127); if (i2c_smbus_write_byte_data(client, MAX1668_REG_LIML_WR(index), - data->temp_max[index])) + data->temp_min[index])) count = -EIO; mutex_unlock(&data->update_lock); diff --git a/drivers/iio/gyro/Kconfig b/drivers/iio/gyro/Kconfig index 41c64a43bca..ac2d69e34c8 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 f8f2bf84a5a..c197360c450 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 d53d91adfb5..a8e174a47bc 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 16b8b8d70bf..23c12f361b0 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 94763e25caf..b4ad3be2668 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/light/cm32181.c b/drivers/iio/light/cm32181.c index f17b4e6183c..47a6dbac2d0 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 0a142af83e2..a45e07492db 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/input/misc/arizona-haptics.c b/drivers/input/misc/arizona-haptics.c index 7a04f54ef96..ef2e281b0a4 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/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index 8911850c944..1d9ab39af29 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 d97fbe4fb9b..80fffba7f12 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/irqchip/irq-metag-ext.c b/drivers/irqchip/irq-metag-ext.c index 92c41ab4dbf..2cb474ad880 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 8e94d7a3b20..c16c186d97d 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-orion.c b/drivers/irqchip/irq-orion.c index e51d4003188..8e41be62812 100644 --- a/drivers/irqchip/irq-orion.c +++ b/drivers/irqchip/irq-orion.c @@ -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/md/dm-cache-target.c b/drivers/md/dm-cache-target.c index ffd472e015c..1af70145fab 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)); } @@ -1010,13 +1011,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); diff --git a/drivers/md/dm-io.c b/drivers/md/dm-io.c index b2b8a10e842..3842ac738f9 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-mpath.c b/drivers/md/dm-mpath.c index 6eb9dc9ef8f..422a9fdeb53 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 f284e0bfb25..7dfdb5c746d 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-thin-metadata.c b/drivers/md/dm-thin-metadata.c index 7da34766555..baa87ff1281 100644 --- a/drivers/md/dm-thin-metadata.c +++ b/drivers/md/dm-thin-metadata.c @@ -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; diff --git a/drivers/md/dm-thin-metadata.h b/drivers/md/dm-thin-metadata.h index 9a368567632..82ea384d36f 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. @@ -161,6 +159,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, diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c index faaf944597a..7e84baccf0a 100644 --- a/drivers/md/dm-thin.c +++ b/drivers/md/dm-thin.c @@ -1357,7 +1357,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)) { @@ -1999,16 +2000,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 +2029,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 +2107,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) { @@ -2287,6 +2294,7 @@ static int maybe_resize_metadata_dev(struct dm_target *ti, bool *need_commit) return -EINVAL; } else if (metadata_dev_size > sb_metadata_dev_size) { + 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); @@ -2894,6 +2902,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 +2914,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 +2935,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: diff --git a/drivers/md/persistent-data/dm-space-map-metadata.c b/drivers/md/persistent-data/dm-space-map-metadata.c index 536782e3bcb..e9bdd462f4f 100644 --- a/drivers/md/persistent-data/dm-space-map-metadata.c +++ b/drivers/md/persistent-data/dm-space-map-metadata.c @@ -680,6 +680,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; diff --git a/drivers/md/persistent-data/dm-space-map-metadata.h b/drivers/md/persistent-data/dm-space-map-metadata.h index 39bba0801cf..64df923974d 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/mfd/da9055-i2c.c b/drivers/mfd/da9055-i2c.c index 13af7e50021..8103e436213 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 ac514fb2b87..71aa14a6bfb 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 be88a3bf7b8..5adede0fb04 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 612ca404e15..5d5e186b5d8 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 a139798b806..714e2135210 100644 --- a/drivers/mfd/sec-core.c +++ b/drivers/mfd/sec-core.c @@ -315,6 +315,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 +350,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/tps65217.c b/drivers/mfd/tps65217.c index 966cf65c5c3..3cc4c7084b9 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/wm8994-core.c b/drivers/mfd/wm8994-core.c index ba04f1bc70e..e6fab94e2c8 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 6cb388e8fb7..3816b59d3e1 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -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 99b9424ce31..7eb4b69580c 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/staging/echo/Kconfig b/drivers/misc/echo/Kconfig index f1d41ea9cd4..f1d41ea9cd4 100644 --- a/drivers/staging/echo/Kconfig +++ b/drivers/misc/echo/Kconfig diff --git a/drivers/staging/echo/Makefile b/drivers/misc/echo/Makefile index 7d4caac12a8..7d4caac12a8 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 9597e9523ca..9597e9523ca 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 9b08c63e636..9b08c63e636 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 7b9fabf1fea..7b9fabf1fea 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 f4175360ce2..f4175360ce2 100644 --- a/drivers/staging/echo/oslec.h +++ b/drivers/misc/echo/oslec.h diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c index 9b809cfc289..89a557972d1 100644 --- a/drivers/misc/mei/client.c +++ b/drivers/misc/mei/client.c @@ -666,7 +666,6 @@ 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_hbm_cl_flow_control_req(dev, cl)) { @@ -678,6 +677,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); diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c index 357bbc54fe4..3e049c13429 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/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 59eba5d2c68..9715a7ba164 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 ef4190a02b7..bf642ceef68 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/ubi/fastmap.c b/drivers/mtd/ubi/fastmap.c index ead861307b3..c5dad652614 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/net/Kconfig b/drivers/net/Kconfig index f342278539d..494b888a656 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. diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c index cce1f1bf90b..6d20fbde8d4 100644 --- a/drivers/net/bonding/bond_3ad.c +++ b/drivers/net/bonding/bond_3ad.c @@ -1796,8 +1796,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 +1809,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 +1878,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; diff --git a/drivers/net/bonding/bond_3ad.h b/drivers/net/bonding/bond_3ad.h index 13dc9d3c5e3..f4dd9592ac6 100644 --- a/drivers/net/bonding/bond_3ad.h +++ b/drivers/net/bonding/bond_3ad.h @@ -253,6 +253,7 @@ struct ad_system { 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 + u16 aggregator_identifier; }; struct ad_slave_info { diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 71ba18efa15..1c6104d3501 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1543,9 +1543,11 @@ 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", @@ -1571,10 +1573,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); @@ -2864,9 +2868,12 @@ static int bond_slave_netdev_event(unsigned long event, 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); @@ -3700,7 +3707,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 diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c index 11cb943222d..c3787843271 100644 --- a/drivers/net/bonding/bond_options.c +++ b/drivers/net/bonding/bond_options.c @@ -14,7 +14,7 @@ #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> diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c index 6c859bba8b6..e77d1104974 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; } diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c index 9d7419e0390..66c0df78c3f 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c @@ -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) diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h index bfc58d488bb..a89a40f88c2 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h @@ -496,7 +496,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, diff --git a/drivers/net/ethernet/dec/tulip/tulip_core.c b/drivers/net/ethernet/dec/tulip/tulip_core.c index add05f14b38..1642de78aac 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/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index d4782b42401..903362a7b58 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -1778,8 +1778,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 +1792,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; diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 6d4ada72dfd..18076c4178b 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -6881,7 +6881,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 @@ -6907,7 +6907,7 @@ static u16 ixgbe_select_queue(struct net_device *dev, struct sk_buff *skb, 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 +6920,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 } diff --git a/drivers/net/ethernet/lantiq_etop.c b/drivers/net/ethernet/lantiq_etop.c index 8f9266c64c7..fd4b6aecf6e 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 6300fd27f2d..68e6a6613e9 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/mellanox/mlx4/en_tx.c b/drivers/net/ethernet/mellanox/mlx4/en_tx.c index 8e8a7eb43a2..13457032d15 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_tx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_tx.c @@ -629,7 +629,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 +641,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) diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h index 3af04c3f42e..9ca223bc90f 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h @@ -723,7 +723,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, diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig index e2f202e3932..f2d7c702c77 100644 --- a/drivers/net/ethernet/stmicro/stmmac/Kconfig +++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig @@ -37,6 +37,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 ecadecea79b..dcef28775da 100644 --- a/drivers/net/ethernet/stmicro/stmmac/Makefile +++ b/drivers/net/ethernet/stmicro/stmmac/Makefile @@ -2,6 +2,7 @@ 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-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/dwmac-sti.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c new file mode 100644 index 00000000000..552bbc17863 --- /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/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h index d9af26ed58e..f9e60d7918c 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h @@ -133,6 +133,9 @@ 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 extern struct platform_driver stmmac_pltfr_driver; static inline int stmmac_register_platform(void) { diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c index 5884a7d2063..c61bc72b8e9 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c @@ -33,6 +33,11 @@ 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,stih127-dwmac", .data = &sti_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/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index 1d860ce914e..651087b5c8d 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -554,7 +554,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 +578,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 +606,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, @@ -1896,6 +1896,11 @@ static int cpsw_probe_dt(struct cpsw_platform_data *data, 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", diff --git a/drivers/net/ethernet/tile/tilegx.c b/drivers/net/ethernet/tile/tilegx.c index 023237a6572..17503da9f7a 100644 --- a/drivers/net/ethernet/tile/tilegx.c +++ b/drivers/net/ethernet/tile/tilegx.c @@ -2071,7 +2071,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/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c index 1ec65feebb9..4bfdf8c7ada 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; } @@ -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/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index 7756118c2f0..7141a193736 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; } @@ -229,23 +238,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); } } @@ -388,17 +398,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,13 +442,10 @@ 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; @@ -443,8 +468,6 @@ 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"); diff --git a/drivers/net/irda/irtty-sir.c b/drivers/net/irda/irtty-sir.c index 177441afeb9..24b6dddd7f2 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/macvlan.c b/drivers/net/macvlan.c index 8433de4509c..a5d21893670 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -879,14 +879,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/phy/dp83640.c b/drivers/net/phy/dp83640.c index 9414fa27216..98e7cbf720a 100644 --- a/drivers/net/phy/dp83640.c +++ b/drivers/net/phy/dp83640.c @@ -1006,11 +1006,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; @@ -1063,6 +1058,14 @@ static void dp83640_remove(struct phy_device *phydev) 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; diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c index 28407426fd6..c8624a8235a 100644 --- a/drivers/net/team/team.c +++ b/drivers/net/team/team.c @@ -1648,7 +1648,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 diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 44c4db8450f..8fe9cb7d0f7 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; diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig index 409499fdb15..7e7269fd370 100644 --- a/drivers/net/usb/Kconfig +++ b/drivers/net/usb/Kconfig @@ -296,7 +296,6 @@ config USB_NET_SR9800 tristate "CoreChip-sz SR9800 based USB 2.0 10/100 ethernet devices" depends on USB_USBNET select CRC32 - default y ---help--- Say Y if you want to use one of the following 100Mbps USB Ethernet device based on the CoreChip-sz SR9800 chip. diff --git a/drivers/net/usb/asix_devices.c b/drivers/net/usb/asix_devices.c index 9765a7d4766..5d194093f3e 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 d6f64dad05b..955df81a435 100644 --- a/drivers/net/usb/ax88179_178a.c +++ b/drivers/net/usb/ax88179_178a.c @@ -1118,6 +1118,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); diff --git a/drivers/net/usb/gl620a.c b/drivers/net/usb/gl620a.c index e4a8a93fbaf..1cc24e6f23e 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/mcs7830.c b/drivers/net/usb/mcs7830.c index a305a7b2dae..82d844a8ebd 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 0a85d922777..4cbdb1307f3 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 ff5c87128ff..313cb6cd484 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); @@ -732,6 +732,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/rndis_host.c b/drivers/net/usb/rndis_host.c index a48bc0f20c1..524a47a2812 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 f17b9e02dd3..d9e7892262f 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 8dd54a0f7b2..424db65e439 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 index 4175eb9fdec..b94a0fbb8b3 100644 --- a/drivers/net/usb/sr9800.c +++ b/drivers/net/usb/sr9800.c @@ -63,6 +63,10 @@ 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; @@ -823,7 +827,7 @@ static int sr9800_bind(struct usbnet *dev, struct usb_interface *intf) dev->rx_urb_size = SR9800_BULKIN_SIZE[SR9800_MAX_BULKIN_2K].size; } - netdev_dbg(dev->net, "%s : setting rx_urb_size with : %ld\n", __func__, + netdev_dbg(dev->net, "%s : setting rx_urb_size with : %zu\n", __func__, dev->rx_urb_size); return 0; diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 4671da755e7..dd10d5817d2 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 diff --git a/drivers/net/wireless/ath/ath5k/phy.c b/drivers/net/wireless/ath/ath5k/phy.c index d6bc7cb61bf..1a2973b7acf 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/hostap/hostap_proc.c b/drivers/net/wireless/hostap/hostap_proc.c index aa7ad3a7a69..4e5c0f8c949 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/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/iwlwifi/dvm/mac80211.c index c24d1d3d55f..73086c1629c 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); diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c index c3728163be4..75103554cd6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/iwlwifi/iwl-drv.c @@ -1286,7 +1286,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)"); diff --git a/drivers/net/wireless/iwlwifi/iwl-modparams.h b/drivers/net/wireless/iwlwifi/iwl-modparams.h index 0a84ade7eda..b29075c3da8 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,7 +93,7 @@ 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 diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 6bf9766e598..c35b8661b39 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -328,6 +328,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, @@ -347,7 +365,7 @@ static int iwl_mvm_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(mvm->cfg)) { ret = -EINVAL; break; } @@ -357,7 +375,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; } diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index 4d79761b9c8..9d3d2758ec3 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c @@ -748,7 +748,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]; diff --git a/drivers/net/wireless/rtl818x/rtl8187/rtl8187.h b/drivers/net/wireless/rtl818x/rtl8187/rtl8187.h index 56aee067f32..a6ad79f61bf 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/rtlwifi/ps.c b/drivers/net/wireless/rtlwifi/ps.c index deedae3c544..d1c0191a195 100644 --- a/drivers/net/wireless/rtlwifi/ps.c +++ b/drivers/net/wireless/rtlwifi/ps.c @@ -48,7 +48,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 */ diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c index a82b30a1996..2eb0b38384d 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c @@ -937,14 +937,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 +964,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 +1044,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; } diff --git a/drivers/of/base.c b/drivers/of/base.c index 10b51106c85..89e888a7889 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -342,27 +342,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 +420,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 +726,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; } @@ -730,65 +772,26 @@ out: } EXPORT_SYMBOL(of_find_node_with_property); -static const struct of_device_id * -of_match_compatible(const struct of_device_id *matches, - const struct device_node *node) -{ - const char *cp; - int cplen, l; - const struct of_device_id *m; - - cp = __of_get_property(node, "compatible", &cplen); - while (cp && (cplen > 0)) { - m = matches; - while (m->name[0] || m->type[0] || m->compatible[0]) { - /* Only match for the entries without type and name */ - if (m->name[0] || m->type[0] || - of_compat_cmp(m->compatible, cp, - strlen(m->compatible))) - m++; - else - return m; - } - - /* Get node's next compatible string */ - l = strlen(cp) + 1; - cp += l; - cplen -= l; - } - - return NULL; -} - static const struct of_device_id *__of_match_node(const struct of_device_id *matches, const struct device_node *node) { - const struct of_device_id *m; + const struct of_device_id *best_match = NULL; + int score, best_score = 0; if (!matches) return NULL; - m = of_match_compatible(matches, node); - if (m) - return m; - - while (matches->name[0] || matches->type[0] || matches->compatible[0]) { - int match = 1; - if (matches->name[0]) - match &= node->name - && !strcmp(matches->name, node->name); - if (matches->type[0]) - match &= node->type - && !strcmp(matches->type, node->type); - if (matches->compatible[0]) - match &= __of_device_is_compatible(node, - matches->compatible); - if (match) - return matches; - matches++; + 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; + } } - return NULL; + + return best_match; } /** @@ -796,12 +799,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. We have two ways - * of matching: - * - Try to find the best compatible match by comparing each compatible - * string of device node with all the given matches respectively. - * - If the above method failed, then try to match the compatible by using - * __of_device_is_compatible() besides the match in type and name. + * 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) diff --git a/drivers/of/of_mdio.c b/drivers/of/of_mdio.c index 875b7b6f0d2..5b3c24f3cde 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: @@ -44,7 +48,7 @@ static int of_mdiobus_register_phy(struct mii_bus *mdio, struct device_node *chi { struct phy_device *phy; bool is_c45; - int rc, prev_irq; + int rc; u32 max_speed = 0; is_c45 = of_device_is_compatible(child, @@ -54,12 +58,14 @@ static int of_mdiobus_register_phy(struct mii_bus *mdio, struct device_node *chi 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/selftest.c b/drivers/of/selftest.c index e21012bde63..6643d192098 100644 --- a/drivers/of/selftest.c +++ b/drivers/of/selftest.c @@ -300,6 +300,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; @@ -316,6 +382,7 @@ static int __init of_selftest(void) 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 00000000000..3a5b75a8e4d --- /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 c843720bd3e..c843720bd3e 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 00000000000..c9e54112953 --- /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 0007d3cd7dc..0007d3cd7dc 100644 --- a/arch/arm/boot/dts/testcases/tests-phandle.dtsi +++ b/drivers/of/testcase-data/tests-phandle.dtsi diff --git a/drivers/pci/host/pci-mvebu.c b/drivers/pci/host/pci-mvebu.c index 13478ecd411..0e79665afd4 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; @@ -388,7 +380,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; diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 7a0fec6ce57..955ab7990c5 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.c b/drivers/pci/pci.c index 1febe90831b..6b05f6134b6 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -1181,6 +1181,8 @@ EXPORT_SYMBOL_GPL(pci_load_and_free_saved_state); 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 +1192,14 @@ static int do_pci_enable_device(struct pci_dev *dev, int bars) return err; pci_fixup_device(pci_fixup_enable, dev); + 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; } diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index afa2354f660..c7a551c2d5f 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. @@ -61,6 +61,7 @@ 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. diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c index 5f5b0f4be5b..6c738376daf 100644 --- a/drivers/phy/phy-core.c +++ b/drivers/phy/phy-core.c @@ -176,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; @@ -232,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); @@ -404,17 +408,11 @@ struct phy *phy_get(struct device *dev, const char *string) 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; - } } 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); diff --git a/drivers/phy/phy-exynos-dp-video.c b/drivers/phy/phy-exynos-dp-video.c index 1dbe6ce7b2c..0786fef842e 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 0c5efab11af..7f139326a64 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-mvebu-sata.c b/drivers/phy/phy-mvebu-sata.c index d43786f6243..d70ecd6a1b3 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/phy/phy-omap-usb2.c b/drivers/phy/phy-omap-usb2.c index bfc5c337f99..7699752fba1 100644 --- a/drivers/phy/phy-omap-usb2.c +++ b/drivers/phy/phy-omap-usb2.c @@ -177,11 +177,6 @@ static int omap_usb2_probe(struct platform_device *pdev) 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); - control_node = of_parse_phandle(node, "ctrl-module", 0); if (!control_node) { dev_err(&pdev->dev, "Failed to get control device phandle\n"); @@ -214,6 +209,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"); diff --git a/drivers/phy/phy-twl4030-usb.c b/drivers/phy/phy-twl4030-usb.c index daf65e68aaa..c3ace1db813 100644 --- a/drivers/phy/phy-twl4030-usb.c +++ b/drivers/phy/phy-twl4030-usb.c @@ -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/pwm/pwm-lp3943.c b/drivers/pwm/pwm-lp3943.c index 8a843a04c22..a40b9c34e9f 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/regulator/core.c b/drivers/regulator/core.c index 16a309e5c02..d1ac4caaf1b 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -1359,7 +1359,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(®ulator_list_mutex); diff --git a/drivers/regulator/da9063-regulator.c b/drivers/regulator/da9063-regulator.c index 56727eb745d..91e99a2c8dc 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, \ diff --git a/drivers/regulator/max14577.c b/drivers/regulator/max14577.c index 186df8785a9..e0619526708 100644 --- a/drivers/regulator/max14577.c +++ b/drivers/regulator/max14577.c @@ -166,9 +166,10 @@ 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); - } + else + ret = 0; of_node_put(np); diff --git a/drivers/regulator/s5m8767.c b/drivers/regulator/s5m8767.c index d7164bb75d3..d958dfa0512 100644 --- a/drivers/regulator/s5m8767.c +++ b/drivers/regulator/s5m8767.c @@ -535,7 +535,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; @@ -591,6 +591,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; diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index f6b9188c5af..9f0ea6cb692 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/crypto/zcrypt_msgtype6.c b/drivers/s390/crypto/zcrypt_msgtype6.c index dc542e0a305..0bc91e46395 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/sbus/char/jsflash.c b/drivers/sbus/char/jsflash.c index 6b4678a7900..4ccb5d86938 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/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c index 2eb97d7e8d1..0cb73074c19 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); @@ -3185,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); @@ -4181,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); @@ -4194,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); @@ -4265,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)) { @@ -4279,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 66e755cdde5..ce33d8c2640 100644 --- a/drivers/scsi/qla2xxx/qla_target.h +++ b/drivers/scsi/qla2xxx/qla_target.h @@ -1001,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/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c index 75a141bbe74..788c4fe2b0c 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 275d8b9a7a3..33aaac8c7d5 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/scsi_lib.c b/drivers/scsi/scsi_lib.c index 7bd7f0d5f05..62ec84b42e3 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -1684,7 +1684,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/staging/Kconfig b/drivers/staging/Kconfig index babb1cf67ce..47cf1754300 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -34,8 +34,6 @@ source "drivers/staging/winbond/Kconfig" source "drivers/staging/wlan-ng/Kconfig" -source "drivers/staging/echo/Kconfig" - source "drivers/staging/comedi/Kconfig" source "drivers/staging/olpc_dcon/Kconfig" @@ -82,8 +80,6 @@ source "drivers/staging/wlags49_h2/Kconfig" source "drivers/staging/wlags49_h25/Kconfig" -source "drivers/staging/sm7xxfb/Kconfig" - source "drivers/staging/crystalhd/Kconfig" source "drivers/staging/cxt1e1/Kconfig" @@ -128,8 +124,6 @@ source "drivers/staging/imx-drm/Kconfig" source "drivers/staging/dgrp/Kconfig" -source "drivers/staging/sb105x/Kconfig" - source "drivers/staging/fwserial/Kconfig" source "drivers/staging/goldfish/Kconfig" @@ -150,4 +144,6 @@ source "drivers/staging/gs_fpgaboot/Kconfig" source "drivers/staging/nokia_h4p/Kconfig" +source "drivers/staging/unisys/Kconfig" + endif # STAGING diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index 2c4949a9bd9..d12f6189db4 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -9,7 +9,6 @@ obj-$(CONFIG_SLICOSS) += slicoss/ obj-$(CONFIG_USBIP_CORE) += usbip/ obj-$(CONFIG_W35UND) += winbond/ obj-$(CONFIG_PRISM2_USB) += wlan-ng/ -obj-$(CONFIG_ECHO) += echo/ obj-$(CONFIG_COMEDI) += comedi/ obj-$(CONFIG_FB_OLPC_DCON) += olpc_dcon/ obj-$(CONFIG_PANEL) += panel/ @@ -35,7 +34,6 @@ obj-$(CONFIG_DX_SEP) += sep/ obj-$(CONFIG_IIO) += iio/ obj-$(CONFIG_WLAGS49_H2) += wlags49_h2/ obj-$(CONFIG_WLAGS49_H25) += wlags49_h25/ -obj-$(CONFIG_FB_SM7XX) += sm7xxfb/ obj-$(CONFIG_CRYSTALHD) += crystalhd/ obj-$(CONFIG_CXT1E1) += cxt1e1/ obj-$(CONFIG_FB_XGI) += xgifb/ @@ -57,7 +55,6 @@ obj-$(CONFIG_NET_VENDOR_SILICOM) += silicom/ obj-$(CONFIG_CED1401) += ced1401/ obj-$(CONFIG_DRM_IMX) += imx-drm/ obj-$(CONFIG_DGRP) += dgrp/ -obj-$(CONFIG_SB105X) += sb105x/ obj-$(CONFIG_FIREWIRE_SERIAL) += fwserial/ obj-$(CONFIG_GOLDFISH) += goldfish/ obj-$(CONFIG_LUSTRE_FS) += lustre/ @@ -67,3 +64,4 @@ obj-$(CONFIG_DGAP) += dgap/ obj-$(CONFIG_MTD_SPINAND_MT29F) += mt29f_spinand/ obj-$(CONFIG_GS_FPGABOOT) += gs_fpgaboot/ obj-$(CONFIG_BT_NOKIA_H4P) += nokia_h4p/ +obj-$(CONFIG_UNISYSSPAR) += unisys/ diff --git a/drivers/staging/android/Kconfig b/drivers/staging/android/Kconfig index b91c758883b..ab28d2b5e30 100644 --- a/drivers/staging/android/Kconfig +++ b/drivers/staging/android/Kconfig @@ -20,6 +20,19 @@ config ANDROID_BINDER_IPC Android process, using Binder to identify, invoke and pass arguments between said processes. +config ANDROID_BINDER_IPC_32BIT + bool + depends on !64BIT && ANDROID_BINDER_IPC + default y + ---help--- + The Binder API has been changed to support both 32 and 64bit + applications in a mixed environment. + + Enable this to support an old 32-bit Android user-space (v4.4 and + earlier). + + Note that enabling this will break newer Android user-space. + config ASHMEM bool "Enable the Anonymous Shared Memory Subsystem" default n diff --git a/drivers/staging/android/binder.c b/drivers/staging/android/binder.c index eaec1dab7fe..cfe4bc8f05c 100644 --- a/drivers/staging/android/binder.c +++ b/drivers/staging/android/binder.c @@ -228,8 +228,8 @@ struct binder_node { int internal_strong_refs; int local_weak_refs; int local_strong_refs; - void __user *ptr; - void __user *cookie; + binder_uintptr_t ptr; + binder_uintptr_t cookie; unsigned has_strong_ref:1; unsigned pending_strong_ref:1; unsigned has_weak_ref:1; @@ -242,7 +242,7 @@ struct binder_node { struct binder_ref_death { struct binder_work work; - void __user *cookie; + binder_uintptr_t cookie; }; struct binder_ref { @@ -515,14 +515,14 @@ static void binder_insert_allocated_buffer(struct binder_proc *proc, } static struct binder_buffer *binder_buffer_lookup(struct binder_proc *proc, - void __user *user_ptr) + uintptr_t user_ptr) { struct rb_node *n = proc->allocated_buffers.rb_node; struct binder_buffer *buffer; struct binder_buffer *kern_ptr; - kern_ptr = user_ptr - proc->user_buffer_offset - - offsetof(struct binder_buffer, data); + kern_ptr = (struct binder_buffer *)(user_ptr - proc->user_buffer_offset + - offsetof(struct binder_buffer, data)); while (n) { buffer = rb_entry(n, struct binder_buffer, rb_node); @@ -856,7 +856,7 @@ static void binder_free_buf(struct binder_proc *proc, } static struct binder_node *binder_get_node(struct binder_proc *proc, - void __user *ptr) + binder_uintptr_t ptr) { struct rb_node *n = proc->nodes.rb_node; struct binder_node *node; @@ -875,8 +875,8 @@ static struct binder_node *binder_get_node(struct binder_proc *proc, } static struct binder_node *binder_new_node(struct binder_proc *proc, - void __user *ptr, - void __user *cookie) + binder_uintptr_t ptr, + binder_uintptr_t cookie) { struct rb_node **p = &proc->nodes.rb_node; struct rb_node *parent = NULL; @@ -908,9 +908,9 @@ static struct binder_node *binder_new_node(struct binder_proc *proc, INIT_LIST_HEAD(&node->work.entry); INIT_LIST_HEAD(&node->async_todo); binder_debug(BINDER_DEBUG_INTERNAL_REFS, - "%d:%d node %d u%p c%p created\n", + "%d:%d node %d u%016llx c%016llx created\n", proc->pid, current->pid, node->debug_id, - node->ptr, node->cookie); + (u64)node->ptr, (u64)node->cookie); return node; } @@ -1226,9 +1226,9 @@ static void binder_send_failed_reply(struct binder_transaction *t, static void binder_transaction_buffer_release(struct binder_proc *proc, struct binder_buffer *buffer, - size_t *failed_at) + binder_size_t *failed_at) { - size_t *offp, *off_end; + binder_size_t *offp, *off_end; int debug_id = buffer->debug_id; binder_debug(BINDER_DEBUG_TRANSACTION, @@ -1239,7 +1239,8 @@ static void binder_transaction_buffer_release(struct binder_proc *proc, if (buffer->target_node) binder_dec_node(buffer->target_node, 1, 0); - offp = (size_t *)(buffer->data + ALIGN(buffer->data_size, sizeof(void *))); + offp = (binder_size_t *)(buffer->data + + ALIGN(buffer->data_size, sizeof(void *))); if (failed_at) off_end = failed_at; else @@ -1249,8 +1250,8 @@ static void binder_transaction_buffer_release(struct binder_proc *proc, if (*offp > buffer->data_size - sizeof(*fp) || buffer->data_size < sizeof(*fp) || !IS_ALIGNED(*offp, sizeof(u32))) { - pr_err("transaction release %d bad offset %zd, size %zd\n", - debug_id, *offp, buffer->data_size); + pr_err("transaction release %d bad offset %lld, size %zd\n", + debug_id, (u64)*offp, buffer->data_size); continue; } fp = (struct flat_binder_object *)(buffer->data + *offp); @@ -1259,13 +1260,13 @@ static void binder_transaction_buffer_release(struct binder_proc *proc, case BINDER_TYPE_WEAK_BINDER: { struct binder_node *node = binder_get_node(proc, fp->binder); if (node == NULL) { - pr_err("transaction release %d bad node %p\n", - debug_id, fp->binder); + pr_err("transaction release %d bad node %016llx\n", + debug_id, (u64)fp->binder); break; } binder_debug(BINDER_DEBUG_TRANSACTION, - " node %d u%p\n", - node->debug_id, node->ptr); + " node %d u%016llx\n", + node->debug_id, (u64)node->ptr); binder_dec_node(node, fp->type == BINDER_TYPE_BINDER, 0); } break; case BINDER_TYPE_HANDLE: @@ -1303,7 +1304,7 @@ static void binder_transaction(struct binder_proc *proc, { struct binder_transaction *t; struct binder_work *tcomplete; - size_t *offp, *off_end; + binder_size_t *offp, *off_end; struct binder_proc *target_proc; struct binder_thread *target_thread = NULL; struct binder_node *target_node = NULL; @@ -1432,18 +1433,20 @@ static void binder_transaction(struct binder_proc *proc, if (reply) binder_debug(BINDER_DEBUG_TRANSACTION, - "%d:%d BC_REPLY %d -> %d:%d, data %p-%p size %zd-%zd\n", + "%d:%d BC_REPLY %d -> %d:%d, data %016llx-%016llx size %lld-%lld\n", proc->pid, thread->pid, t->debug_id, target_proc->pid, target_thread->pid, - tr->data.ptr.buffer, tr->data.ptr.offsets, - tr->data_size, tr->offsets_size); + (u64)tr->data.ptr.buffer, + (u64)tr->data.ptr.offsets, + (u64)tr->data_size, (u64)tr->offsets_size); else binder_debug(BINDER_DEBUG_TRANSACTION, - "%d:%d BC_TRANSACTION %d -> %d - node %d, data %p-%p size %zd-%zd\n", + "%d:%d BC_TRANSACTION %d -> %d - node %d, data %016llx-%016llx size %lld-%lld\n", proc->pid, thread->pid, t->debug_id, target_proc->pid, target_node->debug_id, - tr->data.ptr.buffer, tr->data.ptr.offsets, - tr->data_size, tr->offsets_size); + (u64)tr->data.ptr.buffer, + (u64)tr->data.ptr.offsets, + (u64)tr->data_size, (u64)tr->offsets_size); if (!reply && !(tr->flags & TF_ONE_WAY)) t->from = thread; @@ -1472,23 +1475,26 @@ static void binder_transaction(struct binder_proc *proc, if (target_node) binder_inc_node(target_node, 1, 0, NULL); - offp = (size_t *)(t->buffer->data + ALIGN(tr->data_size, sizeof(void *))); + offp = (binder_size_t *)(t->buffer->data + + ALIGN(tr->data_size, sizeof(void *))); - if (copy_from_user(t->buffer->data, tr->data.ptr.buffer, tr->data_size)) { + if (copy_from_user(t->buffer->data, (const void __user *)(uintptr_t) + tr->data.ptr.buffer, tr->data_size)) { binder_user_error("%d:%d got transaction with invalid data ptr\n", proc->pid, thread->pid); return_error = BR_FAILED_REPLY; goto err_copy_data_failed; } - if (copy_from_user(offp, tr->data.ptr.offsets, tr->offsets_size)) { + if (copy_from_user(offp, (const void __user *)(uintptr_t) + tr->data.ptr.offsets, tr->offsets_size)) { binder_user_error("%d:%d got transaction with invalid offsets ptr\n", proc->pid, thread->pid); return_error = BR_FAILED_REPLY; goto err_copy_data_failed; } - if (!IS_ALIGNED(tr->offsets_size, sizeof(size_t))) { - binder_user_error("%d:%d got transaction with invalid offsets size, %zd\n", - proc->pid, thread->pid, tr->offsets_size); + if (!IS_ALIGNED(tr->offsets_size, sizeof(binder_size_t))) { + binder_user_error("%d:%d got transaction with invalid offsets size, %lld\n", + proc->pid, thread->pid, (u64)tr->offsets_size); return_error = BR_FAILED_REPLY; goto err_bad_offset; } @@ -1498,8 +1504,8 @@ static void binder_transaction(struct binder_proc *proc, if (*offp > t->buffer->data_size - sizeof(*fp) || t->buffer->data_size < sizeof(*fp) || !IS_ALIGNED(*offp, sizeof(u32))) { - binder_user_error("%d:%d got transaction with invalid offset, %zd\n", - proc->pid, thread->pid, *offp); + binder_user_error("%d:%d got transaction with invalid offset, %lld\n", + proc->pid, thread->pid, (u64)*offp); return_error = BR_FAILED_REPLY; goto err_bad_offset; } @@ -1519,10 +1525,10 @@ static void binder_transaction(struct binder_proc *proc, node->accept_fds = !!(fp->flags & FLAT_BINDER_FLAG_ACCEPTS_FDS); } if (fp->cookie != node->cookie) { - binder_user_error("%d:%d sending u%p node %d, cookie mismatch %p != %p\n", + binder_user_error("%d:%d sending u%016llx node %d, cookie mismatch %016llx != %016llx\n", proc->pid, thread->pid, - fp->binder, node->debug_id, - fp->cookie, node->cookie); + (u64)fp->binder, node->debug_id, + (u64)fp->cookie, (u64)node->cookie); goto err_binder_get_ref_for_node_failed; } ref = binder_get_ref_for_node(target_proc, node); @@ -1540,9 +1546,9 @@ static void binder_transaction(struct binder_proc *proc, trace_binder_transaction_node_to_ref(t, node, ref); binder_debug(BINDER_DEBUG_TRANSACTION, - " node %d u%p -> ref %d desc %d\n", - node->debug_id, node->ptr, ref->debug_id, - ref->desc); + " node %d u%016llx -> ref %d desc %d\n", + node->debug_id, (u64)node->ptr, + ref->debug_id, ref->desc); } break; case BINDER_TYPE_HANDLE: case BINDER_TYPE_WEAK_HANDLE: { @@ -1564,9 +1570,9 @@ static void binder_transaction(struct binder_proc *proc, binder_inc_node(ref->node, fp->type == BINDER_TYPE_BINDER, 0, NULL); trace_binder_transaction_ref_to_node(t, ref); binder_debug(BINDER_DEBUG_TRANSACTION, - " ref %d desc %d -> node %d u%p\n", + " ref %d desc %d -> node %d u%016llx\n", ref->debug_id, ref->desc, ref->node->debug_id, - ref->node->ptr); + (u64)ref->node->ptr); } else { struct binder_ref *new_ref; new_ref = binder_get_ref_for_node(target_proc, ref->node); @@ -1682,9 +1688,9 @@ err_dead_binder: err_invalid_target_handle: err_no_context_mgr_node: binder_debug(BINDER_DEBUG_FAILED_TRANSACTION, - "%d:%d transaction failed %d, size %zd-%zd\n", + "%d:%d transaction failed %d, size %lld-%lld\n", proc->pid, thread->pid, return_error, - tr->data_size, tr->offsets_size); + (u64)tr->data_size, (u64)tr->offsets_size); { struct binder_transaction_log_entry *fe; @@ -1702,9 +1708,11 @@ err_no_context_mgr_node: static int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread, - void __user *buffer, size_t size, size_t *consumed) + binder_uintptr_t binder_buffer, size_t size, + binder_size_t *consumed) { uint32_t cmd; + void __user *buffer = (void __user *)(uintptr_t)binder_buffer; void __user *ptr = buffer + *consumed; void __user *end = buffer + size; @@ -1773,33 +1781,33 @@ static int binder_thread_write(struct binder_proc *proc, } case BC_INCREFS_DONE: case BC_ACQUIRE_DONE: { - void __user *node_ptr; - void __user *cookie; + binder_uintptr_t node_ptr; + binder_uintptr_t cookie; struct binder_node *node; - if (get_user(node_ptr, (void * __user *)ptr)) + if (get_user(node_ptr, (binder_uintptr_t __user *)ptr)) return -EFAULT; - ptr += sizeof(void *); - if (get_user(cookie, (void * __user *)ptr)) + ptr += sizeof(binder_uintptr_t); + if (get_user(cookie, (binder_uintptr_t __user *)ptr)) return -EFAULT; - ptr += sizeof(void *); + ptr += sizeof(binder_uintptr_t); node = binder_get_node(proc, node_ptr); if (node == NULL) { - binder_user_error("%d:%d %s u%p no match\n", + binder_user_error("%d:%d %s u%016llx no match\n", proc->pid, thread->pid, cmd == BC_INCREFS_DONE ? "BC_INCREFS_DONE" : "BC_ACQUIRE_DONE", - node_ptr); + (u64)node_ptr); break; } if (cookie != node->cookie) { - binder_user_error("%d:%d %s u%p node %d cookie mismatch %p != %p\n", + binder_user_error("%d:%d %s u%016llx node %d cookie mismatch %016llx != %016llx\n", proc->pid, thread->pid, cmd == BC_INCREFS_DONE ? "BC_INCREFS_DONE" : "BC_ACQUIRE_DONE", - node_ptr, node->debug_id, - cookie, node->cookie); + (u64)node_ptr, node->debug_id, + (u64)cookie, (u64)node->cookie); break; } if (cmd == BC_ACQUIRE_DONE) { @@ -1835,27 +1843,28 @@ static int binder_thread_write(struct binder_proc *proc, return -EINVAL; case BC_FREE_BUFFER: { - void __user *data_ptr; + binder_uintptr_t data_ptr; struct binder_buffer *buffer; - if (get_user(data_ptr, (void * __user *)ptr)) + if (get_user(data_ptr, (binder_uintptr_t __user *)ptr)) return -EFAULT; - ptr += sizeof(void *); + ptr += sizeof(binder_uintptr_t); buffer = binder_buffer_lookup(proc, data_ptr); if (buffer == NULL) { - binder_user_error("%d:%d BC_FREE_BUFFER u%p no match\n", - proc->pid, thread->pid, data_ptr); + binder_user_error("%d:%d BC_FREE_BUFFER u%016llx no match\n", + proc->pid, thread->pid, (u64)data_ptr); break; } if (!buffer->allow_user_free) { - binder_user_error("%d:%d BC_FREE_BUFFER u%p matched unreturned buffer\n", - proc->pid, thread->pid, data_ptr); + binder_user_error("%d:%d BC_FREE_BUFFER u%016llx matched unreturned buffer\n", + proc->pid, thread->pid, (u64)data_ptr); break; } binder_debug(BINDER_DEBUG_FREE_BUFFER, - "%d:%d BC_FREE_BUFFER u%p found buffer %d for %s transaction\n", - proc->pid, thread->pid, data_ptr, buffer->debug_id, + "%d:%d BC_FREE_BUFFER u%016llx found buffer %d for %s transaction\n", + proc->pid, thread->pid, (u64)data_ptr, + buffer->debug_id, buffer->transaction ? "active" : "finished"); if (buffer->transaction) { @@ -1925,16 +1934,16 @@ static int binder_thread_write(struct binder_proc *proc, case BC_REQUEST_DEATH_NOTIFICATION: case BC_CLEAR_DEATH_NOTIFICATION: { uint32_t target; - void __user *cookie; + binder_uintptr_t cookie; struct binder_ref *ref; struct binder_ref_death *death; if (get_user(target, (uint32_t __user *)ptr)) return -EFAULT; ptr += sizeof(uint32_t); - if (get_user(cookie, (void __user * __user *)ptr)) + if (get_user(cookie, (binder_uintptr_t __user *)ptr)) return -EFAULT; - ptr += sizeof(void *); + ptr += sizeof(binder_uintptr_t); ref = binder_get_ref(proc, target); if (ref == NULL) { binder_user_error("%d:%d %s invalid ref %d\n", @@ -1947,12 +1956,12 @@ static int binder_thread_write(struct binder_proc *proc, } binder_debug(BINDER_DEBUG_DEATH_NOTIFICATION, - "%d:%d %s %p ref %d desc %d s %d w %d for node %d\n", + "%d:%d %s %016llx ref %d desc %d s %d w %d for node %d\n", proc->pid, thread->pid, cmd == BC_REQUEST_DEATH_NOTIFICATION ? "BC_REQUEST_DEATH_NOTIFICATION" : "BC_CLEAR_DEATH_NOTIFICATION", - cookie, ref->debug_id, ref->desc, + (u64)cookie, ref->debug_id, ref->desc, ref->strong, ref->weak, ref->node->debug_id); if (cmd == BC_REQUEST_DEATH_NOTIFICATION) { @@ -1990,9 +1999,10 @@ static int binder_thread_write(struct binder_proc *proc, } death = ref->death; if (death->cookie != cookie) { - binder_user_error("%d:%d BC_CLEAR_DEATH_NOTIFICATION death notification cookie mismatch %p != %p\n", + binder_user_error("%d:%d BC_CLEAR_DEATH_NOTIFICATION death notification cookie mismatch %016llx != %016llx\n", proc->pid, thread->pid, - death->cookie, cookie); + (u64)death->cookie, + (u64)cookie); break; } ref->death = NULL; @@ -2012,9 +2022,9 @@ static int binder_thread_write(struct binder_proc *proc, } break; case BC_DEAD_BINDER_DONE: { struct binder_work *w; - void __user *cookie; + binder_uintptr_t cookie; struct binder_ref_death *death = NULL; - if (get_user(cookie, (void __user * __user *)ptr)) + if (get_user(cookie, (binder_uintptr_t __user *)ptr)) return -EFAULT; ptr += sizeof(void *); @@ -2026,11 +2036,12 @@ static int binder_thread_write(struct binder_proc *proc, } } binder_debug(BINDER_DEBUG_DEAD_BINDER, - "%d:%d BC_DEAD_BINDER_DONE %p found %p\n", - proc->pid, thread->pid, cookie, death); + "%d:%d BC_DEAD_BINDER_DONE %016llx found %p\n", + proc->pid, thread->pid, (u64)cookie, + death); if (death == NULL) { - binder_user_error("%d:%d BC_DEAD_BINDER_DONE %p not found\n", - proc->pid, thread->pid, cookie); + binder_user_error("%d:%d BC_DEAD_BINDER_DONE %016llx not found\n", + proc->pid, thread->pid, (u64)cookie); break; } @@ -2082,9 +2093,10 @@ static int binder_has_thread_work(struct binder_thread *thread) static int binder_thread_read(struct binder_proc *proc, struct binder_thread *thread, - void __user *buffer, size_t size, - size_t *consumed, int non_block) + binder_uintptr_t binder_buffer, size_t size, + binder_size_t *consumed, int non_block) { + void __user *buffer = (void __user *)(uintptr_t)binder_buffer; void __user *ptr = buffer + *consumed; void __user *end = buffer + size; @@ -2229,32 +2241,40 @@ retry: if (put_user(cmd, (uint32_t __user *)ptr)) return -EFAULT; ptr += sizeof(uint32_t); - if (put_user(node->ptr, (void * __user *)ptr)) + if (put_user(node->ptr, + (binder_uintptr_t __user *)ptr)) return -EFAULT; - ptr += sizeof(void *); - if (put_user(node->cookie, (void * __user *)ptr)) + ptr += sizeof(binder_uintptr_t); + if (put_user(node->cookie, + (binder_uintptr_t __user *)ptr)) return -EFAULT; - ptr += sizeof(void *); + ptr += sizeof(binder_uintptr_t); binder_stat_br(proc, thread, cmd); binder_debug(BINDER_DEBUG_USER_REFS, - "%d:%d %s %d u%p c%p\n", - proc->pid, thread->pid, cmd_name, node->debug_id, node->ptr, node->cookie); + "%d:%d %s %d u%016llx c%016llx\n", + proc->pid, thread->pid, cmd_name, + node->debug_id, + (u64)node->ptr, (u64)node->cookie); } else { list_del_init(&w->entry); if (!weak && !strong) { binder_debug(BINDER_DEBUG_INTERNAL_REFS, - "%d:%d node %d u%p c%p deleted\n", - proc->pid, thread->pid, node->debug_id, - node->ptr, node->cookie); + "%d:%d node %d u%016llx c%016llx deleted\n", + proc->pid, thread->pid, + node->debug_id, + (u64)node->ptr, + (u64)node->cookie); rb_erase(&node->rb_node, &proc->nodes); kfree(node); binder_stats_deleted(BINDER_STAT_NODE); } else { binder_debug(BINDER_DEBUG_INTERNAL_REFS, - "%d:%d node %d u%p c%p state unchanged\n", - proc->pid, thread->pid, node->debug_id, node->ptr, - node->cookie); + "%d:%d node %d u%016llx c%016llx state unchanged\n", + proc->pid, thread->pid, + node->debug_id, + (u64)node->ptr, + (u64)node->cookie); } } } break; @@ -2272,17 +2292,18 @@ retry: if (put_user(cmd, (uint32_t __user *)ptr)) return -EFAULT; ptr += sizeof(uint32_t); - if (put_user(death->cookie, (void * __user *)ptr)) + if (put_user(death->cookie, + (binder_uintptr_t __user *)ptr)) return -EFAULT; - ptr += sizeof(void *); + ptr += sizeof(binder_uintptr_t); binder_stat_br(proc, thread, cmd); binder_debug(BINDER_DEBUG_DEATH_NOTIFICATION, - "%d:%d %s %p\n", + "%d:%d %s %016llx\n", proc->pid, thread->pid, cmd == BR_DEAD_BINDER ? "BR_DEAD_BINDER" : "BR_CLEAR_DEATH_NOTIFICATION_DONE", - death->cookie); + (u64)death->cookie); if (w->type == BINDER_WORK_CLEAR_DEATH_NOTIFICATION) { list_del(&w->entry); @@ -2312,8 +2333,8 @@ retry: binder_set_nice(target_node->min_priority); cmd = BR_TRANSACTION; } else { - tr.target.ptr = NULL; - tr.cookie = NULL; + tr.target.ptr = 0; + tr.cookie = 0; cmd = BR_REPLY; } tr.code = t->code; @@ -2330,8 +2351,9 @@ retry: tr.data_size = t->buffer->data_size; tr.offsets_size = t->buffer->offsets_size; - tr.data.ptr.buffer = (void *)t->buffer->data + - proc->user_buffer_offset; + tr.data.ptr.buffer = (binder_uintptr_t)( + (uintptr_t)t->buffer->data + + proc->user_buffer_offset); tr.data.ptr.offsets = tr.data.ptr.buffer + ALIGN(t->buffer->data_size, sizeof(void *)); @@ -2346,14 +2368,14 @@ retry: trace_binder_transaction_received(t); binder_stat_br(proc, thread, cmd); binder_debug(BINDER_DEBUG_TRANSACTION, - "%d:%d %s %d %d:%d, cmd %d size %zd-%zd ptr %p-%p\n", + "%d:%d %s %d %d:%d, cmd %d size %zd-%zd ptr %016llx-%016llx\n", proc->pid, thread->pid, (cmd == BR_TRANSACTION) ? "BR_TRANSACTION" : "BR_REPLY", t->debug_id, t->from ? t->from->proc->pid : 0, t->from ? t->from->pid : 0, cmd, t->buffer->data_size, t->buffer->offsets_size, - tr.data.ptr.buffer, tr.data.ptr.offsets); + (u64)tr.data.ptr.buffer, (u64)tr.data.ptr.offsets); list_del(&t->work.entry); t->buffer->allow_user_free = 1; @@ -2423,8 +2445,8 @@ static void binder_release_work(struct list_head *list) death = container_of(w, struct binder_ref_death, work); binder_debug(BINDER_DEBUG_DEAD_TRANSACTION, - "undelivered death notification, %p\n", - death->cookie); + "undelivered death notification, %016llx\n", + (u64)death->cookie); kfree(death); binder_stats_deleted(BINDER_STAT_DEATH); } break; @@ -2580,12 +2602,16 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) goto err; } binder_debug(BINDER_DEBUG_READ_WRITE, - "%d:%d write %zd at %016lx, read %zd at %016lx\n", - proc->pid, thread->pid, bwr.write_size, - bwr.write_buffer, bwr.read_size, bwr.read_buffer); + "%d:%d write %lld at %016llx, read %lld at %016llx\n", + proc->pid, thread->pid, + (u64)bwr.write_size, (u64)bwr.write_buffer, + (u64)bwr.read_size, (u64)bwr.read_buffer); if (bwr.write_size > 0) { - ret = binder_thread_write(proc, thread, (void __user *)bwr.write_buffer, bwr.write_size, &bwr.write_consumed); + ret = binder_thread_write(proc, thread, + bwr.write_buffer, + bwr.write_size, + &bwr.write_consumed); trace_binder_write_done(ret); if (ret < 0) { bwr.read_consumed = 0; @@ -2595,7 +2621,10 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) } } if (bwr.read_size > 0) { - ret = binder_thread_read(proc, thread, (void __user *)bwr.read_buffer, bwr.read_size, &bwr.read_consumed, filp->f_flags & O_NONBLOCK); + ret = binder_thread_read(proc, thread, bwr.read_buffer, + bwr.read_size, + &bwr.read_consumed, + filp->f_flags & O_NONBLOCK); trace_binder_read_done(ret); if (!list_empty(&proc->todo)) wake_up_interruptible(&proc->wait); @@ -2606,9 +2635,10 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) } } binder_debug(BINDER_DEBUG_READ_WRITE, - "%d:%d wrote %zd of %zd, read return %zd of %zd\n", - proc->pid, thread->pid, bwr.write_consumed, bwr.write_size, - bwr.read_consumed, bwr.read_size); + "%d:%d wrote %lld of %lld, read return %lld of %lld\n", + proc->pid, thread->pid, + (u64)bwr.write_consumed, (u64)bwr.write_size, + (u64)bwr.read_consumed, (u64)bwr.read_size); if (copy_to_user(ubuf, &bwr, sizeof(bwr))) { ret = -EFAULT; goto err; @@ -2637,7 +2667,7 @@ static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) } } else binder_context_mgr_uid = current->cred->euid; - binder_context_mgr_node = binder_new_node(proc, NULL, NULL); + binder_context_mgr_node = binder_new_node(proc, 0, 0); if (binder_context_mgr_node == NULL) { ret = -ENOMEM; goto err; @@ -2904,7 +2934,7 @@ static int binder_node_release(struct binder_node *node, int refs) refs++; if (!ref->death) - goto out; + continue; death++; @@ -2917,7 +2947,6 @@ static int binder_node_release(struct binder_node *node, int refs) BUG(); } -out: binder_debug(BINDER_DEBUG_DEAD_BINDER, "node %d now dead, refs %d, death %d\n", node->debug_id, refs, death); @@ -3133,8 +3162,9 @@ static void print_binder_work(struct seq_file *m, const char *prefix, break; case BINDER_WORK_NODE: node = container_of(w, struct binder_node, work); - seq_printf(m, "%snode work %d: u%p c%p\n", - prefix, node->debug_id, node->ptr, node->cookie); + seq_printf(m, "%snode work %d: u%016llx c%016llx\n", + prefix, node->debug_id, + (u64)node->ptr, (u64)node->cookie); break; case BINDER_WORK_DEAD_BINDER: seq_printf(m, "%shas dead binder\n", prefix); @@ -3194,8 +3224,8 @@ static void print_binder_node(struct seq_file *m, struct binder_node *node) hlist_for_each_entry(ref, &node->refs, node_entry) count++; - seq_printf(m, " node %d: u%p c%p hs %d hw %d ls %d lw %d is %d iw %d", - node->debug_id, node->ptr, node->cookie, + seq_printf(m, " node %d: u%016llx c%016llx hs %d hw %d ls %d lw %d is %d iw %d", + node->debug_id, (u64)node->ptr, (u64)node->cookie, node->has_strong_ref, node->has_weak_ref, node->local_strong_refs, node->local_weak_refs, node->internal_strong_refs, count); @@ -3497,6 +3527,7 @@ static const struct file_operations binder_fops = { .owner = THIS_MODULE, .poll = binder_poll, .unlocked_ioctl = binder_ioctl, + .compat_ioctl = binder_ioctl, .mmap = binder_mmap, .open = binder_open, .flush = binder_flush, diff --git a/drivers/staging/android/binder.h b/drivers/staging/android/binder.h index d4101a67171..eb0834656df 100644 --- a/drivers/staging/android/binder.h +++ b/drivers/staging/android/binder.h @@ -20,6 +20,10 @@ #ifndef _LINUX_BINDER_H #define _LINUX_BINDER_H +#ifdef CONFIG_ANDROID_BINDER_IPC_32BIT +#define BINDER_IPC_32BIT 1 +#endif + #include "uapi/binder.h" #endif /* _LINUX_BINDER_H */ diff --git a/drivers/staging/android/binder_trace.h b/drivers/staging/android/binder_trace.h index 82a567c2af6..7f20f3dc836 100644 --- a/drivers/staging/android/binder_trace.h +++ b/drivers/staging/android/binder_trace.h @@ -152,7 +152,7 @@ TRACE_EVENT(binder_transaction_node_to_ref, TP_STRUCT__entry( __field(int, debug_id) __field(int, node_debug_id) - __field(void __user *, node_ptr) + __field(binder_uintptr_t, node_ptr) __field(int, ref_debug_id) __field(uint32_t, ref_desc) ), @@ -163,8 +163,9 @@ TRACE_EVENT(binder_transaction_node_to_ref, __entry->ref_debug_id = ref->debug_id; __entry->ref_desc = ref->desc; ), - TP_printk("transaction=%d node=%d src_ptr=0x%p ==> dest_ref=%d dest_desc=%d", - __entry->debug_id, __entry->node_debug_id, __entry->node_ptr, + TP_printk("transaction=%d node=%d src_ptr=0x%016llx ==> dest_ref=%d dest_desc=%d", + __entry->debug_id, __entry->node_debug_id, + (u64)__entry->node_ptr, __entry->ref_debug_id, __entry->ref_desc) ); @@ -177,7 +178,7 @@ TRACE_EVENT(binder_transaction_ref_to_node, __field(int, ref_debug_id) __field(uint32_t, ref_desc) __field(int, node_debug_id) - __field(void __user *, node_ptr) + __field(binder_uintptr_t, node_ptr) ), TP_fast_assign( __entry->debug_id = t->debug_id; @@ -186,9 +187,10 @@ TRACE_EVENT(binder_transaction_ref_to_node, __entry->node_debug_id = ref->node->debug_id; __entry->node_ptr = ref->node->ptr; ), - TP_printk("transaction=%d node=%d src_ref=%d src_desc=%d ==> dest_ptr=0x%p", + TP_printk("transaction=%d node=%d src_ref=%d src_desc=%d ==> dest_ptr=0x%016llx", __entry->debug_id, __entry->node_debug_id, - __entry->ref_debug_id, __entry->ref_desc, __entry->node_ptr) + __entry->ref_debug_id, __entry->ref_desc, + (u64)__entry->node_ptr) ); TRACE_EVENT(binder_transaction_ref_to_ref, diff --git a/drivers/staging/android/lowmemorykiller.c b/drivers/staging/android/lowmemorykiller.c index 4bcf00a8727..b545d3d1da3 100644 --- a/drivers/staging/android/lowmemorykiller.c +++ b/drivers/staging/android/lowmemorykiller.c @@ -88,7 +88,8 @@ static unsigned long lowmem_scan(struct shrinker *s, struct shrink_control *sc) int array_size = ARRAY_SIZE(lowmem_adj); int other_free = global_page_state(NR_FREE_PAGES) - totalreserve_pages; int other_file = global_page_state(NR_FILE_PAGES) - - global_page_state(NR_SHMEM); + global_page_state(NR_SHMEM) - + total_swapcache_pages(); if (lowmem_adj_size < array_size) array_size = lowmem_adj_size; diff --git a/drivers/staging/android/uapi/binder.h b/drivers/staging/android/uapi/binder.h index 2b1eb8106d5..904adb7600c 100644 --- a/drivers/staging/android/uapi/binder.h +++ b/drivers/staging/android/uapi/binder.h @@ -39,6 +39,14 @@ enum { FLAT_BINDER_FLAG_ACCEPTS_FDS = 0x100, }; +#ifdef BINDER_IPC_32BIT +typedef __u32 binder_size_t; +typedef __u32 binder_uintptr_t; +#else +typedef __u64 binder_size_t; +typedef __u64 binder_uintptr_t; +#endif + /* * This is the flattened representation of a Binder object for transfer * between processes. The 'offsets' supplied as part of a binder transaction @@ -53,12 +61,12 @@ struct flat_binder_object { /* 8 bytes of data. */ union { - void __user *binder; /* local object */ - __u32 handle; /* remote object */ + binder_uintptr_t binder; /* local object */ + __u32 handle; /* remote object */ }; /* extra data associated with local object */ - void __user *cookie; + binder_uintptr_t cookie; }; /* @@ -67,12 +75,12 @@ struct flat_binder_object { */ struct binder_write_read { - size_t write_size; /* bytes to write */ - size_t write_consumed; /* bytes consumed by driver */ - unsigned long write_buffer; - size_t read_size; /* bytes to read */ - size_t read_consumed; /* bytes consumed by driver */ - unsigned long read_buffer; + binder_size_t write_size; /* bytes to write */ + binder_size_t write_consumed; /* bytes consumed by driver */ + binder_uintptr_t write_buffer; + binder_size_t read_size; /* bytes to read */ + binder_size_t read_consumed; /* bytes consumed by driver */ + binder_uintptr_t read_buffer; }; /* Use with BINDER_VERSION, driver fills in fields. */ @@ -82,7 +90,11 @@ struct binder_version { }; /* This is the current protocol version. */ +#ifdef BINDER_IPC_32BIT #define BINDER_CURRENT_PROTOCOL_VERSION 7 +#else +#define BINDER_CURRENT_PROTOCOL_VERSION 8 +#endif #define BINDER_WRITE_READ _IOWR('b', 1, struct binder_write_read) #define BINDER_SET_IDLE_TIMEOUT _IOW('b', 3, __s64) @@ -119,18 +131,20 @@ struct binder_transaction_data { * identifying the target and contents of the transaction. */ union { - __u32 handle; /* target descriptor of command transaction */ - void *ptr; /* target descriptor of return transaction */ + /* target descriptor of command transaction */ + __u32 handle; + /* target descriptor of return transaction */ + binder_uintptr_t ptr; } target; - void *cookie; /* target object cookie */ + binder_uintptr_t cookie; /* target object cookie */ __u32 code; /* transaction command */ /* General information about the transaction. */ __u32 flags; pid_t sender_pid; uid_t sender_euid; - size_t data_size; /* number of bytes of data */ - size_t offsets_size; /* number of bytes of offsets */ + binder_size_t data_size; /* number of bytes of data */ + binder_size_t offsets_size; /* number of bytes of offsets */ /* If this transaction is inline, the data immediately * follows here; otherwise, it ends with a pointer to @@ -139,19 +153,24 @@ struct binder_transaction_data { union { struct { /* transaction data */ - const void __user *buffer; + binder_uintptr_t buffer; /* offsets from buffer to flat_binder_object structs */ - const void __user *offsets; + binder_uintptr_t offsets; } ptr; __u8 buf[8]; } data; }; struct binder_ptr_cookie { - void *ptr; - void *cookie; + binder_uintptr_t ptr; + binder_uintptr_t cookie; }; +struct binder_handle_cookie { + __u32 handle; + binder_uintptr_t cookie; +} __attribute__((packed)); + struct binder_pri_desc { __s32 priority; __u32 desc; @@ -159,8 +178,8 @@ struct binder_pri_desc { struct binder_pri_ptr_cookie { __s32 priority; - void *ptr; - void *cookie; + binder_uintptr_t ptr; + binder_uintptr_t cookie; }; enum binder_driver_return_protocol { @@ -235,11 +254,11 @@ enum binder_driver_return_protocol { * stop threadpool thread */ - BR_DEAD_BINDER = _IOR('r', 15, void *), + BR_DEAD_BINDER = _IOR('r', 15, binder_uintptr_t), /* * void *: cookie */ - BR_CLEAR_DEATH_NOTIFICATION_DONE = _IOR('r', 16, void *), + BR_CLEAR_DEATH_NOTIFICATION_DONE = _IOR('r', 16, binder_uintptr_t), /* * void *: cookie */ @@ -265,7 +284,7 @@ enum binder_driver_command_protocol { * Else you have acquired a primary reference on the object. */ - BC_FREE_BUFFER = _IOW('c', 3, void *), + BC_FREE_BUFFER = _IOW('c', 3, binder_uintptr_t), /* * void *: ptr to transaction data received on a read */ @@ -308,19 +327,21 @@ enum binder_driver_command_protocol { * of looping threads it has available. */ - BC_REQUEST_DEATH_NOTIFICATION = _IOW('c', 14, struct binder_ptr_cookie), + BC_REQUEST_DEATH_NOTIFICATION = _IOW('c', 14, + struct binder_handle_cookie), /* - * void *: ptr to binder + * int: handle * void *: cookie */ - BC_CLEAR_DEATH_NOTIFICATION = _IOW('c', 15, struct binder_ptr_cookie), + BC_CLEAR_DEATH_NOTIFICATION = _IOW('c', 15, + struct binder_handle_cookie), /* - * void *: ptr to binder + * int: handle * void *: cookie */ - BC_DEAD_BINDER_DONE = _IOW('c', 16, void *), + BC_DEAD_BINDER_DONE = _IOW('c', 16, binder_uintptr_t), /* * void *: cookie */ diff --git a/drivers/staging/bcm/Bcmnet.c b/drivers/staging/bcm/Bcmnet.c index 8dfdd2732bd..95a2358267b 100644 --- a/drivers/staging/bcm/Bcmnet.c +++ b/drivers/staging/bcm/Bcmnet.c @@ -40,7 +40,7 @@ static INT bcm_close(struct net_device *dev) } static u16 bcm_select_queue(struct net_device *dev, struct sk_buff *skb, - void *accel_priv) + void *accel_priv, select_queue_fallback_t fallback) { return ClassifyPacket(netdev_priv(dev), skb); } diff --git a/drivers/staging/bcm/InterfaceInit.c b/drivers/staging/bcm/InterfaceInit.c index 94f32728f7c..5b03a19778d 100644 --- a/drivers/staging/bcm/InterfaceInit.c +++ b/drivers/staging/bcm/InterfaceInit.c @@ -1,5 +1,5 @@ #include "headers.h" - +#include <linux/usb/ch9.h> static struct usb_device_id InterfaceUsbtable[] = { { USB_DEVICE(BCM_USB_VENDOR_ID_T3, BCM_USB_PRODUCT_ID_T3) }, { USB_DEVICE(BCM_USB_VENDOR_ID_T3, BCM_USB_PRODUCT_ID_T3B) }, @@ -347,81 +347,6 @@ static int device_run(struct bcm_interface_adapter *psIntfAdapter) return 0; } - -static inline int bcm_usb_endpoint_num(const struct usb_endpoint_descriptor *epd) -{ - return epd->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; -} - -static inline int bcm_usb_endpoint_type(const struct usb_endpoint_descriptor *epd) -{ - return epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; -} - -static inline int bcm_usb_endpoint_dir_in(const struct usb_endpoint_descriptor *epd) -{ - return ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN); -} - -static inline int bcm_usb_endpoint_dir_out(const struct usb_endpoint_descriptor *epd) -{ - return ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT); -} - -static inline int bcm_usb_endpoint_xfer_bulk(const struct usb_endpoint_descriptor *epd) -{ - return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == - USB_ENDPOINT_XFER_BULK); -} - -static inline int bcm_usb_endpoint_xfer_control(const struct usb_endpoint_descriptor *epd) -{ - return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == - USB_ENDPOINT_XFER_CONTROL); -} - -static inline int bcm_usb_endpoint_xfer_int(const struct usb_endpoint_descriptor *epd) -{ - return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == - USB_ENDPOINT_XFER_INT); -} - -static inline int bcm_usb_endpoint_xfer_isoc(const struct usb_endpoint_descriptor *epd) -{ - return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == - USB_ENDPOINT_XFER_ISOC); -} - -static inline int bcm_usb_endpoint_is_bulk_in(const struct usb_endpoint_descriptor *epd) -{ - return bcm_usb_endpoint_xfer_bulk(epd) && bcm_usb_endpoint_dir_in(epd); -} - -static inline int bcm_usb_endpoint_is_bulk_out(const struct usb_endpoint_descriptor *epd) -{ - return bcm_usb_endpoint_xfer_bulk(epd) && bcm_usb_endpoint_dir_out(epd); -} - -static inline int bcm_usb_endpoint_is_int_in(const struct usb_endpoint_descriptor *epd) -{ - return bcm_usb_endpoint_xfer_int(epd) && bcm_usb_endpoint_dir_in(epd); -} - -static inline int bcm_usb_endpoint_is_int_out(const struct usb_endpoint_descriptor *epd) -{ - return bcm_usb_endpoint_xfer_int(epd) && bcm_usb_endpoint_dir_out(epd); -} - -static inline int bcm_usb_endpoint_is_isoc_in(const struct usb_endpoint_descriptor *epd) -{ - return bcm_usb_endpoint_xfer_isoc(epd) && bcm_usb_endpoint_dir_in(epd); -} - -static inline int bcm_usb_endpoint_is_isoc_out(const struct usb_endpoint_descriptor *epd) -{ - return bcm_usb_endpoint_xfer_isoc(epd) && bcm_usb_endpoint_dir_out(epd); -} - static int InterfaceAdapterInit(struct bcm_interface_adapter *psIntfAdapter) { struct usb_host_interface *iface_desc; @@ -481,8 +406,8 @@ static int InterfaceAdapterInit(struct bcm_interface_adapter *psIntfAdapter) * If Modem is high speed device EP2 should be INT OUT End point * If Mode is FS then EP2 should be bulk end point */ - if (((psIntfAdapter->bHighSpeedDevice == TRUE) && (bcm_usb_endpoint_is_int_out(endpoint) == false)) - || ((psIntfAdapter->bHighSpeedDevice == false) && (bcm_usb_endpoint_is_bulk_out(endpoint) == false))) { + if (((psIntfAdapter->bHighSpeedDevice == TRUE) && (usb_endpoint_is_int_out(endpoint) == false)) + || ((psIntfAdapter->bHighSpeedDevice == false) && (usb_endpoint_is_bulk_out(endpoint) == false))) { BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Configuring the EEPROM\n"); /* change the EP2, EP4 to INT OUT end point */ @@ -501,7 +426,7 @@ static int InterfaceAdapterInit(struct bcm_interface_adapter *psIntfAdapter) } } - if ((psIntfAdapter->bHighSpeedDevice == false) && bcm_usb_endpoint_is_bulk_out(endpoint)) { + if ((psIntfAdapter->bHighSpeedDevice == false) && usb_endpoint_is_bulk_out(endpoint)) { /* Once BULK is selected in FS mode. Revert it back to INT. Else USB_IF will fail. */ UINT _uiData = ntohl(EP2_CFG_INT); BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, @@ -513,7 +438,7 @@ static int InterfaceAdapterInit(struct bcm_interface_adapter *psIntfAdapter) endpoint = &iface_desc->endpoint[EP4].desc; BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Choosing AltSetting as a default setting.\n"); - if (bcm_usb_endpoint_is_int_out(endpoint) == false) { + if (usb_endpoint_is_int_out(endpoint) == false) { BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Dongle does not have BCM16 Fix.\n"); /* change the EP2, EP4 to INT OUT end point and use EP4 in altsetting */ @@ -541,7 +466,7 @@ static int InterfaceAdapterInit(struct bcm_interface_adapter *psIntfAdapter) for (value = 0; value < iface_desc->desc.bNumEndpoints; ++value) { endpoint = &iface_desc->endpoint[value].desc; - if (!psIntfAdapter->sBulkIn.bulk_in_endpointAddr && bcm_usb_endpoint_is_bulk_in(endpoint)) { + if (!psIntfAdapter->sBulkIn.bulk_in_endpointAddr && usb_endpoint_is_bulk_in(endpoint)) { buffer_size = le16_to_cpu(endpoint->wMaxPacketSize); psIntfAdapter->sBulkIn.bulk_in_size = buffer_size; psIntfAdapter->sBulkIn.bulk_in_endpointAddr = endpoint->bEndpointAddress; @@ -550,14 +475,14 @@ static int InterfaceAdapterInit(struct bcm_interface_adapter *psIntfAdapter) psIntfAdapter->sBulkIn.bulk_in_endpointAddr); } - if (!psIntfAdapter->sBulkOut.bulk_out_endpointAddr && bcm_usb_endpoint_is_bulk_out(endpoint)) { + if (!psIntfAdapter->sBulkOut.bulk_out_endpointAddr && usb_endpoint_is_bulk_out(endpoint)) { psIntfAdapter->sBulkOut.bulk_out_endpointAddr = endpoint->bEndpointAddress; psIntfAdapter->sBulkOut.bulk_out_pipe = usb_sndbulkpipe(psIntfAdapter->udev, psIntfAdapter->sBulkOut.bulk_out_endpointAddr); } - if (!psIntfAdapter->sIntrIn.int_in_endpointAddr && bcm_usb_endpoint_is_int_in(endpoint)) { + if (!psIntfAdapter->sIntrIn.int_in_endpointAddr && usb_endpoint_is_int_in(endpoint)) { buffer_size = le16_to_cpu(endpoint->wMaxPacketSize); psIntfAdapter->sIntrIn.int_in_size = buffer_size; psIntfAdapter->sIntrIn.int_in_endpointAddr = endpoint->bEndpointAddress; @@ -568,7 +493,7 @@ static int InterfaceAdapterInit(struct bcm_interface_adapter *psIntfAdapter) return -EINVAL; } - if (!psIntfAdapter->sIntrOut.int_out_endpointAddr && bcm_usb_endpoint_is_int_out(endpoint)) { + if (!psIntfAdapter->sIntrOut.int_out_endpointAddr && usb_endpoint_is_int_out(endpoint)) { if (!psIntfAdapter->sBulkOut.bulk_out_endpointAddr && (psIntfAdapter->psAdapter->chip_id == T3B) && (value == usedIntOutForBulkTransfer)) { /* use first intout end point as a bulk out end point */ diff --git a/drivers/staging/bcm/Qos.c b/drivers/staging/bcm/Qos.c index 0727599bf5f..4f315835ddf 100644 --- a/drivers/staging/bcm/Qos.c +++ b/drivers/staging/bcm/Qos.c @@ -222,10 +222,7 @@ static USHORT IpVersion4(struct bcm_mini_adapter *Adapter, //Checking classifier validity if (!pstClassifierRule->bUsed || pstClassifierRule->ucDirection == DOWNLINK_DIR) - { - bClassificationSucceed = false; break; - } BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "is IPv6 check!"); if (pstClassifierRule->bIpv6Protocol) @@ -233,51 +230,47 @@ static USHORT IpVersion4(struct bcm_mini_adapter *Adapter, //**************Checking IP header parameter**************************// BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Trying to match Source IP Address"); - if (false == (bClassificationSucceed = - MatchSrcIpAddress(pstClassifierRule, iphd->saddr))) + if (!MatchSrcIpAddress(pstClassifierRule, iphd->saddr)) break; BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Source IP Address Matched"); - if (false == (bClassificationSucceed = - MatchDestIpAddress(pstClassifierRule, iphd->daddr))) + if (!MatchDestIpAddress(pstClassifierRule, iphd->daddr)) break; BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Destination IP Address Matched"); - if (false == (bClassificationSucceed = - MatchTos(pstClassifierRule, iphd->tos))) - { + if (!MatchTos(pstClassifierRule, iphd->tos)) { BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "TOS Match failed\n"); break; } BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "TOS Matched"); - if (false == (bClassificationSucceed = - MatchProtocol(pstClassifierRule, iphd->protocol))) + if (!MatchProtocol(pstClassifierRule, iphd->protocol)) break; BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Protocol Matched"); //if protocol is not TCP or UDP then no need of comparing source port and destination port - if (iphd->protocol != TCP && iphd->protocol != UDP) + if (iphd->protocol != TCP && iphd->protocol != UDP) { + bClassificationSucceed = TRUE; break; + } //******************Checking Transport Layer Header field if present *****************// BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Source Port %04x", (iphd->protocol == UDP) ? xprt_hdr->uhdr.source : xprt_hdr->thdr.source); - if (false == (bClassificationSucceed = - MatchSrcPort(pstClassifierRule, - ntohs((iphd->protocol == UDP) ? - xprt_hdr->uhdr.source : xprt_hdr->thdr.source)))) + if (!MatchSrcPort(pstClassifierRule, + ntohs((iphd->protocol == UDP) ? + xprt_hdr->uhdr.source : xprt_hdr->thdr.source))) break; BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Src Port Matched"); BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Destination Port %04x", (iphd->protocol == UDP) ? xprt_hdr->uhdr.dest : xprt_hdr->thdr.dest); - if (false == (bClassificationSucceed = - MatchDestPort(pstClassifierRule, - ntohs((iphd->protocol == UDP) ? - xprt_hdr->uhdr.dest : xprt_hdr->thdr.dest)))) + if (!MatchDestPort(pstClassifierRule, + ntohs((iphd->protocol == UDP) ? + xprt_hdr->uhdr.dest : xprt_hdr->thdr.dest))) break; + bClassificationSucceed = TRUE; } while (0); if (TRUE == bClassificationSucceed) diff --git a/drivers/staging/ced1401/usb1401.c b/drivers/staging/ced1401/usb1401.c index f441e33660f..c281fdabb4e 100644 --- a/drivers/staging/ced1401/usb1401.c +++ b/drivers/staging/ced1401/usb1401.c @@ -1054,7 +1054,6 @@ static int Handle1401Esc(DEVICE_EXTENSION *pdx, char *pCh, /* This can never happen, really */ dev_err(&pdx->interface->dev, "ERROR: DMA setup while transfer still waiting\n"); - spin_unlock(&pdx->stagedLock); } else { if ((wTransType == TM_EXTTOHOST) || (wTransType == TM_EXTTO1401)) { diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c index ac1edd9d1e2..a819e543ed3 100644 --- a/drivers/staging/comedi/comedi_fops.c +++ b/drivers/staging/comedi/comedi_fops.c @@ -1481,7 +1481,8 @@ static int do_cmd_ioctl(struct comedi_device *dev, async->cmd.data = NULL; /* load channel/gain list */ async->cmd.chanlist = memdup_user(user_chanlist, - async->cmd.chanlist_len * sizeof(int)); + async->cmd.chanlist_len * + sizeof(int)); if (IS_ERR(async->cmd.chanlist)) { ret = PTR_ERR(async->cmd.chanlist); async->cmd.chanlist = NULL; diff --git a/drivers/staging/comedi/comedidev.h b/drivers/staging/comedi/comedidev.h index f36bf3e02c4..d46123a9758 100644 --- a/drivers/staging/comedi/comedidev.h +++ b/drivers/staging/comedi/comedidev.h @@ -61,31 +61,31 @@ struct comedi_subdevice { unsigned int *chanlist; /* driver-owned chanlist (not used) */ - int (*insn_read) (struct comedi_device *, struct comedi_subdevice *, + int (*insn_read)(struct comedi_device *, struct comedi_subdevice *, + struct comedi_insn *, unsigned int *); + int (*insn_write)(struct comedi_device *, struct comedi_subdevice *, struct comedi_insn *, unsigned int *); - int (*insn_write) (struct comedi_device *, struct comedi_subdevice *, + int (*insn_bits)(struct comedi_device *, struct comedi_subdevice *, + struct comedi_insn *, unsigned int *); + int (*insn_config)(struct comedi_device *, struct comedi_subdevice *, struct comedi_insn *, unsigned int *); - int (*insn_bits) (struct comedi_device *, struct comedi_subdevice *, - struct comedi_insn *, unsigned int *); - int (*insn_config) (struct comedi_device *, struct comedi_subdevice *, - struct comedi_insn *, unsigned int *); - - int (*do_cmd) (struct comedi_device *, struct comedi_subdevice *); - int (*do_cmdtest) (struct comedi_device *, struct comedi_subdevice *, - struct comedi_cmd *); - int (*poll) (struct comedi_device *, struct comedi_subdevice *); - int (*cancel) (struct comedi_device *, struct comedi_subdevice *); + + int (*do_cmd)(struct comedi_device *, struct comedi_subdevice *); + int (*do_cmdtest)(struct comedi_device *, struct comedi_subdevice *, + struct comedi_cmd *); + int (*poll)(struct comedi_device *, struct comedi_subdevice *); + int (*cancel)(struct comedi_device *, struct comedi_subdevice *); /* int (*do_lock)(struct comedi_device *, struct comedi_subdevice *); */ /* int (*do_unlock)(struct comedi_device *, \ struct comedi_subdevice *); */ /* called when the buffer changes */ - int (*buf_change) (struct comedi_device *dev, - struct comedi_subdevice *s, unsigned long new_size); + int (*buf_change)(struct comedi_device *dev, + struct comedi_subdevice *s, unsigned long new_size); - void (*munge) (struct comedi_device *dev, struct comedi_subdevice *s, - void *data, unsigned int num_bytes, - unsigned int start_chan_index); + void (*munge)(struct comedi_device *dev, struct comedi_subdevice *s, + void *data, unsigned int num_bytes, + unsigned int start_chan_index); enum dma_data_direction async_dma_dir; unsigned int state; @@ -146,8 +146,8 @@ struct comedi_async { unsigned int cb_mask; - int (*inttrig) (struct comedi_device *dev, struct comedi_subdevice *s, - unsigned int x); + int (*inttrig)(struct comedi_device *dev, struct comedi_subdevice *s, + unsigned int x); }; struct comedi_driver { @@ -155,9 +155,9 @@ struct comedi_driver { const char *driver_name; struct module *module; - int (*attach) (struct comedi_device *, struct comedi_devconfig *); - void (*detach) (struct comedi_device *); - int (*auto_attach) (struct comedi_device *, unsigned long); + int (*attach)(struct comedi_device *, struct comedi_devconfig *); + void (*detach)(struct comedi_device *); + int (*auto_attach)(struct comedi_device *, unsigned long); /* number of elements in board_name and board_id arrays */ unsigned int num_names; @@ -202,8 +202,8 @@ struct comedi_device { struct fasync_struct *async_queue; - int (*open) (struct comedi_device *dev); - void (*close) (struct comedi_device *dev); + int (*open)(struct comedi_device *dev); + void (*close)(struct comedi_device *dev); }; static inline const void *comedi_board(const struct comedi_device *dev) diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci035.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci035.c index 8ce3335422c..80cca95c830 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci035.c +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci035.c @@ -169,9 +169,9 @@ static int i_APCI035_ConfigTimerWatchdog(struct comedi_device *dev, unsigned int *data) { struct addi_private *devpriv = dev->private; - unsigned int ui_Status = 0; - unsigned int ui_Command = 0; - unsigned int ui_Mode = 0; + unsigned int ui_Status; + unsigned int ui_Command; + unsigned int ui_Mode; i_Temp = 0; devpriv->tsk_Current = current; @@ -182,23 +182,18 @@ static int i_APCI035_ConfigTimerWatchdog(struct comedi_device *dev, else ui_Mode = 0; -/* ui_Command = inl(devpriv->iobase+((i_WatchdogNbr-1)*32)+12); */ ui_Command = 0; -/* ui_Command = ui_Command & 0xFFFFF9FEUL; */ outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); - ui_Command = 0; + ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); - /************************/ + /* Set the reload value */ - /************************/ outl(data[3], devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 4); - /*********************/ + /* Set the time unit */ - /*********************/ outl(data[2], devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 8); if (data[0] == ADDIDATA_TIMER) { - /******************************/ /* Set the mode : */ /* - Disable the hardware */ /* - Disable the counter mode */ @@ -206,101 +201,82 @@ static int i_APCI035_ConfigTimerWatchdog(struct comedi_device *dev, /* - Disable the reset */ /* - Enable the timer mode */ /* - Set the timer mode */ - /******************************/ ui_Command = (ui_Command & 0xFFF719E2UL) | ui_Mode << 13UL | 0x10UL; - } /* if (data[0] == ADDIDATA_TIMER) */ - else { - if (data[0] == ADDIDATA_WATCHDOG) { + } else if (data[0] == ADDIDATA_WATCHDOG) { - /******************************/ - /* Set the mode : */ - /* - Disable the hardware */ - /* - Disable the counter mode */ - /* - Disable the warning */ - /* - Disable the reset */ - /* - Disable the timer mode */ - /******************************/ + /* Set the mode : */ + /* - Disable the hardware */ + /* - Disable the counter mode */ + /* - Disable the warning */ + /* - Disable the reset */ + /* - Disable the timer mode */ - ui_Command = ui_Command & 0xFFF819E2UL; + ui_Command = ui_Command & 0xFFF819E2UL; - } else { - dev_err(dev->class_dev, "The parameter for Timer/watchdog selection is in error\n"); - return -EINVAL; - } + } else { + dev_err(dev->class_dev, "The parameter for Timer/watchdog selection is in error\n"); + return -EINVAL; } + outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); - ui_Command = 0; + ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); - /********************************/ + /* Disable the hardware trigger */ - /********************************/ ui_Command = ui_Command & 0xFFFFF89FUL; if (data[4] == ADDIDATA_ENABLE) { - /**********************************/ + /* Set the hardware trigger level */ - /**********************************/ ui_Command = ui_Command | (data[5] << 5); } outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); - ui_Command = 0; + ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); - /*****************************/ + /* Disable the hardware gate */ - /*****************************/ ui_Command = ui_Command & 0xFFFFF87FUL; if (data[6] == ADDIDATA_ENABLE) { - /*******************************/ + /* Set the hardware gate level */ - /*******************************/ ui_Command = ui_Command | (data[7] << 7); } outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); - ui_Command = 0; + ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); - /*******************************/ + /* Disable the hardware output */ - /*******************************/ ui_Command = ui_Command & 0xFFFFF9FBUL; - /*********************************/ + /* Set the hardware output level */ - /*********************************/ ui_Command = ui_Command | (data[8] << 2); outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); if (data[9] == ADDIDATA_ENABLE) { - /************************/ + /* Set the reload value */ - /************************/ outl(data[11], devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 24); - /**********************/ + /* Set the time unite */ - /**********************/ outl(data[10], devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 28); } - ui_Command = 0; ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); - /*******************************/ + /* Disable the hardware output */ - /*******************************/ ui_Command = ui_Command & 0xFFFFF9F7UL; - /*********************************/ + /* Set the hardware output level */ - /*********************************/ ui_Command = ui_Command | (data[12] << 3); outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); - /*************************************/ - /** Enable the watchdog interrupt **/ - /*************************************/ - ui_Command = 0; + + /* Enable the watchdog interrupt */ ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); - /*******************************/ + /* Set the interrupt selection */ - /*******************************/ ui_Status = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 16); ui_Command = (ui_Command & 0xFFFFF9FDUL) | (data[13] << 1); @@ -342,25 +318,23 @@ static int i_APCI035_StartStopWriteTimerWatchdog(struct comedi_device *dev, unsigned int *data) { struct addi_private *devpriv = dev->private; - unsigned int ui_Command = 0; - int i_Count = 0; + unsigned int ui_Command; + int i_Count; if (data[0] == 1) { ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); - /**********************/ + /* Start the hardware */ - /**********************/ ui_Command = (ui_Command & 0xFFFFF9FFUL) | 0x1UL; outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); - } /* if (data[0]==1) */ + } if (data[0] == 2) { ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); - /***************************/ + /* Set the trigger command */ - /***************************/ ui_Command = (ui_Command & 0xFFFFF9FFUL) | 0x200UL; outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); @@ -375,7 +349,7 @@ static int i_APCI035_StartStopWriteTimerWatchdog(struct comedi_device *dev, */ outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); - } /* if (data[1]==0) */ + } if (data[0] == 3) { /* stop all Watchdogs */ ui_Command = 0; @@ -459,32 +433,23 @@ static int i_APCI035_ReadTimerWatchdog(struct comedi_device *dev, unsigned int *data) { struct addi_private *devpriv = dev->private; - unsigned int ui_Status = 0; /* Status register */ + unsigned int ui_Status; /* Status register */ i_WatchdogNbr = insn->unused[0]; - /******************/ /* Get the status */ - /******************/ - ui_Status = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 16); - /***********************************/ /* Get the software trigger status */ - /***********************************/ - data[0] = ((ui_Status >> 1) & 1); - /***********************************/ + /* Get the hardware trigger status */ - /***********************************/ data[1] = ((ui_Status >> 2) & 1); - /*********************************/ + /* Get the software clear status */ - /*********************************/ data[2] = ((ui_Status >> 3) & 1); - /***************************/ + /* Get the overflow status */ - /***************************/ data[3] = ((ui_Status >> 0) & 1); if (devpriv->b_TimerSelectMode == ADDIDATA_TIMER) data[4] = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 0); @@ -525,9 +490,8 @@ static int i_APCI035_ConfigAnalogInput(struct comedi_device *dev, devpriv->tsk_Current = current; outl(0x200 | 0, devpriv->iobase + 128 + 0x4); outl(0, devpriv->iobase + 128 + 0); - /********************************/ + /* Initialise the warning value */ - /********************************/ outl(0x300 | 0, devpriv->iobase + 128 + 0x4); outl((data[0] << 8), devpriv->iobase + 128 + 0); outl(0x200000UL, devpriv->iobase + 128 + 12); @@ -562,20 +526,15 @@ static int i_APCI035_ReadAnalogInput(struct comedi_device *dev, unsigned int *data) { struct addi_private *devpriv = dev->private; - unsigned int ui_CommandRegister = 0; + unsigned int ui_CommandRegister; - /******************/ /* Set the start */ - /******************/ ui_CommandRegister = 0x80000; - /******************************/ + /* Write the command register */ - /******************************/ outl(ui_CommandRegister, devpriv->iobase + 128 + 8); - /***************************************/ /* Read the digital value of the input */ - /***************************************/ data[0] = inl(devpriv->iobase + 128 + 28); return insn->n; } @@ -598,11 +557,13 @@ static int i_APCI035_ReadAnalogInput(struct comedi_device *dev, static int i_APCI035_Reset(struct comedi_device *dev) { struct addi_private *devpriv = dev->private; - int i_Count = 0; + int i_Count; for (i_Count = 1; i_Count <= 4; i_Count++) { i_WatchdogNbr = i_Count; - outl(0x0, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 0); /* stop all timers */ + + /* stop all timers */ + outl(0x0, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 0); } outl(0x0, devpriv->iobase + 128 + 12); /* Disable the warning delay */ @@ -630,50 +591,45 @@ static void v_APCI035_Interrupt(int irq, void *d) { struct comedi_device *dev = d; struct addi_private *devpriv = dev->private; - unsigned int ui_StatusRegister1 = 0; - unsigned int ui_StatusRegister2 = 0; - unsigned int ui_ReadCommand = 0; - unsigned int ui_ChannelNumber = 0; - unsigned int ui_DigitalTemperature = 0; + unsigned int ui_StatusRegister1; + unsigned int ui_StatusRegister2; + unsigned int ui_ReadCommand; + unsigned int ui_ChannelNumber; + unsigned int ui_DigitalTemperature; if (i_Temp == 1) { i_WatchdogNbr = i_Flag; i_Flag = i_Flag + 1; } - /**************************************/ + /* Read the interrupt status register of temperature Warning */ - /**************************************/ ui_StatusRegister1 = inl(devpriv->iobase + 128 + 16); - /**************************************/ - /* Read the interrupt status register for Watchdog/timer */ - /**************************************/ + /* Read the interrupt status register for Watchdog/timer */ ui_StatusRegister2 = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 20); /* Test if warning relay interrupt */ if ((((ui_StatusRegister1) & 0x8) == 0x8)) { - /**********************************/ + /* Disable the temperature warning */ - /**********************************/ ui_ReadCommand = inl(devpriv->iobase + 128 + 12); ui_ReadCommand = ui_ReadCommand & 0xFFDF0000UL; outl(ui_ReadCommand, devpriv->iobase + 128 + 12); - /***************************/ + /* Read the channel number */ - /***************************/ ui_ChannelNumber = inl(devpriv->iobase + 128 + 60); - /**************************************/ + /* Read the digital temperature value */ - /**************************************/ ui_DigitalTemperature = inl(devpriv->iobase + 128 + 60); - send_sig(SIGIO, devpriv->tsk_Current, 0); /* send signal to the sample */ - } /* if (((ui_StatusRegister1 & 0x8) == 0x8)) */ - else { - if ((ui_StatusRegister2 & 0x1) == 0x1) - send_sig(SIGIO, devpriv->tsk_Current, 0); /* send signal to the sample */ - } /* else if (((ui_StatusRegister1 & 0x8) == 0x8)) */ + /* send signal to the sample */ + send_sig(SIGIO, devpriv->tsk_Current, 0); + + } else if ((ui_StatusRegister2 & 0x1) == 0x1) { + /* send signal to the sample */ + send_sig(SIGIO, devpriv->tsk_Current, 0); + } return; } diff --git a/drivers/staging/comedi/drivers/ke_counter.c b/drivers/staging/comedi/drivers/ke_counter.c index 1c32816e913..ec43c38958d 100644 --- a/drivers/staging/comedi/drivers/ke_counter.c +++ b/drivers/staging/comedi/drivers/ke_counter.c @@ -1,92 +1,113 @@ /* - comedi/drivers/ke_counter.c - Comedi driver for Kolter-Electronic PCI Counter 1 Card - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 2000 David A. Schleef <ds@schleef.org> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. -*/ -/* -Driver: ke_counter -Description: Driver for Kolter Electronic Counter Card -Devices: [Kolter Electronic] PCI Counter Card (ke_counter) -Author: Michael Hillmann -Updated: Mon, 14 Apr 2008 15:42:42 +0100 -Status: tested - -Configuration Options: not applicable, uses PCI auto config + * ke_counter.c + * Comedi driver for Kolter-Electronic PCI Counter 1 Card + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 2000 David A. Schleef <ds@schleef.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ -This driver is a simple driver to read the counter values from -Kolter Electronic PCI Counter Card. -*/ +/* + * Driver: ke_counter + * Description: Driver for Kolter Electronic Counter Card + * Devices: (Kolter Electronic) PCI Counter Card [ke_counter] + * Author: Michael Hillmann + * Updated: Mon, 14 Apr 2008 15:42:42 +0100 + * Status: tested + * + * Configuration Options: not applicable, uses PCI auto config + */ #include <linux/module.h> #include <linux/pci.h> #include "../comedidev.h" -#define CNT_CARD_DEVICE_ID 0x0014 +/* + * PCI BAR 0 Register I/O map + */ +#define KE_RESET_REG(x) (0x00 + ((x) * 0x20)) +#define KE_LATCH_REG(x) (0x00 + ((x) * 0x20)) +#define KE_LSB_REG(x) (0x04 + ((x) * 0x20)) +#define KE_MID_REG(x) (0x08 + ((x) * 0x20)) +#define KE_MSB_REG(x) (0x0c + ((x) * 0x20)) +#define KE_SIGN_REG(x) (0x10 + ((x) * 0x20)) +#define KE_OSC_SEL_REG 0xf8 +#define KE_OSC_SEL_EXT (1 << 0) +#define KE_OSC_SEL_4MHZ (2 << 0) +#define KE_OSC_SEL_20MHZ (3 << 0) +#define KE_DO_REG 0xfc + +static int ke_counter_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int val; + int i; + + for (i = 0; i < insn->n; i++) { + val = data[0]; -/*-- counter write ----------------------------------------------------------*/ + /* Order matters */ + outb((val >> 24) & 0xff, dev->iobase + KE_SIGN_REG(chan)); + outb((val >> 16) & 0xff, dev->iobase + KE_MSB_REG(chan)); + outb((val >> 8) & 0xff, dev->iobase + KE_MID_REG(chan)); + outb((val >> 0) & 0xff, dev->iobase + KE_LSB_REG(chan)); + } -/* This should be used only for resetting the counters; maybe it is better - to make a special command 'reset'. */ -static int cnt_winsn(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data) -{ - int chan = CR_CHAN(insn->chanspec); - - outb((unsigned char)((data[0] >> 24) & 0xff), - dev->iobase + chan * 0x20 + 0x10); - outb((unsigned char)((data[0] >> 16) & 0xff), - dev->iobase + chan * 0x20 + 0x0c); - outb((unsigned char)((data[0] >> 8) & 0xff), - dev->iobase + chan * 0x20 + 0x08); - outb((unsigned char)((data[0] >> 0) & 0xff), - dev->iobase + chan * 0x20 + 0x04); - - /* return the number of samples written */ - return 1; + return insn->n; } -/*-- counter read -----------------------------------------------------------*/ - -static int cnt_rinsn(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data) +static int ke_counter_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - unsigned char a0, a1, a2, a3, a4; - int chan = CR_CHAN(insn->chanspec); - int result; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int val; + int i; - a0 = inb(dev->iobase + chan * 0x20); - a1 = inb(dev->iobase + chan * 0x20 + 0x04); - a2 = inb(dev->iobase + chan * 0x20 + 0x08); - a3 = inb(dev->iobase + chan * 0x20 + 0x0c); - a4 = inb(dev->iobase + chan * 0x20 + 0x10); + for (i = 0; i < insn->n; i++) { + /* Order matters */ + inb(dev->iobase + KE_LATCH_REG(chan)); - result = (a1 + (a2 * 256) + (a3 * 65536)); - if (a4 > 0) - result = result - s->maxdata; + val = inb(dev->iobase + KE_LSB_REG(chan)); + val |= (inb(dev->iobase + KE_MID_REG(chan)) << 8); + val |= (inb(dev->iobase + KE_MSB_REG(chan)) << 16); + val |= (inb(dev->iobase + KE_SIGN_REG(chan)) << 24); - *data = (unsigned int)result; + data[i] = val; + } - /* return the number of samples read */ - return 1; + return insn->n; } -static int cnt_auto_attach(struct comedi_device *dev, - unsigned long context_unused) +static int ke_counter_do_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + if (comedi_dio_update_state(s, data)) + outb(s->state, dev->iobase + KE_DO_REG); + + data[1] = s->state; + + return insn->n; +} + +static int ke_counter_auto_attach(struct comedi_device *dev, + unsigned long context_unused) { struct pci_dev *pcidev = comedi_to_pci_dev(dev); struct comedi_subdevice *s; @@ -97,27 +118,32 @@ static int cnt_auto_attach(struct comedi_device *dev, return ret; dev->iobase = pci_resource_start(pcidev, 0); - ret = comedi_alloc_subdevices(dev, 1); + ret = comedi_alloc_subdevices(dev, 2); if (ret) return ret; s = &dev->subdevices[0]; - dev->read_subdev = s; - - s->type = COMEDI_SUBD_COUNTER; - s->subdev_flags = SDF_READABLE /* | SDF_COMMON */ ; - s->n_chan = 3; - s->maxdata = 0x00ffffff; - s->insn_read = cnt_rinsn; - s->insn_write = cnt_winsn; - - /* select 20MHz clock */ - outb(3, dev->iobase + 248); - - /* reset all counters */ - outb(0, dev->iobase); - outb(0, dev->iobase + 0x20); - outb(0, dev->iobase + 0x40); + s->type = COMEDI_SUBD_COUNTER; + s->subdev_flags = SDF_READABLE; + s->n_chan = 3; + s->maxdata = 0x01ffffff; + s->range_table = &range_unknown; + s->insn_read = ke_counter_insn_read; + s->insn_write = ke_counter_insn_write; + + s = &dev->subdevices[1]; + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = 3; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = ke_counter_do_insn_bits; + + outb(KE_OSC_SEL_20MHZ, dev->iobase + KE_OSC_SEL_REG); + + outb(0, dev->iobase + KE_RESET_REG(0)); + outb(0, dev->iobase + KE_RESET_REG(1)); + outb(0, dev->iobase + KE_RESET_REG(2)); return 0; } @@ -125,7 +151,7 @@ static int cnt_auto_attach(struct comedi_device *dev, static struct comedi_driver ke_counter_driver = { .driver_name = "ke_counter", .module = THIS_MODULE, - .auto_attach = cnt_auto_attach, + .auto_attach = ke_counter_auto_attach, .detach = comedi_pci_disable, }; @@ -137,7 +163,7 @@ static int ke_counter_pci_probe(struct pci_dev *dev, } static const struct pci_device_id ke_counter_pci_table[] = { - { PCI_DEVICE(PCI_VENDOR_ID_KOLTER, CNT_CARD_DEVICE_ID) }, + { PCI_DEVICE(PCI_VENDOR_ID_KOLTER, 0x0014) }, { 0 } }; MODULE_DEVICE_TABLE(pci, ke_counter_pci_table); @@ -151,5 +177,5 @@ static struct pci_driver ke_counter_pci_driver = { module_comedi_pci_driver(ke_counter_driver, ke_counter_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_DESCRIPTION("Comedi driver for Kolter Electronic Counter Card"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/ni_mio_common.c b/drivers/staging/comedi/drivers/ni_mio_common.c index 8adb535516b..3a86d482bab 100644 --- a/drivers/staging/comedi/drivers/ni_mio_common.c +++ b/drivers/staging/comedi/drivers/ni_mio_common.c @@ -4407,6 +4407,9 @@ static int ni_E_init(struct comedi_device *dev) &ni_gpct_read_register, counter_variant, NUM_GPCT); + if (!devpriv->counter_dev) + return -ENOMEM; + /* General purpose counters */ for (j = 0; j < NUM_GPCT; ++j) { s = &dev->subdevices[NI_GPCT_SUBDEV(j)]; diff --git a/drivers/staging/cxt1e1/comet_tables.c b/drivers/staging/cxt1e1/comet_tables.c index 84931117da3..e96665ea366 100644 --- a/drivers/staging/cxt1e1/comet_tables.c +++ b/drivers/staging/cxt1e1/comet_tables.c @@ -19,6 +19,7 @@ */ #include <linux/types.h> +#include "comet_tables.h" /***************************************************************************** * diff --git a/drivers/staging/cxt1e1/functions.c b/drivers/staging/cxt1e1/functions.c index f5ce8529b4a..40dbe2c623c 100644 --- a/drivers/staging/cxt1e1/functions.c +++ b/drivers/staging/cxt1e1/functions.c @@ -25,7 +25,8 @@ #include "pmcc4.h" #if defined(CONFIG_SBE_HDLC_V7) || defined(CONFIG_SBE_WAN256T3_HDLC_V7) || \ - defined(CONFIG_SBE_HDLC_V7_MODULE) || defined(CONFIG_SBE_WAN256T3_HDLC_V7_MODULE) +defined(CONFIG_SBE_HDLC_V7_MODULE) || \ +defined(CONFIG_SBE_WAN256T3_HDLC_V7_MODULE) #define _v7_hdlc_ 1 #else #define _v7_hdlc_ 0 @@ -33,9 +34,9 @@ #if _v7_hdlc_ #define V7(x) (x ## _v7) -extern int hdlc_netif_rx_v7 (hdlc_device *, struct sk_buff *); -extern int register_hdlc_device_v7 (hdlc_device *); -extern int unregister_hdlc_device_v7 (hdlc_device *); +extern int hdlc_netif_rx_v7(hdlc_device *, struct sk_buff *); +extern int register_hdlc_device_v7(hdlc_device *); +extern int unregister_hdlc_device_v7(hdlc_device *); #else #define V7(x) x @@ -53,49 +54,49 @@ extern int drvr_state; #if 1 u_int32_t -pci_read_32 (u_int32_t *p) +pci_read_32(u_int32_t *p) { #ifdef FLOW_DEBUG - u_int32_t v; + u_int32_t v; - FLUSH_PCI_READ (); - v = le32_to_cpu (*p); - if (cxt1e1_log_level >= LOG_DEBUG) - pr_info("pci_read : %x = %x\n", (u_int32_t) p, v); - return v; + FLUSH_PCI_READ(); + v = le32_to_cpu(*p); + if (cxt1e1_log_level >= LOG_DEBUG) + pr_info("pci_read : %x = %x\n", (u_int32_t) p, v); + return v; #else - FLUSH_PCI_READ (); /* */ - return le32_to_cpu (*p); + FLUSH_PCI_READ(); /* */ + return le32_to_cpu(*p); #endif } void -pci_write_32 (u_int32_t *p, u_int32_t v) +pci_write_32(u_int32_t *p, u_int32_t v) { #ifdef FLOW_DEBUG - if (cxt1e1_log_level >= LOG_DEBUG) - pr_info("pci_write: %x = %x\n", (u_int32_t) p, v); + if (cxt1e1_log_level >= LOG_DEBUG) + pr_info("pci_write: %x = %x\n", (u_int32_t) p, v); #endif - *p = cpu_to_le32 (v); - FLUSH_PCI_WRITE (); /* This routine is called from routines - * which do multiple register writes - * which themselves need flushing between - * writes in order to guarantee write - * ordering. It is less code-cumbersome - * to flush here-in then to investigate - * and code the many other register - * writing routines. */ + *p = cpu_to_le32 (v); + FLUSH_PCI_WRITE(); /* This routine is called from routines + * which do multiple register writes + * which themselves need flushing between + * writes in order to guarantee write + * ordering. It is less code-cumbersome + * to flush here-in then to investigate + * and code the many other register + * writing routines. */ } #endif void -pci_flush_write (ci_t *ci) +pci_flush_write(ci_t *ci) { - volatile u_int32_t v; + volatile u_int32_t v; /* issue a PCI read to flush PCI write thru bridge */ - v = *(u_int32_t *) &ci->reg->glcd; /* any address would do */ + v = *(u_int32_t *) &ci->reg->glcd; /* any address would do */ /* * return nothing, this just reads PCI bridge interface to flush @@ -105,55 +106,53 @@ pci_flush_write (ci_t *ci) static void -watchdog_func (unsigned long arg) +watchdog_func(unsigned long arg) { - struct watchdog *wd = (void *) arg; - - if (drvr_state != SBE_DRVR_AVAILABLE) - { - if (cxt1e1_log_level >= LOG_MONITOR) - pr_warning("%s: drvr not available (%x)\n", __func__, drvr_state); - return; - } - schedule_work (&wd->work); - mod_timer (&wd->h, jiffies + wd->ticks); + struct watchdog *wd = (void *) arg; + + if (drvr_state != SBE_DRVR_AVAILABLE) { + if (cxt1e1_log_level >= LOG_MONITOR) + pr_warning("%s: drvr not available (%x)\n", + __func__, drvr_state); + return; + } + schedule_work(&wd->work); + mod_timer(&wd->h, jiffies + wd->ticks); } -int OS_init_watchdog(struct watchdog *wdp, void (*f) (void *), void *c, int usec) +int OS_init_watchdog(struct watchdog *wdp, void (*f) (void *), + void *c, int usec) { - wdp->func = f; - wdp->softc = c; - wdp->ticks = (HZ) * (usec / 1000) / 1000; - INIT_WORK(&wdp->work, (void *)f); - init_timer (&wdp->h); - { - ci_t *ci = (ci_t *) c; - - wdp->h.data = (unsigned long) &ci->wd; - } - wdp->h.function = watchdog_func; - return 0; + wdp->func = f; + wdp->softc = c; + wdp->ticks = (HZ) * (usec / 1000) / 1000; + INIT_WORK(&wdp->work, (void *)f); + init_timer(&wdp->h); + { + ci_t *ci = (ci_t *) c; + + wdp->h.data = (unsigned long) &ci->wd; + } + wdp->h.function = watchdog_func; + return 0; } void -OS_uwait (int usec, char *description) +OS_uwait(int usec, char *description) { - int tmp; - - if (usec >= 1000) - { - mdelay (usec / 1000); - /* now delay residual */ - tmp = (usec / 1000) * 1000; /* round */ - tmp = usec - tmp; /* residual */ - if (tmp) - { /* wait on residual */ - udelay (tmp); - } - } else - { - udelay (usec); - } + int tmp; + + if (usec >= 1000) { + mdelay(usec / 1000); + /* now delay residual */ + tmp = (usec / 1000) * 1000; /* round */ + tmp = usec - tmp; /* residual */ + if (tmp) { /* wait on residual */ + udelay(tmp); + } + } else { + udelay(usec); + } } /* dummy short delay routine called as a subroutine so that compiler @@ -161,96 +160,95 @@ OS_uwait (int usec, char *description) */ void -OS_uwait_dummy (void) +OS_uwait_dummy(void) { #ifndef USE_MAX_INT_DELAY - dummy++; + dummy++; #else - udelay (1); + udelay(1); #endif } void -OS_sem_init (void *sem, int state) +OS_sem_init(void *sem, int state) { - switch (state) - { - case SEM_TAKEN: - sema_init((struct semaphore *) sem, 0); - break; - case SEM_AVAILABLE: + switch (state) { + case SEM_TAKEN: + sema_init((struct semaphore *) sem, 0); + break; + case SEM_AVAILABLE: sema_init((struct semaphore *) sem, 1); - break; - default: /* otherwise, set sem.count to state's - * value */ - sema_init (sem, state); - break; - } + break; + default: /* otherwise, set sem.count to state's + * value */ + sema_init(sem, state); + break; + } } int -sd_line_is_ok (void *user) +sd_line_is_ok(void *user) { - struct net_device *ndev = (struct net_device *) user; + struct net_device *ndev = (struct net_device *) user; - return netif_carrier_ok (ndev); + return netif_carrier_ok(ndev); } void -sd_line_is_up (void *user) +sd_line_is_up(void *user) { - struct net_device *ndev = (struct net_device *) user; + struct net_device *ndev = (struct net_device *) user; - netif_carrier_on (ndev); - return; + netif_carrier_on(ndev); + return; } void -sd_line_is_down (void *user) +sd_line_is_down(void *user) { - struct net_device *ndev = (struct net_device *) user; + struct net_device *ndev = (struct net_device *) user; - netif_carrier_off (ndev); - return; + netif_carrier_off(ndev); + return; } void -sd_disable_xmit (void *user) +sd_disable_xmit(void *user) { - struct net_device *dev = (struct net_device *) user; + struct net_device *dev = (struct net_device *) user; - netif_stop_queue (dev); - return; + netif_stop_queue(dev); + return; } void -sd_enable_xmit (void *user) +sd_enable_xmit(void *user) { - struct net_device *dev = (struct net_device *) user; + struct net_device *dev = (struct net_device *) user; - netif_wake_queue (dev); - return; + netif_wake_queue(dev); + return; } int -sd_queue_stopped (void *user) +sd_queue_stopped(void *user) { - struct net_device *ndev = (struct net_device *) user; + struct net_device *ndev = (struct net_device *) user; - return netif_queue_stopped (ndev); + return netif_queue_stopped(ndev); } void sd_recv_consume(void *token, size_t len, void *user) { - struct net_device *ndev = user; - struct sk_buff *skb = token; + struct net_device *ndev = user; + struct sk_buff *skb = token; - skb->dev = ndev; - skb_put (skb, len); - skb->protocol = hdlc_type_trans(skb, ndev); - netif_rx(skb); + skb->dev = ndev; + skb_put(skb, len); + skb->protocol = hdlc_type_trans(skb, ndev); + netif_rx(skb); } @@ -263,77 +261,76 @@ void sd_recv_consume(void *token, size_t len, void *user) extern ci_t *CI; /* dummy pointer to board ZERO's data */ void -VMETRO_TRIGGER (ci_t *ci, int x) +VMETRO_TRIGGER(ci_t *ci, int x) { - struct s_comet_reg *comet; - volatile u_int32_t data; - - comet = ci->port[0].cometbase; /* default to COMET # 0 */ - - switch (x) - { - default: - case 0: - data = pci_read_32 ((u_int32_t *) &comet->__res24); /* 0x90 */ - break; - case 1: - data = pci_read_32 ((u_int32_t *) &comet->__res25); /* 0x94 */ - break; - case 2: - data = pci_read_32 ((u_int32_t *) &comet->__res26); /* 0x98 */ - break; - case 3: - data = pci_read_32 ((u_int32_t *) &comet->__res27); /* 0x9C */ - break; - case 4: - data = pci_read_32 ((u_int32_t *) &comet->__res88); /* 0x220 */ - break; - case 5: - data = pci_read_32 ((u_int32_t *) &comet->__res89); /* 0x224 */ - break; - case 6: - data = pci_read_32 ((u_int32_t *) &comet->__res8A); /* 0x228 */ - break; - case 7: - data = pci_read_32 ((u_int32_t *) &comet->__res8B); /* 0x22C */ - break; - case 8: - data = pci_read_32 ((u_int32_t *) &comet->__resA0); /* 0x280 */ - break; - case 9: - data = pci_read_32 ((u_int32_t *) &comet->__resA1); /* 0x284 */ - break; - case 10: - data = pci_read_32 ((u_int32_t *) &comet->__resA2); /* 0x288 */ - break; - case 11: - data = pci_read_32 ((u_int32_t *) &comet->__resA3); /* 0x28C */ - break; - case 12: - data = pci_read_32 ((u_int32_t *) &comet->__resA4); /* 0x290 */ - break; - case 13: - data = pci_read_32 ((u_int32_t *) &comet->__resA5); /* 0x294 */ - break; - case 14: - data = pci_read_32 ((u_int32_t *) &comet->__resA6); /* 0x298 */ - break; - case 15: - data = pci_read_32 ((u_int32_t *) &comet->__resA7); /* 0x29C */ - break; - case 16: - data = pci_read_32 ((u_int32_t *) &comet->__res74); /* 0x1D0 */ - break; - case 17: - data = pci_read_32 ((u_int32_t *) &comet->__res75); /* 0x1D4 */ - break; - case 18: - data = pci_read_32 ((u_int32_t *) &comet->__res76); /* 0x1D8 */ - break; - case 19: - data = pci_read_32 ((u_int32_t *) &comet->__res77); /* 0x1DC */ - break; - } + struct s_comet_reg *comet; + volatile u_int32_t data; + + comet = ci->port[0].cometbase; /* default to COMET # 0 */ + + switch (x) { + default: + case 0: + data = pci_read_32((u_int32_t *) &comet->__res24); /* 0x90 */ + break; + case 1: + data = pci_read_32((u_int32_t *) &comet->__res25); /* 0x94 */ + break; + case 2: + data = pci_read_32((u_int32_t *) &comet->__res26); /* 0x98 */ + break; + case 3: + data = pci_read_32((u_int32_t *) &comet->__res27); /* 0x9C */ + break; + case 4: + data = pci_read_32((u_int32_t *) &comet->__res88); /* 0x220 */ + break; + case 5: + data = pci_read_32((u_int32_t *) &comet->__res89); /* 0x224 */ + break; + case 6: + data = pci_read_32((u_int32_t *) &comet->__res8A); /* 0x228 */ + break; + case 7: + data = pci_read_32((u_int32_t *) &comet->__res8B); /* 0x22C */ + break; + case 8: + data = pci_read_32((u_int32_t *) &comet->__resA0); /* 0x280 */ + break; + case 9: + data = pci_read_32((u_int32_t *) &comet->__resA1); /* 0x284 */ + break; + case 10: + data = pci_read_32((u_int32_t *) &comet->__resA2); /* 0x288 */ + break; + case 11: + data = pci_read_32((u_int32_t *) &comet->__resA3); /* 0x28C */ + break; + case 12: + data = pci_read_32((u_int32_t *) &comet->__resA4); /* 0x290 */ + break; + case 13: + data = pci_read_32((u_int32_t *) &comet->__resA5); /* 0x294 */ + break; + case 14: + data = pci_read_32((u_int32_t *) &comet->__resA6); /* 0x298 */ + break; + case 15: + data = pci_read_32((u_int32_t *) &comet->__resA7); /* 0x29C */ + break; + case 16: + data = pci_read_32((u_int32_t *) &comet->__res74); /* 0x1D0 */ + break; + case 17: + data = pci_read_32((u_int32_t *) &comet->__res75); /* 0x1D4 */ + break; + case 18: + data = pci_read_32((u_int32_t *) &comet->__res76); /* 0x1D8 */ + break; + case 19: + data = pci_read_32((u_int32_t *) &comet->__res77); /* 0x1DC */ + break; + } } diff --git a/drivers/staging/cxt1e1/hwprobe.c b/drivers/staging/cxt1e1/hwprobe.c index 02b4f8f1aca..d87a011360b 100644 --- a/drivers/staging/cxt1e1/hwprobe.c +++ b/drivers/staging/cxt1e1/hwprobe.c @@ -36,355 +36,354 @@ extern int error_flag; extern int drvr_state; /* forward references */ -void c4_stopwd (ci_t *); -struct net_device * __init c4_add_dev (hdw_info_t *, int, unsigned long, unsigned long, int, int); +void c4_stopwd(ci_t *); +struct net_device * __init c4_add_dev(hdw_info_t *, int, unsigned long, + unsigned long, int, int); struct s_hdw_info hdw_info[MAX_BOARDS]; -void __init -show_two (hdw_info_t *hi, int brdno) +void __init +show_two(hdw_info_t *hi, int brdno) { - ci_t *ci; - struct pci_dev *pdev; - char *bid; - char *bp, banner[80]; - char sn[6]; - - bp = banner; - memset (banner, 0, 80); /* clear print buffer */ - - ci = (ci_t *)(netdev_priv(hi->ndev)); - bid = sbeid_get_bdname (ci); - switch (hi->promfmt) - { - case PROM_FORMAT_TYPE1: - memcpy (sn, (FLD_TYPE1 *) (hi->mfg_info.pft1.Serial), 6); - break; - case PROM_FORMAT_TYPE2: - memcpy (sn, (FLD_TYPE2 *) (hi->mfg_info.pft2.Serial), 6); - break; - default: - memset (sn, 0, 6); - break; - } - - sprintf (banner, "%s: %s S/N %06X, MUSYCC Rev %02X", - hi->devname, bid, - ((sn[3] << 16) & 0xff0000) | - ((sn[4] << 8) & 0x00ff00) | - (sn[5] & 0x0000ff), - (u_int8_t) hi->revid[0]); - - pr_info("%s\n", banner); - - pdev = hi->pdev[0]; - pr_info("%s: %s at v/p=%lx/%lx (%02x:%02x.%x) irq %d\n", - hi->devname, "MUSYCC", - (unsigned long) hi->addr_mapped[0], hi->addr[0], - hi->pci_busno, (u_int8_t) PCI_SLOT (pdev->devfn), - (u_int8_t) PCI_FUNC (pdev->devfn), pdev->irq); - - pdev = hi->pdev[1]; - pr_info("%s: %s at v/p=%lx/%lx (%02x:%02x.%x) irq %d\n", - hi->devname, "EBUS ", - (unsigned long) hi->addr_mapped[1], hi->addr[1], - hi->pci_busno, (u_int8_t) PCI_SLOT (pdev->devfn), - (u_int8_t) PCI_FUNC (pdev->devfn), pdev->irq); + ci_t *ci; + struct pci_dev *pdev; + char *bid; + char banner[80]; + char sn[6]; + + /* clear print buffer */ + memset(banner, 0, 80); + + ci = (ci_t *)(netdev_priv(hi->ndev)); + bid = sbeid_get_bdname(ci); + switch (hi->promfmt) { + case PROM_FORMAT_TYPE1: + memcpy(sn, (FLD_TYPE1 *)(hi->mfg_info.pft1.Serial), 6); + break; + case PROM_FORMAT_TYPE2: + memcpy(sn, (FLD_TYPE2 *)(hi->mfg_info.pft2.Serial), 6); + break; + default: + memset(sn, 0, 6); + break; + } + + sprintf(banner, "%s: %s S/N %06X, MUSYCC Rev %02X", + hi->devname, bid, + ((sn[3] << 16) & 0xff0000) | + ((sn[4] << 8) & 0x00ff00) | + (sn[5] & 0x0000ff), + (u_int8_t) hi->revid[0]); + + pr_info("%s\n", banner); + + pdev = hi->pdev[0]; + pr_info("%s: %s at v/p=%lx/%lx (%02x:%02x.%x) irq %d\n", + hi->devname, "MUSYCC", + (unsigned long) hi->addr_mapped[0], hi->addr[0], + hi->pci_busno, (u_int8_t) PCI_SLOT(pdev->devfn), + (u_int8_t) PCI_FUNC(pdev->devfn), pdev->irq); + + pdev = hi->pdev[1]; + pr_info("%s: %s at v/p=%lx/%lx (%02x:%02x.%x) irq %d\n", + hi->devname, "EBUS ", + (unsigned long) hi->addr_mapped[1], hi->addr[1], + hi->pci_busno, (u_int8_t) PCI_SLOT(pdev->devfn), + (u_int8_t) PCI_FUNC(pdev->devfn), pdev->irq); } -void __init -hdw_sn_get (hdw_info_t *hi, int brdno) +void __init +hdw_sn_get(hdw_info_t *hi, int brdno) { - /* obtain hardware EEPROM information */ - long addr; + /* obtain hardware EEPROM information */ + long addr; - addr = (long) hi->addr_mapped[1] + EEPROM_OFFSET; + addr = (long) hi->addr_mapped[1] + EEPROM_OFFSET; - /* read EEPROM with largest known format size... */ - pmc_eeprom_read_buffer (addr, 0, (char *) hi->mfg_info.data, sizeof (FLD_TYPE2)); + /* read EEPROM with largest known format size... */ + pmc_eeprom_read_buffer(addr, 0, (char *)hi->mfg_info.data, + sizeof(FLD_TYPE2)); #if 0 - { - unsigned char *ucp = (unsigned char *) &hi->mfg_info.data; - - pr_info("eeprom[00]: %02x %02x %02x %02x %02x %02x %02x %02x\n", - *(ucp + 0), *(ucp + 1), *(ucp + 2), *(ucp + 3), *(ucp + 4), *(ucp + 5), *(ucp + 6), *(ucp + 7)); - pr_info("eeprom[08]: %02x %02x %02x %02x %02x %02x %02x %02x\n", - *(ucp + 8), *(ucp + 9), *(ucp + 10), *(ucp + 11), *(ucp + 12), *(ucp + 13), *(ucp + 14), *(ucp + 15)); - pr_info("eeprom[16]: %02x %02x %02x %02x %02x %02x %02x %02x\n", - *(ucp + 16), *(ucp + 17), *(ucp + 18), *(ucp + 19), *(ucp + 20), *(ucp + 21), *(ucp + 22), *(ucp + 23)); - pr_info("eeprom[24]: %02x %02x %02x %02x %02x %02x %02x %02x\n", - *(ucp + 24), *(ucp + 25), *(ucp + 26), *(ucp + 27), *(ucp + 28), *(ucp + 29), *(ucp + 30), *(ucp + 31)); - pr_info("eeprom[32]: %02x %02x %02x %02x %02x %02x %02x %02x\n", - *(ucp + 32), *(ucp + 33), *(ucp + 34), *(ucp + 35), *(ucp + 36), *(ucp + 37), *(ucp + 38), *(ucp + 39)); - pr_info("eeprom[40]: %02x %02x %02x %02x %02x %02x %02x %02x\n", - *(ucp + 40), *(ucp + 41), *(ucp + 42), *(ucp + 43), *(ucp + 44), *(ucp + 45), *(ucp + 46), *(ucp + 47)); - } + { + unsigned char *ucp = (unsigned char *) &hi->mfg_info.data; + + pr_info("eeprom[00]: %02x %02x %02x %02x %02x %02x %02x %02x\n", + *(ucp + 0), *(ucp + 1), *(ucp + 2), *(ucp + 3), + *(ucp + 4), *(ucp + 5), *(ucp + 6), *(ucp + 7)); + pr_info("eeprom[08]: %02x %02x %02x %02x %02x %02x %02x %02x\n", + *(ucp + 8), *(ucp + 9), *(ucp + 10), *(ucp + 11), + *(ucp + 12), *(ucp + 13), *(ucp + 14), *(ucp + 15)); + pr_info("eeprom[16]: %02x %02x %02x %02x %02x %02x %02x %02x\n", + *(ucp + 16), *(ucp + 17), *(ucp + 18), *(ucp + 19), + *(ucp + 20), *(ucp + 21), *(ucp + 22), *(ucp + 23)); + pr_info("eeprom[24]: %02x %02x %02x %02x %02x %02x %02x %02x\n", + *(ucp + 24), *(ucp + 25), *(ucp + 26), *(ucp + 27), + *(ucp + 28), *(ucp + 29), *(ucp + 30), *(ucp + 31)); + pr_info("eeprom[32]: %02x %02x %02x %02x %02x %02x %02x %02x\n", + *(ucp + 32), *(ucp + 33), *(ucp + 34), *(ucp + 35), + *(ucp + 36), *(ucp + 37), *(ucp + 38), *(ucp + 39)); + pr_info("eeprom[40]: %02x %02x %02x %02x %02x %02x %02x %02x\n", + *(ucp + 40), *(ucp + 41), *(ucp + 42), *(ucp + 43), + *(ucp + 44), *(ucp + 45), *(ucp + 46), *(ucp + 47)); + } #endif #if 0 - pr_info("sn: %x %x %x %x %x %x\n", - hi->mfg_info.Serial[0], - hi->mfg_info.Serial[1], - hi->mfg_info.Serial[2], - hi->mfg_info.Serial[3], - hi->mfg_info.Serial[4], - hi->mfg_info.Serial[5]); + pr_info("sn: %x %x %x %x %x %x\n", + hi->mfg_info.Serial[0], + hi->mfg_info.Serial[1], + hi->mfg_info.Serial[2], + hi->mfg_info.Serial[3], + hi->mfg_info.Serial[4], + hi->mfg_info.Serial[5]); #endif - if ((hi->promfmt = pmc_verify_cksum (&hi->mfg_info.data)) == PROM_FORMAT_Unk) - { - /* bad crc, data is suspect */ - if (cxt1e1_log_level >= LOG_WARN) - pr_info("%s: EEPROM cksum error\n", hi->devname); - hi->mfg_info_sts = EEPROM_CRCERR; - } else - hi->mfg_info_sts = EEPROM_OK; + hi->promfmt = pmc_verify_cksum(&hi->mfg_info.data); + if (hi->promfmt == PROM_FORMAT_Unk) { + /* bad crc, data is suspect */ + if (cxt1e1_log_level >= LOG_WARN) + pr_info("%s: EEPROM cksum error\n", hi->devname); + hi->mfg_info_sts = EEPROM_CRCERR; + } else + hi->mfg_info_sts = EEPROM_OK; } -void __init -prep_hdw_info (void) + void __init +prep_hdw_info(void) { - hdw_info_t *hi; - int i; - - for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++) - { - hi->pci_busno = 0xff; - hi->pci_slot = 0xff; - hi->pci_pin[0] = 0; - hi->pci_pin[1] = 0; - hi->ndev = NULL; - hi->addr[0] = 0L; - hi->addr[1] = 0L; - hi->addr_mapped[0] = 0L; - hi->addr_mapped[1] = 0L; - } + hdw_info_t *hi; + int i; + + for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++) { + hi->pci_busno = 0xff; + hi->pci_slot = 0xff; + hi->pci_pin[0] = 0; + hi->pci_pin[1] = 0; + hi->ndev = NULL; + hi->addr[0] = 0L; + hi->addr[1] = 0L; + hi->addr_mapped[0] = 0L; + hi->addr_mapped[1] = 0L; + } } void -cleanup_ioremap (void) +cleanup_ioremap(void) { - hdw_info_t *hi; - int i; - - for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++) - { - if (hi->pci_slot == 0xff) - break; - if (hi->addr_mapped[0]) - { - iounmap ((void *) (hi->addr_mapped[0])); - release_mem_region ((long) hi->addr[0], hi->len[0]); - hi->addr_mapped[0] = 0; - } - if (hi->addr_mapped[1]) - { - iounmap ((void *) (hi->addr_mapped[1])); - release_mem_region ((long) hi->addr[1], hi->len[1]); - hi->addr_mapped[1] = 0; - } - } + hdw_info_t *hi; + int i; + + for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++) { + if (hi->pci_slot == 0xff) + break; + if (hi->addr_mapped[0]) { + iounmap((void *)(hi->addr_mapped[0])); + release_mem_region((long) hi->addr[0], hi->len[0]); + hi->addr_mapped[0] = 0; + } + if (hi->addr_mapped[1]) { + iounmap((void *)(hi->addr_mapped[1])); + release_mem_region((long) hi->addr[1], hi->len[1]); + hi->addr_mapped[1] = 0; + } + } } void -cleanup_devs (void) +cleanup_devs(void) { - hdw_info_t *hi; - int i; - - for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++) - { - if (hi->pci_slot == 0xff || !hi->ndev) - break; - c4_stopwd(netdev_priv(hi->ndev)); + hdw_info_t *hi; + int i; + + for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++) { + if (hi->pci_slot == 0xff || !hi->ndev) + break; + c4_stopwd(netdev_priv(hi->ndev)); #ifdef CONFIG_PROC_FS - sbecom_proc_brd_cleanup(netdev_priv(hi->ndev)); + sbecom_proc_brd_cleanup(netdev_priv(hi->ndev)); #endif - unregister_netdev (hi->ndev); - free_irq (hi->pdev[0]->irq, hi->ndev); + unregister_netdev(hi->ndev); + free_irq(hi->pdev[0]->irq, hi->ndev); #ifdef CONFIG_SBE_PMCC4_NCOMM - free_irq (hi->pdev[1]->irq, hi->ndev); + free_irq(hi->pdev[1]->irq, hi->ndev); #endif - OS_kfree (hi->ndev); - } + OS_kfree(hi->ndev); + } } static int __init -c4_hdw_init (struct pci_dev *pdev, int found) +c4_hdw_init(struct pci_dev *pdev, int found) { - hdw_info_t *hi; - int i; - int fun, slot; - unsigned char busno = 0xff; - - /* our MUSYCC chip supports two functions, 0 & 1 */ - if ((fun = PCI_FUNC (pdev->devfn)) > 1) - { - pr_warning("unexpected devfun: 0x%x\n", pdev->devfn); - return 0; - } - if (pdev->bus) /* obtain bus number */ - busno = pdev->bus->number; - else - busno = 0; /* default for system PCI inconsistency */ - slot = pdev->devfn & ~0x07; - - /* - * Functions 0 & 1 for a given board (identified by same bus(busno) and - * slot(slot)) are placed into the same 'hardware' structure. The first - * part of the board's functionality will be placed into an unpopulated - * element, identified by "slot==(0xff)". The second part of a board's - * functionality will match the previously loaded slot/busno. - */ - for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++) - { - /* - * match with board's first found interface, otherwise this is first - * found - */ - if ((hi->pci_slot == 0xff) || /* new board */ - ((hi->pci_slot == slot) && (hi->bus == pdev->bus))) - break; /* found for-loop exit */ - } - if (i == MAX_BOARDS) /* no match in above loop means MAX - * exceeded */ - { - pr_warning("exceeded number of allowed devices (>%d)?\n", MAX_BOARDS); - return 0; - } - if (pdev->bus) - hi->pci_busno = pdev->bus->number; - else - hi->pci_busno = 0; /* default for system PCI inconsistency */ - hi->pci_slot = slot; - pci_read_config_byte (pdev, PCI_INTERRUPT_PIN, &hi->pci_pin[fun]); - pci_read_config_byte (pdev, PCI_REVISION_ID, &hi->revid[fun]); - hi->bus = pdev->bus; - hi->addr[fun] = pci_resource_start (pdev, 0); - hi->len[fun] = pci_resource_end (pdev, 0) - hi->addr[fun] + 1; - hi->pdev[fun] = pdev; - - { - /* - * create device name from module name, plus add the appropriate - * board number - */ - char *cp = hi->devname; - - strcpy (cp, KBUILD_MODNAME); - cp += strlen (cp); /* reposition */ - *cp++ = '-'; - *cp++ = '0' + (found / 2); /* there are two found interfaces per - * board */ - *cp = 0; /* termination */ - } - - return 1; + hdw_info_t *hi; + int i; + int fun, slot; + unsigned char busno = 0xff; + + /* our MUSYCC chip supports two functions, 0 & 1 */ + fun = PCI_FUNC(pdev->devfn); + if (fun > 1) { + pr_warning("unexpected devfun: 0x%x\n", pdev->devfn); + return 0; + } + + /* obtain bus number */ + if (pdev->bus) + busno = pdev->bus->number; + else + busno = 0; /* default for system PCI inconsistency */ + slot = pdev->devfn & ~0x07; + + /* + * Functions 0 & 1 for a given board (identified by same bus(busno) and + * slot(slot)) are placed into the same 'hardware' structure. The first + * part of the board's functionality will be placed into an unpopulated + * element, identified by "slot==(0xff)". The second part of a board's + * functionality will match the previously loaded slot/busno. + */ + for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++) { + /* + * match with board's first found interface, otherwise this is + * fisrt found + */ + if ((hi->pci_slot == 0xff) || /* new board */ + ((hi->pci_slot == slot) && (hi->bus == pdev->bus))) + break; /* found for-loop exit */ + } + + /* no match in above loop means MAX exceeded */ + if (i == MAX_BOARDS) { + pr_warning("exceeded number of allowed devices (>%d)?\n", + MAX_BOARDS); + return 0; + } + + if (pdev->bus) + hi->pci_busno = pdev->bus->number; + else + hi->pci_busno = 0; /* default for system PCI inconsistency */ + + hi->pci_slot = slot; + pci_read_config_byte(pdev, PCI_INTERRUPT_PIN, &hi->pci_pin[fun]); + pci_read_config_byte(pdev, PCI_REVISION_ID, &hi->revid[fun]); + hi->bus = pdev->bus; + hi->addr[fun] = pci_resource_start(pdev, 0); + hi->len[fun] = pci_resource_end(pdev, 0) - hi->addr[fun] + 1; + hi->pdev[fun] = pdev; + + { + /* + * create device name from module name, plus add the appropriate + * board number + */ + char *cp = hi->devname; + + strcpy(cp, KBUILD_MODNAME); + cp += strlen(cp); /* reposition */ + *cp++ = '-'; + *cp++ = '0' + (found / 2); /* there are two found interfaces per + * board */ + *cp = 0; /* termination */ + } + + return 1; } - -status_t __init -c4hw_attach_all (void) +status_t __init +c4hw_attach_all(void) { - hdw_info_t *hi; - struct pci_dev *pdev = NULL; - int found = 0, i, j; - - error_flag = 0; - prep_hdw_info (); - /*** scan PCI bus for all possible boards */ - while ((pdev = pci_get_device (PCI_VENDOR_ID_CONEXANT, - PCI_DEVICE_ID_CN8474, - pdev))) - { - if (c4_hdw_init (pdev, found)) - found++; - } - if (!found) - { - pr_warning("No boards found\n"); - return -ENODEV; - } - /* sanity check for consistent hardware found */ - for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++) - { - if (hi->pci_slot != 0xff && (!hi->addr[0] || !hi->addr[1])) - { - pr_warning("%s: something very wrong with pci_get_device\n", - hi->devname); - return -EIO; - } - } - /* bring board's memory regions on/line */ - for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++) - { - if (hi->pci_slot == 0xff) - break; - for (j = 0; j < 2; j++) - { - if (!request_mem_region (hi->addr[j], hi->len[j], hi->devname)) - { - pr_warning("%s: memory in use, addr=0x%lx, len=0x%lx ?\n", - hi->devname, hi->addr[j], hi->len[j]); - cleanup_ioremap (); - return -ENOMEM; - } - hi->addr_mapped[j] = (unsigned long) ioremap (hi->addr[j], hi->len[j]); - if (!hi->addr_mapped[j]) - { - pr_warning("%s: ioremap fails, addr=0x%lx, len=0x%lx ?\n", - hi->devname, hi->addr[j], hi->len[j]); - cleanup_ioremap (); - return -ENOMEM; - } + hdw_info_t *hi; + struct pci_dev *pdev = NULL; + int found = 0, i, j; + + error_flag = 0; + prep_hdw_info(); + /*** scan PCI bus for all possible boards */ + while ((pdev = pci_get_device(PCI_VENDOR_ID_CONEXANT, + PCI_DEVICE_ID_CN8474, + pdev))) { + if (c4_hdw_init(pdev, found)) + found++; + } + + if (!found) { + pr_warning("No boards found\n"); + return -ENODEV; + } + + /* sanity check for consistent hardware found */ + for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++) { + if (hi->pci_slot != 0xff && (!hi->addr[0] || !hi->addr[1])) { + pr_warning("%s: something very wrong with pci_get_device\n", + hi->devname); + return -EIO; + } + } + /* bring board's memory regions on/line */ + for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++) { + if (hi->pci_slot == 0xff) + break; + for (j = 0; j < 2; j++) { + if (!request_mem_region(hi->addr[j], hi->len[j], hi->devname)) { + pr_warning("%s: memory in use, addr=0x%lx, len=0x%lx ?\n", + hi->devname, hi->addr[j], hi->len[j]); + cleanup_ioremap(); + return -ENOMEM; + } + + hi->addr_mapped[j] = (unsigned long)ioremap(hi->addr[j], hi->len[j]); + if (!hi->addr_mapped[j]) { + pr_warning("%s: ioremap fails, addr=0x%lx, len=0x%lx ?\n", + hi->devname, hi->addr[j], hi->len[j]); + cleanup_ioremap(); + return -ENOMEM; + } #ifdef SBE_MAP_DEBUG - pr_warning("%s: io remapped from phys %x to virt %x\n", - hi->devname, (u_int32_t) hi->addr[j], (u_int32_t) hi->addr_mapped[j]); + pr_warning("%s: io remapped from phys %x to virt %x\n", + hi->devname, (u_int32_t) hi->addr[j], + (u_int32_t) hi->addr_mapped[j]); #endif - } - } - - drvr_state = SBE_DRVR_AVAILABLE; - - /* Have now memory mapped all boards. Now allow board's access to system */ - for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++) - { - if (hi->pci_slot == 0xff) - break; - if (pci_enable_device (hi->pdev[0]) || - pci_enable_device (hi->pdev[1])) - { - drvr_state = SBE_DRVR_DOWN; - pr_warning("%s: failed to enable card %d slot %d\n", - hi->devname, i, hi->pci_slot); - cleanup_devs (); - cleanup_ioremap (); - return -EIO; - } - pci_set_master (hi->pdev[0]); - pci_set_master (hi->pdev[1]); - if (!(hi->ndev = c4_add_dev (hi, i, (long) hi->addr_mapped[0], - (long) hi->addr_mapped[1], - hi->pdev[0]->irq, - hi->pdev[1]->irq))) - { - drvr_state = SBE_DRVR_DOWN; - cleanup_ioremap (); - /* NOTE: c4_add_dev() does its own device cleanup */ + } + } + + drvr_state = SBE_DRVR_AVAILABLE; + + /* Have now memory mapped all boards. Now allow board's access to system */ + for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++) { + if (hi->pci_slot == 0xff) + break; + if (pci_enable_device(hi->pdev[0]) || + pci_enable_device(hi->pdev[1])) { + drvr_state = SBE_DRVR_DOWN; + pr_warning("%s: failed to enable card %d slot %d\n", + hi->devname, i, hi->pci_slot); + cleanup_devs(); + cleanup_ioremap(); + return -EIO; + } + pci_set_master(hi->pdev[0]); + pci_set_master(hi->pdev[1]); + hi->ndev = c4_add_dev(hi, i, (long) hi->addr_mapped[0], + (long) hi->addr_mapped[1], + hi->pdev[0]->irq, + hi->pdev[1]->irq); + if (!hi->ndev) { + drvr_state = SBE_DRVR_DOWN; + cleanup_ioremap(); + /* NOTE: c4_add_dev() does its own device cleanup */ #if 0 - cleanup_devs (); + cleanup_devs(); #endif - return error_flag; /* error_flag set w/in add_dev() */ - } - show_two (hi, i); /* displays found information */ - } - return 0; + return error_flag; /* error_flag set w/in add_dev() */ + } + show_two(hi, i); /* displays found information */ + } + return 0; } /*** End-of-File ***/ diff --git a/drivers/staging/cxt1e1/linux.c b/drivers/staging/cxt1e1/linux.c index 4a08e16e42f..579e68e3dec 100644 --- a/drivers/staging/cxt1e1/linux.c +++ b/drivers/staging/cxt1e1/linux.c @@ -31,7 +31,7 @@ #include "pmcc4_private.h" #include "sbeproc.h" -/***************************************************************************************** +/******************************************************************************* * Error out early if we have compiler trouble. * * (This section is included from the kernel's init/main.c as a friendly @@ -50,43 +50,43 @@ #warning gcc-4.1.0 is known to miscompile the kernel. A different compiler version is recommended. #endif -/*****************************************************************************************/ +/*******************************************************************************/ #define CHANNAME "hdlc" /*******************************************************************/ /* forward references */ -status_t c4_chan_work_init (mpi_t *, mch_t *); -void musycc_wq_chan_restart (void *); -status_t __init c4_init (ci_t *, u_char *, u_char *); -status_t __init c4_init2 (ci_t *); -ci_t *__init c4_new (void *); -int __init c4hw_attach_all (void); -void __init hdw_sn_get (hdw_info_t *, int); +status_t c4_chan_work_init(mpi_t *, mch_t *); +void musycc_wq_chan_restart(void *); +status_t __init c4_init(ci_t *, u_char *, u_char *); +status_t __init c4_init2(ci_t *); +ci_t *__init c4_new(void *); +int __init c4hw_attach_all(void); +void __init hdw_sn_get(hdw_info_t *, int); #ifdef CONFIG_SBE_PMCC4_NCOMM -irqreturn_t c4_ebus_intr_th_handler (void *); +irqreturn_t c4_ebus_intr_th_handler(void *); #endif -int c4_frame_rw (ci_t *, struct sbecom_port_param *); -status_t c4_get_port (ci_t *, int); -int c4_loop_port (ci_t *, int, u_int8_t); -int c4_musycc_rw (ci_t *, struct c4_musycc_param *); -int c4_new_chan (ci_t *, int, int, void *); -status_t c4_set_port (ci_t *, int); -int c4_pld_rw (ci_t *, struct sbecom_port_param *); -void cleanup_devs (void); -void cleanup_ioremap (void); -status_t musycc_chan_down (ci_t *, int); -irqreturn_t musycc_intr_th_handler (void *); -int musycc_start_xmit (ci_t *, int, void *); +int c4_frame_rw(ci_t *, struct sbecom_port_param *); +status_t c4_get_port(ci_t *, int); +int c4_loop_port(ci_t *, int, u_int8_t); +int c4_musycc_rw(ci_t *, struct c4_musycc_param *); +int c4_new_chan(ci_t *, int, int, void *); +status_t c4_set_port(ci_t *, int); +int c4_pld_rw(ci_t *, struct sbecom_port_param *); +void cleanup_devs(void); +void cleanup_ioremap(void); +status_t musycc_chan_down(ci_t *, int); +irqreturn_t musycc_intr_th_handler(void *); +int musycc_start_xmit(ci_t *, int, void *); extern char pmcc4_OSSI_release[]; extern ci_t *CI; extern struct s_hdw_info hdw_info[]; #if defined(CONFIG_SBE_HDLC_V7) || defined(CONFIG_SBE_WAN256T3_HDLC_V7) || \ - defined(CONFIG_SBE_HDLC_V7_MODULE) || defined(CONFIG_SBE_WAN256T3_HDLC_V7_MODULE) + defined(CONFIG_SBE_HDLC_V7_MODULE) || defined(CONFIG_SBE_WAN256T3_HDLC_V7_MODULE) #define _v7_hdlc_ 1 #else #define _v7_hdlc_ 0 @@ -94,9 +94,9 @@ extern struct s_hdw_info hdw_info[]; #if _v7_hdlc_ #define V7(x) (x ## _v7) -extern int hdlc_netif_rx_v7 (hdlc_device *, struct sk_buff *); -extern int register_hdlc_device_v7 (hdlc_device *); -extern int unregister_hdlc_device_v7 (hdlc_device *); +extern int hdlc_netif_rx_v7(hdlc_device *, struct sk_buff *); +extern int register_hdlc_device_v7(hdlc_device *); +extern int unregister_hdlc_device_v7(hdlc_device *); #else #define V7(x) x @@ -127,33 +127,33 @@ module_param(max_rxdesc_used, int, 0444); /****************************************************************************/ /****************************************************************************/ -void * -getuserbychan (int channum) +void * +getuserbychan(int channum) { - mch_t *ch; + mch_t *ch; - ch = c4_find_chan (channum); - return ch ? ch->user : NULL; + ch = c4_find_chan(channum); + return ch ? ch->user : NULL; } -char * -get_hdlc_name (hdlc_device *hdlc) +char * +get_hdlc_name(hdlc_device *hdlc) { - struct c4_priv *priv = hdlc->priv; - struct net_device *dev = getuserbychan (priv->channum); + struct c4_priv *priv = hdlc->priv; + struct net_device *dev = getuserbychan(priv->channum); - return dev->name; + return dev->name; } -static status_t -mkret (int bsd) +static status_t +mkret(int bsd) { - if (bsd > 0) - return -bsd; - else - return bsd; + if (bsd > 0) + return -bsd; + else + return bsd; } /***************************************************************************/ @@ -179,956 +179,978 @@ mkret (int bsd) * within a port's group. */ void -c4_wk_chan_restart (mch_t *ch) +c4_wk_chan_restart(mch_t *ch) { - mpi_t *pi = ch->up; + mpi_t *pi = ch->up; #ifdef RLD_RESTART_DEBUG - pr_info(">> %s: queueing Port %d Chan %d, mch_t @ %p\n", - __func__, pi->portnum, ch->channum, ch); + pr_info(">> %s: queueing Port %d Chan %d, mch_t @ %p\n", + __func__, pi->portnum, ch->channum, ch); #endif - /* create new entry w/in workqueue for this channel and let'er rip */ + /* create new entry w/in workqueue for this channel and let'er rip */ - /** queue_work (struct workqueue_struct *queue, - ** struct work_struct *work); - **/ - queue_work (pi->wq_port, &ch->ch_work); + /** queue_work(struct workqueue_struct *queue, + ** struct work_struct *work); + **/ + queue_work(pi->wq_port, &ch->ch_work); } status_t -c4_wk_chan_init (mpi_t *pi, mch_t *ch) +c4_wk_chan_init(mpi_t *pi, mch_t *ch) { - /* - * this will be used to restart a stopped channel - */ - - /** INIT_WORK (struct work_struct *work, - ** void (*function)(void *), - ** void *data); - **/ - INIT_WORK(&ch->ch_work, (void *)musycc_wq_chan_restart); - return 0; /* success */ + /* + * this will be used to restart a stopped channel + */ + + /** INIT_WORK(struct work_struct *work, + ** void (*function)(void *), + ** void *data); + **/ + INIT_WORK(&ch->ch_work, (void *)musycc_wq_chan_restart); + return 0; /* success */ } status_t -c4_wq_port_init (mpi_t *pi) +c4_wq_port_init(mpi_t *pi) { - char name[16], *np; /* NOTE: name of the queue limited by system - * to 10 characters */ + char name[16], *np; /* NOTE: name of the queue limited by system + * to 10 characters */ - if (pi->wq_port) - return 0; /* already initialized */ + if (pi->wq_port) + return 0; /* already initialized */ - np = name; - memset (name, 0, 16); - sprintf (np, "%s%d", pi->up->devname, pi->portnum); /* IE pmcc4-01) */ + np = name; + memset(name, 0, 16); + sprintf(np, "%s%d", pi->up->devname, pi->portnum); /* IE pmcc4-01) */ #ifdef RLD_RESTART_DEBUG - pr_info(">> %s: creating workqueue <%s> for Port %d.\n", - __func__, name, pi->portnum); /* RLD DEBUG */ + pr_info(">> %s: creating workqueue <%s> for Port %d.\n", + __func__, name, pi->portnum); /* RLD DEBUG */ #endif - if (!(pi->wq_port = create_singlethread_workqueue (name))) - return -ENOMEM; - return 0; /* success */ + if (!(pi->wq_port = create_singlethread_workqueue(name))) + return -ENOMEM; + return 0; /* success */ } void -c4_wq_port_cleanup (mpi_t *pi) +c4_wq_port_cleanup(mpi_t *pi) { - /* - * PORT POINT: cannot call this if WQ is statically allocated w/in - * structure since it calls kfree(wq); - */ - if (pi->wq_port) - { - destroy_workqueue (pi->wq_port); /* this also calls - * flush_workqueue() */ - pi->wq_port = NULL; - } + /* + * PORT POINT: cannot call this if WQ is statically allocated w/in + * structure since it calls kfree(wq); + */ + if (pi->wq_port) + { + destroy_workqueue(pi->wq_port); /* this also calls + * flush_workqueue() */ + pi->wq_port = NULL; + } } /***************************************************************************/ irqreturn_t -c4_linux_interrupt (int irq, void *dev_instance) +c4_linux_interrupt(int irq, void *dev_instance) { - struct net_device *ndev = dev_instance; + struct net_device *ndev = dev_instance; - return musycc_intr_th_handler(netdev_priv(ndev)); + return musycc_intr_th_handler(netdev_priv(ndev)); } #ifdef CONFIG_SBE_PMCC4_NCOMM irqreturn_t -c4_ebus_interrupt (int irq, void *dev_instance) +c4_ebus_interrupt(int irq, void *dev_instance) { - struct net_device *ndev = dev_instance; + struct net_device *ndev = dev_instance; - return c4_ebus_intr_th_handler(netdev_priv(ndev)); + return c4_ebus_intr_th_handler(netdev_priv(ndev)); } #endif static int -void_open (struct net_device *ndev) +void_open(struct net_device *ndev) { - pr_info("%s: trying to open master device !\n", ndev->name); - return -1; + pr_info("%s: trying to open master device !\n", ndev->name); + return -1; } static int -chan_open (struct net_device *ndev) +chan_open(struct net_device *ndev) { - hdlc_device *hdlc = dev_to_hdlc (ndev); - const struct c4_priv *priv = hdlc->priv; - int ret; - - if ((ret = hdlc_open (ndev))) - { - pr_info("hdlc_open failure, err %d.\n", ret); - return ret; - } - if ((ret = c4_chan_up (priv->ci, priv->channum))) - return -ret; - try_module_get (THIS_MODULE); - netif_start_queue (ndev); - return 0; /* no error = success */ + hdlc_device *hdlc = dev_to_hdlc(ndev); + const struct c4_priv *priv = hdlc->priv; + int ret; + + if ((ret = hdlc_open(ndev))) + { + pr_info("hdlc_open failure, err %d.\n", ret); + return ret; + } + if ((ret = c4_chan_up(priv->ci, priv->channum))) + return -ret; + try_module_get(THIS_MODULE); + netif_start_queue(ndev); + return 0; /* no error = success */ } static int -chan_close (struct net_device *ndev) +chan_close(struct net_device *ndev) { - hdlc_device *hdlc = dev_to_hdlc (ndev); - const struct c4_priv *priv = hdlc->priv; - - netif_stop_queue (ndev); - musycc_chan_down ((ci_t *) 0, priv->channum); - hdlc_close (ndev); - module_put (THIS_MODULE); - return 0; + hdlc_device *hdlc = dev_to_hdlc(ndev); + const struct c4_priv *priv = hdlc->priv; + + netif_stop_queue(ndev); + musycc_chan_down((ci_t *) 0, priv->channum); + hdlc_close(ndev); + module_put(THIS_MODULE); + return 0; } static int -chan_dev_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) +chan_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { - return hdlc_ioctl (dev, ifr, cmd); + return hdlc_ioctl(dev, ifr, cmd); } static int -chan_attach_noop (struct net_device *ndev, unsigned short foo_1, unsigned short foo_2) +chan_attach_noop(struct net_device *ndev, unsigned short foo_1, + unsigned short foo_2) { - return 0; /* our driver has nothing to do here, show's - * over, go home */ + /* our driver has nothing to do here, show's + * over, go home + */ + return 0; } static struct net_device_stats * -chan_get_stats (struct net_device *ndev) +chan_get_stats(struct net_device *ndev) { - mch_t *ch; - struct net_device_stats *nstats; - struct sbecom_chan_stats *stats; - int channum; - - { - struct c4_priv *priv; - - priv = (struct c4_priv *) dev_to_hdlc (ndev)->priv; - channum = priv->channum; - } - - ch = c4_find_chan (channum); - if (ch == NULL) - return NULL; - - nstats = &ndev->stats; - stats = &ch->s; - - memset (nstats, 0, sizeof (struct net_device_stats)); - nstats->rx_packets = stats->rx_packets; - nstats->tx_packets = stats->tx_packets; - nstats->rx_bytes = stats->rx_bytes; - nstats->tx_bytes = stats->tx_bytes; - nstats->rx_errors = stats->rx_length_errors + - stats->rx_over_errors + - stats->rx_crc_errors + - stats->rx_frame_errors + - stats->rx_fifo_errors + - stats->rx_missed_errors; - nstats->tx_errors = stats->tx_dropped + - stats->tx_aborted_errors + - stats->tx_fifo_errors; - nstats->rx_dropped = stats->rx_dropped; - nstats->tx_dropped = stats->tx_dropped; - - nstats->rx_length_errors = stats->rx_length_errors; - nstats->rx_over_errors = stats->rx_over_errors; - nstats->rx_crc_errors = stats->rx_crc_errors; - nstats->rx_frame_errors = stats->rx_frame_errors; - nstats->rx_fifo_errors = stats->rx_fifo_errors; - nstats->rx_missed_errors = stats->rx_missed_errors; - - nstats->tx_aborted_errors = stats->tx_aborted_errors; - nstats->tx_fifo_errors = stats->tx_fifo_errors; - - return nstats; + mch_t *ch; + struct net_device_stats *nstats; + struct sbecom_chan_stats *stats; + int channum; + + { + struct c4_priv *priv; + + priv = (struct c4_priv *)dev_to_hdlc(ndev)->priv; + channum = priv->channum; + } + + ch = c4_find_chan(channum); + if (ch == NULL) + return NULL; + + nstats = &ndev->stats; + stats = &ch->s; + + memset(nstats, 0, sizeof(struct net_device_stats)); + nstats->rx_packets = stats->rx_packets; + nstats->tx_packets = stats->tx_packets; + nstats->rx_bytes = stats->rx_bytes; + nstats->tx_bytes = stats->tx_bytes; + nstats->rx_errors = stats->rx_length_errors + + stats->rx_over_errors + + stats->rx_crc_errors + + stats->rx_frame_errors + + stats->rx_fifo_errors + + stats->rx_missed_errors; + nstats->tx_errors = stats->tx_dropped + + stats->tx_aborted_errors + + stats->tx_fifo_errors; + nstats->rx_dropped = stats->rx_dropped; + nstats->tx_dropped = stats->tx_dropped; + + nstats->rx_length_errors = stats->rx_length_errors; + nstats->rx_over_errors = stats->rx_over_errors; + nstats->rx_crc_errors = stats->rx_crc_errors; + nstats->rx_frame_errors = stats->rx_frame_errors; + nstats->rx_fifo_errors = stats->rx_fifo_errors; + nstats->rx_missed_errors = stats->rx_missed_errors; + + nstats->tx_aborted_errors = stats->tx_aborted_errors; + nstats->tx_fifo_errors = stats->tx_fifo_errors; + + return nstats; } static ci_t * -get_ci_by_dev (struct net_device *ndev) +get_ci_by_dev(struct net_device *ndev) { - return (ci_t *)(netdev_priv(ndev)); + return (ci_t *)(netdev_priv(ndev)); } static int -c4_linux_xmit (struct sk_buff *skb, struct net_device *ndev) +c4_linux_xmit(struct sk_buff *skb, struct net_device *ndev) { - const struct c4_priv *priv; - int rval; + const struct c4_priv *priv; + int rval; - hdlc_device *hdlc = dev_to_hdlc (ndev); + hdlc_device *hdlc = dev_to_hdlc(ndev); - priv = hdlc->priv; + priv = hdlc->priv; - rval = musycc_start_xmit (priv->ci, priv->channum, skb); - return rval; + rval = musycc_start_xmit(priv->ci, priv->channum, skb); + return rval; } static const struct net_device_ops chan_ops = { - .ndo_open = chan_open, - .ndo_stop = chan_close, - .ndo_start_xmit = c4_linux_xmit, - .ndo_do_ioctl = chan_dev_ioctl, - .ndo_get_stats = chan_get_stats, + .ndo_open = chan_open, + .ndo_stop = chan_close, + .ndo_start_xmit = c4_linux_xmit, + .ndo_do_ioctl = chan_dev_ioctl, + .ndo_get_stats = chan_get_stats, }; static struct net_device * -create_chan (struct net_device *ndev, ci_t *ci, - struct sbecom_chan_param *cp) +create_chan(struct net_device *ndev, ci_t *ci, + struct sbecom_chan_param *cp) { - hdlc_device *hdlc; - struct net_device *dev; - hdw_info_t *hi; - int ret; - - if (c4_find_chan (cp->channum)) - return NULL; /* channel already exists */ - - { - struct c4_priv *priv; - - /* allocate then fill in private data structure */ - priv = OS_kmalloc (sizeof (struct c4_priv)); - if (!priv) - { - pr_warning("%s: no memory for net_device !\n", ci->devname); - return NULL; - } - dev = alloc_hdlcdev (priv); - if (!dev) - { - pr_warning("%s: no memory for hdlc_device !\n", ci->devname); - OS_kfree (priv); - return NULL; - } - priv->ci = ci; - priv->channum = cp->channum; - } - - hdlc = dev_to_hdlc (dev); - - dev->base_addr = 0; /* not I/O mapped */ - dev->irq = ndev->irq; - dev->type = ARPHRD_RAWHDLC; - *dev->name = 0; /* default ifconfig name = "hdlc" */ - - hi = (hdw_info_t *) ci->hdw_info; - if (hi->mfg_info_sts == EEPROM_OK) - { - switch (hi->promfmt) - { - case PROM_FORMAT_TYPE1: - memcpy (dev->dev_addr, (FLD_TYPE1 *) (hi->mfg_info.pft1.Serial), 6); - break; - case PROM_FORMAT_TYPE2: - memcpy (dev->dev_addr, (FLD_TYPE2 *) (hi->mfg_info.pft2.Serial), 6); - break; - default: - memset (dev->dev_addr, 0, 6); - break; - } - } else - { - memset (dev->dev_addr, 0, 6); - } - - hdlc->xmit = c4_linux_xmit; - - dev->netdev_ops = &chan_ops; - /* - * The native hdlc stack calls this 'attach' routine during - * hdlc_raw_ioctl(), passing parameters for line encoding and parity. - * Since hdlc_raw_ioctl() stack does not interrogate whether an 'attach' - * routine is actually registered or not, we supply a dummy routine which - * does nothing (since encoding and parity are setup for our driver via a - * special configuration application). - */ - - hdlc->attach = chan_attach_noop; - - rtnl_unlock (); /* needed due to Ioctl calling sequence */ - ret = register_hdlc_device (dev); - /* NOTE: <stats> setting must occur AFTER registration in order to "take" */ - dev->tx_queue_len = MAX_DEFAULT_IFQLEN; - - rtnl_lock (); /* needed due to Ioctl calling sequence */ - if (ret) - { - if (cxt1e1_log_level >= LOG_WARN) - pr_info("%s: create_chan[%d] registration error = %d.\n", - ci->devname, cp->channum, ret); - free_netdev (dev); /* cleanup */ - return NULL; /* failed to register */ - } - return dev; + hdlc_device *hdlc; + struct net_device *dev; + hdw_info_t *hi; + int ret; + + if (c4_find_chan(cp->channum)) + return NULL; /* channel already exists */ + + { + struct c4_priv *priv; + + /* allocate then fill in private data structure */ + priv = OS_kmalloc(sizeof(struct c4_priv)); + if (!priv) + { + pr_warning("%s: no memory for net_device !\n", + ci->devname); + return NULL; + } + dev = alloc_hdlcdev(priv); + if (!dev) + { + pr_warning("%s: no memory for hdlc_device !\n", + ci->devname); + OS_kfree(priv); + return NULL; + } + priv->ci = ci; + priv->channum = cp->channum; + } + + hdlc = dev_to_hdlc(dev); + + dev->base_addr = 0; /* not I/O mapped */ + dev->irq = ndev->irq; + dev->type = ARPHRD_RAWHDLC; + *dev->name = 0; /* default ifconfig name = "hdlc" */ + + hi = (hdw_info_t *)ci->hdw_info; + if (hi->mfg_info_sts == EEPROM_OK) + { + switch (hi->promfmt) + { + case PROM_FORMAT_TYPE1: + memcpy(dev->dev_addr, + (FLD_TYPE1 *) (hi->mfg_info.pft1.Serial), 6); + break; + case PROM_FORMAT_TYPE2: + memcpy(dev->dev_addr, + (FLD_TYPE2 *) (hi->mfg_info.pft2.Serial), 6); + break; + default: + memset(dev->dev_addr, 0, 6); + break; + } + } else + { + memset(dev->dev_addr, 0, 6); + } + + hdlc->xmit = c4_linux_xmit; + + dev->netdev_ops = &chan_ops; + /* + * The native hdlc stack calls this 'attach' routine during + * hdlc_raw_ioctl(), passing parameters for line encoding and parity. + * Since hdlc_raw_ioctl() stack does not interrogate whether an 'attach' + * routine is actually registered or not, we supply a dummy routine which + * does nothing (since encoding and parity are setup for our driver via a + * special configuration application). + */ + + hdlc->attach = chan_attach_noop; + + /* needed due to Ioctl calling sequence */ + rtnl_unlock(); + ret = register_hdlc_device(dev); + /* NOTE: <stats> setting must occur AFTER registration in order to "take" */ + dev->tx_queue_len = MAX_DEFAULT_IFQLEN; + + /* needed due to Ioctl calling sequence */ + rtnl_lock(); + if (ret) + { + if (cxt1e1_log_level >= LOG_WARN) + pr_info("%s: create_chan[%d] registration error = %d.\n", + ci->devname, cp->channum, ret); + /* cleanup */ + free_netdev(dev); + /* failed to register */ + return NULL; + } + return dev; } /* the idea here is to get port information and pass it back (using pointer) */ -static status_t -do_get_port (struct net_device *ndev, void *data) +static status_t +do_get_port(struct net_device *ndev, void *data) { - int ret; - ci_t *ci; /* ci stands for card information */ - struct sbecom_port_param pp;/* copy data to kernel land */ - - if (copy_from_user (&pp, data, sizeof (struct sbecom_port_param))) - return -EFAULT; - if (pp.portnum >= MUSYCC_NPORTS) - return -EFAULT; - ci = get_ci_by_dev (ndev); - if (!ci) - return -EINVAL; /* get card info */ - - ret = mkret (c4_get_port (ci, pp.portnum)); - if (ret) - return ret; - if (copy_to_user (data, &ci->port[pp.portnum].p, - sizeof (struct sbecom_port_param))) - return -EFAULT; - return 0; + int ret; + ci_t *ci; /* ci stands for card information */ + struct sbecom_port_param pp;/* copy data to kernel land */ + + if (copy_from_user(&pp, data, sizeof(struct sbecom_port_param))) + return -EFAULT; + if (pp.portnum >= MUSYCC_NPORTS) + return -EFAULT; + ci = get_ci_by_dev(ndev); + if (!ci) + return -EINVAL; /* get card info */ + + ret = mkret(c4_get_port(ci, pp.portnum)); + if (ret) + return ret; + if (copy_to_user(data, &ci->port[pp.portnum].p, + sizeof(struct sbecom_port_param))) + return -EFAULT; + return 0; } /* this function copys the user data and then calls the real action function */ -static status_t -do_set_port (struct net_device *ndev, void *data) +static status_t +do_set_port(struct net_device *ndev, void *data) { - ci_t *ci; /* ci stands for card information */ - struct sbecom_port_param pp;/* copy data to kernel land */ - - if (copy_from_user (&pp, data, sizeof (struct sbecom_port_param))) - return -EFAULT; - if (pp.portnum >= MUSYCC_NPORTS) - return -EFAULT; - ci = get_ci_by_dev (ndev); - if (!ci) - return -EINVAL; /* get card info */ - - if (pp.portnum >= ci->max_port) /* sanity check */ - return -ENXIO; - - memcpy (&ci->port[pp.portnum].p, &pp, sizeof (struct sbecom_port_param)); - return mkret (c4_set_port (ci, pp.portnum)); + ci_t *ci; /* ci stands for card information */ + struct sbecom_port_param pp;/* copy data to kernel land */ + + if (copy_from_user(&pp, data, sizeof(struct sbecom_port_param))) + return -EFAULT; + if (pp.portnum >= MUSYCC_NPORTS) + return -EFAULT; + ci = get_ci_by_dev(ndev); + if (!ci) + return -EINVAL; /* get card info */ + + if (pp.portnum >= ci->max_port) /* sanity check */ + return -ENXIO; + + memcpy(&ci->port[pp.portnum].p, &pp, sizeof(struct sbecom_port_param)); + return mkret(c4_set_port(ci, pp.portnum)); } /* work the port loopback mode as per directed */ -static status_t -do_port_loop (struct net_device *ndev, void *data) +static status_t +do_port_loop(struct net_device *ndev, void *data) { - struct sbecom_port_param pp; - ci_t *ci; - - if (copy_from_user (&pp, data, sizeof (struct sbecom_port_param))) - return -EFAULT; - ci = get_ci_by_dev (ndev); - if (!ci) - return -EINVAL; - return mkret (c4_loop_port (ci, pp.portnum, pp.port_mode)); + struct sbecom_port_param pp; + ci_t *ci; + + if (copy_from_user(&pp, data, sizeof(struct sbecom_port_param))) + return -EFAULT; + ci = get_ci_by_dev(ndev); + if (!ci) + return -EINVAL; + return mkret(c4_loop_port(ci, pp.portnum, pp.port_mode)); } /* set the specified register with the given value / or just read it */ -static status_t -do_framer_rw (struct net_device *ndev, void *data) +static status_t +do_framer_rw(struct net_device *ndev, void *data) { - struct sbecom_port_param pp; - ci_t *ci; - int ret; - - if (copy_from_user (&pp, data, sizeof (struct sbecom_port_param))) - return -EFAULT; - ci = get_ci_by_dev (ndev); - if (!ci) - return -EINVAL; - ret = mkret (c4_frame_rw (ci, &pp)); - if (ret) - return ret; - if (copy_to_user (data, &pp, sizeof (struct sbecom_port_param))) - return -EFAULT; - return 0; + struct sbecom_port_param pp; + ci_t *ci; + int ret; + + if (copy_from_user(&pp, data, sizeof(struct sbecom_port_param))) + return -EFAULT; + ci = get_ci_by_dev(ndev); + if (!ci) + return -EINVAL; + ret = mkret(c4_frame_rw(ci, &pp)); + if (ret) + return ret; + if (copy_to_user(data, &pp, sizeof(struct sbecom_port_param))) + return -EFAULT; + return 0; } /* set the specified register with the given value / or just read it */ -static status_t -do_pld_rw (struct net_device *ndev, void *data) +static status_t +do_pld_rw(struct net_device *ndev, void *data) { - struct sbecom_port_param pp; - ci_t *ci; - int ret; - - if (copy_from_user (&pp, data, sizeof (struct sbecom_port_param))) - return -EFAULT; - ci = get_ci_by_dev (ndev); - if (!ci) - return -EINVAL; - ret = mkret (c4_pld_rw (ci, &pp)); - if (ret) - return ret; - if (copy_to_user (data, &pp, sizeof (struct sbecom_port_param))) - return -EFAULT; - return 0; + struct sbecom_port_param pp; + ci_t *ci; + int ret; + + if (copy_from_user(&pp, data, sizeof(struct sbecom_port_param))) + return -EFAULT; + ci = get_ci_by_dev(ndev); + if (!ci) + return -EINVAL; + ret = mkret(c4_pld_rw(ci, &pp)); + if (ret) + return ret; + if (copy_to_user(data, &pp, sizeof(struct sbecom_port_param))) + return -EFAULT; + return 0; } /* set the specified register with the given value / or just read it */ -static status_t -do_musycc_rw (struct net_device *ndev, void *data) +static status_t +do_musycc_rw(struct net_device *ndev, void *data) { - struct c4_musycc_param mp; - ci_t *ci; - int ret; - - if (copy_from_user (&mp, data, sizeof (struct c4_musycc_param))) - return -EFAULT; - ci = get_ci_by_dev (ndev); - if (!ci) - return -EINVAL; - ret = mkret (c4_musycc_rw (ci, &mp)); - if (ret) - return ret; - if (copy_to_user (data, &mp, sizeof (struct c4_musycc_param))) - return -EFAULT; - return 0; + struct c4_musycc_param mp; + ci_t *ci; + int ret; + + if (copy_from_user(&mp, data, sizeof(struct c4_musycc_param))) + return -EFAULT; + ci = get_ci_by_dev(ndev); + if (!ci) + return -EINVAL; + ret = mkret(c4_musycc_rw(ci, &mp)); + if (ret) + return ret; + if (copy_to_user(data, &mp, sizeof(struct c4_musycc_param))) + return -EFAULT; + return 0; } -static status_t -do_get_chan (struct net_device *ndev, void *data) +static status_t +do_get_chan(struct net_device *ndev, void *data) { - struct sbecom_chan_param cp; - int ret; + struct sbecom_chan_param cp; + int ret; - if (copy_from_user (&cp, data, - sizeof (struct sbecom_chan_param))) - return -EFAULT; + if (copy_from_user(&cp, data, + sizeof(struct sbecom_chan_param))) + return -EFAULT; - if ((ret = mkret (c4_get_chan (cp.channum, &cp)))) - return ret; + if ((ret = mkret(c4_get_chan(cp.channum, &cp)))) + return ret; - if (copy_to_user (data, &cp, sizeof (struct sbecom_chan_param))) - return -EFAULT; - return 0; + if (copy_to_user(data, &cp, sizeof(struct sbecom_chan_param))) + return -EFAULT; + return 0; } -static status_t -do_set_chan (struct net_device *ndev, void *data) +static status_t +do_set_chan(struct net_device *ndev, void *data) { - struct sbecom_chan_param cp; - int ret; - ci_t *ci; - - if (copy_from_user (&cp, data, sizeof (struct sbecom_chan_param))) - return -EFAULT; - ci = get_ci_by_dev (ndev); - if (!ci) - return -EINVAL; - switch (ret = mkret (c4_set_chan (cp.channum, &cp))) - { - case 0: - return 0; - default: - return ret; - } + struct sbecom_chan_param cp; + int ret; + ci_t *ci; + + if (copy_from_user(&cp, data, sizeof(struct sbecom_chan_param))) + return -EFAULT; + ci = get_ci_by_dev(ndev); + if (!ci) + return -EINVAL; + switch (ret = mkret(c4_set_chan(cp.channum, &cp))) + { + case 0: + return 0; + default: + return ret; + } } -static status_t -do_create_chan (struct net_device *ndev, void *data) +static status_t +do_create_chan(struct net_device *ndev, void *data) { - ci_t *ci; - struct net_device *dev; - struct sbecom_chan_param cp; - int ret; - - if (copy_from_user (&cp, data, sizeof (struct sbecom_chan_param))) - return -EFAULT; - ci = get_ci_by_dev (ndev); - if (!ci) - return -EINVAL; - dev = create_chan (ndev, ci, &cp); - if (!dev) - return -EBUSY; - ret = mkret (c4_new_chan (ci, cp.port, cp.channum, dev)); - if (ret) - { - rtnl_unlock (); /* needed due to Ioctl calling sequence */ - unregister_hdlc_device (dev); - rtnl_lock (); /* needed due to Ioctl calling sequence */ - free_netdev (dev); - } - return ret; + ci_t *ci; + struct net_device *dev; + struct sbecom_chan_param cp; + int ret; + + if (copy_from_user(&cp, data, sizeof(struct sbecom_chan_param))) + return -EFAULT; + ci = get_ci_by_dev(ndev); + if (!ci) + return -EINVAL; + dev = create_chan(ndev, ci, &cp); + if (!dev) + return -EBUSY; + ret = mkret(c4_new_chan(ci, cp.port, cp.channum, dev)); + if (ret) + { + /* needed due to Ioctl calling sequence */ + rtnl_unlock(); + unregister_hdlc_device(dev); + /* needed due to Ioctl calling sequence */ + rtnl_lock(); + free_netdev(dev); + } + return ret; } -static status_t -do_get_chan_stats (struct net_device *ndev, void *data) +static status_t +do_get_chan_stats(struct net_device *ndev, void *data) { - struct c4_chan_stats_wrap ccs; - int ret; - - if (copy_from_user (&ccs, data, - sizeof (struct c4_chan_stats_wrap))) - return -EFAULT; - switch (ret = mkret (c4_get_chan_stats (ccs.channum, &ccs.stats))) - { - case 0: - break; - default: - return ret; - } - if (copy_to_user (data, &ccs, - sizeof (struct c4_chan_stats_wrap))) - return -EFAULT; - return 0; + struct c4_chan_stats_wrap ccs; + int ret; + + if (copy_from_user(&ccs, data, + sizeof(struct c4_chan_stats_wrap))) + return -EFAULT; + switch (ret = mkret(c4_get_chan_stats(ccs.channum, &ccs.stats))) + { + case 0: + break; + default: + return ret; + } + if (copy_to_user(data, &ccs, + sizeof(struct c4_chan_stats_wrap))) + return -EFAULT; + return 0; } -static status_t -do_set_loglevel (struct net_device *ndev, void *data) +static status_t +do_set_loglevel(struct net_device *ndev, void *data) { - unsigned int cxt1e1_log_level; + unsigned int cxt1e1_log_level; - if (copy_from_user (&cxt1e1_log_level, data, sizeof (int))) - return -EFAULT; - sbecom_set_loglevel (cxt1e1_log_level); - return 0; + if (copy_from_user(&cxt1e1_log_level, data, sizeof(int))) + return -EFAULT; + sbecom_set_loglevel(cxt1e1_log_level); + return 0; } -static status_t -do_deluser (struct net_device *ndev, int lockit) +static status_t +do_deluser(struct net_device *ndev, int lockit) { - if (ndev->flags & IFF_UP) - return -EBUSY; - - { - ci_t *ci; - mch_t *ch; - const struct c4_priv *priv; - int channum; - - priv = (struct c4_priv *) dev_to_hdlc (ndev)->priv; - ci = priv->ci; - channum = priv->channum; - - ch = c4_find_chan (channum); - if (ch == NULL) - return -ENOENT; - ch->user = NULL; /* will be freed, below */ - } - - if (lockit) - rtnl_unlock (); /* needed if Ioctl calling sequence */ - unregister_hdlc_device (ndev); - if (lockit) - rtnl_lock (); /* needed if Ioctl calling sequence */ - free_netdev (ndev); - return 0; + if (ndev->flags & IFF_UP) + return -EBUSY; + + { + ci_t *ci; + mch_t *ch; + const struct c4_priv *priv; + int channum; + + priv = (struct c4_priv *)dev_to_hdlc(ndev)->priv; + ci = priv->ci; + channum = priv->channum; + + ch = c4_find_chan(channum); + if (ch == NULL) + return -ENOENT; + ch->user = NULL; /* will be freed, below */ + } + + /* needed if Ioctl calling sequence */ + if (lockit) + rtnl_unlock(); + unregister_hdlc_device(ndev); + /* needed if Ioctl calling sequence */ + if (lockit) + rtnl_lock(); + free_netdev(ndev); + return 0; } int -do_del_chan (struct net_device *musycc_dev, void *data) +do_del_chan(struct net_device *musycc_dev, void *data) { - struct sbecom_chan_param cp; - char buf[sizeof (CHANNAME) + 3]; - struct net_device *dev; - int ret; - - if (copy_from_user (&cp, data, - sizeof (struct sbecom_chan_param))) - return -EFAULT; - if (cp.channum > 999) - return -EINVAL; - snprintf (buf, sizeof(buf), CHANNAME "%d", cp.channum); + struct sbecom_chan_param cp; + char buf[sizeof(CHANNAME) + 3]; + struct net_device *dev; + int ret; + + if (copy_from_user(&cp, data, + sizeof(struct sbecom_chan_param))) + return -EFAULT; + if (cp.channum > 999) + return -EINVAL; + snprintf(buf, sizeof(buf), CHANNAME "%d", cp.channum); dev = __dev_get_by_name(&init_net, buf); if (!dev) return -ENODEV; - ret = do_deluser (dev, 1); - if (ret) - return ret; - return c4_del_chan (cp.channum); + ret = do_deluser(dev, 1); + if (ret) + return ret; + return c4_del_chan(cp.channum); } -int c4_reset_board (void *); +int c4_reset_board(void *); int -do_reset (struct net_device *musycc_dev, void *data) +do_reset(struct net_device *musycc_dev, void *data) { - const struct c4_priv *priv; - int i; - - for (i = 0; i < 128; i++) - { - struct net_device *ndev; - char buf[sizeof (CHANNAME) + 3]; - - sprintf (buf, CHANNAME "%d", i); - ndev = __dev_get_by_name(&init_net, buf); - if (!ndev) - continue; - priv = dev_to_hdlc (ndev)->priv; - - if ((unsigned long) (priv->ci) == - (unsigned long) (netdev_priv(musycc_dev))) - { - ndev->flags &= ~IFF_UP; - netif_stop_queue (ndev); - do_deluser (ndev, 1); + const struct c4_priv *priv; + int i; + + for (i = 0; i < 128; i++) + { + struct net_device *ndev; + char buf[sizeof(CHANNAME) + 3]; + + sprintf(buf, CHANNAME "%d", i); + ndev = __dev_get_by_name(&init_net, buf); + if (!ndev) + continue; + priv = dev_to_hdlc(ndev)->priv; + + if ((unsigned long) (priv->ci) == + (unsigned long) (netdev_priv(musycc_dev))) + { + ndev->flags &= ~IFF_UP; + netif_stop_queue(ndev); + do_deluser(ndev, 1); + } } - } - return 0; + return 0; } int -do_reset_chan_stats (struct net_device *musycc_dev, void *data) +do_reset_chan_stats(struct net_device *musycc_dev, void *data) { - struct sbecom_chan_param cp; + struct sbecom_chan_param cp; - if (copy_from_user (&cp, data, - sizeof (struct sbecom_chan_param))) - return -EFAULT; - return mkret (c4_del_chan_stats (cp.channum)); + if (copy_from_user(&cp, data, + sizeof(struct sbecom_chan_param))) + return -EFAULT; + return mkret(c4_del_chan_stats(cp.channum)); } -static status_t -c4_ioctl (struct net_device *ndev, struct ifreq *ifr, int cmd) +static status_t +c4_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd) { - ci_t *ci; - void *data; - int iocmd, iolen; - status_t ret; - static struct data - { - union - { - u_int8_t c; - u_int32_t i; - struct sbe_brd_info bip; - struct sbe_drv_info dip; - struct sbe_iid_info iip; - struct sbe_brd_addr bap; - struct sbecom_chan_stats stats; - struct sbecom_chan_param param; - struct temux_card_stats cards; - struct sbecom_card_param cardp; - struct sbecom_framer_param frp; - } u; - } arg; - - - if (!capable (CAP_SYS_ADMIN)) - return -EPERM; - if (cmd != SIOCDEVPRIVATE + 15) - return -EINVAL; - if (!(ci = get_ci_by_dev (ndev))) - return -EINVAL; - if (ci->state != C_RUNNING) - return -ENODEV; - if (copy_from_user (&iocmd, ifr->ifr_data, sizeof (iocmd))) - return -EFAULT; + ci_t *ci; + void *data; + int iocmd, iolen; + status_t ret; + static struct data + { + union + { + u_int8_t c; + u_int32_t i; + struct sbe_brd_info bip; + struct sbe_drv_info dip; + struct sbe_iid_info iip; + struct sbe_brd_addr bap; + struct sbecom_chan_stats stats; + struct sbecom_chan_param param; + struct temux_card_stats cards; + struct sbecom_card_param cardp; + struct sbecom_framer_param frp; + } u; + } arg; + + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (cmd != SIOCDEVPRIVATE + 15) + return -EINVAL; + if (!(ci = get_ci_by_dev(ndev))) + return -EINVAL; + if (ci->state != C_RUNNING) + return -ENODEV; + if (copy_from_user(&iocmd, ifr->ifr_data, sizeof(iocmd))) + return -EFAULT; #if 0 - if (copy_from_user (&len, ifr->ifr_data + sizeof (iocmd), sizeof (len))) - return -EFAULT; + if (copy_from_user(&len, ifr->ifr_data + sizeof(iocmd), sizeof(len))) + return -EFAULT; #endif #if 0 - pr_info("c4_ioctl: iocmd %x, dir %x type %x nr %x iolen %d.\n", iocmd, - _IOC_DIR (iocmd), _IOC_TYPE (iocmd), _IOC_NR (iocmd), - _IOC_SIZE (iocmd)); + pr_info("c4_ioctl: iocmd %x, dir %x type %x nr %x iolen %d.\n", iocmd, + _IOC_DIR(iocmd), _IOC_TYPE(iocmd), _IOC_NR(iocmd), + _IOC_SIZE(iocmd)); #endif - iolen = _IOC_SIZE (iocmd); - data = ifr->ifr_data + sizeof (iocmd); - if (copy_from_user (&arg, data, iolen)) - return -EFAULT; - - ret = 0; - switch (iocmd) - { - case SBE_IOC_PORT_GET: - //pr_info(">> SBE_IOC_PORT_GET Ioctl...\n"); - ret = do_get_port (ndev, data); - break; - case SBE_IOC_PORT_SET: - //pr_info(">> SBE_IOC_PORT_SET Ioctl...\n"); - ret = do_set_port (ndev, data); - break; - case SBE_IOC_CHAN_GET: - //pr_info(">> SBE_IOC_CHAN_GET Ioctl...\n"); - ret = do_get_chan (ndev, data); - break; - case SBE_IOC_CHAN_SET: - //pr_info(">> SBE_IOC_CHAN_SET Ioctl...\n"); - ret = do_set_chan (ndev, data); - break; - case C4_DEL_CHAN: - //pr_info(">> C4_DEL_CHAN Ioctl...\n"); - ret = do_del_chan (ndev, data); - break; - case SBE_IOC_CHAN_NEW: - ret = do_create_chan (ndev, data); - break; - case SBE_IOC_CHAN_GET_STAT: - ret = do_get_chan_stats (ndev, data); - break; - case SBE_IOC_LOGLEVEL: - ret = do_set_loglevel (ndev, data); - break; - case SBE_IOC_RESET_DEV: - ret = do_reset (ndev, data); - break; - case SBE_IOC_CHAN_DEL_STAT: - ret = do_reset_chan_stats (ndev, data); - break; - case C4_LOOP_PORT: - ret = do_port_loop (ndev, data); - break; - case C4_RW_FRMR: - ret = do_framer_rw (ndev, data); - break; - case C4_RW_MSYC: - ret = do_musycc_rw (ndev, data); - break; - case C4_RW_PLD: - ret = do_pld_rw (ndev, data); - break; - case SBE_IOC_IID_GET: - ret = (iolen == sizeof (struct sbe_iid_info)) ? c4_get_iidinfo (ci, &arg.u.iip) : -EFAULT; - if (ret == 0) /* no error, copy data */ - if (copy_to_user (data, &arg, iolen)) - return -EFAULT; - break; - default: - //pr_info(">> c4_ioctl: EINVAL - unknown iocmd <%x>\n", iocmd); - ret = -EINVAL; - break; - } - return mkret (ret); + iolen = _IOC_SIZE(iocmd); + data = ifr->ifr_data + sizeof(iocmd); + if (copy_from_user(&arg, data, iolen)) + return -EFAULT; + + ret = 0; + switch (iocmd) + { + case SBE_IOC_PORT_GET: + //pr_info(">> SBE_IOC_PORT_GET Ioctl...\n"); + ret = do_get_port(ndev, data); + break; + case SBE_IOC_PORT_SET: + //pr_info(">> SBE_IOC_PORT_SET Ioctl...\n"); + ret = do_set_port(ndev, data); + break; + case SBE_IOC_CHAN_GET: + //pr_info(">> SBE_IOC_CHAN_GET Ioctl...\n"); + ret = do_get_chan(ndev, data); + break; + case SBE_IOC_CHAN_SET: + //pr_info(">> SBE_IOC_CHAN_SET Ioctl...\n"); + ret = do_set_chan(ndev, data); + break; + case C4_DEL_CHAN: + //pr_info(">> C4_DEL_CHAN Ioctl...\n"); + ret = do_del_chan(ndev, data); + break; + case SBE_IOC_CHAN_NEW: + ret = do_create_chan(ndev, data); + break; + case SBE_IOC_CHAN_GET_STAT: + ret = do_get_chan_stats(ndev, data); + break; + case SBE_IOC_LOGLEVEL: + ret = do_set_loglevel(ndev, data); + break; + case SBE_IOC_RESET_DEV: + ret = do_reset(ndev, data); + break; + case SBE_IOC_CHAN_DEL_STAT: + ret = do_reset_chan_stats(ndev, data); + break; + case C4_LOOP_PORT: + ret = do_port_loop(ndev, data); + break; + case C4_RW_FRMR: + ret = do_framer_rw(ndev, data); + break; + case C4_RW_MSYC: + ret = do_musycc_rw(ndev, data); + break; + case C4_RW_PLD: + ret = do_pld_rw(ndev, data); + break; + case SBE_IOC_IID_GET: + ret = (iolen == sizeof(struct sbe_iid_info)) ? + c4_get_iidinfo(ci, &arg.u.iip) : -EFAULT; + if (ret == 0) /* no error, copy data */ + if (copy_to_user(data, &arg, iolen)) + return -EFAULT; + break; + default: + //pr_info(">> c4_ioctl: EINVAL - unknown iocmd <%x>\n", iocmd); + ret = -EINVAL; + break; + } + return mkret(ret); } static const struct net_device_ops c4_ops = { - .ndo_open = void_open, - .ndo_start_xmit = c4_linux_xmit, - .ndo_do_ioctl = c4_ioctl, + .ndo_open = void_open, + .ndo_start_xmit = c4_linux_xmit, + .ndo_do_ioctl = c4_ioctl, }; static void c4_setup(struct net_device *dev) { - dev->type = ARPHRD_VOID; - dev->netdev_ops = &c4_ops; + dev->type = ARPHRD_VOID; + dev->netdev_ops = &c4_ops; } struct net_device *__init -c4_add_dev (hdw_info_t *hi, int brdno, unsigned long f0, unsigned long f1, - int irq0, int irq1) +c4_add_dev(hdw_info_t *hi, int brdno, unsigned long f0, unsigned long f1, + int irq0, int irq1) { - struct net_device *ndev; - ci_t *ci; - - ndev = alloc_netdev(sizeof(ci_t), SBE_IFACETMPL, c4_setup); - if (!ndev) - { - pr_warning("%s: no memory for struct net_device !\n", hi->devname); - error_flag = ENOMEM; - return NULL; - } - ci = (ci_t *)(netdev_priv(ndev)); - ndev->irq = irq0; - - ci->hdw_info = hi; - ci->state = C_INIT; /* mark as hardware not available */ - ci->next = c4_list; - c4_list = ci; - ci->brdno = ci->next ? ci->next->brdno + 1 : 0; - - if (!CI) - CI = ci; /* DEBUG, only board 0 usage */ - - strcpy (ci->devname, hi->devname); - ci->release = &pmcc4_OSSI_release[0]; - - /* tasklet */ + struct net_device *ndev; + ci_t *ci; + + ndev = alloc_netdev(sizeof(ci_t), SBE_IFACETMPL, c4_setup); + if (!ndev) + { + pr_warning("%s: no memory for struct net_device !\n", + hi->devname); + error_flag = ENOMEM; + return NULL; + } + ci = (ci_t *)(netdev_priv(ndev)); + ndev->irq = irq0; + + ci->hdw_info = hi; + ci->state = C_INIT; /* mark as hardware not available */ + ci->next = c4_list; + c4_list = ci; + ci->brdno = ci->next ? ci->next->brdno + 1 : 0; + + if (!CI) + CI = ci; /* DEBUG, only board 0 usage */ + + strcpy(ci->devname, hi->devname); + ci->release = &pmcc4_OSSI_release[0]; + + /* tasklet */ #if defined(SBE_ISR_TASKLET) - tasklet_init (&ci->ci_musycc_isr_tasklet, - (void (*) (unsigned long)) musycc_intr_bh_tasklet, - (unsigned long) ci); + tasklet_init(&ci->ci_musycc_isr_tasklet, + (void (*) (unsigned long)) musycc_intr_bh_tasklet, + (unsigned long) ci); - if (atomic_read (&ci->ci_musycc_isr_tasklet.count) == 0) - tasklet_disable_nosync (&ci->ci_musycc_isr_tasklet); + if (atomic_read(&ci->ci_musycc_isr_tasklet.count) == 0) + tasklet_disable_nosync(&ci->ci_musycc_isr_tasklet); #elif defined(SBE_ISR_IMMEDIATE) - ci->ci_musycc_isr_tq.routine = (void *) (unsigned long) musycc_intr_bh_tasklet; - ci->ci_musycc_isr_tq.data = ci; + ci->ci_musycc_isr_tq.routine = (void *)(unsigned long)musycc_intr_bh_tasklet; + ci->ci_musycc_isr_tq.data = ci; #endif - if (register_netdev (ndev) || - (c4_init (ci, (u_char *) f0, (u_char *) f1) != SBE_DRVR_SUCCESS)) - { - OS_kfree (netdev_priv(ndev)); - OS_kfree (ndev); - error_flag = ENODEV; - return NULL; - } - /************************************************************* - * int request_irq(unsigned int irq, - * void (*handler)(int, void *, struct pt_regs *), - * unsigned long flags, const char *dev_name, void *dev_id); - * wherein: - * irq -> The interrupt number that is being requested. - * handler -> Pointer to handling function being installed. - * flags -> A bit mask of options related to interrupt management. - * dev_name -> String used in /proc/interrupts to show owner of interrupt. - * dev_id -> Pointer (for shared interrupt lines) to point to its own - * private data area (to identify which device is interrupting). - * - * extern void free_irq(unsigned int irq, void *dev_id); - **************************************************************/ - - if (request_irq (irq0, &c4_linux_interrupt, - IRQF_SHARED, - ndev->name, ndev)) - { - pr_warning("%s: MUSYCC could not get irq: %d\n", ndev->name, irq0); - unregister_netdev (ndev); - OS_kfree (netdev_priv(ndev)); - OS_kfree (ndev); - error_flag = EIO; - return NULL; - } + if (register_netdev(ndev) || + (c4_init(ci, (u_char *) f0, (u_char *) f1) != SBE_DRVR_SUCCESS)) + { + OS_kfree(netdev_priv(ndev)); + OS_kfree(ndev); + error_flag = ENODEV; + return NULL; + } + /************************************************************* + * int request_irq(unsigned int irq, + * void (*handler)(int, void *, struct pt_regs *), + * unsigned long flags, const char *dev_name, void *dev_id); + * wherein: + * irq -> The interrupt number that is being requested. + * handler -> Pointer to handling function being installed. + * flags -> A bit mask of options related to interrupt management. + * dev_name -> String used in /proc/interrupts to show owner of interrupt. + * dev_id -> Pointer (for shared interrupt lines) to point to its own + * private data area (to identify which device is interrupting). + * + * extern void free_irq(unsigned int irq, void *dev_id); + **************************************************************/ + + if (request_irq(irq0, &c4_linux_interrupt, + IRQF_SHARED, + ndev->name, ndev)) + { + pr_warning("%s: MUSYCC could not get irq: %d\n", + ndev->name, irq0); + unregister_netdev(ndev); + OS_kfree(netdev_priv(ndev)); + OS_kfree(ndev); + error_flag = EIO; + return NULL; + } #ifdef CONFIG_SBE_PMCC4_NCOMM - if (request_irq (irq1, &c4_ebus_interrupt, IRQF_SHARED, ndev->name, ndev)) - { - pr_warning("%s: EBUS could not get irq: %d\n", hi->devname, irq1); - unregister_netdev (ndev); - free_irq (irq0, ndev); - OS_kfree (netdev_priv(ndev)); - OS_kfree (ndev); - error_flag = EIO; - return NULL; - } + if (request_irq(irq1, &c4_ebus_interrupt, IRQF_SHARED, ndev->name, ndev)) + { + pr_warning("%s: EBUS could not get irq: %d\n", hi->devname, irq1); + unregister_netdev(ndev); + free_irq(irq0, ndev); + OS_kfree(netdev_priv(ndev)); + OS_kfree(ndev); + error_flag = EIO; + return NULL; + } #endif - /* setup board identification information */ - - { - u_int32_t tmp; - - hdw_sn_get (hi, brdno); /* also sets PROM format type (promfmt) - * for later usage */ - - switch (hi->promfmt) - { - case PROM_FORMAT_TYPE1: - memcpy (ndev->dev_addr, (FLD_TYPE1 *) (hi->mfg_info.pft1.Serial), 6); - memcpy (&tmp, (FLD_TYPE1 *) (hi->mfg_info.pft1.Id), 4); /* unaligned data - * acquisition */ - ci->brd_id = cpu_to_be32 (tmp); - break; - case PROM_FORMAT_TYPE2: - memcpy (ndev->dev_addr, (FLD_TYPE2 *) (hi->mfg_info.pft2.Serial), 6); - memcpy (&tmp, (FLD_TYPE2 *) (hi->mfg_info.pft2.Id), 4); /* unaligned data - * acquisition */ - ci->brd_id = cpu_to_be32 (tmp); - break; - default: - ci->brd_id = 0; - memset (ndev->dev_addr, 0, 6); - break; - } + /* setup board identification information */ + + { + u_int32_t tmp; + + /* also sets PROM format type (promfmt) for later usage */ + hdw_sn_get(hi, brdno); + + switch (hi->promfmt) + { + case PROM_FORMAT_TYPE1: + memcpy(ndev->dev_addr, + (FLD_TYPE1 *) (hi->mfg_info.pft1.Serial), 6); + /* unaligned data acquisition */ + memcpy(&tmp, (FLD_TYPE1 *) (hi->mfg_info.pft1.Id), 4); + ci->brd_id = cpu_to_be32(tmp); + break; + case PROM_FORMAT_TYPE2: + memcpy(ndev->dev_addr, + (FLD_TYPE2 *) (hi->mfg_info.pft2.Serial), 6); + /* unaligned data acquisition */ + memcpy(&tmp, (FLD_TYPE2 *) (hi->mfg_info.pft2.Id), 4); + ci->brd_id = cpu_to_be32(tmp); + break; + default: + ci->brd_id = 0; + memset(ndev->dev_addr, 0, 6); + break; + } #if 1 - sbeid_set_hdwbid (ci); /* requires bid to be preset */ + /* requires bid to be preset */ + sbeid_set_hdwbid(ci); #else - sbeid_set_bdtype (ci); /* requires hdw_bid to be preset */ + /* requires hdw_bid to be preset */ + sbeid_set_bdtype(ci); #endif - - } + } #ifdef CONFIG_PROC_FS - sbecom_proc_brd_init (ci); + sbecom_proc_brd_init(ci); #endif #if defined(SBE_ISR_TASKLET) - tasklet_enable (&ci->ci_musycc_isr_tasklet); + tasklet_enable(&ci->ci_musycc_isr_tasklet); #endif - if ((error_flag = c4_init2 (ci)) != SBE_DRVR_SUCCESS) - { + if ((error_flag = c4_init2(ci)) != SBE_DRVR_SUCCESS) + { #ifdef CONFIG_PROC_FS - sbecom_proc_brd_cleanup (ci); + sbecom_proc_brd_cleanup(ci); #endif - unregister_netdev (ndev); - free_irq (irq1, ndev); - free_irq (irq0, ndev); - OS_kfree (netdev_priv(ndev)); - OS_kfree (ndev); - return NULL; /* failure, error_flag is set */ - } - return ndev; + unregister_netdev(ndev); + free_irq(irq1, ndev); + free_irq(irq0, ndev); + OS_kfree(netdev_priv(ndev)); + OS_kfree(ndev); + /* failure, error_flag is set */ + return NULL; + } + return ndev; } static int __init -c4_mod_init (void) +c4_mod_init(void) { - int rtn; - - pr_warning("%s\n", pmcc4_OSSI_release); - if ((rtn = c4hw_attach_all ())) - return -rtn; /* installation failure - see system log */ - - /* housekeeping notifications */ - if (cxt1e1_log_level != log_level_default) - pr_info("NOTE: driver parameter <cxt1e1_log_level> changed from default %d to %d.\n", - log_level_default, cxt1e1_log_level); - if (cxt1e1_max_mru != max_mru_default) - pr_info("NOTE: driver parameter <cxt1e1_max_mru> changed from default %d to %d.\n", - max_mru_default, cxt1e1_max_mru); - if (cxt1e1_max_mtu != max_mtu_default) - pr_info("NOTE: driver parameter <cxt1e1_max_mtu> changed from default %d to %d.\n", - max_mtu_default, cxt1e1_max_mtu); - if (max_rxdesc_used != max_rxdesc_default) - { - if (max_rxdesc_used > 2000) - max_rxdesc_used = 2000; /* out-of-bounds reset */ - pr_info("NOTE: driver parameter <max_rxdesc_used> changed from default %d to %d.\n", - max_rxdesc_default, max_rxdesc_used); - } - if (max_txdesc_used != max_txdesc_default) - { - if (max_txdesc_used > 1000) - max_txdesc_used = 1000; /* out-of-bounds reset */ - pr_info("NOTE: driver parameter <max_txdesc_used> changed from default %d to %d.\n", - max_txdesc_default, max_txdesc_used); - } - return 0; /* installation success */ + int rtn; + + pr_warning("%s\n", pmcc4_OSSI_release); + if ((rtn = c4hw_attach_all())) + return -rtn; /* installation failure - see system log */ + + /* housekeeping notifications */ + if (cxt1e1_log_level != log_level_default) + pr_info("NOTE: driver parameter <cxt1e1_log_level> changed from default %d to %d.\n", + log_level_default, cxt1e1_log_level); + if (cxt1e1_max_mru != max_mru_default) + pr_info("NOTE: driver parameter <cxt1e1_max_mru> changed from default %d to %d.\n", + max_mru_default, cxt1e1_max_mru); + if (cxt1e1_max_mtu != max_mtu_default) + pr_info("NOTE: driver parameter <cxt1e1_max_mtu> changed from default %d to %d.\n", + max_mtu_default, cxt1e1_max_mtu); + if (max_rxdesc_used != max_rxdesc_default) + { + if (max_rxdesc_used > 2000) + max_rxdesc_used = 2000; /* out-of-bounds reset */ + pr_info("NOTE: driver parameter <max_rxdesc_used> changed from default %d to %d.\n", + max_rxdesc_default, max_rxdesc_used); + } + if (max_txdesc_used != max_txdesc_default) + { + if (max_txdesc_used > 1000) + max_txdesc_used = 1000; /* out-of-bounds reset */ + pr_info("NOTE: driver parameter <max_txdesc_used> changed from default %d to %d.\n", + max_txdesc_default, max_txdesc_used); + } + return 0; /* installation success */ } @@ -1138,31 +1160,31 @@ c4_mod_init (void) */ static void __exit -cleanup_hdlc (void) +cleanup_hdlc(void) { - hdw_info_t *hi; - ci_t *ci; - struct net_device *ndev; - int i, j, k; - - for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++) - { - if (hi->ndev) /* a board has been attached */ - { - ci = (ci_t *)(netdev_priv(hi->ndev)); - for (j = 0; j < ci->max_port; j++) - for (k = 0; k < MUSYCC_NCHANS; k++) - if ((ndev = ci->port[j].chan[k]->user)) - { - do_deluser (ndev, 0); - } - } - } + hdw_info_t *hi; + ci_t *ci; + struct net_device *ndev; + int i, j, k; + + for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++) + { + if (hi->ndev) /* a board has been attached */ + { + ci = (ci_t *)(netdev_priv(hi->ndev)); + for (j = 0; j < ci->max_port; j++) + for (k = 0; k < MUSYCC_NCHANS; k++) + if ((ndev = ci->port[j].chan[k]->user)) + { + do_deluser(ndev, 0); + } + } + } } static void __exit -c4_mod_remove (void) +c4_mod_remove(void) { cleanup_hdlc(); /* delete any missed channels */ cleanup_devs(); @@ -1171,13 +1193,13 @@ c4_mod_remove (void) pr_info("SBE - driver removed.\n"); } -module_init (c4_mod_init); -module_exit (c4_mod_remove); +module_init(c4_mod_init); +module_exit(c4_mod_remove); -MODULE_AUTHOR ("SBE Technical Services <support@sbei.com>"); -MODULE_DESCRIPTION ("wanPCI-CxT1E1 Generic HDLC WAN Driver module"); +MODULE_AUTHOR("SBE Technical Services <support@sbei.com>"); +MODULE_DESCRIPTION("wanPCI-CxT1E1 Generic HDLC WAN Driver module"); #ifdef MODULE_LICENSE -MODULE_LICENSE ("GPL"); +MODULE_LICENSE("GPL"); #endif /*** End-of-File ***/ diff --git a/drivers/staging/dgap/Makefile b/drivers/staging/dgap/Makefile index 3abe8d2bb74..0063d044ca7 100644 --- a/drivers/staging/dgap/Makefile +++ b/drivers/staging/dgap/Makefile @@ -1,7 +1 @@ obj-$(CONFIG_DGAP) += dgap.o - - -dgap-objs := dgap_driver.o dgap_fep5.o \ - dgap_parse.o dgap_trace.o \ - dgap_tty.o dgap_sysfs.o - diff --git a/drivers/staging/dgap/dgap.c b/drivers/staging/dgap/dgap.c new file mode 100644 index 00000000000..cbce4577623 --- /dev/null +++ b/drivers/staging/dgap/dgap.c @@ -0,0 +1,7857 @@ +/* + * Copyright 2003 Digi International (www.digi.com) + * Scott H Kilau <Scott_Kilau at digi dot com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + * NOTE TO LINUX KERNEL HACKERS: DO NOT REFORMAT THIS CODE! + * + * This is shared code between Digi's CVS archive and the + * Linux Kernel sources. + * Changing the source just for reformatting needlessly breaks + * our CVS diff history. + * + * Send any bug fixes/changes to: Eng.Linux at digi dot com. + * Thank you. + * + */ + +/* + * In the original out of kernel Digi dgap driver, firmware + * loading was done via user land to driver handshaking. + * + * For cards that support a concentrator (port expander), + * I believe the concentrator its self told the card which + * concentrator is actually attached and then that info + * was used to tell user land which concentrator firmware + * image was to be downloaded. I think even the BIOS or + * FEP images required could change with the connection + * of a particular concentrator. + * + * Since I have no access to any of these cards or + * concentrators, I cannot put the correct concentrator + * firmware file names into the firmware_info structure + * as is now done for the BIOS and FEP images. + * + * I think, but am not certain, that the cards supporting + * concentrators will function without them. So support + * of these cards has been left in this driver. + * + * In order to fully support those cards, they would + * either have to be acquired for dissection or maybe + * Digi International could provide some assistance. + */ +#undef DIGI_CONCENTRATORS_SUPPORTED + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/delay.h> /* For udelay */ +#include <linux/slab.h> +#include <linux/uaccess.h> +#include <linux/sched.h> + +#include <linux/interrupt.h> /* For tasklet and interrupt structs/defines */ +#include <linux/ctype.h> +#include <linux/tty.h> +#include <linux/tty_flip.h> +#include <linux/serial_reg.h> +#include <linux/io.h> /* For read[bwl]/write[bwl] */ + +#include <linux/string.h> +#include <linux/device.h> +#include <linux/kdev_t.h> +#include <linux/firmware.h> + +#include "dgap.h" + +#define init_MUTEX(sem) sema_init(sem, 1) +#define DECLARE_MUTEX(name) \ + struct semaphore name = __SEMAPHORE_INITIALIZER(name, 1) + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Digi International, http://www.digi.com"); +MODULE_DESCRIPTION("Driver for the Digi International EPCA PCI based product line"); +MODULE_SUPPORTED_DEVICE("dgap"); + +/* + * insmod command line overrideable parameters + * + * NOTE: we use a set of macros to create the variables, which allows + * us to specify the variable type, name, initial value, and description. + */ +PARM_INT(rawreadok, 1, 0644, "Bypass flip buffers on input"); + + +/************************************************************************** + * + * protos for this file + * + */ + +static int dgap_start(void); +static void dgap_init_globals(void); +static int dgap_found_board(struct pci_dev *pdev, int id); +static void dgap_cleanup_board(struct board_t *brd); +static void dgap_poll_handler(ulong dummy); +static int dgap_init_pci(void); +static int dgap_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); +static void dgap_remove_one(struct pci_dev *dev); +static int dgap_probe1(struct pci_dev *pdev, int card_type); +static int dgap_do_remap(struct board_t *brd); +static irqreturn_t dgap_intr(int irq, void *voidbrd); + +/* Our function prototypes */ +static int dgap_tty_open(struct tty_struct *tty, struct file *file); +static void dgap_tty_close(struct tty_struct *tty, struct file *file); +static int dgap_block_til_ready(struct tty_struct *tty, struct file *file, struct channel_t *ch); +static int dgap_tty_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg); +static int dgap_tty_digigeta(struct tty_struct *tty, struct digi_t __user *retinfo); +static int dgap_tty_digiseta(struct tty_struct *tty, struct digi_t __user *new_info); +static int dgap_tty_digigetedelay(struct tty_struct *tty, int __user *retinfo); +static int dgap_tty_digisetedelay(struct tty_struct *tty, int __user *new_info); +static int dgap_tty_write_room(struct tty_struct *tty); +static int dgap_tty_chars_in_buffer(struct tty_struct *tty); +static void dgap_tty_start(struct tty_struct *tty); +static void dgap_tty_stop(struct tty_struct *tty); +static void dgap_tty_throttle(struct tty_struct *tty); +static void dgap_tty_unthrottle(struct tty_struct *tty); +static void dgap_tty_flush_chars(struct tty_struct *tty); +static void dgap_tty_flush_buffer(struct tty_struct *tty); +static void dgap_tty_hangup(struct tty_struct *tty); +static int dgap_wait_for_drain(struct tty_struct *tty); +static int dgap_set_modem_info(struct tty_struct *tty, unsigned int command, unsigned int __user *value); +static int dgap_get_modem_info(struct channel_t *ch, unsigned int __user *value); +static int dgap_tty_digisetcustombaud(struct tty_struct *tty, int __user *new_info); +static int dgap_tty_digigetcustombaud(struct tty_struct *tty, int __user *retinfo); +static int dgap_tty_tiocmget(struct tty_struct *tty); +static int dgap_tty_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear); +static int dgap_tty_send_break(struct tty_struct *tty, int msec); +static void dgap_tty_wait_until_sent(struct tty_struct *tty, int timeout); +static int dgap_tty_write(struct tty_struct *tty, const unsigned char *buf, int count); +static void dgap_tty_set_termios(struct tty_struct *tty, struct ktermios *old_termios); +static int dgap_tty_put_char(struct tty_struct *tty, unsigned char c); +static void dgap_tty_send_xchar(struct tty_struct *tty, char ch); + +static int dgap_tty_register(struct board_t *brd); +static int dgap_tty_preinit(void); +static int dgap_tty_init(struct board_t *); +static void dgap_tty_post_uninit(void); +static void dgap_tty_uninit(struct board_t *); +static void dgap_carrier(struct channel_t *ch); +static void dgap_input(struct channel_t *ch); + +/* + * Our function prototypes from dgap_fep5 + */ +static void dgap_cmdw_ext(struct channel_t *ch, u16 cmd, u16 word, uint ncmds); +static int dgap_event(struct board_t *bd); + +static void dgap_poll_tasklet(unsigned long data); +static void dgap_cmdb(struct channel_t *ch, uchar cmd, uchar byte1, uchar byte2, uint ncmds); +static void dgap_cmdw(struct channel_t *ch, uchar cmd, u16 word, uint ncmds); +static void dgap_wmove(struct channel_t *ch, char *buf, uint cnt); +static int dgap_param(struct tty_struct *tty); +static void dgap_parity_scan(struct channel_t *ch, unsigned char *cbuf, unsigned char *fbuf, int *len); +static uint dgap_get_custom_baud(struct channel_t *ch); +static void dgap_firmware_reset_port(struct channel_t *ch); + +/* + * Function prototypes from dgap_parse.c. + */ +static int dgap_gettok(char **in, struct cnode *p); +static char *dgap_getword(char **in); +static char *dgap_savestring(char *s); +static struct cnode *dgap_newnode(int t); +static int dgap_checknode(struct cnode *p); +static void dgap_err(char *s); + +/* + * Function prototypes from dgap_sysfs.h + */ +struct board_t; +struct channel_t; +struct un_t; +struct pci_driver; +struct class_device; + +static void dgap_create_ports_sysfiles(struct board_t *bd); +static void dgap_remove_ports_sysfiles(struct board_t *bd); + +static void dgap_create_driver_sysfiles(struct pci_driver *); +static void dgap_remove_driver_sysfiles(struct pci_driver *); + +static void dgap_create_tty_sysfs(struct un_t *un, struct device *c); +static void dgap_remove_tty_sysfs(struct device *c); + +/* + * Function prototypes from dgap_parse.h + */ +static int dgap_parsefile(char **in, int Remove); +static struct cnode *dgap_find_config(int type, int bus, int slot); +static uint dgap_config_get_number_of_ports(struct board_t *bd); +static char *dgap_create_config_string(struct board_t *bd, char *string); +static uint dgap_config_get_useintr(struct board_t *bd); +static uint dgap_config_get_altpin(struct board_t *bd); + +static int dgap_ms_sleep(ulong ms); +static void dgap_do_bios_load(struct board_t *brd, uchar __user *ubios, int len); +static void dgap_do_fep_load(struct board_t *brd, uchar __user *ufep, int len); +#ifdef DIGI_CONCENTRATORS_SUPPORTED +static void dgap_do_conc_load(struct board_t *brd, uchar *uaddr, int len); +#endif +static int dgap_after_config_loaded(int board); +static int dgap_finalize_board_init(struct board_t *brd); + +static void dgap_get_vpd(struct board_t *brd); +static void dgap_do_reset_board(struct board_t *brd); +static void dgap_do_wait_for_bios(struct board_t *brd); +static void dgap_do_wait_for_fep(struct board_t *brd); +static int dgap_tty_register_ports(struct board_t *brd); +static int dgap_firmware_load(struct pci_dev *pdev, int card_type); + +/* Driver load/unload functions */ +int dgap_init_module(void); +void dgap_cleanup_module(void); + +module_init(dgap_init_module); +module_exit(dgap_cleanup_module); + +/* + * File operations permitted on Control/Management major. + */ +static const struct file_operations DgapBoardFops = { + .owner = THIS_MODULE, +}; + +/* + * Globals + */ +static uint dgap_NumBoards; +static struct board_t *dgap_Board[MAXBOARDS]; +DEFINE_SPINLOCK(dgap_global_lock); +static ulong dgap_poll_counter; +static char *dgap_config_buf; +static int dgap_driver_state = DRIVER_INITIALIZED; +DEFINE_SPINLOCK(dgap_dl_lock); +static wait_queue_head_t dgap_dl_wait; +static int dgap_dl_action; +static int dgap_poll_tick = 20; /* Poll interval - 20 ms */ + +/* + * Static vars. + */ +static int dgap_Major_Control_Registered = FALSE; +static uint dgap_driver_start = FALSE; + +static struct class *dgap_class; + +static struct board_t *dgap_BoardsByMajor[256]; +static uchar *dgap_TmpWriteBuf = NULL; +DECLARE_MUTEX(dgap_TmpWriteSem); +static uint dgap_count = 500; + +/* + * Poller stuff + */ +DEFINE_SPINLOCK(dgap_poll_lock); /* Poll scheduling lock */ +static ulong dgap_poll_time; /* Time of next poll */ +static uint dgap_poll_stop; /* Used to tell poller to stop */ +static struct timer_list dgap_poll_timer; + +/* + SUPPORTED PRODUCTS + + Card Model Number of Ports Interface + ---------------------------------------------------------------- + Acceleport Xem 4 - 64 (EIA232 & EIA422) + Acceleport Xr 4 & 8 (EIA232) + Acceleport Xr 920 4 & 8 (EIA232) + Acceleport C/X 8 - 128 (EIA232) + Acceleport EPC/X 8 - 224 (EIA232) + Acceleport Xr/422 4 & 8 (EIA422) + Acceleport 2r/920 2 (EIA232) + Acceleport 4r/920 4 (EIA232) + Acceleport 8r/920 8 (EIA232) + + IBM 8-Port Asynchronous PCI Adapter (EIA232) + IBM 128-Port Asynchronous PCI Adapter (EIA232 & EIA422) +*/ + +static struct pci_device_id dgap_pci_tbl[] = { + { DIGI_VID, PCI_DEVICE_XEM_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { DIGI_VID, PCI_DEVICE_CX_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 }, + { DIGI_VID, PCI_DEVICE_CX_IBM_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2 }, + { DIGI_VID, PCI_DEVICE_EPCJ_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3 }, + { DIGI_VID, PCI_DEVICE_920_2_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 }, + { DIGI_VID, PCI_DEVICE_920_4_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5 }, + { DIGI_VID, PCI_DEVICE_920_8_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6 }, + { DIGI_VID, PCI_DEVICE_XR_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 7 }, + { DIGI_VID, PCI_DEVICE_XRJ_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 }, + { DIGI_VID, PCI_DEVICE_XR_422_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 9 }, + { DIGI_VID, PCI_DEVICE_XR_IBM_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 10 }, + { DIGI_VID, PCI_DEVICE_XR_SAIP_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 11 }, + { DIGI_VID, PCI_DEVICE_XR_BULL_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 12 }, + { DIGI_VID, PCI_DEVICE_920_8_HP_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 13 }, + { DIGI_VID, PCI_DEVICE_XEM_HP_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 14 }, + {0,} /* 0 terminated list. */ +}; +MODULE_DEVICE_TABLE(pci, dgap_pci_tbl); + +/* + * A generic list of Product names, PCI Vendor ID, and PCI Device ID. + */ +struct board_id { + uint config_type; + uchar *name; + uint maxports; + uint dpatype; +}; + +static struct board_id dgap_Ids[] = { + { PPCM, PCI_DEVICE_XEM_NAME, 64, (T_PCXM | T_PCLITE | T_PCIBUS) }, + { PCX, PCI_DEVICE_CX_NAME, 128, (T_CX | T_PCIBUS) }, + { PCX, PCI_DEVICE_CX_IBM_NAME, 128, (T_CX | T_PCIBUS) }, + { PEPC, PCI_DEVICE_EPCJ_NAME, 224, (T_EPC | T_PCIBUS) }, + { APORT2_920P, PCI_DEVICE_920_2_NAME, 2, (T_PCXR | T_PCLITE | T_PCIBUS) }, + { APORT4_920P, PCI_DEVICE_920_4_NAME, 4, (T_PCXR | T_PCLITE | T_PCIBUS) }, + { APORT8_920P, PCI_DEVICE_920_8_NAME, 8, (T_PCXR | T_PCLITE | T_PCIBUS) }, + { PAPORT8, PCI_DEVICE_XR_NAME, 8, (T_PCXR | T_PCLITE | T_PCIBUS) }, + { PAPORT8, PCI_DEVICE_XRJ_NAME, 8, (T_PCXR | T_PCLITE | T_PCIBUS) }, + { PAPORT8, PCI_DEVICE_XR_422_NAME, 8, (T_PCXR | T_PCLITE | T_PCIBUS) }, + { PAPORT8, PCI_DEVICE_XR_IBM_NAME, 8, (T_PCXR | T_PCLITE | T_PCIBUS) }, + { PAPORT8, PCI_DEVICE_XR_SAIP_NAME, 8, (T_PCXR | T_PCLITE | T_PCIBUS) }, + { PAPORT8, PCI_DEVICE_XR_BULL_NAME, 8, (T_PCXR | T_PCLITE | T_PCIBUS) }, + { APORT8_920P, PCI_DEVICE_920_8_HP_NAME, 8, (T_PCXR | T_PCLITE | T_PCIBUS) }, + { PPCM, PCI_DEVICE_XEM_HP_NAME, 64, (T_PCXM | T_PCLITE | T_PCIBUS) }, + {0,} /* 0 terminated list. */ +}; + +static struct pci_driver dgap_driver = { + .name = "dgap", + .probe = dgap_init_one, + .id_table = dgap_pci_tbl, + .remove = dgap_remove_one, +}; + +struct firmware_info { + uchar *conf_name; /* dgap.conf */ + uchar *bios_name; /* BIOS filename */ + uchar *fep_name; /* FEP filename */ + uchar *con_name; /* Concentrator filename FIXME*/ + int num; /* sequence number */ +}; + +/* + * Firmware - BIOS, FEP, and CONC filenames + */ +static struct firmware_info fw_info[] = { + { "dgap/dgap.conf", "dgap/sxbios.bin", "dgap/sxfep.bin", 0, 0 }, + { "dgap/dgap.conf", "dgap/cxpbios.bin", "dgap/cxpfep.bin", 0, 1 }, + { "dgap/dgap.conf", "dgap/cxpbios.bin", "dgap/cxpfep.bin", 0, 2 }, + { "dgap/dgap.conf", "dgap/pcibios.bin", "dgap/pcifep.bin", 0, 3 }, + { "dgap/dgap.conf", "dgap/xrbios.bin", "dgap/xrfep.bin", 0, 4 }, + { "dgap/dgap.conf", "dgap/xrbios.bin", "dgap/xrfep.bin", 0, 5 }, + { "dgap/dgap.conf", "dgap/xrbios.bin", "dgap/xrfep.bin", 0, 6 }, + { "dgap/dgap.conf", "dgap/xrbios.bin", "dgap/xrfep.bin", 0, 7 }, + { "dgap/dgap.conf", "dgap/xrbios.bin", "dgap/xrfep.bin", 0, 8 }, + { "dgap/dgap.conf", "dgap/xrbios.bin", "dgap/xrfep.bin", 0, 9 }, + { "dgap/dgap.conf", "dgap/xrbios.bin", "dgap/xrfep.bin", 0, 10 }, + { "dgap/dgap.conf", "dgap/xrbios.bin", "dgap/xrfep.bin", 0, 11 }, + { "dgap/dgap.conf", "dgap/xrbios.bin", "dgap/xrfep.bin", 0, 12 }, + { "dgap/dgap.conf", "dgap/xrbios.bin", "dgap/xrfep.bin", 0, 13 }, + { "dgap/dgap.conf", "dgap/sxbios.bin", "dgap/sxfep.bin", 0, 14 }, + {0,} +}; + +static char *dgap_driver_state_text[] = { + "Driver Initialized", + "Driver needs configuration load.", + "Driver requested configuration from download daemon.", + "Driver Ready." +}; + +/* + * Default transparent print information. + */ +static struct digi_t dgap_digi_init = { + .digi_flags = DIGI_COOK, /* Flags */ + .digi_maxcps = 100, /* Max CPS */ + .digi_maxchar = 50, /* Max chars in print queue */ + .digi_bufsize = 100, /* Printer buffer size */ + .digi_onlen = 4, /* size of printer on string */ + .digi_offlen = 4, /* size of printer off string */ + .digi_onstr = "\033[5i", /* ANSI printer on string ] */ + .digi_offstr = "\033[4i", /* ANSI printer off string ] */ + .digi_term = "ansi" /* default terminal type */ +}; + +/* + * Define a local default termios struct. All ports will be created + * with this termios initially. + * + * This defines a raw port at 9600 baud, 8 data bits, no parity, + * 1 stop bit. + */ + +static struct ktermios DgapDefaultTermios = { + .c_iflag = (DEFAULT_IFLAGS), /* iflags */ + .c_oflag = (DEFAULT_OFLAGS), /* oflags */ + .c_cflag = (DEFAULT_CFLAGS), /* cflags */ + .c_lflag = (DEFAULT_LFLAGS), /* lflags */ + .c_cc = INIT_C_CC, + .c_line = 0, +}; + +static const struct tty_operations dgap_tty_ops = { + .open = dgap_tty_open, + .close = dgap_tty_close, + .write = dgap_tty_write, + .write_room = dgap_tty_write_room, + .flush_buffer = dgap_tty_flush_buffer, + .chars_in_buffer = dgap_tty_chars_in_buffer, + .flush_chars = dgap_tty_flush_chars, + .ioctl = dgap_tty_ioctl, + .set_termios = dgap_tty_set_termios, + .stop = dgap_tty_stop, + .start = dgap_tty_start, + .throttle = dgap_tty_throttle, + .unthrottle = dgap_tty_unthrottle, + .hangup = dgap_tty_hangup, + .put_char = dgap_tty_put_char, + .tiocmget = dgap_tty_tiocmget, + .tiocmset = dgap_tty_tiocmset, + .break_ctl = dgap_tty_send_break, + .wait_until_sent = dgap_tty_wait_until_sent, + .send_xchar = dgap_tty_send_xchar +}; + +/* + * Our needed internal static variables from dgap_parse.c + */ +static struct cnode dgap_head; +#define MAXCWORD 200 +static char dgap_cword[MAXCWORD]; + +struct toklist { + int token; + char *string; +}; + +static struct toklist dgap_tlist[] = { + { BEGIN, "config_begin" }, + { END, "config_end" }, + { BOARD, "board" }, + { PCX, "Digi_AccelePort_C/X_PCI" }, /* C/X_PCI */ + { PEPC, "Digi_AccelePort_EPC/X_PCI" }, /* EPC/X_PCI */ + { PPCM, "Digi_AccelePort_Xem_PCI" }, /* PCI/Xem */ + { APORT2_920P, "Digi_AccelePort_2r_920_PCI" }, + { APORT4_920P, "Digi_AccelePort_4r_920_PCI" }, + { APORT8_920P, "Digi_AccelePort_8r_920_PCI" }, + { PAPORT4, "Digi_AccelePort_4r_PCI(EIA-232/RS-422)" }, + { PAPORT8, "Digi_AccelePort_8r_PCI(EIA-232/RS-422)" }, + { IO, "io" }, + { PCIINFO, "pciinfo" }, + { LINE, "line" }, + { CONC, "conc" }, + { CONC, "concentrator" }, + { CX, "cx" }, + { CX, "ccon" }, + { EPC, "epccon" }, + { EPC, "epc" }, + { MOD, "module" }, + { ID, "id" }, + { STARTO, "start" }, + { SPEED, "speed" }, + { CABLE, "cable" }, + { CONNECT, "connect" }, + { METHOD, "method" }, + { STATUS, "status" }, + { CUSTOM, "Custom" }, + { BASIC, "Basic" }, + { MEM, "mem" }, + { MEM, "memory" }, + { PORTS, "ports" }, + { MODEM, "modem" }, + { NPORTS, "nports" }, + { TTYN, "ttyname" }, + { CU, "cuname" }, + { PRINT, "prname" }, + { CMAJOR, "major" }, + { ALTPIN, "altpin" }, + { USEINTR, "useintr" }, + { TTSIZ, "ttysize" }, + { CHSIZ, "chsize" }, + { BSSIZ, "boardsize" }, + { UNTSIZ, "schedsize" }, + { F2SIZ, "f2200size" }, + { VPSIZ, "vpixsize" }, + { 0, NULL } +}; + +/************************************************************************ + * + * Driver load/unload functions + * + ************************************************************************/ + +/* + * init_module() + * + * Module load. This is where it all starts. + */ +int dgap_init_module(void) +{ + int rc = 0; + + pr_info("%s, Digi International Part Number %s\n", DG_NAME, DG_PART); + + dgap_driver_state = DRIVER_NEED_CONFIG_LOAD; + + /* + * Initialize global stuff + */ + rc = dgap_start(); + + if (rc < 0) + return rc; + + /* + * Find and configure all the cards + */ + rc = dgap_init_pci(); + + /* + * If something went wrong in the scan, bail out of driver. + */ + if (rc < 0) { + /* Only unregister the pci driver if it was actually registered. */ + if (dgap_NumBoards) + pci_unregister_driver(&dgap_driver); + else + printk("WARNING: dgap driver load failed. No DGAP boards found.\n"); + + dgap_cleanup_module(); + } else { + dgap_create_driver_sysfiles(&dgap_driver); + dgap_driver_state = DRIVER_READY; + } + + return rc; +} + +/* + * Start of driver. + */ +static int dgap_start(void) +{ + int rc = 0; + unsigned long flags; + + if (dgap_driver_start == FALSE) { + + dgap_driver_start = TRUE; + + /* + * make sure that the globals are + * init'd before we do anything else + */ + dgap_init_globals(); + + dgap_NumBoards = 0; + + pr_info("For the tools package please visit http://www.digi.com\n"); + + /* + * Register our base character device into the kernel. + * This allows the download daemon to connect to the downld device + * before any of the boards are init'ed. + */ + if (!dgap_Major_Control_Registered) { + /* + * Register management/dpa devices + */ + rc = register_chrdev(DIGI_DGAP_MAJOR, "dgap", &DgapBoardFops); + if (rc < 0) + return rc; + + dgap_class = class_create(THIS_MODULE, "dgap_mgmt"); + device_create(dgap_class, NULL, + MKDEV(DIGI_DGAP_MAJOR, 0), + NULL, "dgap_mgmt"); + dgap_Major_Control_Registered = TRUE; + } + + /* + * Init any global tty stuff. + */ + rc = dgap_tty_preinit(); + + if (rc < 0) + return rc; + + /* Start the poller */ + DGAP_LOCK(dgap_poll_lock, flags); + init_timer(&dgap_poll_timer); + dgap_poll_timer.function = dgap_poll_handler; + dgap_poll_timer.data = 0; + dgap_poll_time = jiffies + dgap_jiffies_from_ms(dgap_poll_tick); + dgap_poll_timer.expires = dgap_poll_time; + DGAP_UNLOCK(dgap_poll_lock, flags); + + add_timer(&dgap_poll_timer); + + dgap_driver_state = DRIVER_NEED_CONFIG_LOAD; + } + + return rc; +} + +/* + * Register pci driver, and return how many boards we have. + */ +static int dgap_init_pci(void) +{ + return pci_register_driver(&dgap_driver); +} + +/* returns count (>= 0), or negative on error */ +static int dgap_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + int rc; + + /* wake up and enable device */ + rc = pci_enable_device(pdev); + + if (rc < 0) { + rc = -EIO; + } else { + rc = dgap_probe1(pdev, ent->driver_data); + if (rc == 0) { + dgap_NumBoards++; + rc = dgap_firmware_load(pdev, ent->driver_data); + } + } + return rc; +} + +static int dgap_probe1(struct pci_dev *pdev, int card_type) +{ + return dgap_found_board(pdev, card_type); +} + +static void dgap_remove_one(struct pci_dev *dev) +{ + /* Do Nothing */ +} + +/* + * dgap_cleanup_module() + * + * Module unload. This is where it all ends. + */ +void dgap_cleanup_module(void) +{ + int i; + ulong lock_flags; + + DGAP_LOCK(dgap_poll_lock, lock_flags); + dgap_poll_stop = 1; + DGAP_UNLOCK(dgap_poll_lock, lock_flags); + + /* Turn off poller right away. */ + del_timer_sync(&dgap_poll_timer); + + dgap_remove_driver_sysfiles(&dgap_driver); + + + if (dgap_Major_Control_Registered) { + device_destroy(dgap_class, MKDEV(DIGI_DGAP_MAJOR, 0)); + device_destroy(dgap_class, MKDEV(DIGI_DGAP_MAJOR, 1)); + class_destroy(dgap_class); + unregister_chrdev(DIGI_DGAP_MAJOR, "dgap"); + } + + kfree(dgap_config_buf); + + for (i = 0; i < dgap_NumBoards; ++i) { + dgap_remove_ports_sysfiles(dgap_Board[i]); + dgap_tty_uninit(dgap_Board[i]); + dgap_cleanup_board(dgap_Board[i]); + } + + dgap_tty_post_uninit(); + +#if defined(DGAP_TRACER) + /* last thing, make sure we release the tracebuffer */ + dgap_tracer_free(); +#endif + if (dgap_NumBoards) + pci_unregister_driver(&dgap_driver); +} + +/* + * dgap_cleanup_board() + * + * Free all the memory associated with a board + */ +static void dgap_cleanup_board(struct board_t *brd) +{ + int i = 0; + + if (!brd || brd->magic != DGAP_BOARD_MAGIC) + return; + + if (brd->intr_used && brd->irq) + free_irq(brd->irq, brd); + + tasklet_kill(&brd->helper_tasklet); + + if (brd->re_map_port) { + release_mem_region(brd->membase + 0x200000, 0x200000); + iounmap(brd->re_map_port); + brd->re_map_port = NULL; + } + + if (brd->re_map_membase) { + release_mem_region(brd->membase, 0x200000); + iounmap(brd->re_map_membase); + brd->re_map_membase = NULL; + } + + if (brd->msgbuf_head) { + unsigned long flags; + + DGAP_LOCK(dgap_global_lock, flags); + brd->msgbuf = NULL; + printk("%s", brd->msgbuf_head); + kfree(brd->msgbuf_head); + brd->msgbuf_head = NULL; + DGAP_UNLOCK(dgap_global_lock, flags); + } + + /* Free all allocated channels structs */ + for (i = 0; i < MAXPORTS ; i++) { + if (brd->channels[i]) { + kfree(brd->channels[i]); + brd->channels[i] = NULL; + } + } + + kfree(brd->flipbuf); + kfree(brd->flipflagbuf); + + dgap_Board[brd->boardnum] = NULL; + + kfree(brd); +} + +/* + * dgap_found_board() + * + * A board has been found, init it. + */ +static int dgap_found_board(struct pci_dev *pdev, int id) +{ + struct board_t *brd; + unsigned int pci_irq; + int i = 0; + unsigned long flags; + + /* get the board structure and prep it */ + brd = dgap_Board[dgap_NumBoards] = + (struct board_t *) kzalloc(sizeof(struct board_t), GFP_KERNEL); + if (!brd) + return -ENOMEM; + + /* make a temporary message buffer for the boot messages */ + brd->msgbuf = brd->msgbuf_head = + (char *) kzalloc(sizeof(char) * 8192, GFP_KERNEL); + if (!brd->msgbuf) { + kfree(brd); + return -ENOMEM; + } + + /* store the info for the board we've found */ + brd->magic = DGAP_BOARD_MAGIC; + brd->boardnum = dgap_NumBoards; + brd->firstminor = 0; + brd->vendor = dgap_pci_tbl[id].vendor; + brd->device = dgap_pci_tbl[id].device; + brd->pdev = pdev; + brd->pci_bus = pdev->bus->number; + brd->pci_slot = PCI_SLOT(pdev->devfn); + brd->name = dgap_Ids[id].name; + brd->maxports = dgap_Ids[id].maxports; + brd->type = dgap_Ids[id].config_type; + brd->dpatype = dgap_Ids[id].dpatype; + brd->dpastatus = BD_NOFEP; + init_waitqueue_head(&brd->state_wait); + + DGAP_SPINLOCK_INIT(brd->bd_lock); + + brd->state = BOARD_FOUND; + brd->runwait = 0; + brd->inhibit_poller = FALSE; + brd->wait_for_bios = 0; + brd->wait_for_fep = 0; + + for (i = 0; i < MAXPORTS; i++) + brd->channels[i] = NULL; + + /* store which card & revision we have */ + pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, &brd->subvendor); + pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &brd->subdevice); + pci_read_config_byte(pdev, PCI_REVISION_ID, &brd->rev); + + pci_irq = pdev->irq; + brd->irq = pci_irq; + + /* get the PCI Base Address Registers */ + + /* Xr Jupiter and EPC use BAR 2 */ + if (brd->device == PCI_DEVICE_XRJ_DID || brd->device == PCI_DEVICE_EPCJ_DID) { + brd->membase = pci_resource_start(pdev, 2); + brd->membase_end = pci_resource_end(pdev, 2); + } + /* Everyone else uses BAR 0 */ + else { + brd->membase = pci_resource_start(pdev, 0); + brd->membase_end = pci_resource_end(pdev, 0); + } + + if (!brd->membase) + return -ENODEV; + + if (brd->membase & 1) + brd->membase &= ~3; + else + brd->membase &= ~15; + + /* + * On the PCI boards, there is no IO space allocated + * The I/O registers will be in the first 3 bytes of the + * upper 2MB of the 4MB memory space. The board memory + * will be mapped into the low 2MB of the 4MB memory space + */ + brd->port = brd->membase + PCI_IO_OFFSET; + brd->port_end = brd->port + PCI_IO_SIZE; + + /* + * Special initialization for non-PLX boards + */ + if (brd->device != PCI_DEVICE_XRJ_DID && brd->device != PCI_DEVICE_EPCJ_DID) { + unsigned short cmd; + + pci_write_config_byte(pdev, 0x40, 0); + pci_write_config_byte(pdev, 0x46, 0); + + /* Limit burst length to 2 doubleword transactions */ + pci_write_config_byte(pdev, 0x42, 1); + + /* + * Enable IO and mem if not already done. + * This was needed for support on Itanium. + */ + pci_read_config_word(pdev, PCI_COMMAND, &cmd); + cmd |= (PCI_COMMAND_IO | PCI_COMMAND_MEMORY); + pci_write_config_word(pdev, PCI_COMMAND, cmd); + } + + /* init our poll helper tasklet */ + tasklet_init(&brd->helper_tasklet, dgap_poll_tasklet, (unsigned long) brd); + + DGAP_LOCK(dgap_global_lock, flags); + brd->msgbuf = NULL; + printk("%s", brd->msgbuf_head); + kfree(brd->msgbuf_head); + brd->msgbuf_head = NULL; + DGAP_UNLOCK(dgap_global_lock, flags); + + i = dgap_do_remap(brd); + if (i) + brd->state = BOARD_FAILED; + else + brd->state = NEED_RESET; + + return 0; +} + + +static int dgap_finalize_board_init(struct board_t *brd) +{ + int rc; + + if (!brd || brd->magic != DGAP_BOARD_MAGIC) + return -ENODEV; + + brd->use_interrupts = dgap_config_get_useintr(brd); + + /* + * Set up our interrupt handler if we are set to do interrupts. + */ + if (brd->use_interrupts && brd->irq) { + + rc = request_irq(brd->irq, dgap_intr, IRQF_SHARED, "DGAP", brd); + + if (rc) + brd->intr_used = 0; + else + brd->intr_used = 1; + } else { + brd->intr_used = 0; + } + + return 0; +} + +static int dgap_firmware_load(struct pci_dev *pdev, int card_type) +{ + struct board_t *brd = dgap_Board[dgap_NumBoards - 1]; + const struct firmware *fw; + int ret; + + dgap_get_vpd(brd); + dgap_do_reset_board(brd); + + if ((fw_info[card_type].conf_name) && + (dgap_driver_state == DRIVER_NEED_CONFIG_LOAD)) { + ret = request_firmware(&fw, fw_info[card_type].conf_name, + &pdev->dev); + if (ret) { + pr_err("dgap: config file %s not found\n", + fw_info[card_type].conf_name); + return ret; + } + if (!dgap_config_buf) { + dgap_config_buf = kmalloc(fw->size + 1, GFP_ATOMIC); + if (!dgap_config_buf) { + release_firmware(fw); + return -ENOMEM; + } + } + + memcpy(dgap_config_buf, fw->data, fw->size); + release_firmware(fw); + dgap_config_buf[fw->size + 1] = '\0'; + + if (dgap_parsefile(&dgap_config_buf, TRUE) != 0) + return -EINVAL; + + dgap_driver_state = -1; + } + + ret = dgap_after_config_loaded(brd->boardnum); + if (ret) + return ret; + /* + * Match this board to a config the user created for us. + */ + brd->bd_config = + dgap_find_config(brd->type, brd->pci_bus, brd->pci_slot); + + /* + * Because the 4 port Xr products share the same PCI ID + * as the 8 port Xr products, if we receive a NULL config + * back, and this is a PAPORT8 board, retry with a + * PAPORT4 attempt as well. + */ + if (brd->type == PAPORT8 && !brd->bd_config) + brd->bd_config = + dgap_find_config(PAPORT4, brd->pci_bus, brd->pci_slot); + + if (!brd->bd_config) { + pr_err("dgap: No valid configuration found\n"); + return -EINVAL; + } + + dgap_tty_register(brd); + dgap_finalize_board_init(brd); + + if (fw_info[card_type].bios_name) { + ret = request_firmware(&fw, fw_info[card_type].bios_name, + &pdev->dev); + if (ret) { + pr_err("dgap: bios file %s not found\n", + fw_info[card_type].bios_name); + return ret; + } + dgap_do_bios_load(brd, (char *)fw->data, fw->size); + release_firmware(fw); + + /* Wait for BIOS to test board... */ + dgap_do_wait_for_bios(brd); + + if (brd->state != FINISHED_BIOS_LOAD) + return -ENXIO; + } + + if (fw_info[card_type].fep_name) { + ret = request_firmware(&fw, fw_info[card_type].fep_name, + &pdev->dev); + if (ret) { + pr_err("dgap: fep file %s not found\n", + fw_info[card_type].fep_name); + return ret; + } + dgap_do_fep_load(brd, (char *)fw->data, fw->size); + release_firmware(fw); + + /* Wait for FEP to load on board... */ + dgap_do_wait_for_fep(brd); + + if (brd->state != FINISHED_FEP_LOAD) + return -ENXIO; + } + +#ifdef DIGI_CONCENTRATORS_SUPPORTED + /* + * If this is a CX or EPCX, we need to see if the firmware + * is requesting a concentrator image from us. + */ + if ((bd->type == PCX) || (bd->type == PEPC)) { + chk_addr = (u16 *) (vaddr + DOWNREQ); + /* Nonzero if FEP is requesting concentrator image. */ + check = readw(chk_addr); + vaddr = brd->re_map_membase; + } + + if (fw_info[card_type].con_name && check && vaddr) { + ret = request_firmware(&fw, fw_info[card_type].con_name, + &pdev->dev); + if (ret) { + pr_err("dgap: conc file %s not found\n", + fw_info[card_type].con_name); + return ret; + } + /* Put concentrator firmware loading code here */ + offset = readw((u16 *) (vaddr + DOWNREQ)); + memcpy_toio(offset, fw->data, fw->size); + + dgap_do_conc_load(brd, (char *)fw->data, fw->size) + release_firmware(fw); + } +#endif + /* + * Do tty device initialization. + */ + ret = dgap_tty_init(brd); + if (ret < 0) { + dgap_tty_uninit(brd); + return ret; + } + + ret = dgap_tty_register_ports(brd); + if (ret) + return ret; + + brd->state = BOARD_READY; + brd->dpastatus = BD_RUNNING; + + return 0; +} + +/* + * Remap PCI memory. + */ +static int dgap_do_remap(struct board_t *brd) +{ + if (!brd || brd->magic != DGAP_BOARD_MAGIC) + return -ENXIO; + + if (!request_mem_region(brd->membase, 0x200000, "dgap")) + return -ENOMEM; + + if (!request_mem_region(brd->membase + PCI_IO_OFFSET, 0x200000, "dgap")) { + release_mem_region(brd->membase, 0x200000); + return -ENOMEM; + } + + brd->re_map_membase = ioremap(brd->membase, 0x200000); + if (!brd->re_map_membase) { + release_mem_region(brd->membase, 0x200000); + release_mem_region(brd->membase + PCI_IO_OFFSET, 0x200000); + return -ENOMEM; + } + + brd->re_map_port = ioremap((brd->membase + PCI_IO_OFFSET), 0x200000); + if (!brd->re_map_port) { + release_mem_region(brd->membase, 0x200000); + release_mem_region(brd->membase + PCI_IO_OFFSET, 0x200000); + iounmap(brd->re_map_membase); + return -ENOMEM; + } + + return 0; +} + +/***************************************************************************** +* +* Function: +* +* dgap_poll_handler +* +* Author: +* +* Scott H Kilau +* +* Parameters: +* +* dummy -- ignored +* +* Return Values: +* +* none +* +* Description: +* +* As each timer expires, it determines (a) whether the "transmit" +* waiter needs to be woken up, and (b) whether the poller needs to +* be rescheduled. +* +******************************************************************************/ + +static void dgap_poll_handler(ulong dummy) +{ + int i; + struct board_t *brd; + unsigned long lock_flags; + ulong new_time; + + dgap_poll_counter++; + + /* + * Do not start the board state machine until + * driver tells us its up and running, and has + * everything it needs. + */ + if (dgap_driver_state != DRIVER_READY) + goto schedule_poller; + + /* + * If we have just 1 board, or the system is not SMP, + * then use the typical old style poller. + * Otherwise, use our new tasklet based poller, which should + * speed things up for multiple boards. + */ + if ((dgap_NumBoards == 1) || (num_online_cpus() <= 1)) { + for (i = 0; i < dgap_NumBoards; i++) { + + brd = dgap_Board[i]; + + if (brd->state == BOARD_FAILED) + continue; + if (!brd->intr_running) + /* Call the real board poller directly */ + dgap_poll_tasklet((unsigned long) brd); + } + } else { + /* Go thru each board, kicking off a tasklet for each if needed */ + for (i = 0; i < dgap_NumBoards; i++) { + brd = dgap_Board[i]; + + /* + * Attempt to grab the board lock. + * + * If we can't get it, no big deal, the next poll will get it. + * Basically, I just really don't want to spin in here, because I want + * to kick off my tasklets as fast as I can, and then get out the poller. + */ + if (!spin_trylock(&brd->bd_lock)) + continue; + + /* If board is in a failed state, don't bother scheduling a tasklet */ + if (brd->state == BOARD_FAILED) { + spin_unlock(&brd->bd_lock); + continue; + } + + /* Schedule a poll helper task */ + if (!brd->intr_running) + tasklet_schedule(&brd->helper_tasklet); + + /* + * Can't do DGAP_UNLOCK here, as we don't have + * lock_flags because we did a trylock above. + */ + spin_unlock(&brd->bd_lock); + } + } + +schedule_poller: + + /* + * Schedule ourself back at the nominal wakeup interval. + */ + DGAP_LOCK(dgap_poll_lock, lock_flags); + dgap_poll_time += dgap_jiffies_from_ms(dgap_poll_tick); + + new_time = dgap_poll_time - jiffies; + + if ((ulong) new_time >= 2 * dgap_poll_tick) + dgap_poll_time = jiffies + dgap_jiffies_from_ms(dgap_poll_tick); + + dgap_poll_timer.function = dgap_poll_handler; + dgap_poll_timer.data = 0; + dgap_poll_timer.expires = dgap_poll_time; + DGAP_UNLOCK(dgap_poll_lock, lock_flags); + + if (!dgap_poll_stop) + add_timer(&dgap_poll_timer); +} + +/* + * dgap_intr() + * + * Driver interrupt handler. + */ +static irqreturn_t dgap_intr(int irq, void *voidbrd) +{ + struct board_t *brd = (struct board_t *) voidbrd; + + if (!brd) + return IRQ_NONE; + + /* + * Check to make sure its for us. + */ + if (brd->magic != DGAP_BOARD_MAGIC) + return IRQ_NONE; + + brd->intr_count++; + + /* + * Schedule tasklet to run at a better time. + */ + tasklet_schedule(&brd->helper_tasklet); + return IRQ_HANDLED; +} + +/* + * dgap_init_globals() + * + * This is where we initialize the globals from the static insmod + * configuration variables. These are declared near the head of + * this file. + */ +static void dgap_init_globals(void) +{ + int i = 0; + + dgap_rawreadok = rawreadok; + + for (i = 0; i < MAXBOARDS; i++) + dgap_Board[i] = NULL; + + init_timer(&dgap_poll_timer); + + init_waitqueue_head(&dgap_dl_wait); + dgap_dl_action = 0; +} + +/************************************************************************ + * + * Utility functions + * + ************************************************************************/ + +/* + * dgap_ms_sleep() + * + * Put the driver to sleep for x ms's + * + * Returns 0 if timed out, !0 (showing signal) if interrupted by a signal. + */ +static int dgap_ms_sleep(ulong ms) +{ + current->state = TASK_INTERRUPTIBLE; + schedule_timeout((ms * HZ) / 1000); + return signal_pending(current); +} + +/************************************************************************ + * + * TTY Initialization/Cleanup Functions + * + ************************************************************************/ + +/* + * dgap_tty_preinit() + * + * Initialize any global tty related data before we download any boards. + */ +static int dgap_tty_preinit(void) +{ + unsigned long flags; + + DGAP_LOCK(dgap_global_lock, flags); + + /* + * Allocate a buffer for doing the copy from user space to + * kernel space in dgap_input(). We only use one buffer and + * control access to it with a semaphore. If we are paging, we + * are already in trouble so one buffer won't hurt much anyway. + */ + dgap_TmpWriteBuf = kmalloc(WRITEBUFLEN, GFP_ATOMIC); + + if (!dgap_TmpWriteBuf) { + DGAP_UNLOCK(dgap_global_lock, flags); + return -ENOMEM; + } + + DGAP_UNLOCK(dgap_global_lock, flags); + return 0; +} + +/* + * dgap_tty_register() + * + * Init the tty subsystem for this board. + */ +static int dgap_tty_register(struct board_t *brd) +{ + int rc = 0; + + brd->SerialDriver = alloc_tty_driver(MAXPORTS); + + snprintf(brd->SerialName, MAXTTYNAMELEN, "tty_dgap_%d_", brd->boardnum); + brd->SerialDriver->name = brd->SerialName; + brd->SerialDriver->name_base = 0; + brd->SerialDriver->major = 0; + brd->SerialDriver->minor_start = 0; + brd->SerialDriver->type = TTY_DRIVER_TYPE_SERIAL; + brd->SerialDriver->subtype = SERIAL_TYPE_NORMAL; + brd->SerialDriver->init_termios = DgapDefaultTermios; + brd->SerialDriver->driver_name = DRVSTR; + brd->SerialDriver->flags = (TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_HARDWARE_BREAK); + + /* The kernel wants space to store pointers to tty_structs */ + brd->SerialDriver->ttys = kzalloc(MAXPORTS * sizeof(struct tty_struct *), GFP_KERNEL); + if (!brd->SerialDriver->ttys) + return -ENOMEM; + + /* + * Entry points for driver. Called by the kernel from + * tty_io.c and n_tty.c. + */ + tty_set_operations(brd->SerialDriver, &dgap_tty_ops); + + /* + * If we're doing transparent print, we have to do all of the above + * again, separately so we don't get the LD confused about what major + * we are when we get into the dgap_tty_open() routine. + */ + brd->PrintDriver = alloc_tty_driver(MAXPORTS); + + snprintf(brd->PrintName, MAXTTYNAMELEN, "pr_dgap_%d_", brd->boardnum); + brd->PrintDriver->name = brd->PrintName; + brd->PrintDriver->name_base = 0; + brd->PrintDriver->major = 0; + brd->PrintDriver->minor_start = 0; + brd->PrintDriver->type = TTY_DRIVER_TYPE_SERIAL; + brd->PrintDriver->subtype = SERIAL_TYPE_NORMAL; + brd->PrintDriver->init_termios = DgapDefaultTermios; + brd->PrintDriver->driver_name = DRVSTR; + brd->PrintDriver->flags = (TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_HARDWARE_BREAK); + + /* The kernel wants space to store pointers to tty_structs */ + brd->PrintDriver->ttys = kzalloc(MAXPORTS * sizeof(struct tty_struct *), GFP_KERNEL); + if (!brd->PrintDriver->ttys) + return -ENOMEM; + + /* + * Entry points for driver. Called by the kernel from + * tty_io.c and n_tty.c. + */ + tty_set_operations(brd->PrintDriver, &dgap_tty_ops); + + if (!brd->dgap_Major_Serial_Registered) { + /* Register tty devices */ + rc = tty_register_driver(brd->SerialDriver); + if (rc < 0) + return rc; + brd->dgap_Major_Serial_Registered = TRUE; + dgap_BoardsByMajor[brd->SerialDriver->major] = brd; + brd->dgap_Serial_Major = brd->SerialDriver->major; + } + + if (!brd->dgap_Major_TransparentPrint_Registered) { + /* Register Transparent Print devices */ + rc = tty_register_driver(brd->PrintDriver); + if (rc < 0) + return rc; + brd->dgap_Major_TransparentPrint_Registered = TRUE; + dgap_BoardsByMajor[brd->PrintDriver->major] = brd; + brd->dgap_TransparentPrint_Major = brd->PrintDriver->major; + } + + return rc; +} + +/* + * dgap_tty_init() + * + * Init the tty subsystem. Called once per board after board has been + * downloaded and init'ed. + */ +static int dgap_tty_init(struct board_t *brd) +{ + int i; + int tlw; + uint true_count = 0; + uchar *vaddr; + uchar modem = 0; + struct channel_t *ch; + struct bs_t *bs; + struct cm_t *cm; + + if (!brd) + return -ENXIO; + + /* + * Initialize board structure elements. + */ + + vaddr = brd->re_map_membase; + true_count = readw((vaddr + NCHAN)); + + brd->nasync = dgap_config_get_number_of_ports(brd); + + if (!brd->nasync) + brd->nasync = brd->maxports; + + if (brd->nasync > brd->maxports) + brd->nasync = brd->maxports; + + if (true_count != brd->nasync) { + if ((brd->type == PPCM) && (true_count == 64)) + pr_warn("dgap: %s configured for %d ports, has %d ports.\nPlease make SURE the EBI cable running from the card\nto each EM module is plugged into EBI IN!\n", + brd->name, brd->nasync, true_count); + else if ((brd->type == PPCM) && (true_count == 0)) + pr_warn("dgap: %s configured for %d ports, has %d ports.\nPlease make SURE the EBI cable running from the card\nto each EM module is plugged into EBI IN!\n", + brd->name, brd->nasync, true_count); + else + pr_warn("dgap: %s configured for %d ports, has %d ports.\n", + brd->name, brd->nasync, true_count); + + brd->nasync = true_count; + + /* If no ports, don't bother going any further */ + if (!brd->nasync) { + brd->state = BOARD_FAILED; + brd->dpastatus = BD_NOFEP; + return -ENXIO; + } + } + + /* + * Allocate channel memory that might not have been allocated + * when the driver was first loaded. + */ + for (i = 0; i < brd->nasync; i++) { + if (!brd->channels[i]) { + brd->channels[i] = kzalloc(sizeof(struct channel_t), GFP_ATOMIC); + if (!brd->channels[i]) + return -ENOMEM; + } + } + + ch = brd->channels[0]; + vaddr = brd->re_map_membase; + + bs = (struct bs_t *) ((ulong) vaddr + CHANBUF); + cm = (struct cm_t *) ((ulong) vaddr + CMDBUF); + + brd->bd_bs = bs; + + /* Set up channel variables */ + for (i = 0; i < brd->nasync; i++, ch = brd->channels[i], bs++) { + + if (!brd->channels[i]) + continue; + + DGAP_SPINLOCK_INIT(ch->ch_lock); + + /* Store all our magic numbers */ + ch->magic = DGAP_CHANNEL_MAGIC; + ch->ch_tun.magic = DGAP_UNIT_MAGIC; + ch->ch_tun.un_type = DGAP_SERIAL; + ch->ch_tun.un_ch = ch; + ch->ch_tun.un_dev = i; + + ch->ch_pun.magic = DGAP_UNIT_MAGIC; + ch->ch_pun.un_type = DGAP_PRINT; + ch->ch_pun.un_ch = ch; + ch->ch_pun.un_dev = i; + + ch->ch_vaddr = vaddr; + ch->ch_bs = bs; + ch->ch_cm = cm; + ch->ch_bd = brd; + ch->ch_portnum = i; + ch->ch_digi = dgap_digi_init; + + /* + * Set up digi dsr and dcd bits based on altpin flag. + */ + if (dgap_config_get_altpin(brd)) { + ch->ch_dsr = DM_CD; + ch->ch_cd = DM_DSR; + ch->ch_digi.digi_flags |= DIGI_ALTPIN; + } else { + ch->ch_cd = DM_CD; + ch->ch_dsr = DM_DSR; + } + + ch->ch_taddr = vaddr + ((ch->ch_bs->tx_seg) << 4); + ch->ch_raddr = vaddr + ((ch->ch_bs->rx_seg) << 4); + ch->ch_tx_win = 0; + ch->ch_rx_win = 0; + ch->ch_tsize = readw(&(ch->ch_bs->tx_max)) + 1; + ch->ch_rsize = readw(&(ch->ch_bs->rx_max)) + 1; + ch->ch_tstart = 0; + ch->ch_rstart = 0; + + /* .25 second delay */ + ch->ch_close_delay = 250; + + /* + * Set queue water marks, interrupt mask, + * and general tty parameters. + */ + ch->ch_tlw = tlw = ch->ch_tsize >= 2000 ? ((ch->ch_tsize * 5) / 8) : ch->ch_tsize / 2; + + dgap_cmdw(ch, STLOW, tlw, 0); + + dgap_cmdw(ch, SRLOW, ch->ch_rsize / 2, 0); + + dgap_cmdw(ch, SRHIGH, 7 * ch->ch_rsize / 8, 0); + + ch->ch_mistat = readb(&(ch->ch_bs->m_stat)); + + init_waitqueue_head(&ch->ch_flags_wait); + init_waitqueue_head(&ch->ch_tun.un_flags_wait); + init_waitqueue_head(&ch->ch_pun.un_flags_wait); + init_waitqueue_head(&ch->ch_sniff_wait); + + /* Turn on all modem interrupts for now */ + modem = (DM_CD | DM_DSR | DM_CTS | DM_RI); + writeb(modem, &(ch->ch_bs->m_int)); + + /* + * Set edelay to 0 if interrupts are turned on, + * otherwise set edelay to the usual 100. + */ + if (brd->intr_used) + writew(0, &(ch->ch_bs->edelay)); + else + writew(100, &(ch->ch_bs->edelay)); + + writeb(1, &(ch->ch_bs->idata)); + } + + return 0; +} + +/* + * dgap_tty_post_uninit() + * + * UnInitialize any global tty related data. + */ +static void dgap_tty_post_uninit(void) +{ + kfree(dgap_TmpWriteBuf); + dgap_TmpWriteBuf = NULL; +} + +/* + * dgap_tty_uninit() + * + * Uninitialize the TTY portion of this driver. Free all memory and + * resources. + */ +static void dgap_tty_uninit(struct board_t *brd) +{ + int i = 0; + + if (brd->dgap_Major_Serial_Registered) { + dgap_BoardsByMajor[brd->SerialDriver->major] = NULL; + brd->dgap_Serial_Major = 0; + for (i = 0; i < brd->nasync; i++) { + tty_port_destroy(&brd->SerialPorts[i]); + dgap_remove_tty_sysfs(brd->channels[i]->ch_tun.un_sysfs); + tty_unregister_device(brd->SerialDriver, i); + } + tty_unregister_driver(brd->SerialDriver); + kfree(brd->SerialDriver->ttys); + brd->SerialDriver->ttys = NULL; + put_tty_driver(brd->SerialDriver); + kfree(brd->SerialPorts); + brd->dgap_Major_Serial_Registered = FALSE; + } + + if (brd->dgap_Major_TransparentPrint_Registered) { + dgap_BoardsByMajor[brd->PrintDriver->major] = NULL; + brd->dgap_TransparentPrint_Major = 0; + for (i = 0; i < brd->nasync; i++) { + tty_port_destroy(&brd->PrinterPorts[i]); + dgap_remove_tty_sysfs(brd->channels[i]->ch_pun.un_sysfs); + tty_unregister_device(brd->PrintDriver, i); + } + tty_unregister_driver(brd->PrintDriver); + kfree(brd->PrintDriver->ttys); + brd->PrintDriver->ttys = NULL; + put_tty_driver(brd->PrintDriver); + kfree(brd->PrinterPorts); + brd->dgap_Major_TransparentPrint_Registered = FALSE; + } +} + +#define TMPBUFLEN (1024) +/* + * dgap_sniff - Dump data out to the "sniff" buffer if the + * proc sniff file is opened... + */ +static void dgap_sniff_nowait_nolock(struct channel_t *ch, uchar *text, uchar *buf, int len) +{ + struct timeval tv; + int n; + int r; + int nbuf; + int i; + int tmpbuflen; + char tmpbuf[TMPBUFLEN]; + char *p = tmpbuf; + int too_much_data; + + /* Leave if sniff not open */ + if (!(ch->ch_sniff_flags & SNIFF_OPEN)) + return; + + do_gettimeofday(&tv); + + /* Create our header for data dump */ + p += sprintf(p, "<%ld %ld><%s><", tv.tv_sec, tv.tv_usec, text); + tmpbuflen = p - tmpbuf; + + do { + too_much_data = 0; + + for (i = 0; i < len && tmpbuflen < (TMPBUFLEN - 4); i++) { + p += sprintf(p, "%02x ", *buf); + buf++; + tmpbuflen = p - tmpbuf; + } + + if (tmpbuflen < (TMPBUFLEN - 4)) { + if (i > 0) + p += sprintf(p - 1, "%s\n", ">"); + else + p += sprintf(p, "%s\n", ">"); + } else { + too_much_data = 1; + len -= i; + } + + nbuf = strlen(tmpbuf); + p = tmpbuf; + + /* + * Loop while data remains. + */ + while (nbuf > 0 && ch->ch_sniff_buf) { + /* + * Determine the amount of available space left in the + * buffer. If there's none, wait until some appears. + */ + n = (ch->ch_sniff_out - ch->ch_sniff_in - 1) & SNIFF_MASK; + + /* + * If there is no space left to write to in our sniff buffer, + * we have no choice but to drop the data. + * We *cannot* sleep here waiting for space, because this + * function was probably called by the interrupt/timer routines! + */ + if (n == 0) + return; + + /* + * Copy as much data as will fit. + */ + + if (n > nbuf) + n = nbuf; + + r = SNIFF_MAX - ch->ch_sniff_in; + + if (r <= n) { + memcpy(ch->ch_sniff_buf + ch->ch_sniff_in, p, r); + + n -= r; + ch->ch_sniff_in = 0; + p += r; + nbuf -= r; + } + + memcpy(ch->ch_sniff_buf + ch->ch_sniff_in, p, n); + + ch->ch_sniff_in += n; + p += n; + nbuf -= n; + + /* + * Wakeup any thread waiting for data + */ + if (ch->ch_sniff_flags & SNIFF_WAIT_DATA) { + ch->ch_sniff_flags &= ~SNIFF_WAIT_DATA; + wake_up_interruptible(&ch->ch_sniff_wait); + } + } + + /* + * If the user sent us too much data to push into our tmpbuf, + * we need to keep looping around on all the data. + */ + if (too_much_data) { + p = tmpbuf; + tmpbuflen = 0; + } + + } while (too_much_data); +} + +/*======================================================================= + * + * dgap_input - Process received data. + * + * ch - Pointer to channel structure. + * + *=======================================================================*/ + +static void dgap_input(struct channel_t *ch) +{ + struct board_t *bd; + struct bs_t *bs; + struct tty_struct *tp; + struct tty_ldisc *ld; + uint rmask; + uint head; + uint tail; + int data_len; + ulong lock_flags; + ulong lock_flags2; + int flip_len; + int len = 0; + int n = 0; + uchar *buf; + uchar tmpchar; + int s = 0; + + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return; + + tp = ch->ch_tun.un_tty; + + bs = ch->ch_bs; + if (!bs) + return; + + bd = ch->ch_bd; + if (!bd || bd->magic != DGAP_BOARD_MAGIC) + return; + + DGAP_LOCK(bd->bd_lock, lock_flags); + DGAP_LOCK(ch->ch_lock, lock_flags2); + + /* + * Figure the number of characters in the buffer. + * Exit immediately if none. + */ + + rmask = ch->ch_rsize - 1; + + head = readw(&(bs->rx_head)); + head &= rmask; + tail = readw(&(bs->rx_tail)); + tail &= rmask; + + data_len = (head - tail) & rmask; + + if (data_len == 0) { + writeb(1, &(bs->idata)); + DGAP_UNLOCK(ch->ch_lock, lock_flags2); + DGAP_UNLOCK(bd->bd_lock, lock_flags); + return; + } + + /* + * If the device is not open, or CREAD is off, flush + * input data and return immediately. + */ + if ((bd->state != BOARD_READY) || !tp || + (tp->magic != TTY_MAGIC) || + !(ch->ch_tun.un_flags & UN_ISOPEN) || + !(tp->termios.c_cflag & CREAD) || + (ch->ch_tun.un_flags & UN_CLOSING)) { + + writew(head, &(bs->rx_tail)); + writeb(1, &(bs->idata)); + DGAP_UNLOCK(ch->ch_lock, lock_flags2); + DGAP_UNLOCK(bd->bd_lock, lock_flags); + return; + } + + /* + * If we are throttled, simply don't read any data. + */ + if (ch->ch_flags & CH_RXBLOCK) { + writeb(1, &(bs->idata)); + DGAP_UNLOCK(ch->ch_lock, lock_flags2); + DGAP_UNLOCK(bd->bd_lock, lock_flags); + return; + } + + /* + * Ignore oruns. + */ + tmpchar = readb(&(bs->orun)); + if (tmpchar) { + ch->ch_err_overrun++; + writeb(0, &(bs->orun)); + } + + /* Decide how much data we can send into the tty layer */ + flip_len = TTY_FLIPBUF_SIZE; + + /* Chop down the length, if needed */ + len = min(data_len, flip_len); + len = min(len, (N_TTY_BUF_SIZE - 1)); + + ld = tty_ldisc_ref(tp); + +#ifdef TTY_DONT_FLIP + /* + * If the DONT_FLIP flag is on, don't flush our buffer, and act + * like the ld doesn't have any space to put the data right now. + */ + if (test_bit(TTY_DONT_FLIP, &tp->flags)) + len = 0; +#endif + + /* + * If we were unable to get a reference to the ld, + * don't flush our buffer, and act like the ld doesn't + * have any space to put the data right now. + */ + if (!ld) { + len = 0; + } else { + /* + * If ld doesn't have a pointer to a receive_buf function, + * flush the data, then act like the ld doesn't have any + * space to put the data right now. + */ + if (!ld->ops->receive_buf) { + writew(head, &(bs->rx_tail)); + len = 0; + } + } + + if (len <= 0) { + writeb(1, &(bs->idata)); + DGAP_UNLOCK(ch->ch_lock, lock_flags2); + DGAP_UNLOCK(bd->bd_lock, lock_flags); + if (ld) + tty_ldisc_deref(ld); + return; + } + + buf = ch->ch_bd->flipbuf; + n = len; + + /* + * n now contains the most amount of data we can copy, + * bounded either by our buffer size or the amount + * of data the card actually has pending... + */ + while (n) { + + s = ((head >= tail) ? head : ch->ch_rsize) - tail; + s = min(s, n); + + if (s <= 0) + break; + + memcpy_fromio(buf, (char *) ch->ch_raddr + tail, s); + dgap_sniff_nowait_nolock(ch, "USER READ", buf, s); + + tail += s; + buf += s; + + n -= s; + /* Flip queue if needed */ + tail &= rmask; + } + + writew(tail, &(bs->rx_tail)); + writeb(1, &(bs->idata)); + ch->ch_rxcount += len; + + /* + * If we are completely raw, we don't need to go through a lot + * of the tty layers that exist. + * In this case, we take the shortest and fastest route we + * can to relay the data to the user. + * + * On the other hand, if we are not raw, we need to go through + * the tty layer, which has its API more well defined. + */ + if (I_PARMRK(tp) || I_BRKINT(tp) || I_INPCK(tp)) { + dgap_parity_scan(ch, ch->ch_bd->flipbuf, ch->ch_bd->flipflagbuf, &len); + + len = tty_buffer_request_room(tp->port, len); + tty_insert_flip_string_flags(tp->port, ch->ch_bd->flipbuf, + ch->ch_bd->flipflagbuf, len); + } else { + len = tty_buffer_request_room(tp->port, len); + tty_insert_flip_string(tp->port, ch->ch_bd->flipbuf, len); + } + + DGAP_UNLOCK(ch->ch_lock, lock_flags2); + DGAP_UNLOCK(bd->bd_lock, lock_flags); + + /* Tell the tty layer its okay to "eat" the data now */ + tty_flip_buffer_push(tp->port); + + if (ld) + tty_ldisc_deref(ld); + +} + +/************************************************************************ + * Determines when CARRIER changes state and takes appropriate + * action. + ************************************************************************/ +static void dgap_carrier(struct channel_t *ch) +{ + struct board_t *bd; + + int virt_carrier = 0; + int phys_carrier = 0; + + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return; + + bd = ch->ch_bd; + + if (!bd || bd->magic != DGAP_BOARD_MAGIC) + return; + + /* Make sure altpin is always set correctly */ + if (ch->ch_digi.digi_flags & DIGI_ALTPIN) { + ch->ch_dsr = DM_CD; + ch->ch_cd = DM_DSR; + } else { + ch->ch_dsr = DM_DSR; + ch->ch_cd = DM_CD; + } + + if (ch->ch_mistat & D_CD(ch)) + phys_carrier = 1; + + if (ch->ch_digi.digi_flags & DIGI_FORCEDCD) + virt_carrier = 1; + + if (ch->ch_c_cflag & CLOCAL) + virt_carrier = 1; + + /* + * Test for a VIRTUAL carrier transition to HIGH. + */ + if (((ch->ch_flags & CH_FCAR) == 0) && (virt_carrier == 1)) { + + /* + * When carrier rises, wake any threads waiting + * for carrier in the open routine. + */ + + if (waitqueue_active(&(ch->ch_flags_wait))) + wake_up_interruptible(&ch->ch_flags_wait); + } + + /* + * Test for a PHYSICAL carrier transition to HIGH. + */ + if (((ch->ch_flags & CH_CD) == 0) && (phys_carrier == 1)) { + + /* + * When carrier rises, wake any threads waiting + * for carrier in the open routine. + */ + + if (waitqueue_active(&(ch->ch_flags_wait))) + wake_up_interruptible(&ch->ch_flags_wait); + } + + /* + * Test for a PHYSICAL transition to low, so long as we aren't + * currently ignoring physical transitions (which is what "virtual + * carrier" indicates). + * + * The transition of the virtual carrier to low really doesn't + * matter... it really only means "ignore carrier state", not + * "make pretend that carrier is there". + */ + if ((virt_carrier == 0) && + ((ch->ch_flags & CH_CD) != 0) && + (phys_carrier == 0)) { + + /* + * When carrier drops: + * + * Drop carrier on all open units. + * + * Flush queues, waking up any task waiting in the + * line discipline. + * + * Send a hangup to the control terminal. + * + * Enable all select calls. + */ + if (waitqueue_active(&(ch->ch_flags_wait))) + wake_up_interruptible(&ch->ch_flags_wait); + + if (ch->ch_tun.un_open_count > 0) + tty_hangup(ch->ch_tun.un_tty); + + if (ch->ch_pun.un_open_count > 0) + tty_hangup(ch->ch_pun.un_tty); + } + + /* + * Make sure that our cached values reflect the current reality. + */ + if (virt_carrier == 1) + ch->ch_flags |= CH_FCAR; + else + ch->ch_flags &= ~CH_FCAR; + + if (phys_carrier == 1) + ch->ch_flags |= CH_CD; + else + ch->ch_flags &= ~CH_CD; +} + +/************************************************************************ + * + * TTY Entry points and helper functions + * + ************************************************************************/ + +/* + * dgap_tty_open() + * + */ +static int dgap_tty_open(struct tty_struct *tty, struct file *file) +{ + struct board_t *brd; + struct channel_t *ch; + struct un_t *un; + struct bs_t *bs; + uint major = 0; + uint minor = 0; + int rc = 0; + ulong lock_flags; + ulong lock_flags2; + u16 head; + + rc = 0; + + major = MAJOR(tty_devnum(tty)); + minor = MINOR(tty_devnum(tty)); + + if (major > 255) + return -ENXIO; + + /* Get board pointer from our array of majors we have allocated */ + brd = dgap_BoardsByMajor[major]; + if (!brd) + return -ENXIO; + + /* + * If board is not yet up to a state of READY, go to + * sleep waiting for it to happen or they cancel the open. + */ + rc = wait_event_interruptible(brd->state_wait, + (brd->state & BOARD_READY)); + + if (rc) + return rc; + + DGAP_LOCK(brd->bd_lock, lock_flags); + + /* The wait above should guarantee this cannot happen */ + if (brd->state != BOARD_READY) { + DGAP_UNLOCK(brd->bd_lock, lock_flags); + return -ENXIO; + } + + /* If opened device is greater than our number of ports, bail. */ + if (MINOR(tty_devnum(tty)) > brd->nasync) { + DGAP_UNLOCK(brd->bd_lock, lock_flags); + return -ENXIO; + } + + ch = brd->channels[minor]; + if (!ch) { + DGAP_UNLOCK(brd->bd_lock, lock_flags); + return -ENXIO; + } + + /* Grab channel lock */ + DGAP_LOCK(ch->ch_lock, lock_flags2); + + /* Figure out our type */ + if (major == brd->dgap_Serial_Major) { + un = &brd->channels[minor]->ch_tun; + un->un_type = DGAP_SERIAL; + } else if (major == brd->dgap_TransparentPrint_Major) { + un = &brd->channels[minor]->ch_pun; + un->un_type = DGAP_PRINT; + } else { + DGAP_UNLOCK(ch->ch_lock, lock_flags2); + DGAP_UNLOCK(brd->bd_lock, lock_flags); + return -ENXIO; + } + + /* Store our unit into driver_data, so we always have it available. */ + tty->driver_data = un; + + /* + * Error if channel info pointer is NULL. + */ + bs = ch->ch_bs; + if (!bs) { + DGAP_UNLOCK(ch->ch_lock, lock_flags2); + DGAP_UNLOCK(brd->bd_lock, lock_flags); + return -ENXIO; + } + + /* + * Initialize tty's + */ + if (!(un->un_flags & UN_ISOPEN)) { + /* Store important variables. */ + un->un_tty = tty; + + /* Maybe do something here to the TTY struct as well? */ + } + + /* + * Initialize if neither terminal or printer is open. + */ + if (!((ch->ch_tun.un_flags | ch->ch_pun.un_flags) & UN_ISOPEN)) { + + ch->ch_mforce = 0; + ch->ch_mval = 0; + + /* + * Flush input queue. + */ + head = readw(&(bs->rx_head)); + writew(head, &(bs->rx_tail)); + + ch->ch_flags = 0; + ch->pscan_state = 0; + ch->pscan_savechar = 0; + + ch->ch_c_cflag = tty->termios.c_cflag; + ch->ch_c_iflag = tty->termios.c_iflag; + ch->ch_c_oflag = tty->termios.c_oflag; + ch->ch_c_lflag = tty->termios.c_lflag; + ch->ch_startc = tty->termios.c_cc[VSTART]; + ch->ch_stopc = tty->termios.c_cc[VSTOP]; + + /* TODO: flush our TTY struct here? */ + } + + dgap_carrier(ch); + /* + * Run param in case we changed anything + */ + dgap_param(tty); + + /* + * follow protocol for opening port + */ + + DGAP_UNLOCK(ch->ch_lock, lock_flags2); + DGAP_UNLOCK(brd->bd_lock, lock_flags); + + rc = dgap_block_til_ready(tty, file, ch); + + if (!un->un_tty) + return -ENODEV; + + /* No going back now, increment our unit and channel counters */ + DGAP_LOCK(ch->ch_lock, lock_flags); + ch->ch_open_count++; + un->un_open_count++; + un->un_flags |= (UN_ISOPEN); + DGAP_UNLOCK(ch->ch_lock, lock_flags); + + return rc; +} + +/* + * dgap_block_til_ready() + * + * Wait for DCD, if needed. + */ +static int dgap_block_til_ready(struct tty_struct *tty, struct file *file, struct channel_t *ch) +{ + int retval = 0; + struct un_t *un = NULL; + ulong lock_flags; + uint old_flags = 0; + int sleep_on_un_flags = 0; + + if (!tty || tty->magic != TTY_MAGIC || !file || !ch || + ch->magic != DGAP_CHANNEL_MAGIC) + return -ENXIO; + + un = tty->driver_data; + if (!un || un->magic != DGAP_UNIT_MAGIC) + return -ENXIO; + + DGAP_LOCK(ch->ch_lock, lock_flags); + + ch->ch_wopen++; + + /* Loop forever */ + while (1) { + + sleep_on_un_flags = 0; + + /* + * If board has failed somehow during our sleep, bail with error. + */ + if (ch->ch_bd->state == BOARD_FAILED) { + retval = -ENXIO; + break; + } + + /* If tty was hung up, break out of loop and set error. */ + if (tty_hung_up_p(file)) { + retval = -EAGAIN; + break; + } + + /* + * If either unit is in the middle of the fragile part of close, + * we just cannot touch the channel safely. + * Go back to sleep, knowing that when the channel can be + * touched safely, the close routine will signal the + * ch_wait_flags to wake us back up. + */ + if (!((ch->ch_tun.un_flags | ch->ch_pun.un_flags) & UN_CLOSING)) { + + /* + * Our conditions to leave cleanly and happily: + * 1) NONBLOCKING on the tty is set. + * 2) CLOCAL is set. + * 3) DCD (fake or real) is active. + */ + + if (file->f_flags & O_NONBLOCK) + break; + + if (tty->flags & (1 << TTY_IO_ERROR)) + break; + + if (ch->ch_flags & CH_CD) + break; + + if (ch->ch_flags & CH_FCAR) + break; + } else { + sleep_on_un_flags = 1; + } + + /* + * If there is a signal pending, the user probably + * interrupted (ctrl-c) us. + * Leave loop with error set. + */ + if (signal_pending(current)) { + retval = -ERESTARTSYS; + break; + } + + /* + * Store the flags before we let go of channel lock + */ + if (sleep_on_un_flags) + old_flags = ch->ch_tun.un_flags | ch->ch_pun.un_flags; + else + old_flags = ch->ch_flags; + + /* + * Let go of channel lock before calling schedule. + * Our poller will get any FEP events and wake us up when DCD + * eventually goes active. + */ + + DGAP_UNLOCK(ch->ch_lock, lock_flags); + + /* + * Wait for something in the flags to change from the current value. + */ + if (sleep_on_un_flags) { + retval = wait_event_interruptible(un->un_flags_wait, + (old_flags != (ch->ch_tun.un_flags | ch->ch_pun.un_flags))); + } else { + retval = wait_event_interruptible(ch->ch_flags_wait, + (old_flags != ch->ch_flags)); + } + + /* + * We got woken up for some reason. + * Before looping around, grab our channel lock. + */ + DGAP_LOCK(ch->ch_lock, lock_flags); + } + + ch->ch_wopen--; + + DGAP_UNLOCK(ch->ch_lock, lock_flags); + + if (retval) + return retval; + + return 0; +} + +/* + * dgap_tty_hangup() + * + * Hangup the port. Like a close, but don't wait for output to drain. + */ +static void dgap_tty_hangup(struct tty_struct *tty) +{ + struct board_t *bd; + struct channel_t *ch; + struct un_t *un; + + if (!tty || tty->magic != TTY_MAGIC) + return; + + un = tty->driver_data; + if (!un || un->magic != DGAP_UNIT_MAGIC) + return; + + ch = un->un_ch; + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return; + + bd = ch->ch_bd; + if (!bd || bd->magic != DGAP_BOARD_MAGIC) + return; + + /* flush the transmit queues */ + dgap_tty_flush_buffer(tty); + +} + +/* + * dgap_tty_close() + * + */ +static void dgap_tty_close(struct tty_struct *tty, struct file *file) +{ + struct ktermios *ts; + struct board_t *bd; + struct channel_t *ch; + struct un_t *un; + ulong lock_flags; + int rc = 0; + + if (!tty || tty->magic != TTY_MAGIC) + return; + + un = tty->driver_data; + if (!un || un->magic != DGAP_UNIT_MAGIC) + return; + + ch = un->un_ch; + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return; + + bd = ch->ch_bd; + if (!bd || bd->magic != DGAP_BOARD_MAGIC) + return; + + ts = &tty->termios; + + DGAP_LOCK(ch->ch_lock, lock_flags); + + /* + * Determine if this is the last close or not - and if we agree about + * which type of close it is with the Line Discipline + */ + if ((tty->count == 1) && (un->un_open_count != 1)) + /* + * Uh, oh. tty->count is 1, which means that the tty + * structure will be freed. un_open_count should always + * be one in these conditions. If it's greater than + * one, we've got real problems, since it means the + * serial port won't be shutdown. + */ + un->un_open_count = 1; + + if (--un->un_open_count < 0) + un->un_open_count = 0; + + ch->ch_open_count--; + + if (ch->ch_open_count && un->un_open_count) { + DGAP_UNLOCK(ch->ch_lock, lock_flags); + return; + } + + /* OK, its the last close on the unit */ + + un->un_flags |= UN_CLOSING; + + tty->closing = 1; + + /* + * Only officially close channel if count is 0 and + * DIGI_PRINTER bit is not set. + */ + if ((ch->ch_open_count == 0) && !(ch->ch_digi.digi_flags & DIGI_PRINTER)) { + + ch->ch_flags &= ~(CH_RXBLOCK); + + DGAP_UNLOCK(ch->ch_lock, lock_flags); + + /* wait for output to drain */ + /* This will also return if we take an interrupt */ + + rc = dgap_wait_for_drain(tty); + + dgap_tty_flush_buffer(tty); + tty_ldisc_flush(tty); + + DGAP_LOCK(ch->ch_lock, lock_flags); + + tty->closing = 0; + + /* + * If we have HUPCL set, lower DTR and RTS + */ + if (ch->ch_c_cflag & HUPCL) { + ch->ch_mostat &= ~(D_RTS(ch)|D_DTR(ch)); + dgap_cmdb(ch, SMODEM, 0, D_DTR(ch)|D_RTS(ch), 0); + + /* + * Go to sleep to ensure RTS/DTR + * have been dropped for modems to see it. + */ + if (ch->ch_close_delay) { + DGAP_UNLOCK(ch->ch_lock, lock_flags); + dgap_ms_sleep(ch->ch_close_delay); + DGAP_LOCK(ch->ch_lock, lock_flags); + } + } + + ch->pscan_state = 0; + ch->pscan_savechar = 0; + ch->ch_baud_info = 0; + + } + + /* + * turn off print device when closing print device. + */ + if ((un->un_type == DGAP_PRINT) && (ch->ch_flags & CH_PRON)) { + dgap_wmove(ch, ch->ch_digi.digi_offstr, + (int) ch->ch_digi.digi_offlen); + ch->ch_flags &= ~CH_PRON; + } + + un->un_tty = NULL; + un->un_flags &= ~(UN_ISOPEN | UN_CLOSING); + tty->driver_data = NULL; + + wake_up_interruptible(&ch->ch_flags_wait); + wake_up_interruptible(&un->un_flags_wait); + + DGAP_UNLOCK(ch->ch_lock, lock_flags); +} + +/* + * dgap_tty_chars_in_buffer() + * + * Return number of characters that have not been transmitted yet. + * + * This routine is used by the line discipline to determine if there + * is data waiting to be transmitted/drained/flushed or not. + */ +static int dgap_tty_chars_in_buffer(struct tty_struct *tty) +{ + struct board_t *bd = NULL; + struct channel_t *ch = NULL; + struct un_t *un = NULL; + struct bs_t *bs = NULL; + uchar tbusy; + uint chars = 0; + u16 thead, ttail, tmask, chead, ctail; + ulong lock_flags = 0; + ulong lock_flags2 = 0; + + if (tty == NULL) + return 0; + + un = tty->driver_data; + if (!un || un->magic != DGAP_UNIT_MAGIC) + return 0; + + ch = un->un_ch; + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return 0; + + bd = ch->ch_bd; + if (!bd || bd->magic != DGAP_BOARD_MAGIC) + return 0; + + bs = ch->ch_bs; + if (!bs) + return 0; + + DGAP_LOCK(bd->bd_lock, lock_flags); + DGAP_LOCK(ch->ch_lock, lock_flags2); + + tmask = (ch->ch_tsize - 1); + + /* Get Transmit queue pointers */ + thead = readw(&(bs->tx_head)) & tmask; + ttail = readw(&(bs->tx_tail)) & tmask; + + /* Get tbusy flag */ + tbusy = readb(&(bs->tbusy)); + + /* Get Command queue pointers */ + chead = readw(&(ch->ch_cm->cm_head)); + ctail = readw(&(ch->ch_cm->cm_tail)); + + DGAP_UNLOCK(ch->ch_lock, lock_flags2); + DGAP_UNLOCK(bd->bd_lock, lock_flags); + + /* + * The only way we know for sure if there is no pending + * data left to be transferred, is if: + * 1) Transmit head and tail are equal (empty). + * 2) Command queue head and tail are equal (empty). + * 3) The "TBUSY" flag is 0. (Transmitter not busy). + */ + + if ((ttail == thead) && (tbusy == 0) && (chead == ctail)) { + chars = 0; + } else { + if (thead >= ttail) + chars = thead - ttail; + else + chars = thead - ttail + ch->ch_tsize; + /* + * Fudge factor here. + * If chars is zero, we know that the command queue had + * something in it or tbusy was set. Because we cannot + * be sure if there is still some data to be transmitted, + * lets lie, and tell ld we have 1 byte left. + */ + if (chars == 0) { + /* + * If TBUSY is still set, and our tx buffers are empty, + * force the firmware to send me another wakeup after + * TBUSY has been cleared. + */ + if (tbusy != 0) { + DGAP_LOCK(ch->ch_lock, lock_flags); + un->un_flags |= UN_EMPTY; + writeb(1, &(bs->iempty)); + DGAP_UNLOCK(ch->ch_lock, lock_flags); + } + chars = 1; + } + } + + return chars; +} + +static int dgap_wait_for_drain(struct tty_struct *tty) +{ + struct channel_t *ch; + struct un_t *un; + struct bs_t *bs; + int ret = -EIO; + uint count = 1; + ulong lock_flags = 0; + + if (!tty || tty->magic != TTY_MAGIC) + return ret; + + un = tty->driver_data; + if (!un || un->magic != DGAP_UNIT_MAGIC) + return ret; + + ch = un->un_ch; + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return ret; + + bs = ch->ch_bs; + if (!bs) + return ret; + + ret = 0; + + /* Loop until data is drained */ + while (count != 0) { + + count = dgap_tty_chars_in_buffer(tty); + + if (count == 0) + break; + + /* Set flag waiting for drain */ + DGAP_LOCK(ch->ch_lock, lock_flags); + un->un_flags |= UN_EMPTY; + writeb(1, &(bs->iempty)); + DGAP_UNLOCK(ch->ch_lock, lock_flags); + + /* Go to sleep till we get woken up */ + ret = wait_event_interruptible(un->un_flags_wait, ((un->un_flags & UN_EMPTY) == 0)); + /* If ret is non-zero, user ctrl-c'ed us */ + if (ret) + break; + } + + DGAP_LOCK(ch->ch_lock, lock_flags); + un->un_flags &= ~(UN_EMPTY); + DGAP_UNLOCK(ch->ch_lock, lock_flags); + + return ret; +} + +/* + * dgap_maxcps_room + * + * Reduces bytes_available to the max number of characters + * that can be sent currently given the maxcps value, and + * returns the new bytes_available. This only affects printer + * output. + */ +static int dgap_maxcps_room(struct tty_struct *tty, int bytes_available) +{ + struct channel_t *ch = NULL; + struct un_t *un = NULL; + + if (tty == NULL) + return bytes_available; + + un = tty->driver_data; + if (!un || un->magic != DGAP_UNIT_MAGIC) + return bytes_available; + + ch = un->un_ch; + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return bytes_available; + + /* + * If its not the Transparent print device, return + * the full data amount. + */ + if (un->un_type != DGAP_PRINT) + return bytes_available; + + if (ch->ch_digi.digi_maxcps > 0 && ch->ch_digi.digi_bufsize > 0) { + int cps_limit = 0; + unsigned long current_time = jiffies; + unsigned long buffer_time = current_time + + (HZ * ch->ch_digi.digi_bufsize) / ch->ch_digi.digi_maxcps; + + if (ch->ch_cpstime < current_time) { + /* buffer is empty */ + ch->ch_cpstime = current_time; /* reset ch_cpstime */ + cps_limit = ch->ch_digi.digi_bufsize; + } else if (ch->ch_cpstime < buffer_time) { + /* still room in the buffer */ + cps_limit = ((buffer_time - ch->ch_cpstime) * ch->ch_digi.digi_maxcps) / HZ; + } else { + /* no room in the buffer */ + cps_limit = 0; + } + + bytes_available = min(cps_limit, bytes_available); + } + + return bytes_available; +} + +static inline void dgap_set_firmware_event(struct un_t *un, unsigned int event) +{ + struct channel_t *ch = NULL; + struct bs_t *bs = NULL; + + if (!un || un->magic != DGAP_UNIT_MAGIC) + return; + ch = un->un_ch; + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return; + bs = ch->ch_bs; + if (!bs) + return; + + if ((event & UN_LOW) != 0) { + if ((un->un_flags & UN_LOW) == 0) { + un->un_flags |= UN_LOW; + writeb(1, &(bs->ilow)); + } + } + if ((event & UN_LOW) != 0) { + if ((un->un_flags & UN_EMPTY) == 0) { + un->un_flags |= UN_EMPTY; + writeb(1, &(bs->iempty)); + } + } +} + +/* + * dgap_tty_write_room() + * + * Return space available in Tx buffer + */ +static int dgap_tty_write_room(struct tty_struct *tty) +{ + struct channel_t *ch = NULL; + struct un_t *un = NULL; + struct bs_t *bs = NULL; + u16 head, tail, tmask; + int ret = 0; + ulong lock_flags = 0; + + if (tty == NULL || dgap_TmpWriteBuf == NULL) + return 0; + + un = tty->driver_data; + if (!un || un->magic != DGAP_UNIT_MAGIC) + return 0; + + ch = un->un_ch; + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return 0; + + bs = ch->ch_bs; + if (!bs) + return 0; + + DGAP_LOCK(ch->ch_lock, lock_flags); + + tmask = ch->ch_tsize - 1; + head = readw(&(bs->tx_head)) & tmask; + tail = readw(&(bs->tx_tail)) & tmask; + + ret = tail - head - 1; + if (ret < 0) + ret += ch->ch_tsize; + + /* Limit printer to maxcps */ + ret = dgap_maxcps_room(tty, ret); + + /* + * If we are printer device, leave space for + * possibly both the on and off strings. + */ + if (un->un_type == DGAP_PRINT) { + if (!(ch->ch_flags & CH_PRON)) + ret -= ch->ch_digi.digi_onlen; + ret -= ch->ch_digi.digi_offlen; + } else { + if (ch->ch_flags & CH_PRON) + ret -= ch->ch_digi.digi_offlen; + } + + if (ret < 0) + ret = 0; + + /* + * Schedule FEP to wake us up if needed. + * + * TODO: This might be overkill... + * Do we really need to schedule callbacks from the FEP + * in every case? Can we get smarter based on ret? + */ + dgap_set_firmware_event(un, UN_LOW | UN_EMPTY); + DGAP_UNLOCK(ch->ch_lock, lock_flags); + + return ret; +} + +/* + * dgap_tty_put_char() + * + * Put a character into ch->ch_buf + * + * - used by the line discipline for OPOST processing + */ +static int dgap_tty_put_char(struct tty_struct *tty, unsigned char c) +{ + /* + * Simply call tty_write. + */ + dgap_tty_write(tty, &c, 1); + return 1; +} + +/* + * dgap_tty_write() + * + * Take data from the user or kernel and send it out to the FEP. + * In here exists all the Transparent Print magic as well. + */ +static int dgap_tty_write(struct tty_struct *tty, const unsigned char *buf, int count) +{ + struct channel_t *ch = NULL; + struct un_t *un = NULL; + struct bs_t *bs = NULL; + char *vaddr = NULL; + u16 head, tail, tmask, remain; + int bufcount = 0, n = 0; + int orig_count = 0; + ulong lock_flags; + int from_user = 0; + + if (tty == NULL || dgap_TmpWriteBuf == NULL) + return 0; + + un = tty->driver_data; + if (!un || un->magic != DGAP_UNIT_MAGIC) + return 0; + + ch = un->un_ch; + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return 0; + + bs = ch->ch_bs; + if (!bs) + return 0; + + if (!count) + return 0; + + /* + * Store original amount of characters passed in. + * This helps to figure out if we should ask the FEP + * to send us an event when it has more space available. + */ + orig_count = count; + + DGAP_LOCK(ch->ch_lock, lock_flags); + + /* Get our space available for the channel from the board */ + tmask = ch->ch_tsize - 1; + head = readw(&(bs->tx_head)) & tmask; + tail = readw(&(bs->tx_tail)) & tmask; + + bufcount = tail - head - 1; + if (bufcount < 0) + bufcount += ch->ch_tsize; + + /* + * Limit printer output to maxcps overall, with bursts allowed + * up to bufsize characters. + */ + bufcount = dgap_maxcps_room(tty, bufcount); + + /* + * Take minimum of what the user wants to send, and the + * space available in the FEP buffer. + */ + count = min(count, bufcount); + + /* + * Bail if no space left. + */ + if (count <= 0) { + dgap_set_firmware_event(un, UN_LOW | UN_EMPTY); + DGAP_UNLOCK(ch->ch_lock, lock_flags); + return 0; + } + + /* + * Output the printer ON string, if we are in terminal mode, but + * need to be in printer mode. + */ + if ((un->un_type == DGAP_PRINT) && !(ch->ch_flags & CH_PRON)) { + dgap_wmove(ch, ch->ch_digi.digi_onstr, + (int) ch->ch_digi.digi_onlen); + head = readw(&(bs->tx_head)) & tmask; + ch->ch_flags |= CH_PRON; + } + + /* + * On the other hand, output the printer OFF string, if we are + * currently in printer mode, but need to output to the terminal. + */ + if ((un->un_type != DGAP_PRINT) && (ch->ch_flags & CH_PRON)) { + dgap_wmove(ch, ch->ch_digi.digi_offstr, + (int) ch->ch_digi.digi_offlen); + head = readw(&(bs->tx_head)) & tmask; + ch->ch_flags &= ~CH_PRON; + } + + /* + * If there is nothing left to copy, or I can't handle any more data, leave. + */ + if (count <= 0) { + dgap_set_firmware_event(un, UN_LOW | UN_EMPTY); + DGAP_UNLOCK(ch->ch_lock, lock_flags); + return 0; + } + + if (from_user) { + + count = min(count, WRITEBUFLEN); + + DGAP_UNLOCK(ch->ch_lock, lock_flags); + + /* + * If data is coming from user space, copy it into a temporary + * buffer so we don't get swapped out while doing the copy to + * the board. + */ + /* we're allowed to block if it's from_user */ + if (down_interruptible(&dgap_TmpWriteSem)) + return -EINTR; + + if (copy_from_user(dgap_TmpWriteBuf, (const uchar __user *) buf, count)) { + up(&dgap_TmpWriteSem); + printk("Write: Copy from user failed!\n"); + return -EFAULT; + } + + DGAP_LOCK(ch->ch_lock, lock_flags); + + buf = dgap_TmpWriteBuf; + } + + n = count; + + /* + * If the write wraps over the top of the circular buffer, + * move the portion up to the wrap point, and reset the + * pointers to the bottom. + */ + remain = ch->ch_tstart + ch->ch_tsize - head; + + if (n >= remain) { + n -= remain; + vaddr = ch->ch_taddr + head; + + memcpy_toio(vaddr, (uchar *) buf, remain); + dgap_sniff_nowait_nolock(ch, "USER WRITE", (uchar *) buf, remain); + + head = ch->ch_tstart; + buf += remain; + } + + if (n > 0) { + + /* + * Move rest of data. + */ + vaddr = ch->ch_taddr + head; + remain = n; + + memcpy_toio(vaddr, (uchar *) buf, remain); + dgap_sniff_nowait_nolock(ch, "USER WRITE", (uchar *) buf, remain); + + head += remain; + + } + + if (count) { + ch->ch_txcount += count; + head &= tmask; + writew(head, &(bs->tx_head)); + } + + dgap_set_firmware_event(un, UN_LOW | UN_EMPTY); + + /* + * If this is the print device, and the + * printer is still on, we need to turn it + * off before going idle. If the buffer is + * non-empty, wait until it goes empty. + * Otherwise turn it off right now. + */ + if ((un->un_type == DGAP_PRINT) && (ch->ch_flags & CH_PRON)) { + tail = readw(&(bs->tx_tail)) & tmask; + + if (tail != head) { + un->un_flags |= UN_EMPTY; + writeb(1, &(bs->iempty)); + } else { + dgap_wmove(ch, ch->ch_digi.digi_offstr, + (int) ch->ch_digi.digi_offlen); + head = readw(&(bs->tx_head)) & tmask; + ch->ch_flags &= ~CH_PRON; + } + } + + /* Update printer buffer empty time. */ + if ((un->un_type == DGAP_PRINT) && (ch->ch_digi.digi_maxcps > 0) + && (ch->ch_digi.digi_bufsize > 0)) { + ch->ch_cpstime += (HZ * count) / ch->ch_digi.digi_maxcps; + } + + if (from_user) { + DGAP_UNLOCK(ch->ch_lock, lock_flags); + up(&dgap_TmpWriteSem); + } else + DGAP_UNLOCK(ch->ch_lock, lock_flags); + + return count; +} + +/* + * Return modem signals to ld. + */ +static int dgap_tty_tiocmget(struct tty_struct *tty) +{ + struct channel_t *ch; + struct un_t *un; + int result = -EIO; + uchar mstat = 0; + ulong lock_flags; + + if (!tty || tty->magic != TTY_MAGIC) + return result; + + un = tty->driver_data; + if (!un || un->magic != DGAP_UNIT_MAGIC) + return result; + + ch = un->un_ch; + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return result; + + DGAP_LOCK(ch->ch_lock, lock_flags); + + mstat = readb(&(ch->ch_bs->m_stat)); + /* Append any outbound signals that might be pending... */ + mstat |= ch->ch_mostat; + + DGAP_UNLOCK(ch->ch_lock, lock_flags); + + result = 0; + + if (mstat & D_DTR(ch)) + result |= TIOCM_DTR; + if (mstat & D_RTS(ch)) + result |= TIOCM_RTS; + if (mstat & D_CTS(ch)) + result |= TIOCM_CTS; + if (mstat & D_DSR(ch)) + result |= TIOCM_DSR; + if (mstat & D_RI(ch)) + result |= TIOCM_RI; + if (mstat & D_CD(ch)) + result |= TIOCM_CD; + + return result; +} + +/* + * dgap_tty_tiocmset() + * + * Set modem signals, called by ld. + */ +static int dgap_tty_tiocmset(struct tty_struct *tty, + unsigned int set, unsigned int clear) +{ + struct board_t *bd; + struct channel_t *ch; + struct un_t *un; + int ret = -EIO; + ulong lock_flags; + ulong lock_flags2; + + if (!tty || tty->magic != TTY_MAGIC) + return ret; + + un = tty->driver_data; + if (!un || un->magic != DGAP_UNIT_MAGIC) + return ret; + + ch = un->un_ch; + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return ret; + + bd = ch->ch_bd; + if (!bd || bd->magic != DGAP_BOARD_MAGIC) + return ret; + + DGAP_LOCK(bd->bd_lock, lock_flags); + DGAP_LOCK(ch->ch_lock, lock_flags2); + + if (set & TIOCM_RTS) { + ch->ch_mforce |= D_RTS(ch); + ch->ch_mval |= D_RTS(ch); + } + + if (set & TIOCM_DTR) { + ch->ch_mforce |= D_DTR(ch); + ch->ch_mval |= D_DTR(ch); + } + + if (clear & TIOCM_RTS) { + ch->ch_mforce |= D_RTS(ch); + ch->ch_mval &= ~(D_RTS(ch)); + } + + if (clear & TIOCM_DTR) { + ch->ch_mforce |= D_DTR(ch); + ch->ch_mval &= ~(D_DTR(ch)); + } + + dgap_param(tty); + + DGAP_UNLOCK(ch->ch_lock, lock_flags2); + DGAP_UNLOCK(bd->bd_lock, lock_flags); + + return 0; +} + +/* + * dgap_tty_send_break() + * + * Send a Break, called by ld. + */ +static int dgap_tty_send_break(struct tty_struct *tty, int msec) +{ + struct board_t *bd; + struct channel_t *ch; + struct un_t *un; + int ret = -EIO; + ulong lock_flags; + ulong lock_flags2; + + if (!tty || tty->magic != TTY_MAGIC) + return ret; + + un = tty->driver_data; + if (!un || un->magic != DGAP_UNIT_MAGIC) + return ret; + + ch = un->un_ch; + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return ret; + + bd = ch->ch_bd; + if (!bd || bd->magic != DGAP_BOARD_MAGIC) + return ret; + + switch (msec) { + case -1: + msec = 0xFFFF; + break; + case 0: + msec = 1; + break; + default: + msec /= 10; + break; + } + + DGAP_LOCK(bd->bd_lock, lock_flags); + DGAP_LOCK(ch->ch_lock, lock_flags2); +#if 0 + dgap_cmdw(ch, SBREAK, (u16) SBREAK_TIME, 0); +#endif + dgap_cmdw(ch, SBREAK, (u16) msec, 0); + + DGAP_UNLOCK(ch->ch_lock, lock_flags2); + DGAP_UNLOCK(bd->bd_lock, lock_flags); + + return 0; +} + +/* + * dgap_tty_wait_until_sent() + * + * wait until data has been transmitted, called by ld. + */ +static void dgap_tty_wait_until_sent(struct tty_struct *tty, int timeout) +{ + dgap_wait_for_drain(tty); +} + +/* + * dgap_send_xchar() + * + * send a high priority character, called by ld. + */ +static void dgap_tty_send_xchar(struct tty_struct *tty, char c) +{ + struct board_t *bd; + struct channel_t *ch; + struct un_t *un; + ulong lock_flags; + ulong lock_flags2; + + if (!tty || tty->magic != TTY_MAGIC) + return; + + un = tty->driver_data; + if (!un || un->magic != DGAP_UNIT_MAGIC) + return; + + ch = un->un_ch; + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return; + + bd = ch->ch_bd; + if (!bd || bd->magic != DGAP_BOARD_MAGIC) + return; + + DGAP_LOCK(bd->bd_lock, lock_flags); + DGAP_LOCK(ch->ch_lock, lock_flags2); + + /* + * This is technically what we should do. + * However, the NIST tests specifically want + * to see each XON or XOFF character that it + * sends, so lets just send each character + * by hand... + */ +#if 0 + if (c == STOP_CHAR(tty)) + dgap_cmdw(ch, RPAUSE, 0, 0); + else if (c == START_CHAR(tty)) + dgap_cmdw(ch, RRESUME, 0, 0); + else + dgap_wmove(ch, &c, 1); +#else + dgap_wmove(ch, &c, 1); +#endif + + DGAP_UNLOCK(ch->ch_lock, lock_flags2); + DGAP_UNLOCK(bd->bd_lock, lock_flags); + + return; +} + +/* + * Return modem signals to ld. + */ +static int dgap_get_modem_info(struct channel_t *ch, unsigned int __user *value) +{ + int result = 0; + uchar mstat = 0; + ulong lock_flags; + int rc = 0; + + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return -ENXIO; + + DGAP_LOCK(ch->ch_lock, lock_flags); + + mstat = readb(&(ch->ch_bs->m_stat)); + /* Append any outbound signals that might be pending... */ + mstat |= ch->ch_mostat; + + DGAP_UNLOCK(ch->ch_lock, lock_flags); + + result = 0; + + if (mstat & D_DTR(ch)) + result |= TIOCM_DTR; + if (mstat & D_RTS(ch)) + result |= TIOCM_RTS; + if (mstat & D_CTS(ch)) + result |= TIOCM_CTS; + if (mstat & D_DSR(ch)) + result |= TIOCM_DSR; + if (mstat & D_RI(ch)) + result |= TIOCM_RI; + if (mstat & D_CD(ch)) + result |= TIOCM_CD; + + rc = put_user(result, value); + + return rc; +} + +/* + * dgap_set_modem_info() + * + * Set modem signals, called by ld. + */ +static int dgap_set_modem_info(struct tty_struct *tty, unsigned int command, unsigned int __user *value) +{ + struct board_t *bd; + struct channel_t *ch; + struct un_t *un; + int ret = -ENXIO; + unsigned int arg = 0; + ulong lock_flags; + ulong lock_flags2; + + if (!tty || tty->magic != TTY_MAGIC) + return ret; + + un = tty->driver_data; + if (!un || un->magic != DGAP_UNIT_MAGIC) + return ret; + + ch = un->un_ch; + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return ret; + + bd = ch->ch_bd; + if (!bd || bd->magic != DGAP_BOARD_MAGIC) + return ret; + + ret = get_user(arg, value); + if (ret) + return ret; + + switch (command) { + case TIOCMBIS: + if (arg & TIOCM_RTS) { + ch->ch_mforce |= D_RTS(ch); + ch->ch_mval |= D_RTS(ch); + } + + if (arg & TIOCM_DTR) { + ch->ch_mforce |= D_DTR(ch); + ch->ch_mval |= D_DTR(ch); + } + + break; + + case TIOCMBIC: + if (arg & TIOCM_RTS) { + ch->ch_mforce |= D_RTS(ch); + ch->ch_mval &= ~(D_RTS(ch)); + } + + if (arg & TIOCM_DTR) { + ch->ch_mforce |= D_DTR(ch); + ch->ch_mval &= ~(D_DTR(ch)); + } + + break; + + case TIOCMSET: + ch->ch_mforce = D_DTR(ch)|D_RTS(ch); + + if (arg & TIOCM_RTS) + ch->ch_mval |= D_RTS(ch); + else + ch->ch_mval &= ~(D_RTS(ch)); + + if (arg & TIOCM_DTR) + ch->ch_mval |= (D_DTR(ch)); + else + ch->ch_mval &= ~(D_DTR(ch)); + + break; + + default: + return -EINVAL; + } + + DGAP_LOCK(bd->bd_lock, lock_flags); + DGAP_LOCK(ch->ch_lock, lock_flags2); + + dgap_param(tty); + + DGAP_UNLOCK(ch->ch_lock, lock_flags2); + DGAP_UNLOCK(bd->bd_lock, lock_flags); + + return 0; +} + +/* + * dgap_tty_digigeta() + * + * Ioctl to get the information for ditty. + * + * + * + */ +static int dgap_tty_digigeta(struct tty_struct *tty, struct digi_t __user *retinfo) +{ + struct channel_t *ch; + struct un_t *un; + struct digi_t tmp; + ulong lock_flags; + + if (!retinfo) + return -EFAULT; + + if (!tty || tty->magic != TTY_MAGIC) + return -EFAULT; + + un = tty->driver_data; + if (!un || un->magic != DGAP_UNIT_MAGIC) + return -EFAULT; + + ch = un->un_ch; + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return -EFAULT; + + memset(&tmp, 0, sizeof(tmp)); + + DGAP_LOCK(ch->ch_lock, lock_flags); + memcpy(&tmp, &ch->ch_digi, sizeof(tmp)); + DGAP_UNLOCK(ch->ch_lock, lock_flags); + + if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) + return -EFAULT; + + return 0; +} + +/* + * dgap_tty_digiseta() + * + * Ioctl to set the information for ditty. + * + * + * + */ +static int dgap_tty_digiseta(struct tty_struct *tty, struct digi_t __user *new_info) +{ + struct board_t *bd; + struct channel_t *ch; + struct un_t *un; + struct digi_t new_digi; + ulong lock_flags = 0; + unsigned long lock_flags2; + + if (!tty || tty->magic != TTY_MAGIC) + return -EFAULT; + + un = tty->driver_data; + if (!un || un->magic != DGAP_UNIT_MAGIC) + return -EFAULT; + + ch = un->un_ch; + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return -EFAULT; + + bd = ch->ch_bd; + if (!bd || bd->magic != DGAP_BOARD_MAGIC) + return -EFAULT; + + if (copy_from_user(&new_digi, new_info, sizeof(struct digi_t))) + return -EFAULT; + + DGAP_LOCK(bd->bd_lock, lock_flags); + DGAP_LOCK(ch->ch_lock, lock_flags2); + + memcpy(&ch->ch_digi, &new_digi, sizeof(struct digi_t)); + + if (ch->ch_digi.digi_maxcps < 1) + ch->ch_digi.digi_maxcps = 1; + + if (ch->ch_digi.digi_maxcps > 10000) + ch->ch_digi.digi_maxcps = 10000; + + if (ch->ch_digi.digi_bufsize < 10) + ch->ch_digi.digi_bufsize = 10; + + if (ch->ch_digi.digi_maxchar < 1) + ch->ch_digi.digi_maxchar = 1; + + if (ch->ch_digi.digi_maxchar > ch->ch_digi.digi_bufsize) + ch->ch_digi.digi_maxchar = ch->ch_digi.digi_bufsize; + + if (ch->ch_digi.digi_onlen > DIGI_PLEN) + ch->ch_digi.digi_onlen = DIGI_PLEN; + + if (ch->ch_digi.digi_offlen > DIGI_PLEN) + ch->ch_digi.digi_offlen = DIGI_PLEN; + + dgap_param(tty); + + DGAP_UNLOCK(ch->ch_lock, lock_flags2); + DGAP_UNLOCK(bd->bd_lock, lock_flags); + + return 0; +} + +/* + * dgap_tty_digigetedelay() + * + * Ioctl to get the current edelay setting. + * + * + * + */ +static int dgap_tty_digigetedelay(struct tty_struct *tty, int __user *retinfo) +{ + struct channel_t *ch; + struct un_t *un; + int tmp; + ulong lock_flags; + + if (!retinfo) + return -EFAULT; + + if (!tty || tty->magic != TTY_MAGIC) + return -EFAULT; + + un = tty->driver_data; + if (!un || un->magic != DGAP_UNIT_MAGIC) + return -EFAULT; + + ch = un->un_ch; + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return -EFAULT; + + memset(&tmp, 0, sizeof(tmp)); + + DGAP_LOCK(ch->ch_lock, lock_flags); + tmp = readw(&(ch->ch_bs->edelay)); + DGAP_UNLOCK(ch->ch_lock, lock_flags); + + if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) + return -EFAULT; + + return 0; +} + +/* + * dgap_tty_digisetedelay() + * + * Ioctl to set the EDELAY setting + * + */ +static int dgap_tty_digisetedelay(struct tty_struct *tty, int __user *new_info) +{ + struct board_t *bd; + struct channel_t *ch; + struct un_t *un; + int new_digi; + ulong lock_flags; + ulong lock_flags2; + + if (!tty || tty->magic != TTY_MAGIC) + return -EFAULT; + + un = tty->driver_data; + if (!un || un->magic != DGAP_UNIT_MAGIC) + return -EFAULT; + + ch = un->un_ch; + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return -EFAULT; + + bd = ch->ch_bd; + if (!bd || bd->magic != DGAP_BOARD_MAGIC) + return -EFAULT; + + if (copy_from_user(&new_digi, new_info, sizeof(int))) + return -EFAULT; + + DGAP_LOCK(bd->bd_lock, lock_flags); + DGAP_LOCK(ch->ch_lock, lock_flags2); + + writew((u16) new_digi, &(ch->ch_bs->edelay)); + + dgap_param(tty); + + DGAP_UNLOCK(ch->ch_lock, lock_flags2); + DGAP_UNLOCK(bd->bd_lock, lock_flags); + + return 0; +} + +/* + * dgap_tty_digigetcustombaud() + * + * Ioctl to get the current custom baud rate setting. + */ +static int dgap_tty_digigetcustombaud(struct tty_struct *tty, int __user *retinfo) +{ + struct channel_t *ch; + struct un_t *un; + int tmp; + ulong lock_flags; + + if (!retinfo) + return -EFAULT; + + if (!tty || tty->magic != TTY_MAGIC) + return -EFAULT; + + un = tty->driver_data; + if (!un || un->magic != DGAP_UNIT_MAGIC) + return -EFAULT; + + ch = un->un_ch; + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return -EFAULT; + + memset(&tmp, 0, sizeof(tmp)); + + DGAP_LOCK(ch->ch_lock, lock_flags); + tmp = dgap_get_custom_baud(ch); + DGAP_UNLOCK(ch->ch_lock, lock_flags); + + if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) + return -EFAULT; + + return 0; +} + +/* + * dgap_tty_digisetcustombaud() + * + * Ioctl to set the custom baud rate setting + */ +static int dgap_tty_digisetcustombaud(struct tty_struct *tty, int __user *new_info) +{ + struct board_t *bd; + struct channel_t *ch; + struct un_t *un; + uint new_rate; + ulong lock_flags; + ulong lock_flags2; + + if (!tty || tty->magic != TTY_MAGIC) + return -EFAULT; + + un = tty->driver_data; + if (!un || un->magic != DGAP_UNIT_MAGIC) + return -EFAULT; + + ch = un->un_ch; + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return -EFAULT; + + bd = ch->ch_bd; + if (!bd || bd->magic != DGAP_BOARD_MAGIC) + return -EFAULT; + + + if (copy_from_user(&new_rate, new_info, sizeof(unsigned int))) + return -EFAULT; + + if (bd->bd_flags & BD_FEP5PLUS) { + + DGAP_LOCK(bd->bd_lock, lock_flags); + DGAP_LOCK(ch->ch_lock, lock_flags2); + + ch->ch_custom_speed = new_rate; + + dgap_param(tty); + + DGAP_UNLOCK(ch->ch_lock, lock_flags2); + DGAP_UNLOCK(bd->bd_lock, lock_flags); + } + + return 0; +} + +/* + * dgap_set_termios() + */ +static void dgap_tty_set_termios(struct tty_struct *tty, struct ktermios *old_termios) +{ + struct board_t *bd; + struct channel_t *ch; + struct un_t *un; + unsigned long lock_flags; + unsigned long lock_flags2; + + if (!tty || tty->magic != TTY_MAGIC) + return; + + un = tty->driver_data; + if (!un || un->magic != DGAP_UNIT_MAGIC) + return; + + ch = un->un_ch; + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return; + + bd = ch->ch_bd; + if (!bd || bd->magic != DGAP_BOARD_MAGIC) + return; + + DGAP_LOCK(bd->bd_lock, lock_flags); + DGAP_LOCK(ch->ch_lock, lock_flags2); + + ch->ch_c_cflag = tty->termios.c_cflag; + ch->ch_c_iflag = tty->termios.c_iflag; + ch->ch_c_oflag = tty->termios.c_oflag; + ch->ch_c_lflag = tty->termios.c_lflag; + ch->ch_startc = tty->termios.c_cc[VSTART]; + ch->ch_stopc = tty->termios.c_cc[VSTOP]; + + dgap_carrier(ch); + dgap_param(tty); + + DGAP_UNLOCK(ch->ch_lock, lock_flags2); + DGAP_UNLOCK(bd->bd_lock, lock_flags); +} + +static void dgap_tty_throttle(struct tty_struct *tty) +{ + struct board_t *bd; + struct channel_t *ch; + struct un_t *un; + ulong lock_flags; + ulong lock_flags2; + + if (!tty || tty->magic != TTY_MAGIC) + return; + + un = tty->driver_data; + if (!un || un->magic != DGAP_UNIT_MAGIC) + return; + + ch = un->un_ch; + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return; + + bd = ch->ch_bd; + if (!bd || bd->magic != DGAP_BOARD_MAGIC) + return; + + DGAP_LOCK(bd->bd_lock, lock_flags); + DGAP_LOCK(ch->ch_lock, lock_flags2); + + ch->ch_flags |= (CH_RXBLOCK); +#if 1 + dgap_cmdw(ch, RPAUSE, 0, 0); +#endif + + DGAP_UNLOCK(ch->ch_lock, lock_flags2); + DGAP_UNLOCK(bd->bd_lock, lock_flags); + +} + +static void dgap_tty_unthrottle(struct tty_struct *tty) +{ + struct board_t *bd; + struct channel_t *ch; + struct un_t *un; + ulong lock_flags; + ulong lock_flags2; + + if (!tty || tty->magic != TTY_MAGIC) + return; + + un = tty->driver_data; + if (!un || un->magic != DGAP_UNIT_MAGIC) + return; + + ch = un->un_ch; + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return; + + bd = ch->ch_bd; + if (!bd || bd->magic != DGAP_BOARD_MAGIC) + return; + + DGAP_LOCK(bd->bd_lock, lock_flags); + DGAP_LOCK(ch->ch_lock, lock_flags2); + + ch->ch_flags &= ~(CH_RXBLOCK); + +#if 1 + dgap_cmdw(ch, RRESUME, 0, 0); +#endif + + DGAP_UNLOCK(ch->ch_lock, lock_flags2); + DGAP_UNLOCK(bd->bd_lock, lock_flags); +} + +static void dgap_tty_start(struct tty_struct *tty) +{ + struct board_t *bd; + struct channel_t *ch; + struct un_t *un; + ulong lock_flags; + ulong lock_flags2; + + if (!tty || tty->magic != TTY_MAGIC) + return; + + un = tty->driver_data; + if (!un || un->magic != DGAP_UNIT_MAGIC) + return; + + ch = un->un_ch; + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return; + + bd = ch->ch_bd; + if (!bd || bd->magic != DGAP_BOARD_MAGIC) + return; + + DGAP_LOCK(bd->bd_lock, lock_flags); + DGAP_LOCK(ch->ch_lock, lock_flags2); + + dgap_cmdw(ch, RESUMETX, 0, 0); + + DGAP_UNLOCK(ch->ch_lock, lock_flags2); + DGAP_UNLOCK(bd->bd_lock, lock_flags); + +} + +static void dgap_tty_stop(struct tty_struct *tty) +{ + struct board_t *bd; + struct channel_t *ch; + struct un_t *un; + ulong lock_flags; + ulong lock_flags2; + + if (!tty || tty->magic != TTY_MAGIC) + return; + + un = tty->driver_data; + if (!un || un->magic != DGAP_UNIT_MAGIC) + return; + + ch = un->un_ch; + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return; + + bd = ch->ch_bd; + if (!bd || bd->magic != DGAP_BOARD_MAGIC) + return; + + DGAP_LOCK(bd->bd_lock, lock_flags); + DGAP_LOCK(ch->ch_lock, lock_flags2); + + dgap_cmdw(ch, PAUSETX, 0, 0); + + DGAP_UNLOCK(ch->ch_lock, lock_flags2); + DGAP_UNLOCK(bd->bd_lock, lock_flags); + +} + +/* + * dgap_tty_flush_chars() + * + * Flush the cook buffer + * + * Note to self, and any other poor souls who venture here: + * + * flush in this case DOES NOT mean dispose of the data. + * instead, it means "stop buffering and send it if you + * haven't already." Just guess how I figured that out... SRW 2-Jun-98 + * + * It is also always called in interrupt context - JAR 8-Sept-99 + */ +static void dgap_tty_flush_chars(struct tty_struct *tty) +{ + struct board_t *bd; + struct channel_t *ch; + struct un_t *un; + ulong lock_flags; + ulong lock_flags2; + + if (!tty || tty->magic != TTY_MAGIC) + return; + + un = tty->driver_data; + if (!un || un->magic != DGAP_UNIT_MAGIC) + return; + + ch = un->un_ch; + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return; + + bd = ch->ch_bd; + if (!bd || bd->magic != DGAP_BOARD_MAGIC) + return; + + DGAP_LOCK(bd->bd_lock, lock_flags); + DGAP_LOCK(ch->ch_lock, lock_flags2); + + /* TODO: Do something here */ + + DGAP_UNLOCK(ch->ch_lock, lock_flags2); + DGAP_UNLOCK(bd->bd_lock, lock_flags); +} + +/* + * dgap_tty_flush_buffer() + * + * Flush Tx buffer (make in == out) + */ +static void dgap_tty_flush_buffer(struct tty_struct *tty) +{ + struct board_t *bd; + struct channel_t *ch; + struct un_t *un; + ulong lock_flags; + ulong lock_flags2; + u16 head = 0; + + if (!tty || tty->magic != TTY_MAGIC) + return; + + un = tty->driver_data; + if (!un || un->magic != DGAP_UNIT_MAGIC) + return; + + ch = un->un_ch; + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return; + + bd = ch->ch_bd; + if (!bd || bd->magic != DGAP_BOARD_MAGIC) + return; + + DGAP_LOCK(bd->bd_lock, lock_flags); + DGAP_LOCK(ch->ch_lock, lock_flags2); + + ch->ch_flags &= ~CH_STOP; + head = readw(&(ch->ch_bs->tx_head)); + dgap_cmdw(ch, FLUSHTX, (u16) head, 0); + dgap_cmdw(ch, RESUMETX, 0, 0); + if (ch->ch_tun.un_flags & (UN_LOW|UN_EMPTY)) { + ch->ch_tun.un_flags &= ~(UN_LOW|UN_EMPTY); + wake_up_interruptible(&ch->ch_tun.un_flags_wait); + } + if (ch->ch_pun.un_flags & (UN_LOW|UN_EMPTY)) { + ch->ch_pun.un_flags &= ~(UN_LOW|UN_EMPTY); + wake_up_interruptible(&ch->ch_pun.un_flags_wait); + } + + DGAP_UNLOCK(ch->ch_lock, lock_flags2); + DGAP_UNLOCK(bd->bd_lock, lock_flags); + if (waitqueue_active(&tty->write_wait)) + wake_up_interruptible(&tty->write_wait); + tty_wakeup(tty); +} + +/***************************************************************************** + * + * The IOCTL function and all of its helpers + * + *****************************************************************************/ + +/* + * dgap_tty_ioctl() + * + * The usual assortment of ioctl's + */ +static int dgap_tty_ioctl(struct tty_struct *tty, unsigned int cmd, + unsigned long arg) +{ + struct board_t *bd; + struct channel_t *ch; + struct un_t *un; + int rc; + u16 head = 0; + ulong lock_flags = 0; + ulong lock_flags2 = 0; + void __user *uarg = (void __user *) arg; + + if (!tty || tty->magic != TTY_MAGIC) + return -ENODEV; + + un = tty->driver_data; + if (!un || un->magic != DGAP_UNIT_MAGIC) + return -ENODEV; + + ch = un->un_ch; + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return -ENODEV; + + bd = ch->ch_bd; + if (!bd || bd->magic != DGAP_BOARD_MAGIC) + return -ENODEV; + + DGAP_LOCK(bd->bd_lock, lock_flags); + DGAP_LOCK(ch->ch_lock, lock_flags2); + + if (un->un_open_count <= 0) { + DGAP_UNLOCK(ch->ch_lock, lock_flags2); + DGAP_UNLOCK(bd->bd_lock, lock_flags); + return -EIO; + } + + switch (cmd) { + + /* Here are all the standard ioctl's that we MUST implement */ + + case TCSBRK: + /* + * TCSBRK is SVID version: non-zero arg --> no break + * this behaviour is exploited by tcdrain(). + * + * According to POSIX.1 spec (7.2.2.1.2) breaks should be + * between 0.25 and 0.5 seconds so we'll ask for something + * in the middle: 0.375 seconds. + */ + rc = tty_check_change(tty); + DGAP_UNLOCK(ch->ch_lock, lock_flags2); + DGAP_UNLOCK(bd->bd_lock, lock_flags); + if (rc) + return rc; + + rc = dgap_wait_for_drain(tty); + + if (rc) + return -EINTR; + + DGAP_LOCK(bd->bd_lock, lock_flags); + DGAP_LOCK(ch->ch_lock, lock_flags2); + + if (((cmd == TCSBRK) && (!arg)) || (cmd == TCSBRKP)) + dgap_cmdw(ch, SBREAK, (u16) SBREAK_TIME, 0); + + DGAP_UNLOCK(ch->ch_lock, lock_flags2); + DGAP_UNLOCK(bd->bd_lock, lock_flags); + + return 0; + + case TCSBRKP: + /* support for POSIX tcsendbreak() + + * According to POSIX.1 spec (7.2.2.1.2) breaks should be + * between 0.25 and 0.5 seconds so we'll ask for something + * in the middle: 0.375 seconds. + */ + rc = tty_check_change(tty); + DGAP_UNLOCK(ch->ch_lock, lock_flags2); + DGAP_UNLOCK(bd->bd_lock, lock_flags); + if (rc) + return rc; + + rc = dgap_wait_for_drain(tty); + if (rc) + return -EINTR; + + DGAP_LOCK(bd->bd_lock, lock_flags); + DGAP_LOCK(ch->ch_lock, lock_flags2); + + dgap_cmdw(ch, SBREAK, (u16) SBREAK_TIME, 0); + + DGAP_UNLOCK(ch->ch_lock, lock_flags2); + DGAP_UNLOCK(bd->bd_lock, lock_flags); + + return 0; + + case TIOCSBRK: + /* + * FEP5 doesn't support turning on a break unconditionally. + * The FEP5 device will stop sending a break automatically + * after the specified time value that was sent when turning on + * the break. + */ + rc = tty_check_change(tty); + DGAP_UNLOCK(ch->ch_lock, lock_flags2); + DGAP_UNLOCK(bd->bd_lock, lock_flags); + if (rc) + return rc; + + rc = dgap_wait_for_drain(tty); + if (rc) + return -EINTR; + + DGAP_LOCK(bd->bd_lock, lock_flags); + DGAP_LOCK(ch->ch_lock, lock_flags2); + + dgap_cmdw(ch, SBREAK, (u16) SBREAK_TIME, 0); + + DGAP_UNLOCK(ch->ch_lock, lock_flags2); + DGAP_UNLOCK(bd->bd_lock, lock_flags); + + return 0; + + case TIOCCBRK: + /* + * FEP5 doesn't support turning off a break unconditionally. + * The FEP5 device will stop sending a break automatically + * after the specified time value that was sent when turning on + * the break. + */ + DGAP_UNLOCK(ch->ch_lock, lock_flags2); + DGAP_UNLOCK(bd->bd_lock, lock_flags); + return 0; + + case TIOCGSOFTCAR: + + DGAP_UNLOCK(ch->ch_lock, lock_flags2); + DGAP_UNLOCK(bd->bd_lock, lock_flags); + + rc = put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long __user *) arg); + return rc; + + case TIOCSSOFTCAR: + DGAP_UNLOCK(ch->ch_lock, lock_flags2); + DGAP_UNLOCK(bd->bd_lock, lock_flags); + + rc = get_user(arg, (unsigned long __user *) arg); + if (rc) + return rc; + + DGAP_LOCK(bd->bd_lock, lock_flags); + DGAP_LOCK(ch->ch_lock, lock_flags2); + tty->termios.c_cflag = ((tty->termios.c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0)); + dgap_param(tty); + DGAP_UNLOCK(ch->ch_lock, lock_flags2); + DGAP_UNLOCK(bd->bd_lock, lock_flags); + + return 0; + + case TIOCMGET: + DGAP_UNLOCK(ch->ch_lock, lock_flags2); + DGAP_UNLOCK(bd->bd_lock, lock_flags); + return dgap_get_modem_info(ch, uarg); + + case TIOCMBIS: + case TIOCMBIC: + case TIOCMSET: + DGAP_UNLOCK(ch->ch_lock, lock_flags2); + DGAP_UNLOCK(bd->bd_lock, lock_flags); + return dgap_set_modem_info(tty, cmd, uarg); + + /* + * Here are any additional ioctl's that we want to implement + */ + + case TCFLSH: + /* + * The linux tty driver doesn't have a flush + * input routine for the driver, assuming all backed + * up data is in the line disc. buffers. However, + * we all know that's not the case. Here, we + * act on the ioctl, but then lie and say we didn't + * so the line discipline will process the flush + * also. + */ + rc = tty_check_change(tty); + if (rc) { + DGAP_UNLOCK(ch->ch_lock, lock_flags2); + DGAP_UNLOCK(bd->bd_lock, lock_flags); + return rc; + } + + if ((arg == TCIFLUSH) || (arg == TCIOFLUSH)) { + if (!(un->un_type == DGAP_PRINT)) { + head = readw(&(ch->ch_bs->rx_head)); + writew(head, &(ch->ch_bs->rx_tail)); + writeb(0, &(ch->ch_bs->orun)); + } + } + + if ((arg == TCOFLUSH) || (arg == TCIOFLUSH)) { + ch->ch_flags &= ~CH_STOP; + head = readw(&(ch->ch_bs->tx_head)); + dgap_cmdw(ch, FLUSHTX, (u16) head, 0); + dgap_cmdw(ch, RESUMETX, 0, 0); + if (ch->ch_tun.un_flags & (UN_LOW|UN_EMPTY)) { + ch->ch_tun.un_flags &= ~(UN_LOW|UN_EMPTY); + wake_up_interruptible(&ch->ch_tun.un_flags_wait); + } + if (ch->ch_pun.un_flags & (UN_LOW|UN_EMPTY)) { + ch->ch_pun.un_flags &= ~(UN_LOW|UN_EMPTY); + wake_up_interruptible(&ch->ch_pun.un_flags_wait); + } + if (waitqueue_active(&tty->write_wait)) + wake_up_interruptible(&tty->write_wait); + + /* Can't hold any locks when calling tty_wakeup! */ + DGAP_UNLOCK(ch->ch_lock, lock_flags2); + DGAP_UNLOCK(bd->bd_lock, lock_flags); + tty_wakeup(tty); + DGAP_LOCK(bd->bd_lock, lock_flags); + DGAP_LOCK(ch->ch_lock, lock_flags2); + } + + /* pretend we didn't recognize this IOCTL */ + DGAP_UNLOCK(ch->ch_lock, lock_flags2); + DGAP_UNLOCK(bd->bd_lock, lock_flags); + + return -ENOIOCTLCMD; + + case TCSETSF: + case TCSETSW: + /* + * The linux tty driver doesn't have a flush + * input routine for the driver, assuming all backed + * up data is in the line disc. buffers. However, + * we all know that's not the case. Here, we + * act on the ioctl, but then lie and say we didn't + * so the line discipline will process the flush + * also. + */ + if (cmd == TCSETSF) { + /* flush rx */ + ch->ch_flags &= ~CH_STOP; + head = readw(&(ch->ch_bs->rx_head)); + writew(head, &(ch->ch_bs->rx_tail)); + } + + /* now wait for all the output to drain */ + DGAP_UNLOCK(ch->ch_lock, lock_flags2); + DGAP_UNLOCK(bd->bd_lock, lock_flags); + rc = dgap_wait_for_drain(tty); + if (rc) + return -EINTR; + + /* pretend we didn't recognize this */ + return -ENOIOCTLCMD; + + case TCSETAW: + + DGAP_UNLOCK(ch->ch_lock, lock_flags2); + DGAP_UNLOCK(bd->bd_lock, lock_flags); + rc = dgap_wait_for_drain(tty); + if (rc) + return -EINTR; + + /* pretend we didn't recognize this */ + return -ENOIOCTLCMD; + + case TCXONC: + /* + * The Linux Line Discipline (LD) would do this for us if we + * let it, but we have the special firmware options to do this + * the "right way" regardless of hardware or software flow + * control so we'll do it outselves instead of letting the LD + * do it. + */ + rc = tty_check_change(tty); + if (rc) { + DGAP_UNLOCK(ch->ch_lock, lock_flags2); + DGAP_UNLOCK(bd->bd_lock, lock_flags); + return rc; + } + + switch (arg) { + + case TCOON: + DGAP_UNLOCK(ch->ch_lock, lock_flags2); + DGAP_UNLOCK(bd->bd_lock, lock_flags); + dgap_tty_start(tty); + return 0; + case TCOOFF: + DGAP_UNLOCK(ch->ch_lock, lock_flags2); + DGAP_UNLOCK(bd->bd_lock, lock_flags); + dgap_tty_stop(tty); + return 0; + case TCION: + DGAP_UNLOCK(ch->ch_lock, lock_flags2); + DGAP_UNLOCK(bd->bd_lock, lock_flags); + /* Make the ld do it */ + return -ENOIOCTLCMD; + case TCIOFF: + DGAP_UNLOCK(ch->ch_lock, lock_flags2); + DGAP_UNLOCK(bd->bd_lock, lock_flags); + /* Make the ld do it */ + return -ENOIOCTLCMD; + default: + DGAP_UNLOCK(ch->ch_lock, lock_flags2); + DGAP_UNLOCK(bd->bd_lock, lock_flags); + return -EINVAL; + } + + case DIGI_GETA: + /* get information for ditty */ + DGAP_UNLOCK(ch->ch_lock, lock_flags2); + DGAP_UNLOCK(bd->bd_lock, lock_flags); + return dgap_tty_digigeta(tty, uarg); + + case DIGI_SETAW: + case DIGI_SETAF: + + /* set information for ditty */ + if (cmd == (DIGI_SETAW)) { + + DGAP_UNLOCK(ch->ch_lock, lock_flags2); + DGAP_UNLOCK(bd->bd_lock, lock_flags); + rc = dgap_wait_for_drain(tty); + if (rc) + return -EINTR; + DGAP_LOCK(bd->bd_lock, lock_flags); + DGAP_LOCK(ch->ch_lock, lock_flags2); + } else + tty_ldisc_flush(tty); + /* fall thru */ + + case DIGI_SETA: + DGAP_UNLOCK(ch->ch_lock, lock_flags2); + DGAP_UNLOCK(bd->bd_lock, lock_flags); + return dgap_tty_digiseta(tty, uarg); + + case DIGI_GEDELAY: + DGAP_UNLOCK(ch->ch_lock, lock_flags2); + DGAP_UNLOCK(bd->bd_lock, lock_flags); + return dgap_tty_digigetedelay(tty, uarg); + + case DIGI_SEDELAY: + DGAP_UNLOCK(ch->ch_lock, lock_flags2); + DGAP_UNLOCK(bd->bd_lock, lock_flags); + return dgap_tty_digisetedelay(tty, uarg); + + case DIGI_GETCUSTOMBAUD: + DGAP_UNLOCK(ch->ch_lock, lock_flags2); + DGAP_UNLOCK(bd->bd_lock, lock_flags); + return dgap_tty_digigetcustombaud(tty, uarg); + + case DIGI_SETCUSTOMBAUD: + DGAP_UNLOCK(ch->ch_lock, lock_flags2); + DGAP_UNLOCK(bd->bd_lock, lock_flags); + return dgap_tty_digisetcustombaud(tty, uarg); + + case DIGI_RESET_PORT: + dgap_firmware_reset_port(ch); + dgap_param(tty); + DGAP_UNLOCK(ch->ch_lock, lock_flags2); + DGAP_UNLOCK(bd->bd_lock, lock_flags); + return 0; + + default: + DGAP_UNLOCK(ch->ch_lock, lock_flags2); + DGAP_UNLOCK(bd->bd_lock, lock_flags); + + return -ENOIOCTLCMD; + } +} + +static int dgap_after_config_loaded(int board) +{ + /* + * Initialize KME waitqueues... + */ + init_waitqueue_head(&(dgap_Board[board]->kme_wait)); + + /* + * allocate flip buffer for board. + */ + dgap_Board[board]->flipbuf = kmalloc(MYFLIPLEN, GFP_ATOMIC); + if (!dgap_Board[board]->flipbuf) + return -ENOMEM; + + dgap_Board[board]->flipflagbuf = kmalloc(MYFLIPLEN, GFP_ATOMIC); + if (!dgap_Board[board]->flipflagbuf) { + kfree(dgap_Board[board]->flipbuf); + return -ENOMEM; + } + + return 0; +} + +/* + * Create pr and tty device entries + */ +static int dgap_tty_register_ports(struct board_t *brd) +{ + struct channel_t *ch; + int i; + + brd->SerialPorts = kcalloc(brd->nasync, sizeof(*brd->SerialPorts), + GFP_KERNEL); + if (brd->SerialPorts == NULL) + return -ENOMEM; + for (i = 0; i < brd->nasync; i++) + tty_port_init(&brd->SerialPorts[i]); + + brd->PrinterPorts = kcalloc(brd->nasync, sizeof(*brd->PrinterPorts), + GFP_KERNEL); + if (brd->PrinterPorts == NULL) { + kfree(brd->SerialPorts); + return -ENOMEM; + } + for (i = 0; i < brd->nasync; i++) + tty_port_init(&brd->PrinterPorts[i]); + + ch = brd->channels[0]; + for (i = 0; i < brd->nasync; i++, ch = brd->channels[i]) { + + struct device *classp; + + classp = tty_port_register_device(&brd->SerialPorts[i], + brd->SerialDriver, + brd->firstminor + i, NULL); + + dgap_create_tty_sysfs(&ch->ch_tun, classp); + ch->ch_tun.un_sysfs = classp; + + classp = tty_port_register_device(&brd->PrinterPorts[i], + brd->PrintDriver, + brd->firstminor + i, NULL); + + dgap_create_tty_sysfs(&ch->ch_pun, classp); + ch->ch_pun.un_sysfs = classp; + } + dgap_create_ports_sysfiles(brd); + + return 0; +} + +/* + * Copies the BIOS code from the user to the board, + * and starts the BIOS running. + */ +static void dgap_do_bios_load(struct board_t *brd, uchar __user *ubios, int len) +{ + uchar *addr; + uint offset; + int i; + + if (!brd || (brd->magic != DGAP_BOARD_MAGIC) || !brd->re_map_membase) + return; + + addr = brd->re_map_membase; + + /* + * clear POST area + */ + for (i = 0; i < 16; i++) + writeb(0, addr + POSTAREA + i); + + /* + * Download bios + */ + offset = 0x1000; + memcpy_toio(addr + offset, ubios, len); + + writel(0x0bf00401, addr); + writel(0, (addr + 4)); + + /* Clear the reset, and change states. */ + writeb(FEPCLR, brd->re_map_port); +} + +/* + * Checks to see if the BIOS completed running on the card. + */ +static void dgap_do_wait_for_bios(struct board_t *brd) +{ + uchar *addr; + u16 word; + u16 err1; + u16 err2; + + if (!brd || (brd->magic != DGAP_BOARD_MAGIC) || !brd->re_map_membase) + return; + + addr = brd->re_map_membase; + word = readw(addr + POSTAREA); + + /* + * It can take 5-6 seconds for a board to + * pass the bios self test and post results. + * Give it 10 seconds. + */ + brd->wait_for_bios = 0; + while (brd->wait_for_bios < 1000) { + /* Check to see if BIOS thinks board is good. (GD). */ + if (word == *(u16 *) "GD") { + brd->state = FINISHED_BIOS_LOAD; + return; + } + msleep_interruptible(10); + brd->wait_for_bios++; + word = readw(addr + POSTAREA); + } + + /* Gave up on board after too long of time taken */ + err1 = readw(addr + SEQUENCE); + err2 = readw(addr + ERROR); + pr_warn("dgap: %s failed diagnostics. Error #(%x,%x).\n", + brd->name, err1, err2); + brd->state = BOARD_FAILED; + brd->dpastatus = BD_NOBIOS; +} + +/* + * Copies the FEP code from the user to the board, + * and starts the FEP running. + */ +static void dgap_do_fep_load(struct board_t *brd, uchar *ufep, int len) +{ + uchar *addr; + uint offset; + + if (!brd || (brd->magic != DGAP_BOARD_MAGIC) || !brd->re_map_membase) + return; + + addr = brd->re_map_membase; + + /* + * Download FEP + */ + offset = 0x1000; + memcpy_toio(addr + offset, ufep, len); + + /* + * If board is a concentrator product, we need to give + * it its config string describing how the concentrators look. + */ + if ((brd->type == PCX) || (brd->type == PEPC)) { + uchar string[100]; + uchar *config, *xconfig; + int i = 0; + + xconfig = dgap_create_config_string(brd, string); + + /* Write string to board memory */ + config = addr + CONFIG; + for (; i < CONFIGSIZE; i++, config++, xconfig++) { + writeb(*xconfig, config); + if ((*xconfig & 0xff) == 0xff) + break; + } + } + + writel(0xbfc01004, (addr + 0xc34)); + writel(0x3, (addr + 0xc30)); + +} + +/* + * Waits for the FEP to report thats its ready for us to use. + */ +static void dgap_do_wait_for_fep(struct board_t *brd) +{ + uchar *addr; + u16 word; + u16 err1; + u16 err2; + + if (!brd || (brd->magic != DGAP_BOARD_MAGIC) || !brd->re_map_membase) + return; + + addr = brd->re_map_membase; + word = readw(addr + FEPSTAT); + + /* + * It can take 2-3 seconds for the FEP to + * be up and running. Give it 5 secs. + */ + brd->wait_for_fep = 0; + while (brd->wait_for_fep < 500) { + /* Check to see if FEP is up and running now. */ + if (word == *(u16 *) "OS") { + brd->state = FINISHED_FEP_LOAD; + /* + * Check to see if the board can support FEP5+ commands. + */ + word = readw(addr + FEP5_PLUS); + if (word == *(u16 *) "5A") + brd->bd_flags |= BD_FEP5PLUS; + + return; + } + msleep_interruptible(10); + brd->wait_for_fep++; + word = readw(addr + FEPSTAT); + } + + /* Gave up on board after too long of time taken */ + err1 = readw(addr + SEQUENCE); + err2 = readw(addr + ERROR); + pr_warn("dgap: FEPOS for %s not functioning. Error #(%x,%x).\n", + brd->name, err1, err2); + brd->state = BOARD_FAILED; + brd->dpastatus = BD_NOFEP; +} + +/* + * Physically forces the FEP5 card to reset itself. + */ +static void dgap_do_reset_board(struct board_t *brd) +{ + uchar check; + u32 check1; + u32 check2; + int i = 0; + + if (!brd || (brd->magic != DGAP_BOARD_MAGIC) || + !brd->re_map_membase || !brd->re_map_port) + return; + + /* FEPRST does not vary among supported boards */ + writeb(FEPRST, brd->re_map_port); + + for (i = 0; i <= 1000; i++) { + check = readb(brd->re_map_port) & 0xe; + if (check == FEPRST) + break; + udelay(10); + + } + if (i > 1000) { + pr_warn("dgap: Board not resetting... Failing board.\n"); + brd->state = BOARD_FAILED; + brd->dpastatus = BD_NOFEP; + return; + } + + /* + * Make sure there really is memory out there. + */ + writel(0xa55a3cc3, (brd->re_map_membase + LOWMEM)); + writel(0x5aa5c33c, (brd->re_map_membase + HIGHMEM)); + check1 = readl(brd->re_map_membase + LOWMEM); + check2 = readl(brd->re_map_membase + HIGHMEM); + + if ((check1 != 0xa55a3cc3) || (check2 != 0x5aa5c33c)) { + pr_warn("dgap: No memory at %p for board.\n", + brd->re_map_membase); + brd->state = BOARD_FAILED; + brd->dpastatus = BD_NOFEP; + return; + } + + if (brd->state != BOARD_FAILED) + brd->state = FINISHED_RESET; +} + +#ifdef DIGI_CONCENTRATORS_SUPPORTED +/* + * Sends a concentrator image into the FEP5 board. + */ +static void dgap_do_conc_load(struct board_t *brd, uchar *uaddr, int len) +{ + char *vaddr; + u16 offset = 0; + struct downld_t *to_dp; + + if (!brd || (brd->magic != DGAP_BOARD_MAGIC) || !brd->re_map_membase) + return; + + vaddr = brd->re_map_membase; + + offset = readw((u16 *) (vaddr + DOWNREQ)); + to_dp = (struct downld_t *) (vaddr + (int) offset); + memcpy_toio(to_dp, uaddr, len); + + /* Tell card we have data for it */ + writew(0, vaddr + (DOWNREQ)); + + brd->conc_dl_status = NO_PENDING_CONCENTRATOR_REQUESTS; +} +#endif + +#define EXPANSION_ROM_SIZE (64 * 1024) +#define FEP5_ROM_MAGIC (0xFEFFFFFF) + +static void dgap_get_vpd(struct board_t *brd) +{ + u32 magic; + u32 base_offset; + u16 rom_offset; + u16 vpd_offset; + u16 image_length; + u16 i; + uchar byte1; + uchar byte2; + + /* + * Poke the magic number at the PCI Rom Address location. + * If VPD is supported, the value read from that address + * will be non-zero. + */ + magic = FEP5_ROM_MAGIC; + pci_write_config_dword(brd->pdev, PCI_ROM_ADDRESS, magic); + pci_read_config_dword(brd->pdev, PCI_ROM_ADDRESS, &magic); + + /* VPD not supported, bail */ + if (!magic) + return; + + /* + * To get to the OTPROM memory, we have to send the boards base + * address or'ed with 1 into the PCI Rom Address location. + */ + magic = brd->membase | 0x01; + pci_write_config_dword(brd->pdev, PCI_ROM_ADDRESS, magic); + pci_read_config_dword(brd->pdev, PCI_ROM_ADDRESS, &magic); + + byte1 = readb(brd->re_map_membase); + byte2 = readb(brd->re_map_membase + 1); + + /* + * If the board correctly swapped to the OTPROM memory, + * the first 2 bytes (header) should be 0x55, 0xAA + */ + if (byte1 == 0x55 && byte2 == 0xAA) { + + base_offset = 0; + + /* + * We have to run through all the OTPROM memory looking + * for the VPD offset. + */ + while (base_offset <= EXPANSION_ROM_SIZE) { + + /* + * Lots of magic numbers here. + * + * The VPD offset is located inside the ROM Data Structure. + * We also have to remember the length of each + * ROM Data Structure, so we can "hop" to the next + * entry if the VPD isn't in the current + * ROM Data Structure. + */ + rom_offset = readw(brd->re_map_membase + base_offset + 0x18); + image_length = readw(brd->re_map_membase + rom_offset + 0x10) * 512; + vpd_offset = readw(brd->re_map_membase + rom_offset + 0x08); + + /* Found the VPD entry */ + if (vpd_offset) + break; + + /* We didn't find a VPD entry, go to next ROM entry. */ + base_offset += image_length; + + byte1 = readb(brd->re_map_membase + base_offset); + byte2 = readb(brd->re_map_membase + base_offset + 1); + + /* + * If the new ROM offset doesn't have 0x55, 0xAA + * as its header, we have run out of ROM. + */ + if (byte1 != 0x55 || byte2 != 0xAA) + break; + } + + /* + * If we have a VPD offset, then mark the board + * as having a valid VPD, and copy VPDSIZE (512) bytes of + * that VPD to the buffer we have in our board structure. + */ + if (vpd_offset) { + brd->bd_flags |= BD_HAS_VPD; + for (i = 0; i < VPDSIZE; i++) + brd->vpd[i] = readb(brd->re_map_membase + vpd_offset + i); + } + } + + /* + * We MUST poke the magic number at the PCI Rom Address location again. + * This makes the card report the regular board memory back to us, + * rather than the OTPROM memory. + */ + magic = FEP5_ROM_MAGIC; + pci_write_config_dword(brd->pdev, PCI_ROM_ADDRESS, magic); +} + +/* + * Our board poller function. + */ +static void dgap_poll_tasklet(unsigned long data) +{ + struct board_t *bd = (struct board_t *) data; + ulong lock_flags; + ulong lock_flags2; + char *vaddr; + u16 head, tail; + + if (!bd || (bd->magic != DGAP_BOARD_MAGIC)) + return; + + if (bd->inhibit_poller) + return; + + DGAP_LOCK(bd->bd_lock, lock_flags); + + vaddr = bd->re_map_membase; + + /* + * If board is ready, parse deeper to see if there is anything to do. + */ + if (bd->state == BOARD_READY) { + + struct ev_t *eaddr = NULL; + + if (!bd->re_map_membase) { + DGAP_UNLOCK(bd->bd_lock, lock_flags); + return; + } + if (!bd->re_map_port) { + DGAP_UNLOCK(bd->bd_lock, lock_flags); + return; + } + + if (!bd->nasync) + goto out; + + eaddr = (struct ev_t *) (vaddr + EVBUF); + + /* Get our head and tail */ + head = readw(&(eaddr->ev_head)); + tail = readw(&(eaddr->ev_tail)); + + /* + * If there is an event pending. Go service it. + */ + if (head != tail) { + DGAP_UNLOCK(bd->bd_lock, lock_flags); + dgap_event(bd); + DGAP_LOCK(bd->bd_lock, lock_flags); + } + +out: + /* + * If board is doing interrupts, ACK the interrupt. + */ + if (bd && bd->intr_running) + readb(bd->re_map_port + 2); + + DGAP_UNLOCK(bd->bd_lock, lock_flags); + return; + } + + /* Our state machine to get the board up and running */ + + /* Reset board */ + if (bd->state == NEED_RESET) { + + /* Get VPD info */ + dgap_get_vpd(bd); + + dgap_do_reset_board(bd); + } + + /* Move to next state */ + if (bd->state == FINISHED_RESET) + bd->state = NEED_CONFIG; + + if (bd->state == NEED_CONFIG) { + /* + * Match this board to a config the user created for us. + */ + bd->bd_config = dgap_find_config(bd->type, bd->pci_bus, bd->pci_slot); + + /* + * Because the 4 port Xr products share the same PCI ID + * as the 8 port Xr products, if we receive a NULL config + * back, and this is a PAPORT8 board, retry with a + * PAPORT4 attempt as well. + */ + if (bd->type == PAPORT8 && !bd->bd_config) + bd->bd_config = dgap_find_config(PAPORT4, bd->pci_bus, bd->pci_slot); + + /* + * Register the ttys (if any) into the kernel. + */ + if (bd->bd_config) + bd->state = FINISHED_CONFIG; + else + bd->state = CONFIG_NOT_FOUND; + } + + /* Move to next state */ + if (bd->state == FINISHED_CONFIG) + bd->state = NEED_DEVICE_CREATION; + + /* Move to next state */ + if (bd->state == NEED_DEVICE_CREATION) { + /* + * Signal downloader, its got some work to do. + */ + DGAP_LOCK(dgap_dl_lock, lock_flags2); + if (dgap_dl_action != 1) { + dgap_dl_action = 1; + wake_up_interruptible(&dgap_dl_wait); + } + DGAP_UNLOCK(dgap_dl_lock, lock_flags2); + } + + /* Move to next state */ + if (bd->state == FINISHED_DEVICE_CREATION) + bd->state = NEED_BIOS_LOAD; + + /* Move to next state */ + if (bd->state == NEED_BIOS_LOAD) { + /* + * Signal downloader, its got some work to do. + */ + DGAP_LOCK(dgap_dl_lock, lock_flags2); + if (dgap_dl_action != 1) { + dgap_dl_action = 1; + wake_up_interruptible(&dgap_dl_wait); + } + DGAP_UNLOCK(dgap_dl_lock, lock_flags2); + } + + /* Wait for BIOS to test board... */ + if (bd->state == WAIT_BIOS_LOAD) + dgap_do_wait_for_bios(bd); + + /* Move to next state */ + if (bd->state == FINISHED_BIOS_LOAD) { + bd->state = NEED_FEP_LOAD; + + /* + * Signal downloader, its got some work to do. + */ + DGAP_LOCK(dgap_dl_lock, lock_flags2); + if (dgap_dl_action != 1) { + dgap_dl_action = 1; + wake_up_interruptible(&dgap_dl_wait); + } + DGAP_UNLOCK(dgap_dl_lock, lock_flags2); + } + + /* Wait for FEP to load on board... */ + if (bd->state == WAIT_FEP_LOAD) + dgap_do_wait_for_fep(bd); + + /* Move to next state */ + if (bd->state == FINISHED_FEP_LOAD) { + + /* + * Do tty device initialization. + */ + int rc = dgap_tty_init(bd); + + if (rc < 0) { + dgap_tty_uninit(bd); + bd->state = BOARD_FAILED; + bd->dpastatus = BD_NOFEP; + } else { + bd->state = NEED_PROC_CREATION; + + /* + * Signal downloader, its got some work to do. + */ + DGAP_LOCK(dgap_dl_lock, lock_flags2); + if (dgap_dl_action != 1) { + dgap_dl_action = 1; + wake_up_interruptible(&dgap_dl_wait); + } + DGAP_UNLOCK(dgap_dl_lock, lock_flags2); + } + } + + /* Move to next state */ + if (bd->state == FINISHED_PROC_CREATION) { + + bd->state = BOARD_READY; + bd->dpastatus = BD_RUNNING; + + /* + * If user requested the board to run in interrupt mode, + * go and set it up on the board. + */ + if (bd->intr_used) { + writew(1, (bd->re_map_membase + ENABLE_INTR)); + /* + * Tell the board to poll the UARTS as fast as possible. + */ + writew(FEPPOLL_MIN, (bd->re_map_membase + FEPPOLL)); + bd->intr_running = 1; + } + + /* Wake up anyone waiting for board state to change to ready */ + wake_up_interruptible(&bd->state_wait); + } + + DGAP_UNLOCK(bd->bd_lock, lock_flags); +} + +/*======================================================================= + * + * dgap_cmdb - Sends a 2 byte command to the FEP. + * + * ch - Pointer to channel structure. + * cmd - Command to be sent. + * byte1 - Integer containing first byte to be sent. + * byte2 - Integer containing second byte to be sent. + * ncmds - Wait until ncmds or fewer cmds are left + * in the cmd buffer before returning. + * + *=======================================================================*/ +static void dgap_cmdb(struct channel_t *ch, uchar cmd, uchar byte1, uchar byte2, uint ncmds) +{ + char *vaddr = NULL; + struct cm_t *cm_addr = NULL; + uint count; + uint n; + u16 head; + u16 tail; + + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return; + + /* + * Check if board is still alive. + */ + if (ch->ch_bd->state == BOARD_FAILED) + return; + + /* + * Make sure the pointers are in range before + * writing to the FEP memory. + */ + vaddr = ch->ch_bd->re_map_membase; + + if (!vaddr) + return; + + cm_addr = (struct cm_t *) (vaddr + CMDBUF); + head = readw(&(cm_addr->cm_head)); + + /* + * Forget it if pointers out of range. + */ + if (head >= (CMDMAX - CMDSTART) || (head & 03)) { + ch->ch_bd->state = BOARD_FAILED; + return; + } + + /* + * Put the data in the circular command buffer. + */ + writeb(cmd, (char *) (vaddr + head + CMDSTART + 0)); + writeb((uchar) ch->ch_portnum, (char *) (vaddr + head + CMDSTART + 1)); + writeb(byte1, (char *) (vaddr + head + CMDSTART + 2)); + writeb(byte2, (char *) (vaddr + head + CMDSTART + 3)); + + head = (head + 4) & (CMDMAX - CMDSTART - 4); + + writew(head, &(cm_addr->cm_head)); + + /* + * Wait if necessary before updating the head + * pointer to limit the number of outstanding + * commands to the FEP. If the time spent waiting + * is outlandish, declare the FEP dead. + */ + for (count = dgap_count ;;) { + + head = readw(&(cm_addr->cm_head)); + tail = readw(&(cm_addr->cm_tail)); + + n = (head - tail) & (CMDMAX - CMDSTART - 4); + + if (n <= ncmds * sizeof(struct cm_t)) + break; + + if (--count == 0) { + ch->ch_bd->state = BOARD_FAILED; + return; + } + udelay(10); + } +} + +/*======================================================================= + * + * dgap_cmdw - Sends a 1 word command to the FEP. + * + * ch - Pointer to channel structure. + * cmd - Command to be sent. + * word - Integer containing word to be sent. + * ncmds - Wait until ncmds or fewer cmds are left + * in the cmd buffer before returning. + * + *=======================================================================*/ +static void dgap_cmdw(struct channel_t *ch, uchar cmd, u16 word, uint ncmds) +{ + char *vaddr = NULL; + struct cm_t *cm_addr = NULL; + uint count; + uint n; + u16 head; + u16 tail; + + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return; + + /* + * Check if board is still alive. + */ + if (ch->ch_bd->state == BOARD_FAILED) + return; + + /* + * Make sure the pointers are in range before + * writing to the FEP memory. + */ + vaddr = ch->ch_bd->re_map_membase; + if (!vaddr) + return; + + cm_addr = (struct cm_t *) (vaddr + CMDBUF); + head = readw(&(cm_addr->cm_head)); + + /* + * Forget it if pointers out of range. + */ + if (head >= (CMDMAX - CMDSTART) || (head & 03)) { + ch->ch_bd->state = BOARD_FAILED; + return; + } + + /* + * Put the data in the circular command buffer. + */ + writeb(cmd, (char *) (vaddr + head + CMDSTART + 0)); + writeb((uchar) ch->ch_portnum, (char *) (vaddr + head + CMDSTART + 1)); + writew((u16) word, (char *) (vaddr + head + CMDSTART + 2)); + + head = (head + 4) & (CMDMAX - CMDSTART - 4); + + writew(head, &(cm_addr->cm_head)); + + /* + * Wait if necessary before updating the head + * pointer to limit the number of outstanding + * commands to the FEP. If the time spent waiting + * is outlandish, declare the FEP dead. + */ + for (count = dgap_count ;;) { + + head = readw(&(cm_addr->cm_head)); + tail = readw(&(cm_addr->cm_tail)); + + n = (head - tail) & (CMDMAX - CMDSTART - 4); + + if (n <= ncmds * sizeof(struct cm_t)) + break; + + if (--count == 0) { + ch->ch_bd->state = BOARD_FAILED; + return; + } + udelay(10); + } +} + +/*======================================================================= + * + * dgap_cmdw_ext - Sends a extended word command to the FEP. + * + * ch - Pointer to channel structure. + * cmd - Command to be sent. + * word - Integer containing word to be sent. + * ncmds - Wait until ncmds or fewer cmds are left + * in the cmd buffer before returning. + * + *=======================================================================*/ +static void dgap_cmdw_ext(struct channel_t *ch, u16 cmd, u16 word, uint ncmds) +{ + char *vaddr = NULL; + struct cm_t *cm_addr = NULL; + uint count; + uint n; + u16 head; + u16 tail; + + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return; + + /* + * Check if board is still alive. + */ + if (ch->ch_bd->state == BOARD_FAILED) + return; + + /* + * Make sure the pointers are in range before + * writing to the FEP memory. + */ + vaddr = ch->ch_bd->re_map_membase; + if (!vaddr) + return; + + cm_addr = (struct cm_t *) (vaddr + CMDBUF); + head = readw(&(cm_addr->cm_head)); + + /* + * Forget it if pointers out of range. + */ + if (head >= (CMDMAX - CMDSTART) || (head & 03)) { + ch->ch_bd->state = BOARD_FAILED; + return; + } + + /* + * Put the data in the circular command buffer. + */ + + /* Write an FF to tell the FEP that we want an extended command */ + writeb((uchar) 0xff, (char *) (vaddr + head + CMDSTART + 0)); + + writeb((uchar) ch->ch_portnum, (uchar *) (vaddr + head + CMDSTART + 1)); + writew((u16) cmd, (char *) (vaddr + head + CMDSTART + 2)); + + /* + * If the second part of the command won't fit, + * put it at the beginning of the circular buffer. + */ + if (((head + 4) >= ((CMDMAX - CMDSTART)) || (head & 03))) + writew((u16) word, (char *) (vaddr + CMDSTART)); + else + writew((u16) word, (char *) (vaddr + head + CMDSTART + 4)); + + head = (head + 8) & (CMDMAX - CMDSTART - 4); + + writew(head, &(cm_addr->cm_head)); + + /* + * Wait if necessary before updating the head + * pointer to limit the number of outstanding + * commands to the FEP. If the time spent waiting + * is outlandish, declare the FEP dead. + */ + for (count = dgap_count ;;) { + + head = readw(&(cm_addr->cm_head)); + tail = readw(&(cm_addr->cm_tail)); + + n = (head - tail) & (CMDMAX - CMDSTART - 4); + + if (n <= ncmds * sizeof(struct cm_t)) + break; + + if (--count == 0) { + ch->ch_bd->state = BOARD_FAILED; + return; + } + udelay(10); + } +} + +/*======================================================================= + * + * dgap_wmove - Write data to FEP buffer. + * + * ch - Pointer to channel structure. + * buf - Poiter to characters to be moved. + * cnt - Number of characters to move. + * + *=======================================================================*/ +static void dgap_wmove(struct channel_t *ch, char *buf, uint cnt) +{ + int n; + char *taddr; + struct bs_t *bs; + u16 head; + + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return; + + /* + * Check parameters. + */ + bs = ch->ch_bs; + head = readw(&(bs->tx_head)); + + /* + * If pointers are out of range, just return. + */ + if ((cnt > ch->ch_tsize) || + (unsigned)(head - ch->ch_tstart) >= ch->ch_tsize) + return; + + /* + * If the write wraps over the top of the circular buffer, + * move the portion up to the wrap point, and reset the + * pointers to the bottom. + */ + n = ch->ch_tstart + ch->ch_tsize - head; + + if (cnt >= n) { + cnt -= n; + taddr = ch->ch_taddr + head; + memcpy_toio(taddr, buf, n); + head = ch->ch_tstart; + buf += n; + } + + /* + * Move rest of data. + */ + taddr = ch->ch_taddr + head; + n = cnt; + memcpy_toio(taddr, buf, n); + head += cnt; + + writew(head, &(bs->tx_head)); +} + +/* + * Retrives the current custom baud rate from FEP memory, + * and returns it back to the user. + * Returns 0 on error. + */ +static uint dgap_get_custom_baud(struct channel_t *ch) +{ + uchar *vaddr; + ulong offset = 0; + uint value = 0; + + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return 0; + + if (!ch->ch_bd || ch->ch_bd->magic != DGAP_BOARD_MAGIC) + return 0; + + if (!(ch->ch_bd->bd_flags & BD_FEP5PLUS)) + return 0; + + vaddr = ch->ch_bd->re_map_membase; + + if (!vaddr) + return 0; + + /* + * Go get from fep mem, what the fep + * believes the custom baud rate is. + */ + offset = ((((*(unsigned short *)(vaddr + ECS_SEG)) << 4) + + (ch->ch_portnum * 0x28) + LINE_SPEED)); + + value = readw(vaddr + offset); + return value; +} + +/* + * Calls the firmware to reset this channel. + */ +static void dgap_firmware_reset_port(struct channel_t *ch) +{ + dgap_cmdb(ch, CHRESET, 0, 0, 0); + + /* + * Now that the channel is reset, we need to make sure + * all the current settings get reapplied to the port + * in the firmware. + * + * So we will set the driver's cache of firmware + * settings all to 0, and then call param. + */ + ch->ch_fepiflag = 0; + ch->ch_fepcflag = 0; + ch->ch_fepoflag = 0; + ch->ch_fepstartc = 0; + ch->ch_fepstopc = 0; + ch->ch_fepastartc = 0; + ch->ch_fepastopc = 0; + ch->ch_mostat = 0; + ch->ch_hflow = 0; +} + +/*======================================================================= + * + * dgap_param - Set Digi parameters. + * + * struct tty_struct * - TTY for port. + * + *=======================================================================*/ +static int dgap_param(struct tty_struct *tty) +{ + struct ktermios *ts; + struct board_t *bd; + struct channel_t *ch; + struct bs_t *bs; + struct un_t *un; + u16 head; + u16 cflag; + u16 iflag; + uchar mval; + uchar hflow; + + if (!tty || tty->magic != TTY_MAGIC) + return -ENXIO; + + un = (struct un_t *) tty->driver_data; + if (!un || un->magic != DGAP_UNIT_MAGIC) + return -ENXIO; + + ch = un->un_ch; + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return -ENXIO; + + bd = ch->ch_bd; + if (!bd || bd->magic != DGAP_BOARD_MAGIC) + return -ENXIO; + + bs = ch->ch_bs; + if (!bs) + return -ENXIO; + + ts = &tty->termios; + + /* + * If baud rate is zero, flush queues, and set mval to drop DTR. + */ + if ((ch->ch_c_cflag & (CBAUD)) == 0) { + + /* flush rx */ + head = readw(&(ch->ch_bs->rx_head)); + writew(head, &(ch->ch_bs->rx_tail)); + + /* flush tx */ + head = readw(&(ch->ch_bs->tx_head)); + writew(head, &(ch->ch_bs->tx_tail)); + + ch->ch_flags |= (CH_BAUD0); + + /* Drop RTS and DTR */ + ch->ch_mval &= ~(D_RTS(ch)|D_DTR(ch)); + mval = D_DTR(ch) | D_RTS(ch); + ch->ch_baud_info = 0; + + } else if (ch->ch_custom_speed && (bd->bd_flags & BD_FEP5PLUS)) { + /* + * Tell the fep to do the command + */ + + dgap_cmdw_ext(ch, 0xff01, ch->ch_custom_speed, 0); + + /* + * Now go get from fep mem, what the fep + * believes the custom baud rate is. + */ + ch->ch_baud_info = ch->ch_custom_speed = dgap_get_custom_baud(ch); + + /* Handle transition from B0 */ + if (ch->ch_flags & CH_BAUD0) { + ch->ch_flags &= ~(CH_BAUD0); + ch->ch_mval |= (D_RTS(ch)|D_DTR(ch)); + } + mval = D_DTR(ch) | D_RTS(ch); + + } else { + /* + * Set baud rate, character size, and parity. + */ + + + int iindex = 0; + int jindex = 0; + int baud = 0; + + ulong bauds[4][16] = { + { /* slowbaud */ + 0, 50, 75, 110, + 134, 150, 200, 300, + 600, 1200, 1800, 2400, + 4800, 9600, 19200, 38400 }, + { /* slowbaud & CBAUDEX */ + 0, 57600, 115200, 230400, + 460800, 150, 200, 921600, + 600, 1200, 1800, 2400, + 4800, 9600, 19200, 38400 }, + { /* fastbaud */ + 0, 57600, 76800, 115200, + 14400, 57600, 230400, 76800, + 115200, 230400, 28800, 460800, + 921600, 9600, 19200, 38400 }, + { /* fastbaud & CBAUDEX */ + 0, 57600, 115200, 230400, + 460800, 150, 200, 921600, + 600, 1200, 1800, 2400, + 4800, 9600, 19200, 38400 } + }; + + /* Only use the TXPrint baud rate if the terminal unit is NOT open */ + if (!(ch->ch_tun.un_flags & UN_ISOPEN) && (un->un_type == DGAP_PRINT)) + baud = C_BAUD(ch->ch_pun.un_tty) & 0xff; + else + baud = C_BAUD(ch->ch_tun.un_tty) & 0xff; + + if (ch->ch_c_cflag & CBAUDEX) + iindex = 1; + + if (ch->ch_digi.digi_flags & DIGI_FAST) + iindex += 2; + + jindex = baud; + + if ((iindex >= 0) && (iindex < 4) && + (jindex >= 0) && (jindex < 16)) + baud = bauds[iindex][jindex]; + else + baud = 0; + + if (baud == 0) + baud = 9600; + + ch->ch_baud_info = baud; + + /* + * CBAUD has bit position 0x1000 set these days to indicate Linux + * baud rate remap. + * We use a different bit assignment for high speed. Clear this + * bit out while grabbing the parts of "cflag" we want. + */ + cflag = ch->ch_c_cflag & ((CBAUD ^ CBAUDEX) | PARODD | PARENB | CSTOPB | CSIZE); + + /* + * HUPCL bit is used by FEP to indicate fast baud + * table is to be used. + */ + if ((ch->ch_digi.digi_flags & DIGI_FAST) || (ch->ch_c_cflag & CBAUDEX)) + cflag |= HUPCL; + + if ((ch->ch_c_cflag & CBAUDEX) && !(ch->ch_digi.digi_flags & DIGI_FAST)) { + /* + * The below code is trying to guarantee that only baud rates + * 115200, 230400, 460800, 921600 are remapped. We use exclusive or + * because the various baud rates share common bit positions + * and therefore can't be tested for easily. + */ + tcflag_t tcflag = (ch->ch_c_cflag & CBAUD) | CBAUDEX; + int baudpart = 0; + + /* Map high speed requests to index into FEP's baud table */ + switch (tcflag) { + case B57600: + baudpart = 1; + break; +#ifdef B76800 + case B76800: + baudpart = 2; + break; +#endif + case B115200: + baudpart = 3; + break; + case B230400: + baudpart = 9; + break; + case B460800: + baudpart = 11; + break; +#ifdef B921600 + case B921600: + baudpart = 12; + break; +#endif + default: + baudpart = 0; + } + + if (baudpart) + cflag = (cflag & ~(CBAUD | CBAUDEX)) | baudpart; + } + + cflag &= 0xffff; + + if (cflag != ch->ch_fepcflag) { + ch->ch_fepcflag = (u16) (cflag & 0xffff); + + /* Okay to have channel and board locks held calling this */ + dgap_cmdw(ch, SCFLAG, (u16) cflag, 0); + } + + /* Handle transition from B0 */ + if (ch->ch_flags & CH_BAUD0) { + ch->ch_flags &= ~(CH_BAUD0); + ch->ch_mval |= (D_RTS(ch)|D_DTR(ch)); + } + mval = D_DTR(ch) | D_RTS(ch); + } + + /* + * Get input flags. + */ + iflag = ch->ch_c_iflag & (IGNBRK | BRKINT | IGNPAR | PARMRK | INPCK | ISTRIP | IXON | IXANY | IXOFF); + + if ((ch->ch_startc == _POSIX_VDISABLE) || (ch->ch_stopc == _POSIX_VDISABLE)) { + iflag &= ~(IXON | IXOFF); + ch->ch_c_iflag &= ~(IXON | IXOFF); + } + + /* + * Only the IBM Xr card can switch between + * 232 and 422 modes on the fly + */ + if (bd->device == PCI_DEVICE_XR_IBM_DID) { + if (ch->ch_digi.digi_flags & DIGI_422) + dgap_cmdb(ch, SCOMMODE, MODE_422, 0, 0); + else + dgap_cmdb(ch, SCOMMODE, MODE_232, 0, 0); + } + + if (ch->ch_digi.digi_flags & DIGI_ALTPIN) + iflag |= IALTPIN; + + if (iflag != ch->ch_fepiflag) { + ch->ch_fepiflag = iflag; + + /* Okay to have channel and board locks held calling this */ + dgap_cmdw(ch, SIFLAG, (u16) ch->ch_fepiflag, 0); + } + + /* + * Select hardware handshaking. + */ + hflow = 0; + + if (ch->ch_c_cflag & CRTSCTS) + hflow |= (D_RTS(ch) | D_CTS(ch)); + if (ch->ch_digi.digi_flags & RTSPACE) + hflow |= D_RTS(ch); + if (ch->ch_digi.digi_flags & DTRPACE) + hflow |= D_DTR(ch); + if (ch->ch_digi.digi_flags & CTSPACE) + hflow |= D_CTS(ch); + if (ch->ch_digi.digi_flags & DSRPACE) + hflow |= D_DSR(ch); + if (ch->ch_digi.digi_flags & DCDPACE) + hflow |= D_CD(ch); + + if (hflow != ch->ch_hflow) { + ch->ch_hflow = hflow; + + /* Okay to have channel and board locks held calling this */ + dgap_cmdb(ch, SHFLOW, (uchar) hflow, 0xff, 0); + } + + + /* + * Set RTS and/or DTR Toggle if needed, but only if product is FEP5+ based. + */ + if (bd->bd_flags & BD_FEP5PLUS) { + u16 hflow2 = 0; + if (ch->ch_digi.digi_flags & DIGI_RTS_TOGGLE) + hflow2 |= (D_RTS(ch)); + if (ch->ch_digi.digi_flags & DIGI_DTR_TOGGLE) + hflow2 |= (D_DTR(ch)); + + dgap_cmdw_ext(ch, 0xff03, hflow2, 0); + } + + /* + * Set modem control lines. + */ + + mval ^= ch->ch_mforce & (mval ^ ch->ch_mval); + + if (ch->ch_mostat ^ mval) { + ch->ch_mostat = mval; + + /* Okay to have channel and board locks held calling this */ + dgap_cmdb(ch, SMODEM, (uchar) mval, D_RTS(ch)|D_DTR(ch), 0); + } + + /* + * Read modem signals, and then call carrier function. + */ + ch->ch_mistat = readb(&(bs->m_stat)); + dgap_carrier(ch); + + /* + * Set the start and stop characters. + */ + if (ch->ch_startc != ch->ch_fepstartc || ch->ch_stopc != ch->ch_fepstopc) { + ch->ch_fepstartc = ch->ch_startc; + ch->ch_fepstopc = ch->ch_stopc; + + /* Okay to have channel and board locks held calling this */ + dgap_cmdb(ch, SFLOWC, ch->ch_fepstartc, ch->ch_fepstopc, 0); + } + + /* + * Set the Auxiliary start and stop characters. + */ + if (ch->ch_astartc != ch->ch_fepastartc || ch->ch_astopc != ch->ch_fepastopc) { + ch->ch_fepastartc = ch->ch_astartc; + ch->ch_fepastopc = ch->ch_astopc; + + /* Okay to have channel and board locks held calling this */ + dgap_cmdb(ch, SAFLOWC, ch->ch_fepastartc, ch->ch_fepastopc, 0); + } + + return 0; +} + +/* + * dgap_parity_scan() + * + * Convert the FEP5 way of reporting parity errors and breaks into + * the Linux line discipline way. + */ +static void dgap_parity_scan(struct channel_t *ch, unsigned char *cbuf, unsigned char *fbuf, int *len) +{ + int l = *len; + int count = 0; + unsigned char *in, *cout, *fout; + unsigned char c; + + in = cbuf; + cout = cbuf; + fout = fbuf; + + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return; + + while (l--) { + c = *in++; + switch (ch->pscan_state) { + default: + /* reset to sanity and fall through */ + ch->pscan_state = 0; + + case 0: + /* No FF seen yet */ + if (c == (unsigned char) '\377') + /* delete this character from stream */ + ch->pscan_state = 1; + else { + *cout++ = c; + *fout++ = TTY_NORMAL; + count += 1; + } + break; + + case 1: + /* first FF seen */ + if (c == (unsigned char) '\377') { + /* doubled ff, transform to single ff */ + *cout++ = c; + *fout++ = TTY_NORMAL; + count += 1; + ch->pscan_state = 0; + } else { + /* save value examination in next state */ + ch->pscan_savechar = c; + ch->pscan_state = 2; + } + break; + + case 2: + /* third character of ff sequence */ + + *cout++ = c; + + if (ch->pscan_savechar == 0x0) { + + if (c == 0x0) { + ch->ch_err_break++; + *fout++ = TTY_BREAK; + } else { + ch->ch_err_parity++; + *fout++ = TTY_PARITY; + } + } + + count += 1; + ch->pscan_state = 0; + } + } + *len = count; +} + +/*======================================================================= + * + * dgap_event - FEP to host event processing routine. + * + * bd - Board of current event. + * + *=======================================================================*/ +static int dgap_event(struct board_t *bd) +{ + struct channel_t *ch; + ulong lock_flags; + ulong lock_flags2; + struct bs_t *bs; + uchar *event; + uchar *vaddr = NULL; + struct ev_t *eaddr = NULL; + uint head; + uint tail; + int port; + int reason; + int modem; + int b1; + + if (!bd || bd->magic != DGAP_BOARD_MAGIC) + return -ENXIO; + + DGAP_LOCK(bd->bd_lock, lock_flags); + + vaddr = bd->re_map_membase; + + if (!vaddr) { + DGAP_UNLOCK(bd->bd_lock, lock_flags); + return -ENXIO; + } + + eaddr = (struct ev_t *) (vaddr + EVBUF); + + /* Get our head and tail */ + head = readw(&(eaddr->ev_head)); + tail = readw(&(eaddr->ev_tail)); + + /* + * Forget it if pointers out of range. + */ + + if (head >= EVMAX - EVSTART || tail >= EVMAX - EVSTART || + (head | tail) & 03) { + /* Let go of board lock */ + DGAP_UNLOCK(bd->bd_lock, lock_flags); + return -ENXIO; + } + + /* + * Loop to process all the events in the buffer. + */ + while (tail != head) { + + /* + * Get interrupt information. + */ + + event = bd->re_map_membase + tail + EVSTART; + + port = event[0]; + reason = event[1]; + modem = event[2]; + b1 = event[3]; + + /* + * Make sure the interrupt is valid. + */ + if (port >= bd->nasync) + goto next; + + if (!(reason & (IFMODEM | IFBREAK | IFTLW | IFTEM | IFDATA))) + goto next; + + ch = bd->channels[port]; + + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + goto next; + + /* + * If we have made it here, the event was valid. + * Lock down the channel. + */ + DGAP_LOCK(ch->ch_lock, lock_flags2); + + bs = ch->ch_bs; + + if (!bs) { + DGAP_UNLOCK(ch->ch_lock, lock_flags2); + goto next; + } + + /* + * Process received data. + */ + if (reason & IFDATA) { + + /* + * ALL LOCKS *MUST* BE DROPPED BEFORE CALLING INPUT! + * input could send some data to ld, which in turn + * could do a callback to one of our other functions. + */ + DGAP_UNLOCK(ch->ch_lock, lock_flags2); + DGAP_UNLOCK(bd->bd_lock, lock_flags); + + dgap_input(ch); + + DGAP_LOCK(bd->bd_lock, lock_flags); + DGAP_LOCK(ch->ch_lock, lock_flags2); + + if (ch->ch_flags & CH_RACTIVE) + ch->ch_flags |= CH_RENABLE; + else + writeb(1, &(bs->idata)); + + if (ch->ch_flags & CH_RWAIT) { + ch->ch_flags &= ~CH_RWAIT; + + wake_up_interruptible(&ch->ch_tun.un_flags_wait); + } + } + + /* + * Process Modem change signals. + */ + if (reason & IFMODEM) { + ch->ch_mistat = modem; + dgap_carrier(ch); + } + + /* + * Process break. + */ + if (reason & IFBREAK) { + + if (ch->ch_tun.un_tty) { + /* A break has been indicated */ + ch->ch_err_break++; + tty_buffer_request_room(ch->ch_tun.un_tty->port, 1); + tty_insert_flip_char(ch->ch_tun.un_tty->port, 0, TTY_BREAK); + tty_flip_buffer_push(ch->ch_tun.un_tty->port); + } + } + + /* + * Process Transmit low. + */ + if (reason & IFTLW) { + + if (ch->ch_tun.un_flags & UN_LOW) { + ch->ch_tun.un_flags &= ~UN_LOW; + + if (ch->ch_tun.un_flags & UN_ISOPEN) { + if ((ch->ch_tun.un_tty->flags & + (1 << TTY_DO_WRITE_WAKEUP)) && + ch->ch_tun.un_tty->ldisc->ops->write_wakeup) { + DGAP_UNLOCK(ch->ch_lock, lock_flags2); + DGAP_UNLOCK(bd->bd_lock, lock_flags); + (ch->ch_tun.un_tty->ldisc->ops->write_wakeup)(ch->ch_tun.un_tty); + DGAP_LOCK(bd->bd_lock, lock_flags); + DGAP_LOCK(ch->ch_lock, lock_flags2); + } + wake_up_interruptible(&ch->ch_tun.un_tty->write_wait); + wake_up_interruptible(&ch->ch_tun.un_flags_wait); + } + } + + if (ch->ch_pun.un_flags & UN_LOW) { + ch->ch_pun.un_flags &= ~UN_LOW; + if (ch->ch_pun.un_flags & UN_ISOPEN) { + if ((ch->ch_pun.un_tty->flags & + (1 << TTY_DO_WRITE_WAKEUP)) && + ch->ch_pun.un_tty->ldisc->ops->write_wakeup) { + DGAP_UNLOCK(ch->ch_lock, lock_flags2); + DGAP_UNLOCK(bd->bd_lock, lock_flags); + (ch->ch_pun.un_tty->ldisc->ops->write_wakeup)(ch->ch_pun.un_tty); + DGAP_LOCK(bd->bd_lock, lock_flags); + DGAP_LOCK(ch->ch_lock, lock_flags2); + } + wake_up_interruptible(&ch->ch_pun.un_tty->write_wait); + wake_up_interruptible(&ch->ch_pun.un_flags_wait); + } + } + + if (ch->ch_flags & CH_WLOW) { + ch->ch_flags &= ~CH_WLOW; + wake_up_interruptible(&ch->ch_flags_wait); + } + } + + /* + * Process Transmit empty. + */ + if (reason & IFTEM) { + if (ch->ch_tun.un_flags & UN_EMPTY) { + ch->ch_tun.un_flags &= ~UN_EMPTY; + if (ch->ch_tun.un_flags & UN_ISOPEN) { + if ((ch->ch_tun.un_tty->flags & + (1 << TTY_DO_WRITE_WAKEUP)) && + ch->ch_tun.un_tty->ldisc->ops->write_wakeup) { + DGAP_UNLOCK(ch->ch_lock, lock_flags2); + DGAP_UNLOCK(bd->bd_lock, lock_flags); + + (ch->ch_tun.un_tty->ldisc->ops->write_wakeup)(ch->ch_tun.un_tty); + DGAP_LOCK(bd->bd_lock, lock_flags); + DGAP_LOCK(ch->ch_lock, lock_flags2); + } + wake_up_interruptible(&ch->ch_tun.un_tty->write_wait); + wake_up_interruptible(&ch->ch_tun.un_flags_wait); + } + } + + if (ch->ch_pun.un_flags & UN_EMPTY) { + ch->ch_pun.un_flags &= ~UN_EMPTY; + if (ch->ch_pun.un_flags & UN_ISOPEN) { + if ((ch->ch_pun.un_tty->flags & + (1 << TTY_DO_WRITE_WAKEUP)) && + ch->ch_pun.un_tty->ldisc->ops->write_wakeup) { + DGAP_UNLOCK(ch->ch_lock, lock_flags2); + DGAP_UNLOCK(bd->bd_lock, lock_flags); + (ch->ch_pun.un_tty->ldisc->ops->write_wakeup)(ch->ch_pun.un_tty); + DGAP_LOCK(bd->bd_lock, lock_flags); + DGAP_LOCK(ch->ch_lock, lock_flags2); + } + wake_up_interruptible(&ch->ch_pun.un_tty->write_wait); + wake_up_interruptible(&ch->ch_pun.un_flags_wait); + } + } + + + if (ch->ch_flags & CH_WEMPTY) { + ch->ch_flags &= ~CH_WEMPTY; + wake_up_interruptible(&ch->ch_flags_wait); + } + } + + DGAP_UNLOCK(ch->ch_lock, lock_flags2); + +next: + tail = (tail + 4) & (EVMAX - EVSTART - 4); + } + + writew(tail, &(eaddr->ev_tail)); + DGAP_UNLOCK(bd->bd_lock, lock_flags); + + return 0; +} + +static ssize_t dgap_driver_version_show(struct device_driver *ddp, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%s\n", DG_PART); +} +static DRIVER_ATTR(version, S_IRUSR, dgap_driver_version_show, NULL); + + +static ssize_t dgap_driver_boards_show(struct device_driver *ddp, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", dgap_NumBoards); +} +static DRIVER_ATTR(boards, S_IRUSR, dgap_driver_boards_show, NULL); + + +static ssize_t dgap_driver_maxboards_show(struct device_driver *ddp, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", MAXBOARDS); +} +static DRIVER_ATTR(maxboards, S_IRUSR, dgap_driver_maxboards_show, NULL); + + +static ssize_t dgap_driver_pollcounter_show(struct device_driver *ddp, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%ld\n", dgap_poll_counter); +} +static DRIVER_ATTR(pollcounter, S_IRUSR, dgap_driver_pollcounter_show, NULL); + + +static ssize_t dgap_driver_state_show(struct device_driver *ddp, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%s\n", dgap_driver_state_text[dgap_driver_state]); +} +static DRIVER_ATTR(state, S_IRUSR, dgap_driver_state_show, NULL); + +static ssize_t dgap_driver_rawreadok_show(struct device_driver *ddp, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "0x%x\n", dgap_rawreadok); +} + +static ssize_t dgap_driver_rawreadok_store(struct device_driver *ddp, const char *buf, size_t count) +{ + sscanf(buf, "0x%x\n", &dgap_rawreadok); + return count; +} +static DRIVER_ATTR(rawreadok, (S_IRUSR | S_IWUSR), dgap_driver_rawreadok_show, dgap_driver_rawreadok_store); + + +static ssize_t dgap_driver_pollrate_show(struct device_driver *ddp, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%dms\n", dgap_poll_tick); +} + +static ssize_t dgap_driver_pollrate_store(struct device_driver *ddp, const char *buf, size_t count) +{ + sscanf(buf, "%d\n", &dgap_poll_tick); + return count; +} +static DRIVER_ATTR(pollrate, (S_IRUSR | S_IWUSR), dgap_driver_pollrate_show, dgap_driver_pollrate_store); + +static void dgap_create_driver_sysfiles(struct pci_driver *dgap_driver) +{ + int rc = 0; + struct device_driver *driverfs = &dgap_driver->driver; + + rc |= driver_create_file(driverfs, &driver_attr_version); + rc |= driver_create_file(driverfs, &driver_attr_boards); + rc |= driver_create_file(driverfs, &driver_attr_maxboards); + rc |= driver_create_file(driverfs, &driver_attr_rawreadok); + rc |= driver_create_file(driverfs, &driver_attr_pollrate); + rc |= driver_create_file(driverfs, &driver_attr_pollcounter); + rc |= driver_create_file(driverfs, &driver_attr_state); + if (rc) + printk(KERN_ERR "DGAP: sysfs driver_create_file failed!\n"); +} + +static void dgap_remove_driver_sysfiles(struct pci_driver *dgap_driver) +{ + struct device_driver *driverfs = &dgap_driver->driver; + driver_remove_file(driverfs, &driver_attr_version); + driver_remove_file(driverfs, &driver_attr_boards); + driver_remove_file(driverfs, &driver_attr_maxboards); + driver_remove_file(driverfs, &driver_attr_rawreadok); + driver_remove_file(driverfs, &driver_attr_pollrate); + driver_remove_file(driverfs, &driver_attr_pollcounter); + driver_remove_file(driverfs, &driver_attr_state); +} + +#define DGAP_VERIFY_BOARD(p, bd) \ + if (!p) \ + return 0; \ + \ + bd = dev_get_drvdata(p); \ + if (!bd || bd->magic != DGAP_BOARD_MAGIC) \ + return 0; \ + if (bd->state != BOARD_READY) \ + return 0; \ + +static ssize_t dgap_ports_state_show(struct device *p, struct device_attribute *attr, char *buf) +{ + struct board_t *bd; + int count = 0; + int i = 0; + + DGAP_VERIFY_BOARD(p, bd); + + for (i = 0; i < bd->nasync; i++) { + count += snprintf(buf + count, PAGE_SIZE - count, + "%d %s\n", bd->channels[i]->ch_portnum, + bd->channels[i]->ch_open_count ? "Open" : "Closed"); + } + return count; +} +static DEVICE_ATTR(ports_state, S_IRUSR, dgap_ports_state_show, NULL); + +static ssize_t dgap_ports_baud_show(struct device *p, struct device_attribute *attr, char *buf) +{ + struct board_t *bd; + int count = 0; + int i = 0; + + DGAP_VERIFY_BOARD(p, bd); + + for (i = 0; i < bd->nasync; i++) { + count += snprintf(buf + count, PAGE_SIZE - count, + "%d %d\n", bd->channels[i]->ch_portnum, bd->channels[i]->ch_baud_info); + } + return count; +} +static DEVICE_ATTR(ports_baud, S_IRUSR, dgap_ports_baud_show, NULL); + +static ssize_t dgap_ports_msignals_show(struct device *p, struct device_attribute *attr, char *buf) +{ + struct board_t *bd; + int count = 0; + int i = 0; + + DGAP_VERIFY_BOARD(p, bd); + + for (i = 0; i < bd->nasync; i++) { + if (bd->channels[i]->ch_open_count) + count += snprintf(buf + count, PAGE_SIZE - count, + "%d %s %s %s %s %s %s\n", bd->channels[i]->ch_portnum, + (bd->channels[i]->ch_mostat & UART_MCR_RTS) ? "RTS" : "", + (bd->channels[i]->ch_mistat & UART_MSR_CTS) ? "CTS" : "", + (bd->channels[i]->ch_mostat & UART_MCR_DTR) ? "DTR" : "", + (bd->channels[i]->ch_mistat & UART_MSR_DSR) ? "DSR" : "", + (bd->channels[i]->ch_mistat & UART_MSR_DCD) ? "DCD" : "", + (bd->channels[i]->ch_mistat & UART_MSR_RI) ? "RI" : ""); + else + count += snprintf(buf + count, PAGE_SIZE - count, + "%d\n", bd->channels[i]->ch_portnum); + } + return count; +} +static DEVICE_ATTR(ports_msignals, S_IRUSR, dgap_ports_msignals_show, NULL); + +static ssize_t dgap_ports_iflag_show(struct device *p, struct device_attribute *attr, char *buf) +{ + struct board_t *bd; + int count = 0; + int i = 0; + + DGAP_VERIFY_BOARD(p, bd); + + for (i = 0; i < bd->nasync; i++) + count += snprintf(buf + count, PAGE_SIZE - count, "%d %x\n", + bd->channels[i]->ch_portnum, bd->channels[i]->ch_c_iflag); + return count; +} +static DEVICE_ATTR(ports_iflag, S_IRUSR, dgap_ports_iflag_show, NULL); + +static ssize_t dgap_ports_cflag_show(struct device *p, struct device_attribute *attr, char *buf) +{ + struct board_t *bd; + int count = 0; + int i = 0; + + DGAP_VERIFY_BOARD(p, bd); + + for (i = 0; i < bd->nasync; i++) + count += snprintf(buf + count, PAGE_SIZE - count, "%d %x\n", + bd->channels[i]->ch_portnum, bd->channels[i]->ch_c_cflag); + return count; +} +static DEVICE_ATTR(ports_cflag, S_IRUSR, dgap_ports_cflag_show, NULL); + +static ssize_t dgap_ports_oflag_show(struct device *p, struct device_attribute *attr, char *buf) +{ + struct board_t *bd; + int count = 0; + int i = 0; + + DGAP_VERIFY_BOARD(p, bd); + + for (i = 0; i < bd->nasync; i++) + count += snprintf(buf + count, PAGE_SIZE - count, "%d %x\n", + bd->channels[i]->ch_portnum, bd->channels[i]->ch_c_oflag); + return count; +} +static DEVICE_ATTR(ports_oflag, S_IRUSR, dgap_ports_oflag_show, NULL); + +static ssize_t dgap_ports_lflag_show(struct device *p, struct device_attribute *attr, char *buf) +{ + struct board_t *bd; + int count = 0; + int i = 0; + + DGAP_VERIFY_BOARD(p, bd); + + for (i = 0; i < bd->nasync; i++) + count += snprintf(buf + count, PAGE_SIZE - count, "%d %x\n", + bd->channels[i]->ch_portnum, bd->channels[i]->ch_c_lflag); + return count; +} +static DEVICE_ATTR(ports_lflag, S_IRUSR, dgap_ports_lflag_show, NULL); + +static ssize_t dgap_ports_digi_flag_show(struct device *p, struct device_attribute *attr, char *buf) +{ + struct board_t *bd; + int count = 0; + int i = 0; + + DGAP_VERIFY_BOARD(p, bd); + + for (i = 0; i < bd->nasync; i++) + count += snprintf(buf + count, PAGE_SIZE - count, "%d %x\n", + bd->channels[i]->ch_portnum, bd->channels[i]->ch_digi.digi_flags); + return count; +} +static DEVICE_ATTR(ports_digi_flag, S_IRUSR, dgap_ports_digi_flag_show, NULL); + +static ssize_t dgap_ports_rxcount_show(struct device *p, struct device_attribute *attr, char *buf) +{ + struct board_t *bd; + int count = 0; + int i = 0; + + DGAP_VERIFY_BOARD(p, bd); + + for (i = 0; i < bd->nasync; i++) + count += snprintf(buf + count, PAGE_SIZE - count, "%d %ld\n", + bd->channels[i]->ch_portnum, bd->channels[i]->ch_rxcount); + return count; +} +static DEVICE_ATTR(ports_rxcount, S_IRUSR, dgap_ports_rxcount_show, NULL); + +static ssize_t dgap_ports_txcount_show(struct device *p, struct device_attribute *attr, char *buf) +{ + struct board_t *bd; + int count = 0; + int i = 0; + + DGAP_VERIFY_BOARD(p, bd); + + for (i = 0; i < bd->nasync; i++) + count += snprintf(buf + count, PAGE_SIZE - count, "%d %ld\n", + bd->channels[i]->ch_portnum, bd->channels[i]->ch_txcount); + return count; +} +static DEVICE_ATTR(ports_txcount, S_IRUSR, dgap_ports_txcount_show, NULL); + +/* this function creates the sys files that will export each signal status + * to sysfs each value will be put in a separate filename + */ +static void dgap_create_ports_sysfiles(struct board_t *bd) +{ + int rc = 0; + + dev_set_drvdata(&bd->pdev->dev, bd); + rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_state); + rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_baud); + rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_msignals); + rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_iflag); + rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_cflag); + rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_oflag); + rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_lflag); + rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_digi_flag); + rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_rxcount); + rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_txcount); + if (rc) + printk(KERN_ERR "DGAP: sysfs device_create_file failed!\n"); +} + +/* removes all the sys files created for that port */ +static void dgap_remove_ports_sysfiles(struct board_t *bd) +{ + device_remove_file(&(bd->pdev->dev), &dev_attr_ports_state); + device_remove_file(&(bd->pdev->dev), &dev_attr_ports_baud); + device_remove_file(&(bd->pdev->dev), &dev_attr_ports_msignals); + device_remove_file(&(bd->pdev->dev), &dev_attr_ports_iflag); + device_remove_file(&(bd->pdev->dev), &dev_attr_ports_cflag); + device_remove_file(&(bd->pdev->dev), &dev_attr_ports_oflag); + device_remove_file(&(bd->pdev->dev), &dev_attr_ports_lflag); + device_remove_file(&(bd->pdev->dev), &dev_attr_ports_digi_flag); + device_remove_file(&(bd->pdev->dev), &dev_attr_ports_rxcount); + device_remove_file(&(bd->pdev->dev), &dev_attr_ports_txcount); +} + +static ssize_t dgap_tty_state_show(struct device *d, struct device_attribute *attr, char *buf) +{ + struct board_t *bd; + struct channel_t *ch; + struct un_t *un; + + if (!d) + return 0; + un = dev_get_drvdata(d); + if (!un || un->magic != DGAP_UNIT_MAGIC) + return 0; + ch = un->un_ch; + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return 0; + bd = ch->ch_bd; + if (!bd || bd->magic != DGAP_BOARD_MAGIC) + return 0; + if (bd->state != BOARD_READY) + return 0; + + return snprintf(buf, PAGE_SIZE, "%s", un->un_open_count ? "Open" : "Closed"); +} +static DEVICE_ATTR(state, S_IRUSR, dgap_tty_state_show, NULL); + +static ssize_t dgap_tty_baud_show(struct device *d, struct device_attribute *attr, char *buf) +{ + struct board_t *bd; + struct channel_t *ch; + struct un_t *un; + + if (!d) + return 0; + un = dev_get_drvdata(d); + if (!un || un->magic != DGAP_UNIT_MAGIC) + return 0; + ch = un->un_ch; + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return 0; + bd = ch->ch_bd; + if (!bd || bd->magic != DGAP_BOARD_MAGIC) + return 0; + if (bd->state != BOARD_READY) + return 0; + + return snprintf(buf, PAGE_SIZE, "%d\n", ch->ch_baud_info); +} +static DEVICE_ATTR(baud, S_IRUSR, dgap_tty_baud_show, NULL); + +static ssize_t dgap_tty_msignals_show(struct device *d, struct device_attribute *attr, char *buf) +{ + struct board_t *bd; + struct channel_t *ch; + struct un_t *un; + + if (!d) + return 0; + un = dev_get_drvdata(d); + if (!un || un->magic != DGAP_UNIT_MAGIC) + return 0; + ch = un->un_ch; + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return 0; + bd = ch->ch_bd; + if (!bd || bd->magic != DGAP_BOARD_MAGIC) + return 0; + if (bd->state != BOARD_READY) + return 0; + + if (ch->ch_open_count) { + return snprintf(buf, PAGE_SIZE, "%s %s %s %s %s %s\n", + (ch->ch_mostat & UART_MCR_RTS) ? "RTS" : "", + (ch->ch_mistat & UART_MSR_CTS) ? "CTS" : "", + (ch->ch_mostat & UART_MCR_DTR) ? "DTR" : "", + (ch->ch_mistat & UART_MSR_DSR) ? "DSR" : "", + (ch->ch_mistat & UART_MSR_DCD) ? "DCD" : "", + (ch->ch_mistat & UART_MSR_RI) ? "RI" : ""); + } + return 0; +} +static DEVICE_ATTR(msignals, S_IRUSR, dgap_tty_msignals_show, NULL); + +static ssize_t dgap_tty_iflag_show(struct device *d, struct device_attribute *attr, char *buf) +{ + struct board_t *bd; + struct channel_t *ch; + struct un_t *un; + + if (!d) + return 0; + un = dev_get_drvdata(d); + if (!un || un->magic != DGAP_UNIT_MAGIC) + return 0; + ch = un->un_ch; + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return 0; + bd = ch->ch_bd; + if (!bd || bd->magic != DGAP_BOARD_MAGIC) + return 0; + if (bd->state != BOARD_READY) + return 0; + + return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_c_iflag); +} +static DEVICE_ATTR(iflag, S_IRUSR, dgap_tty_iflag_show, NULL); + +static ssize_t dgap_tty_cflag_show(struct device *d, struct device_attribute *attr, char *buf) +{ + struct board_t *bd; + struct channel_t *ch; + struct un_t *un; + + if (!d) + return 0; + un = dev_get_drvdata(d); + if (!un || un->magic != DGAP_UNIT_MAGIC) + return 0; + ch = un->un_ch; + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return 0; + bd = ch->ch_bd; + if (!bd || bd->magic != DGAP_BOARD_MAGIC) + return 0; + if (bd->state != BOARD_READY) + return 0; + + return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_c_cflag); +} +static DEVICE_ATTR(cflag, S_IRUSR, dgap_tty_cflag_show, NULL); + +static ssize_t dgap_tty_oflag_show(struct device *d, struct device_attribute *attr, char *buf) +{ + struct board_t *bd; + struct channel_t *ch; + struct un_t *un; + + if (!d) + return 0; + un = dev_get_drvdata(d); + if (!un || un->magic != DGAP_UNIT_MAGIC) + return 0; + ch = un->un_ch; + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return 0; + bd = ch->ch_bd; + if (!bd || bd->magic != DGAP_BOARD_MAGIC) + return 0; + if (bd->state != BOARD_READY) + return 0; + + return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_c_oflag); +} +static DEVICE_ATTR(oflag, S_IRUSR, dgap_tty_oflag_show, NULL); + +static ssize_t dgap_tty_lflag_show(struct device *d, struct device_attribute *attr, char *buf) +{ + struct board_t *bd; + struct channel_t *ch; + struct un_t *un; + + if (!d) + return 0; + un = dev_get_drvdata(d); + if (!un || un->magic != DGAP_UNIT_MAGIC) + return 0; + ch = un->un_ch; + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return 0; + bd = ch->ch_bd; + if (!bd || bd->magic != DGAP_BOARD_MAGIC) + return 0; + if (bd->state != BOARD_READY) + return 0; + + return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_c_lflag); +} +static DEVICE_ATTR(lflag, S_IRUSR, dgap_tty_lflag_show, NULL); + +static ssize_t dgap_tty_digi_flag_show(struct device *d, struct device_attribute *attr, char *buf) +{ + struct board_t *bd; + struct channel_t *ch; + struct un_t *un; + + if (!d) + return 0; + un = dev_get_drvdata(d); + if (!un || un->magic != DGAP_UNIT_MAGIC) + return 0; + ch = un->un_ch; + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return 0; + bd = ch->ch_bd; + if (!bd || bd->magic != DGAP_BOARD_MAGIC) + return 0; + if (bd->state != BOARD_READY) + return 0; + + return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_digi.digi_flags); +} +static DEVICE_ATTR(digi_flag, S_IRUSR, dgap_tty_digi_flag_show, NULL); + +static ssize_t dgap_tty_rxcount_show(struct device *d, struct device_attribute *attr, char *buf) +{ + struct board_t *bd; + struct channel_t *ch; + struct un_t *un; + + if (!d) + return 0; + un = dev_get_drvdata(d); + if (!un || un->magic != DGAP_UNIT_MAGIC) + return 0; + ch = un->un_ch; + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return 0; + bd = ch->ch_bd; + if (!bd || bd->magic != DGAP_BOARD_MAGIC) + return 0; + if (bd->state != BOARD_READY) + return 0; + + return snprintf(buf, PAGE_SIZE, "%ld\n", ch->ch_rxcount); +} +static DEVICE_ATTR(rxcount, S_IRUSR, dgap_tty_rxcount_show, NULL); + +static ssize_t dgap_tty_txcount_show(struct device *d, struct device_attribute *attr, char *buf) +{ + struct board_t *bd; + struct channel_t *ch; + struct un_t *un; + + if (!d) + return 0; + un = dev_get_drvdata(d); + if (!un || un->magic != DGAP_UNIT_MAGIC) + return 0; + ch = un->un_ch; + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return 0; + bd = ch->ch_bd; + if (!bd || bd->magic != DGAP_BOARD_MAGIC) + return 0; + if (bd->state != BOARD_READY) + return 0; + + return snprintf(buf, PAGE_SIZE, "%ld\n", ch->ch_txcount); +} +static DEVICE_ATTR(txcount, S_IRUSR, dgap_tty_txcount_show, NULL); + +static ssize_t dgap_tty_name_show(struct device *d, struct device_attribute *attr, char *buf) +{ + struct board_t *bd; + struct channel_t *ch; + struct un_t *un; + int cn; + int bn; + struct cnode *cptr = NULL; + int found = FALSE; + int ncount = 0; + int starto = 0; + int i = 0; + + if (!d) + return 0; + un = dev_get_drvdata(d); + if (!un || un->magic != DGAP_UNIT_MAGIC) + return 0; + ch = un->un_ch; + if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) + return 0; + bd = ch->ch_bd; + if (!bd || bd->magic != DGAP_BOARD_MAGIC) + return 0; + if (bd->state != BOARD_READY) + return 0; + + bn = bd->boardnum; + cn = ch->ch_portnum; + + for (cptr = bd->bd_config; cptr; cptr = cptr->next) { + + if ((cptr->type == BNODE) && + ((cptr->u.board.type == APORT2_920P) || (cptr->u.board.type == APORT4_920P) || + (cptr->u.board.type == APORT8_920P) || (cptr->u.board.type == PAPORT4) || + (cptr->u.board.type == PAPORT8))) { + + found = TRUE; + if (cptr->u.board.v_start) + starto = cptr->u.board.start; + else + starto = 1; + } + + if (cptr->type == TNODE && found == TRUE) { + char *ptr1; + if (strstr(cptr->u.ttyname, "tty")) { + ptr1 = cptr->u.ttyname; + ptr1 += 3; + } else + ptr1 = cptr->u.ttyname; + + for (i = 0; i < dgap_config_get_number_of_ports(bd); i++) { + if (cn == i) + return snprintf(buf, PAGE_SIZE, "%s%s%02d\n", + (un->un_type == DGAP_PRINT) ? "pr" : "tty", + ptr1, i + starto); + } + } + + if (cptr->type == CNODE) { + + for (i = 0; i < cptr->u.conc.nport; i++) { + if (cn == (i + ncount)) + + return snprintf(buf, PAGE_SIZE, "%s%s%02d\n", + (un->un_type == DGAP_PRINT) ? "pr" : "tty", + cptr->u.conc.id, + i + (cptr->u.conc.v_start ? cptr->u.conc.start : 1)); + } + + ncount += cptr->u.conc.nport; + } + + if (cptr->type == MNODE) { + + for (i = 0; i < cptr->u.module.nport; i++) { + if (cn == (i + ncount)) + return snprintf(buf, PAGE_SIZE, "%s%s%02d\n", + (un->un_type == DGAP_PRINT) ? "pr" : "tty", + cptr->u.module.id, + i + (cptr->u.module.v_start ? cptr->u.module.start : 1)); + } + + ncount += cptr->u.module.nport; + + } + } + + return snprintf(buf, PAGE_SIZE, "%s_dgap_%d_%d\n", + (un->un_type == DGAP_PRINT) ? "pr" : "tty", bn, cn); + +} +static DEVICE_ATTR(custom_name, S_IRUSR, dgap_tty_name_show, NULL); + +static struct attribute *dgap_sysfs_tty_entries[] = { + &dev_attr_state.attr, + &dev_attr_baud.attr, + &dev_attr_msignals.attr, + &dev_attr_iflag.attr, + &dev_attr_cflag.attr, + &dev_attr_oflag.attr, + &dev_attr_lflag.attr, + &dev_attr_digi_flag.attr, + &dev_attr_rxcount.attr, + &dev_attr_txcount.attr, + &dev_attr_custom_name.attr, + NULL +}; + +static struct attribute_group dgap_tty_attribute_group = { + .name = NULL, + .attrs = dgap_sysfs_tty_entries, +}; + +static void dgap_create_tty_sysfs(struct un_t *un, struct device *c) +{ + int ret; + + ret = sysfs_create_group(&c->kobj, &dgap_tty_attribute_group); + if (ret) { + printk(KERN_ERR "dgap: failed to create sysfs tty device attributes.\n"); + sysfs_remove_group(&c->kobj, &dgap_tty_attribute_group); + return; + } + + dev_set_drvdata(c, un); + +} + +static void dgap_remove_tty_sysfs(struct device *c) +{ + sysfs_remove_group(&c->kobj, &dgap_tty_attribute_group); +} + +/* + * Parse a configuration file read into memory as a string. + */ +static int dgap_parsefile(char **in, int Remove) +{ + struct cnode *p, *brd, *line, *conc; + int rc; + char *s = NULL, *s2 = NULL; + int linecnt = 0; + + p = &dgap_head; + brd = line = conc = NULL; + + /* perhaps we are adding to an existing list? */ + while (p->next != NULL) + p = p->next; + + /* file must start with a BEGIN */ + while ((rc = dgap_gettok(in, p)) != BEGIN) { + if (rc == 0) { + dgap_err("unexpected EOF"); + return -1; + } + } + + for (; ;) { + rc = dgap_gettok(in, p); + if (rc == 0) { + dgap_err("unexpected EOF"); + return -1; + } + + switch (rc) { + case 0: + dgap_err("unexpected end of file"); + return -1; + + case BEGIN: /* should only be 1 begin */ + dgap_err("unexpected config_begin\n"); + return -1; + + case END: + return 0; + + case BOARD: /* board info */ + if (dgap_checknode(p)) + return -1; + p->next = dgap_newnode(BNODE); + if (!p->next) { + dgap_err("out of memory"); + return -1; + } + p = p->next; + + p->u.board.status = dgap_savestring("No"); + line = conc = NULL; + brd = p; + linecnt = -1; + break; + + case APORT2_920P: /* AccelePort_4 */ + if (p->type != BNODE) { + dgap_err("unexpected Digi_2r_920 string"); + return -1; + } + p->u.board.type = APORT2_920P; + p->u.board.v_type = 1; + break; + + case APORT4_920P: /* AccelePort_4 */ + if (p->type != BNODE) { + dgap_err("unexpected Digi_4r_920 string"); + return -1; + } + p->u.board.type = APORT4_920P; + p->u.board.v_type = 1; + break; + + case APORT8_920P: /* AccelePort_8 */ + if (p->type != BNODE) { + dgap_err("unexpected Digi_8r_920 string"); + return -1; + } + p->u.board.type = APORT8_920P; + p->u.board.v_type = 1; + break; + + case PAPORT4: /* AccelePort_4 PCI */ + if (p->type != BNODE) { + dgap_err("unexpected Digi_4r(PCI) string"); + return -1; + } + p->u.board.type = PAPORT4; + p->u.board.v_type = 1; + break; + + case PAPORT8: /* AccelePort_8 PCI */ + if (p->type != BNODE) { + dgap_err("unexpected Digi_8r string"); + return -1; + } + p->u.board.type = PAPORT8; + p->u.board.v_type = 1; + break; + + case PCX: /* PCI C/X */ + if (p->type != BNODE) { + dgap_err("unexpected Digi_C/X_(PCI) string"); + return -1; + } + p->u.board.type = PCX; + p->u.board.v_type = 1; + p->u.board.conc1 = 0; + p->u.board.conc2 = 0; + p->u.board.module1 = 0; + p->u.board.module2 = 0; + break; + + case PEPC: /* PCI EPC/X */ + if (p->type != BNODE) { + dgap_err("unexpected \"Digi_EPC/X_(PCI)\" string"); + return -1; + } + p->u.board.type = PEPC; + p->u.board.v_type = 1; + p->u.board.conc1 = 0; + p->u.board.conc2 = 0; + p->u.board.module1 = 0; + p->u.board.module2 = 0; + break; + + case PPCM: /* PCI/Xem */ + if (p->type != BNODE) { + dgap_err("unexpected PCI/Xem string"); + return -1; + } + p->u.board.type = PPCM; + p->u.board.v_type = 1; + p->u.board.conc1 = 0; + p->u.board.conc2 = 0; + break; + + case IO: /* i/o port */ + if (p->type != BNODE) { + dgap_err("IO port only vaild for boards"); + return -1; + } + s = dgap_getword(in); + if (s == NULL) { + dgap_err("unexpected end of file"); + return -1; + } + p->u.board.portstr = dgap_savestring(s); + p->u.board.port = (short)simple_strtol(s, &s2, 0); + if ((short)strlen(s) > (short)(s2 - s)) { + dgap_err("bad number for IO port"); + return -1; + } + p->u.board.v_port = 1; + break; + + case MEM: /* memory address */ + if (p->type != BNODE) { + dgap_err("memory address only vaild for boards"); + return -1; + } + s = dgap_getword(in); + if (s == NULL) { + dgap_err("unexpected end of file"); + return -1; + } + p->u.board.addrstr = dgap_savestring(s); + p->u.board.addr = simple_strtoul(s, &s2, 0); + if ((int)strlen(s) > (int)(s2 - s)) { + dgap_err("bad number for memory address"); + return -1; + } + p->u.board.v_addr = 1; + break; + + case PCIINFO: /* pci information */ + if (p->type != BNODE) { + dgap_err("memory address only vaild for boards"); + return -1; + } + s = dgap_getword(in); + if (s == NULL) { + dgap_err("unexpected end of file"); + return -1; + } + p->u.board.pcibusstr = dgap_savestring(s); + p->u.board.pcibus = simple_strtoul(s, &s2, 0); + if ((int)strlen(s) > (int)(s2 - s)) { + dgap_err("bad number for pci bus"); + return -1; + } + p->u.board.v_pcibus = 1; + s = dgap_getword(in); + if (s == NULL) { + dgap_err("unexpected end of file"); + return -1; + } + p->u.board.pcislotstr = dgap_savestring(s); + p->u.board.pcislot = simple_strtoul(s, &s2, 0); + if ((int)strlen(s) > (int)(s2 - s)) { + dgap_err("bad number for pci slot"); + return -1; + } + p->u.board.v_pcislot = 1; + break; + + case METHOD: + if (p->type != BNODE) { + dgap_err("install method only vaild for boards"); + return -1; + } + s = dgap_getword(in); + if (s == NULL) { + dgap_err("unexpected end of file"); + return -1; + } + p->u.board.method = dgap_savestring(s); + p->u.board.v_method = 1; + break; + + case STATUS: + if (p->type != BNODE) { + dgap_err("config status only vaild for boards"); + return -1; + } + s = dgap_getword(in); + if (s == NULL) { + dgap_err("unexpected end of file"); + return -1; + } + p->u.board.status = dgap_savestring(s); + break; + + case NPORTS: /* number of ports */ + if (p->type == BNODE) { + s = dgap_getword(in); + if (s == NULL) { + dgap_err("unexpected end of file"); + return -1; + } + p->u.board.nport = (char)simple_strtol(s, &s2, 0); + if ((int)strlen(s) > (int)(s2 - s)) { + dgap_err("bad number for number of ports"); + return -1; + } + p->u.board.v_nport = 1; + } else if (p->type == CNODE) { + s = dgap_getword(in); + if (s == NULL) { + dgap_err("unexpected end of file"); + return -1; + } + p->u.conc.nport = (char)simple_strtol(s, &s2, 0); + if ((int)strlen(s) > (int)(s2 - s)) { + dgap_err("bad number for number of ports"); + return -1; + } + p->u.conc.v_nport = 1; + } else if (p->type == MNODE) { + s = dgap_getword(in); + if (s == NULL) { + dgap_err("unexpected end of file"); + return -1; + } + p->u.module.nport = (char)simple_strtol(s, &s2, 0); + if ((int)strlen(s) > (int)(s2 - s)) { + dgap_err("bad number for number of ports"); + return -1; + } + p->u.module.v_nport = 1; + } else { + dgap_err("nports only valid for concentrators or modules"); + return -1; + } + break; + + case ID: /* letter ID used in tty name */ + s = dgap_getword(in); + if (s == NULL) { + dgap_err("unexpected end of file"); + return -1; + } + + p->u.board.status = dgap_savestring(s); + + if (p->type == CNODE) { + p->u.conc.id = dgap_savestring(s); + p->u.conc.v_id = 1; + } else if (p->type == MNODE) { + p->u.module.id = dgap_savestring(s); + p->u.module.v_id = 1; + } else { + dgap_err("id only valid for concentrators or modules"); + return -1; + } + break; + + case STARTO: /* start offset of ID */ + if (p->type == BNODE) { + s = dgap_getword(in); + if (s == NULL) { + dgap_err("unexpected end of file"); + return -1; + } + p->u.board.start = simple_strtol(s, &s2, 0); + if ((int)strlen(s) > (int)(s2 - s)) { + dgap_err("bad number for start of tty count"); + return -1; + } + p->u.board.v_start = 1; + } else if (p->type == CNODE) { + s = dgap_getword(in); + if (s == NULL) { + dgap_err("unexpected end of file"); + return -1; + } + p->u.conc.start = simple_strtol(s, &s2, 0); + if ((int)strlen(s) > (int)(s2 - s)) { + dgap_err("bad number for start of tty count"); + return -1; + } + p->u.conc.v_start = 1; + } else if (p->type == MNODE) { + s = dgap_getword(in); + if (s == NULL) { + dgap_err("unexpected end of file"); + return -1; + } + p->u.module.start = simple_strtol(s, &s2, 0); + if ((int)strlen(s) > (int)(s2 - s)) { + dgap_err("bad number for start of tty count"); + return -1; + } + p->u.module.v_start = 1; + } else { + dgap_err("start only valid for concentrators or modules"); + return -1; + } + break; + + case TTYN: /* tty name prefix */ + if (dgap_checknode(p)) + return -1; + p->next = dgap_newnode(TNODE); + if (!p->next) { + dgap_err("out of memory"); + return -1; + } + p = p->next; + s = dgap_getword(in); + if (!s) { + dgap_err("unexpeced end of file"); + return -1; + } + p->u.ttyname = dgap_savestring(s); + if (!p->u.ttyname) { + dgap_err("out of memory"); + return -1; + } + break; + + case CU: /* cu name prefix */ + if (dgap_checknode(p)) + return -1; + p->next = dgap_newnode(CUNODE); + if (!p->next) { + dgap_err("out of memory"); + return -1; + } + p = p->next; + s = dgap_getword(in); + if (!s) { + dgap_err("unexpeced end of file"); + return -1; + } + p->u.cuname = dgap_savestring(s); + if (!p->u.cuname) { + dgap_err("out of memory"); + return -1; + } + break; + + case LINE: /* line information */ + if (dgap_checknode(p)) + return -1; + if (brd == NULL) { + dgap_err("must specify board before line info"); + return -1; + } + switch (brd->u.board.type) { + case PPCM: + dgap_err("line not vaild for PC/em"); + return -1; + } + p->next = dgap_newnode(LNODE); + if (!p->next) { + dgap_err("out of memory"); + return -1; + } + p = p->next; + conc = NULL; + line = p; + linecnt++; + break; + + case CONC: /* concentrator information */ + if (dgap_checknode(p)) + return -1; + if (line == NULL) { + dgap_err("must specify line info before concentrator"); + return -1; + } + p->next = dgap_newnode(CNODE); + if (!p->next) { + dgap_err("out of memory"); + return -1; + } + p = p->next; + conc = p; + if (linecnt) + brd->u.board.conc2++; + else + brd->u.board.conc1++; + + break; + + case CX: /* c/x type concentrator */ + if (p->type != CNODE) { + dgap_err("cx only valid for concentrators"); + return -1; + } + p->u.conc.type = CX; + p->u.conc.v_type = 1; + break; + + case EPC: /* epc type concentrator */ + if (p->type != CNODE) { + dgap_err("cx only valid for concentrators"); + return -1; + } + p->u.conc.type = EPC; + p->u.conc.v_type = 1; + break; + + case MOD: /* EBI module */ + if (dgap_checknode(p)) + return -1; + if (brd == NULL) { + dgap_err("must specify board info before EBI modules"); + return -1; + } + switch (brd->u.board.type) { + case PPCM: + linecnt = 0; + break; + default: + if (conc == NULL) { + dgap_err("must specify concentrator info before EBI module"); + return -1; + } + } + p->next = dgap_newnode(MNODE); + if (!p->next) { + dgap_err("out of memory"); + return -1; + } + p = p->next; + if (linecnt) + brd->u.board.module2++; + else + brd->u.board.module1++; + + break; + + case PORTS: /* ports type EBI module */ + if (p->type != MNODE) { + dgap_err("ports only valid for EBI modules"); + return -1; + } + p->u.module.type = PORTS; + p->u.module.v_type = 1; + break; + + case MODEM: /* ports type EBI module */ + if (p->type != MNODE) { + dgap_err("modem only valid for modem modules"); + return -1; + } + p->u.module.type = MODEM; + p->u.module.v_type = 1; + break; + + case CABLE: + if (p->type == LNODE) { + s = dgap_getword(in); + if (!s) { + dgap_err("unexpected end of file"); + return -1; + } + p->u.line.cable = dgap_savestring(s); + p->u.line.v_cable = 1; + } + break; + + case SPEED: /* sync line speed indication */ + if (p->type == LNODE) { + s = dgap_getword(in); + if (s == NULL) { + dgap_err("unexpected end of file"); + return -1; + } + p->u.line.speed = (char)simple_strtol(s, &s2, 0); + if ((short)strlen(s) > (short)(s2 - s)) { + dgap_err("bad number for line speed"); + return -1; + } + p->u.line.v_speed = 1; + } else if (p->type == CNODE) { + s = dgap_getword(in); + if (s == NULL) { + dgap_err("unexpected end of file"); + return -1; + } + p->u.conc.speed = (char)simple_strtol(s, &s2, 0); + if ((short)strlen(s) > (short)(s2 - s)) { + dgap_err("bad number for line speed"); + return -1; + } + p->u.conc.v_speed = 1; + } else { + dgap_err("speed valid only for lines or concentrators."); + return -1; + } + break; + + case CONNECT: + if (p->type == CNODE) { + s = dgap_getword(in); + if (!s) { + dgap_err("unexpected end of file"); + return -1; + } + p->u.conc.connect = dgap_savestring(s); + p->u.conc.v_connect = 1; + } + break; + case PRINT: /* transparent print name prefix */ + if (dgap_checknode(p)) + return -1; + p->next = dgap_newnode(PNODE); + if (!p->next) { + dgap_err("out of memory"); + return -1; + } + p = p->next; + s = dgap_getword(in); + if (!s) { + dgap_err("unexpeced end of file"); + return -1; + } + p->u.printname = dgap_savestring(s); + if (!p->u.printname) { + dgap_err("out of memory"); + return -1; + } + break; + + case CMAJOR: /* major number */ + if (dgap_checknode(p)) + return -1; + p->next = dgap_newnode(JNODE); + if (!p->next) { + dgap_err("out of memory"); + return -1; + } + p = p->next; + s = dgap_getword(in); + if (s == NULL) { + dgap_err("unexpected end of file"); + return -1; + } + p->u.majornumber = simple_strtol(s, &s2, 0); + if ((int)strlen(s) > (int)(s2 - s)) { + dgap_err("bad number for major number"); + return -1; + } + break; + + case ALTPIN: /* altpin setting */ + if (dgap_checknode(p)) + return -1; + p->next = dgap_newnode(ANODE); + if (!p->next) { + dgap_err("out of memory"); + return -1; + } + p = p->next; + s = dgap_getword(in); + if (s == NULL) { + dgap_err("unexpected end of file"); + return -1; + } + p->u.altpin = simple_strtol(s, &s2, 0); + if ((int)strlen(s) > (int)(s2 - s)) { + dgap_err("bad number for altpin"); + return -1; + } + break; + + case USEINTR: /* enable interrupt setting */ + if (dgap_checknode(p)) + return -1; + p->next = dgap_newnode(INTRNODE); + if (!p->next) { + dgap_err("out of memory"); + return -1; + } + p = p->next; + s = dgap_getword(in); + if (s == NULL) { + dgap_err("unexpected end of file"); + return -1; + } + p->u.useintr = simple_strtol(s, &s2, 0); + if ((int)strlen(s) > (int)(s2 - s)) { + dgap_err("bad number for useintr"); + return -1; + } + break; + + case TTSIZ: /* size of tty structure */ + if (dgap_checknode(p)) + return -1; + p->next = dgap_newnode(TSNODE); + if (!p->next) { + dgap_err("out of memory"); + return -1; + } + p = p->next; + s = dgap_getword(in); + if (s == NULL) { + dgap_err("unexpected end of file"); + return -1; + } + p->u.ttysize = simple_strtol(s, &s2, 0); + if ((int)strlen(s) > (int)(s2 - s)) { + dgap_err("bad number for ttysize"); + return -1; + } + break; + + case CHSIZ: /* channel structure size */ + if (dgap_checknode(p)) + return -1; + p->next = dgap_newnode(CSNODE); + if (!p->next) { + dgap_err("out of memory"); + return -1; + } + p = p->next; + s = dgap_getword(in); + if (s == NULL) { + dgap_err("unexpected end of file"); + return -1; + } + p->u.chsize = simple_strtol(s, &s2, 0); + if ((int)strlen(s) > (int)(s2 - s)) { + dgap_err("bad number for chsize"); + return -1; + } + break; + + case BSSIZ: /* board structure size */ + if (dgap_checknode(p)) + return -1; + p->next = dgap_newnode(BSNODE); + if (!p->next) { + dgap_err("out of memory"); + return -1; + } + p = p->next; + s = dgap_getword(in); + if (s == NULL) { + dgap_err("unexpected end of file"); + return -1; + } + p->u.bssize = simple_strtol(s, &s2, 0); + if ((int)strlen(s) > (int)(s2 - s)) { + dgap_err("bad number for bssize"); + return -1; + } + break; + + case UNTSIZ: /* sched structure size */ + if (dgap_checknode(p)) + return -1; + p->next = dgap_newnode(USNODE); + if (!p->next) { + dgap_err("out of memory"); + return -1; + } + p = p->next; + s = dgap_getword(in); + if (s == NULL) { + dgap_err("unexpected end of file"); + return -1; + } + p->u.unsize = simple_strtol(s, &s2, 0); + if ((int)strlen(s) > (int)(s2 - s)) { + dgap_err("bad number for schedsize"); + return -1; + } + break; + + case F2SIZ: /* f2200 structure size */ + if (dgap_checknode(p)) + return -1; + p->next = dgap_newnode(FSNODE); + if (!p->next) { + dgap_err("out of memory"); + return -1; + } + p = p->next; + s = dgap_getword(in); + if (s == NULL) { + dgap_err("unexpected end of file"); + return -1; + } + p->u.f2size = simple_strtol(s, &s2, 0); + if ((int)strlen(s) > (int)(s2 - s)) { + dgap_err("bad number for f2200size"); + return -1; + } + break; + + case VPSIZ: /* vpix structure size */ + if (dgap_checknode(p)) + return -1; + p->next = dgap_newnode(VSNODE); + if (!p->next) { + dgap_err("out of memory"); + return -1; + } + p = p->next; + s = dgap_getword(in); + if (s == NULL) { + dgap_err("unexpected end of file"); + return -1; + } + p->u.vpixsize = simple_strtol(s, &s2, 0); + if ((int)strlen(s) > (int)(s2 - s)) { + dgap_err("bad number for vpixsize"); + return -1; + } + break; + } + } +} + +/* + * dgap_sindex: much like index(), but it looks for a match of any character in + * the group, and returns that position. If the first character is a ^, then + * this will match the first occurrence not in that group. + */ +static char *dgap_sindex (char *string, char *group) +{ + char *ptr; + + if (!string || !group) + return (char *) NULL; + + if (*group == '^') { + group++; + for (; *string; string++) { + for (ptr = group; *ptr; ptr++) { + if (*ptr == *string) + break; + } + if (*ptr == '\0') + return string; + } + } else { + for (; *string; string++) { + for (ptr = group; *ptr; ptr++) { + if (*ptr == *string) + return string; + } + } + } + + return (char *) NULL; +} + +/* + * Get a token from the input file; return 0 if end of file is reached + */ +static int dgap_gettok(char **in, struct cnode *p) +{ + char *w; + struct toklist *t; + + if (strstr(dgap_cword, "boar")) { + w = dgap_getword(in); + snprintf(dgap_cword, MAXCWORD, "%s", w); + for (t = dgap_tlist; t->token != 0; t++) { + if (!strcmp(w, t->string)) + return t->token; + } + dgap_err("board !!type not specified"); + return 1; + } else { + while ( (w = dgap_getword(in)) != NULL ) { + snprintf(dgap_cword, MAXCWORD, "%s", w); + for (t = dgap_tlist; t->token != 0; t++) { + if (!strcmp(w, t->string)) + return t->token; + } + } + return 0; + } +} + +/* + * get a word from the input stream, also keep track of current line number. + * words are separated by whitespace. + */ +static char *dgap_getword(char **in) +{ + char *ret_ptr = *in; + + char *ptr = dgap_sindex(*in, " \t\n"); + + /* If no word found, return null */ + if (!ptr) + return NULL; + + /* Mark new location for our buffer */ + *ptr = '\0'; + *in = ptr + 1; + + /* Eat any extra spaces/tabs/newlines that might be present */ + while (*in && **in && ((**in == ' ') || (**in == '\t') || (**in == '\n'))) { + **in = '\0'; + *in = *in + 1; + } + + return ret_ptr; +} + +/* + * print an error message, giving the line number in the file where + * the error occurred. + */ +static void dgap_err(char *s) +{ + printk("DGAP: parse: %s\n", s); +} + +/* + * allocate a new configuration node of type t + */ +static struct cnode *dgap_newnode(int t) +{ + struct cnode *n; + + n = kmalloc(sizeof(struct cnode), GFP_ATOMIC); + if (n != NULL) { + memset((char *)n, 0, sizeof(struct cnode)); + n->type = t; + } + return n; +} + +/* + * dgap_checknode: see if all the necessary info has been supplied for a node + * before creating the next node. + */ +static int dgap_checknode(struct cnode *p) +{ + switch (p->type) { + case BNODE: + if (p->u.board.v_type == 0) { + dgap_err("board type !not specified"); + return 1; + } + + return 0; + + case LNODE: + if (p->u.line.v_speed == 0) { + dgap_err("line speed not specified"); + return 1; + } + return 0; + + case CNODE: + if (p->u.conc.v_type == 0) { + dgap_err("concentrator type not specified"); + return 1; + } + if (p->u.conc.v_speed == 0) { + dgap_err("concentrator line speed not specified"); + return 1; + } + if (p->u.conc.v_nport == 0) { + dgap_err("number of ports on concentrator not specified"); + return 1; + } + if (p->u.conc.v_id == 0) { + dgap_err("concentrator id letter not specified"); + return 1; + } + return 0; + + case MNODE: + if (p->u.module.v_type == 0) { + dgap_err("EBI module type not specified"); + return 1; + } + if (p->u.module.v_nport == 0) { + dgap_err("number of ports on EBI module not specified"); + return 1; + } + if (p->u.module.v_id == 0) { + dgap_err("EBI module id letter not specified"); + return 1; + } + return 0; + } + return 0; +} + +/* + * save a string somewhere + */ +static char *dgap_savestring(char *s) +{ + char *p; + + p = kmalloc(strlen(s) + 1, GFP_ATOMIC); + if (p) + strcpy(p, s); + return p; +} + +/* + * Given a board pointer, returns whether we should use interrupts or not. + */ +static uint dgap_config_get_useintr(struct board_t *bd) +{ + struct cnode *p = NULL; + + if (!bd) + return 0; + + for (p = bd->bd_config; p; p = p->next) { + switch (p->type) { + case INTRNODE: + /* + * check for pcxr types. + */ + return p->u.useintr; + default: + break; + } + } + + /* If not found, then don't turn on interrupts. */ + return 0; +} + +/* + * Given a board pointer, returns whether we turn on altpin or not. + */ +static uint dgap_config_get_altpin(struct board_t *bd) +{ + struct cnode *p = NULL; + + if (!bd) + return 0; + + for (p = bd->bd_config; p; p = p->next) { + switch (p->type) { + case ANODE: + /* + * check for pcxr types. + */ + return p->u.altpin; + default: + break; + } + } + + /* If not found, then don't turn on interrupts. */ + return 0; +} + +/* + * Given a specific type of board, if found, detached link and + * returns the first occurrence in the list. + */ +static struct cnode *dgap_find_config(int type, int bus, int slot) +{ + struct cnode *p, *prev = NULL, *prev2 = NULL, *found = NULL; + + p = &dgap_head; + + while (p->next != NULL) { + prev = p; + p = p->next; + + if (p->type == BNODE) { + + if (p->u.board.type == type) { + + if (p->u.board.v_pcibus && + p->u.board.pcibus != bus) + continue; + if (p->u.board.v_pcislot && + p->u.board.pcislot != slot) + continue; + + found = p; + /* + * Keep walking thru the list till we find the next board. + */ + while (p->next != NULL) { + prev2 = p; + p = p->next; + if (p->type == BNODE) { + + /* + * Mark the end of our 1 board chain of configs. + */ + prev2->next = NULL; + + /* + * Link the "next" board to the previous board, + * effectively "unlinking" our board from the main config. + */ + prev->next = p; + + return found; + } + } + /* + * It must be the last board in the list. + */ + prev->next = NULL; + return found; + } + } + } + return NULL; +} + +/* + * Given a board pointer, walks the config link, counting up + * all ports user specified should be on the board. + * (This does NOT mean they are all actually present right now tho) + */ +static uint dgap_config_get_number_of_ports(struct board_t *bd) +{ + int count = 0; + struct cnode *p = NULL; + + if (!bd) + return 0; + + for (p = bd->bd_config; p; p = p->next) { + + switch (p->type) { + case BNODE: + /* + * check for pcxr types. + */ + if (p->u.board.type > EPCFE) + count += p->u.board.nport; + break; + case CNODE: + count += p->u.conc.nport; + break; + case MNODE: + count += p->u.module.nport; + break; + } + } + return count; +} + +static char *dgap_create_config_string(struct board_t *bd, char *string) +{ + char *ptr = string; + struct cnode *p = NULL; + struct cnode *q = NULL; + int speed; + + if (!bd) { + *ptr = 0xff; + return string; + } + + for (p = bd->bd_config; p; p = p->next) { + + switch (p->type) { + case LNODE: + *ptr = '\0'; + ptr++; + *ptr = p->u.line.speed; + ptr++; + break; + case CNODE: + /* + * Because the EPC/con concentrators can have EM modules + * hanging off of them, we have to walk ahead in the list + * and keep adding the number of ports on each EM to the config. + * UGH! + */ + speed = p->u.conc.speed; + q = p->next; + if ((q != NULL) && (q->type == MNODE)) { + *ptr = (p->u.conc.nport + 0x80); + ptr++; + p = q; + while ((q->next != NULL) && (q->next->type) == MNODE) { + *ptr = (q->u.module.nport + 0x80); + ptr++; + p = q; + q = q->next; + } + *ptr = q->u.module.nport; + ptr++; + } else { + *ptr = p->u.conc.nport; + ptr++; + } + + *ptr = speed; + ptr++; + break; + } + } + + *ptr = 0xff; + return string; +} diff --git a/drivers/staging/dgap/dgap.h b/drivers/staging/dgap/dgap.h new file mode 100644 index 00000000000..e33e59198ff --- /dev/null +++ b/drivers/staging/dgap/dgap.h @@ -0,0 +1,1408 @@ +/* + * Copyright 2003 Digi International (www.digi.com) + * Scott H Kilau <Scott_Kilau at digi dot com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the + * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!! + * + ************************************************************************* + * + * Driver includes + * + *************************************************************************/ + +#ifndef __DGAP_DRIVER_H +#define __DGAP_DRIVER_H + +#include <linux/types.h> /* To pick up the varions Linux types */ +#include <linux/tty.h> /* To pick up the various tty structs/defines */ +#include <linux/interrupt.h> /* For irqreturn_t type */ + +#ifndef TRUE +# define TRUE 1 +#endif + +#ifndef FALSE +# define FALSE 0 +#endif + +/* Required for our shared headers! */ +typedef unsigned char uchar; + +#if !defined(TTY_FLIPBUF_SIZE) +# define TTY_FLIPBUF_SIZE 512 +#endif + +/* Sparse stuff */ +# ifndef __user +# define __user +# define __kernel +# define __safe +# define __force +# define __chk_user_ptr(x) (void)0 +# endif + + +# define PARM_STR(VAR, INIT, PERM, DESC) \ + static char *VAR = INIT; \ + char *dgap_##VAR; \ + module_param(VAR, charp, PERM); \ + MODULE_PARM_DESC(VAR, DESC); + +# define PARM_INT(VAR, INIT, PERM, DESC) \ + static int VAR = INIT; \ + int dgap_##VAR; \ + module_param(VAR, int, PERM); \ + MODULE_PARM_DESC(VAR, DESC); + +# define PARM_ULONG(VAR, INIT, PERM, DESC) \ + static ulong VAR = INIT; \ + ulong dgap_##VAR; \ + module_param(VAR, long, PERM); \ + MODULE_PARM_DESC(VAR, DESC); + +/************************************************************************* + * + * Driver defines + * + *************************************************************************/ + +/* + * Driver identification, error and debugging statments + * + * In theory, you can change all occurrences of "digi" in the next + * three lines, and the driver printk's will all automagically change. + * + * APR((fmt, args, ...)); Always prints message + * DPR((fmt, args, ...)); Only prints if DGAP_TRACER is defined at + * compile time and dgap_debug!=0 + */ +#define DG_NAME "dgap-1.3-16" +#define DG_PART "40002347_C" + +#define PROCSTR "dgap" /* /proc entries */ +#define DEVSTR "/dev/dg/dgap" /* /dev entries */ +#define DRVSTR "dgap" /* Driver name string + * displayed by APR */ +#define APR(args) do { PRINTF_TO_KMEM(args); printk(DRVSTR": "); printk args; \ + } while (0) +#define RAPR(args) do { PRINTF_TO_KMEM(args); printk args; } while (0) + +#define TRC_TO_CONSOLE 1 + +/* + * defines from dgap_pci.h + */ +#define PCIMAX 32 /* maximum number of PCI boards */ + +#define DIGI_VID 0x114F + +#define PCI_DEVICE_EPC_DID 0x0002 +#define PCI_DEVICE_XEM_DID 0x0004 +#define PCI_DEVICE_XR_DID 0x0005 +#define PCI_DEVICE_CX_DID 0x0006 +#define PCI_DEVICE_XRJ_DID 0x0009 /* PLX-based Xr adapter */ +#define PCI_DEVICE_XR_IBM_DID 0x0011 /* IBM 8-port Async Adapter */ +#define PCI_DEVICE_XR_BULL_DID 0x0013 /* BULL 8-port Async Adapter */ +#define PCI_DEVICE_XR_SAIP_DID 0x001c /* SAIP card - Xr adapter */ +#define PCI_DEVICE_XR_422_DID 0x0012 /* Xr-422 */ +#define PCI_DEVICE_920_2_DID 0x0034 /* XR-Plus 920 K, 2 port */ +#define PCI_DEVICE_920_4_DID 0x0026 /* XR-Plus 920 K, 4 port */ +#define PCI_DEVICE_920_8_DID 0x0027 /* XR-Plus 920 K, 8 port */ +#define PCI_DEVICE_EPCJ_DID 0x000a /* PLX 9060 chip for PCI */ +#define PCI_DEVICE_CX_IBM_DID 0x001b /* IBM 128-port Async Adapter */ +#define PCI_DEVICE_920_8_HP_DID 0x0058 /* HP XR-Plus 920 K, 8 port */ +#define PCI_DEVICE_XEM_HP_DID 0x0059 /* HP Xem PCI */ + +#define PCI_DEVICE_XEM_NAME "AccelePort XEM" +#define PCI_DEVICE_CX_NAME "AccelePort CX" +#define PCI_DEVICE_XR_NAME "AccelePort Xr" +#define PCI_DEVICE_XRJ_NAME "AccelePort Xr (PLX)" +#define PCI_DEVICE_XR_SAIP_NAME "AccelePort Xr (SAIP)" +#define PCI_DEVICE_920_2_NAME "AccelePort Xr920 2 port" +#define PCI_DEVICE_920_4_NAME "AccelePort Xr920 4 port" +#define PCI_DEVICE_920_8_NAME "AccelePort Xr920 8 port" +#define PCI_DEVICE_XR_422_NAME "AccelePort Xr 422" +#define PCI_DEVICE_EPCJ_NAME "AccelePort EPC (PLX)" +#define PCI_DEVICE_XR_BULL_NAME "AccelePort Xr (BULL)" +#define PCI_DEVICE_XR_IBM_NAME "AccelePort Xr (IBM)" +#define PCI_DEVICE_CX_IBM_NAME "AccelePort CX (IBM)" +#define PCI_DEVICE_920_8_HP_NAME "AccelePort Xr920 8 port (HP)" +#define PCI_DEVICE_XEM_HP_NAME "AccelePort XEM (HP)" + +/* + * On the PCI boards, there is no IO space allocated + * The I/O registers will be in the first 3 bytes of the + * upper 2MB of the 4MB memory space. The board memory + * will be mapped into the low 2MB of the 4MB memory space + */ + +/* Potential location of PCI Bios from E0000 to FFFFF*/ +#define PCI_BIOS_SIZE 0x00020000 + +/* Size of Memory and I/O for PCI (4MB) */ +#define PCI_RAM_SIZE 0x00400000 + +/* Size of Memory (2MB) */ +#define PCI_MEM_SIZE 0x00200000 + +/* Max PCI Window Size (2MB) */ +#define PCI_WIN_SIZE 0x00200000 + +#define PCI_WIN_SHIFT 21 /* 21 bits max */ + +/* Offset of I/0 in Memory (2MB) */ +#define PCI_IO_OFFSET 0x00200000 + +/* Size of IO (2MB) */ +#define PCI_IO_SIZE 0x00200000 + +/* Number of boards we support at once. */ +#define MAXBOARDS 32 +#define MAXPORTS 224 +#define MAXTTYNAMELEN 200 + +/* Our 3 magic numbers for our board, channel and unit structs */ +#define DGAP_BOARD_MAGIC 0x5c6df104 +#define DGAP_CHANNEL_MAGIC 0x6c6df104 +#define DGAP_UNIT_MAGIC 0x7c6df104 + +/* Serial port types */ +#define DGAP_SERIAL 0 +#define DGAP_PRINT 1 + +#define SERIAL_TYPE_NORMAL 1 + +/* 4 extra for alignment play space */ +#define WRITEBUFLEN ((4096) + 4) +#define MYFLIPLEN N_TTY_BUF_SIZE + +#define SBREAK_TIME 0x25 +#define U2BSIZE 0x400 + +#define dgap_jiffies_from_ms(a) (((a) * HZ) / 1000) + +/* + * Our major for the mgmt devices. + * + * We can use 22, because Digi was allocated 22 and 23 for the epca driver. + * 22 has now become obsolete now that the "cu" devices have + * been removed from 2.6. + * Also, this *IS* the epca driver, just PCI only now. + */ +#ifndef DIGI_DGAP_MAJOR +# define DIGI_DGAP_MAJOR 22 +#endif + +/* + * The parameters we use to define the periods of the moving averages. + */ +#define MA_PERIOD (HZ / 10) +#define SMA_DUR (1 * HZ) +#define EMA_DUR (1 * HZ) +#define SMA_NPERIODS (SMA_DUR / MA_PERIOD) +#define EMA_NPERIODS (EMA_DUR / MA_PERIOD) + +/* + * Define a local default termios struct. All ports will be created + * with this termios initially. This is the same structure that is defined + * as the default in tty_io.c with the same settings overriden as in serial.c + * + * In short, this should match the internal serial ports' defaults. + */ +#define DEFAULT_IFLAGS (ICRNL | IXON) +#define DEFAULT_OFLAGS (OPOST | ONLCR) +#define DEFAULT_CFLAGS (B9600 | CS8 | CREAD | HUPCL | CLOCAL) +#define DEFAULT_LFLAGS (ISIG | ICANON | ECHO | ECHOE | ECHOK | \ + ECHOCTL | ECHOKE | IEXTEN) + +#ifndef _POSIX_VDISABLE +#define _POSIX_VDISABLE '\0' +#endif + +#define SNIFF_MAX 65536 /* Sniff buffer size (2^n) */ +#define SNIFF_MASK (SNIFF_MAX - 1) /* Sniff wrap mask */ + +#define VPDSIZE (512) + +/* + * Lock function/defines. + * Makes spotting lock/unlock locations easier. + */ +# define DGAP_SPINLOCK_INIT(x) spin_lock_init(&(x)) +# define DGAP_LOCK(x,y) spin_lock_irqsave(&(x), y) +# define DGAP_UNLOCK(x,y) spin_unlock_irqrestore(&(x), y) +# define DGAP_TRYLOCK(x,y) spin_trylock(&(x)) + +/************************************************************************ + * FEP memory offsets + ************************************************************************/ +#define START 0x0004L /* Execution start address */ + +#define CMDBUF 0x0d10L /* Command (cm_t) structure offset */ +#define CMDSTART 0x0400L /* Start of command buffer */ +#define CMDMAX 0x0800L /* End of command buffer */ + +#define EVBUF 0x0d18L /* Event (ev_t) structure */ +#define EVSTART 0x0800L /* Start of event buffer */ +#define EVMAX 0x0c00L /* End of event buffer */ +#define FEP5_PLUS 0x0E40 /* ASCII '5' and ASCII 'A' is here */ +#define ECS_SEG 0x0E44 /* Segment of the extended channel structure */ +#define LINE_SPEED 0x10 /* Offset into ECS_SEG for line speed */ + /* if the fep has extended capabilities */ + +/* BIOS MAGIC SPOTS */ +#define ERROR 0x0C14L /* BIOS error code */ +#define SEQUENCE 0x0C12L /* BIOS sequence indicator */ +#define POSTAREA 0x0C00L /* POST complete message area */ + +/* FEP MAGIC SPOTS */ +#define FEPSTAT POSTAREA /* OS here when FEP comes up */ +#define NCHAN 0x0C02L /* number of ports FEP sees */ +#define PANIC 0x0C10L /* PANIC area for FEP */ +#define KMEMEM 0x0C30L /* Memory for KME use */ +#define CONFIG 0x0CD0L /* Concentrator configuration info */ +#define CONFIGSIZE 0x0030 /* configuration info size */ +#define DOWNREQ 0x0D00 /* Download request buffer pointer */ + +#define CHANBUF 0x1000L /* Async channel (bs_t) structs */ +#define FEPOSSIZE 0x1FFF /* 8K FEPOS */ + +#define XEMPORTS 0xC02 /* + * Offset in board memory where FEP5 stores + * how many ports it has detected. + * NOTE: FEP5 reports 64 ports when the user + * has the cable in EBI OUT instead of EBI IN. + */ + +#define FEPCLR 0x00 +#define FEPMEM 0x02 +#define FEPRST 0x04 +#define FEPINT 0x08 +#define FEPMASK 0x0e +#define FEPWIN 0x80 + +#define LOWMEM 0x0100 +#define HIGHMEM 0x7f00 + +#define FEPTIMEOUT 200000 + +#define ENABLE_INTR 0x0e04 /* Enable interrupts flag */ +#define FEPPOLL_MIN 1 /* minimum of 1 millisecond */ +#define FEPPOLL_MAX 20 /* maximum of 20 milliseconds */ +#define FEPPOLL 0x0c26 /* Fep event poll interval */ + +#define IALTPIN 0x0080 /* Input flag to swap DSR <-> DCD */ + +/************************************************************************ + * FEP supported functions + ************************************************************************/ +#define SRLOW 0xe0 /* Set receive low water */ +#define SRHIGH 0xe1 /* Set receive high water */ +#define FLUSHTX 0xe2 /* Flush transmit buffer */ +#define PAUSETX 0xe3 /* Pause data transmission */ +#define RESUMETX 0xe4 /* Resume data transmission */ +#define SMINT 0xe5 /* Set Modem Interrupt */ +#define SAFLOWC 0xe6 /* Set Aux. flow control chars */ +#define SBREAK 0xe8 /* Send break */ +#define SMODEM 0xe9 /* Set 8530 modem control lines */ +#define SIFLAG 0xea /* Set UNIX iflags */ +#define SFLOWC 0xeb /* Set flow control characters */ +#define STLOW 0xec /* Set transmit low water mark */ +#define RPAUSE 0xee /* Pause receive */ +#define RRESUME 0xef /* Resume receive */ +#define CHRESET 0xf0 /* Reset Channel */ +#define BUFSETALL 0xf2 /* Set Tx & Rx buffer size avail*/ +#define SOFLAG 0xf3 /* Set UNIX oflags */ +#define SHFLOW 0xf4 /* Set hardware handshake */ +#define SCFLAG 0xf5 /* Set UNIX cflags */ +#define SVNEXT 0xf6 /* Set VNEXT character */ +#define SPINTFC 0xfc /* Reserved */ +#define SCOMMODE 0xfd /* Set RS232/422 mode */ + + +/************************************************************************ + * Modes for SCOMMODE + ************************************************************************/ +#define MODE_232 0x00 +#define MODE_422 0x01 + + +/************************************************************************ + * Event flags. + ************************************************************************/ +#define IFBREAK 0x01 /* Break received */ +#define IFTLW 0x02 /* Transmit low water */ +#define IFTEM 0x04 /* Transmitter empty */ +#define IFDATA 0x08 /* Receive data present */ +#define IFMODEM 0x20 /* Modem status change */ + +/************************************************************************ + * Modem flags + ************************************************************************/ +# define DM_RTS 0x02 /* Request to send */ +# define DM_CD 0x80 /* Carrier detect */ +# define DM_DSR 0x20 /* Data set ready */ +# define DM_CTS 0x10 /* Clear to send */ +# define DM_RI 0x40 /* Ring indicator */ +# define DM_DTR 0x01 /* Data terminal ready */ + +/* + * defines from dgap_conf.h + */ +#define NULLNODE 0 /* header node, not used */ +#define BNODE 1 /* Board node */ +#define LNODE 2 /* Line node */ +#define CNODE 3 /* Concentrator node */ +#define MNODE 4 /* EBI Module node */ +#define TNODE 5 /* tty name prefix node */ +#define CUNODE 6 /* cu name prefix (non-SCO) */ +#define PNODE 7 /* trans. print prefix node */ +#define JNODE 8 /* maJor number node */ +#define ANODE 9 /* altpin */ +#define TSNODE 10 /* tty structure size */ +#define CSNODE 11 /* channel structure size */ +#define BSNODE 12 /* board structure size */ +#define USNODE 13 /* unit schedule structure size */ +#define FSNODE 14 /* f2200 structure size */ +#define VSNODE 15 /* size of VPIX structures */ +#define INTRNODE 16 /* enable interrupt */ + +/* Enumeration of tokens */ +#define BEGIN 1 +#define END 2 +#define BOARD 10 + +#define EPCFS 11 /* start of EPC family definitions */ +#define ICX 11 +#define MCX 13 +#define PCX 14 +#define IEPC 15 +#define EEPC 16 +#define MEPC 17 +#define IPCM 18 +#define EPCM 19 +#define MPCM 20 +#define PEPC 21 +#define PPCM 22 +#ifdef CP +#define ICP 23 +#define ECP 24 +#define MCP 25 +#endif +#define EPCFE 25 /* end of EPC family definitions */ +#define PC2E 26 +#define PC4E 27 +#define PC4E8K 28 +#define PC8E 29 +#define PC8E8K 30 +#define PC16E 31 +#define MC2E8K 34 +#define MC4E8K 35 +#define MC8E8K 36 + +#define AVANFS 42 /* start of Avanstar family definitions */ +#define A8P 42 +#define A16P 43 +#define AVANFE 43 /* end of Avanstar family definitions */ + +#define DA2000FS 44 /* start of AccelePort 2000 family definitions */ +#define DA22 44 /* AccelePort 2002 */ +#define DA24 45 /* AccelePort 2004 */ +#define DA28 46 /* AccelePort 2008 */ +#define DA216 47 /* AccelePort 2016 */ +#define DAR4 48 /* AccelePort RAS 4 port */ +#define DAR8 49 /* AccelePort RAS 8 port */ +#define DDR24 50 /* DataFire RAS 24 port */ +#define DDR30 51 /* DataFire RAS 30 port */ +#define DDR48 52 /* DataFire RAS 48 port */ +#define DDR60 53 /* DataFire RAS 60 port */ +#define DA2000FE 53 /* end of AccelePort 2000/RAS family definitions */ + +#define PCXRFS 106 /* start of PCXR family definitions */ +#define APORT4 106 +#define APORT8 107 +#define PAPORT4 108 +#define PAPORT8 109 +#define APORT4_920I 110 +#define APORT8_920I 111 +#define APORT4_920P 112 +#define APORT8_920P 113 +#define APORT2_920P 114 +#define PCXRFE 117 /* end of PCXR family definitions */ + +#define LINE 82 +#ifdef T1 +#define T1M 83 +#define E1M 84 +#endif +#define CONC 64 +#define CX 65 +#define EPC 66 +#define MOD 67 +#define PORTS 68 +#define METHOD 69 +#define CUSTOM 70 +#define BASIC 71 +#define STATUS 72 +#define MODEM 73 +/* The following tokens can appear in multiple places */ +#define SPEED 74 +#define NPORTS 75 +#define ID 76 +#define CABLE 77 +#define CONNECT 78 +#define IO 79 +#define MEM 80 +#define DPSZ 81 + +#define TTYN 90 +#define CU 91 +#define PRINT 92 +#define XPRINT 93 +#define CMAJOR 94 +#define ALTPIN 95 +#define STARTO 96 +#define USEINTR 97 +#define PCIINFO 98 + +#define TTSIZ 100 +#define CHSIZ 101 +#define BSSIZ 102 +#define UNTSIZ 103 +#define F2SIZ 104 +#define VPSIZ 105 + +#define TOTAL_BOARD 2 +#define CURRENT_BRD 4 +#define BOARD_TYPE 6 +#define IO_ADDRESS 8 +#define MEM_ADDRESS 10 + +#define FIELDS_PER_PAGE 18 + +#define TB_FIELD 1 +#define CB_FIELD 3 +#define BT_FIELD 5 +#define IO_FIELD 7 +#define ID_FIELD 8 +#define ME_FIELD 9 +#define TTY_FIELD 11 +#define CU_FIELD 13 +#define PR_FIELD 15 +#define MPR_FIELD 17 + +#define MAX_FIELD 512 + +#define INIT 0 +#define NITEMS 128 +#define MAX_ITEM 512 + +#define DSCRINST 1 +#define DSCRNUM 3 +#define ALTPINQ 5 +#define SSAVE 7 + +#define DSCR "32" +#define ONETONINE "123456789" +#define ALL "1234567890" + +/* + * All the possible states the driver can be while being loaded. + */ +enum { + DRIVER_INITIALIZED = 0, + DRIVER_NEED_CONFIG_LOAD, + DRIVER_REQUESTED_CONFIG, + DRIVER_READY +}; + +/* + * All the possible states the board can be while booting up. + */ +enum { + BOARD_FAILED = 0, + CONFIG_NOT_FOUND, + BOARD_FOUND, + NEED_RESET, + FINISHED_RESET, + NEED_CONFIG, + FINISHED_CONFIG, + NEED_DEVICE_CREATION, + REQUESTED_DEVICE_CREATION, + FINISHED_DEVICE_CREATION, + NEED_BIOS_LOAD, + REQUESTED_BIOS, + WAIT_BIOS_LOAD, + FINISHED_BIOS_LOAD, + NEED_FEP_LOAD, + REQUESTED_FEP, + WAIT_FEP_LOAD, + FINISHED_FEP_LOAD, + NEED_PROC_CREATION, + FINISHED_PROC_CREATION, + BOARD_READY +}; + +/* + * All the possible states that a requested concentrator image can be in. + */ +enum { + NO_PENDING_CONCENTRATOR_REQUESTS = 0, + NEED_CONCENTRATOR, + REQUESTED_CONCENTRATOR +}; + + + +/* + * Modem line constants are defined as macros because DSR and + * DCD are swapable using the ditty altpin option. + */ +#define D_CD(ch) ch->ch_cd /* Carrier detect */ +#define D_DSR(ch) ch->ch_dsr /* Data set ready */ +#define D_RTS(ch) DM_RTS /* Request to send */ +#define D_CTS(ch) DM_CTS /* Clear to send */ +#define D_RI(ch) DM_RI /* Ring indicator */ +#define D_DTR(ch) DM_DTR /* Data terminal ready */ + + +/************************************************************************* + * + * Structures and closely related defines. + * + *************************************************************************/ + + +/* + * A structure to hold a statistics counter. We also + * compute moving averages for this counter. + */ +struct macounter +{ + u32 cnt; /* Total count */ + ulong accum; /* Acuumulator per period */ + ulong sma; /* Simple moving average */ + ulong ema; /* Exponential moving average */ +}; + + +/************************************************************************ + * Device flag definitions for bd_flags. + ************************************************************************/ +#define BD_FEP5PLUS 0x0001 /* Supports FEP5 Plus commands */ +#define BD_HAS_VPD 0x0002 /* Board has VPD info available */ + +/* + * Per-board information + */ +struct board_t +{ + int magic; /* Board Magic number. */ + int boardnum; /* Board number: 0-3 */ + int firstminor; /* First minor, e.g. 0, 30, 60 */ + + int type; /* Type of board */ + char *name; /* Product Name */ + struct pci_dev *pdev; /* Pointer to the pci_dev struct */ + u16 vendor; /* PCI vendor ID */ + u16 device; /* PCI device ID */ + u16 subvendor; /* PCI subsystem vendor ID */ + u16 subdevice; /* PCI subsystem device ID */ + uchar rev; /* PCI revision ID */ + uint pci_bus; /* PCI bus value */ + uint pci_slot; /* PCI slot value */ + u16 maxports; /* MAX ports this board can handle */ + uchar vpd[VPDSIZE]; /* VPD of board, if found */ + u32 bd_flags; /* Board flags */ + + spinlock_t bd_lock; /* Used to protect board */ + + u32 state; /* State of card. */ + wait_queue_head_t state_wait; /* Place to sleep on for state change */ + + struct tasklet_struct helper_tasklet; /* Poll helper tasklet */ + + u32 wait_for_bios; + u32 wait_for_fep; + + struct cnode * bd_config; /* Config of board */ + + u16 nasync; /* Number of ports on card */ + + u32 use_interrupts; /* Should we be interrupt driven? */ + ulong irq; /* Interrupt request number */ + ulong intr_count; /* Count of interrupts */ + u32 intr_used; /* Non-zero if using interrupts */ + u32 intr_running; /* Non-zero if FEP knows its doing interrupts */ + + ulong port; /* Start of base io port of the card */ + ulong port_end; /* End of base io port of the card */ + ulong membase; /* Start of base memory of the card */ + ulong membase_end; /* End of base memory of the card */ + + uchar *re_map_port; /* Remapped io port of the card */ + uchar *re_map_membase;/* Remapped memory of the card */ + + uchar runwait; /* # Processes waiting for FEP */ + uchar inhibit_poller; /* Tells the poller to leave us alone */ + + struct channel_t *channels[MAXPORTS]; /* array of pointers to our channels. */ + + struct tty_driver *SerialDriver; + struct tty_port *SerialPorts; + char SerialName[200]; + struct tty_driver *PrintDriver; + struct tty_port *PrinterPorts; + char PrintName[200]; + + u32 dgap_Major_Serial_Registered; + u32 dgap_Major_TransparentPrint_Registered; + + u32 dgap_Serial_Major; + u32 dgap_TransparentPrint_Major; + + struct bs_t *bd_bs; /* Base structure pointer */ + + char *flipbuf; /* Our flip buffer, alloced if board is found */ + char *flipflagbuf; /* Our flip flag buffer, alloced if board is found */ + + u16 dpatype; /* The board "type", as defined by DPA */ + u16 dpastatus; /* The board "status", as defined by DPA */ + wait_queue_head_t kme_wait; /* Needed for DPA support */ + + u32 conc_dl_status; /* Status of any pending conc download */ + /* + * Mgmt data. + */ + char *msgbuf_head; + char *msgbuf; +}; + + + +/************************************************************************ + * Unit flag definitions for un_flags. + ************************************************************************/ +#define UN_ISOPEN 0x0001 /* Device is open */ +#define UN_CLOSING 0x0002 /* Line is being closed */ +#define UN_IMM 0x0004 /* Service immediately */ +#define UN_BUSY 0x0008 /* Some work this channel */ +#define UN_BREAKI 0x0010 /* Input break received */ +#define UN_PWAIT 0x0020 /* Printer waiting for terminal */ +#define UN_TIME 0x0040 /* Waiting on time */ +#define UN_EMPTY 0x0080 /* Waiting output queue empty */ +#define UN_LOW 0x0100 /* Waiting output low water mark*/ +#define UN_EXCL_OPEN 0x0200 /* Open for exclusive use */ +#define UN_WOPEN 0x0400 /* Device waiting for open */ +#define UN_WIOCTL 0x0800 /* Device waiting for open */ +#define UN_HANGUP 0x8000 /* Carrier lost */ + +struct device; + +/************************************************************************ + * Structure for terminal or printer unit. + ************************************************************************/ +struct un_t { + int magic; /* Unit Magic Number. */ + struct channel_t *un_ch; + u32 un_time; + u32 un_type; + u32 un_open_count; /* Counter of opens to port */ + struct tty_struct *un_tty;/* Pointer to unit tty structure */ + u32 un_flags; /* Unit flags */ + wait_queue_head_t un_flags_wait; /* Place to sleep to wait on unit */ + u32 un_dev; /* Minor device number */ + tcflag_t un_oflag; /* oflags being done on board */ + tcflag_t un_lflag; /* lflags being done on board */ + struct device *un_sysfs; +}; + + +/************************************************************************ + * Device flag definitions for ch_flags. + ************************************************************************/ +#define CH_PRON 0x0001 /* Printer on string */ +#define CH_OUT 0x0002 /* Dial-out device open */ +#define CH_STOP 0x0004 /* Output is stopped */ +#define CH_STOPI 0x0008 /* Input is stopped */ +#define CH_CD 0x0010 /* Carrier is present */ +#define CH_FCAR 0x0020 /* Carrier forced on */ + +#define CH_RXBLOCK 0x0080 /* Enable rx blocked flag */ +#define CH_WLOW 0x0100 /* Term waiting low event */ +#define CH_WEMPTY 0x0200 /* Term waiting empty event */ +#define CH_RENABLE 0x0400 /* Buffer just emptied */ +#define CH_RACTIVE 0x0800 /* Process active in xxread() */ +#define CH_RWAIT 0x1000 /* Process waiting in xxread() */ +#define CH_BAUD0 0x2000 /* Used for checking B0 transitions */ +#define CH_HANGUP 0x8000 /* Hangup received */ + +/* + * Definitions for ch_sniff_flags + */ +#define SNIFF_OPEN 0x1 +#define SNIFF_WAIT_DATA 0x2 +#define SNIFF_WAIT_SPACE 0x4 + + +/************************************************************************ + *** Definitions for Digi ditty(1) command. + ************************************************************************/ + + +/* + * Copyright (c) 1988-96 Digi International Inc., All Rights Reserved. + */ + +/************************************************************************ + * This module provides application access to special Digi + * serial line enhancements which are not standard UNIX(tm) features. + ************************************************************************/ + +#if !defined(TIOCMODG) + +#define TIOCMODG ('d'<<8) | 250 /* get modem ctrl state */ +#define TIOCMODS ('d'<<8) | 251 /* set modem ctrl state */ + +#ifndef TIOCM_LE +#define TIOCM_LE 0x01 /* line enable */ +#define TIOCM_DTR 0x02 /* data terminal ready */ +#define TIOCM_RTS 0x04 /* request to send */ +#define TIOCM_ST 0x08 /* secondary transmit */ +#define TIOCM_SR 0x10 /* secondary receive */ +#define TIOCM_CTS 0x20 /* clear to send */ +#define TIOCM_CAR 0x40 /* carrier detect */ +#define TIOCM_RNG 0x80 /* ring indicator */ +#define TIOCM_DSR 0x100 /* data set ready */ +#define TIOCM_RI TIOCM_RNG /* ring (alternate) */ +#define TIOCM_CD TIOCM_CAR /* carrier detect (alt) */ +#endif + +#endif + +#if !defined(TIOCMSET) +#define TIOCMSET ('d'<<8) | 252 /* set modem ctrl state */ +#define TIOCMGET ('d'<<8) | 253 /* set modem ctrl state */ +#endif + +#if !defined(TIOCMBIC) +#define TIOCMBIC ('d'<<8) | 254 /* set modem ctrl state */ +#define TIOCMBIS ('d'<<8) | 255 /* set modem ctrl state */ +#endif + + +#if !defined(TIOCSDTR) +#define TIOCSDTR ('e'<<8) | 0 /* set DTR */ +#define TIOCCDTR ('e'<<8) | 1 /* clear DTR */ +#endif + +/************************************************************************ + * Ioctl command arguments for DIGI parameters. + ************************************************************************/ +#define DIGI_GETA ('e'<<8) | 94 /* Read params */ + +#define DIGI_SETA ('e'<<8) | 95 /* Set params */ +#define DIGI_SETAW ('e'<<8) | 96 /* Drain & set params */ +#define DIGI_SETAF ('e'<<8) | 97 /* Drain, flush & set params */ + +#define DIGI_KME ('e'<<8) | 98 /* Read/Write Host */ + /* Adapter Memory */ + +#define DIGI_GETFLOW ('e'<<8) | 99 /* Get startc/stopc flow */ + /* control characters */ +#define DIGI_SETFLOW ('e'<<8) | 100 /* Set startc/stopc flow */ + /* control characters */ +#define DIGI_GETAFLOW ('e'<<8) | 101 /* Get Aux. startc/stopc */ + /* flow control chars */ +#define DIGI_SETAFLOW ('e'<<8) | 102 /* Set Aux. startc/stopc */ + /* flow control chars */ + +#define DIGI_GEDELAY ('d'<<8) | 246 /* Get edelay */ +#define DIGI_SEDELAY ('d'<<8) | 247 /* Set edelay */ + +struct digiflow_t { + unsigned char startc; /* flow cntl start char */ + unsigned char stopc; /* flow cntl stop char */ +}; + + +#ifdef FLOW_2200 +#define F2200_GETA ('e'<<8) | 104 /* Get 2x36 flow cntl flags */ +#define F2200_SETAW ('e'<<8) | 105 /* Set 2x36 flow cntl flags */ +#define F2200_MASK 0x03 /* 2200 flow cntl bit mask */ +#define FCNTL_2200 0x01 /* 2x36 terminal flow cntl */ +#define PCNTL_2200 0x02 /* 2x36 printer flow cntl */ +#define F2200_XON 0xf8 +#define P2200_XON 0xf9 +#define F2200_XOFF 0xfa +#define P2200_XOFF 0xfb + +#define FXOFF_MASK 0x03 /* 2200 flow status mask */ +#define RCVD_FXOFF 0x01 /* 2x36 Terminal XOFF rcvd */ +#define RCVD_PXOFF 0x02 /* 2x36 Printer XOFF rcvd */ +#endif + +/************************************************************************ + * Values for digi_flags + ************************************************************************/ +#define DIGI_IXON 0x0001 /* Handle IXON in the FEP */ +#define DIGI_FAST 0x0002 /* Fast baud rates */ +#define RTSPACE 0x0004 /* RTS input flow control */ +#define CTSPACE 0x0008 /* CTS output flow control */ +#define DSRPACE 0x0010 /* DSR output flow control */ +#define DCDPACE 0x0020 /* DCD output flow control */ +#define DTRPACE 0x0040 /* DTR input flow control */ +#define DIGI_COOK 0x0080 /* Cooked processing done in FEP */ +#define DIGI_FORCEDCD 0x0100 /* Force carrier */ +#define DIGI_ALTPIN 0x0200 /* Alternate RJ-45 pin config */ +#define DIGI_AIXON 0x0400 /* Aux flow control in fep */ +#define DIGI_PRINTER 0x0800 /* Hold port open for flow cntrl*/ +#define DIGI_PP_INPUT 0x1000 /* Change parallel port to input*/ +#define DIGI_DTR_TOGGLE 0x2000 /* Support DTR Toggle */ +#define DIGI_422 0x4000 /* for 422/232 selectable panel */ +#define DIGI_RTS_TOGGLE 0x8000 /* Support RTS Toggle */ + +/************************************************************************ + * These options are not supported on the comxi. + ************************************************************************/ +#define DIGI_COMXI (DIGI_FAST|DIGI_COOK|DSRPACE|DCDPACE|DTRPACE) + +#define DIGI_PLEN 28 /* String length */ +#define DIGI_TSIZ 10 /* Terminal string len */ + +/************************************************************************ + * Structure used with ioctl commands for DIGI parameters. + ************************************************************************/ +struct digi_t { + unsigned short digi_flags; /* Flags (see above) */ + unsigned short digi_maxcps; /* Max printer CPS */ + unsigned short digi_maxchar; /* Max chars in print queue */ + unsigned short digi_bufsize; /* Buffer size */ + unsigned char digi_onlen; /* Length of ON string */ + unsigned char digi_offlen; /* Length of OFF string */ + char digi_onstr[DIGI_PLEN]; /* Printer on string */ + char digi_offstr[DIGI_PLEN]; /* Printer off string */ + char digi_term[DIGI_TSIZ]; /* terminal string */ +}; + +/************************************************************************ + * KME definitions and structures. + ************************************************************************/ +#define RW_IDLE 0 /* Operation complete */ +#define RW_READ 1 /* Read Concentrator Memory */ +#define RW_WRITE 2 /* Write Concentrator Memory */ + +struct rw_t { + unsigned char rw_req; /* Request type */ + unsigned char rw_board; /* Host Adapter board number */ + unsigned char rw_conc; /* Concentrator number */ + unsigned char rw_reserved; /* Reserved for expansion */ + unsigned long rw_addr; /* Address in concentrator */ + unsigned short rw_size; /* Read/write request length */ + unsigned char rw_data[128]; /* Data to read/write */ +}; + +/*********************************************************************** + * Shrink Buffer and Board Information definitions and structures. + + ************************************************************************/ + /* Board type return codes */ +#define PCXI_TYPE 1 /* Board type at the designated port is a PC/Xi */ +#define PCXM_TYPE 2 /* Board type at the designated port is a PC/Xm */ +#define PCXE_TYPE 3 /* Board type at the designated port is a PC/Xe */ +#define MCXI_TYPE 4 /* Board type at the designated port is a MC/Xi */ +#define COMXI_TYPE 5 /* Board type at the designated port is a COM/Xi */ + + /* Non-Zero Result codes. */ +#define RESULT_NOBDFND 1 /* A Digi product at that port is not config installed */ +#define RESULT_NODESCT 2 /* A memory descriptor was not obtainable */ +#define RESULT_NOOSSIG 3 /* FEP/OS signature was not detected on the board */ +#define RESULT_TOOSML 4 /* Too small an area to shrink. */ +#define RESULT_NOCHAN 5 /* Channel structure for the board was not found */ + +struct shrink_buf_struct { + unsigned long shrink_buf_vaddr; /* Virtual address of board */ + unsigned long shrink_buf_phys; /* Physical address of board */ + unsigned long shrink_buf_bseg; /* Amount of board memory */ + unsigned long shrink_buf_hseg; /* '186 Beginning of Dual-Port */ + + unsigned long shrink_buf_lseg; /* '186 Beginning of freed memory */ + unsigned long shrink_buf_mseg; /* Linear address from start of + dual-port were freed memory + begins, host viewpoint. */ + + unsigned long shrink_buf_bdparam; /* Parameter for xxmemon and + xxmemoff */ + + unsigned long shrink_buf_reserva; /* Reserved */ + unsigned long shrink_buf_reservb; /* Reserved */ + unsigned long shrink_buf_reservc; /* Reserved */ + unsigned long shrink_buf_reservd; /* Reserved */ + + unsigned char shrink_buf_result; /* Reason for call failing + Zero is Good return */ + unsigned char shrink_buf_init; /* Non-Zero if it caused an + xxinit call. */ + + unsigned char shrink_buf_anports; /* Number of async ports */ + unsigned char shrink_buf_snports; /* Number of sync ports */ + unsigned char shrink_buf_type; /* Board type 1 = PC/Xi, + 2 = PC/Xm, + 3 = PC/Xe + 4 = MC/Xi + 5 = COMX/i */ + unsigned char shrink_buf_card; /* Card number */ + +}; + +/************************************************************************ + * Structure to get driver status information + ************************************************************************/ +struct digi_dinfo { + unsigned long dinfo_nboards; /* # boards configured */ + char dinfo_reserved[12]; /* for future expansion */ + char dinfo_version[16]; /* driver version */ +}; + +#define DIGI_GETDD ('d'<<8) | 248 /* get driver info */ + +/************************************************************************ + * Structure used with ioctl commands for per-board information + * + * physsize and memsize differ when board has "windowed" memory + ************************************************************************/ +struct digi_info { + unsigned long info_bdnum; /* Board number (0 based) */ + unsigned long info_ioport; /* io port address */ + unsigned long info_physaddr; /* memory address */ + unsigned long info_physsize; /* Size of host mem window */ + unsigned long info_memsize; /* Amount of dual-port mem */ + /* on board */ + unsigned short info_bdtype; /* Board type */ + unsigned short info_nports; /* number of ports */ + char info_bdstate; /* board state */ + char info_reserved[7]; /* for future expansion */ +}; + +#define DIGI_GETBD ('d'<<8) | 249 /* get board info */ + +struct digi_stat { + unsigned int info_chan; /* Channel number (0 based) */ + unsigned int info_brd; /* Board number (0 based) */ + unsigned long info_cflag; /* cflag for channel */ + unsigned long info_iflag; /* iflag for channel */ + unsigned long info_oflag; /* oflag for channel */ + unsigned long info_mstat; /* mstat for channel */ + unsigned long info_tx_data; /* tx_data for channel */ + unsigned long info_rx_data; /* rx_data for channel */ + unsigned long info_hflow; /* hflow for channel */ + unsigned long info_reserved[8]; /* for future expansion */ +}; + +#define DIGI_GETSTAT ('d'<<8) | 244 /* get board info */ +/************************************************************************ + * + * Structure used with ioctl commands for per-channel information + * + ************************************************************************/ +struct digi_ch { + unsigned long info_bdnum; /* Board number (0 based) */ + unsigned long info_channel; /* Channel index number */ + unsigned long info_ch_cflag; /* Channel cflag */ + unsigned long info_ch_iflag; /* Channel iflag */ + unsigned long info_ch_oflag; /* Channel oflag */ + unsigned long info_chsize; /* Channel structure size */ + unsigned long info_sleep_stat; /* sleep status */ + dev_t info_dev; /* device number */ + unsigned char info_initstate; /* Channel init state */ + unsigned char info_running; /* Channel running state */ + long reserved[8]; /* reserved for future use */ +}; + +/* +* This structure is used with the DIGI_FEPCMD ioctl to +* tell the driver which port to send the command for. +*/ +struct digi_cmd { + int cmd; + int word; + int ncmds; + int chan; /* channel index (zero based) */ + int bdid; /* board index (zero based) */ +}; + +/* +* info_sleep_stat defines +*/ +#define INFO_RUNWAIT 0x0001 +#define INFO_WOPEN 0x0002 +#define INFO_TTIOW 0x0004 +#define INFO_CH_RWAIT 0x0008 +#define INFO_CH_WEMPTY 0x0010 +#define INFO_CH_WLOW 0x0020 +#define INFO_XXBUF_BUSY 0x0040 + +#define DIGI_GETCH ('d'<<8) | 245 /* get board info */ + +/* Board type definitions */ + +#define SUBTYPE 0007 +#define T_PCXI 0000 +#define T_PCXM 0001 +#define T_PCXE 0002 +#define T_PCXR 0003 +#define T_SP 0004 +#define T_SP_PLUS 0005 +# define T_HERC 0000 +# define T_HOU 0001 +# define T_LON 0002 +# define T_CHA 0003 +#define FAMILY 0070 +#define T_COMXI 0000 +#define T_PCXX 0010 +#define T_CX 0020 +#define T_EPC 0030 +#define T_PCLITE 0040 +#define T_SPXX 0050 +#define T_AVXX 0060 +#define T_DXB 0070 +#define T_A2K_4_8 0070 +#define BUSTYPE 0700 +#define T_ISABUS 0000 +#define T_MCBUS 0100 +#define T_EISABUS 0200 +#define T_PCIBUS 0400 + +/* Board State Definitions */ + +#define BD_RUNNING 0x0 +#define BD_REASON 0x7f +#define BD_NOTFOUND 0x1 +#define BD_NOIOPORT 0x2 +#define BD_NOMEM 0x3 +#define BD_NOBIOS 0x4 +#define BD_NOFEP 0x5 +#define BD_FAILED 0x6 +#define BD_ALLOCATED 0x7 +#define BD_TRIBOOT 0x8 +#define BD_BADKME 0x80 + +#define DIGI_LOOPBACK ('d'<<8) | 252 /* Enable/disable UART internal loopback */ +#define DIGI_SPOLL ('d'<<8) | 254 /* change poller rate */ + +#define DIGI_SETCUSTOMBAUD _IOW('e', 106, int) /* Set integer baud rate */ +#define DIGI_GETCUSTOMBAUD _IOR('e', 107, int) /* Get integer baud rate */ +#define DIGI_RESET_PORT ('e'<<8) | 93 /* Reset port */ + +/************************************************************************ + * Channel information structure. + ************************************************************************/ +struct channel_t { + int magic; /* Channel Magic Number */ + struct bs_t *ch_bs; /* Base structure pointer */ + struct cm_t *ch_cm; /* Command queue pointer */ + struct board_t *ch_bd; /* Board structure pointer */ + unsigned char *ch_vaddr; /* FEP memory origin */ + unsigned char *ch_taddr; /* Write buffer origin */ + unsigned char *ch_raddr; /* Read buffer origin */ + struct digi_t ch_digi; /* Transparent Print structure */ + struct un_t ch_tun; /* Terminal unit info */ + struct un_t ch_pun; /* Printer unit info */ + + spinlock_t ch_lock; /* provide for serialization */ + wait_queue_head_t ch_flags_wait; + + u32 pscan_state; + uchar pscan_savechar; + + u32 ch_portnum; /* Port number, 0 offset. */ + u32 ch_open_count; /* open count */ + u32 ch_flags; /* Channel flags */ + + + u32 ch_close_delay; /* How long we should drop RTS/DTR for */ + + u32 ch_cpstime; /* Time for CPS calculations */ + + tcflag_t ch_c_iflag; /* channel iflags */ + tcflag_t ch_c_cflag; /* channel cflags */ + tcflag_t ch_c_oflag; /* channel oflags */ + tcflag_t ch_c_lflag; /* channel lflags */ + + u16 ch_fepiflag; /* FEP tty iflags */ + u16 ch_fepcflag; /* FEP tty cflags */ + u16 ch_fepoflag; /* FEP tty oflags */ + u16 ch_wopen; /* Waiting for open process cnt */ + u16 ch_tstart; /* Transmit buffer start */ + u16 ch_tsize; /* Transmit buffer size */ + u16 ch_rstart; /* Receive buffer start */ + u16 ch_rsize; /* Receive buffer size */ + u16 ch_rdelay; /* Receive delay time */ + + u16 ch_tlw; /* Our currently set low water mark */ + + u16 ch_cook; /* Output character mask */ + + uchar ch_card; /* Card channel is on */ + uchar ch_stopc; /* Stop character */ + uchar ch_startc; /* Start character */ + + uchar ch_mostat; /* FEP output modem status */ + uchar ch_mistat; /* FEP input modem status */ + uchar ch_mforce; /* Modem values to be forced */ + uchar ch_mval; /* Force values */ + uchar ch_fepstopc; /* FEP stop character */ + uchar ch_fepstartc; /* FEP start character */ + + uchar ch_astopc; /* Auxiliary Stop character */ + uchar ch_astartc; /* Auxiliary Start character */ + uchar ch_fepastopc; /* Auxiliary FEP stop char */ + uchar ch_fepastartc; /* Auxiliary FEP start char */ + + uchar ch_hflow; /* FEP hardware handshake */ + uchar ch_dsr; /* stores real dsr value */ + uchar ch_cd; /* stores real cd value */ + uchar ch_tx_win; /* channel tx buffer window */ + uchar ch_rx_win; /* channel rx buffer window */ + uint ch_custom_speed; /* Custom baud, if set */ + uint ch_baud_info; /* Current baud info for /proc output */ + ulong ch_rxcount; /* total of data received so far */ + ulong ch_txcount; /* total of data transmitted so far */ + ulong ch_err_parity; /* Count of parity errors on channel */ + ulong ch_err_frame; /* Count of framing errors on channel */ + ulong ch_err_break; /* Count of breaks on channel */ + ulong ch_err_overrun; /* Count of overruns on channel */ + + uint ch_sniff_in; + uint ch_sniff_out; + char *ch_sniff_buf; /* Sniff buffer for proc */ + ulong ch_sniff_flags; /* Channel flags */ + wait_queue_head_t ch_sniff_wait; +}; + +/************************************************************************ + * Command structure definition. + ************************************************************************/ +struct cm_t { + volatile unsigned short cm_head; /* Command buffer head offset */ + volatile unsigned short cm_tail; /* Command buffer tail offset */ + volatile unsigned short cm_start; /* start offset of buffer */ + volatile unsigned short cm_max; /* last offset of buffer */ +}; + +/************************************************************************ + * Event structure definition. + ************************************************************************/ +struct ev_t { + volatile unsigned short ev_head; /* Command buffer head offset */ + volatile unsigned short ev_tail; /* Command buffer tail offset */ + volatile unsigned short ev_start; /* start offset of buffer */ + volatile unsigned short ev_max; /* last offset of buffer */ +}; + +/************************************************************************ + * Download buffer structure. + ************************************************************************/ +struct downld_t { + uchar dl_type; /* Header */ + uchar dl_seq; /* Download sequence */ + ushort dl_srev; /* Software revision number */ + ushort dl_lrev; /* Low revision number */ + ushort dl_hrev; /* High revision number */ + ushort dl_seg; /* Start segment address */ + ushort dl_size; /* Number of bytes to download */ + uchar dl_data[1024]; /* Download data */ +}; + +/************************************************************************ + * Per channel buffer structure + ************************************************************************ + * Base Structure Entries Usage Meanings to Host * + * * + * W = read write R = read only * + * C = changed by commands only * + * U = unknown (may be changed w/o notice) * + ************************************************************************/ +struct bs_t { + volatile unsigned short tp_jmp; /* Transmit poll jump */ + volatile unsigned short tc_jmp; /* Cooked procedure jump */ + volatile unsigned short ri_jmp; /* Not currently used */ + volatile unsigned short rp_jmp; /* Receive poll jump */ + + volatile unsigned short tx_seg; /* W Tx segment */ + volatile unsigned short tx_head; /* W Tx buffer head offset */ + volatile unsigned short tx_tail; /* R Tx buffer tail offset */ + volatile unsigned short tx_max; /* W Tx buffer size - 1 */ + + volatile unsigned short rx_seg; /* W Rx segment */ + volatile unsigned short rx_head; /* W Rx buffer head offset */ + volatile unsigned short rx_tail; /* R Rx buffer tail offset */ + volatile unsigned short rx_max; /* W Rx buffer size - 1 */ + + volatile unsigned short tx_lw; /* W Tx buffer low water mark */ + volatile unsigned short rx_lw; /* W Rx buffer low water mark */ + volatile unsigned short rx_hw; /* W Rx buffer high water mark */ + volatile unsigned short incr; /* W Increment to next channel */ + + volatile unsigned short fepdev; /* U SCC device base address */ + volatile unsigned short edelay; /* W Exception delay */ + volatile unsigned short blen; /* W Break length */ + volatile unsigned short btime; /* U Break complete time */ + + volatile unsigned short iflag; /* C UNIX input flags */ + volatile unsigned short oflag; /* C UNIX output flags */ + volatile unsigned short cflag; /* C UNIX control flags */ + volatile unsigned short wfill[13]; /* U Reserved for expansion */ + + volatile unsigned char num; /* U Channel number */ + volatile unsigned char ract; /* U Receiver active counter */ + volatile unsigned char bstat; /* U Break status bits */ + volatile unsigned char tbusy; /* W Transmit busy */ + volatile unsigned char iempty; /* W Transmit empty event enable */ + volatile unsigned char ilow; /* W Transmit low-water event enable */ + volatile unsigned char idata; /* W Receive data interrupt enable */ + volatile unsigned char eflag; /* U Host event flags */ + + volatile unsigned char tflag; /* U Transmit flags */ + volatile unsigned char rflag; /* U Receive flags */ + volatile unsigned char xmask; /* U Transmit ready flags */ + volatile unsigned char xval; /* U Transmit ready value */ + volatile unsigned char m_stat; /* RC Modem status bits */ + volatile unsigned char m_change; /* U Modem bits which changed */ + volatile unsigned char m_int; /* W Modem interrupt enable bits */ + volatile unsigned char m_last; /* U Last modem status */ + + volatile unsigned char mtran; /* C Unreported modem trans */ + volatile unsigned char orun; /* C Buffer overrun occurred */ + volatile unsigned char astartc; /* W Auxiliary Xon char */ + volatile unsigned char astopc; /* W Auxiliary Xoff char */ + volatile unsigned char startc; /* W Xon character */ + volatile unsigned char stopc; /* W Xoff character */ + volatile unsigned char vnextc; /* W Vnext character */ + volatile unsigned char hflow; /* C Software flow control */ + + volatile unsigned char fillc; /* U Delay Fill character */ + volatile unsigned char ochar; /* U Saved output character */ + volatile unsigned char omask; /* U Output character mask */ + + volatile unsigned char bfill[13]; /* U Reserved for expansion */ + + volatile unsigned char scc[16]; /* U SCC registers */ +}; + +struct cnode { + struct cnode *next; + int type; + int numbrd; + + union { + struct { + char type; /* Board Type */ + short port; /* I/O Address */ + char *portstr; /* I/O Address in string */ + long addr; /* Memory Address */ + char *addrstr; /* Memory Address in string */ + long pcibus; /* PCI BUS */ + char *pcibusstr; /* PCI BUS in string */ + long pcislot; /* PCI SLOT */ + char *pcislotstr; /* PCI SLOT in string */ + char nport; /* Number of Ports */ + char *id; /* tty id */ + int start; /* start of tty counting */ + char *method; /* Install method */ + char v_type; + char v_port; + char v_addr; + char v_pcibus; + char v_pcislot; + char v_nport; + char v_id; + char v_start; + char v_method; + char line1; + char line2; + char conc1; /* total concs in line1 */ + char conc2; /* total concs in line2 */ + char module1; /* total modules for line1 */ + char module2; /* total modules for line2 */ + char *status; /* config status */ + char *dimstatus; /* Y/N */ + int status_index; /* field pointer */ + } board; + + struct { + char *cable; + char v_cable; + char speed; + char v_speed; + } line; + + struct { + char type; + char *connect; + char speed; + char nport; + char *id; + char *idstr; + int start; + char v_type; + char v_connect; + char v_speed; + char v_nport; + char v_id; + char v_start; + } conc; + + struct { + char type; + char nport; + char *id; + char *idstr; + int start; + char v_type; + char v_nport; + char v_id; + char v_start; + } module; + + char *ttyname; + + char *cuname; + + char *printname; + + int majornumber; + + int altpin; + + int ttysize; + + int chsize; + + int bssize; + + int unsize; + + int f2size; + + int vpixsize; + + int useintr; + } u; +}; + +#endif diff --git a/drivers/staging/dgap/dgap_conf.h b/drivers/staging/dgap/dgap_conf.h deleted file mode 100644 index 484ed726a4d..00000000000 --- a/drivers/staging/dgap/dgap_conf.h +++ /dev/null @@ -1,290 +0,0 @@ -/* - * Copyright 2003 Digi International (www.digi.com) - * Scott H Kilau <Scott_Kilau at digi dot com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the - * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - ***************************************************************************** - * - * dgap_conf.h - Header file for installations and parse files. - * - * $Id: dgap_conf.h,v 1.1 2009/10/23 14:01:57 markh Exp $ - * - * NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!! - */ - -#ifndef _DGAP_CONF_H -#define _DGAP_CONF_H - -#define NULLNODE 0 /* header node, not used */ -#define BNODE 1 /* Board node */ -#define LNODE 2 /* Line node */ -#define CNODE 3 /* Concentrator node */ -#define MNODE 4 /* EBI Module node */ -#define TNODE 5 /* tty name prefix node */ -#define CUNODE 6 /* cu name prefix (non-SCO) */ -#define PNODE 7 /* trans. print prefix node */ -#define JNODE 8 /* maJor number node */ -#define ANODE 9 /* altpin */ -#define TSNODE 10 /* tty structure size */ -#define CSNODE 11 /* channel structure size */ -#define BSNODE 12 /* board structure size */ -#define USNODE 13 /* unit schedule structure size */ -#define FSNODE 14 /* f2200 structure size */ -#define VSNODE 15 /* size of VPIX structures */ -#define INTRNODE 16 /* enable interrupt */ - -/* Enumeration of tokens */ -#define BEGIN 1 -#define END 2 -#define BOARD 10 - -#define EPCFS 11 /* start of EPC family definitions */ -#define ICX 11 -#define MCX 13 -#define PCX 14 -#define IEPC 15 -#define EEPC 16 -#define MEPC 17 -#define IPCM 18 -#define EPCM 19 -#define MPCM 20 -#define PEPC 21 -#define PPCM 22 -#ifdef CP -#define ICP 23 -#define ECP 24 -#define MCP 25 -#endif -#define EPCFE 25 /* end of EPC family definitions */ -#define PC2E 26 -#define PC4E 27 -#define PC4E8K 28 -#define PC8E 29 -#define PC8E8K 30 -#define PC16E 31 -#define MC2E8K 34 -#define MC4E8K 35 -#define MC8E8K 36 - -#define AVANFS 42 /* start of Avanstar family definitions */ -#define A8P 42 -#define A16P 43 -#define AVANFE 43 /* end of Avanstar family definitions */ - -#define DA2000FS 44 /* start of AccelePort 2000 family definitions */ -#define DA22 44 /* AccelePort 2002 */ -#define DA24 45 /* AccelePort 2004 */ -#define DA28 46 /* AccelePort 2008 */ -#define DA216 47 /* AccelePort 2016 */ -#define DAR4 48 /* AccelePort RAS 4 port */ -#define DAR8 49 /* AccelePort RAS 8 port */ -#define DDR24 50 /* DataFire RAS 24 port */ -#define DDR30 51 /* DataFire RAS 30 port */ -#define DDR48 52 /* DataFire RAS 48 port */ -#define DDR60 53 /* DataFire RAS 60 port */ -#define DA2000FE 53 /* end of AccelePort 2000/RAS family definitions */ - -#define PCXRFS 106 /* start of PCXR family definitions */ -#define APORT4 106 -#define APORT8 107 -#define PAPORT4 108 -#define PAPORT8 109 -#define APORT4_920I 110 -#define APORT8_920I 111 -#define APORT4_920P 112 -#define APORT8_920P 113 -#define APORT2_920P 114 -#define PCXRFE 117 /* end of PCXR family definitions */ - -#define LINE 82 -#ifdef T1 -#define T1M 83 -#define E1M 84 -#endif -#define CONC 64 -#define CX 65 -#define EPC 66 -#define MOD 67 -#define PORTS 68 -#define METHOD 69 -#define CUSTOM 70 -#define BASIC 71 -#define STATUS 72 -#define MODEM 73 -/* The following tokens can appear in multiple places */ -#define SPEED 74 -#define NPORTS 75 -#define ID 76 -#define CABLE 77 -#define CONNECT 78 -#define IO 79 -#define MEM 80 -#define DPSZ 81 - -#define TTYN 90 -#define CU 91 -#define PRINT 92 -#define XPRINT 93 -#define CMAJOR 94 -#define ALTPIN 95 -#define STARTO 96 -#define USEINTR 97 -#define PCIINFO 98 - -#define TTSIZ 100 -#define CHSIZ 101 -#define BSSIZ 102 -#define UNTSIZ 103 -#define F2SIZ 104 -#define VPSIZ 105 - -#define TOTAL_BOARD 2 -#define CURRENT_BRD 4 -#define BOARD_TYPE 6 -#define IO_ADDRESS 8 -#define MEM_ADDRESS 10 - -#define FIELDS_PER_PAGE 18 - -#define TB_FIELD 1 -#define CB_FIELD 3 -#define BT_FIELD 5 -#define IO_FIELD 7 -#define ID_FIELD 8 -#define ME_FIELD 9 -#define TTY_FIELD 11 -#define CU_FIELD 13 -#define PR_FIELD 15 -#define MPR_FIELD 17 - -#define MAX_FIELD 512 - -#define INIT 0 -#define NITEMS 128 -#define MAX_ITEM 512 - -#define DSCRINST 1 -#define DSCRNUM 3 -#define ALTPINQ 5 -#define SSAVE 7 - -#define DSCR "32" -#define ONETONINE "123456789" -#define ALL "1234567890" - - -struct cnode { - struct cnode *next; - int type; - int numbrd; - - union { - struct { - char type; /* Board Type */ - short port; /* I/O Address */ - char *portstr; /* I/O Address in string */ - long addr; /* Memory Address */ - char *addrstr; /* Memory Address in string */ - long pcibus; /* PCI BUS */ - char *pcibusstr; /* PCI BUS in string */ - long pcislot; /* PCI SLOT */ - char *pcislotstr; /* PCI SLOT in string */ - char nport; /* Number of Ports */ - char *id; /* tty id */ - int start; /* start of tty counting */ - char *method; /* Install method */ - char v_type; - char v_port; - char v_addr; - char v_pcibus; - char v_pcislot; - char v_nport; - char v_id; - char v_start; - char v_method; - char line1; - char line2; - char conc1; /* total concs in line1 */ - char conc2; /* total concs in line2 */ - char module1; /* total modules for line1 */ - char module2; /* total modules for line2 */ - char *status; /* config status */ - char *dimstatus; /* Y/N */ - int status_index; /* field pointer */ - } board; - - struct { - char *cable; - char v_cable; - char speed; - char v_speed; - } line; - - struct { - char type; - char *connect; - char speed; - char nport; - char *id; - char *idstr; - int start; - char v_type; - char v_connect; - char v_speed; - char v_nport; - char v_id; - char v_start; - } conc; - - struct { - char type; - char nport; - char *id; - char *idstr; - int start; - char v_type; - char v_nport; - char v_id; - char v_start; - } module; - - char *ttyname; - - char *cuname; - - char *printname; - - int majornumber; - - int altpin; - - int ttysize; - - int chsize; - - int bssize; - - int unsize; - - int f2size; - - int vpixsize; - - int useintr; - } u; -}; - -#endif diff --git a/drivers/staging/dgap/dgap_downld.h b/drivers/staging/dgap/dgap_downld.h deleted file mode 100644 index 910a45d3f1f..00000000000 --- a/drivers/staging/dgap/dgap_downld.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2003 Digi International (www.digi.com) - * Scott H Kilau <Scott_Kilau at digi dot com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the - * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * $Id: dgap_downld.h,v 1.1 2009/10/23 14:01:57 markh Exp $ - * - * NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!! - * - */ - -/* -** downld.h -** - describes the interface between the user level download process -** and the concentrator download driver. -*/ - -#ifndef _DGAP_DOWNLD_H_ -#define _DGAP_DOWNLD_H_ - - -struct fepimg { - int type; /* board type */ - int len; /* length of image */ - char fepimage[1]; /* beginning of image */ -}; - -struct downldio { - unsigned int req_type; /* FEP or concentrator */ - unsigned int bdid; /* opaque board identifier */ - union { - struct downld_t dl; /* download structure */ - struct fepimg fi; /* fep/bios image structure */ - } image; -}; - -#define DIGI_DLREQ_GET (('d'<<8) | 220) -#define DIGI_DLREQ_SET (('d'<<8) | 221) - -#define DIGI_DL_NUKE (('d'<<8) | 222) /* Not really a dl request, but - dangerous enuff to not put in - digi.h */ -/* Packed bits of intarg for DIGI_DL_NUKE */ -#define DIGI_NUKE_RESET_ALL (1 << 31) -#define DIGI_NUKE_INHIBIT_POLLER (1 << 30) -#define DIGI_NUKE_BRD_NUMB 0x0f - - - -#define DLREQ_BIOS 0 -#define DLREQ_FEP 1 -#define DLREQ_CONC 2 -#define DLREQ_CONFIG 3 -#define DLREQ_DEVCREATE 4 - -#endif diff --git a/drivers/staging/dgap/dgap_driver.c b/drivers/staging/dgap/dgap_driver.c deleted file mode 100644 index 11dd6dd51dd..00000000000 --- a/drivers/staging/dgap/dgap_driver.c +++ /dev/null @@ -1,1030 +0,0 @@ -/* - * Copyright 2003 Digi International (www.digi.com) - * Scott H Kilau <Scott_Kilau at digi dot com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the - * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * - * NOTE TO LINUX KERNEL HACKERS: DO NOT REFORMAT THIS CODE! - * - * This is shared code between Digi's CVS archive and the - * Linux Kernel sources. - * Changing the source just for reformatting needlessly breaks - * our CVS diff history. - * - * Send any bug fixes/changes to: Eng.Linux at digi dot com. - * Thank you. - * - * $Id: dgap_driver.c,v 1.3 2011/06/21 10:35:16 markh Exp $ - */ - - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/pci.h> -#include <linux/delay.h> /* For udelay */ -#include <linux/slab.h> -#include <asm/uaccess.h> /* For copy_from_user/copy_to_user */ -#include <linux/sched.h> - -#include "dgap_driver.h" -#include "dgap_pci.h" -#include "dgap_fep5.h" -#include "dgap_tty.h" -#include "dgap_conf.h" -#include "dgap_parse.h" -#include "dgap_trace.h" -#include "dgap_sysfs.h" - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Digi International, http://www.digi.com"); -MODULE_DESCRIPTION("Driver for the Digi International EPCA PCI based product line"); -MODULE_SUPPORTED_DEVICE("dgap"); - -/* - * insmod command line overrideable parameters - * - * NOTE: we use a set of macros to create the variables, which allows - * us to specify the variable type, name, initial value, and description. - */ -PARM_INT(debug, 0x00, 0644, "Driver debugging level"); -PARM_INT(rawreadok, 1, 0644, "Bypass flip buffers on input"); -PARM_INT(trcbuf_size, 0x100000, 0644, "Debugging trace buffer size."); - - -/************************************************************************** - * - * protos for this file - * - */ - -static int dgap_start(void); -static void dgap_init_globals(void); -static int dgap_found_board(struct pci_dev *pdev, int id); -static void dgap_cleanup_board(struct board_t *brd); -static void dgap_poll_handler(ulong dummy); -static int dgap_init_pci(void); -static int dgap_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); -static void dgap_remove_one(struct pci_dev *dev); -static int dgap_probe1(struct pci_dev *pdev, int card_type); -static void dgap_mbuf(struct board_t *brd, const char *fmt, ...); -static int dgap_do_remap(struct board_t *brd); -static irqreturn_t dgap_intr(int irq, void *voidbrd); - -/* Driver load/unload functions */ -int dgap_init_module(void); -void dgap_cleanup_module(void); - -module_init(dgap_init_module); -module_exit(dgap_cleanup_module); - - -/* - * File operations permitted on Control/Management major. - */ -static struct file_operations DgapBoardFops = -{ - .owner = THIS_MODULE, -}; - - -/* - * Globals - */ -uint dgap_NumBoards; -struct board_t *dgap_Board[MAXBOARDS]; -DEFINE_SPINLOCK(dgap_global_lock); -ulong dgap_poll_counter; -char *dgap_config_buf; -int dgap_driver_state = DRIVER_INITIALIZED; -DEFINE_SPINLOCK(dgap_dl_lock); -wait_queue_head_t dgap_dl_wait; -int dgap_dl_action; -int dgap_poll_tick = 20; /* Poll interval - 20 ms */ - -/* - * Static vars. - */ -static int dgap_Major_Control_Registered = FALSE; -static uint dgap_driver_start = FALSE; - -static struct class * dgap_class; - -/* - * Poller stuff - */ -static DEFINE_SPINLOCK(dgap_poll_lock); /* Poll scheduling lock */ -static ulong dgap_poll_time; /* Time of next poll */ -static uint dgap_poll_stop; /* Used to tell poller to stop */ -static struct timer_list dgap_poll_timer; - - -static struct pci_device_id dgap_pci_tbl[] = { - { DIGI_VID, PCI_DEVICE_XEM_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { DIGI_VID, PCI_DEVICE_CX_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 }, - { DIGI_VID, PCI_DEVICE_CX_IBM_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2 }, - { DIGI_VID, PCI_DEVICE_EPCJ_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3 }, - { DIGI_VID, PCI_DEVICE_920_2_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 }, - { DIGI_VID, PCI_DEVICE_920_4_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5 }, - { DIGI_VID, PCI_DEVICE_920_8_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6 }, - { DIGI_VID, PCI_DEVICE_XR_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 7 }, - { DIGI_VID, PCI_DEVICE_XRJ_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 }, - { DIGI_VID, PCI_DEVICE_XR_422_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 9 }, - { DIGI_VID, PCI_DEVICE_XR_IBM_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 10 }, - { DIGI_VID, PCI_DEVICE_XR_SAIP_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 11 }, - { DIGI_VID, PCI_DEVICE_XR_BULL_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 12 }, - { DIGI_VID, PCI_DEVICE_920_8_HP_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 13 }, - { DIGI_VID, PCI_DEVICE_XEM_HP_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 14 }, - {0,} /* 0 terminated list. */ -}; -MODULE_DEVICE_TABLE(pci, dgap_pci_tbl); - - -/* - * A generic list of Product names, PCI Vendor ID, and PCI Device ID. - */ -struct board_id { - uint config_type; - uchar *name; - uint maxports; - uint dpatype; -}; - -static struct board_id dgap_Ids[] = -{ - { PPCM, PCI_DEVICE_XEM_NAME, 64, (T_PCXM | T_PCLITE | T_PCIBUS) }, - { PCX, PCI_DEVICE_CX_NAME, 128, (T_CX | T_PCIBUS) }, - { PCX, PCI_DEVICE_CX_IBM_NAME, 128, (T_CX | T_PCIBUS) }, - { PEPC, PCI_DEVICE_EPCJ_NAME, 224, (T_EPC | T_PCIBUS) }, - { APORT2_920P, PCI_DEVICE_920_2_NAME, 2, (T_PCXR | T_PCLITE | T_PCIBUS) }, - { APORT4_920P, PCI_DEVICE_920_4_NAME, 4, (T_PCXR | T_PCLITE | T_PCIBUS) }, - { APORT8_920P, PCI_DEVICE_920_8_NAME, 8, (T_PCXR | T_PCLITE | T_PCIBUS) }, - { PAPORT8, PCI_DEVICE_XR_NAME, 8, (T_PCXR | T_PCLITE | T_PCIBUS) }, - { PAPORT8, PCI_DEVICE_XRJ_NAME, 8, (T_PCXR | T_PCLITE | T_PCIBUS) }, - { PAPORT8, PCI_DEVICE_XR_422_NAME, 8, (T_PCXR | T_PCLITE | T_PCIBUS) }, - { PAPORT8, PCI_DEVICE_XR_IBM_NAME, 8, (T_PCXR | T_PCLITE | T_PCIBUS) }, - { PAPORT8, PCI_DEVICE_XR_SAIP_NAME, 8, (T_PCXR | T_PCLITE | T_PCIBUS) }, - { PAPORT8, PCI_DEVICE_XR_BULL_NAME, 8, (T_PCXR | T_PCLITE | T_PCIBUS) }, - { APORT8_920P, PCI_DEVICE_920_8_HP_NAME, 8, (T_PCXR | T_PCLITE | T_PCIBUS) }, - { PPCM, PCI_DEVICE_XEM_HP_NAME, 64, (T_PCXM | T_PCLITE | T_PCIBUS) }, - {0,} /* 0 terminated list. */ -}; - -static struct pci_driver dgap_driver = { - .name = "dgap", - .probe = dgap_init_one, - .id_table = dgap_pci_tbl, - .remove = dgap_remove_one, -}; - - -char *dgap_state_text[] = { - "Board Failed", - "Configuration for board not found.\n\t\t\tRun mpi to configure board.", - "Board Found", - "Need Reset", - "Finished Reset", - "Need Config", - "Finished Config", - "Need Device Creation", - "Requested Device Creation", - "Finished Device Creation", - "Need BIOS Load", - "Requested BIOS", - "Doing BIOS Load", - "Finished BIOS Load", - "Need FEP Load", - "Requested FEP", - "Doing FEP Load", - "Finished FEP Load", - "Requested PROC creation", - "Finished PROC creation", - "Board READY", -}; - -char *dgap_driver_state_text[] = { - "Driver Initialized", - "Driver needs configuration load.", - "Driver requested configuration from download daemon.", - "Driver Ready." -}; - - - -/************************************************************************ - * - * Driver load/unload functions - * - ************************************************************************/ - -/* - * init_module() - * - * Module load. This is where it all starts. - */ -int dgap_init_module(void) -{ - int rc = 0; - - APR(("%s, Digi International Part Number %s\n", DG_NAME, DG_PART)); - - /* - * Initialize global stuff - */ - rc = dgap_start(); - - if (rc < 0) { - return(rc); - } - - /* - * Find and configure all the cards - */ - rc = dgap_init_pci(); - - /* - * If something went wrong in the scan, bail out of driver. - */ - if (rc < 0) { - /* Only unregister the pci driver if it was actually registered. */ - if (dgap_NumBoards) - pci_unregister_driver(&dgap_driver); - else - printk("WARNING: dgap driver load failed. No DGAP boards found.\n"); - - dgap_cleanup_module(); - } - else { - dgap_create_driver_sysfiles(&dgap_driver); - } - - DPR_INIT(("Finished init_module. Returning %d\n", rc)); - return (rc); -} - - -/* - * Start of driver. - */ -static int dgap_start(void) -{ - int rc = 0; - unsigned long flags; - - if (dgap_driver_start == FALSE) { - - dgap_driver_start = TRUE; - - /* make sure that the globals are init'd before we do anything else */ - dgap_init_globals(); - - dgap_NumBoards = 0; - - APR(("For the tools package or updated drivers please visit http://www.digi.com\n")); - - /* - * Register our base character device into the kernel. - * This allows the download daemon to connect to the downld device - * before any of the boards are init'ed. - */ - if (!dgap_Major_Control_Registered) { - /* - * Register management/dpa devices - */ - rc = register_chrdev(DIGI_DGAP_MAJOR, "dgap", &DgapBoardFops); - if (rc < 0) { - APR(("Can't register dgap driver device (%d)\n", rc)); - return (rc); - } - - dgap_class = class_create(THIS_MODULE, "dgap_mgmt"); - device_create(dgap_class, NULL, - MKDEV(DIGI_DGAP_MAJOR, 0), - NULL, "dgap_mgmt"); - device_create(dgap_class, NULL, - MKDEV(DIGI_DGAP_MAJOR, 1), - NULL, "dgap_downld"); - dgap_Major_Control_Registered = TRUE; - } - - /* - * Init any global tty stuff. - */ - rc = dgap_tty_preinit(); - - if (rc < 0) { - APR(("tty preinit - not enough memory (%d)\n", rc)); - return(rc); - } - - /* Start the poller */ - DGAP_LOCK(dgap_poll_lock, flags); - init_timer(&dgap_poll_timer); - dgap_poll_timer.function = dgap_poll_handler; - dgap_poll_timer.data = 0; - dgap_poll_time = jiffies + dgap_jiffies_from_ms(dgap_poll_tick); - dgap_poll_timer.expires = dgap_poll_time; - DGAP_UNLOCK(dgap_poll_lock, flags); - - add_timer(&dgap_poll_timer); - - dgap_driver_state = DRIVER_NEED_CONFIG_LOAD; - } - - return (rc); -} - - -/* - * Register pci driver, and return how many boards we have. - */ -static int dgap_init_pci(void) -{ - return pci_register_driver(&dgap_driver); -} - - -/* returns count (>= 0), or negative on error */ -static int dgap_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) -{ - int rc; - - /* wake up and enable device */ - rc = pci_enable_device(pdev); - - if (rc < 0) { - rc = -EIO; - } else { - rc = dgap_probe1(pdev, ent->driver_data); - if (rc == 0) { - dgap_NumBoards++; - DPR_INIT(("Incrementing numboards to %d\n", dgap_NumBoards)); - } - } - return rc; -} - - -static int dgap_probe1(struct pci_dev *pdev, int card_type) -{ - return dgap_found_board(pdev, card_type); -} - - -static void dgap_remove_one(struct pci_dev *dev) -{ - /* Do Nothing */ -} - - -/* - * dgap_cleanup_module() - * - * Module unload. This is where it all ends. - */ -void dgap_cleanup_module(void) -{ - int i; - ulong lock_flags; - - DGAP_LOCK(dgap_poll_lock, lock_flags); - dgap_poll_stop = 1; - DGAP_UNLOCK(dgap_poll_lock, lock_flags); - - /* Turn off poller right away. */ - del_timer_sync( &dgap_poll_timer); - - dgap_remove_driver_sysfiles(&dgap_driver); - - - if (dgap_Major_Control_Registered) { - device_destroy(dgap_class, MKDEV(DIGI_DGAP_MAJOR, 0)); - device_destroy(dgap_class, MKDEV(DIGI_DGAP_MAJOR, 1)); - class_destroy(dgap_class); - unregister_chrdev(DIGI_DGAP_MAJOR, "dgap"); - } - - kfree(dgap_config_buf); - - for (i = 0; i < dgap_NumBoards; ++i) { - dgap_remove_ports_sysfiles(dgap_Board[i]); - dgap_tty_uninit(dgap_Board[i]); - dgap_cleanup_board(dgap_Board[i]); - } - - dgap_tty_post_uninit(); - -#if defined(DGAP_TRACER) - /* last thing, make sure we release the tracebuffer */ - dgap_tracer_free(); -#endif - if (dgap_NumBoards) - pci_unregister_driver(&dgap_driver); -} - - -/* - * dgap_cleanup_board() - * - * Free all the memory associated with a board - */ -static void dgap_cleanup_board(struct board_t *brd) -{ - int i = 0; - - if(!brd || brd->magic != DGAP_BOARD_MAGIC) - return; - - if (brd->intr_used && brd->irq) - free_irq(brd->irq, brd); - - tasklet_kill(&brd->helper_tasklet); - - if (brd->re_map_port) { - release_mem_region(brd->membase + 0x200000, 0x200000); - iounmap(brd->re_map_port); - brd->re_map_port = NULL; - } - - if (brd->re_map_membase) { - release_mem_region(brd->membase, 0x200000); - iounmap(brd->re_map_membase); - brd->re_map_membase = NULL; - } - - if (brd->msgbuf_head) { - unsigned long flags; - - DGAP_LOCK(dgap_global_lock, flags); - brd->msgbuf = NULL; - printk("%s", brd->msgbuf_head); - kfree(brd->msgbuf_head); - brd->msgbuf_head = NULL; - DGAP_UNLOCK(dgap_global_lock, flags); - } - - /* Free all allocated channels structs */ - for (i = 0; i < MAXPORTS ; i++) { - if (brd->channels[i]) { - kfree(brd->channels[i]); - brd->channels[i] = NULL; - } - } - - kfree(brd->flipbuf); - kfree(brd->flipflagbuf); - - dgap_Board[brd->boardnum] = NULL; - - kfree(brd); -} - - -/* - * dgap_found_board() - * - * A board has been found, init it. - */ -static int dgap_found_board(struct pci_dev *pdev, int id) -{ - struct board_t *brd; - unsigned int pci_irq; - int i = 0; - unsigned long flags; - - /* get the board structure and prep it */ - brd = dgap_Board[dgap_NumBoards] = - (struct board_t *) kzalloc(sizeof(struct board_t), GFP_KERNEL); - if (!brd) { - APR(("memory allocation for board structure failed\n")); - return(-ENOMEM); - } - - /* make a temporary message buffer for the boot messages */ - brd->msgbuf = brd->msgbuf_head = - (char *) kzalloc(sizeof(char) * 8192, GFP_KERNEL); - if(!brd->msgbuf) { - kfree(brd); - APR(("memory allocation for board msgbuf failed\n")); - return(-ENOMEM); - } - - /* store the info for the board we've found */ - brd->magic = DGAP_BOARD_MAGIC; - brd->boardnum = dgap_NumBoards; - brd->firstminor = 0; - brd->vendor = dgap_pci_tbl[id].vendor; - brd->device = dgap_pci_tbl[id].device; - brd->pdev = pdev; - brd->pci_bus = pdev->bus->number; - brd->pci_slot = PCI_SLOT(pdev->devfn); - brd->name = dgap_Ids[id].name; - brd->maxports = dgap_Ids[id].maxports; - brd->type = dgap_Ids[id].config_type; - brd->dpatype = dgap_Ids[id].dpatype; - brd->dpastatus = BD_NOFEP; - init_waitqueue_head(&brd->state_wait); - - DGAP_SPINLOCK_INIT(brd->bd_lock); - - brd->state = BOARD_FOUND; - brd->runwait = 0; - brd->inhibit_poller = FALSE; - brd->wait_for_bios = 0; - brd->wait_for_fep = 0; - - for (i = 0; i < MAXPORTS; i++) { - brd->channels[i] = NULL; - } - - /* store which card & revision we have */ - pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, &brd->subvendor); - pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &brd->subdevice); - pci_read_config_byte(pdev, PCI_REVISION_ID, &brd->rev); - - pci_irq = pdev->irq; - brd->irq = pci_irq; - - /* get the PCI Base Address Registers */ - - /* Xr Jupiter and EPC use BAR 2 */ - if (brd->device == PCI_DEVICE_XRJ_DID || brd->device == PCI_DEVICE_EPCJ_DID) { - brd->membase = pci_resource_start(pdev, 2); - brd->membase_end = pci_resource_end(pdev, 2); - } - /* Everyone else uses BAR 0 */ - else { - brd->membase = pci_resource_start(pdev, 0); - brd->membase_end = pci_resource_end(pdev, 0); - } - - if (!brd->membase) { - APR(("card has no PCI IO resources, failing board.\n")); - return -ENODEV; - } - - if (brd->membase & 1) - brd->membase &= ~3; - else - brd->membase &= ~15; - - /* - * On the PCI boards, there is no IO space allocated - * The I/O registers will be in the first 3 bytes of the - * upper 2MB of the 4MB memory space. The board memory - * will be mapped into the low 2MB of the 4MB memory space - */ - brd->port = brd->membase + PCI_IO_OFFSET; - brd->port_end = brd->port + PCI_IO_SIZE; - - - /* - * Special initialization for non-PLX boards - */ - if (brd->device != PCI_DEVICE_XRJ_DID && brd->device != PCI_DEVICE_EPCJ_DID) { - unsigned short cmd; - - pci_write_config_byte(pdev, 0x40, 0); - pci_write_config_byte(pdev, 0x46, 0); - - /* Limit burst length to 2 doubleword transactions */ - pci_write_config_byte(pdev, 0x42, 1); - - /* - * Enable IO and mem if not already done. - * This was needed for support on Itanium. - */ - pci_read_config_word(pdev, PCI_COMMAND, &cmd); - cmd |= (PCI_COMMAND_IO | PCI_COMMAND_MEMORY); - pci_write_config_word(pdev, PCI_COMMAND, cmd); - } - - /* init our poll helper tasklet */ - tasklet_init(&brd->helper_tasklet, dgap_poll_tasklet, (unsigned long) brd); - - /* Log the information about the board */ - dgap_mbuf(brd, DRVSTR": board %d: %s (rev %d), irq %d\n", - dgap_NumBoards, brd->name, brd->rev, brd->irq); - - DPR_INIT(("dgap_scan(%d) - printing out the msgbuf\n", i)); - DGAP_LOCK(dgap_global_lock, flags); - brd->msgbuf = NULL; - printk("%s", brd->msgbuf_head); - kfree(brd->msgbuf_head); - brd->msgbuf_head = NULL; - DGAP_UNLOCK(dgap_global_lock, flags); - - i = dgap_do_remap(brd); - if (i) - brd->state = BOARD_FAILED; - else - brd->state = NEED_RESET; - - return(0); -} - - -int dgap_finalize_board_init(struct board_t *brd) { - - int rc; - - DPR_INIT(("dgap_finalize_board_init() - start\n")); - - if (!brd || brd->magic != DGAP_BOARD_MAGIC) - return(-ENODEV); - - DPR_INIT(("dgap_finalize_board_init() - start #2\n")); - - brd->use_interrupts = dgap_config_get_useintr(brd); - - /* - * Set up our interrupt handler if we are set to do interrupts. - */ - if (brd->use_interrupts && brd->irq) { - - rc = request_irq(brd->irq, dgap_intr, IRQF_SHARED, "DGAP", brd); - - if (rc) { - dgap_mbuf(brd, DRVSTR": Failed to hook IRQ %d. Board will work in poll mode.\n", - brd->irq); - brd->intr_used = 0; - } - else - brd->intr_used = 1; - } else { - brd->intr_used = 0; - } - - return(0); -} - - -/* - * Remap PCI memory. - */ -static int dgap_do_remap(struct board_t *brd) -{ - if (!brd || brd->magic != DGAP_BOARD_MAGIC) - return -ENXIO; - - if (!request_mem_region(brd->membase, 0x200000, "dgap")) { - APR(("dgap: mem_region %lx already in use.\n", brd->membase)); - return -ENOMEM; - } - - if (!request_mem_region(brd->membase + PCI_IO_OFFSET, 0x200000, "dgap")) { - APR(("dgap: mem_region IO %lx already in use.\n", - brd->membase + PCI_IO_OFFSET)); - release_mem_region(brd->membase, 0x200000); - return -ENOMEM; - } - - brd->re_map_membase = ioremap(brd->membase, 0x200000); - if (!brd->re_map_membase) { - APR(("dgap: ioremap mem %lx cannot be mapped.\n", brd->membase)); - release_mem_region(brd->membase, 0x200000); - release_mem_region(brd->membase + PCI_IO_OFFSET, 0x200000); - return -ENOMEM; - } - - brd->re_map_port = ioremap((brd->membase + PCI_IO_OFFSET), 0x200000); - if (!brd->re_map_port) { - release_mem_region(brd->membase, 0x200000); - release_mem_region(brd->membase + PCI_IO_OFFSET, 0x200000); - iounmap(brd->re_map_membase); - APR(("dgap: ioremap IO mem %lx cannot be mapped.\n", - brd->membase + PCI_IO_OFFSET)); - return -ENOMEM; - } - - DPR_INIT(("remapped io: 0x%p remapped mem: 0x%p\n", - brd->re_map_port, brd->re_map_membase)); - return 0; -} - - -/***************************************************************************** -* -* Function: -* -* dgap_poll_handler -* -* Author: -* -* Scott H Kilau -* -* Parameters: -* -* dummy -- ignored -* -* Return Values: -* -* none -* -* Description: -* -* As each timer expires, it determines (a) whether the "transmit" -* waiter needs to be woken up, and (b) whether the poller needs to -* be rescheduled. -* -******************************************************************************/ - -static void dgap_poll_handler(ulong dummy) -{ - int i; - struct board_t *brd; - unsigned long lock_flags; - unsigned long lock_flags2; - ulong new_time; - - dgap_poll_counter++; - - - /* - * If driver needs the config file still, - * keep trying to wake up the downloader to - * send us the file. - */ - if (dgap_driver_state == DRIVER_NEED_CONFIG_LOAD) { - /* - * Signal downloader, its got some work to do. - */ - DGAP_LOCK(dgap_dl_lock, lock_flags2); - if (dgap_dl_action != 1) { - dgap_dl_action = 1; - wake_up_interruptible(&dgap_dl_wait); - } - DGAP_UNLOCK(dgap_dl_lock, lock_flags2); - goto schedule_poller; - } - /* - * Do not start the board state machine until - * driver tells us its up and running, and has - * everything it needs. - */ - else if (dgap_driver_state != DRIVER_READY) { - goto schedule_poller; - } - - /* - * If we have just 1 board, or the system is not SMP, - * then use the typical old style poller. - * Otherwise, use our new tasklet based poller, which should - * speed things up for multiple boards. - */ - if ( (dgap_NumBoards == 1) || (num_online_cpus() <= 1) ) { - for (i = 0; i < dgap_NumBoards; i++) { - - brd = dgap_Board[i]; - - if (brd->state == BOARD_FAILED) { - continue; - } - if (!brd->intr_running) { - /* Call the real board poller directly */ - dgap_poll_tasklet((unsigned long) brd); - } - } - } - else { - /* Go thru each board, kicking off a tasklet for each if needed */ - for (i = 0; i < dgap_NumBoards; i++) { - brd = dgap_Board[i]; - - /* - * Attempt to grab the board lock. - * - * If we can't get it, no big deal, the next poll will get it. - * Basically, I just really don't want to spin in here, because I want - * to kick off my tasklets as fast as I can, and then get out the poller. - */ - if (!spin_trylock(&brd->bd_lock)) { - continue; - } - - /* If board is in a failed state, don't bother scheduling a tasklet */ - if (brd->state == BOARD_FAILED) { - spin_unlock(&brd->bd_lock); - continue; - } - - /* Schedule a poll helper task */ - if (!brd->intr_running) { - tasklet_schedule(&brd->helper_tasklet); - } - - /* - * Can't do DGAP_UNLOCK here, as we don't have - * lock_flags because we did a trylock above. - */ - spin_unlock(&brd->bd_lock); - } - } - -schedule_poller: - - /* - * Schedule ourself back at the nominal wakeup interval. - */ - DGAP_LOCK(dgap_poll_lock, lock_flags ); - dgap_poll_time += dgap_jiffies_from_ms(dgap_poll_tick); - - new_time = dgap_poll_time - jiffies; - - if ((ulong) new_time >= 2 * dgap_poll_tick) { - dgap_poll_time = jiffies + dgap_jiffies_from_ms(dgap_poll_tick); - } - - dgap_poll_timer.function = dgap_poll_handler; - dgap_poll_timer.data = 0; - dgap_poll_timer.expires = dgap_poll_time; - DGAP_UNLOCK(dgap_poll_lock, lock_flags ); - - if (!dgap_poll_stop) - add_timer(&dgap_poll_timer); -} - - - - -/* - * dgap_intr() - * - * Driver interrupt handler. - */ -static irqreturn_t dgap_intr(int irq, void *voidbrd) -{ - struct board_t *brd = (struct board_t *) voidbrd; - - if (!brd) { - APR(("Received interrupt (%d) with null board associated\n", irq)); - return IRQ_NONE; - } - - /* - * Check to make sure its for us. - */ - if (brd->magic != DGAP_BOARD_MAGIC) { - APR(("Received interrupt (%d) with a board pointer that wasn't ours!\n", irq)); - return IRQ_NONE; - } - - brd->intr_count++; - - /* - * Schedule tasklet to run at a better time. - */ - tasklet_schedule(&brd->helper_tasklet); - return IRQ_HANDLED; -} - - -/* - * dgap_init_globals() - * - * This is where we initialize the globals from the static insmod - * configuration variables. These are declared near the head of - * this file. - */ -static void dgap_init_globals(void) -{ - int i = 0; - - dgap_rawreadok = rawreadok; - dgap_trcbuf_size = trcbuf_size; - dgap_debug = debug; - - for (i = 0; i < MAXBOARDS; i++) { - dgap_Board[i] = NULL; - } - - init_timer( &dgap_poll_timer ); - - init_waitqueue_head(&dgap_dl_wait); - dgap_dl_action = 0; -} - - -/************************************************************************ - * - * Utility functions - * - ************************************************************************/ - - -/* - * dgap_mbuf() - * - * Used to print to the message buffer during board init. - */ -static void dgap_mbuf(struct board_t *brd, const char *fmt, ...) { - va_list ap; - char buf[1024]; - int i; - unsigned long flags; - size_t length; - - DGAP_LOCK(dgap_global_lock, flags); - - /* Format buf using fmt and arguments contained in ap. */ - va_start(ap, fmt); - i = vsnprintf(buf, sizeof(buf), fmt, ap); - va_end(ap); - - DPR((buf)); - - if (!brd || !brd->msgbuf) { - printk("%s", buf); - DGAP_UNLOCK(dgap_global_lock, flags); - return; - } - - length = strlen(buf) + 1; - if (brd->msgbuf - brd->msgbuf_head < length) - length = brd->msgbuf - brd->msgbuf_head; - memcpy(brd->msgbuf, buf, length); - brd->msgbuf += length; - - DGAP_UNLOCK(dgap_global_lock, flags); -} - - -/* - * dgap_ms_sleep() - * - * Put the driver to sleep for x ms's - * - * Returns 0 if timed out, !0 (showing signal) if interrupted by a signal. - */ -int dgap_ms_sleep(ulong ms) -{ - current->state = TASK_INTERRUPTIBLE; - schedule_timeout((ms * HZ) / 1000); - return (signal_pending(current)); -} - - - -/* - * dgap_ioctl_name() : Returns a text version of each ioctl value. - */ -char *dgap_ioctl_name(int cmd) -{ - switch(cmd) { - - case TCGETA: return("TCGETA"); - case TCGETS: return("TCGETS"); - case TCSETA: return("TCSETA"); - case TCSETS: return("TCSETS"); - case TCSETAW: return("TCSETAW"); - case TCSETSW: return("TCSETSW"); - case TCSETAF: return("TCSETAF"); - case TCSETSF: return("TCSETSF"); - case TCSBRK: return("TCSBRK"); - case TCXONC: return("TCXONC"); - case TCFLSH: return("TCFLSH"); - case TIOCGSID: return("TIOCGSID"); - - case TIOCGETD: return("TIOCGETD"); - case TIOCSETD: return("TIOCSETD"); - case TIOCGWINSZ: return("TIOCGWINSZ"); - case TIOCSWINSZ: return("TIOCSWINSZ"); - - case TIOCMGET: return("TIOCMGET"); - case TIOCMSET: return("TIOCMSET"); - case TIOCMBIS: return("TIOCMBIS"); - case TIOCMBIC: return("TIOCMBIC"); - - /* from digi.h */ - case DIGI_SETA: return("DIGI_SETA"); - case DIGI_SETAW: return("DIGI_SETAW"); - case DIGI_SETAF: return("DIGI_SETAF"); - case DIGI_SETFLOW: return("DIGI_SETFLOW"); - case DIGI_SETAFLOW: return("DIGI_SETAFLOW"); - case DIGI_GETFLOW: return("DIGI_GETFLOW"); - case DIGI_GETAFLOW: return("DIGI_GETAFLOW"); - case DIGI_GETA: return("DIGI_GETA"); - case DIGI_GEDELAY: return("DIGI_GEDELAY"); - case DIGI_SEDELAY: return("DIGI_SEDELAY"); - case DIGI_GETCUSTOMBAUD: return("DIGI_GETCUSTOMBAUD"); - case DIGI_SETCUSTOMBAUD: return("DIGI_SETCUSTOMBAUD"); - case TIOCMODG: return("TIOCMODG"); - case TIOCMODS: return("TIOCMODS"); - case TIOCSDTR: return("TIOCSDTR"); - case TIOCCDTR: return("TIOCCDTR"); - - default: return("unknown"); - } -} diff --git a/drivers/staging/dgap/dgap_driver.h b/drivers/staging/dgap/dgap_driver.h deleted file mode 100644 index 9296adcb06c..00000000000 --- a/drivers/staging/dgap/dgap_driver.h +++ /dev/null @@ -1,615 +0,0 @@ -/* - * Copyright 2003 Digi International (www.digi.com) - * Scott H Kilau <Scott_Kilau at digi dot com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the - * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!! - * - ************************************************************************* - * - * Driver includes - * - *************************************************************************/ - -#ifndef __DGAP_DRIVER_H -#define __DGAP_DRIVER_H - -#include <linux/types.h> /* To pick up the varions Linux types */ -#include <linux/tty.h> /* To pick up the various tty structs/defines */ -#include <linux/interrupt.h> /* For irqreturn_t type */ - -#include "dgap_types.h" /* Additional types needed by the Digi header files */ -#include "digi.h" /* Digi specific ioctl header */ -#include "dgap_kcompat.h" /* Kernel 2.4/2.6 compat includes */ -#include "dgap_sysfs.h" /* Support for SYSFS */ - -/************************************************************************* - * - * Driver defines - * - *************************************************************************/ - -/* - * Driver identification, error and debugging statments - * - * In theory, you can change all occurrences of "digi" in the next - * three lines, and the driver printk's will all automagically change. - * - * APR((fmt, args, ...)); Always prints message - * DPR((fmt, args, ...)); Only prints if DGAP_TRACER is defined at - * compile time and dgap_debug!=0 - */ -#define DG_NAME "dgap-1.3-16" -#define DG_PART "40002347_C" - -#define PROCSTR "dgap" /* /proc entries */ -#define DEVSTR "/dev/dg/dgap" /* /dev entries */ -#define DRVSTR "dgap" /* Driver name string - * displayed by APR */ -#define APR(args) do { PRINTF_TO_KMEM(args); printk(DRVSTR": "); printk args; \ - } while (0) -#define RAPR(args) do { PRINTF_TO_KMEM(args); printk args; } while (0) - -#define TRC_TO_CONSOLE 1 - -/* - * Debugging levels can be set using debug insmod variable - * They can also be compiled out completely. - */ - -#define DBG_INIT (dgap_debug & 0x01) -#define DBG_BASIC (dgap_debug & 0x02) -#define DBG_CORE (dgap_debug & 0x04) - -#define DBG_OPEN (dgap_debug & 0x08) -#define DBG_CLOSE (dgap_debug & 0x10) -#define DBG_READ (dgap_debug & 0x20) -#define DBG_WRITE (dgap_debug & 0x40) - -#define DBG_IOCTL (dgap_debug & 0x80) - -#define DBG_PROC (dgap_debug & 0x100) -#define DBG_PARAM (dgap_debug & 0x200) -#define DBG_PSCAN (dgap_debug & 0x400) -#define DBG_EVENT (dgap_debug & 0x800) - -#define DBG_DRAIN (dgap_debug & 0x1000) -#define DBG_CARR (dgap_debug & 0x2000) - -#define DBG_MGMT (dgap_debug & 0x4000) - - -#if defined(DGAP_TRACER) - -# if defined(TRC_TO_KMEM) -/* Choose one: */ -# define TRC_ON_OVERFLOW_WRAP_AROUND -# undef TRC_ON_OVERFLOW_SHIFT_BUFFER -# endif //TRC_TO_KMEM - -# define TRC_MAXMSG 1024 -# define TRC_OVERFLOW "(OVERFLOW)" -# define TRC_DTRC "/usr/bin/dtrc" - -#if defined TRC_TO_CONSOLE -#define PRINTF_TO_CONSOLE(args) { printk(DRVSTR": "); printk args; } -#else //!defined TRACE_TO_CONSOLE -#define PRINTF_TO_CONSOLE(args) -#endif - -#if defined TRC_TO_KMEM -#define PRINTF_TO_KMEM(args) dgap_tracef args -#else //!defined TRC_TO_KMEM -#define PRINTF_TO_KMEM(args) -#endif - -#define TRC(args) { PRINTF_TO_KMEM(args); PRINTF_TO_CONSOLE(args) } - -# define DPR_INIT(ARGS) if (DBG_INIT) TRC(ARGS) -# define DPR_BASIC(ARGS) if (DBG_BASIC) TRC(ARGS) -# define DPR_CORE(ARGS) if (DBG_CORE) TRC(ARGS) -# define DPR_OPEN(ARGS) if (DBG_OPEN) TRC(ARGS) -# define DPR_CLOSE(ARGS) if (DBG_CLOSE) TRC(ARGS) -# define DPR_READ(ARGS) if (DBG_READ) TRC(ARGS) -# define DPR_WRITE(ARGS) if (DBG_WRITE) TRC(ARGS) -# define DPR_IOCTL(ARGS) if (DBG_IOCTL) TRC(ARGS) -# define DPR_PROC(ARGS) if (DBG_PROC) TRC(ARGS) -# define DPR_PARAM(ARGS) if (DBG_PARAM) TRC(ARGS) -# define DPR_PSCAN(ARGS) if (DBG_PSCAN) TRC(ARGS) -# define DPR_EVENT(ARGS) if (DBG_EVENT) TRC(ARGS) -# define DPR_DRAIN(ARGS) if (DBG_DRAIN) TRC(ARGS) -# define DPR_CARR(ARGS) if (DBG_CARR) TRC(ARGS) -# define DPR_MGMT(ARGS) if (DBG_MGMT) TRC(ARGS) - -# define DPR(ARGS) if (dgap_debug) TRC(ARGS) -# define P(X) dgap_tracef(#X "=%p\n", X) -# define X(X) dgap_tracef(#X "=%x\n", X) - -#else//!defined DGAP_TRACER - -#define PRINTF_TO_KMEM(args) -# define TRC(ARGS) -# define DPR_INIT(ARGS) -# define DPR_BASIC(ARGS) -# define DPR_CORE(ARGS) -# define DPR_OPEN(ARGS) -# define DPR_CLOSE(ARGS) -# define DPR_READ(ARGS) -# define DPR_WRITE(ARGS) -# define DPR_IOCTL(ARGS) -# define DPR_PROC(ARGS) -# define DPR_PARAM(ARGS) -# define DPR_PSCAN(ARGS) -# define DPR_EVENT(ARGS) -# define DPR_DRAIN(ARGS) -# define DPR_CARR(ARGS) -# define DPR_MGMT(ARGS) - -# define DPR(args) - -#endif//DGAP_TRACER - -/* Number of boards we support at once. */ -#define MAXBOARDS 32 -#define MAXPORTS 224 -#define MAXTTYNAMELEN 200 - -/* Our 3 magic numbers for our board, channel and unit structs */ -#define DGAP_BOARD_MAGIC 0x5c6df104 -#define DGAP_CHANNEL_MAGIC 0x6c6df104 -#define DGAP_UNIT_MAGIC 0x7c6df104 - -/* Serial port types */ -#define DGAP_SERIAL 0 -#define DGAP_PRINT 1 - -#define SERIAL_TYPE_NORMAL 1 - -/* 4 extra for alignment play space */ -#define WRITEBUFLEN ((4096) + 4) -#define MYFLIPLEN N_TTY_BUF_SIZE - -#define SBREAK_TIME 0x25 -#define U2BSIZE 0x400 - -#define dgap_jiffies_from_ms(a) (((a) * HZ) / 1000) - -/* - * Our major for the mgmt devices. - * - * We can use 22, because Digi was allocated 22 and 23 for the epca driver. - * 22 has now become obsolete now that the "cu" devices have - * been removed from 2.6. - * Also, this *IS* the epca driver, just PCI only now. - */ -#ifndef DIGI_DGAP_MAJOR -# define DIGI_DGAP_MAJOR 22 -#endif - -/* - * The parameters we use to define the periods of the moving averages. - */ -#define MA_PERIOD (HZ / 10) -#define SMA_DUR (1 * HZ) -#define EMA_DUR (1 * HZ) -#define SMA_NPERIODS (SMA_DUR / MA_PERIOD) -#define EMA_NPERIODS (EMA_DUR / MA_PERIOD) - -/* - * Define a local default termios struct. All ports will be created - * with this termios initially. This is the same structure that is defined - * as the default in tty_io.c with the same settings overriden as in serial.c - * - * In short, this should match the internal serial ports' defaults. - */ -#define DEFAULT_IFLAGS (ICRNL | IXON) -#define DEFAULT_OFLAGS (OPOST | ONLCR) -#define DEFAULT_CFLAGS (B9600 | CS8 | CREAD | HUPCL | CLOCAL) -#define DEFAULT_LFLAGS (ISIG | ICANON | ECHO | ECHOE | ECHOK | \ - ECHOCTL | ECHOKE | IEXTEN) - -#ifndef _POSIX_VDISABLE -#define _POSIX_VDISABLE '\0' -#endif - -#define SNIFF_MAX 65536 /* Sniff buffer size (2^n) */ -#define SNIFF_MASK (SNIFF_MAX - 1) /* Sniff wrap mask */ - -#define VPDSIZE (512) - -/* - * Lock function/defines. - * Makes spotting lock/unlock locations easier. - */ -# define DGAP_SPINLOCK_INIT(x) spin_lock_init(&(x)) -# define DGAP_LOCK(x,y) spin_lock_irqsave(&(x), y) -# define DGAP_UNLOCK(x,y) spin_unlock_irqrestore(&(x), y) -# define DGAP_TRYLOCK(x,y) spin_trylock(&(x)) - -/* - * All the possible states the driver can be while being loaded. - */ -enum { - DRIVER_INITIALIZED = 0, - DRIVER_NEED_CONFIG_LOAD, - DRIVER_REQUESTED_CONFIG, - DRIVER_READY -}; - -/* - * All the possible states the board can be while booting up. - */ -enum { - BOARD_FAILED = 0, - CONFIG_NOT_FOUND, - BOARD_FOUND, - NEED_RESET, - FINISHED_RESET, - NEED_CONFIG, - FINISHED_CONFIG, - NEED_DEVICE_CREATION, - REQUESTED_DEVICE_CREATION, - FINISHED_DEVICE_CREATION, - NEED_BIOS_LOAD, - REQUESTED_BIOS, - WAIT_BIOS_LOAD, - FINISHED_BIOS_LOAD, - NEED_FEP_LOAD, - REQUESTED_FEP, - WAIT_FEP_LOAD, - FINISHED_FEP_LOAD, - NEED_PROC_CREATION, - FINISHED_PROC_CREATION, - BOARD_READY -}; - -/* - * All the possible states that a requested concentrator image can be in. - */ -enum { - NO_PENDING_CONCENTRATOR_REQUESTS = 0, - NEED_CONCENTRATOR, - REQUESTED_CONCENTRATOR -}; - -extern char *dgap_state_text[]; -extern char *dgap_driver_state_text[]; - - -/* - * Modem line constants are defined as macros because DSR and - * DCD are swapable using the ditty altpin option. - */ -#define D_CD(ch) ch->ch_cd /* Carrier detect */ -#define D_DSR(ch) ch->ch_dsr /* Data set ready */ -#define D_RTS(ch) DM_RTS /* Request to send */ -#define D_CTS(ch) DM_CTS /* Clear to send */ -#define D_RI(ch) DM_RI /* Ring indicator */ -#define D_DTR(ch) DM_DTR /* Data terminal ready */ - - -/************************************************************************* - * - * Structures and closely related defines. - * - *************************************************************************/ - - -/* - * A structure to hold a statistics counter. We also - * compute moving averages for this counter. - */ -struct macounter -{ - u32 cnt; /* Total count */ - ulong accum; /* Acuumulator per period */ - ulong sma; /* Simple moving average */ - ulong ema; /* Exponential moving average */ -}; - - -/************************************************************************ - * Device flag definitions for bd_flags. - ************************************************************************/ -#define BD_FEP5PLUS 0x0001 /* Supports FEP5 Plus commands */ -#define BD_HAS_VPD 0x0002 /* Board has VPD info available */ - - -/* - * Per-board information - */ -struct board_t -{ - int magic; /* Board Magic number. */ - int boardnum; /* Board number: 0-3 */ - int firstminor; /* First minor, e.g. 0, 30, 60 */ - - int type; /* Type of board */ - char *name; /* Product Name */ - struct pci_dev *pdev; /* Pointer to the pci_dev struct */ - u16 vendor; /* PCI vendor ID */ - u16 device; /* PCI device ID */ - u16 subvendor; /* PCI subsystem vendor ID */ - u16 subdevice; /* PCI subsystem device ID */ - uchar rev; /* PCI revision ID */ - uint pci_bus; /* PCI bus value */ - uint pci_slot; /* PCI slot value */ - u16 maxports; /* MAX ports this board can handle */ - uchar vpd[VPDSIZE]; /* VPD of board, if found */ - u32 bd_flags; /* Board flags */ - - spinlock_t bd_lock; /* Used to protect board */ - - u32 state; /* State of card. */ - wait_queue_head_t state_wait; /* Place to sleep on for state change */ - - struct tasklet_struct helper_tasklet; /* Poll helper tasklet */ - - u32 wait_for_bios; - u32 wait_for_fep; - - struct cnode * bd_config; /* Config of board */ - - u16 nasync; /* Number of ports on card */ - - u32 use_interrupts; /* Should we be interrupt driven? */ - ulong irq; /* Interrupt request number */ - ulong intr_count; /* Count of interrupts */ - u32 intr_used; /* Non-zero if using interrupts */ - u32 intr_running; /* Non-zero if FEP knows its doing interrupts */ - - ulong port; /* Start of base io port of the card */ - ulong port_end; /* End of base io port of the card */ - ulong membase; /* Start of base memory of the card */ - ulong membase_end; /* End of base memory of the card */ - - uchar *re_map_port; /* Remapped io port of the card */ - uchar *re_map_membase;/* Remapped memory of the card */ - - uchar runwait; /* # Processes waiting for FEP */ - uchar inhibit_poller; /* Tells the poller to leave us alone */ - - struct channel_t *channels[MAXPORTS]; /* array of pointers to our channels. */ - - struct tty_driver *SerialDriver; - char SerialName[200]; - struct tty_driver *PrintDriver; - char PrintName[200]; - - u32 dgap_Major_Serial_Registered; - u32 dgap_Major_TransparentPrint_Registered; - - u32 dgap_Serial_Major; - u32 dgap_TransparentPrint_Major; - - struct bs_t *bd_bs; /* Base structure pointer */ - - char *flipbuf; /* Our flip buffer, alloced if board is found */ - char *flipflagbuf; /* Our flip flag buffer, alloced if board is found */ - - u16 dpatype; /* The board "type", as defined by DPA */ - u16 dpastatus; /* The board "status", as defined by DPA */ - wait_queue_head_t kme_wait; /* Needed for DPA support */ - - u32 conc_dl_status; /* Status of any pending conc download */ - /* - * Mgmt data. - */ - char *msgbuf_head; - char *msgbuf; -}; - - - -/************************************************************************ - * Unit flag definitions for un_flags. - ************************************************************************/ -#define UN_ISOPEN 0x0001 /* Device is open */ -#define UN_CLOSING 0x0002 /* Line is being closed */ -#define UN_IMM 0x0004 /* Service immediately */ -#define UN_BUSY 0x0008 /* Some work this channel */ -#define UN_BREAKI 0x0010 /* Input break received */ -#define UN_PWAIT 0x0020 /* Printer waiting for terminal */ -#define UN_TIME 0x0040 /* Waiting on time */ -#define UN_EMPTY 0x0080 /* Waiting output queue empty */ -#define UN_LOW 0x0100 /* Waiting output low water mark*/ -#define UN_EXCL_OPEN 0x0200 /* Open for exclusive use */ -#define UN_WOPEN 0x0400 /* Device waiting for open */ -#define UN_WIOCTL 0x0800 /* Device waiting for open */ -#define UN_HANGUP 0x8000 /* Carrier lost */ - -struct device; - -/************************************************************************ - * Structure for terminal or printer unit. - ************************************************************************/ -struct un_t { - int magic; /* Unit Magic Number. */ - struct channel_t *un_ch; - u32 un_time; - u32 un_type; - u32 un_open_count; /* Counter of opens to port */ - struct tty_struct *un_tty;/* Pointer to unit tty structure */ - u32 un_flags; /* Unit flags */ - wait_queue_head_t un_flags_wait; /* Place to sleep to wait on unit */ - u32 un_dev; /* Minor device number */ - tcflag_t un_oflag; /* oflags being done on board */ - tcflag_t un_lflag; /* lflags being done on board */ - struct device *un_sysfs; -}; - - -/************************************************************************ - * Device flag definitions for ch_flags. - ************************************************************************/ -#define CH_PRON 0x0001 /* Printer on string */ -#define CH_OUT 0x0002 /* Dial-out device open */ -#define CH_STOP 0x0004 /* Output is stopped */ -#define CH_STOPI 0x0008 /* Input is stopped */ -#define CH_CD 0x0010 /* Carrier is present */ -#define CH_FCAR 0x0020 /* Carrier forced on */ - -#define CH_RXBLOCK 0x0080 /* Enable rx blocked flag */ -#define CH_WLOW 0x0100 /* Term waiting low event */ -#define CH_WEMPTY 0x0200 /* Term waiting empty event */ -#define CH_RENABLE 0x0400 /* Buffer just emptied */ -#define CH_RACTIVE 0x0800 /* Process active in xxread() */ -#define CH_RWAIT 0x1000 /* Process waiting in xxread() */ -#define CH_BAUD0 0x2000 /* Used for checking B0 transitions */ -#define CH_HANGUP 0x8000 /* Hangup received */ - -/* - * Definitions for ch_sniff_flags - */ -#define SNIFF_OPEN 0x1 -#define SNIFF_WAIT_DATA 0x2 -#define SNIFF_WAIT_SPACE 0x4 - - -/************************************************************************ - * Channel information structure. - ************************************************************************/ -struct channel_t { - int magic; /* Channel Magic Number */ - struct bs_t *ch_bs; /* Base structure pointer */ - struct cm_t *ch_cm; /* Command queue pointer */ - struct board_t *ch_bd; /* Board structure pointer */ - unsigned char *ch_vaddr; /* FEP memory origin */ - unsigned char *ch_taddr; /* Write buffer origin */ - unsigned char *ch_raddr; /* Read buffer origin */ - struct digi_t ch_digi; /* Transparent Print structure */ - struct un_t ch_tun; /* Terminal unit info */ - struct un_t ch_pun; /* Printer unit info */ - - spinlock_t ch_lock; /* provide for serialization */ - wait_queue_head_t ch_flags_wait; - - u32 pscan_state; - uchar pscan_savechar; - - u32 ch_portnum; /* Port number, 0 offset. */ - u32 ch_open_count; /* open count */ - u32 ch_flags; /* Channel flags */ - - - u32 ch_close_delay; /* How long we should drop RTS/DTR for */ - - u32 ch_cpstime; /* Time for CPS calculations */ - - tcflag_t ch_c_iflag; /* channel iflags */ - tcflag_t ch_c_cflag; /* channel cflags */ - tcflag_t ch_c_oflag; /* channel oflags */ - tcflag_t ch_c_lflag; /* channel lflags */ - - u16 ch_fepiflag; /* FEP tty iflags */ - u16 ch_fepcflag; /* FEP tty cflags */ - u16 ch_fepoflag; /* FEP tty oflags */ - u16 ch_wopen; /* Waiting for open process cnt */ - u16 ch_tstart; /* Transmit buffer start */ - u16 ch_tsize; /* Transmit buffer size */ - u16 ch_rstart; /* Receive buffer start */ - u16 ch_rsize; /* Receive buffer size */ - u16 ch_rdelay; /* Receive delay time */ - - u16 ch_tlw; /* Our currently set low water mark */ - - u16 ch_cook; /* Output character mask */ - - uchar ch_card; /* Card channel is on */ - uchar ch_stopc; /* Stop character */ - uchar ch_startc; /* Start character */ - - uchar ch_mostat; /* FEP output modem status */ - uchar ch_mistat; /* FEP input modem status */ - uchar ch_mforce; /* Modem values to be forced */ - uchar ch_mval; /* Force values */ - uchar ch_fepstopc; /* FEP stop character */ - uchar ch_fepstartc; /* FEP start character */ - - uchar ch_astopc; /* Auxiliary Stop character */ - uchar ch_astartc; /* Auxiliary Start character */ - uchar ch_fepastopc; /* Auxiliary FEP stop char */ - uchar ch_fepastartc; /* Auxiliary FEP start char */ - - uchar ch_hflow; /* FEP hardware handshake */ - uchar ch_dsr; /* stores real dsr value */ - uchar ch_cd; /* stores real cd value */ - uchar ch_tx_win; /* channel tx buffer window */ - uchar ch_rx_win; /* channel rx buffer window */ - uint ch_custom_speed; /* Custom baud, if set */ - uint ch_baud_info; /* Current baud info for /proc output */ - ulong ch_rxcount; /* total of data received so far */ - ulong ch_txcount; /* total of data transmitted so far */ - ulong ch_err_parity; /* Count of parity errors on channel */ - ulong ch_err_frame; /* Count of framing errors on channel */ - ulong ch_err_break; /* Count of breaks on channel */ - ulong ch_err_overrun; /* Count of overruns on channel */ - - uint ch_sniff_in; - uint ch_sniff_out; - char *ch_sniff_buf; /* Sniff buffer for proc */ - ulong ch_sniff_flags; /* Channel flags */ - wait_queue_head_t ch_sniff_wait; -}; - - -/************************************************************************* - * - * Prototypes for non-static functions used in more than one module - * - *************************************************************************/ - -extern int dgap_ms_sleep(ulong ms); -extern char *dgap_ioctl_name(int cmd); -extern void dgap_do_bios_load(struct board_t *brd, uchar __user *ubios, int len); -extern void dgap_do_fep_load(struct board_t *brd, uchar __user *ufep, int len); -extern void dgap_do_conc_load(struct board_t *brd, uchar *uaddr, int len); -extern void dgap_do_config_load(uchar __user *uaddr, int len); -extern int dgap_after_config_loaded(void); -extern int dgap_finalize_board_init(struct board_t *brd); - -/* - * Our Global Variables. - */ -extern int dgap_driver_state; /* The state of the driver */ -extern int dgap_debug; /* Debug variable */ -extern int dgap_rawreadok; /* Set if user wants rawreads */ -extern int dgap_poll_tick; /* Poll interval - 20 ms */ -extern spinlock_t dgap_global_lock; /* Driver global spinlock */ -extern uint dgap_NumBoards; /* Total number of boards */ -extern struct board_t *dgap_Board[MAXBOARDS]; /* Array of board structs */ -extern ulong dgap_poll_counter; /* Times the poller has run */ -extern char *dgap_config_buf; /* The config file buffer */ -extern spinlock_t dgap_dl_lock; /* Downloader spinlock */ -extern wait_queue_head_t dgap_dl_wait; /* Wait queue for downloader */ -extern int dgap_dl_action; /* Action flag for downloader */ -extern int dgap_registerttyswithsysfs; /* Should we register the */ - /* ttys with sysfs or not */ - -/* - * Global functions declared in dgap_fep5.c, but must be hidden from - * user space programs. - */ -extern void dgap_poll_tasklet(unsigned long data); -extern void dgap_cmdb(struct channel_t *ch, uchar cmd, uchar byte1, uchar byte2, uint ncmds); -extern void dgap_cmdw(struct channel_t *ch, uchar cmd, u16 word, uint ncmds); -extern void dgap_wmove(struct channel_t *ch, char *buf, uint cnt); -extern int dgap_param(struct tty_struct *tty); -extern void dgap_parity_scan(struct channel_t *ch, unsigned char *cbuf, unsigned char *fbuf, int *len); -extern uint dgap_get_custom_baud(struct channel_t *ch); -extern void dgap_firmware_reset_port(struct channel_t *ch); - -#endif diff --git a/drivers/staging/dgap/dgap_fep5.c b/drivers/staging/dgap/dgap_fep5.c deleted file mode 100644 index 51cda71400f..00000000000 --- a/drivers/staging/dgap/dgap_fep5.c +++ /dev/null @@ -1,1903 +0,0 @@ -/* - * Copyright 2003 Digi International (www.digi.com) - * Scott H Kilau <Scott_Kilau at digi dot com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * NOTE TO LINUX KERNEL HACKERS: DO NOT REFORMAT THIS CODE! - * - * This is shared code between Digi's CVS archive and the - * Linux Kernel sources. - * Changing the source just for reformatting needlessly breaks - * our CVS diff history. - * - * Send any bug fixes/changes to: Eng.Linux at digi dot com. - * Thank you. - * - * $Id: dgap_fep5.c,v 1.2 2011/06/21 10:35:40 markh Exp $ - */ - - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/pci.h> -#include <linux/delay.h> /* For udelay */ -#include <asm/uaccess.h> /* For copy_from_user/copy_to_user */ -#include <linux/tty.h> -#include <linux/tty_flip.h> /* For tty_schedule_flip */ -#include <linux/slab.h> -#include <linux/sched.h> - -#include "dgap_driver.h" -#include "dgap_pci.h" -#include "dgap_fep5.h" -#include "dgap_tty.h" -#include "dgap_conf.h" -#include "dgap_parse.h" -#include "dgap_trace.h" - -/* - * Our function prototypes - */ -static void dgap_cmdw_ext(struct channel_t *ch, u16 cmd, u16 word, uint ncmds); -static int dgap_event(struct board_t *bd); - -/* - * internal variables - */ -static uint dgap_count = 500; - - -/* - * Loads the dgap.conf config file from the user. - */ -void dgap_do_config_load(uchar __user *uaddr, int len) -{ - int orig_len = len; - char *to_addr; - uchar __user *from_addr = uaddr; - char buf[U2BSIZE]; - int n; - - to_addr = dgap_config_buf = kzalloc(len + 1, GFP_ATOMIC); - if (!dgap_config_buf) { - DPR_INIT(("dgap_do_config_load - unable to allocate memory for file\n")); - dgap_driver_state = DRIVER_NEED_CONFIG_LOAD; - return; - } - - n = U2BSIZE; - while (len) { - - if (n > len) - n = len; - - if (copy_from_user((char *) &buf, from_addr, n) == -1 ) - return; - - /* Copy data from buffer to kernel memory */ - memcpy(to_addr, buf, n); - - /* increment counts */ - len -= n; - to_addr += n; - from_addr += n; - n = U2BSIZE; - } - - dgap_config_buf[orig_len] = '\0'; - - to_addr = dgap_config_buf; - dgap_parsefile(&to_addr, TRUE); - - DPR_INIT(("dgap_config_load() finish\n")); - - return; -} - - -int dgap_after_config_loaded(void) -{ - int i = 0; - int rc = 0; - - /* - * Register our ttys, now that we have the config loaded. - */ - for (i = 0; i < dgap_NumBoards; ++i) { - - /* - * Initialize KME waitqueues... - */ - init_waitqueue_head(&(dgap_Board[i]->kme_wait)); - - /* - * allocate flip buffer for board. - */ - dgap_Board[i]->flipbuf = kzalloc(MYFLIPLEN, GFP_ATOMIC); - dgap_Board[i]->flipflagbuf = kzalloc(MYFLIPLEN, GFP_ATOMIC); - } - - return rc; -} - - - -/*======================================================================= - * - * usertoboard - copy from user space to board space. - * - *=======================================================================*/ -static int dgap_usertoboard(struct board_t *brd, char *to_addr, char __user *from_addr, int len) -{ - char buf[U2BSIZE]; - int n = U2BSIZE; - - if (!brd || brd->magic != DGAP_BOARD_MAGIC) - return -EFAULT; - - while (len) { - if (n > len) - n = len; - - if (copy_from_user((char *) &buf, from_addr, n) == -1 ) { - return -EFAULT; - } - - /* Copy data from buffer to card memory */ - memcpy_toio(to_addr, buf, n); - - /* increment counts */ - len -= n; - to_addr += n; - from_addr += n; - n = U2BSIZE; - } - return 0; -} - - -/* - * Copies the BIOS code from the user to the board, - * and starts the BIOS running. - */ -void dgap_do_bios_load(struct board_t *brd, uchar __user *ubios, int len) -{ - uchar *addr; - uint offset; - int i; - - if (!brd || (brd->magic != DGAP_BOARD_MAGIC) || !brd->re_map_membase) - return; - - DPR_INIT(("dgap_do_bios_load() start\n")); - - addr = brd->re_map_membase; - - /* - * clear POST area - */ - for (i = 0; i < 16; i++) - writeb(0, addr + POSTAREA + i); - - /* - * Download bios - */ - offset = 0x1000; - if (dgap_usertoboard(brd, addr + offset, ubios, len) == -1 ) { - brd->state = BOARD_FAILED; - brd->dpastatus = BD_NOFEP; - return; - } - - writel(0x0bf00401, addr); - writel(0, (addr + 4)); - - /* Clear the reset, and change states. */ - writeb(FEPCLR, brd->re_map_port); - brd->state = WAIT_BIOS_LOAD; -} - - -/* - * Checks to see if the BIOS completed running on the card. - */ -static void dgap_do_wait_for_bios(struct board_t *brd) -{ - uchar *addr; - u16 word; - - if (!brd || (brd->magic != DGAP_BOARD_MAGIC) || !brd->re_map_membase) - return; - - addr = brd->re_map_membase; - word = readw(addr + POSTAREA); - - /* Check to see if BIOS thinks board is good. (GD). */ - if (word == *(u16 *) "GD") { - DPR_INIT(("GOT GD in memory, moving states.\n")); - brd->state = FINISHED_BIOS_LOAD; - return; - } - - /* Give up on board after too long of time taken */ - if (brd->wait_for_bios++ > 5000) { - u16 err1 = readw(addr + SEQUENCE); - u16 err2 = readw(addr + ERROR); - APR(("***WARNING*** %s failed diagnostics. Error #(%x,%x).\n", - brd->name, err1, err2)); - brd->state = BOARD_FAILED; - brd->dpastatus = BD_NOFEP; - } -} - - -/* - * Copies the FEP code from the user to the board, - * and starts the FEP running. - */ -void dgap_do_fep_load(struct board_t *brd, uchar __user *ufep, int len) -{ - uchar *addr; - uint offset; - - if (!brd || (brd->magic != DGAP_BOARD_MAGIC) || !brd->re_map_membase) - return; - - addr = brd->re_map_membase; - - DPR_INIT(("dgap_do_fep_load() for board %s : start\n", brd->name)); - - /* - * Download FEP - */ - offset = 0x1000; - if (dgap_usertoboard(brd, addr + offset, ufep, len) == -1 ) { - brd->state = BOARD_FAILED; - brd->dpastatus = BD_NOFEP; - return; - } - - /* - * If board is a concentrator product, we need to give - * it its config string describing how the concentrators look. - */ - if ((brd->type == PCX) || (brd->type == PEPC)) { - uchar string[100]; - uchar *config, *xconfig; - int i = 0; - - xconfig = dgap_create_config_string(brd, string); - - /* Write string to board memory */ - config = addr + CONFIG; - for (; i < CONFIGSIZE; i++, config++, xconfig++) { - writeb(*xconfig, config); - if ((*xconfig & 0xff) == 0xff) - break; - } - } - - writel(0xbfc01004, (addr + 0xc34)); - writel(0x3, (addr + 0xc30)); - - /* change states. */ - brd->state = WAIT_FEP_LOAD; - - DPR_INIT(("dgap_do_fep_load() for board %s : finish\n", brd->name)); - -} - - -/* - * Waits for the FEP to report thats its ready for us to use. - */ -static void dgap_do_wait_for_fep(struct board_t *brd) -{ - uchar *addr; - u16 word; - - if (!brd || (brd->magic != DGAP_BOARD_MAGIC) || !brd->re_map_membase) - return; - - addr = brd->re_map_membase; - - DPR_INIT(("dgap_do_wait_for_fep() for board %s : start. addr: %p\n", brd->name, addr)); - - word = readw(addr + FEPSTAT); - - /* Check to see if FEP is up and running now. */ - if (word == *(u16 *) "OS") { - DPR_INIT(("GOT OS in memory for board %s, moving states.\n", brd->name)); - brd->state = FINISHED_FEP_LOAD; - - /* - * Check to see if the board can support FEP5+ commands. - */ - word = readw(addr + FEP5_PLUS); - if (word == *(u16 *) "5A") { - DPR_INIT(("GOT 5A in memory for board %s, board supports extended FEP5 commands.\n", brd->name)); - brd->bd_flags |= BD_FEP5PLUS; - } - - return; - } - - /* Give up on board after too long of time taken */ - if (brd->wait_for_fep++ > 5000) { - u16 err1 = readw(addr + SEQUENCE); - u16 err2 = readw(addr + ERROR); - APR(("***WARNING*** FEPOS for %s not functioning. Error #(%x,%x).\n", - brd->name, err1, err2)); - brd->state = BOARD_FAILED; - brd->dpastatus = BD_NOFEP; - } - - DPR_INIT(("dgap_do_wait_for_fep() for board %s : finish\n", brd->name)); -} - - -/* - * Physically forces the FEP5 card to reset itself. - */ -static void dgap_do_reset_board(struct board_t *brd) -{ - uchar check; - u32 check1; - u32 check2; - int i = 0; - - if (!brd || (brd->magic != DGAP_BOARD_MAGIC) || !brd->re_map_membase || !brd->re_map_port) { - DPR_INIT(("dgap_do_reset_board() start. bad values. brd: %p mem: %p io: %p\n", - brd, brd ? brd->re_map_membase : 0, brd ? brd->re_map_port : 0)); - return; - } - - DPR_INIT(("dgap_do_reset_board() start. io: %p\n", brd->re_map_port)); - - /* FEPRST does not vary among supported boards */ - writeb(FEPRST, brd->re_map_port); - - for (i = 0; i <= 1000; i++) { - check = readb(brd->re_map_port) & 0xe; - if (check == FEPRST) - break; - udelay(10); - - } - if (i > 1000) { - APR(("*** WARNING *** Board not resetting... Failing board.\n")); - brd->state = BOARD_FAILED; - brd->dpastatus = BD_NOFEP; - goto failed; - } - - /* - * Make sure there really is memory out there. - */ - writel(0xa55a3cc3, (brd->re_map_membase + LOWMEM)); - writel(0x5aa5c33c, (brd->re_map_membase + HIGHMEM)); - check1 = readl(brd->re_map_membase + LOWMEM); - check2 = readl(brd->re_map_membase + HIGHMEM); - - if ((check1 != 0xa55a3cc3) || (check2 != 0x5aa5c33c)) { - APR(("*** Warning *** No memory at %p for board.\n", brd->re_map_membase)); - brd->state = BOARD_FAILED; - brd->dpastatus = BD_NOFEP; - goto failed; - } - - if (brd->state != BOARD_FAILED) - brd->state = FINISHED_RESET; - -failed: - DPR_INIT(("dgap_do_reset_board() finish\n")); -} - - -/* - * Sends a concentrator image into the FEP5 board. - */ -void dgap_do_conc_load(struct board_t *brd, uchar *uaddr, int len) -{ - char *vaddr; - u16 offset = 0; - struct downld_t *to_dp; - - if (!brd || (brd->magic != DGAP_BOARD_MAGIC) || !brd->re_map_membase) - return; - - vaddr = brd->re_map_membase; - - offset = readw((u16 *) (vaddr + DOWNREQ)); - to_dp = (struct downld_t *) (vaddr + (int) offset); - - /* - * The image was already read into kernel space, - * we do NOT need a user space read here - */ - memcpy_toio((char *) to_dp, uaddr, sizeof(struct downld_t)); - - /* Tell card we have data for it */ - writew(0, vaddr + (DOWNREQ)); - - brd->conc_dl_status = NO_PENDING_CONCENTRATOR_REQUESTS; -} - - -#define EXPANSION_ROM_SIZE (64 * 1024) -#define FEP5_ROM_MAGIC (0xFEFFFFFF) - -static void dgap_get_vpd(struct board_t *brd) -{ - u32 magic; - u32 base_offset; - u16 rom_offset; - u16 vpd_offset; - u16 image_length; - u16 i; - uchar byte1; - uchar byte2; - - /* - * Poke the magic number at the PCI Rom Address location. - * If VPD is supported, the value read from that address - * will be non-zero. - */ - magic = FEP5_ROM_MAGIC; - pci_write_config_dword(brd->pdev, PCI_ROM_ADDRESS, magic); - pci_read_config_dword(brd->pdev, PCI_ROM_ADDRESS, &magic); - - /* VPD not supported, bail */ - if (!magic) - return; - - /* - * To get to the OTPROM memory, we have to send the boards base - * address or'ed with 1 into the PCI Rom Address location. - */ - magic = brd->membase | 0x01; - pci_write_config_dword(brd->pdev, PCI_ROM_ADDRESS, magic); - pci_read_config_dword(brd->pdev, PCI_ROM_ADDRESS, &magic); - - byte1 = readb(brd->re_map_membase); - byte2 = readb(brd->re_map_membase + 1); - - /* - * If the board correctly swapped to the OTPROM memory, - * the first 2 bytes (header) should be 0x55, 0xAA - */ - if (byte1 == 0x55 && byte2 == 0xAA) { - - base_offset = 0; - - /* - * We have to run through all the OTPROM memory looking - * for the VPD offset. - */ - while (base_offset <= EXPANSION_ROM_SIZE) { - - /* - * Lots of magic numbers here. - * - * The VPD offset is located inside the ROM Data Structure. - * We also have to remember the length of each - * ROM Data Structure, so we can "hop" to the next - * entry if the VPD isn't in the current - * ROM Data Structure. - */ - rom_offset = readw(brd->re_map_membase + base_offset + 0x18); - image_length = readw(brd->re_map_membase + rom_offset + 0x10) * 512; - vpd_offset = readw(brd->re_map_membase + rom_offset + 0x08); - - /* Found the VPD entry */ - if (vpd_offset) - break; - - /* We didn't find a VPD entry, go to next ROM entry. */ - base_offset += image_length; - - byte1 = readb(brd->re_map_membase + base_offset); - byte2 = readb(brd->re_map_membase + base_offset + 1); - - /* - * If the new ROM offset doesn't have 0x55, 0xAA - * as its header, we have run out of ROM. - */ - if (byte1 != 0x55 || byte2 != 0xAA) - break; - } - - /* - * If we have a VPD offset, then mark the board - * as having a valid VPD, and copy VPDSIZE (512) bytes of - * that VPD to the buffer we have in our board structure. - */ - if (vpd_offset) { - brd->bd_flags |= BD_HAS_VPD; - for (i = 0; i < VPDSIZE; i++) - brd->vpd[i] = readb(brd->re_map_membase + vpd_offset + i); - } - } - - /* - * We MUST poke the magic number at the PCI Rom Address location again. - * This makes the card report the regular board memory back to us, - * rather than the OTPROM memory. - */ - magic = FEP5_ROM_MAGIC; - pci_write_config_dword(brd->pdev, PCI_ROM_ADDRESS, magic); -} - - -/* - * Our board poller function. - */ -void dgap_poll_tasklet(unsigned long data) -{ - struct board_t *bd = (struct board_t *) data; - ulong lock_flags; - ulong lock_flags2; - char *vaddr; - u16 head, tail; - u16 *chk_addr; - u16 check = 0; - - if (!bd || (bd->magic != DGAP_BOARD_MAGIC)) { - APR(("dgap_poll_tasklet() - NULL or bad bd.\n")); - return; - } - - if (bd->inhibit_poller) - return; - - DGAP_LOCK(bd->bd_lock, lock_flags); - - vaddr = bd->re_map_membase; - - /* - * If board is ready, parse deeper to see if there is anything to do. - */ - if (bd->state == BOARD_READY) { - - struct ev_t *eaddr = NULL; - - if (!bd->re_map_membase) { - DGAP_UNLOCK(bd->bd_lock, lock_flags); - return; - } - if (!bd->re_map_port) { - DGAP_UNLOCK(bd->bd_lock, lock_flags); - return; - } - - if (!bd->nasync) { - goto out; - } - - /* - * If this is a CX or EPCX, we need to see if the firmware - * is requesting a concentrator image from us. - */ - if ((bd->type == PCX) || (bd->type == PEPC)) { - chk_addr = (u16 *) (vaddr + DOWNREQ); - check = readw(chk_addr); - /* Nonzero if FEP is requesting concentrator image. */ - if (check) { - if (bd->conc_dl_status == NO_PENDING_CONCENTRATOR_REQUESTS) - bd->conc_dl_status = NEED_CONCENTRATOR; - /* - * Signal downloader, its got some work to do. - */ - DGAP_LOCK(dgap_dl_lock, lock_flags2); - if (dgap_dl_action != 1) { - dgap_dl_action = 1; - wake_up_interruptible(&dgap_dl_wait); - } - DGAP_UNLOCK(dgap_dl_lock, lock_flags2); - - } - } - - eaddr = (struct ev_t *) (vaddr + EVBUF); - - /* Get our head and tail */ - head = readw(&(eaddr->ev_head)); - tail = readw(&(eaddr->ev_tail)); - - /* - * If there is an event pending. Go service it. - */ - if (head != tail) { - DGAP_UNLOCK(bd->bd_lock, lock_flags); - dgap_event(bd); - DGAP_LOCK(bd->bd_lock, lock_flags); - } - -out: - /* - * If board is doing interrupts, ACK the interrupt. - */ - if (bd && bd->intr_running) { - readb(bd->re_map_port + 2); - } - - DGAP_UNLOCK(bd->bd_lock, lock_flags); - return; - } - - /* Our state machine to get the board up and running */ - - /* Reset board */ - if (bd->state == NEED_RESET) { - - /* Get VPD info */ - dgap_get_vpd(bd); - - dgap_do_reset_board(bd); - } - - /* Move to next state */ - if (bd->state == FINISHED_RESET) { - bd->state = NEED_CONFIG; - } - - if (bd->state == NEED_CONFIG) { - /* - * Match this board to a config the user created for us. - */ - bd->bd_config = dgap_find_config(bd->type, bd->pci_bus, bd->pci_slot); - - /* - * Because the 4 port Xr products share the same PCI ID - * as the 8 port Xr products, if we receive a NULL config - * back, and this is a PAPORT8 board, retry with a - * PAPORT4 attempt as well. - */ - if (bd->type == PAPORT8 && !bd->bd_config) { - bd->bd_config = dgap_find_config(PAPORT4, bd->pci_bus, bd->pci_slot); - } - - /* - * Register the ttys (if any) into the kernel. - */ - if (bd->bd_config) { - bd->state = FINISHED_CONFIG; - } - else { - bd->state = CONFIG_NOT_FOUND; - } - } - - /* Move to next state */ - if (bd->state == FINISHED_CONFIG) { - bd->state = NEED_DEVICE_CREATION; - } - - /* Move to next state */ - if (bd->state == NEED_DEVICE_CREATION) { - /* - * Signal downloader, its got some work to do. - */ - DGAP_LOCK(dgap_dl_lock, lock_flags2); - if (dgap_dl_action != 1) { - dgap_dl_action = 1; - wake_up_interruptible(&dgap_dl_wait); - } - DGAP_UNLOCK(dgap_dl_lock, lock_flags2); - } - - /* Move to next state */ - if (bd->state == FINISHED_DEVICE_CREATION) { - bd->state = NEED_BIOS_LOAD; - } - - /* Move to next state */ - if (bd->state == NEED_BIOS_LOAD) { - /* - * Signal downloader, its got some work to do. - */ - DGAP_LOCK(dgap_dl_lock, lock_flags2); - if (dgap_dl_action != 1) { - dgap_dl_action = 1; - wake_up_interruptible(&dgap_dl_wait); - } - DGAP_UNLOCK(dgap_dl_lock, lock_flags2); - } - - /* Wait for BIOS to test board... */ - if (bd->state == WAIT_BIOS_LOAD) { - dgap_do_wait_for_bios(bd); - } - - /* Move to next state */ - if (bd->state == FINISHED_BIOS_LOAD) { - bd->state = NEED_FEP_LOAD; - - /* - * Signal downloader, its got some work to do. - */ - DGAP_LOCK(dgap_dl_lock, lock_flags2); - if (dgap_dl_action != 1) { - dgap_dl_action = 1; - wake_up_interruptible(&dgap_dl_wait); - } - DGAP_UNLOCK(dgap_dl_lock, lock_flags2); - } - - /* Wait for FEP to load on board... */ - if (bd->state == WAIT_FEP_LOAD) { - dgap_do_wait_for_fep(bd); - } - - - /* Move to next state */ - if (bd->state == FINISHED_FEP_LOAD) { - - /* - * Do tty device initialization. - */ - int rc = dgap_tty_init(bd); - - if (rc < 0) { - dgap_tty_uninit(bd); - APR(("Can't init tty devices (%d)\n", rc)); - bd->state = BOARD_FAILED; - bd->dpastatus = BD_NOFEP; - } - else { - bd->state = NEED_PROC_CREATION; - - /* - * Signal downloader, its got some work to do. - */ - DGAP_LOCK(dgap_dl_lock, lock_flags2); - if (dgap_dl_action != 1) { - dgap_dl_action = 1; - wake_up_interruptible(&dgap_dl_wait); - } - DGAP_UNLOCK(dgap_dl_lock, lock_flags2); - } - } - - /* Move to next state */ - if (bd->state == FINISHED_PROC_CREATION) { - - bd->state = BOARD_READY; - bd->dpastatus = BD_RUNNING; - - /* - * If user requested the board to run in interrupt mode, - * go and set it up on the board. - */ - if (bd->intr_used) { - writew(1, (bd->re_map_membase + ENABLE_INTR)); - /* - * Tell the board to poll the UARTS as fast as possible. - */ - writew(FEPPOLL_MIN, (bd->re_map_membase + FEPPOLL)); - bd->intr_running = 1; - } - - /* Wake up anyone waiting for board state to change to ready */ - wake_up_interruptible(&bd->state_wait); - } - - DGAP_UNLOCK(bd->bd_lock, lock_flags); -} - - -/*======================================================================= - * - * dgap_cmdb - Sends a 2 byte command to the FEP. - * - * ch - Pointer to channel structure. - * cmd - Command to be sent. - * byte1 - Integer containing first byte to be sent. - * byte2 - Integer containing second byte to be sent. - * ncmds - Wait until ncmds or fewer cmds are left - * in the cmd buffer before returning. - * - *=======================================================================*/ -void dgap_cmdb(struct channel_t *ch, uchar cmd, uchar byte1, uchar byte2, uint ncmds) -{ - char *vaddr = NULL; - struct cm_t *cm_addr = NULL; - uint count; - uint n; - u16 head; - u16 tail; - - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return; - - /* - * Check if board is still alive. - */ - if (ch->ch_bd->state == BOARD_FAILED) { - DPR_CORE(("%s:%d board is in failed state.\n", __FILE__, __LINE__)); - return; - } - - /* - * Make sure the pointers are in range before - * writing to the FEP memory. - */ - vaddr = ch->ch_bd->re_map_membase; - - if (!vaddr) - return; - - cm_addr = (struct cm_t *) (vaddr + CMDBUF); - head = readw(&(cm_addr->cm_head)); - - /* - * Forget it if pointers out of range. - */ - if (head >= (CMDMAX - CMDSTART) || (head & 03)) { - DPR_CORE(("%s:%d pointers out of range, failing board!\n", __FILE__, __LINE__)); - ch->ch_bd->state = BOARD_FAILED; - return; - } - - /* - * Put the data in the circular command buffer. - */ - writeb(cmd, (char *) (vaddr + head + CMDSTART + 0)); - writeb((uchar) ch->ch_portnum, (char *) (vaddr + head + CMDSTART + 1)); - writeb(byte1, (char *) (vaddr + head + CMDSTART + 2)); - writeb(byte2, (char *) (vaddr + head + CMDSTART + 3)); - - head = (head + 4) & (CMDMAX - CMDSTART - 4); - - writew(head, &(cm_addr->cm_head)); - - /* - * Wait if necessary before updating the head - * pointer to limit the number of outstanding - * commands to the FEP. If the time spent waiting - * is outlandish, declare the FEP dead. - */ - for (count = dgap_count ;;) { - - head = readw(&(cm_addr->cm_head)); - tail = readw(&(cm_addr->cm_tail)); - - n = (head - tail) & (CMDMAX - CMDSTART - 4); - - if (n <= ncmds * sizeof(struct cm_t)) - break; - - if (--count == 0) { - DPR_CORE(("%s:%d failing board.\n",__FILE__, __LINE__)); - ch->ch_bd->state = BOARD_FAILED; - return; - } - udelay(10); - } -} - - -/*======================================================================= - * - * dgap_cmdw - Sends a 1 word command to the FEP. - * - * ch - Pointer to channel structure. - * cmd - Command to be sent. - * word - Integer containing word to be sent. - * ncmds - Wait until ncmds or fewer cmds are left - * in the cmd buffer before returning. - * - *=======================================================================*/ -void dgap_cmdw(struct channel_t *ch, uchar cmd, u16 word, uint ncmds) -{ - char *vaddr = NULL; - struct cm_t *cm_addr = NULL; - uint count; - uint n; - u16 head; - u16 tail; - - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return; - - /* - * Check if board is still alive. - */ - if (ch->ch_bd->state == BOARD_FAILED) { - DPR_CORE(("%s:%d board is failed!\n", __FILE__, __LINE__)); - return; - } - - /* - * Make sure the pointers are in range before - * writing to the FEP memory. - */ - vaddr = ch->ch_bd->re_map_membase; - if (!vaddr) - return; - - cm_addr = (struct cm_t *) (vaddr + CMDBUF); - head = readw(&(cm_addr->cm_head)); - - /* - * Forget it if pointers out of range. - */ - if (head >= (CMDMAX - CMDSTART) || (head & 03)) { - DPR_CORE(("%s:%d Pointers out of range. Failing board.\n",__FILE__, __LINE__)); - ch->ch_bd->state = BOARD_FAILED; - return; - } - - /* - * Put the data in the circular command buffer. - */ - writeb(cmd, (char *) (vaddr + head + CMDSTART + 0)); - writeb((uchar) ch->ch_portnum, (char *) (vaddr + head + CMDSTART + 1)); - writew((u16) word, (char *) (vaddr + head + CMDSTART + 2)); - - head = (head + 4) & (CMDMAX - CMDSTART - 4); - - writew(head, &(cm_addr->cm_head)); - - /* - * Wait if necessary before updating the head - * pointer to limit the number of outstanding - * commands to the FEP. If the time spent waiting - * is outlandish, declare the FEP dead. - */ - for (count = dgap_count ;;) { - - head = readw(&(cm_addr->cm_head)); - tail = readw(&(cm_addr->cm_tail)); - - n = (head - tail) & (CMDMAX - CMDSTART - 4); - - if (n <= ncmds * sizeof(struct cm_t)) - break; - - if (--count == 0) { - DPR_CORE(("%s:%d Failing board.\n",__FILE__, __LINE__)); - ch->ch_bd->state = BOARD_FAILED; - return; - } - udelay(10); - } -} - - - -/*======================================================================= - * - * dgap_cmdw_ext - Sends a extended word command to the FEP. - * - * ch - Pointer to channel structure. - * cmd - Command to be sent. - * word - Integer containing word to be sent. - * ncmds - Wait until ncmds or fewer cmds are left - * in the cmd buffer before returning. - * - *=======================================================================*/ -static void dgap_cmdw_ext(struct channel_t *ch, u16 cmd, u16 word, uint ncmds) -{ - char *vaddr = NULL; - struct cm_t *cm_addr = NULL; - uint count; - uint n; - u16 head; - u16 tail; - - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return; - - /* - * Check if board is still alive. - */ - if (ch->ch_bd->state == BOARD_FAILED) { - DPR_CORE(("%s:%d board is failed!\n", __FILE__, __LINE__)); - return; - } - - /* - * Make sure the pointers are in range before - * writing to the FEP memory. - */ - vaddr = ch->ch_bd->re_map_membase; - if (!vaddr) - return; - - cm_addr = (struct cm_t *) (vaddr + CMDBUF); - head = readw(&(cm_addr->cm_head)); - - /* - * Forget it if pointers out of range. - */ - if (head >= (CMDMAX - CMDSTART) || (head & 03)) { - DPR_CORE(("%s:%d Pointers out of range. Failing board.\n",__FILE__, __LINE__)); - ch->ch_bd->state = BOARD_FAILED; - return; - } - - /* - * Put the data in the circular command buffer. - */ - - /* Write an FF to tell the FEP that we want an extended command */ - writeb((uchar) 0xff, (char *) (vaddr + head + CMDSTART + 0)); - - writeb((uchar) ch->ch_portnum, (uchar *) (vaddr + head + CMDSTART + 1)); - writew((u16) cmd, (char *) (vaddr + head + CMDSTART + 2)); - - /* - * If the second part of the command won't fit, - * put it at the beginning of the circular buffer. - */ - if (((head + 4) >= ((CMDMAX - CMDSTART)) || (head & 03))) { - writew((u16) word, (char *) (vaddr + CMDSTART)); - } else { - writew((u16) word, (char *) (vaddr + head + CMDSTART + 4)); - } - - head = (head + 8) & (CMDMAX - CMDSTART - 4); - - writew(head, &(cm_addr->cm_head)); - - /* - * Wait if necessary before updating the head - * pointer to limit the number of outstanding - * commands to the FEP. If the time spent waiting - * is outlandish, declare the FEP dead. - */ - for (count = dgap_count ;;) { - - head = readw(&(cm_addr->cm_head)); - tail = readw(&(cm_addr->cm_tail)); - - n = (head - tail) & (CMDMAX - CMDSTART - 4); - - if (n <= ncmds * sizeof(struct cm_t)) - break; - - if (--count == 0) { - DPR_CORE(("%s:%d Failing board.\n",__FILE__, __LINE__)); - ch->ch_bd->state = BOARD_FAILED; - return; - } - udelay(10); - } -} - - -/*======================================================================= - * - * dgap_wmove - Write data to FEP buffer. - * - * ch - Pointer to channel structure. - * buf - Poiter to characters to be moved. - * cnt - Number of characters to move. - * - *=======================================================================*/ -void dgap_wmove(struct channel_t *ch, char *buf, uint cnt) -{ - int n; - char *taddr; - struct bs_t *bs; - u16 head; - - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return; - - /* - * Check parameters. - */ - bs = ch->ch_bs; - head = readw(&(bs->tx_head)); - - /* - * If pointers are out of range, just return. - */ - if ((cnt > ch->ch_tsize) || (unsigned)(head - ch->ch_tstart) >= ch->ch_tsize) { - DPR_CORE(("%s:%d pointer out of range", __FILE__, __LINE__)); - return; - } - - /* - * If the write wraps over the top of the circular buffer, - * move the portion up to the wrap point, and reset the - * pointers to the bottom. - */ - n = ch->ch_tstart + ch->ch_tsize - head; - - if (cnt >= n) { - cnt -= n; - taddr = ch->ch_taddr + head; - memcpy_toio(taddr, buf, n); - head = ch->ch_tstart; - buf += n; - } - - /* - * Move rest of data. - */ - taddr = ch->ch_taddr + head; - n = cnt; - memcpy_toio(taddr, buf, n); - head += cnt; - - writew(head, &(bs->tx_head)); -} - -/* - * Retrives the current custom baud rate from FEP memory, - * and returns it back to the user. - * Returns 0 on error. - */ -uint dgap_get_custom_baud(struct channel_t *ch) -{ - uchar *vaddr; - ulong offset = 0; - uint value = 0; - - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) { - return 0; - } - - if (!ch->ch_bd || ch->ch_bd->magic != DGAP_BOARD_MAGIC) { - return 0; - } - - if (!(ch->ch_bd->bd_flags & BD_FEP5PLUS)) - return 0; - - vaddr = ch->ch_bd->re_map_membase; - - if (!vaddr) - return 0; - - /* - * Go get from fep mem, what the fep - * believes the custom baud rate is. - */ - offset = ((((*(unsigned short *)(vaddr + ECS_SEG)) << 4) + - (ch->ch_portnum * 0x28) + LINE_SPEED)); - - value = readw(vaddr + offset); - return value; -} - - -/* - * Calls the firmware to reset this channel. - */ -void dgap_firmware_reset_port(struct channel_t *ch) -{ - dgap_cmdb(ch, CHRESET, 0, 0, 0); - - /* - * Now that the channel is reset, we need to make sure - * all the current settings get reapplied to the port - * in the firmware. - * - * So we will set the driver's cache of firmware - * settings all to 0, and then call param. - */ - ch->ch_fepiflag = 0; - ch->ch_fepcflag = 0; - ch->ch_fepoflag = 0; - ch->ch_fepstartc = 0; - ch->ch_fepstopc = 0; - ch->ch_fepastartc = 0; - ch->ch_fepastopc = 0; - ch->ch_mostat = 0; - ch->ch_hflow = 0; -} - - -/*======================================================================= - * - * dgap_param - Set Digi parameters. - * - * struct tty_struct * - TTY for port. - * - *=======================================================================*/ -int dgap_param(struct tty_struct *tty) -{ - struct ktermios *ts; - struct board_t *bd; - struct channel_t *ch; - struct bs_t *bs; - struct un_t *un; - u16 head; - u16 cflag; - u16 iflag; - uchar mval; - uchar hflow; - - if (!tty || tty->magic != TTY_MAGIC) - return -ENXIO; - - un = (struct un_t *) tty->driver_data; - if (!un || un->magic != DGAP_UNIT_MAGIC) - return -ENXIO; - - ch = un->un_ch; - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return -ENXIO; - - bd = ch->ch_bd; - if (!bd || bd->magic != DGAP_BOARD_MAGIC) - return -ENXIO; - - bs = ch->ch_bs; - if (!bs) - return -ENXIO; - - DPR_PARAM(("param start: tdev: %x cflags: %x oflags: %x iflags: %x\n", - ch->ch_tun.un_dev, ch->ch_c_cflag, ch->ch_c_oflag, ch->ch_c_iflag)); - - ts = &tty->termios; - - /* - * If baud rate is zero, flush queues, and set mval to drop DTR. - */ - if ((ch->ch_c_cflag & (CBAUD)) == 0) { - - /* flush rx */ - head = readw(&(ch->ch_bs->rx_head)); - writew(head, &(ch->ch_bs->rx_tail)); - - /* flush tx */ - head = readw(&(ch->ch_bs->tx_head)); - writew(head, &(ch->ch_bs->tx_tail)); - - ch->ch_flags |= (CH_BAUD0); - - /* Drop RTS and DTR */ - ch->ch_mval &= ~(D_RTS(ch)|D_DTR(ch)); - mval = D_DTR(ch) | D_RTS(ch); - ch->ch_baud_info = 0; - - } else if (ch->ch_custom_speed && (bd->bd_flags & BD_FEP5PLUS)) { - /* - * Tell the fep to do the command - */ - - DPR_PARAM(("param: Want %d speed\n", ch->ch_custom_speed)); - - dgap_cmdw_ext(ch, 0xff01, ch->ch_custom_speed, 0); - - /* - * Now go get from fep mem, what the fep - * believes the custom baud rate is. - */ - ch->ch_baud_info = ch->ch_custom_speed = dgap_get_custom_baud(ch); - - DPR_PARAM(("param: Got %d speed\n", ch->ch_custom_speed)); - - /* Handle transition from B0 */ - if (ch->ch_flags & CH_BAUD0) { - ch->ch_flags &= ~(CH_BAUD0); - ch->ch_mval |= (D_RTS(ch)|D_DTR(ch)); - } - mval = D_DTR(ch) | D_RTS(ch); - - } else { - /* - * Set baud rate, character size, and parity. - */ - - - int iindex = 0; - int jindex = 0; - int baud = 0; - - ulong bauds[4][16] = { - { /* slowbaud */ - 0, 50, 75, 110, - 134, 150, 200, 300, - 600, 1200, 1800, 2400, - 4800, 9600, 19200, 38400 }, - { /* slowbaud & CBAUDEX */ - 0, 57600, 115200, 230400, - 460800, 150, 200, 921600, - 600, 1200, 1800, 2400, - 4800, 9600, 19200, 38400 }, - { /* fastbaud */ - 0, 57600, 76800, 115200, - 14400, 57600, 230400, 76800, - 115200, 230400, 28800, 460800, - 921600, 9600, 19200, 38400 }, - { /* fastbaud & CBAUDEX */ - 0, 57600, 115200, 230400, - 460800, 150, 200, 921600, - 600, 1200, 1800, 2400, - 4800, 9600, 19200, 38400 } - }; - - /* Only use the TXPrint baud rate if the terminal unit is NOT open */ - if (!(ch->ch_tun.un_flags & UN_ISOPEN) && (un->un_type == DGAP_PRINT)) - baud = C_BAUD(ch->ch_pun.un_tty) & 0xff; - else - baud = C_BAUD(ch->ch_tun.un_tty) & 0xff; - - if (ch->ch_c_cflag & CBAUDEX) - iindex = 1; - - if (ch->ch_digi.digi_flags & DIGI_FAST) - iindex += 2; - - jindex = baud; - - if ((iindex >= 0) && (iindex < 4) && (jindex >= 0) && (jindex < 16)) { - baud = bauds[iindex][jindex]; - } else { - DPR_IOCTL(("baud indices were out of range (%d)(%d)", - iindex, jindex)); - baud = 0; - } - - if (baud == 0) - baud = 9600; - - ch->ch_baud_info = baud; - - - /* - * CBAUD has bit position 0x1000 set these days to indicate Linux - * baud rate remap. - * We use a different bit assignment for high speed. Clear this - * bit out while grabbing the parts of "cflag" we want. - */ - cflag = ch->ch_c_cflag & ((CBAUD ^ CBAUDEX) | PARODD | PARENB | CSTOPB | CSIZE); - - /* - * HUPCL bit is used by FEP to indicate fast baud - * table is to be used. - */ - if ((ch->ch_digi.digi_flags & DIGI_FAST) || (ch->ch_c_cflag & CBAUDEX)) - cflag |= HUPCL; - - - if ((ch->ch_c_cflag & CBAUDEX) && !(ch->ch_digi.digi_flags & DIGI_FAST)) { - /* - * The below code is trying to guarantee that only baud rates - * 115200, 230400, 460800, 921600 are remapped. We use exclusive or - * because the various baud rates share common bit positions - * and therefore can't be tested for easily. - */ - tcflag_t tcflag = (ch->ch_c_cflag & CBAUD) | CBAUDEX; - int baudpart = 0; - - /* Map high speed requests to index into FEP's baud table */ - switch (tcflag) { - case B57600 : - baudpart = 1; - break; -#ifdef B76800 - case B76800 : - baudpart = 2; - break; -#endif - case B115200 : - baudpart = 3; - break; - case B230400 : - baudpart = 9; - break; - case B460800 : - baudpart = 11; - break; -#ifdef B921600 - case B921600 : - baudpart = 12; - break; -#endif - default: - baudpart = 0; - } - - if (baudpart) - cflag = (cflag & ~(CBAUD | CBAUDEX)) | baudpart; - } - - cflag &= 0xffff; - - if (cflag != ch->ch_fepcflag) { - ch->ch_fepcflag = (u16) (cflag & 0xffff); - - /* Okay to have channel and board locks held calling this */ - dgap_cmdw(ch, SCFLAG, (u16) cflag, 0); - } - - /* Handle transition from B0 */ - if (ch->ch_flags & CH_BAUD0) { - ch->ch_flags &= ~(CH_BAUD0); - ch->ch_mval |= (D_RTS(ch)|D_DTR(ch)); - } - mval = D_DTR(ch) | D_RTS(ch); - } - - /* - * Get input flags. - */ - iflag = ch->ch_c_iflag & (IGNBRK | BRKINT | IGNPAR | PARMRK | INPCK | ISTRIP | IXON | IXANY | IXOFF); - - if ((ch->ch_startc == _POSIX_VDISABLE) || (ch->ch_stopc == _POSIX_VDISABLE)) { - iflag &= ~(IXON | IXOFF); - ch->ch_c_iflag &= ~(IXON | IXOFF); - } - - /* - * Only the IBM Xr card can switch between - * 232 and 422 modes on the fly - */ - if (bd->device == PCI_DEVICE_XR_IBM_DID) { - if (ch->ch_digi.digi_flags & DIGI_422) - dgap_cmdb(ch, SCOMMODE, MODE_422, 0, 0); - else - dgap_cmdb(ch, SCOMMODE, MODE_232, 0, 0); - } - - if (ch->ch_digi.digi_flags & DIGI_ALTPIN) - iflag |= IALTPIN ; - - if (iflag != ch->ch_fepiflag) { - ch->ch_fepiflag = iflag; - - /* Okay to have channel and board locks held calling this */ - dgap_cmdw(ch, SIFLAG, (u16) ch->ch_fepiflag, 0); - } - - /* - * Select hardware handshaking. - */ - hflow = 0; - - if (ch->ch_c_cflag & CRTSCTS) { - hflow |= (D_RTS(ch) | D_CTS(ch)); - } - if (ch->ch_digi.digi_flags & RTSPACE) - hflow |= D_RTS(ch); - if (ch->ch_digi.digi_flags & DTRPACE) - hflow |= D_DTR(ch); - if (ch->ch_digi.digi_flags & CTSPACE) - hflow |= D_CTS(ch); - if (ch->ch_digi.digi_flags & DSRPACE) - hflow |= D_DSR(ch); - if (ch->ch_digi.digi_flags & DCDPACE) - hflow |= D_CD(ch); - - if (hflow != ch->ch_hflow) { - ch->ch_hflow = hflow; - - /* Okay to have channel and board locks held calling this */ - dgap_cmdb(ch, SHFLOW, (uchar) hflow, 0xff, 0); - } - - - /* - * Set RTS and/or DTR Toggle if needed, but only if product is FEP5+ based. - */ - if (bd->bd_flags & BD_FEP5PLUS) { - u16 hflow2 = 0; - if (ch->ch_digi.digi_flags & DIGI_RTS_TOGGLE) { - hflow2 |= (D_RTS(ch)); - } - if (ch->ch_digi.digi_flags & DIGI_DTR_TOGGLE) { - hflow2 |= (D_DTR(ch)); - } - - dgap_cmdw_ext(ch, 0xff03, hflow2, 0); - } - - /* - * Set modem control lines. - */ - - mval ^= ch->ch_mforce & (mval ^ ch->ch_mval); - - DPR_PARAM(("dgap_param: mval: %x ch_mforce: %x ch_mval: %x ch_mostat: %x\n", - mval, ch->ch_mforce, ch->ch_mval, ch->ch_mostat)); - - if (ch->ch_mostat ^ mval) { - ch->ch_mostat = mval; - - /* Okay to have channel and board locks held calling this */ - DPR_PARAM(("dgap_param: Sending SMODEM mval: %x\n", mval)); - dgap_cmdb(ch, SMODEM, (uchar) mval, D_RTS(ch)|D_DTR(ch), 0); - } - - /* - * Read modem signals, and then call carrier function. - */ - ch->ch_mistat = readb(&(bs->m_stat)); - dgap_carrier(ch); - - /* - * Set the start and stop characters. - */ - if (ch->ch_startc != ch->ch_fepstartc || ch->ch_stopc != ch->ch_fepstopc) { - ch->ch_fepstartc = ch->ch_startc; - ch->ch_fepstopc = ch->ch_stopc; - - /* Okay to have channel and board locks held calling this */ - dgap_cmdb(ch, SFLOWC, ch->ch_fepstartc, ch->ch_fepstopc, 0); - } - - /* - * Set the Auxiliary start and stop characters. - */ - if (ch->ch_astartc != ch->ch_fepastartc || ch->ch_astopc != ch->ch_fepastopc) { - ch->ch_fepastartc = ch->ch_astartc; - ch->ch_fepastopc = ch->ch_astopc; - - /* Okay to have channel and board locks held calling this */ - dgap_cmdb(ch, SAFLOWC, ch->ch_fepastartc, ch->ch_fepastopc, 0); - } - - DPR_PARAM(("param finish\n")); - - return 0; -} - - -/* - * dgap_parity_scan() - * - * Convert the FEP5 way of reporting parity errors and breaks into - * the Linux line discipline way. - */ -void dgap_parity_scan(struct channel_t *ch, unsigned char *cbuf, unsigned char *fbuf, int *len) -{ - int l = *len; - int count = 0; - unsigned char *in, *cout, *fout; - unsigned char c; - - in = cbuf; - cout = cbuf; - fout = fbuf; - - DPR_PSCAN(("dgap_parity_scan start\n")); - - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return; - - while (l--) { - c = *in++; - switch (ch->pscan_state) { - default: - /* reset to sanity and fall through */ - ch->pscan_state = 0; - - case 0: - /* No FF seen yet */ - if (c == (unsigned char) '\377') { - /* delete this character from stream */ - ch->pscan_state = 1; - } else { - *cout++ = c; - *fout++ = TTY_NORMAL; - count += 1; - } - break; - - case 1: - /* first FF seen */ - if (c == (unsigned char) '\377') { - /* doubled ff, transform to single ff */ - *cout++ = c; - *fout++ = TTY_NORMAL; - count += 1; - ch->pscan_state = 0; - } else { - /* save value examination in next state */ - ch->pscan_savechar = c; - ch->pscan_state = 2; - } - break; - - case 2: - /* third character of ff sequence */ - - *cout++ = c; - - if (ch->pscan_savechar == 0x0) { - - if (c == 0x0) { - DPR_PSCAN(("dgap_parity_scan in 3rd char of ff seq. c: %x setting break.\n", c)); - ch->ch_err_break++; - *fout++ = TTY_BREAK; - } - else { - DPR_PSCAN(("dgap_parity_scan in 3rd char of ff seq. c: %x setting parity.\n", c)); - ch->ch_err_parity++; - *fout++ = TTY_PARITY; - } - } - else { - DPR_PSCAN(("%s:%d Logic Error.\n", __FILE__, __LINE__)); - } - - count += 1; - ch->pscan_state = 0; - } - } - *len = count; - DPR_PSCAN(("dgap_parity_scan finish\n")); -} - - - - -/*======================================================================= - * - * dgap_event - FEP to host event processing routine. - * - * bd - Board of current event. - * - *=======================================================================*/ -static int dgap_event(struct board_t *bd) -{ - struct channel_t *ch; - ulong lock_flags; - ulong lock_flags2; - struct bs_t *bs; - uchar *event; - uchar *vaddr = NULL; - struct ev_t *eaddr = NULL; - uint head; - uint tail; - int port; - int reason; - int modem; - int b1; - - if (!bd || bd->magic != DGAP_BOARD_MAGIC) - return -ENXIO; - - DGAP_LOCK(bd->bd_lock, lock_flags); - - vaddr = bd->re_map_membase; - - if (!vaddr) { - DGAP_UNLOCK(bd->bd_lock, lock_flags); - return -ENXIO; - } - - eaddr = (struct ev_t *) (vaddr + EVBUF); - - /* Get our head and tail */ - head = readw(&(eaddr->ev_head)); - tail = readw(&(eaddr->ev_tail)); - - /* - * Forget it if pointers out of range. - */ - - if (head >= EVMAX - EVSTART || tail >= EVMAX - EVSTART || - (head | tail) & 03) { - DPR_EVENT(("should be calling xxfail %d\n", __LINE__)); - /* Let go of board lock */ - DGAP_UNLOCK(bd->bd_lock, lock_flags); - return -ENXIO; - } - - /* - * Loop to process all the events in the buffer. - */ - while (tail != head) { - - /* - * Get interrupt information. - */ - - event = bd->re_map_membase + tail + EVSTART; - - port = event[0]; - reason = event[1]; - modem = event[2]; - b1 = event[3]; - - DPR_EVENT(("event: jiffies: %ld port: %d reason: %x modem: %x\n", - jiffies, port, reason, modem)); - - /* - * Make sure the interrupt is valid. - */ - if (port >= bd->nasync) - goto next; - - if (!(reason & (IFMODEM | IFBREAK | IFTLW | IFTEM | IFDATA))) { - goto next; - } - - ch = bd->channels[port]; - - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) { - goto next; - } - - /* - * If we have made it here, the event was valid. - * Lock down the channel. - */ - DGAP_LOCK(ch->ch_lock, lock_flags2); - - bs = ch->ch_bs; - - if (!bs) { - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - goto next; - } - - /* - * Process received data. - */ - if (reason & IFDATA) { - - /* - * ALL LOCKS *MUST* BE DROPPED BEFORE CALLING INPUT! - * input could send some data to ld, which in turn - * could do a callback to one of our other functions. - */ - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - - dgap_input(ch); - - DGAP_LOCK(bd->bd_lock, lock_flags); - DGAP_LOCK(ch->ch_lock, lock_flags2); - - if (ch->ch_flags & CH_RACTIVE) - ch->ch_flags |= CH_RENABLE; - else - writeb(1, &(bs->idata)); - - if (ch->ch_flags & CH_RWAIT) { - ch->ch_flags &= ~CH_RWAIT; - - wake_up_interruptible(&ch->ch_tun.un_flags_wait); - } - } - - /* - * Process Modem change signals. - */ - if (reason & IFMODEM) { - ch->ch_mistat = modem; - dgap_carrier(ch); - } - - /* - * Process break. - */ - if (reason & IFBREAK) { - - DPR_EVENT(("got IFBREAK\n")); - - if (ch->ch_tun.un_tty) { - /* A break has been indicated */ - ch->ch_err_break++; - tty_buffer_request_room(ch->ch_tun.un_tty->port, 1); - tty_insert_flip_char(ch->ch_tun.un_tty->port, 0, TTY_BREAK); - tty_flip_buffer_push(ch->ch_tun.un_tty->port); - } - } - - /* - * Process Transmit low. - */ - if (reason & IFTLW) { - - DPR_EVENT(("event: got low event\n")); - - if (ch->ch_tun.un_flags & UN_LOW) { - ch->ch_tun.un_flags &= ~UN_LOW; - - if (ch->ch_tun.un_flags & UN_ISOPEN) { - if ((ch->ch_tun.un_tty->flags & - (1 << TTY_DO_WRITE_WAKEUP)) && - ch->ch_tun.un_tty->ldisc->ops->write_wakeup) - { - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - (ch->ch_tun.un_tty->ldisc->ops->write_wakeup)(ch->ch_tun.un_tty); - DGAP_LOCK(bd->bd_lock, lock_flags); - DGAP_LOCK(ch->ch_lock, lock_flags2); - } - wake_up_interruptible(&ch->ch_tun.un_tty->write_wait); - wake_up_interruptible(&ch->ch_tun.un_flags_wait); - - DPR_EVENT(("event: Got low event. jiffies: %lu\n", jiffies)); - } - } - - if (ch->ch_pun.un_flags & UN_LOW) { - ch->ch_pun.un_flags &= ~UN_LOW; - if (ch->ch_pun.un_flags & UN_ISOPEN) { - if ((ch->ch_pun.un_tty->flags & - (1 << TTY_DO_WRITE_WAKEUP)) && - ch->ch_pun.un_tty->ldisc->ops->write_wakeup) - { - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - (ch->ch_pun.un_tty->ldisc->ops->write_wakeup)(ch->ch_pun.un_tty); - DGAP_LOCK(bd->bd_lock, lock_flags); - DGAP_LOCK(ch->ch_lock, lock_flags2); - } - wake_up_interruptible(&ch->ch_pun.un_tty->write_wait); - wake_up_interruptible(&ch->ch_pun.un_flags_wait); - } - } - - if (ch->ch_flags & CH_WLOW) { - ch->ch_flags &= ~CH_WLOW; - wake_up_interruptible(&ch->ch_flags_wait); - } - } - - /* - * Process Transmit empty. - */ - if (reason & IFTEM) { - DPR_EVENT(("event: got empty event\n")); - - if (ch->ch_tun.un_flags & UN_EMPTY) { - ch->ch_tun.un_flags &= ~UN_EMPTY; - if (ch->ch_tun.un_flags & UN_ISOPEN) { - if ((ch->ch_tun.un_tty->flags & - (1 << TTY_DO_WRITE_WAKEUP)) && - ch->ch_tun.un_tty->ldisc->ops->write_wakeup) - { - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - - (ch->ch_tun.un_tty->ldisc->ops->write_wakeup)(ch->ch_tun.un_tty); - DGAP_LOCK(bd->bd_lock, lock_flags); - DGAP_LOCK(ch->ch_lock, lock_flags2); - } - wake_up_interruptible(&ch->ch_tun.un_tty->write_wait); - wake_up_interruptible(&ch->ch_tun.un_flags_wait); - } - } - - if (ch->ch_pun.un_flags & UN_EMPTY) { - ch->ch_pun.un_flags &= ~UN_EMPTY; - if (ch->ch_pun.un_flags & UN_ISOPEN) { - if ((ch->ch_pun.un_tty->flags & - (1 << TTY_DO_WRITE_WAKEUP)) && - ch->ch_pun.un_tty->ldisc->ops->write_wakeup) - { - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - (ch->ch_pun.un_tty->ldisc->ops->write_wakeup)(ch->ch_pun.un_tty); - DGAP_LOCK(bd->bd_lock, lock_flags); - DGAP_LOCK(ch->ch_lock, lock_flags2); - } - wake_up_interruptible(&ch->ch_pun.un_tty->write_wait); - wake_up_interruptible(&ch->ch_pun.un_flags_wait); - } - } - - - if (ch->ch_flags & CH_WEMPTY) { - ch->ch_flags &= ~CH_WEMPTY; - wake_up_interruptible(&ch->ch_flags_wait); - } - } - - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - -next: - tail = (tail + 4) & (EVMAX - EVSTART - 4); - } - - writew(tail, &(eaddr->ev_tail)); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - - return 0; -} diff --git a/drivers/staging/dgap/dgap_fep5.h b/drivers/staging/dgap/dgap_fep5.h deleted file mode 100644 index d0650ae2dd5..00000000000 --- a/drivers/staging/dgap/dgap_fep5.h +++ /dev/null @@ -1,253 +0,0 @@ -/* - * Copyright 2003 Digi International (www.digi.com) - * Scott H Kilau <Scott_Kilau at digi dot com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the - * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!! - * - ************************************************************************ - *** FEP Version 5 dependent definitions - ************************************************************************/ - -#ifndef __DGAP_FEP5_H -#define __DGAP_FEP5_H - -/************************************************************************ - * FEP memory offsets - ************************************************************************/ -#define START 0x0004L /* Execution start address */ - -#define CMDBUF 0x0d10L /* Command (cm_t) structure offset */ -#define CMDSTART 0x0400L /* Start of command buffer */ -#define CMDMAX 0x0800L /* End of command buffer */ - -#define EVBUF 0x0d18L /* Event (ev_t) structure */ -#define EVSTART 0x0800L /* Start of event buffer */ -#define EVMAX 0x0c00L /* End of event buffer */ -#define FEP5_PLUS 0x0E40 /* ASCII '5' and ASCII 'A' is here */ -#define ECS_SEG 0x0E44 /* Segment of the extended channel structure */ -#define LINE_SPEED 0x10 /* Offset into ECS_SEG for line speed */ - /* if the fep has extended capabilities */ - -/* BIOS MAGIC SPOTS */ -#define ERROR 0x0C14L /* BIOS error code */ -#define SEQUENCE 0x0C12L /* BIOS sequence indicator */ -#define POSTAREA 0x0C00L /* POST complete message area */ - -/* FEP MAGIC SPOTS */ -#define FEPSTAT POSTAREA /* OS here when FEP comes up */ -#define NCHAN 0x0C02L /* number of ports FEP sees */ -#define PANIC 0x0C10L /* PANIC area for FEP */ -#define KMEMEM 0x0C30L /* Memory for KME use */ -#define CONFIG 0x0CD0L /* Concentrator configuration info */ -#define CONFIGSIZE 0x0030 /* configuration info size */ -#define DOWNREQ 0x0D00 /* Download request buffer pointer */ - -#define CHANBUF 0x1000L /* Async channel (bs_t) structs */ -#define FEPOSSIZE 0x1FFF /* 8K FEPOS */ - -#define XEMPORTS 0xC02 /* - * Offset in board memory where FEP5 stores - * how many ports it has detected. - * NOTE: FEP5 reports 64 ports when the user - * has the cable in EBI OUT instead of EBI IN. - */ - -#define FEPCLR 0x00 -#define FEPMEM 0x02 -#define FEPRST 0x04 -#define FEPINT 0x08 -#define FEPMASK 0x0e -#define FEPWIN 0x80 - -#define LOWMEM 0x0100 -#define HIGHMEM 0x7f00 - -#define FEPTIMEOUT 200000 - -#define ENABLE_INTR 0x0e04 /* Enable interrupts flag */ -#define FEPPOLL_MIN 1 /* minimum of 1 millisecond */ -#define FEPPOLL_MAX 20 /* maximum of 20 milliseconds */ -#define FEPPOLL 0x0c26 /* Fep event poll interval */ - -#define IALTPIN 0x0080 /* Input flag to swap DSR <-> DCD */ - -/************************************************************************ - * Command structure definition. - ************************************************************************/ -struct cm_t { - volatile unsigned short cm_head; /* Command buffer head offset */ - volatile unsigned short cm_tail; /* Command buffer tail offset */ - volatile unsigned short cm_start; /* start offset of buffer */ - volatile unsigned short cm_max; /* last offset of buffer */ -}; - -/************************************************************************ - * Event structure definition. - ************************************************************************/ -struct ev_t { - volatile unsigned short ev_head; /* Command buffer head offset */ - volatile unsigned short ev_tail; /* Command buffer tail offset */ - volatile unsigned short ev_start; /* start offset of buffer */ - volatile unsigned short ev_max; /* last offset of buffer */ -}; - -/************************************************************************ - * Download buffer structure. - ************************************************************************/ -struct downld_t { - uchar dl_type; /* Header */ - uchar dl_seq; /* Download sequence */ - ushort dl_srev; /* Software revision number */ - ushort dl_lrev; /* Low revision number */ - ushort dl_hrev; /* High revision number */ - ushort dl_seg; /* Start segment address */ - ushort dl_size; /* Number of bytes to download */ - uchar dl_data[1024]; /* Download data */ -}; - -/************************************************************************ - * Per channel buffer structure - ************************************************************************ - * Base Structure Entries Usage Meanings to Host * - * * - * W = read write R = read only * - * C = changed by commands only * - * U = unknown (may be changed w/o notice) * - ************************************************************************/ -struct bs_t { - volatile unsigned short tp_jmp; /* Transmit poll jump */ - volatile unsigned short tc_jmp; /* Cooked procedure jump */ - volatile unsigned short ri_jmp; /* Not currently used */ - volatile unsigned short rp_jmp; /* Receive poll jump */ - - volatile unsigned short tx_seg; /* W Tx segment */ - volatile unsigned short tx_head; /* W Tx buffer head offset */ - volatile unsigned short tx_tail; /* R Tx buffer tail offset */ - volatile unsigned short tx_max; /* W Tx buffer size - 1 */ - - volatile unsigned short rx_seg; /* W Rx segment */ - volatile unsigned short rx_head; /* W Rx buffer head offset */ - volatile unsigned short rx_tail; /* R Rx buffer tail offset */ - volatile unsigned short rx_max; /* W Rx buffer size - 1 */ - - volatile unsigned short tx_lw; /* W Tx buffer low water mark */ - volatile unsigned short rx_lw; /* W Rx buffer low water mark */ - volatile unsigned short rx_hw; /* W Rx buffer high water mark */ - volatile unsigned short incr; /* W Increment to next channel */ - - volatile unsigned short fepdev; /* U SCC device base address */ - volatile unsigned short edelay; /* W Exception delay */ - volatile unsigned short blen; /* W Break length */ - volatile unsigned short btime; /* U Break complete time */ - - volatile unsigned short iflag; /* C UNIX input flags */ - volatile unsigned short oflag; /* C UNIX output flags */ - volatile unsigned short cflag; /* C UNIX control flags */ - volatile unsigned short wfill[13]; /* U Reserved for expansion */ - - volatile unsigned char num; /* U Channel number */ - volatile unsigned char ract; /* U Receiver active counter */ - volatile unsigned char bstat; /* U Break status bits */ - volatile unsigned char tbusy; /* W Transmit busy */ - volatile unsigned char iempty; /* W Transmit empty event enable */ - volatile unsigned char ilow; /* W Transmit low-water event enable */ - volatile unsigned char idata; /* W Receive data interrupt enable */ - volatile unsigned char eflag; /* U Host event flags */ - - volatile unsigned char tflag; /* U Transmit flags */ - volatile unsigned char rflag; /* U Receive flags */ - volatile unsigned char xmask; /* U Transmit ready flags */ - volatile unsigned char xval; /* U Transmit ready value */ - volatile unsigned char m_stat; /* RC Modem status bits */ - volatile unsigned char m_change; /* U Modem bits which changed */ - volatile unsigned char m_int; /* W Modem interrupt enable bits */ - volatile unsigned char m_last; /* U Last modem status */ - - volatile unsigned char mtran; /* C Unreported modem trans */ - volatile unsigned char orun; /* C Buffer overrun occurred */ - volatile unsigned char astartc; /* W Auxiliary Xon char */ - volatile unsigned char astopc; /* W Auxiliary Xoff char */ - volatile unsigned char startc; /* W Xon character */ - volatile unsigned char stopc; /* W Xoff character */ - volatile unsigned char vnextc; /* W Vnext character */ - volatile unsigned char hflow; /* C Software flow control */ - - volatile unsigned char fillc; /* U Delay Fill character */ - volatile unsigned char ochar; /* U Saved output character */ - volatile unsigned char omask; /* U Output character mask */ - - volatile unsigned char bfill[13]; /* U Reserved for expansion */ - - volatile unsigned char scc[16]; /* U SCC registers */ -}; - - -/************************************************************************ - * FEP supported functions - ************************************************************************/ -#define SRLOW 0xe0 /* Set receive low water */ -#define SRHIGH 0xe1 /* Set receive high water */ -#define FLUSHTX 0xe2 /* Flush transmit buffer */ -#define PAUSETX 0xe3 /* Pause data transmission */ -#define RESUMETX 0xe4 /* Resume data transmission */ -#define SMINT 0xe5 /* Set Modem Interrupt */ -#define SAFLOWC 0xe6 /* Set Aux. flow control chars */ -#define SBREAK 0xe8 /* Send break */ -#define SMODEM 0xe9 /* Set 8530 modem control lines */ -#define SIFLAG 0xea /* Set UNIX iflags */ -#define SFLOWC 0xeb /* Set flow control characters */ -#define STLOW 0xec /* Set transmit low water mark */ -#define RPAUSE 0xee /* Pause receive */ -#define RRESUME 0xef /* Resume receive */ -#define CHRESET 0xf0 /* Reset Channel */ -#define BUFSETALL 0xf2 /* Set Tx & Rx buffer size avail*/ -#define SOFLAG 0xf3 /* Set UNIX oflags */ -#define SHFLOW 0xf4 /* Set hardware handshake */ -#define SCFLAG 0xf5 /* Set UNIX cflags */ -#define SVNEXT 0xf6 /* Set VNEXT character */ -#define SPINTFC 0xfc /* Reserved */ -#define SCOMMODE 0xfd /* Set RS232/422 mode */ - - -/************************************************************************ - * Modes for SCOMMODE - ************************************************************************/ -#define MODE_232 0x00 -#define MODE_422 0x01 - - -/************************************************************************ - * Event flags. - ************************************************************************/ -#define IFBREAK 0x01 /* Break received */ -#define IFTLW 0x02 /* Transmit low water */ -#define IFTEM 0x04 /* Transmitter empty */ -#define IFDATA 0x08 /* Receive data present */ -#define IFMODEM 0x20 /* Modem status change */ - -/************************************************************************ - * Modem flags - ************************************************************************/ -# define DM_RTS 0x02 /* Request to send */ -# define DM_CD 0x80 /* Carrier detect */ -# define DM_DSR 0x20 /* Data set ready */ -# define DM_CTS 0x10 /* Clear to send */ -# define DM_RI 0x40 /* Ring indicator */ -# define DM_DTR 0x01 /* Data terminal ready */ - - -#endif diff --git a/drivers/staging/dgap/dgap_kcompat.h b/drivers/staging/dgap/dgap_kcompat.h deleted file mode 100644 index 0dc2404922f..00000000000 --- a/drivers/staging/dgap/dgap_kcompat.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright 2004 Digi International (www.digi.com) - * Scott H Kilau <Scott_Kilau at digi dot com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the - * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!! - * - ************************************************************************* - * - * This file is intended to contain all the kernel "differences" between the - * various kernels that we support. - * - *************************************************************************/ - -#ifndef __DGAP_KCOMPAT_H -#define __DGAP_KCOMPAT_H - -#if !defined(TTY_FLIPBUF_SIZE) -# define TTY_FLIPBUF_SIZE 512 -#endif - - -/* Sparse stuff */ -# ifndef __user -# define __user -# define __kernel -# define __safe -# define __force -# define __chk_user_ptr(x) (void)0 -# endif - - -# define PARM_STR(VAR, INIT, PERM, DESC) \ - static char *VAR = INIT; \ - char *dgap_##VAR; \ - module_param(VAR, charp, PERM); \ - MODULE_PARM_DESC(VAR, DESC); - -# define PARM_INT(VAR, INIT, PERM, DESC) \ - static int VAR = INIT; \ - int dgap_##VAR; \ - module_param(VAR, int, PERM); \ - MODULE_PARM_DESC(VAR, DESC); - -# define PARM_ULONG(VAR, INIT, PERM, DESC) \ - static ulong VAR = INIT; \ - ulong dgap_##VAR; \ - module_param(VAR, long, PERM); \ - MODULE_PARM_DESC(VAR, DESC); - -#endif /* ! __DGAP_KCOMPAT_H */ diff --git a/drivers/staging/dgap/dgap_parse.c b/drivers/staging/dgap/dgap_parse.c deleted file mode 100644 index 7bc5bc326bf..00000000000 --- a/drivers/staging/dgap/dgap_parse.c +++ /dev/null @@ -1,1374 +0,0 @@ -/* - * Copyright 2003 Digi International (www.digi.com) - * Scott H Kilau <Scott_Kilau at digi dot com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the - * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * - * NOTE TO LINUX KERNEL HACKERS: DO NOT REFORMAT THIS CODE! - * - * This is shared code between Digi's CVS archive and the - * Linux Kernel sources. - * Changing the source just for reformatting needlessly breaks - * our CVS diff history. - * - * Send any bug fixes/changes to: Eng.Linux at digi dot com. - * Thank you. - * - * - ***************************************************************************** - * - * dgap_parse.c - Parses the configuration information from the input file. - * - * $Id: dgap_parse.c,v 1.1 2009/10/23 14:01:57 markh Exp $ - * - */ -#include <linux/kernel.h> -#include <linux/ctype.h> -#include <linux/slab.h> - -#include "dgap_types.h" -#include "dgap_fep5.h" -#include "dgap_driver.h" -#include "dgap_parse.h" -#include "dgap_conf.h" - - -/* - * Function prototypes. - */ -static int dgap_gettok(char **in, struct cnode *p); -static char *dgap_getword(char **in); -static char *dgap_savestring(char *s); -static struct cnode *dgap_newnode(int t); -static int dgap_checknode(struct cnode *p); -static void dgap_err(char *s); - -/* - * Our needed internal static variables... - */ -static struct cnode dgap_head; -#define MAXCWORD 200 -static char dgap_cword[MAXCWORD]; - -struct toklist { - int token; - char *string; -}; - -static struct toklist dgap_tlist[] = { - { BEGIN, "config_begin" }, - { END, "config_end" }, - { BOARD, "board" }, - { PCX, "Digi_AccelePort_C/X_PCI" }, /* C/X_PCI */ - { PEPC, "Digi_AccelePort_EPC/X_PCI" }, /* EPC/X_PCI */ - { PPCM, "Digi_AccelePort_Xem_PCI" }, /* PCI/Xem */ - { APORT2_920P, "Digi_AccelePort_2r_920_PCI" }, - { APORT4_920P, "Digi_AccelePort_4r_920_PCI" }, - { APORT8_920P, "Digi_AccelePort_8r_920_PCI" }, - { PAPORT4, "Digi_AccelePort_4r_PCI(EIA-232/RS-422)" }, - { PAPORT8, "Digi_AccelePort_8r_PCI(EIA-232/RS-422)" }, - { IO, "io" }, - { PCIINFO, "pciinfo" }, - { LINE, "line" }, - { CONC, "conc" }, - { CONC, "concentrator" }, - { CX, "cx" }, - { CX, "ccon" }, - { EPC, "epccon" }, - { EPC, "epc" }, - { MOD, "module" }, - { ID, "id" }, - { STARTO, "start" }, - { SPEED, "speed" }, - { CABLE, "cable" }, - { CONNECT, "connect" }, - { METHOD, "method" }, - { STATUS, "status" }, - { CUSTOM, "Custom" }, - { BASIC, "Basic" }, - { MEM, "mem" }, - { MEM, "memory" }, - { PORTS, "ports" }, - { MODEM, "modem" }, - { NPORTS, "nports" }, - { TTYN, "ttyname" }, - { CU, "cuname" }, - { PRINT, "prname" }, - { CMAJOR, "major" }, - { ALTPIN, "altpin" }, - { USEINTR, "useintr" }, - { TTSIZ, "ttysize" }, - { CHSIZ, "chsize" }, - { BSSIZ, "boardsize" }, - { UNTSIZ, "schedsize" }, - { F2SIZ, "f2200size" }, - { VPSIZ, "vpixsize" }, - { 0, NULL } -}; - - -/* - * Parse a configuration file read into memory as a string. - */ -int dgap_parsefile(char **in, int Remove) -{ - struct cnode *p, *brd, *line, *conc; - int rc; - char *s = NULL, *s2 = NULL; - int linecnt = 0; - - p = &dgap_head; - brd = line = conc = NULL; - - /* perhaps we are adding to an existing list? */ - while (p->next != NULL) { - p = p->next; - } - - /* file must start with a BEGIN */ - while ( (rc = dgap_gettok(in,p)) != BEGIN ) { - if (rc == 0) { - dgap_err("unexpected EOF"); - return(-1); - } - } - - for (; ; ) { - rc = dgap_gettok(in,p); - if (rc == 0) { - dgap_err("unexpected EOF"); - return(-1); - } - - switch (rc) { - case 0: - dgap_err("unexpected end of file"); - return(-1); - - case BEGIN: /* should only be 1 begin */ - dgap_err("unexpected config_begin\n"); - return(-1); - - case END: - return(0); - - case BOARD: /* board info */ - if (dgap_checknode(p)) - return(-1); - if ( (p->next = dgap_newnode(BNODE)) == NULL ) { - dgap_err("out of memory"); - return(-1); - } - p = p->next; - - p->u.board.status = dgap_savestring("No"); - line = conc = NULL; - brd = p; - linecnt = -1; - break; - - case APORT2_920P: /* AccelePort_4 */ - if (p->type != BNODE) { - dgap_err("unexpected Digi_2r_920 string"); - return(-1); - } - p->u.board.type = APORT2_920P; - p->u.board.v_type = 1; - DPR_INIT(("Adding Digi_2r_920 PCI to config...\n")); - break; - - case APORT4_920P: /* AccelePort_4 */ - if (p->type != BNODE) { - dgap_err("unexpected Digi_4r_920 string"); - return(-1); - } - p->u.board.type = APORT4_920P; - p->u.board.v_type = 1; - DPR_INIT(("Adding Digi_4r_920 PCI to config...\n")); - break; - - case APORT8_920P: /* AccelePort_8 */ - if (p->type != BNODE) { - dgap_err("unexpected Digi_8r_920 string"); - return(-1); - } - p->u.board.type = APORT8_920P; - p->u.board.v_type = 1; - DPR_INIT(("Adding Digi_8r_920 PCI to config...\n")); - break; - - case PAPORT4: /* AccelePort_4 PCI */ - if (p->type != BNODE) { - dgap_err("unexpected Digi_4r(PCI) string"); - return(-1); - } - p->u.board.type = PAPORT4; - p->u.board.v_type = 1; - DPR_INIT(("Adding Digi_4r PCI to config...\n")); - break; - - case PAPORT8: /* AccelePort_8 PCI */ - if (p->type != BNODE) { - dgap_err("unexpected Digi_8r string"); - return(-1); - } - p->u.board.type = PAPORT8; - p->u.board.v_type = 1; - DPR_INIT(("Adding Digi_8r PCI to config...\n")); - break; - - case PCX: /* PCI C/X */ - if (p->type != BNODE) { - dgap_err("unexpected Digi_C/X_(PCI) string"); - return(-1); - } - p->u.board.type = PCX; - p->u.board.v_type = 1; - p->u.board.conc1 = 0; - p->u.board.conc2 = 0; - p->u.board.module1 = 0; - p->u.board.module2 = 0; - DPR_INIT(("Adding PCI C/X to config...\n")); - break; - - case PEPC: /* PCI EPC/X */ - if (p->type != BNODE) { - dgap_err("unexpected \"Digi_EPC/X_(PCI)\" string"); - return(-1); - } - p->u.board.type = PEPC; - p->u.board.v_type = 1; - p->u.board.conc1 = 0; - p->u.board.conc2 = 0; - p->u.board.module1 = 0; - p->u.board.module2 = 0; - DPR_INIT(("Adding PCI EPC/X to config...\n")); - break; - - case PPCM: /* PCI/Xem */ - if (p->type != BNODE) { - dgap_err("unexpected PCI/Xem string"); - return(-1); - } - p->u.board.type = PPCM; - p->u.board.v_type = 1; - p->u.board.conc1 = 0; - p->u.board.conc2 = 0; - DPR_INIT(("Adding PCI XEM to config...\n")); - break; - - case IO: /* i/o port */ - if (p->type != BNODE) { - dgap_err("IO port only vaild for boards"); - return(-1); - } - s = dgap_getword(in); - if (s == NULL) { - dgap_err("unexpected end of file"); - return(-1); - } - p->u.board.portstr = dgap_savestring(s); - p->u.board.port = (short)simple_strtol(s, &s2, 0); - if ((short)strlen(s) > (short)(s2 - s)) { - dgap_err("bad number for IO port"); - return(-1); - } - p->u.board.v_port = 1; - DPR_INIT(("Adding IO (%s) to config...\n", s)); - break; - - case MEM: /* memory address */ - if (p->type != BNODE) { - dgap_err("memory address only vaild for boards"); - return(-1); - } - s = dgap_getword(in); - if (s == NULL) { - dgap_err("unexpected end of file"); - return(-1); - } - p->u.board.addrstr = dgap_savestring(s); - p->u.board.addr = simple_strtoul(s, &s2, 0); - if ((int)strlen(s) > (int)(s2 - s)) { - dgap_err("bad number for memory address"); - return(-1); - } - p->u.board.v_addr = 1; - DPR_INIT(("Adding MEM (%s) to config...\n", s)); - break; - - case PCIINFO: /* pci information */ - if (p->type != BNODE) { - dgap_err("memory address only vaild for boards"); - return(-1); - } - s = dgap_getword(in); - if (s == NULL) { - dgap_err("unexpected end of file"); - return(-1); - } - p->u.board.pcibusstr = dgap_savestring(s); - p->u.board.pcibus = simple_strtoul(s, &s2, 0); - if ((int)strlen(s) > (int)(s2 - s)) { - dgap_err("bad number for pci bus"); - return(-1); - } - p->u.board.v_pcibus = 1; - s = dgap_getword(in); - if (s == NULL) { - dgap_err("unexpected end of file"); - return(-1); - } - p->u.board.pcislotstr = dgap_savestring(s); - p->u.board.pcislot = simple_strtoul(s, &s2, 0); - if ((int)strlen(s) > (int)(s2 - s)) { - dgap_err("bad number for pci slot"); - return(-1); - } - p->u.board.v_pcislot = 1; - - DPR_INIT(("Adding PCIINFO (%s %s) to config...\n", p->u.board.pcibusstr, - p->u.board.pcislotstr)); - break; - - case METHOD: - if (p->type != BNODE) { - dgap_err("install method only vaild for boards"); - return(-1); - } - s = dgap_getword(in); - if (s == NULL) { - dgap_err("unexpected end of file"); - return(-1); - } - p->u.board.method = dgap_savestring(s); - p->u.board.v_method = 1; - DPR_INIT(("Adding METHOD (%s) to config...\n", s)); - break; - - case STATUS: - if (p->type != BNODE) { - dgap_err("config status only vaild for boards"); - return(-1); - } - s = dgap_getword(in); - if (s == NULL) { - dgap_err("unexpected end of file"); - return(-1); - } - p->u.board.status = dgap_savestring(s); - DPR_INIT(("Adding STATUS (%s) to config...\n", s)); - break; - - case NPORTS: /* number of ports */ - if (p->type == BNODE) { - s = dgap_getword(in); - if (s == NULL) { - dgap_err("unexpected end of file"); - return(-1); - } - p->u.board.nport = (char)simple_strtol(s, &s2, 0); - if ((int)strlen(s) > (int)(s2 - s)) { - dgap_err("bad number for number of ports"); - return(-1); - } - p->u.board.v_nport = 1; - } else if (p->type == CNODE) { - s = dgap_getword(in); - if (s == NULL) { - dgap_err("unexpected end of file"); - return(-1); - } - p->u.conc.nport = (char)simple_strtol(s, &s2, 0); - if ((int)strlen(s) > (int)(s2 - s)) { - dgap_err("bad number for number of ports"); - return(-1); - } - p->u.conc.v_nport = 1; - } else if (p->type == MNODE) { - s = dgap_getword(in); - if (s == NULL) { - dgap_err("unexpected end of file"); - return(-1); - } - p->u.module.nport = (char)simple_strtol(s, &s2, 0); - if ((int)strlen(s) > (int)(s2 - s)) { - dgap_err("bad number for number of ports"); - return(-1); - } - p->u.module.v_nport = 1; - } else { - dgap_err("nports only valid for concentrators or modules"); - return(-1); - } - DPR_INIT(("Adding NPORTS (%s) to config...\n", s)); - break; - - case ID: /* letter ID used in tty name */ - s = dgap_getword(in); - if (s == NULL) { - dgap_err("unexpected end of file"); - return(-1); - } - - p->u.board.status = dgap_savestring(s); - - if (p->type == CNODE) { - p->u.conc.id = dgap_savestring(s); - p->u.conc.v_id = 1; - } else if (p->type == MNODE) { - p->u.module.id = dgap_savestring(s); - p->u.module.v_id = 1; - } else { - dgap_err("id only valid for concentrators or modules"); - return(-1); - } - DPR_INIT(("Adding ID (%s) to config...\n", s)); - break; - - case STARTO: /* start offset of ID */ - if (p->type == BNODE) { - s = dgap_getword(in); - if (s == NULL) { - dgap_err("unexpected end of file"); - return(-1); - } - p->u.board.start = simple_strtol(s, &s2, 0); - if ((int)strlen(s) > (int)(s2 - s)) { - dgap_err("bad number for start of tty count"); - return(-1); - } - p->u.board.v_start = 1; - } else if (p->type == CNODE) { - s = dgap_getword(in); - if (s == NULL) { - dgap_err("unexpected end of file"); - return(-1); - } - p->u.conc.start = simple_strtol(s, &s2, 0); - if ((int)strlen(s) > (int)(s2 - s)) { - dgap_err("bad number for start of tty count"); - return(-1); - } - p->u.conc.v_start = 1; - } else if (p->type == MNODE) { - s = dgap_getword(in); - if (s == NULL) { - dgap_err("unexpected end of file"); - return(-1); - } - p->u.module.start = simple_strtol(s, &s2, 0); - if ((int)strlen(s) > (int)(s2 - s)) { - dgap_err("bad number for start of tty count"); - return(-1); - } - p->u.module.v_start = 1; - } else { - dgap_err("start only valid for concentrators or modules"); - return(-1); - } - DPR_INIT(("Adding START (%s) to config...\n", s)); - break; - - case TTYN: /* tty name prefix */ - if (dgap_checknode(p)) - return(-1); - if ( (p->next = dgap_newnode(TNODE)) == NULL ) { - dgap_err("out of memory"); - return(-1); - } - p = p->next; - if ( (s = dgap_getword(in)) == NULL ) { - dgap_err("unexpeced end of file"); - return(-1); - } - if ( (p->u.ttyname = dgap_savestring(s)) == NULL ) { - dgap_err("out of memory"); - return(-1); - } - DPR_INIT(("Adding TTY (%s) to config...\n", s)); - break; - - case CU: /* cu name prefix */ - if (dgap_checknode(p)) - return(-1); - if ( (p->next = dgap_newnode(CUNODE)) == NULL ) { - dgap_err("out of memory"); - return(-1); - } - p = p->next; - if ( (s = dgap_getword(in)) == NULL ) { - dgap_err("unexpeced end of file"); - return(-1); - } - if ( (p->u.cuname = dgap_savestring(s)) == NULL ) { - dgap_err("out of memory"); - return(-1); - } - DPR_INIT(("Adding CU (%s) to config...\n", s)); - break; - - case LINE: /* line information */ - if (dgap_checknode(p)) - return(-1); - if (brd == NULL) { - dgap_err("must specify board before line info"); - return(-1); - } - switch (brd->u.board.type) { - case PPCM: - dgap_err("line not vaild for PC/em"); - return(-1); - } - if ( (p->next = dgap_newnode(LNODE)) == NULL ) { - dgap_err("out of memory"); - return(-1); - } - p = p->next; - conc = NULL; - line = p; - linecnt++; - DPR_INIT(("Adding LINE to config...\n")); - break; - - case CONC: /* concentrator information */ - if (dgap_checknode(p)) - return(-1); - if (line == NULL) { - dgap_err("must specify line info before concentrator"); - return(-1); - } - if ( (p->next = dgap_newnode(CNODE)) == NULL ) { - dgap_err("out of memory"); - return(-1); - } - p = p->next; - conc = p; - if (linecnt) - brd->u.board.conc2++; - else - brd->u.board.conc1++; - - DPR_INIT(("Adding CONC to config...\n")); - break; - - case CX: /* c/x type concentrator */ - if (p->type != CNODE) { - dgap_err("cx only valid for concentrators"); - return(-1); - } - p->u.conc.type = CX; - p->u.conc.v_type = 1; - DPR_INIT(("Adding CX to config...\n")); - break; - - case EPC: /* epc type concentrator */ - if (p->type != CNODE) { - dgap_err("cx only valid for concentrators"); - return(-1); - } - p->u.conc.type = EPC; - p->u.conc.v_type = 1; - DPR_INIT(("Adding EPC to config...\n")); - break; - - case MOD: /* EBI module */ - if (dgap_checknode(p)) - return(-1); - if (brd == NULL) { - dgap_err("must specify board info before EBI modules"); - return(-1); - } - switch (brd->u.board.type) { - case PPCM: - linecnt = 0; - break; - default: - if (conc == NULL) { - dgap_err("must specify concentrator info before EBI module"); - return(-1); - } - } - if ( (p->next = dgap_newnode(MNODE)) == NULL ) { - dgap_err("out of memory"); - return(-1); - } - p = p->next; - if (linecnt) - brd->u.board.module2++; - else - brd->u.board.module1++; - - DPR_INIT(("Adding MOD to config...\n")); - break; - - case PORTS: /* ports type EBI module */ - if (p->type != MNODE) { - dgap_err("ports only valid for EBI modules"); - return(-1); - } - p->u.module.type = PORTS; - p->u.module.v_type = 1; - DPR_INIT(("Adding PORTS to config...\n")); - break; - - case MODEM: /* ports type EBI module */ - if (p->type != MNODE) { - dgap_err("modem only valid for modem modules"); - return(-1); - } - p->u.module.type = MODEM; - p->u.module.v_type = 1; - DPR_INIT(("Adding MODEM to config...\n")); - break; - - case CABLE: - if (p->type == LNODE) { - if ((s = dgap_getword(in)) == NULL) { - dgap_err("unexpected end of file"); - return(-1); - } - p->u.line.cable = dgap_savestring(s); - p->u.line.v_cable = 1; - } - DPR_INIT(("Adding CABLE (%s) to config...\n", s)); - break; - - case SPEED: /* sync line speed indication */ - if (p->type == LNODE) { - s = dgap_getword(in); - if (s == NULL) { - dgap_err("unexpected end of file"); - return(-1); - } - p->u.line.speed = (char)simple_strtol(s, &s2, 0); - if ((short)strlen(s) > (short)(s2 - s)) { - dgap_err("bad number for line speed"); - return(-1); - } - p->u.line.v_speed = 1; - } else if (p->type == CNODE) { - s = dgap_getword(in); - if (s == NULL) { - dgap_err("unexpected end of file"); - return(-1); - } - p->u.conc.speed = (char)simple_strtol(s, &s2, 0); - if ((short)strlen(s) > (short)(s2 - s)) { - dgap_err("bad number for line speed"); - return(-1); - } - p->u.conc.v_speed = 1; - } else { - dgap_err("speed valid only for lines or concentrators."); - return(-1); - } - DPR_INIT(("Adding SPEED (%s) to config...\n", s)); - break; - - case CONNECT: - if (p->type == CNODE) { - if ((s = dgap_getword(in)) == NULL) { - dgap_err("unexpected end of file"); - return(-1); - } - p->u.conc.connect = dgap_savestring(s); - p->u.conc.v_connect = 1; - } - DPR_INIT(("Adding CONNECT (%s) to config...\n", s)); - break; - case PRINT: /* transparent print name prefix */ - if (dgap_checknode(p)) - return(-1); - if ( (p->next = dgap_newnode(PNODE)) == NULL ) { - dgap_err("out of memory"); - return(-1); - } - p = p->next; - if ( (s = dgap_getword(in)) == NULL ) { - dgap_err("unexpeced end of file"); - return(-1); - } - if ( (p->u.printname = dgap_savestring(s)) == NULL ) { - dgap_err("out of memory"); - return(-1); - } - DPR_INIT(("Adding PRINT (%s) to config...\n", s)); - break; - - case CMAJOR: /* major number */ - if (dgap_checknode(p)) - return(-1); - if ( (p->next = dgap_newnode(JNODE)) == NULL ) { - dgap_err("out of memory"); - return(-1); - } - p = p->next; - s = dgap_getword(in); - if (s == NULL) { - dgap_err("unexpected end of file"); - return(-1); - } - p->u.majornumber = simple_strtol(s, &s2, 0); - if ((int)strlen(s) > (int)(s2 - s)) { - dgap_err("bad number for major number"); - return(-1); - } - DPR_INIT(("Adding CMAJOR (%s) to config...\n", s)); - break; - - case ALTPIN: /* altpin setting */ - if (dgap_checknode(p)) - return(-1); - if ( (p->next = dgap_newnode(ANODE)) == NULL ) { - dgap_err("out of memory"); - return(-1); - } - p = p->next; - s = dgap_getword(in); - if (s == NULL) { - dgap_err("unexpected end of file"); - return(-1); - } - p->u.altpin = simple_strtol(s, &s2, 0); - if ((int)strlen(s) > (int)(s2 - s)) { - dgap_err("bad number for altpin"); - return(-1); - } - DPR_INIT(("Adding ALTPIN (%s) to config...\n", s)); - break; - - case USEINTR: /* enable interrupt setting */ - if (dgap_checknode(p)) - return(-1); - if ( (p->next = dgap_newnode(INTRNODE)) == NULL ) { - dgap_err("out of memory"); - return(-1); - } - p = p->next; - s = dgap_getword(in); - if (s == NULL) { - dgap_err("unexpected end of file"); - return(-1); - } - p->u.useintr = simple_strtol(s, &s2, 0); - if ((int)strlen(s) > (int)(s2 - s)) { - dgap_err("bad number for useintr"); - return(-1); - } - DPR_INIT(("Adding USEINTR (%s) to config...\n", s)); - break; - - case TTSIZ: /* size of tty structure */ - if (dgap_checknode(p)) - return(-1); - if ( (p->next = dgap_newnode(TSNODE)) == NULL ) { - dgap_err("out of memory"); - return(-1); - } - p = p->next; - s = dgap_getword(in); - if (s == NULL) { - dgap_err("unexpected end of file"); - return(-1); - } - p->u.ttysize = simple_strtol(s, &s2, 0); - if ((int)strlen(s) > (int)(s2 - s)) { - dgap_err("bad number for ttysize"); - return(-1); - } - DPR_INIT(("Adding TTSIZ (%s) to config...\n", s)); - break; - - case CHSIZ: /* channel structure size */ - if (dgap_checknode(p)) - return(-1); - if ( (p->next = dgap_newnode(CSNODE)) == NULL ) { - dgap_err("out of memory"); - return(-1); - } - p = p->next; - s = dgap_getword(in); - if (s == NULL) { - dgap_err("unexpected end of file"); - return(-1); - } - p->u.chsize = simple_strtol(s, &s2, 0); - if ((int)strlen(s) > (int)(s2 - s)) { - dgap_err("bad number for chsize"); - return(-1); - } - DPR_INIT(("Adding CHSIZE (%s) to config...\n", s)); - break; - - case BSSIZ: /* board structure size */ - if (dgap_checknode(p)) - return(-1); - if ( (p->next = dgap_newnode(BSNODE)) == NULL ) { - dgap_err("out of memory"); - return(-1); - } - p = p->next; - s = dgap_getword(in); - if (s == NULL) { - dgap_err("unexpected end of file"); - return(-1); - } - p->u.bssize = simple_strtol(s, &s2, 0); - if ((int)strlen(s) > (int)(s2 - s)) { - dgap_err("bad number for bssize"); - return(-1); - } - DPR_INIT(("Adding BSSIZ (%s) to config...\n", s)); - break; - - case UNTSIZ: /* sched structure size */ - if (dgap_checknode(p)) - return(-1); - if ( (p->next = dgap_newnode(USNODE)) == NULL ) { - dgap_err("out of memory"); - return(-1); - } - p = p->next; - s = dgap_getword(in); - if (s == NULL) { - dgap_err("unexpected end of file"); - return(-1); - } - p->u.unsize = simple_strtol(s, &s2, 0); - if ((int)strlen(s) > (int)(s2 - s)) { - dgap_err("bad number for schedsize"); - return(-1); - } - DPR_INIT(("Adding UNTSIZ (%s) to config...\n", s)); - break; - - case F2SIZ: /* f2200 structure size */ - if (dgap_checknode(p)) - return(-1); - if ( (p->next = dgap_newnode(FSNODE)) == NULL ) { - dgap_err("out of memory"); - return(-1); - } - p = p->next; - s = dgap_getword(in); - if (s == NULL) { - dgap_err("unexpected end of file"); - return(-1); - } - p->u.f2size = simple_strtol(s, &s2, 0); - if ((int)strlen(s) > (int)(s2 - s)) { - dgap_err("bad number for f2200size"); - return(-1); - } - DPR_INIT(("Adding F2SIZ (%s) to config...\n", s)); - break; - - case VPSIZ: /* vpix structure size */ - if (dgap_checknode(p)) - return(-1); - if ( (p->next = dgap_newnode(VSNODE)) == NULL ) { - dgap_err("out of memory"); - return(-1); - } - p = p->next; - s = dgap_getword(in); - if (s == NULL) { - dgap_err("unexpected end of file"); - return(-1); - } - p->u.vpixsize = simple_strtol(s, &s2, 0); - if ((int)strlen(s) > (int)(s2 - s)) { - dgap_err("bad number for vpixsize"); - return(-1); - } - DPR_INIT(("Adding VPSIZ (%s) to config...\n", s)); - break; - } - } -} - - -/* - * dgap_sindex: much like index(), but it looks for a match of any character in - * the group, and returns that position. If the first character is a ^, then - * this will match the first occurrence not in that group. - */ -static char *dgap_sindex (char *string, char *group) -{ - char *ptr; - - if (!string || !group) - return (char *) NULL; - - if (*group == '^') { - group++; - for (; *string; string++) { - for (ptr = group; *ptr; ptr++) { - if (*ptr == *string) - break; - } - if (*ptr == '\0') - return string; - } - } - else { - for (; *string; string++) { - for (ptr = group; *ptr; ptr++) { - if (*ptr == *string) - return string; - } - } - } - - return (char *) NULL; -} - - -/* - * Get a token from the input file; return 0 if end of file is reached - */ -static int dgap_gettok(char **in, struct cnode *p) -{ - char *w; - struct toklist *t; - - if (strstr(dgap_cword, "boar")) { - w = dgap_getword(in); - snprintf(dgap_cword, MAXCWORD, "%s", w); - for (t = dgap_tlist; t->token != 0; t++) { - if ( !strcmp(w, t->string)) { - return(t->token); - } - } - dgap_err("board !!type not specified"); - return(1); - } - else { - while ( (w = dgap_getword(in)) != NULL ) { - snprintf(dgap_cword, MAXCWORD, "%s", w); - for (t = dgap_tlist; t->token != 0; t++) { - if ( !strcmp(w, t->string) ) - return(t->token); - } - } - return(0); - } -} - - -/* - * get a word from the input stream, also keep track of current line number. - * words are separated by whitespace. - */ -static char *dgap_getword(char **in) -{ - char *ret_ptr = *in; - - char *ptr = dgap_sindex(*in, " \t\n"); - - /* If no word found, return null */ - if (!ptr) - return NULL; - - /* Mark new location for our buffer */ - *ptr = '\0'; - *in = ptr + 1; - - /* Eat any extra spaces/tabs/newlines that might be present */ - while (*in && **in && ((**in == ' ') || (**in == '\t') || (**in == '\n'))) { - **in = '\0'; - *in = *in + 1; - } - - return ret_ptr; -} - - -/* - * print an error message, giving the line number in the file where - * the error occurred. - */ -static void dgap_err(char *s) -{ - printk("DGAP: parse: %s\n", s); -} - - -/* - * allocate a new configuration node of type t - */ -static struct cnode *dgap_newnode(int t) -{ - struct cnode *n; - - n = kmalloc(sizeof(struct cnode), GFP_ATOMIC); - if (n != NULL) { - memset((char *)n, 0, sizeof(struct cnode)); - n->type = t; - } - return(n); -} - - -/* - * dgap_checknode: see if all the necessary info has been supplied for a node - * before creating the next node. - */ -static int dgap_checknode(struct cnode *p) -{ - switch (p->type) { - case BNODE: - if (p->u.board.v_type == 0) { - dgap_err("board type !not specified"); - return(1); - } - - return(0); - - case LNODE: - if (p->u.line.v_speed == 0) { - dgap_err("line speed not specified"); - return(1); - } - return(0); - - case CNODE: - if (p->u.conc.v_type == 0) { - dgap_err("concentrator type not specified"); - return(1); - } - if (p->u.conc.v_speed == 0) { - dgap_err("concentrator line speed not specified"); - return(1); - } - if (p->u.conc.v_nport == 0) { - dgap_err("number of ports on concentrator not specified"); - return(1); - } - if (p->u.conc.v_id == 0) { - dgap_err("concentrator id letter not specified"); - return(1); - } - return(0); - - case MNODE: - if (p->u.module.v_type == 0) { - dgap_err("EBI module type not specified"); - return(1); - } - if (p->u.module.v_nport == 0) { - dgap_err("number of ports on EBI module not specified"); - return(1); - } - if (p->u.module.v_id == 0) { - dgap_err("EBI module id letter not specified"); - return(1); - } - return(0); - } - return(0); -} - -/* - * save a string somewhere - */ -static char *dgap_savestring(char *s) -{ - char *p; - if ( (p = kmalloc(strlen(s) + 1, GFP_ATOMIC) ) != NULL) { - strcpy(p, s); - } - return(p); -} - - -/* - * Given a board pointer, returns whether we should use interrupts or not. - */ -uint dgap_config_get_useintr(struct board_t *bd) -{ - struct cnode *p = NULL; - - if (!bd) - return(0); - - for (p = bd->bd_config; p; p = p->next) { - switch (p->type) { - case INTRNODE: - /* - * check for pcxr types. - */ - return p->u.useintr; - default: - break; - } - } - - /* If not found, then don't turn on interrupts. */ - return 0; -} - - -/* - * Given a board pointer, returns whether we turn on altpin or not. - */ -uint dgap_config_get_altpin(struct board_t *bd) -{ - struct cnode *p = NULL; - - if (!bd) - return(0); - - for (p = bd->bd_config; p; p = p->next) { - switch (p->type) { - case ANODE: - /* - * check for pcxr types. - */ - return p->u.altpin; - default: - break; - } - } - - /* If not found, then don't turn on interrupts. */ - return 0; -} - - - -/* - * Given a specific type of board, if found, detached link and - * returns the first occurrence in the list. - */ -struct cnode *dgap_find_config(int type, int bus, int slot) -{ - struct cnode *p, *prev = NULL, *prev2 = NULL, *found = NULL; - - p = &dgap_head; - - while (p->next != NULL) { - prev = p; - p = p->next; - - if (p->type == BNODE) { - - if (p->u.board.type == type) { - - if (p->u.board.v_pcibus && p->u.board.pcibus != bus) { - DPR(("Found matching board, but wrong bus position. System says bus %d, we want bus %ld\n", - bus, p->u.board.pcibus)); - continue; - } - if (p->u.board.v_pcislot && p->u.board.pcislot != slot) { - DPR_INIT(("Found matching board, but wrong slot position. System says slot %d, we want slot %ld\n", - slot, p->u.board.pcislot)); - continue; - } - - DPR_INIT(("Matched type in config file\n")); - - found = p; - /* - * Keep walking thru the list till we find the next board. - */ - while (p->next != NULL) { - prev2 = p; - p = p->next; - if (p->type == BNODE) { - - /* - * Mark the end of our 1 board chain of configs. - */ - prev2->next = NULL; - - /* - * Link the "next" board to the previous board, - * effectively "unlinking" our board from the main config. - */ - prev->next = p; - - return found; - } - } - /* - * It must be the last board in the list. - */ - prev->next = NULL; - return found; - } - } - } - return NULL; -} - -/* - * Given a board pointer, walks the config link, counting up - * all ports user specified should be on the board. - * (This does NOT mean they are all actually present right now tho) - */ -uint dgap_config_get_number_of_ports(struct board_t *bd) -{ - int count = 0; - struct cnode *p = NULL; - - if (!bd) - return(0); - - for (p = bd->bd_config; p; p = p->next) { - - switch (p->type) { - case BNODE: - /* - * check for pcxr types. - */ - if (p->u.board.type > EPCFE) - count += p->u.board.nport; - break; - case CNODE: - count += p->u.conc.nport; - break; - case MNODE: - count += p->u.module.nport; - break; - } - } - return (count); -} - -char *dgap_create_config_string(struct board_t *bd, char *string) -{ - char *ptr = string; - struct cnode *p = NULL; - struct cnode *q = NULL; - int speed; - - if (!bd) { - *ptr = 0xff; - return string; - } - - for (p = bd->bd_config; p; p = p->next) { - - switch (p->type) { - case LNODE: - *ptr = '\0'; - ptr++; - *ptr = p->u.line.speed; - ptr++; - break; - case CNODE: - /* - * Because the EPC/con concentrators can have EM modules - * hanging off of them, we have to walk ahead in the list - * and keep adding the number of ports on each EM to the config. - * UGH! - */ - speed = p->u.conc.speed; - q = p->next; - if ((q != NULL) && (q->type == MNODE) ) { - *ptr = (p->u.conc.nport + 0x80); - ptr++; - p = q; - while ((q->next != NULL) && (q->next->type) == MNODE) { - *ptr = (q->u.module.nport + 0x80); - ptr++; - p = q; - q = q->next; - } - *ptr = q->u.module.nport; - ptr++; - } else { - *ptr = p->u.conc.nport; - ptr++; - } - - *ptr = speed; - ptr++; - break; - } - } - - *ptr = 0xff; - return string; -} - - - -char *dgap_get_config_letters(struct board_t *bd, char *string) -{ - int found = FALSE; - char *ptr = string; - struct cnode *cptr = NULL; - int len = 0; - int left = MAXTTYNAMELEN; - - if (!bd) { - return "<NULL>"; - } - - for (cptr = bd->bd_config; cptr; cptr = cptr->next) { - - if ((cptr->type == BNODE) && - ((cptr->u.board.type == APORT2_920P) || (cptr->u.board.type == APORT4_920P) || - (cptr->u.board.type == APORT8_920P) || (cptr->u.board.type == PAPORT4) || - (cptr->u.board.type == PAPORT8))) { - - found = TRUE; - } - - if (cptr->type == TNODE && found == TRUE) { - char *ptr1; - if (strstr(cptr->u.ttyname, "tty")) { - ptr1 = cptr->u.ttyname; - ptr1 += 3; - } - else { - ptr1 = cptr->u.ttyname; - } - if (ptr1) { - len = snprintf(ptr, left, "%s", ptr1); - left -= len; - ptr += len; - if (left <= 0) - break; - } - } - - if (cptr->type == CNODE) { - if (cptr->u.conc.id) { - len = snprintf(ptr, left, "%s", cptr->u.conc.id); - left -= len; - ptr += len; - if (left <= 0) - break; - } - } - - if (cptr->type == MNODE) { - if (cptr->u.module.id) { - len = snprintf(ptr, left, "%s", cptr->u.module.id); - left -= len; - ptr += len; - if (left <= 0) - break; - } - } - } - - return string; -} diff --git a/drivers/staging/dgap/dgap_parse.h b/drivers/staging/dgap/dgap_parse.h deleted file mode 100644 index 8128c47343c..00000000000 --- a/drivers/staging/dgap/dgap_parse.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2003 Digi International (www.digi.com) - * Scott H Kilau <Scott_Kilau at digi dot com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the - * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!! - */ - -#ifndef _DGAP_PARSE_H -#define _DGAP_PARSE_H - -#include "dgap_driver.h" - -extern int dgap_parsefile(char **in, int Remove); -extern struct cnode *dgap_find_config(int type, int bus, int slot); -extern uint dgap_config_get_number_of_ports(struct board_t *bd); -extern char *dgap_create_config_string(struct board_t *bd, char *string); -extern char *dgap_get_config_letters(struct board_t *bd, char *string); -extern uint dgap_config_get_useintr(struct board_t *bd); -extern uint dgap_config_get_altpin(struct board_t *bd); - -#endif diff --git a/drivers/staging/dgap/dgap_pci.h b/drivers/staging/dgap/dgap_pci.h deleted file mode 100644 index 05ed374f08e..00000000000 --- a/drivers/staging/dgap/dgap_pci.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright 2003 Digi International (www.digi.com) - * Scott H Kilau <Scott_Kilau at digi dot com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the - * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!! - */ - -/* $Id: dgap_pci.h,v 1.1 2009/10/23 14:01:57 markh Exp $ */ - -#ifndef __DGAP_PCI_H -#define __DGAP_PCI_H - -#define PCIMAX 32 /* maximum number of PCI boards */ - -#define DIGI_VID 0x114F - -#define PCI_DEVICE_EPC_DID 0x0002 -#define PCI_DEVICE_XEM_DID 0x0004 -#define PCI_DEVICE_XR_DID 0x0005 -#define PCI_DEVICE_CX_DID 0x0006 -#define PCI_DEVICE_XRJ_DID 0x0009 /* PLX-based Xr adapter */ -#define PCI_DEVICE_XR_IBM_DID 0x0011 /* IBM 8-port Async Adapter */ -#define PCI_DEVICE_XR_BULL_DID 0x0013 /* BULL 8-port Async Adapter */ -#define PCI_DEVICE_XR_SAIP_DID 0x001c /* SAIP card - Xr adapter */ -#define PCI_DEVICE_XR_422_DID 0x0012 /* Xr-422 */ -#define PCI_DEVICE_920_2_DID 0x0034 /* XR-Plus 920 K, 2 port */ -#define PCI_DEVICE_920_4_DID 0x0026 /* XR-Plus 920 K, 4 port */ -#define PCI_DEVICE_920_8_DID 0x0027 /* XR-Plus 920 K, 8 port */ -#define PCI_DEVICE_EPCJ_DID 0x000a /* PLX 9060 chip for PCI */ -#define PCI_DEVICE_CX_IBM_DID 0x001b /* IBM 128-port Async Adapter */ -#define PCI_DEVICE_920_8_HP_DID 0x0058 /* HP XR-Plus 920 K, 8 port */ -#define PCI_DEVICE_XEM_HP_DID 0x0059 /* HP Xem PCI */ - -#define PCI_DEVICE_XEM_NAME "AccelePort XEM" -#define PCI_DEVICE_CX_NAME "AccelePort CX" -#define PCI_DEVICE_XR_NAME "AccelePort Xr" -#define PCI_DEVICE_XRJ_NAME "AccelePort Xr (PLX)" -#define PCI_DEVICE_XR_SAIP_NAME "AccelePort Xr (SAIP)" -#define PCI_DEVICE_920_2_NAME "AccelePort Xr920 2 port" -#define PCI_DEVICE_920_4_NAME "AccelePort Xr920 4 port" -#define PCI_DEVICE_920_8_NAME "AccelePort Xr920 8 port" -#define PCI_DEVICE_XR_422_NAME "AccelePort Xr 422" -#define PCI_DEVICE_EPCJ_NAME "AccelePort EPC (PLX)" -#define PCI_DEVICE_XR_BULL_NAME "AccelePort Xr (BULL)" -#define PCI_DEVICE_XR_IBM_NAME "AccelePort Xr (IBM)" -#define PCI_DEVICE_CX_IBM_NAME "AccelePort CX (IBM)" -#define PCI_DEVICE_920_8_HP_NAME "AccelePort Xr920 8 port (HP)" -#define PCI_DEVICE_XEM_HP_NAME "AccelePort XEM (HP)" - - -/* - * On the PCI boards, there is no IO space allocated - * The I/O registers will be in the first 3 bytes of the - * upper 2MB of the 4MB memory space. The board memory - * will be mapped into the low 2MB of the 4MB memory space - */ - -/* Potential location of PCI Bios from E0000 to FFFFF*/ -#define PCI_BIOS_SIZE 0x00020000 - -/* Size of Memory and I/O for PCI (4MB) */ -#define PCI_RAM_SIZE 0x00400000 - -/* Size of Memory (2MB) */ -#define PCI_MEM_SIZE 0x00200000 - -/* Max PCI Window Size (2MB) */ -#define PCI_WIN_SIZE 0x00200000 - -#define PCI_WIN_SHIFT 21 /* 21 bits max */ - -/* Offset of I/0 in Memory (2MB) */ -#define PCI_IO_OFFSET 0x00200000 - -/* Size of IO (2MB) */ -#define PCI_IO_SIZE 0x00200000 - -#endif diff --git a/drivers/staging/dgap/dgap_sysfs.c b/drivers/staging/dgap/dgap_sysfs.c deleted file mode 100644 index aa7e36f9d5d..00000000000 --- a/drivers/staging/dgap/dgap_sysfs.c +++ /dev/null @@ -1,793 +0,0 @@ -/* - * Copyright 2004 Digi International (www.digi.com) - * Scott H Kilau <Scott_Kilau at digi dot com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the - * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * - * NOTE TO LINUX KERNEL HACKERS: DO NOT REFORMAT THIS CODE! - * - * This is shared code between Digi's CVS archive and the - * Linux Kernel sources. - * Changing the source just for reformatting needlessly breaks - * our CVS diff history. - * - * Send any bug fixes/changes to: Eng.Linux at digi dot com. - * Thank you. - * - * - * - * $Id: dgap_sysfs.c,v 1.1 2009/10/23 14:01:57 markh Exp $ - */ - - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/ctype.h> -#include <linux/string.h> -#include <linux/serial_reg.h> -#include <linux/device.h> -#include <linux/pci.h> -#include <linux/kdev_t.h> - -#include "dgap_driver.h" -#include "dgap_conf.h" -#include "dgap_parse.h" - - -static ssize_t dgap_driver_version_show(struct device_driver *ddp, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%s\n", DG_PART); -} -static DRIVER_ATTR(version, S_IRUSR, dgap_driver_version_show, NULL); - - -static ssize_t dgap_driver_boards_show(struct device_driver *ddp, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%d\n", dgap_NumBoards); -} -static DRIVER_ATTR(boards, S_IRUSR, dgap_driver_boards_show, NULL); - - -static ssize_t dgap_driver_maxboards_show(struct device_driver *ddp, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%d\n", MAXBOARDS); -} -static DRIVER_ATTR(maxboards, S_IRUSR, dgap_driver_maxboards_show, NULL); - - -static ssize_t dgap_driver_pollcounter_show(struct device_driver *ddp, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%ld\n", dgap_poll_counter); -} -static DRIVER_ATTR(pollcounter, S_IRUSR, dgap_driver_pollcounter_show, NULL); - - -static ssize_t dgap_driver_state_show(struct device_driver *ddp, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%s\n", dgap_driver_state_text[dgap_driver_state]); -} -static DRIVER_ATTR(state, S_IRUSR, dgap_driver_state_show, NULL); - - -static ssize_t dgap_driver_debug_show(struct device_driver *ddp, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "0x%x\n", dgap_debug); -} - -static ssize_t dgap_driver_debug_store(struct device_driver *ddp, const char *buf, size_t count) -{ - sscanf(buf, "0x%x\n", &dgap_debug); - return count; -} -static DRIVER_ATTR(debug, (S_IRUSR | S_IWUSR), dgap_driver_debug_show, dgap_driver_debug_store); - - -static ssize_t dgap_driver_rawreadok_show(struct device_driver *ddp, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "0x%x\n", dgap_rawreadok); -} - -static ssize_t dgap_driver_rawreadok_store(struct device_driver *ddp, const char *buf, size_t count) -{ - sscanf(buf, "0x%x\n", &dgap_rawreadok); - return count; -} -static DRIVER_ATTR(rawreadok, (S_IRUSR | S_IWUSR), dgap_driver_rawreadok_show, dgap_driver_rawreadok_store); - - -static ssize_t dgap_driver_pollrate_show(struct device_driver *ddp, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%dms\n", dgap_poll_tick); -} - -static ssize_t dgap_driver_pollrate_store(struct device_driver *ddp, const char *buf, size_t count) -{ - sscanf(buf, "%d\n", &dgap_poll_tick); - return count; -} -static DRIVER_ATTR(pollrate, (S_IRUSR | S_IWUSR), dgap_driver_pollrate_show, dgap_driver_pollrate_store); - - -void dgap_create_driver_sysfiles(struct pci_driver *dgap_driver) -{ - int rc = 0; - struct device_driver *driverfs = &dgap_driver->driver; - - rc |= driver_create_file(driverfs, &driver_attr_version); - rc |= driver_create_file(driverfs, &driver_attr_boards); - rc |= driver_create_file(driverfs, &driver_attr_maxboards); - rc |= driver_create_file(driverfs, &driver_attr_debug); - rc |= driver_create_file(driverfs, &driver_attr_rawreadok); - rc |= driver_create_file(driverfs, &driver_attr_pollrate); - rc |= driver_create_file(driverfs, &driver_attr_pollcounter); - rc |= driver_create_file(driverfs, &driver_attr_state); - if (rc) { - printk(KERN_ERR "DGAP: sysfs driver_create_file failed!\n"); - } -} - - -void dgap_remove_driver_sysfiles(struct pci_driver *dgap_driver) -{ - struct device_driver *driverfs = &dgap_driver->driver; - driver_remove_file(driverfs, &driver_attr_version); - driver_remove_file(driverfs, &driver_attr_boards); - driver_remove_file(driverfs, &driver_attr_maxboards); - driver_remove_file(driverfs, &driver_attr_debug); - driver_remove_file(driverfs, &driver_attr_rawreadok); - driver_remove_file(driverfs, &driver_attr_pollrate); - driver_remove_file(driverfs, &driver_attr_pollcounter); - driver_remove_file(driverfs, &driver_attr_state); -} - - -#define DGAP_VERIFY_BOARD(p, bd) \ - if (!p) \ - return (0); \ - \ - bd = dev_get_drvdata(p); \ - if (!bd || bd->magic != DGAP_BOARD_MAGIC) \ - return (0); \ - if (bd->state != BOARD_READY) \ - return (0); \ - - -static ssize_t dgap_ports_state_show(struct device *p, struct device_attribute *attr, char *buf) -{ - struct board_t *bd; - int count = 0; - int i = 0; - - DGAP_VERIFY_BOARD(p, bd); - - for (i = 0; i < bd->nasync; i++) { - count += snprintf(buf + count, PAGE_SIZE - count, - "%d %s\n", bd->channels[i]->ch_portnum, - bd->channels[i]->ch_open_count ? "Open" : "Closed"); - } - return count; -} -static DEVICE_ATTR(ports_state, S_IRUSR, dgap_ports_state_show, NULL); - - -static ssize_t dgap_ports_baud_show(struct device *p, struct device_attribute *attr, char *buf) -{ - struct board_t *bd; - int count = 0; - int i = 0; - - DGAP_VERIFY_BOARD(p, bd); - - for (i = 0; i < bd->nasync; i++) { - count += snprintf(buf + count, PAGE_SIZE - count, - "%d %d\n", bd->channels[i]->ch_portnum, bd->channels[i]->ch_baud_info); - } - return count; -} -static DEVICE_ATTR(ports_baud, S_IRUSR, dgap_ports_baud_show, NULL); - - -static ssize_t dgap_ports_msignals_show(struct device *p, struct device_attribute *attr, char *buf) -{ - struct board_t *bd; - int count = 0; - int i = 0; - - DGAP_VERIFY_BOARD(p, bd); - - for (i = 0; i < bd->nasync; i++) { - if (bd->channels[i]->ch_open_count) { - count += snprintf(buf + count, PAGE_SIZE - count, - "%d %s %s %s %s %s %s\n", bd->channels[i]->ch_portnum, - (bd->channels[i]->ch_mostat & UART_MCR_RTS) ? "RTS" : "", - (bd->channels[i]->ch_mistat & UART_MSR_CTS) ? "CTS" : "", - (bd->channels[i]->ch_mostat & UART_MCR_DTR) ? "DTR" : "", - (bd->channels[i]->ch_mistat & UART_MSR_DSR) ? "DSR" : "", - (bd->channels[i]->ch_mistat & UART_MSR_DCD) ? "DCD" : "", - (bd->channels[i]->ch_mistat & UART_MSR_RI) ? "RI" : ""); - } else { - count += snprintf(buf + count, PAGE_SIZE - count, - "%d\n", bd->channels[i]->ch_portnum); - } - } - return count; -} -static DEVICE_ATTR(ports_msignals, S_IRUSR, dgap_ports_msignals_show, NULL); - - -static ssize_t dgap_ports_iflag_show(struct device *p, struct device_attribute *attr, char *buf) -{ - struct board_t *bd; - int count = 0; - int i = 0; - - DGAP_VERIFY_BOARD(p, bd); - - for (i = 0; i < bd->nasync; i++) { - count += snprintf(buf + count, PAGE_SIZE - count, "%d %x\n", - bd->channels[i]->ch_portnum, bd->channels[i]->ch_c_iflag); - } - return count; -} -static DEVICE_ATTR(ports_iflag, S_IRUSR, dgap_ports_iflag_show, NULL); - - -static ssize_t dgap_ports_cflag_show(struct device *p, struct device_attribute *attr, char *buf) -{ - struct board_t *bd; - int count = 0; - int i = 0; - - DGAP_VERIFY_BOARD(p, bd); - - for (i = 0; i < bd->nasync; i++) { - count += snprintf(buf + count, PAGE_SIZE - count, "%d %x\n", - bd->channels[i]->ch_portnum, bd->channels[i]->ch_c_cflag); - } - return count; -} -static DEVICE_ATTR(ports_cflag, S_IRUSR, dgap_ports_cflag_show, NULL); - - -static ssize_t dgap_ports_oflag_show(struct device *p, struct device_attribute *attr, char *buf) -{ - struct board_t *bd; - int count = 0; - int i = 0; - - DGAP_VERIFY_BOARD(p, bd); - - for (i = 0; i < bd->nasync; i++) { - count += snprintf(buf + count, PAGE_SIZE - count, "%d %x\n", - bd->channels[i]->ch_portnum, bd->channels[i]->ch_c_oflag); - } - return count; -} -static DEVICE_ATTR(ports_oflag, S_IRUSR, dgap_ports_oflag_show, NULL); - - -static ssize_t dgap_ports_lflag_show(struct device *p, struct device_attribute *attr, char *buf) -{ - struct board_t *bd; - int count = 0; - int i = 0; - - DGAP_VERIFY_BOARD(p, bd); - - for (i = 0; i < bd->nasync; i++) { - count += snprintf(buf + count, PAGE_SIZE - count, "%d %x\n", - bd->channels[i]->ch_portnum, bd->channels[i]->ch_c_lflag); - } - return count; -} -static DEVICE_ATTR(ports_lflag, S_IRUSR, dgap_ports_lflag_show, NULL); - - -static ssize_t dgap_ports_digi_flag_show(struct device *p, struct device_attribute *attr, char *buf) -{ - struct board_t *bd; - int count = 0; - int i = 0; - - DGAP_VERIFY_BOARD(p, bd); - - for (i = 0; i < bd->nasync; i++) { - count += snprintf(buf + count, PAGE_SIZE - count, "%d %x\n", - bd->channels[i]->ch_portnum, bd->channels[i]->ch_digi.digi_flags); - } - return count; -} -static DEVICE_ATTR(ports_digi_flag, S_IRUSR, dgap_ports_digi_flag_show, NULL); - - -static ssize_t dgap_ports_rxcount_show(struct device *p, struct device_attribute *attr, char *buf) -{ - struct board_t *bd; - int count = 0; - int i = 0; - - DGAP_VERIFY_BOARD(p, bd); - - for (i = 0; i < bd->nasync; i++) { - count += snprintf(buf + count, PAGE_SIZE - count, "%d %ld\n", - bd->channels[i]->ch_portnum, bd->channels[i]->ch_rxcount); - } - return count; -} -static DEVICE_ATTR(ports_rxcount, S_IRUSR, dgap_ports_rxcount_show, NULL); - - -static ssize_t dgap_ports_txcount_show(struct device *p, struct device_attribute *attr, char *buf) -{ - struct board_t *bd; - int count = 0; - int i = 0; - - DGAP_VERIFY_BOARD(p, bd); - - for (i = 0; i < bd->nasync; i++) { - count += snprintf(buf + count, PAGE_SIZE - count, "%d %ld\n", - bd->channels[i]->ch_portnum, bd->channels[i]->ch_txcount); - } - return count; -} -static DEVICE_ATTR(ports_txcount, S_IRUSR, dgap_ports_txcount_show, NULL); - - -/* this function creates the sys files that will export each signal status - * to sysfs each value will be put in a separate filename - */ -void dgap_create_ports_sysfiles(struct board_t *bd) -{ - int rc = 0; - - dev_set_drvdata(&bd->pdev->dev, bd); - rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_state); - rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_baud); - rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_msignals); - rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_iflag); - rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_cflag); - rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_oflag); - rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_lflag); - rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_digi_flag); - rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_rxcount); - rc |= device_create_file(&(bd->pdev->dev), &dev_attr_ports_txcount); - if (rc) { - printk(KERN_ERR "DGAP: sysfs device_create_file failed!\n"); - } -} - - -/* removes all the sys files created for that port */ -void dgap_remove_ports_sysfiles(struct board_t *bd) -{ - device_remove_file(&(bd->pdev->dev), &dev_attr_ports_state); - device_remove_file(&(bd->pdev->dev), &dev_attr_ports_baud); - device_remove_file(&(bd->pdev->dev), &dev_attr_ports_msignals); - device_remove_file(&(bd->pdev->dev), &dev_attr_ports_iflag); - device_remove_file(&(bd->pdev->dev), &dev_attr_ports_cflag); - device_remove_file(&(bd->pdev->dev), &dev_attr_ports_oflag); - device_remove_file(&(bd->pdev->dev), &dev_attr_ports_lflag); - device_remove_file(&(bd->pdev->dev), &dev_attr_ports_digi_flag); - device_remove_file(&(bd->pdev->dev), &dev_attr_ports_rxcount); - device_remove_file(&(bd->pdev->dev), &dev_attr_ports_txcount); -} - - -static ssize_t dgap_tty_state_show(struct device *d, struct device_attribute *attr, char *buf) -{ - struct board_t *bd; - struct channel_t *ch; - struct un_t *un; - - if (!d) - return (0); - un = dev_get_drvdata(d); - if (!un || un->magic != DGAP_UNIT_MAGIC) - return (0); - ch = un->un_ch; - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return (0); - bd = ch->ch_bd; - if (!bd || bd->magic != DGAP_BOARD_MAGIC) - return (0); - if (bd->state != BOARD_READY) - return (0); - - return snprintf(buf, PAGE_SIZE, "%s", un->un_open_count ? "Open" : "Closed"); -} -static DEVICE_ATTR(state, S_IRUSR, dgap_tty_state_show, NULL); - - -static ssize_t dgap_tty_baud_show(struct device *d, struct device_attribute *attr, char *buf) -{ - struct board_t *bd; - struct channel_t *ch; - struct un_t *un; - - if (!d) - return (0); - un = dev_get_drvdata(d); - if (!un || un->magic != DGAP_UNIT_MAGIC) - return (0); - ch = un->un_ch; - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return (0); - bd = ch->ch_bd; - if (!bd || bd->magic != DGAP_BOARD_MAGIC) - return (0); - if (bd->state != BOARD_READY) - return (0); - - return snprintf(buf, PAGE_SIZE, "%d\n", ch->ch_baud_info); -} -static DEVICE_ATTR(baud, S_IRUSR, dgap_tty_baud_show, NULL); - - -static ssize_t dgap_tty_msignals_show(struct device *d, struct device_attribute *attr, char *buf) -{ - struct board_t *bd; - struct channel_t *ch; - struct un_t *un; - - if (!d) - return (0); - un = dev_get_drvdata(d); - if (!un || un->magic != DGAP_UNIT_MAGIC) - return (0); - ch = un->un_ch; - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return (0); - bd = ch->ch_bd; - if (!bd || bd->magic != DGAP_BOARD_MAGIC) - return (0); - if (bd->state != BOARD_READY) - return (0); - - if (ch->ch_open_count) { - return snprintf(buf, PAGE_SIZE, "%s %s %s %s %s %s\n", - (ch->ch_mostat & UART_MCR_RTS) ? "RTS" : "", - (ch->ch_mistat & UART_MSR_CTS) ? "CTS" : "", - (ch->ch_mostat & UART_MCR_DTR) ? "DTR" : "", - (ch->ch_mistat & UART_MSR_DSR) ? "DSR" : "", - (ch->ch_mistat & UART_MSR_DCD) ? "DCD" : "", - (ch->ch_mistat & UART_MSR_RI) ? "RI" : ""); - } - return 0; -} -static DEVICE_ATTR(msignals, S_IRUSR, dgap_tty_msignals_show, NULL); - - -static ssize_t dgap_tty_iflag_show(struct device *d, struct device_attribute *attr, char *buf) -{ - struct board_t *bd; - struct channel_t *ch; - struct un_t *un; - - if (!d) - return (0); - un = dev_get_drvdata(d); - if (!un || un->magic != DGAP_UNIT_MAGIC) - return (0); - ch = un->un_ch; - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return (0); - bd = ch->ch_bd; - if (!bd || bd->magic != DGAP_BOARD_MAGIC) - return (0); - if (bd->state != BOARD_READY) - return (0); - - return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_c_iflag); -} -static DEVICE_ATTR(iflag, S_IRUSR, dgap_tty_iflag_show, NULL); - - -static ssize_t dgap_tty_cflag_show(struct device *d, struct device_attribute *attr, char *buf) -{ - struct board_t *bd; - struct channel_t *ch; - struct un_t *un; - - if (!d) - return (0); - un = dev_get_drvdata(d); - if (!un || un->magic != DGAP_UNIT_MAGIC) - return (0); - ch = un->un_ch; - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return (0); - bd = ch->ch_bd; - if (!bd || bd->magic != DGAP_BOARD_MAGIC) - return (0); - if (bd->state != BOARD_READY) - return (0); - - return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_c_cflag); -} -static DEVICE_ATTR(cflag, S_IRUSR, dgap_tty_cflag_show, NULL); - - -static ssize_t dgap_tty_oflag_show(struct device *d, struct device_attribute *attr, char *buf) -{ - struct board_t *bd; - struct channel_t *ch; - struct un_t *un; - - if (!d) - return (0); - un = dev_get_drvdata(d); - if (!un || un->magic != DGAP_UNIT_MAGIC) - return (0); - ch = un->un_ch; - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return (0); - bd = ch->ch_bd; - if (!bd || bd->magic != DGAP_BOARD_MAGIC) - return (0); - if (bd->state != BOARD_READY) - return (0); - - return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_c_oflag); -} -static DEVICE_ATTR(oflag, S_IRUSR, dgap_tty_oflag_show, NULL); - - -static ssize_t dgap_tty_lflag_show(struct device *d, struct device_attribute *attr, char *buf) -{ - struct board_t *bd; - struct channel_t *ch; - struct un_t *un; - - if (!d) - return (0); - un = dev_get_drvdata(d); - if (!un || un->magic != DGAP_UNIT_MAGIC) - return (0); - ch = un->un_ch; - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return (0); - bd = ch->ch_bd; - if (!bd || bd->magic != DGAP_BOARD_MAGIC) - return (0); - if (bd->state != BOARD_READY) - return (0); - - return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_c_lflag); -} -static DEVICE_ATTR(lflag, S_IRUSR, dgap_tty_lflag_show, NULL); - - -static ssize_t dgap_tty_digi_flag_show(struct device *d, struct device_attribute *attr, char *buf) -{ - struct board_t *bd; - struct channel_t *ch; - struct un_t *un; - - if (!d) - return (0); - un = dev_get_drvdata(d); - if (!un || un->magic != DGAP_UNIT_MAGIC) - return (0); - ch = un->un_ch; - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return (0); - bd = ch->ch_bd; - if (!bd || bd->magic != DGAP_BOARD_MAGIC) - return (0); - if (bd->state != BOARD_READY) - return (0); - - return snprintf(buf, PAGE_SIZE, "%x\n", ch->ch_digi.digi_flags); -} -static DEVICE_ATTR(digi_flag, S_IRUSR, dgap_tty_digi_flag_show, NULL); - - -static ssize_t dgap_tty_rxcount_show(struct device *d, struct device_attribute *attr, char *buf) -{ - struct board_t *bd; - struct channel_t *ch; - struct un_t *un; - - if (!d) - return (0); - un = dev_get_drvdata(d); - if (!un || un->magic != DGAP_UNIT_MAGIC) - return (0); - ch = un->un_ch; - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return (0); - bd = ch->ch_bd; - if (!bd || bd->magic != DGAP_BOARD_MAGIC) - return (0); - if (bd->state != BOARD_READY) - return (0); - - return snprintf(buf, PAGE_SIZE, "%ld\n", ch->ch_rxcount); -} -static DEVICE_ATTR(rxcount, S_IRUSR, dgap_tty_rxcount_show, NULL); - - -static ssize_t dgap_tty_txcount_show(struct device *d, struct device_attribute *attr, char *buf) -{ - struct board_t *bd; - struct channel_t *ch; - struct un_t *un; - - if (!d) - return (0); - un = dev_get_drvdata(d); - if (!un || un->magic != DGAP_UNIT_MAGIC) - return (0); - ch = un->un_ch; - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return (0); - bd = ch->ch_bd; - if (!bd || bd->magic != DGAP_BOARD_MAGIC) - return (0); - if (bd->state != BOARD_READY) - return (0); - - return snprintf(buf, PAGE_SIZE, "%ld\n", ch->ch_txcount); -} -static DEVICE_ATTR(txcount, S_IRUSR, dgap_tty_txcount_show, NULL); - - -static ssize_t dgap_tty_name_show(struct device *d, struct device_attribute *attr, char *buf) -{ - struct board_t *bd; - struct channel_t *ch; - struct un_t *un; - int cn; - int bn; - struct cnode *cptr = NULL; - int found = FALSE; - int ncount = 0; - int starto = 0; - int i = 0; - - if (!d) - return (0); - un = dev_get_drvdata(d); - if (!un || un->magic != DGAP_UNIT_MAGIC) - return (0); - ch = un->un_ch; - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return (0); - bd = ch->ch_bd; - if (!bd || bd->magic != DGAP_BOARD_MAGIC) - return (0); - if (bd->state != BOARD_READY) - return (0); - - bn = bd->boardnum; - cn = ch->ch_portnum; - - for (cptr = bd->bd_config; cptr; cptr = cptr->next) { - - if ((cptr->type == BNODE) && - ((cptr->u.board.type == APORT2_920P) || (cptr->u.board.type == APORT4_920P) || - (cptr->u.board.type == APORT8_920P) || (cptr->u.board.type == PAPORT4) || - (cptr->u.board.type == PAPORT8))) { - - found = TRUE; - if (cptr->u.board.v_start) - starto = cptr->u.board.start; - else - starto = 1; - } - - if (cptr->type == TNODE && found == TRUE) { - char *ptr1; - if (strstr(cptr->u.ttyname, "tty")) { - ptr1 = cptr->u.ttyname; - ptr1 += 3; - } - else { - ptr1 = cptr->u.ttyname; - } - - for (i = 0; i < dgap_config_get_number_of_ports(bd); i++) { - if (cn == i) { - return snprintf(buf, PAGE_SIZE, "%s%s%02d\n", - (un->un_type == DGAP_PRINT) ? "pr" : "tty", - ptr1, i + starto); - } - } - } - - if (cptr->type == CNODE) { - - for (i = 0; i < cptr->u.conc.nport; i++) { - if (cn == (i + ncount)) { - - return snprintf(buf, PAGE_SIZE, "%s%s%02d\n", - (un->un_type == DGAP_PRINT) ? "pr" : "tty", - cptr->u.conc.id, - i + (cptr->u.conc.v_start ? cptr->u.conc.start : 1)); - } - } - - ncount += cptr->u.conc.nport; - } - - if (cptr->type == MNODE) { - - for (i = 0; i < cptr->u.module.nport; i++) { - if (cn == (i + ncount)) { - return snprintf(buf, PAGE_SIZE, "%s%s%02d\n", - (un->un_type == DGAP_PRINT) ? "pr" : "tty", - cptr->u.module.id, - i + (cptr->u.module.v_start ? cptr->u.module.start : 1)); - } - } - - ncount += cptr->u.module.nport; - - } - } - - return snprintf(buf, PAGE_SIZE, "%s_dgap_%d_%d\n", - (un->un_type == DGAP_PRINT) ? "pr" : "tty", bn, cn); - -} -static DEVICE_ATTR(custom_name, S_IRUSR, dgap_tty_name_show, NULL); - - -static struct attribute *dgap_sysfs_tty_entries[] = { - &dev_attr_state.attr, - &dev_attr_baud.attr, - &dev_attr_msignals.attr, - &dev_attr_iflag.attr, - &dev_attr_cflag.attr, - &dev_attr_oflag.attr, - &dev_attr_lflag.attr, - &dev_attr_digi_flag.attr, - &dev_attr_rxcount.attr, - &dev_attr_txcount.attr, - &dev_attr_custom_name.attr, - NULL -}; - - -static struct attribute_group dgap_tty_attribute_group = { - .name = NULL, - .attrs = dgap_sysfs_tty_entries, -}; - - - - -void dgap_create_tty_sysfs(struct un_t *un, struct device *c) -{ - int ret; - - ret = sysfs_create_group(&c->kobj, &dgap_tty_attribute_group); - if (ret) { - printk(KERN_ERR "dgap: failed to create sysfs tty device attributes.\n"); - sysfs_remove_group(&c->kobj, &dgap_tty_attribute_group); - return; - } - - dev_set_drvdata(c, un); - -} - - -void dgap_remove_tty_sysfs(struct device *c) -{ - sysfs_remove_group(&c->kobj, &dgap_tty_attribute_group); -} diff --git a/drivers/staging/dgap/dgap_sysfs.h b/drivers/staging/dgap/dgap_sysfs.h deleted file mode 100644 index 151f1b32c76..00000000000 --- a/drivers/staging/dgap/dgap_sysfs.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2003 Digi International (www.digi.com) - * Scott H Kilau <Scott_Kilau at digi dot com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the - * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!! - */ - -#ifndef __DGAP_SYSFS_H -#define __DGAP_SYSFS_H - -#include "dgap_driver.h" - -#include <linux/device.h> - -struct board_t; -struct channel_t; -struct un_t; -struct pci_driver; -struct class_device; - -extern void dgap_create_ports_sysfiles(struct board_t *bd); -extern void dgap_remove_ports_sysfiles(struct board_t *bd); - -extern void dgap_create_driver_sysfiles(struct pci_driver *); -extern void dgap_remove_driver_sysfiles(struct pci_driver *); - -extern int dgap_tty_class_init(void); -extern int dgap_tty_class_destroy(void); - -extern void dgap_create_tty_sysfs(struct un_t *un, struct device *c); -extern void dgap_remove_tty_sysfs(struct device *c); - - -#endif diff --git a/drivers/staging/dgap/dgap_trace.c b/drivers/staging/dgap/dgap_trace.c deleted file mode 100644 index a53db9e0a57..00000000000 --- a/drivers/staging/dgap/dgap_trace.c +++ /dev/null @@ -1,186 +0,0 @@ -/* - * Copyright 2003 Digi International (www.digi.com) - * Scott H Kilau <Scott_Kilau at digi dot com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the - * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * - * NOTE TO LINUX KERNEL HACKERS: DO NOT REFORMAT THIS CODE! - * - * This is shared code between Digi's CVS archive and the - * Linux Kernel sources. - * Changing the source just for reformatting needlessly breaks - * our CVS diff history. - * - * Send any bug fixes/changes to: Eng.Linux at digi dot com. - * Thank you. - * - */ - -/* $Id: dgap_trace.c,v 1.1 2009/10/23 14:01:57 markh Exp $ */ - -#include <linux/kernel.h> -#include <linux/sched.h> /* For jiffies, task states */ -#include <linux/interrupt.h> /* For tasklet and interrupt structs/defines */ -#include <linux/vmalloc.h> - -#include "dgap_driver.h" -#include "dgap_trace.h" - -#define TRC_TO_CONSOLE 1 - -/* file level globals */ -static char *dgap_trcbuf; /* the ringbuffer */ - -#if defined(TRC_TO_KMEM) -static int dgap_trcbufi = 0; /* index of the tilde at the end of */ -#endif - -extern int dgap_trcbuf_size; /* size of the ringbuffer */ - -#if defined(TRC_TO_KMEM) -static DEFINE_SPINLOCK(dgap_tracef_lock); -#endif - -#if 0 - -#if !defined(TRC_TO_KMEM) && !defined(TRC_TO_CONSOLE) -void dgap_tracef(const char *fmt, ...) -{ - return; -} - -#else /* !defined(TRC_TO_KMEM) && !defined(TRC_TO_CONSOLE) */ - -void dgap_tracef(const char *fmt, ...) -{ - va_list ap; - char buf[TRC_MAXMSG+1]; - size_t lenbuf; - int i; - static int failed = FALSE; -# if defined(TRC_TO_KMEM) - unsigned long flags; -#endif - - if(failed) - return; -# if defined(TRC_TO_KMEM) - DGAP_LOCK(dgap_tracef_lock, flags); -#endif - - /* Format buf using fmt and arguments contained in ap. */ - va_start(ap, fmt); - i = vsprintf(buf, fmt, ap); - va_end(ap); - lenbuf = strlen(buf); - -# if defined(TRC_TO_KMEM) - { - static int initd=0; - - /* - * Now, in addition to (or instead of) printing this stuff out - * (which is a buffered operation), also tuck it away into a - * corner of memory which can be examined post-crash in kdb. - */ - if (!initd) { - dgap_trcbuf = (char *) vmalloc(dgap_trcbuf_size); - if(!dgap_trcbuf) { - failed = TRUE; - printk("dgap: tracing init failed!\n"); - return; - } - - memset(dgap_trcbuf, '\0', dgap_trcbuf_size); - dgap_trcbufi = 0; - initd++; - - printk("dgap: tracing enabled - " TRC_DTRC - " 0x%lx 0x%x\n", - (unsigned long)dgap_trcbuf, - dgap_trcbuf_size); - } - -# if defined(TRC_ON_OVERFLOW_WRAP_AROUND) - /* - * This is the less CPU-intensive way to do things. We simply - * wrap around before we fall off the end of the buffer. A - * tilde (~) demarcates the current end of the trace. - * - * This method should be used if you are concerned about race - * conditions as it is less likely to affect the timing of - * things. - */ - - if (dgap_trcbufi + lenbuf >= dgap_trcbuf_size) { - /* We are wrapping, so wipe out the last tilde. */ - dgap_trcbuf[dgap_trcbufi] = '\0'; - /* put the new string at the beginning of the buffer */ - dgap_trcbufi = 0; - } - - strcpy(&dgap_trcbuf[dgap_trcbufi], buf); - dgap_trcbufi += lenbuf; - dgap_trcbuf[dgap_trcbufi] = '~'; - -# elif defined(TRC_ON_OVERFLOW_SHIFT_BUFFER) - /* - * This is the more CPU-intensive way to do things. If we - * venture into the last 1/8 of the buffer, we shift the - * last 7/8 of the buffer forward, wiping out the first 1/8. - * Advantage: No wrap-around, only truncation from the - * beginning. - * - * This method should not be used if you are concerned about - * timing changes affecting the behaviour of the driver (ie, - * race conditions). - */ - strcpy(&dgap_trcbuf[dgap_trcbufi], buf); - dgap_trcbufi += lenbuf; - dgap_trcbuf[dgap_trcbufi] = '~'; - dgap_trcbuf[dgap_trcbufi+1] = '\0'; - - /* If we're near the end of the trace buffer... */ - if (dgap_trcbufi > (dgap_trcbuf_size/8)*7) { - /* Wipe out the first eighth to make some more room. */ - strcpy(dgap_trcbuf, &dgap_trcbuf[dgap_trcbuf_size/8]); - dgap_trcbufi = strlen(dgap_trcbuf)-1; - /* Plop overflow message at the top of the buffer. */ - bcopy(TRC_OVERFLOW, dgap_trcbuf, strlen(TRC_OVERFLOW)); - } -# else -# error "TRC_ON_OVERFLOW_WRAP_AROUND or TRC_ON_OVERFLOW_SHIFT_BUFFER?" -# endif - } - DGAP_UNLOCK(dgap_tracef_lock, flags); - -# endif /* defined(TRC_TO_KMEM) */ -} - -#endif /* !defined(TRC_TO_KMEM) && !defined(TRC_TO_CONSOLE) */ - -#endif - -/* - * dgap_tracer_free() - * - * - */ -void dgap_tracer_free(void) -{ - if(dgap_trcbuf) - vfree(dgap_trcbuf); -} diff --git a/drivers/staging/dgap/dgap_trace.h b/drivers/staging/dgap/dgap_trace.h deleted file mode 100644 index b21f46198e7..00000000000 --- a/drivers/staging/dgap/dgap_trace.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2003 Digi International (www.digi.com) - * Scott H Kilau <Scott_Kilau at digi dot com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the - * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!! - * - ***************************************************************************** - * Header file for dgap_trace.c - * - * $Id: dgap_trace.h,v 1.1 2009/10/23 14:01:57 markh Exp $ - */ - -#ifndef __DGAP_TRACE_H -#define __DGAP_TRACE_H - -#include "dgap_driver.h" - -void dgap_tracef(const char *fmt, ...); -void dgap_tracer_free(void); - -#endif - diff --git a/drivers/staging/dgap/dgap_tty.c b/drivers/staging/dgap/dgap_tty.c deleted file mode 100644 index 565319f883c..00000000000 --- a/drivers/staging/dgap/dgap_tty.c +++ /dev/null @@ -1,3556 +0,0 @@ -/* - * Copyright 2003 Digi International (www.digi.com) - * Scott H Kilau <Scott_Kilau at digi dot com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the - * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * - * NOTE TO LINUX KERNEL HACKERS: DO NOT REFORMAT THIS CODE! - * - * This is shared code between Digi's CVS archive and the - * Linux Kernel sources. - * Changing the source just for reformatting needlessly breaks - * our CVS diff history. - * - * Send any bug fixes/changes to: Eng.Linux at digi dot com. - * Thank you. - */ - -/************************************************************************ - * - * This file implements the tty driver functionality for the - * FEP5 based product lines. - * - ************************************************************************ - * - * $Id: dgap_tty.c,v 1.3 2011/06/23 12:11:31 markh Exp $ - */ - -#include <linux/kernel.h> -#include <linux/sched.h> /* For jiffies, task states */ -#include <linux/interrupt.h> /* For tasklet and interrupt structs/defines */ -#include <linux/module.h> -#include <linux/ctype.h> -#include <linux/tty.h> -#include <linux/tty_flip.h> -#include <linux/serial_reg.h> -#include <linux/slab.h> -#include <linux/delay.h> /* For udelay */ -#include <asm/uaccess.h> /* For copy_from_user/copy_to_user */ -#include <asm/io.h> /* For read[bwl]/write[bwl] */ -#include <linux/pci.h> - -#include "dgap_driver.h" -#include "dgap_tty.h" -#include "dgap_types.h" -#include "dgap_fep5.h" -#include "dgap_parse.h" -#include "dgap_conf.h" -#include "dgap_sysfs.h" - -#define init_MUTEX(sem) sema_init(sem, 1) -#define DECLARE_MUTEX(name) \ - struct semaphore name = __SEMAPHORE_INITIALIZER(name, 1) - -/* - * internal variables - */ -static struct board_t *dgap_BoardsByMajor[256]; -static uchar *dgap_TmpWriteBuf = NULL; -static DECLARE_MUTEX(dgap_TmpWriteSem); - -/* - * Default transparent print information. - */ -static struct digi_t dgap_digi_init = { - .digi_flags = DIGI_COOK, /* Flags */ - .digi_maxcps = 100, /* Max CPS */ - .digi_maxchar = 50, /* Max chars in print queue */ - .digi_bufsize = 100, /* Printer buffer size */ - .digi_onlen = 4, /* size of printer on string */ - .digi_offlen = 4, /* size of printer off string */ - .digi_onstr = "\033[5i", /* ANSI printer on string ] */ - .digi_offstr = "\033[4i", /* ANSI printer off string ] */ - .digi_term = "ansi" /* default terminal type */ -}; - - -/* - * Define a local default termios struct. All ports will be created - * with this termios initially. - * - * This defines a raw port at 9600 baud, 8 data bits, no parity, - * 1 stop bit. - */ - -static struct ktermios DgapDefaultTermios = -{ - .c_iflag = (DEFAULT_IFLAGS), /* iflags */ - .c_oflag = (DEFAULT_OFLAGS), /* oflags */ - .c_cflag = (DEFAULT_CFLAGS), /* cflags */ - .c_lflag = (DEFAULT_LFLAGS), /* lflags */ - .c_cc = INIT_C_CC, - .c_line = 0, -}; - -/* Our function prototypes */ -static int dgap_tty_open(struct tty_struct *tty, struct file *file); -static void dgap_tty_close(struct tty_struct *tty, struct file *file); -static int dgap_block_til_ready(struct tty_struct *tty, struct file *file, struct channel_t *ch); -static int dgap_tty_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg); -static int dgap_tty_digigeta(struct tty_struct *tty, struct digi_t __user *retinfo); -static int dgap_tty_digiseta(struct tty_struct *tty, struct digi_t __user *new_info); -static int dgap_tty_digigetedelay(struct tty_struct *tty, int __user *retinfo); -static int dgap_tty_digisetedelay(struct tty_struct *tty, int __user *new_info); -static int dgap_tty_write_room(struct tty_struct* tty); -static int dgap_tty_chars_in_buffer(struct tty_struct* tty); -static void dgap_tty_start(struct tty_struct *tty); -static void dgap_tty_stop(struct tty_struct *tty); -static void dgap_tty_throttle(struct tty_struct *tty); -static void dgap_tty_unthrottle(struct tty_struct *tty); -static void dgap_tty_flush_chars(struct tty_struct *tty); -static void dgap_tty_flush_buffer(struct tty_struct *tty); -static void dgap_tty_hangup(struct tty_struct *tty); -static int dgap_wait_for_drain(struct tty_struct *tty); -static int dgap_set_modem_info(struct tty_struct *tty, unsigned int command, unsigned int __user *value); -static int dgap_get_modem_info(struct channel_t *ch, unsigned int __user *value); -static int dgap_tty_digisetcustombaud(struct tty_struct *tty, int __user *new_info); -static int dgap_tty_digigetcustombaud(struct tty_struct *tty, int __user *retinfo); -static int dgap_tty_tiocmget(struct tty_struct *tty); -static int dgap_tty_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear); -static int dgap_tty_send_break(struct tty_struct *tty, int msec); -static void dgap_tty_wait_until_sent(struct tty_struct *tty, int timeout); -static int dgap_tty_write(struct tty_struct *tty, const unsigned char *buf, int count); -static void dgap_tty_set_termios(struct tty_struct *tty, struct ktermios *old_termios); -static int dgap_tty_put_char(struct tty_struct *tty, unsigned char c); -static void dgap_tty_send_xchar(struct tty_struct *tty, char ch); - -static const struct tty_operations dgap_tty_ops = { - .open = dgap_tty_open, - .close = dgap_tty_close, - .write = dgap_tty_write, - .write_room = dgap_tty_write_room, - .flush_buffer = dgap_tty_flush_buffer, - .chars_in_buffer = dgap_tty_chars_in_buffer, - .flush_chars = dgap_tty_flush_chars, - .ioctl = dgap_tty_ioctl, - .set_termios = dgap_tty_set_termios, - .stop = dgap_tty_stop, - .start = dgap_tty_start, - .throttle = dgap_tty_throttle, - .unthrottle = dgap_tty_unthrottle, - .hangup = dgap_tty_hangup, - .put_char = dgap_tty_put_char, - .tiocmget = dgap_tty_tiocmget, - .tiocmset = dgap_tty_tiocmset, - .break_ctl = dgap_tty_send_break, - .wait_until_sent = dgap_tty_wait_until_sent, - .send_xchar = dgap_tty_send_xchar -}; - - - - - -/************************************************************************ - * - * TTY Initialization/Cleanup Functions - * - ************************************************************************/ - -/* - * dgap_tty_preinit() - * - * Initialize any global tty related data before we download any boards. - */ -int dgap_tty_preinit(void) -{ - unsigned long flags; - - DGAP_LOCK(dgap_global_lock, flags); - - /* - * Allocate a buffer for doing the copy from user space to - * kernel space in dgap_input(). We only use one buffer and - * control access to it with a semaphore. If we are paging, we - * are already in trouble so one buffer won't hurt much anyway. - */ - dgap_TmpWriteBuf = kmalloc(WRITEBUFLEN, GFP_ATOMIC); - - if (!dgap_TmpWriteBuf) { - DGAP_UNLOCK(dgap_global_lock, flags); - DPR_INIT(("unable to allocate tmp write buf")); - return (-ENOMEM); - } - - DGAP_UNLOCK(dgap_global_lock, flags); - return(0); -} - - -/* - * dgap_tty_register() - * - * Init the tty subsystem for this board. - */ -int dgap_tty_register(struct board_t *brd) -{ - int rc = 0; - - DPR_INIT(("tty_register start")); - - brd->SerialDriver = alloc_tty_driver(MAXPORTS); - - snprintf(brd->SerialName, MAXTTYNAMELEN, "tty_dgap_%d_", brd->boardnum); - brd->SerialDriver->name = brd->SerialName; - brd->SerialDriver->name_base = 0; - brd->SerialDriver->major = 0; - brd->SerialDriver->minor_start = 0; - brd->SerialDriver->type = TTY_DRIVER_TYPE_SERIAL; - brd->SerialDriver->subtype = SERIAL_TYPE_NORMAL; - brd->SerialDriver->init_termios = DgapDefaultTermios; - brd->SerialDriver->driver_name = DRVSTR; - brd->SerialDriver->flags = (TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_HARDWARE_BREAK); - - /* The kernel wants space to store pointers to tty_structs */ - brd->SerialDriver->ttys = kzalloc(MAXPORTS * sizeof(struct tty_struct *), GFP_KERNEL); - if (!brd->SerialDriver->ttys) - return(-ENOMEM); - - /* - * Entry points for driver. Called by the kernel from - * tty_io.c and n_tty.c. - */ - tty_set_operations(brd->SerialDriver, &dgap_tty_ops); - - /* - * If we're doing transparent print, we have to do all of the above - * again, separately so we don't get the LD confused about what major - * we are when we get into the dgap_tty_open() routine. - */ - brd->PrintDriver = alloc_tty_driver(MAXPORTS); - - snprintf(brd->PrintName, MAXTTYNAMELEN, "pr_dgap_%d_", brd->boardnum); - brd->PrintDriver->name = brd->PrintName; - brd->PrintDriver->name_base = 0; - brd->PrintDriver->major = 0; - brd->PrintDriver->minor_start = 0; - brd->PrintDriver->type = TTY_DRIVER_TYPE_SERIAL; - brd->PrintDriver->subtype = SERIAL_TYPE_NORMAL; - brd->PrintDriver->init_termios = DgapDefaultTermios; - brd->PrintDriver->driver_name = DRVSTR; - brd->PrintDriver->flags = (TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_HARDWARE_BREAK); - - /* The kernel wants space to store pointers to tty_structs */ - brd->PrintDriver->ttys = kzalloc(MAXPORTS * sizeof(struct tty_struct *), GFP_KERNEL); - if (!brd->PrintDriver->ttys) - return(-ENOMEM); - - /* - * Entry points for driver. Called by the kernel from - * tty_io.c and n_tty.c. - */ - tty_set_operations(brd->PrintDriver, &dgap_tty_ops); - - if (!brd->dgap_Major_Serial_Registered) { - /* Register tty devices */ - rc = tty_register_driver(brd->SerialDriver); - if (rc < 0) { - APR(("Can't register tty device (%d)\n", rc)); - return(rc); - } - brd->dgap_Major_Serial_Registered = TRUE; - dgap_BoardsByMajor[brd->SerialDriver->major] = brd; - brd->dgap_Serial_Major = brd->SerialDriver->major; - } - - if (!brd->dgap_Major_TransparentPrint_Registered) { - /* Register Transparent Print devices */ - rc = tty_register_driver(brd->PrintDriver); - if (rc < 0) { - APR(("Can't register Transparent Print device (%d)\n", rc)); - return(rc); - } - brd->dgap_Major_TransparentPrint_Registered = TRUE; - dgap_BoardsByMajor[brd->PrintDriver->major] = brd; - brd->dgap_TransparentPrint_Major = brd->PrintDriver->major; - } - - DPR_INIT(("DGAP REGISTER TTY: MAJORS: %d %d\n", brd->SerialDriver->major, - brd->PrintDriver->major)); - - return (rc); -} - - -/* - * dgap_tty_init() - * - * Init the tty subsystem. Called once per board after board has been - * downloaded and init'ed. - */ -int dgap_tty_init(struct board_t *brd) -{ - int i; - int tlw; - uint true_count = 0; - uchar *vaddr; - uchar modem = 0; - struct channel_t *ch; - struct bs_t *bs; - struct cm_t *cm; - - if (!brd) - return (-ENXIO); - - DPR_INIT(("dgap_tty_init start\n")); - - /* - * Initialize board structure elements. - */ - - vaddr = brd->re_map_membase; - true_count = readw((vaddr + NCHAN)); - - brd->nasync = dgap_config_get_number_of_ports(brd); - - if (!brd->nasync) { - brd->nasync = brd->maxports; - } - - if (brd->nasync > brd->maxports) { - brd->nasync = brd->maxports; - } - - if (true_count != brd->nasync) { - if ((brd->type == PPCM) && (true_count == 64)) { - APR(("***WARNING**** %s configured for %d ports, has %d ports.\nPlease make SURE the EBI cable running from the card\nto each EM module is plugged into EBI IN!\n", - brd->name, brd->nasync, true_count)); - } - else if ((brd->type == PPCM) && (true_count == 0)) { - APR(("***WARNING**** %s configured for %d ports, has %d ports.\nPlease make SURE the EBI cable running from the card\nto each EM module is plugged into EBI IN!\n", - brd->name, brd->nasync, true_count)); - } - else { - APR(("***WARNING**** %s configured for %d ports, has %d ports.\n", - brd->name, brd->nasync, true_count)); - } - - brd->nasync = true_count; - - /* If no ports, don't bother going any further */ - if (!brd->nasync) { - brd->state = BOARD_FAILED; - brd->dpastatus = BD_NOFEP; - return(-ENXIO); - } - } - - /* - * Allocate channel memory that might not have been allocated - * when the driver was first loaded. - */ - for (i = 0; i < brd->nasync; i++) { - if (!brd->channels[i]) { - brd->channels[i] = kzalloc(sizeof(struct channel_t), GFP_ATOMIC); - if (!brd->channels[i]) { - DPR_CORE(("%s:%d Unable to allocate memory for channel struct\n", - __FILE__, __LINE__)); - } - } - } - - ch = brd->channels[0]; - vaddr = brd->re_map_membase; - - bs = (struct bs_t *) ((ulong) vaddr + CHANBUF); - cm = (struct cm_t *) ((ulong) vaddr + CMDBUF); - - brd->bd_bs = bs; - - /* Set up channel variables */ - for (i = 0; i < brd->nasync; i++, ch = brd->channels[i], bs++) { - - if (!brd->channels[i]) - continue; - - DGAP_SPINLOCK_INIT(ch->ch_lock); - - /* Store all our magic numbers */ - ch->magic = DGAP_CHANNEL_MAGIC; - ch->ch_tun.magic = DGAP_UNIT_MAGIC; - ch->ch_tun.un_type = DGAP_SERIAL; - ch->ch_tun.un_ch = ch; - ch->ch_tun.un_dev = i; - - ch->ch_pun.magic = DGAP_UNIT_MAGIC; - ch->ch_pun.un_type = DGAP_PRINT; - ch->ch_pun.un_ch = ch; - ch->ch_pun.un_dev = i; - - ch->ch_vaddr = vaddr; - ch->ch_bs = bs; - ch->ch_cm = cm; - ch->ch_bd = brd; - ch->ch_portnum = i; - ch->ch_digi = dgap_digi_init; - - /* - * Set up digi dsr and dcd bits based on altpin flag. - */ - if (dgap_config_get_altpin(brd)) { - ch->ch_dsr = DM_CD; - ch->ch_cd = DM_DSR; - ch->ch_digi.digi_flags |= DIGI_ALTPIN; - } - else { - ch->ch_cd = DM_CD; - ch->ch_dsr = DM_DSR; - } - - ch->ch_taddr = vaddr + ((ch->ch_bs->tx_seg) << 4); - ch->ch_raddr = vaddr + ((ch->ch_bs->rx_seg) << 4); - ch->ch_tx_win = 0; - ch->ch_rx_win = 0; - ch->ch_tsize = readw(&(ch->ch_bs->tx_max)) + 1; - ch->ch_rsize = readw(&(ch->ch_bs->rx_max)) + 1; - ch->ch_tstart = 0; - ch->ch_rstart = 0; - - /* .25 second delay */ - ch->ch_close_delay = 250; - - /* - * Set queue water marks, interrupt mask, - * and general tty parameters. - */ - ch->ch_tlw = tlw = ch->ch_tsize >= 2000 ? ((ch->ch_tsize * 5) / 8) : ch->ch_tsize / 2; - - dgap_cmdw(ch, STLOW, tlw, 0); - - dgap_cmdw(ch, SRLOW, ch->ch_rsize / 2, 0); - - dgap_cmdw(ch, SRHIGH, 7 * ch->ch_rsize / 8, 0); - - ch->ch_mistat = readb(&(ch->ch_bs->m_stat)); - - init_waitqueue_head(&ch->ch_flags_wait); - init_waitqueue_head(&ch->ch_tun.un_flags_wait); - init_waitqueue_head(&ch->ch_pun.un_flags_wait); - init_waitqueue_head(&ch->ch_sniff_wait); - - /* Turn on all modem interrupts for now */ - modem = (DM_CD | DM_DSR | DM_CTS | DM_RI); - writeb(modem, &(ch->ch_bs->m_int)); - - /* - * Set edelay to 0 if interrupts are turned on, - * otherwise set edelay to the usual 100. - */ - if (brd->intr_used) - writew(0, &(ch->ch_bs->edelay)); - else - writew(100, &(ch->ch_bs->edelay)); - - writeb(1, &(ch->ch_bs->idata)); - } - - - DPR_INIT(("dgap_tty_init finish\n")); - - return (0); -} - - -/* - * dgap_tty_post_uninit() - * - * UnInitialize any global tty related data. - */ -void dgap_tty_post_uninit(void) -{ - kfree(dgap_TmpWriteBuf); - dgap_TmpWriteBuf = NULL; -} - - -/* - * dgap_tty_uninit() - * - * Uninitialize the TTY portion of this driver. Free all memory and - * resources. - */ -void dgap_tty_uninit(struct board_t *brd) -{ - int i = 0; - - if (brd->dgap_Major_Serial_Registered) { - dgap_BoardsByMajor[brd->SerialDriver->major] = NULL; - brd->dgap_Serial_Major = 0; - for (i = 0; i < brd->nasync; i++) { - dgap_remove_tty_sysfs(brd->channels[i]->ch_tun.un_sysfs); - tty_unregister_device(brd->SerialDriver, i); - } - tty_unregister_driver(brd->SerialDriver); - kfree(brd->SerialDriver->ttys); - brd->SerialDriver->ttys = NULL; - put_tty_driver(brd->SerialDriver); - brd->dgap_Major_Serial_Registered = FALSE; - } - - if (brd->dgap_Major_TransparentPrint_Registered) { - dgap_BoardsByMajor[brd->PrintDriver->major] = NULL; - brd->dgap_TransparentPrint_Major = 0; - for (i = 0; i < brd->nasync; i++) { - dgap_remove_tty_sysfs(brd->channels[i]->ch_pun.un_sysfs); - tty_unregister_device(brd->PrintDriver, i); - } - tty_unregister_driver(brd->PrintDriver); - kfree(brd->PrintDriver->ttys); - brd->PrintDriver->ttys = NULL; - put_tty_driver(brd->PrintDriver); - brd->dgap_Major_TransparentPrint_Registered = FALSE; - } -} - - -#define TMPBUFLEN (1024) - -/* - * dgap_sniff - Dump data out to the "sniff" buffer if the - * proc sniff file is opened... - */ -static void dgap_sniff_nowait_nolock(struct channel_t *ch, uchar *text, uchar *buf, int len) -{ - struct timeval tv; - int n; - int r; - int nbuf; - int i; - int tmpbuflen; - char tmpbuf[TMPBUFLEN]; - char *p = tmpbuf; - int too_much_data; - - /* Leave if sniff not open */ - if (!(ch->ch_sniff_flags & SNIFF_OPEN)) - return; - - do_gettimeofday(&tv); - - /* Create our header for data dump */ - p += sprintf(p, "<%ld %ld><%s><", tv.tv_sec, tv.tv_usec, text); - tmpbuflen = p - tmpbuf; - - do { - too_much_data = 0; - - for (i = 0; i < len && tmpbuflen < (TMPBUFLEN - 4); i++) { - p += sprintf(p, "%02x ", *buf); - buf++; - tmpbuflen = p - tmpbuf; - } - - if (tmpbuflen < (TMPBUFLEN - 4)) { - if (i > 0) - p += sprintf(p - 1, "%s\n", ">"); - else - p += sprintf(p, "%s\n", ">"); - } else { - too_much_data = 1; - len -= i; - } - - nbuf = strlen(tmpbuf); - p = tmpbuf; - - /* - * Loop while data remains. - */ - while (nbuf > 0 && ch->ch_sniff_buf) { - /* - * Determine the amount of available space left in the - * buffer. If there's none, wait until some appears. - */ - n = (ch->ch_sniff_out - ch->ch_sniff_in - 1) & SNIFF_MASK; - - /* - * If there is no space left to write to in our sniff buffer, - * we have no choice but to drop the data. - * We *cannot* sleep here waiting for space, because this - * function was probably called by the interrupt/timer routines! - */ - if (n == 0) { - return; - } - - /* - * Copy as much data as will fit. - */ - - if (n > nbuf) - n = nbuf; - - r = SNIFF_MAX - ch->ch_sniff_in; - - if (r <= n) { - memcpy(ch->ch_sniff_buf + ch->ch_sniff_in, p, r); - - n -= r; - ch->ch_sniff_in = 0; - p += r; - nbuf -= r; - } - - memcpy(ch->ch_sniff_buf + ch->ch_sniff_in, p, n); - - ch->ch_sniff_in += n; - p += n; - nbuf -= n; - - /* - * Wakeup any thread waiting for data - */ - if (ch->ch_sniff_flags & SNIFF_WAIT_DATA) { - ch->ch_sniff_flags &= ~SNIFF_WAIT_DATA; - wake_up_interruptible(&ch->ch_sniff_wait); - } - } - - /* - * If the user sent us too much data to push into our tmpbuf, - * we need to keep looping around on all the data. - */ - if (too_much_data) { - p = tmpbuf; - tmpbuflen = 0; - } - - } while (too_much_data); -} - - -/*======================================================================= - * - * dgap_input - Process received data. - * - * ch - Pointer to channel structure. - * - *=======================================================================*/ - -void dgap_input(struct channel_t *ch) -{ - struct board_t *bd; - struct bs_t *bs; - struct tty_struct *tp; - struct tty_ldisc *ld; - uint rmask; - uint head; - uint tail; - int data_len; - ulong lock_flags; - ulong lock_flags2; - int flip_len; - int len = 0; - int n = 0; - uchar *buf; - uchar tmpchar; - int s = 0; - - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return; - - tp = ch->ch_tun.un_tty; - - bs = ch->ch_bs; - if (!bs) { - return; - } - - bd = ch->ch_bd; - if(!bd || bd->magic != DGAP_BOARD_MAGIC) - return; - - DPR_READ(("dgap_input start\n")); - - DGAP_LOCK(bd->bd_lock, lock_flags); - DGAP_LOCK(ch->ch_lock, lock_flags2); - - /* - * Figure the number of characters in the buffer. - * Exit immediately if none. - */ - - rmask = ch->ch_rsize - 1; - - head = readw(&(bs->rx_head)); - head &= rmask; - tail = readw(&(bs->rx_tail)); - tail &= rmask; - - data_len = (head - tail) & rmask; - - if (data_len == 0) { - writeb(1, &(bs->idata)); - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - DPR_READ(("No data on port %d\n", ch->ch_portnum)); - return; - } - - /* - * If the device is not open, or CREAD is off, flush - * input data and return immediately. - */ - if ((bd->state != BOARD_READY) || !tp || (tp->magic != TTY_MAGIC) || - !(ch->ch_tun.un_flags & UN_ISOPEN) || !(tp->termios.c_cflag & CREAD) || - (ch->ch_tun.un_flags & UN_CLOSING)) { - - DPR_READ(("input. dropping %d bytes on port %d...\n", data_len, ch->ch_portnum)); - DPR_READ(("input. tp: %p tp->magic: %x MAGIC:%x ch flags: %x\n", - tp, tp ? tp->magic : 0, TTY_MAGIC, ch->ch_tun.un_flags)); - writew(head, &(bs->rx_tail)); - writeb(1, &(bs->idata)); - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - return; - } - - /* - * If we are throttled, simply don't read any data. - */ - if (ch->ch_flags & CH_RXBLOCK) { - writeb(1, &(bs->idata)); - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - DPR_READ(("Port %d throttled, not reading any data. head: %x tail: %x\n", - ch->ch_portnum, head, tail)); - return; - } - - /* - * Ignore oruns. - */ - tmpchar = readb(&(bs->orun)); - if (tmpchar) { - ch->ch_err_overrun++; - writeb(0, &(bs->orun)); - } - - DPR_READ(("dgap_input start 2\n")); - - /* Decide how much data we can send into the tty layer */ - flip_len = TTY_FLIPBUF_SIZE; - - /* Chop down the length, if needed */ - len = min(data_len, flip_len); - len = min(len, (N_TTY_BUF_SIZE - 1)); - - ld = tty_ldisc_ref(tp); - -#ifdef TTY_DONT_FLIP - /* - * If the DONT_FLIP flag is on, don't flush our buffer, and act - * like the ld doesn't have any space to put the data right now. - */ - if (test_bit(TTY_DONT_FLIP, &tp->flags)) - len = 0; -#endif - - /* - * If we were unable to get a reference to the ld, - * don't flush our buffer, and act like the ld doesn't - * have any space to put the data right now. - */ - if (!ld) { - len = 0; - } else { - /* - * If ld doesn't have a pointer to a receive_buf function, - * flush the data, then act like the ld doesn't have any - * space to put the data right now. - */ - if (!ld->ops->receive_buf) { - writew(head, &(bs->rx_tail)); - len = 0; - } - } - - if (len <= 0) { - writeb(1, &(bs->idata)); - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - DPR_READ(("dgap_input 1 - finish\n")); - if (ld) - tty_ldisc_deref(ld); - return; - } - - buf = ch->ch_bd->flipbuf; - n = len; - - /* - * n now contains the most amount of data we can copy, - * bounded either by our buffer size or the amount - * of data the card actually has pending... - */ - while (n) { - - s = ((head >= tail) ? head : ch->ch_rsize) - tail; - s = min(s, n); - - if (s <= 0) - break; - - memcpy_fromio(buf, (char *) ch->ch_raddr + tail, s); - dgap_sniff_nowait_nolock(ch, "USER READ", buf, s); - - tail += s; - buf += s; - - n -= s; - /* Flip queue if needed */ - tail &= rmask; - } - - writew(tail, &(bs->rx_tail)); - writeb(1, &(bs->idata)); - ch->ch_rxcount += len; - - /* - * If we are completely raw, we don't need to go through a lot - * of the tty layers that exist. - * In this case, we take the shortest and fastest route we - * can to relay the data to the user. - * - * On the other hand, if we are not raw, we need to go through - * the tty layer, which has its API more well defined. - */ - if (I_PARMRK(tp) || I_BRKINT(tp) || I_INPCK(tp)) { - dgap_parity_scan(ch, ch->ch_bd->flipbuf, ch->ch_bd->flipflagbuf, &len); - - len = tty_buffer_request_room(tp->port, len); - tty_insert_flip_string_flags(tp->port, ch->ch_bd->flipbuf, - ch->ch_bd->flipflagbuf, len); - } - else { - len = tty_buffer_request_room(tp->port, len); - tty_insert_flip_string(tp->port, ch->ch_bd->flipbuf, len); - } - - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - - /* Tell the tty layer its okay to "eat" the data now */ - tty_flip_buffer_push(tp->port); - - if (ld) - tty_ldisc_deref(ld); - - DPR_READ(("dgap_input - finish\n")); -} - - -/************************************************************************ - * Determines when CARRIER changes state and takes appropriate - * action. - ************************************************************************/ -void dgap_carrier(struct channel_t *ch) -{ - struct board_t *bd; - - int virt_carrier = 0; - int phys_carrier = 0; - - DPR_CARR(("dgap_carrier called...\n")); - - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return; - - bd = ch->ch_bd; - - if (!bd || bd->magic != DGAP_BOARD_MAGIC) - return; - - /* Make sure altpin is always set correctly */ - if (ch->ch_digi.digi_flags & DIGI_ALTPIN) { - ch->ch_dsr = DM_CD; - ch->ch_cd = DM_DSR; - } - else { - ch->ch_dsr = DM_DSR; - ch->ch_cd = DM_CD; - } - - if (ch->ch_mistat & D_CD(ch)) { - DPR_CARR(("mistat: %x D_CD: %x\n", ch->ch_mistat, D_CD(ch))); - phys_carrier = 1; - } - - if (ch->ch_digi.digi_flags & DIGI_FORCEDCD) { - virt_carrier = 1; - } - - if (ch->ch_c_cflag & CLOCAL) { - virt_carrier = 1; - } - - - DPR_CARR(("DCD: physical: %d virt: %d\n", phys_carrier, virt_carrier)); - - /* - * Test for a VIRTUAL carrier transition to HIGH. - */ - if (((ch->ch_flags & CH_FCAR) == 0) && (virt_carrier == 1)) { - - /* - * When carrier rises, wake any threads waiting - * for carrier in the open routine. - */ - - DPR_CARR(("carrier: virt DCD rose\n")); - - if (waitqueue_active(&(ch->ch_flags_wait))) - wake_up_interruptible(&ch->ch_flags_wait); - } - - /* - * Test for a PHYSICAL carrier transition to HIGH. - */ - if (((ch->ch_flags & CH_CD) == 0) && (phys_carrier == 1)) { - - /* - * When carrier rises, wake any threads waiting - * for carrier in the open routine. - */ - - DPR_CARR(("carrier: physical DCD rose\n")); - - if (waitqueue_active(&(ch->ch_flags_wait))) - wake_up_interruptible(&ch->ch_flags_wait); - } - - /* - * Test for a PHYSICAL transition to low, so long as we aren't - * currently ignoring physical transitions (which is what "virtual - * carrier" indicates). - * - * The transition of the virtual carrier to low really doesn't - * matter... it really only means "ignore carrier state", not - * "make pretend that carrier is there". - */ - if ((virt_carrier == 0) && ((ch->ch_flags & CH_CD) != 0) && - (phys_carrier == 0)) - { - - /* - * When carrier drops: - * - * Drop carrier on all open units. - * - * Flush queues, waking up any task waiting in the - * line discipline. - * - * Send a hangup to the control terminal. - * - * Enable all select calls. - */ - if (waitqueue_active(&(ch->ch_flags_wait))) - wake_up_interruptible(&ch->ch_flags_wait); - - if (ch->ch_tun.un_open_count > 0) { - DPR_CARR(("Sending tty hangup\n")); - tty_hangup(ch->ch_tun.un_tty); - } - - if (ch->ch_pun.un_open_count > 0) { - DPR_CARR(("Sending pr hangup\n")); - tty_hangup(ch->ch_pun.un_tty); - } - } - - /* - * Make sure that our cached values reflect the current reality. - */ - if (virt_carrier == 1) - ch->ch_flags |= CH_FCAR; - else - ch->ch_flags &= ~CH_FCAR; - - if (phys_carrier == 1) - ch->ch_flags |= CH_CD; - else - ch->ch_flags &= ~CH_CD; -} - - -/************************************************************************ - * - * TTY Entry points and helper functions - * - ************************************************************************/ - -/* - * dgap_tty_open() - * - */ -static int dgap_tty_open(struct tty_struct *tty, struct file *file) -{ - struct board_t *brd; - struct channel_t *ch; - struct un_t *un; - struct bs_t *bs; - uint major = 0; - uint minor = 0; - int rc = 0; - ulong lock_flags; - ulong lock_flags2; - u16 head; - - rc = 0; - - major = MAJOR(tty_devnum(tty)); - minor = MINOR(tty_devnum(tty)); - - if (major > 255) { - return -ENXIO; - } - - /* Get board pointer from our array of majors we have allocated */ - brd = dgap_BoardsByMajor[major]; - if (!brd) { - return -ENXIO; - } - - /* - * If board is not yet up to a state of READY, go to - * sleep waiting for it to happen or they cancel the open. - */ - rc = wait_event_interruptible(brd->state_wait, - (brd->state & BOARD_READY)); - - if (rc) { - return rc; - } - - DGAP_LOCK(brd->bd_lock, lock_flags); - - /* The wait above should guarantee this cannot happen */ - if (brd->state != BOARD_READY) { - DGAP_UNLOCK(brd->bd_lock, lock_flags); - return -ENXIO; - } - - /* If opened device is greater than our number of ports, bail. */ - if (MINOR(tty_devnum(tty)) > brd->nasync) { - DGAP_UNLOCK(brd->bd_lock, lock_flags); - return -ENXIO; - } - - ch = brd->channels[minor]; - if (!ch) { - DGAP_UNLOCK(brd->bd_lock, lock_flags); - return -ENXIO; - } - - /* Grab channel lock */ - DGAP_LOCK(ch->ch_lock, lock_flags2); - - /* Figure out our type */ - if (major == brd->dgap_Serial_Major) { - un = &brd->channels[minor]->ch_tun; - un->un_type = DGAP_SERIAL; - } - else if (major == brd->dgap_TransparentPrint_Major) { - un = &brd->channels[minor]->ch_pun; - un->un_type = DGAP_PRINT; - } - else { - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(brd->bd_lock, lock_flags); - DPR_OPEN(("%d Unknown TYPE!\n", __LINE__)); - return -ENXIO; - } - - /* Store our unit into driver_data, so we always have it available. */ - tty->driver_data = un; - - DPR_OPEN(("Open called. MAJOR: %d MINOR:%d unit: %p NAME: %s\n", - MAJOR(tty_devnum(tty)), MINOR(tty_devnum(tty)), un, brd->name)); - - /* - * Error if channel info pointer is NULL. - */ - bs = ch->ch_bs; - if (!bs) { - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(brd->bd_lock, lock_flags); - DPR_OPEN(("%d BS is 0!\n", __LINE__)); - return -ENXIO; - } - - DPR_OPEN(("%d: tflag=%x pflag=%x\n", __LINE__, ch->ch_tun.un_flags, ch->ch_pun.un_flags)); - - /* - * Initialize tty's - */ - if (!(un->un_flags & UN_ISOPEN)) { - /* Store important variables. */ - un->un_tty = tty; - - /* Maybe do something here to the TTY struct as well? */ - } - - /* - * Initialize if neither terminal or printer is open. - */ - if (!((ch->ch_tun.un_flags | ch->ch_pun.un_flags) & UN_ISOPEN)) { - - DPR_OPEN(("dgap_open: initializing channel in open...\n")); - - ch->ch_mforce = 0; - ch->ch_mval = 0; - - /* - * Flush input queue. - */ - head = readw(&(bs->rx_head)); - writew(head, &(bs->rx_tail)); - - ch->ch_flags = 0; - ch->pscan_state = 0; - ch->pscan_savechar = 0; - - ch->ch_c_cflag = tty->termios.c_cflag; - ch->ch_c_iflag = tty->termios.c_iflag; - ch->ch_c_oflag = tty->termios.c_oflag; - ch->ch_c_lflag = tty->termios.c_lflag; - ch->ch_startc = tty->termios.c_cc[VSTART]; - ch->ch_stopc = tty->termios.c_cc[VSTOP]; - - /* TODO: flush our TTY struct here? */ - } - - dgap_carrier(ch); - /* - * Run param in case we changed anything - */ - dgap_param(tty); - - /* - * follow protocol for opening port - */ - - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(brd->bd_lock, lock_flags); - - rc = dgap_block_til_ready(tty, file, ch); - - if (!un->un_tty) { - return -ENODEV; - } - - if (rc) { - DPR_OPEN(("dgap_tty_open returning after dgap_block_til_ready " - "with %d\n", rc)); - } - - /* No going back now, increment our unit and channel counters */ - DGAP_LOCK(ch->ch_lock, lock_flags); - ch->ch_open_count++; - un->un_open_count++; - un->un_flags |= (UN_ISOPEN); - DGAP_UNLOCK(ch->ch_lock, lock_flags); - - DPR_OPEN(("dgap_tty_open finished\n")); - return (rc); -} - - -/* - * dgap_block_til_ready() - * - * Wait for DCD, if needed. - */ -static int dgap_block_til_ready(struct tty_struct *tty, struct file *file, struct channel_t *ch) -{ - int retval = 0; - struct un_t *un = NULL; - ulong lock_flags; - uint old_flags = 0; - int sleep_on_un_flags = 0; - - if (!tty || tty->magic != TTY_MAGIC || !file || !ch || ch->magic != DGAP_CHANNEL_MAGIC) { - return (-ENXIO); - } - - un = tty->driver_data; - if (!un || un->magic != DGAP_UNIT_MAGIC) { - return (-ENXIO); - } - - DPR_OPEN(("dgap_block_til_ready - before block.\n")); - - DGAP_LOCK(ch->ch_lock, lock_flags); - - ch->ch_wopen++; - - /* Loop forever */ - while (1) { - - sleep_on_un_flags = 0; - - /* - * If board has failed somehow during our sleep, bail with error. - */ - if (ch->ch_bd->state == BOARD_FAILED) { - retval = -ENXIO; - break; - } - - /* If tty was hung up, break out of loop and set error. */ - if (tty_hung_up_p(file)) { - retval = -EAGAIN; - break; - } - - /* - * If either unit is in the middle of the fragile part of close, - * we just cannot touch the channel safely. - * Go back to sleep, knowing that when the channel can be - * touched safely, the close routine will signal the - * ch_wait_flags to wake us back up. - */ - if (!((ch->ch_tun.un_flags | ch->ch_pun.un_flags) & UN_CLOSING)) { - - /* - * Our conditions to leave cleanly and happily: - * 1) NONBLOCKING on the tty is set. - * 2) CLOCAL is set. - * 3) DCD (fake or real) is active. - */ - - if (file->f_flags & O_NONBLOCK) { - break; - } - - if (tty->flags & (1 << TTY_IO_ERROR)) { - break; - } - - if (ch->ch_flags & CH_CD) { - DPR_OPEN(("%d: ch_flags: %x\n", __LINE__, ch->ch_flags)); - break; - } - - if (ch->ch_flags & CH_FCAR) { - DPR_OPEN(("%d: ch_flags: %x\n", __LINE__, ch->ch_flags)); - break; - } - } - else { - sleep_on_un_flags = 1; - } - - /* - * If there is a signal pending, the user probably - * interrupted (ctrl-c) us. - * Leave loop with error set. - */ - if (signal_pending(current)) { - DPR_OPEN(("%d: signal pending...\n", __LINE__)); - retval = -ERESTARTSYS; - break; - } - - DPR_OPEN(("dgap_block_til_ready - blocking.\n")); - - /* - * Store the flags before we let go of channel lock - */ - if (sleep_on_un_flags) - old_flags = ch->ch_tun.un_flags | ch->ch_pun.un_flags; - else - old_flags = ch->ch_flags; - - /* - * Let go of channel lock before calling schedule. - * Our poller will get any FEP events and wake us up when DCD - * eventually goes active. - */ - - DGAP_UNLOCK(ch->ch_lock, lock_flags); - - DPR_OPEN(("Going to sleep on %s flags...\n", - (sleep_on_un_flags ? "un" : "ch"))); - - /* - * Wait for something in the flags to change from the current value. - */ - if (sleep_on_un_flags) { - retval = wait_event_interruptible(un->un_flags_wait, - (old_flags != (ch->ch_tun.un_flags | ch->ch_pun.un_flags))); - } - else { - retval = wait_event_interruptible(ch->ch_flags_wait, - (old_flags != ch->ch_flags)); - } - - DPR_OPEN(("After sleep... retval: %x\n", retval)); - - /* - * We got woken up for some reason. - * Before looping around, grab our channel lock. - */ - DGAP_LOCK(ch->ch_lock, lock_flags); - } - - ch->ch_wopen--; - - DGAP_UNLOCK(ch->ch_lock, lock_flags); - - DPR_OPEN(("dgap_block_til_ready - after blocking.\n")); - - if (retval) { - DPR_OPEN(("dgap_block_til_ready - done. error. retval: %x\n", retval)); - return(retval); - } - - DPR_OPEN(("dgap_block_til_ready - done no error. jiffies: %lu\n", jiffies)); - - return(0); -} - - -/* - * dgap_tty_hangup() - * - * Hangup the port. Like a close, but don't wait for output to drain. - */ -static void dgap_tty_hangup(struct tty_struct *tty) -{ - struct board_t *bd; - struct channel_t *ch; - struct un_t *un; - - if (!tty || tty->magic != TTY_MAGIC) - return; - - un = tty->driver_data; - if (!un || un->magic != DGAP_UNIT_MAGIC) - return; - - ch = un->un_ch; - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return; - - bd = ch->ch_bd; - if (!bd || bd->magic != DGAP_BOARD_MAGIC) - return; - - DPR_CLOSE(("dgap_hangup called. ch->ch_open_count: %d un->un_open_count: %d\n", - ch->ch_open_count, un->un_open_count)); - - /* flush the transmit queues */ - dgap_tty_flush_buffer(tty); - - DPR_CLOSE(("dgap_hangup finished. ch->ch_open_count: %d un->un_open_count: %d\n", - ch->ch_open_count, un->un_open_count)); -} - - - -/* - * dgap_tty_close() - * - */ -static void dgap_tty_close(struct tty_struct *tty, struct file *file) -{ - struct ktermios *ts; - struct board_t *bd; - struct channel_t *ch; - struct un_t *un; - ulong lock_flags; - int rc = 0; - - if (!tty || tty->magic != TTY_MAGIC) - return; - - un = tty->driver_data; - if (!un || un->magic != DGAP_UNIT_MAGIC) - return; - - ch = un->un_ch; - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return; - - bd = ch->ch_bd; - if (!bd || bd->magic != DGAP_BOARD_MAGIC) - return; - - ts = &tty->termios; - - DPR_CLOSE(("Close called\n")); - - DGAP_LOCK(ch->ch_lock, lock_flags); - - /* - * Determine if this is the last close or not - and if we agree about - * which type of close it is with the Line Discipline - */ - if ((tty->count == 1) && (un->un_open_count != 1)) { - /* - * Uh, oh. tty->count is 1, which means that the tty - * structure will be freed. un_open_count should always - * be one in these conditions. If it's greater than - * one, we've got real problems, since it means the - * serial port won't be shutdown. - */ - APR(("tty->count is 1, un open count is %d\n", un->un_open_count)); - un->un_open_count = 1; - } - - if (--un->un_open_count < 0) { - APR(("bad serial port open count of %d\n", un->un_open_count)); - un->un_open_count = 0; - } - - ch->ch_open_count--; - - if (ch->ch_open_count && un->un_open_count) { - DPR_CLOSE(("dgap_tty_close: not last close ch: %d un:%d\n", - ch->ch_open_count, un->un_open_count)); - - DGAP_UNLOCK(ch->ch_lock, lock_flags); - return; - } - - /* OK, its the last close on the unit */ - DPR_CLOSE(("dgap_tty_close - last close on unit procedures\n")); - - un->un_flags |= UN_CLOSING; - - tty->closing = 1; - - /* - * Only officially close channel if count is 0 and - * DIGI_PRINTER bit is not set. - */ - if ((ch->ch_open_count == 0) && !(ch->ch_digi.digi_flags & DIGI_PRINTER)) { - - ch->ch_flags &= ~(CH_RXBLOCK); - - DGAP_UNLOCK(ch->ch_lock, lock_flags); - - /* wait for output to drain */ - /* This will also return if we take an interrupt */ - - DPR_CLOSE(("Calling wait_for_drain\n")); - rc = dgap_wait_for_drain(tty); - DPR_CLOSE(("After calling wait_for_drain\n")); - - if (rc) { - DPR_BASIC(("dgap_tty_close - bad return: %d ", rc)); - } - - dgap_tty_flush_buffer(tty); - tty_ldisc_flush(tty); - - DGAP_LOCK(ch->ch_lock, lock_flags); - - tty->closing = 0; - - /* - * If we have HUPCL set, lower DTR and RTS - */ - if (ch->ch_c_cflag & HUPCL ) { - DPR_CLOSE(("Close. HUPCL set, dropping DTR/RTS\n")); - ch->ch_mostat &= ~(D_RTS(ch)|D_DTR(ch)); - dgap_cmdb( ch, SMODEM, 0, D_DTR(ch)|D_RTS(ch), 0 ); - - /* - * Go to sleep to ensure RTS/DTR - * have been dropped for modems to see it. - */ - if (ch->ch_close_delay) { - DPR_CLOSE(("Close. Sleeping for RTS/DTR drop\n")); - - DGAP_UNLOCK(ch->ch_lock, lock_flags); - dgap_ms_sleep(ch->ch_close_delay); - DGAP_LOCK(ch->ch_lock, lock_flags); - - DPR_CLOSE(("Close. After sleeping for RTS/DTR drop\n")); - } - } - - ch->pscan_state = 0; - ch->pscan_savechar = 0; - ch->ch_baud_info = 0; - - } - - /* - * turn off print device when closing print device. - */ - if ((un->un_type == DGAP_PRINT) && (ch->ch_flags & CH_PRON) ) { - dgap_wmove(ch, ch->ch_digi.digi_offstr, - (int) ch->ch_digi.digi_offlen); - ch->ch_flags &= ~CH_PRON; - } - - un->un_tty = NULL; - un->un_flags &= ~(UN_ISOPEN | UN_CLOSING); - tty->driver_data = NULL; - - DPR_CLOSE(("Close. Doing wakeups\n")); - wake_up_interruptible(&ch->ch_flags_wait); - wake_up_interruptible(&un->un_flags_wait); - - DGAP_UNLOCK(ch->ch_lock, lock_flags); - - DPR_BASIC(("dgap_tty_close - complete\n")); -} - - -/* - * dgap_tty_chars_in_buffer() - * - * Return number of characters that have not been transmitted yet. - * - * This routine is used by the line discipline to determine if there - * is data waiting to be transmitted/drained/flushed or not. - */ -static int dgap_tty_chars_in_buffer(struct tty_struct *tty) -{ - struct board_t *bd = NULL; - struct channel_t *ch = NULL; - struct un_t *un = NULL; - struct bs_t *bs = NULL; - uchar tbusy; - uint chars = 0; - u16 thead, ttail, tmask, chead, ctail; - ulong lock_flags = 0; - ulong lock_flags2 = 0; - - if (tty == NULL) - return(0); - - un = tty->driver_data; - if (!un || un->magic != DGAP_UNIT_MAGIC) - return (0); - - ch = un->un_ch; - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return (0); - - bd = ch->ch_bd; - if (!bd || bd->magic != DGAP_BOARD_MAGIC) - return (0); - - bs = ch->ch_bs; - if (!bs) - return (0); - - DGAP_LOCK(bd->bd_lock, lock_flags); - DGAP_LOCK(ch->ch_lock, lock_flags2); - - tmask = (ch->ch_tsize - 1); - - /* Get Transmit queue pointers */ - thead = readw(&(bs->tx_head)) & tmask; - ttail = readw(&(bs->tx_tail)) & tmask; - - /* Get tbusy flag */ - tbusy = readb(&(bs->tbusy)); - - /* Get Command queue pointers */ - chead = readw(&(ch->ch_cm->cm_head)); - ctail = readw(&(ch->ch_cm->cm_tail)); - - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - - /* - * The only way we know for sure if there is no pending - * data left to be transferred, is if: - * 1) Transmit head and tail are equal (empty). - * 2) Command queue head and tail are equal (empty). - * 3) The "TBUSY" flag is 0. (Transmitter not busy). - */ - - if ((ttail == thead) && (tbusy == 0) && (chead == ctail)) { - chars = 0; - } - else { - if (thead >= ttail) - chars = thead - ttail; - else - chars = thead - ttail + ch->ch_tsize; - /* - * Fudge factor here. - * If chars is zero, we know that the command queue had - * something in it or tbusy was set. Because we cannot - * be sure if there is still some data to be transmitted, - * lets lie, and tell ld we have 1 byte left. - */ - if (chars == 0) { - /* - * If TBUSY is still set, and our tx buffers are empty, - * force the firmware to send me another wakeup after - * TBUSY has been cleared. - */ - if (tbusy != 0) { - DGAP_LOCK(ch->ch_lock, lock_flags); - un->un_flags |= UN_EMPTY; - writeb(1, &(bs->iempty)); - DGAP_UNLOCK(ch->ch_lock, lock_flags); - } - chars = 1; - } - } - - DPR_WRITE(("dgap_tty_chars_in_buffer. Port: %x - %d (head: %d tail: %d tsize: %d)\n", - ch->ch_portnum, chars, thead, ttail, ch->ch_tsize)); - return(chars); -} - - -static int dgap_wait_for_drain(struct tty_struct *tty) -{ - struct channel_t *ch; - struct un_t *un; - struct bs_t *bs; - int ret = -EIO; - uint count = 1; - ulong lock_flags = 0; - - if (!tty || tty->magic != TTY_MAGIC) - return ret; - - un = tty->driver_data; - if (!un || un->magic != DGAP_UNIT_MAGIC) - return ret; - - ch = un->un_ch; - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return ret; - - bs = ch->ch_bs; - if (!bs) - return ret; - - ret = 0; - - DPR_DRAIN(("dgap_wait_for_drain start\n")); - - /* Loop until data is drained */ - while (count != 0) { - - count = dgap_tty_chars_in_buffer(tty); - - if (count == 0) - break; - - /* Set flag waiting for drain */ - DGAP_LOCK(ch->ch_lock, lock_flags); - un->un_flags |= UN_EMPTY; - writeb(1, &(bs->iempty)); - DGAP_UNLOCK(ch->ch_lock, lock_flags); - - /* Go to sleep till we get woken up */ - ret = wait_event_interruptible(un->un_flags_wait, ((un->un_flags & UN_EMPTY) == 0)); - /* If ret is non-zero, user ctrl-c'ed us */ - if (ret) { - break; - } - } - - DGAP_LOCK(ch->ch_lock, lock_flags); - un->un_flags &= ~(UN_EMPTY); - DGAP_UNLOCK(ch->ch_lock, lock_flags); - - DPR_DRAIN(("dgap_wait_for_drain finish\n")); - return (ret); -} - - -/* - * dgap_maxcps_room - * - * Reduces bytes_available to the max number of characters - * that can be sent currently given the maxcps value, and - * returns the new bytes_available. This only affects printer - * output. - */ -static int dgap_maxcps_room(struct tty_struct *tty, int bytes_available) -{ - struct channel_t *ch = NULL; - struct un_t *un = NULL; - - if (tty == NULL) - return (bytes_available); - - un = tty->driver_data; - if (!un || un->magic != DGAP_UNIT_MAGIC) - return (bytes_available); - - ch = un->un_ch; - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return (bytes_available); - - /* - * If its not the Transparent print device, return - * the full data amount. - */ - if (un->un_type != DGAP_PRINT) - return (bytes_available); - - if (ch->ch_digi.digi_maxcps > 0 && ch->ch_digi.digi_bufsize > 0 ) { - int cps_limit = 0; - unsigned long current_time = jiffies; - unsigned long buffer_time = current_time + - (HZ * ch->ch_digi.digi_bufsize) / ch->ch_digi.digi_maxcps; - - if (ch->ch_cpstime < current_time) { - /* buffer is empty */ - ch->ch_cpstime = current_time; /* reset ch_cpstime */ - cps_limit = ch->ch_digi.digi_bufsize; - } - else if (ch->ch_cpstime < buffer_time) { - /* still room in the buffer */ - cps_limit = ((buffer_time - ch->ch_cpstime) * ch->ch_digi.digi_maxcps) / HZ; - } - else { - /* no room in the buffer */ - cps_limit = 0; - } - - bytes_available = min(cps_limit, bytes_available); - } - - return (bytes_available); -} - - -static inline void dgap_set_firmware_event(struct un_t *un, unsigned int event) -{ - struct channel_t *ch = NULL; - struct bs_t *bs = NULL; - - if (!un || un->magic != DGAP_UNIT_MAGIC) - return; - ch = un->un_ch; - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return; - bs = ch->ch_bs; - if (!bs) - return; - - if ((event & UN_LOW) != 0) { - if ((un->un_flags & UN_LOW) == 0) { - un->un_flags |= UN_LOW; - writeb(1, &(bs->ilow)); - } - } - if ((event & UN_LOW) != 0) { - if ((un->un_flags & UN_EMPTY) == 0) { - un->un_flags |= UN_EMPTY; - writeb(1, &(bs->iempty)); - } - } -} - - -/* - * dgap_tty_write_room() - * - * Return space available in Tx buffer - */ -static int dgap_tty_write_room(struct tty_struct *tty) -{ - struct channel_t *ch = NULL; - struct un_t *un = NULL; - struct bs_t *bs = NULL; - u16 head, tail, tmask; - int ret = 0; - ulong lock_flags = 0; - - if (tty == NULL || dgap_TmpWriteBuf == NULL) - return(0); - - un = tty->driver_data; - if (!un || un->magic != DGAP_UNIT_MAGIC) - return (0); - - ch = un->un_ch; - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return (0); - - bs = ch->ch_bs; - if (!bs) - return (0); - - DGAP_LOCK(ch->ch_lock, lock_flags); - - tmask = ch->ch_tsize - 1; - head = readw(&(bs->tx_head)) & tmask; - tail = readw(&(bs->tx_tail)) & tmask; - - if ((ret = tail - head - 1) < 0) - ret += ch->ch_tsize; - - /* Limit printer to maxcps */ - ret = dgap_maxcps_room(tty, ret); - - /* - * If we are printer device, leave space for - * possibly both the on and off strings. - */ - if (un->un_type == DGAP_PRINT) { - if (!(ch->ch_flags & CH_PRON)) - ret -= ch->ch_digi.digi_onlen; - ret -= ch->ch_digi.digi_offlen; - } - else { - if (ch->ch_flags & CH_PRON) - ret -= ch->ch_digi.digi_offlen; - } - - if (ret < 0) - ret = 0; - - /* - * Schedule FEP to wake us up if needed. - * - * TODO: This might be overkill... - * Do we really need to schedule callbacks from the FEP - * in every case? Can we get smarter based on ret? - */ - dgap_set_firmware_event(un, UN_LOW | UN_EMPTY); - DGAP_UNLOCK(ch->ch_lock, lock_flags); - - DPR_WRITE(("dgap_tty_write_room - %d tail: %d head: %d\n", ret, tail, head)); - - return(ret); -} - - -/* - * dgap_tty_put_char() - * - * Put a character into ch->ch_buf - * - * - used by the line discipline for OPOST processing - */ -static int dgap_tty_put_char(struct tty_struct *tty, unsigned char c) -{ - /* - * Simply call tty_write. - */ - DPR_WRITE(("dgap_tty_put_char called\n")); - dgap_tty_write(tty, &c, 1); - return 1; -} - - -/* - * dgap_tty_write() - * - * Take data from the user or kernel and send it out to the FEP. - * In here exists all the Transparent Print magic as well. - */ -static int dgap_tty_write(struct tty_struct *tty, const unsigned char *buf, int count) -{ - struct channel_t *ch = NULL; - struct un_t *un = NULL; - struct bs_t *bs = NULL; - char *vaddr = NULL; - u16 head, tail, tmask, remain; - int bufcount = 0, n = 0; - int orig_count = 0; - ulong lock_flags; - int from_user = 0; - - if (tty == NULL || dgap_TmpWriteBuf == NULL) - return(0); - - un = tty->driver_data; - if (!un || un->magic != DGAP_UNIT_MAGIC) - return (0); - - ch = un->un_ch; - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return(0); - - bs = ch->ch_bs; - if (!bs) - return(0); - - if (!count) - return(0); - - DPR_WRITE(("dgap_tty_write: Port: %x tty=%p user=%d len=%d\n", - ch->ch_portnum, tty, from_user, count)); - - /* - * Store original amount of characters passed in. - * This helps to figure out if we should ask the FEP - * to send us an event when it has more space available. - */ - orig_count = count; - - DGAP_LOCK(ch->ch_lock, lock_flags); - - /* Get our space available for the channel from the board */ - tmask = ch->ch_tsize - 1; - head = readw(&(bs->tx_head)) & tmask; - tail = readw(&(bs->tx_tail)) & tmask; - - if ((bufcount = tail - head - 1) < 0) - bufcount += ch->ch_tsize; - - DPR_WRITE(("%d: bufcount: %x count: %x tail: %x head: %x tmask: %x\n", - __LINE__, bufcount, count, tail, head, tmask)); - - /* - * Limit printer output to maxcps overall, with bursts allowed - * up to bufsize characters. - */ - bufcount = dgap_maxcps_room(tty, bufcount); - - /* - * Take minimum of what the user wants to send, and the - * space available in the FEP buffer. - */ - count = min(count, bufcount); - - /* - * Bail if no space left. - */ - if (count <= 0) { - dgap_set_firmware_event(un, UN_LOW | UN_EMPTY); - DGAP_UNLOCK(ch->ch_lock, lock_flags); - return(0); - } - - /* - * Output the printer ON string, if we are in terminal mode, but - * need to be in printer mode. - */ - if ((un->un_type == DGAP_PRINT) && !(ch->ch_flags & CH_PRON)) { - dgap_wmove(ch, ch->ch_digi.digi_onstr, - (int) ch->ch_digi.digi_onlen); - head = readw(&(bs->tx_head)) & tmask; - ch->ch_flags |= CH_PRON; - } - - /* - * On the other hand, output the printer OFF string, if we are - * currently in printer mode, but need to output to the terminal. - */ - if ((un->un_type != DGAP_PRINT) && (ch->ch_flags & CH_PRON)) { - dgap_wmove(ch, ch->ch_digi.digi_offstr, - (int) ch->ch_digi.digi_offlen); - head = readw(&(bs->tx_head)) & tmask; - ch->ch_flags &= ~CH_PRON; - } - - /* - * If there is nothing left to copy, or I can't handle any more data, leave. - */ - if (count <= 0) { - dgap_set_firmware_event(un, UN_LOW | UN_EMPTY); - DGAP_UNLOCK(ch->ch_lock, lock_flags); - return(0); - } - - if (from_user) { - - count = min(count, WRITEBUFLEN); - - DGAP_UNLOCK(ch->ch_lock, lock_flags); - - /* - * If data is coming from user space, copy it into a temporary - * buffer so we don't get swapped out while doing the copy to - * the board. - */ - /* we're allowed to block if it's from_user */ - if (down_interruptible(&dgap_TmpWriteSem)) { - return (-EINTR); - } - - if (copy_from_user(dgap_TmpWriteBuf, (const uchar __user *) buf, count)) { - up(&dgap_TmpWriteSem); - printk("Write: Copy from user failed!\n"); - return -EFAULT; - } - - DGAP_LOCK(ch->ch_lock, lock_flags); - - buf = dgap_TmpWriteBuf; - } - - n = count; - - /* - * If the write wraps over the top of the circular buffer, - * move the portion up to the wrap point, and reset the - * pointers to the bottom. - */ - remain = ch->ch_tstart + ch->ch_tsize - head; - - if (n >= remain) { - n -= remain; - vaddr = ch->ch_taddr + head; - - memcpy_toio(vaddr, (uchar *) buf, remain); - dgap_sniff_nowait_nolock(ch, "USER WRITE", (uchar *) buf, remain); - - head = ch->ch_tstart; - buf += remain; - } - - if (n > 0) { - - /* - * Move rest of data. - */ - vaddr = ch->ch_taddr + head; - remain = n; - - memcpy_toio(vaddr, (uchar *) buf, remain); - dgap_sniff_nowait_nolock(ch, "USER WRITE", (uchar *) buf, remain); - - head += remain; - - } - - if (count) { - ch->ch_txcount += count; - head &= tmask; - writew(head, &(bs->tx_head)); - } - - - dgap_set_firmware_event(un, UN_LOW | UN_EMPTY); - - /* - * If this is the print device, and the - * printer is still on, we need to turn it - * off before going idle. If the buffer is - * non-empty, wait until it goes empty. - * Otherwise turn it off right now. - */ - if ((un->un_type == DGAP_PRINT) && (ch->ch_flags & CH_PRON)) { - tail = readw(&(bs->tx_tail)) & tmask; - - if (tail != head) { - un->un_flags |= UN_EMPTY; - writeb(1, &(bs->iempty)); - } - else { - dgap_wmove(ch, ch->ch_digi.digi_offstr, - (int) ch->ch_digi.digi_offlen); - head = readw(&(bs->tx_head)) & tmask; - ch->ch_flags &= ~CH_PRON; - } - } - - /* Update printer buffer empty time. */ - if ((un->un_type == DGAP_PRINT) && (ch->ch_digi.digi_maxcps > 0) - && (ch->ch_digi.digi_bufsize > 0)) { - ch->ch_cpstime += (HZ * count) / ch->ch_digi.digi_maxcps; - } - - if (from_user) { - DGAP_UNLOCK(ch->ch_lock, lock_flags); - up(&dgap_TmpWriteSem); - } - else { - DGAP_UNLOCK(ch->ch_lock, lock_flags); - } - - DPR_WRITE(("Write finished - Write %d bytes of %d.\n", count, orig_count)); - - return (count); -} - - - -/* - * Return modem signals to ld. - */ -static int dgap_tty_tiocmget(struct tty_struct *tty) -{ - struct channel_t *ch; - struct un_t *un; - int result = -EIO; - uchar mstat = 0; - ulong lock_flags; - - if (!tty || tty->magic != TTY_MAGIC) - return result; - - un = tty->driver_data; - if (!un || un->magic != DGAP_UNIT_MAGIC) - return result; - - ch = un->un_ch; - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return result; - - DPR_IOCTL(("dgap_tty_tiocmget start\n")); - - DGAP_LOCK(ch->ch_lock, lock_flags); - - mstat = readb(&(ch->ch_bs->m_stat)); - /* Append any outbound signals that might be pending... */ - mstat |= ch->ch_mostat; - - DGAP_UNLOCK(ch->ch_lock, lock_flags); - - result = 0; - - if (mstat & D_DTR(ch)) - result |= TIOCM_DTR; - if (mstat & D_RTS(ch)) - result |= TIOCM_RTS; - if (mstat & D_CTS(ch)) - result |= TIOCM_CTS; - if (mstat & D_DSR(ch)) - result |= TIOCM_DSR; - if (mstat & D_RI(ch)) - result |= TIOCM_RI; - if (mstat & D_CD(ch)) - result |= TIOCM_CD; - - DPR_IOCTL(("dgap_tty_tiocmget finish\n")); - - return result; -} - - -/* - * dgap_tty_tiocmset() - * - * Set modem signals, called by ld. - */ - -static int dgap_tty_tiocmset(struct tty_struct *tty, - unsigned int set, unsigned int clear) -{ - struct board_t *bd; - struct channel_t *ch; - struct un_t *un; - int ret = -EIO; - ulong lock_flags; - ulong lock_flags2; - - if (!tty || tty->magic != TTY_MAGIC) - return ret; - - un = tty->driver_data; - if (!un || un->magic != DGAP_UNIT_MAGIC) - return ret; - - ch = un->un_ch; - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return ret; - - bd = ch->ch_bd; - if (!bd || bd->magic != DGAP_BOARD_MAGIC) - return ret; - - DPR_IOCTL(("dgap_tty_tiocmset start\n")); - - DGAP_LOCK(bd->bd_lock, lock_flags); - DGAP_LOCK(ch->ch_lock, lock_flags2); - - if (set & TIOCM_RTS) { - ch->ch_mforce |= D_RTS(ch); - ch->ch_mval |= D_RTS(ch); - } - - if (set & TIOCM_DTR) { - ch->ch_mforce |= D_DTR(ch); - ch->ch_mval |= D_DTR(ch); - } - - if (clear & TIOCM_RTS) { - ch->ch_mforce |= D_RTS(ch); - ch->ch_mval &= ~(D_RTS(ch)); - } - - if (clear & TIOCM_DTR) { - ch->ch_mforce |= D_DTR(ch); - ch->ch_mval &= ~(D_DTR(ch)); - } - - dgap_param(tty); - - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - - DPR_IOCTL(("dgap_tty_tiocmset finish\n")); - - return (0); -} - - - -/* - * dgap_tty_send_break() - * - * Send a Break, called by ld. - */ -static int dgap_tty_send_break(struct tty_struct *tty, int msec) -{ - struct board_t *bd; - struct channel_t *ch; - struct un_t *un; - int ret = -EIO; - ulong lock_flags; - ulong lock_flags2; - - if (!tty || tty->magic != TTY_MAGIC) - return ret; - - un = tty->driver_data; - if (!un || un->magic != DGAP_UNIT_MAGIC) - return ret; - - ch = un->un_ch; - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return ret; - - bd = ch->ch_bd; - if (!bd || bd->magic != DGAP_BOARD_MAGIC) - return ret; - - switch (msec) { - case -1: - msec = 0xFFFF; - break; - case 0: - msec = 1; - break; - default: - msec /= 10; - break; - } - - DPR_IOCTL(("dgap_tty_send_break start 1. %lx\n", jiffies)); - - DGAP_LOCK(bd->bd_lock, lock_flags); - DGAP_LOCK(ch->ch_lock, lock_flags2); -#if 0 - dgap_cmdw(ch, SBREAK, (u16) SBREAK_TIME, 0); -#endif - dgap_cmdw(ch, SBREAK, (u16) msec, 0); - - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - - DPR_IOCTL(("dgap_tty_send_break finish\n")); - - return (0); -} - - - - -/* - * dgap_tty_wait_until_sent() - * - * wait until data has been transmitted, called by ld. - */ -static void dgap_tty_wait_until_sent(struct tty_struct *tty, int timeout) -{ - int rc; - rc = dgap_wait_for_drain(tty); - if (rc) { - DPR_IOCTL(("dgap_tty_ioctl - bad return: %d ", rc)); - return; - } - return; -} - - - -/* - * dgap_send_xchar() - * - * send a high priority character, called by ld. - */ -static void dgap_tty_send_xchar(struct tty_struct *tty, char c) -{ - struct board_t *bd; - struct channel_t *ch; - struct un_t *un; - ulong lock_flags; - ulong lock_flags2; - - if (!tty || tty->magic != TTY_MAGIC) - return; - - un = tty->driver_data; - if (!un || un->magic != DGAP_UNIT_MAGIC) - return; - - ch = un->un_ch; - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return; - - bd = ch->ch_bd; - if (!bd || bd->magic != DGAP_BOARD_MAGIC) - return; - - DPR_IOCTL(("dgap_tty_send_xchar start 1. %lx\n", jiffies)); - - DGAP_LOCK(bd->bd_lock, lock_flags); - DGAP_LOCK(ch->ch_lock, lock_flags2); - - /* - * This is technically what we should do. - * However, the NIST tests specifically want - * to see each XON or XOFF character that it - * sends, so lets just send each character - * by hand... - */ -#if 0 - if (c == STOP_CHAR(tty)) { - dgap_cmdw(ch, RPAUSE, 0, 0); - } - else if (c == START_CHAR(tty)) { - dgap_cmdw(ch, RRESUME, 0, 0); - } - else { - dgap_wmove(ch, &c, 1); - } -#else - dgap_wmove(ch, &c, 1); -#endif - - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - - DPR_IOCTL(("dgap_tty_send_xchar finish\n")); - - return; -} - - - - -/* - * Return modem signals to ld. - */ -static int dgap_get_modem_info(struct channel_t *ch, unsigned int __user *value) -{ - int result = 0; - uchar mstat = 0; - ulong lock_flags; - int rc = 0; - - DPR_IOCTL(("dgap_get_modem_info start\n")); - - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return(-ENXIO); - - DGAP_LOCK(ch->ch_lock, lock_flags); - - mstat = readb(&(ch->ch_bs->m_stat)); - /* Append any outbound signals that might be pending... */ - mstat |= ch->ch_mostat; - - DGAP_UNLOCK(ch->ch_lock, lock_flags); - - result = 0; - - if (mstat & D_DTR(ch)) - result |= TIOCM_DTR; - if (mstat & D_RTS(ch)) - result |= TIOCM_RTS; - if (mstat & D_CTS(ch)) - result |= TIOCM_CTS; - if (mstat & D_DSR(ch)) - result |= TIOCM_DSR; - if (mstat & D_RI(ch)) - result |= TIOCM_RI; - if (mstat & D_CD(ch)) - result |= TIOCM_CD; - - rc = put_user(result, value); - - DPR_IOCTL(("dgap_get_modem_info finish\n")); - return(rc); -} - - -/* - * dgap_set_modem_info() - * - * Set modem signals, called by ld. - */ -static int dgap_set_modem_info(struct tty_struct *tty, unsigned int command, unsigned int __user *value) -{ - struct board_t *bd; - struct channel_t *ch; - struct un_t *un; - int ret = -ENXIO; - unsigned int arg = 0; - ulong lock_flags; - ulong lock_flags2; - - if (!tty || tty->magic != TTY_MAGIC) - return ret; - - un = tty->driver_data; - if (!un || un->magic != DGAP_UNIT_MAGIC) - return ret; - - ch = un->un_ch; - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return ret; - - bd = ch->ch_bd; - if (!bd || bd->magic != DGAP_BOARD_MAGIC) - return ret; - - DPR_IOCTL(("dgap_set_modem_info() start\n")); - - ret = get_user(arg, value); - if (ret) { - DPR_IOCTL(("dgap_set_modem_info %d ret: %x. finished.\n", __LINE__, ret)); - return(ret); - } - - DPR_IOCTL(("dgap_set_modem_info: command: %x arg: %x\n", command, arg)); - - switch (command) { - case TIOCMBIS: - if (arg & TIOCM_RTS) { - ch->ch_mforce |= D_RTS(ch); - ch->ch_mval |= D_RTS(ch); - } - - if (arg & TIOCM_DTR) { - ch->ch_mforce |= D_DTR(ch); - ch->ch_mval |= D_DTR(ch); - } - - break; - - case TIOCMBIC: - if (arg & TIOCM_RTS) { - ch->ch_mforce |= D_RTS(ch); - ch->ch_mval &= ~(D_RTS(ch)); - } - - if (arg & TIOCM_DTR) { - ch->ch_mforce |= D_DTR(ch); - ch->ch_mval &= ~(D_DTR(ch)); - } - - break; - - case TIOCMSET: - ch->ch_mforce = D_DTR(ch)|D_RTS(ch); - - if (arg & TIOCM_RTS) { - ch->ch_mval |= D_RTS(ch); - } - else { - ch->ch_mval &= ~(D_RTS(ch)); - } - - if (arg & TIOCM_DTR) { - ch->ch_mval |= (D_DTR(ch)); - } - else { - ch->ch_mval &= ~(D_DTR(ch)); - } - - break; - - default: - return(-EINVAL); - } - - DGAP_LOCK(bd->bd_lock, lock_flags); - DGAP_LOCK(ch->ch_lock, lock_flags2); - - dgap_param(tty); - - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - - DPR_IOCTL(("dgap_set_modem_info finish\n")); - - return (0); -} - - -/* - * dgap_tty_digigeta() - * - * Ioctl to get the information for ditty. - * - * - * - */ -static int dgap_tty_digigeta(struct tty_struct *tty, struct digi_t __user *retinfo) -{ - struct channel_t *ch; - struct un_t *un; - struct digi_t tmp; - ulong lock_flags; - - if (!retinfo) - return (-EFAULT); - - if (!tty || tty->magic != TTY_MAGIC) - return (-EFAULT); - - un = tty->driver_data; - if (!un || un->magic != DGAP_UNIT_MAGIC) - return (-EFAULT); - - ch = un->un_ch; - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return (-EFAULT); - - memset(&tmp, 0, sizeof(tmp)); - - DGAP_LOCK(ch->ch_lock, lock_flags); - memcpy(&tmp, &ch->ch_digi, sizeof(tmp)); - DGAP_UNLOCK(ch->ch_lock, lock_flags); - - if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) - return (-EFAULT); - - return (0); -} - - -/* - * dgap_tty_digiseta() - * - * Ioctl to set the information for ditty. - * - * - * - */ -static int dgap_tty_digiseta(struct tty_struct *tty, struct digi_t __user *new_info) -{ - struct board_t *bd; - struct channel_t *ch; - struct un_t *un; - struct digi_t new_digi; - ulong lock_flags = 0; - unsigned long lock_flags2; - - DPR_IOCTL(("DIGI_SETA start\n")); - - if (!tty || tty->magic != TTY_MAGIC) - return (-EFAULT); - - un = tty->driver_data; - if (!un || un->magic != DGAP_UNIT_MAGIC) - return (-EFAULT); - - ch = un->un_ch; - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return (-EFAULT); - - bd = ch->ch_bd; - if (!bd || bd->magic != DGAP_BOARD_MAGIC) - return (-EFAULT); - - if (copy_from_user(&new_digi, new_info, sizeof(struct digi_t))) { - DPR_IOCTL(("DIGI_SETA failed copy_from_user\n")); - return(-EFAULT); - } - - DGAP_LOCK(bd->bd_lock, lock_flags); - DGAP_LOCK(ch->ch_lock, lock_flags2); - - memcpy(&ch->ch_digi, &new_digi, sizeof(struct digi_t)); - - if (ch->ch_digi.digi_maxcps < 1) - ch->ch_digi.digi_maxcps = 1; - - if (ch->ch_digi.digi_maxcps > 10000) - ch->ch_digi.digi_maxcps = 10000; - - if (ch->ch_digi.digi_bufsize < 10) - ch->ch_digi.digi_bufsize = 10; - - if (ch->ch_digi.digi_maxchar < 1) - ch->ch_digi.digi_maxchar = 1; - - if (ch->ch_digi.digi_maxchar > ch->ch_digi.digi_bufsize) - ch->ch_digi.digi_maxchar = ch->ch_digi.digi_bufsize; - - if (ch->ch_digi.digi_onlen > DIGI_PLEN) - ch->ch_digi.digi_onlen = DIGI_PLEN; - - if (ch->ch_digi.digi_offlen > DIGI_PLEN) - ch->ch_digi.digi_offlen = DIGI_PLEN; - - dgap_param(tty); - - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - - DPR_IOCTL(("DIGI_SETA finish\n")); - - return(0); -} - - -/* - * dgap_tty_digigetedelay() - * - * Ioctl to get the current edelay setting. - * - * - * - */ -static int dgap_tty_digigetedelay(struct tty_struct *tty, int __user *retinfo) -{ - struct channel_t *ch; - struct un_t *un; - int tmp; - ulong lock_flags; - - if (!retinfo) - return (-EFAULT); - - if (!tty || tty->magic != TTY_MAGIC) - return (-EFAULT); - - un = tty->driver_data; - if (!un || un->magic != DGAP_UNIT_MAGIC) - return (-EFAULT); - - ch = un->un_ch; - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return (-EFAULT); - - memset(&tmp, 0, sizeof(tmp)); - - DGAP_LOCK(ch->ch_lock, lock_flags); - tmp = readw(&(ch->ch_bs->edelay)); - DGAP_UNLOCK(ch->ch_lock, lock_flags); - - if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) - return (-EFAULT); - - return (0); -} - - -/* - * dgap_tty_digisetedelay() - * - * Ioctl to set the EDELAY setting - * - */ -static int dgap_tty_digisetedelay(struct tty_struct *tty, int __user *new_info) -{ - struct board_t *bd; - struct channel_t *ch; - struct un_t *un; - int new_digi; - ulong lock_flags; - ulong lock_flags2; - - DPR_IOCTL(("DIGI_SETA start\n")); - - if (!tty || tty->magic != TTY_MAGIC) - return (-EFAULT); - - un = tty->driver_data; - if (!un || un->magic != DGAP_UNIT_MAGIC) - return (-EFAULT); - - ch = un->un_ch; - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return (-EFAULT); - - bd = ch->ch_bd; - if (!bd || bd->magic != DGAP_BOARD_MAGIC) - return (-EFAULT); - - if (copy_from_user(&new_digi, new_info, sizeof(int))) { - DPR_IOCTL(("DIGI_SETEDELAY failed copy_from_user\n")); - return(-EFAULT); - } - - DGAP_LOCK(bd->bd_lock, lock_flags); - DGAP_LOCK(ch->ch_lock, lock_flags2); - - writew((u16) new_digi, &(ch->ch_bs->edelay)); - - dgap_param(tty); - - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - - DPR_IOCTL(("DIGI_SETA finish\n")); - - return(0); -} - - -/* - * dgap_tty_digigetcustombaud() - * - * Ioctl to get the current custom baud rate setting. - */ -static int dgap_tty_digigetcustombaud(struct tty_struct *tty, int __user *retinfo) -{ - struct channel_t *ch; - struct un_t *un; - int tmp; - ulong lock_flags; - - if (!retinfo) - return (-EFAULT); - - if (!tty || tty->magic != TTY_MAGIC) - return (-EFAULT); - - un = tty->driver_data; - if (!un || un->magic != DGAP_UNIT_MAGIC) - return (-EFAULT); - - ch = un->un_ch; - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return (-EFAULT); - - memset(&tmp, 0, sizeof(tmp)); - - DGAP_LOCK(ch->ch_lock, lock_flags); - tmp = dgap_get_custom_baud(ch); - DGAP_UNLOCK(ch->ch_lock, lock_flags); - - DPR_IOCTL(("DIGI_GETCUSTOMBAUD. Returning %d\n", tmp)); - - if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) - return (-EFAULT); - - return (0); -} - - -/* - * dgap_tty_digisetcustombaud() - * - * Ioctl to set the custom baud rate setting - */ -static int dgap_tty_digisetcustombaud(struct tty_struct *tty, int __user *new_info) -{ - struct board_t *bd; - struct channel_t *ch; - struct un_t *un; - uint new_rate; - ulong lock_flags; - ulong lock_flags2; - - DPR_IOCTL(("DIGI_SETCUSTOMBAUD start\n")); - - if (!tty || tty->magic != TTY_MAGIC) - return (-EFAULT); - - un = tty->driver_data; - if (!un || un->magic != DGAP_UNIT_MAGIC) - return (-EFAULT); - - ch = un->un_ch; - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return (-EFAULT); - - bd = ch->ch_bd; - if (!bd || bd->magic != DGAP_BOARD_MAGIC) - return (-EFAULT); - - - if (copy_from_user(&new_rate, new_info, sizeof(unsigned int))) { - DPR_IOCTL(("DIGI_SETCUSTOMBAUD failed copy_from_user\n")); - return(-EFAULT); - } - - if (bd->bd_flags & BD_FEP5PLUS) { - - DPR_IOCTL(("DIGI_SETCUSTOMBAUD. Setting %d\n", new_rate)); - - DGAP_LOCK(bd->bd_lock, lock_flags); - DGAP_LOCK(ch->ch_lock, lock_flags2); - - ch->ch_custom_speed = new_rate; - - dgap_param(tty); - - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - } - - DPR_IOCTL(("DIGI_SETCUSTOMBAUD finish\n")); - - return(0); -} - - -/* - * dgap_set_termios() - */ -static void dgap_tty_set_termios(struct tty_struct *tty, struct ktermios *old_termios) -{ - struct board_t *bd; - struct channel_t *ch; - struct un_t *un; - unsigned long lock_flags; - unsigned long lock_flags2; - - if (!tty || tty->magic != TTY_MAGIC) - return; - - un = tty->driver_data; - if (!un || un->magic != DGAP_UNIT_MAGIC) - return; - - ch = un->un_ch; - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return; - - bd = ch->ch_bd; - if (!bd || bd->magic != DGAP_BOARD_MAGIC) - return; - - DGAP_LOCK(bd->bd_lock, lock_flags); - DGAP_LOCK(ch->ch_lock, lock_flags2); - - ch->ch_c_cflag = tty->termios.c_cflag; - ch->ch_c_iflag = tty->termios.c_iflag; - ch->ch_c_oflag = tty->termios.c_oflag; - ch->ch_c_lflag = tty->termios.c_lflag; - ch->ch_startc = tty->termios.c_cc[VSTART]; - ch->ch_stopc = tty->termios.c_cc[VSTOP]; - - dgap_carrier(ch); - dgap_param(tty); - - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); -} - - -static void dgap_tty_throttle(struct tty_struct *tty) -{ - struct board_t *bd; - struct channel_t *ch; - struct un_t *un; - ulong lock_flags; - ulong lock_flags2; - - if (!tty || tty->magic != TTY_MAGIC) - return; - - un = tty->driver_data; - if (!un || un->magic != DGAP_UNIT_MAGIC) - return; - - ch = un->un_ch; - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return; - - bd = ch->ch_bd; - if (!bd || bd->magic != DGAP_BOARD_MAGIC) - return; - - DPR_IOCTL(("dgap_tty_throttle start\n")); - - DGAP_LOCK(bd->bd_lock, lock_flags); - DGAP_LOCK(ch->ch_lock, lock_flags2); - - ch->ch_flags |= (CH_RXBLOCK); -#if 1 - dgap_cmdw(ch, RPAUSE, 0, 0); -#endif - - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - - DPR_IOCTL(("dgap_tty_throttle finish\n")); -} - - -static void dgap_tty_unthrottle(struct tty_struct *tty) -{ - struct board_t *bd; - struct channel_t *ch; - struct un_t *un; - ulong lock_flags; - ulong lock_flags2; - - if (!tty || tty->magic != TTY_MAGIC) - return; - - un = tty->driver_data; - if (!un || un->magic != DGAP_UNIT_MAGIC) - return; - - ch = un->un_ch; - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return; - - bd = ch->ch_bd; - if (!bd || bd->magic != DGAP_BOARD_MAGIC) - return; - - DPR_IOCTL(("dgap_tty_unthrottle start\n")); - - DGAP_LOCK(bd->bd_lock, lock_flags); - DGAP_LOCK(ch->ch_lock, lock_flags2); - - ch->ch_flags &= ~(CH_RXBLOCK); - -#if 1 - dgap_cmdw(ch, RRESUME, 0, 0); -#endif - - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - - DPR_IOCTL(("dgap_tty_unthrottle finish\n")); -} - - -static void dgap_tty_start(struct tty_struct *tty) -{ - struct board_t *bd; - struct channel_t *ch; - struct un_t *un; - ulong lock_flags; - ulong lock_flags2; - - if (!tty || tty->magic != TTY_MAGIC) - return; - - un = tty->driver_data; - if (!un || un->magic != DGAP_UNIT_MAGIC) - return; - - ch = un->un_ch; - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return; - - bd = ch->ch_bd; - if (!bd || bd->magic != DGAP_BOARD_MAGIC) - return; - - DPR_IOCTL(("dgap_tty_start start\n")); - - DGAP_LOCK(bd->bd_lock, lock_flags); - DGAP_LOCK(ch->ch_lock, lock_flags2); - - dgap_cmdw(ch, RESUMETX, 0, 0); - - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - - DPR_IOCTL(("dgap_tty_start finish\n")); -} - - -static void dgap_tty_stop(struct tty_struct *tty) -{ - struct board_t *bd; - struct channel_t *ch; - struct un_t *un; - ulong lock_flags; - ulong lock_flags2; - - if (!tty || tty->magic != TTY_MAGIC) - return; - - un = tty->driver_data; - if (!un || un->magic != DGAP_UNIT_MAGIC) - return; - - ch = un->un_ch; - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return; - - bd = ch->ch_bd; - if (!bd || bd->magic != DGAP_BOARD_MAGIC) - return; - - DPR_IOCTL(("dgap_tty_stop start\n")); - - DGAP_LOCK(bd->bd_lock, lock_flags); - DGAP_LOCK(ch->ch_lock, lock_flags2); - - dgap_cmdw(ch, PAUSETX, 0, 0); - - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - - DPR_IOCTL(("dgap_tty_stop finish\n")); -} - - -/* - * dgap_tty_flush_chars() - * - * Flush the cook buffer - * - * Note to self, and any other poor souls who venture here: - * - * flush in this case DOES NOT mean dispose of the data. - * instead, it means "stop buffering and send it if you - * haven't already." Just guess how I figured that out... SRW 2-Jun-98 - * - * It is also always called in interrupt context - JAR 8-Sept-99 - */ -static void dgap_tty_flush_chars(struct tty_struct *tty) -{ - struct board_t *bd; - struct channel_t *ch; - struct un_t *un; - ulong lock_flags; - ulong lock_flags2; - - if (!tty || tty->magic != TTY_MAGIC) - return; - - un = tty->driver_data; - if (!un || un->magic != DGAP_UNIT_MAGIC) - return; - - ch = un->un_ch; - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return; - - bd = ch->ch_bd; - if (!bd || bd->magic != DGAP_BOARD_MAGIC) - return; - - DPR_IOCTL(("dgap_tty_flush_chars start\n")); - - DGAP_LOCK(bd->bd_lock, lock_flags); - DGAP_LOCK(ch->ch_lock, lock_flags2); - - /* TODO: Do something here */ - - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - - DPR_IOCTL(("dgap_tty_flush_chars finish\n")); -} - - - -/* - * dgap_tty_flush_buffer() - * - * Flush Tx buffer (make in == out) - */ -static void dgap_tty_flush_buffer(struct tty_struct *tty) -{ - struct board_t *bd; - struct channel_t *ch; - struct un_t *un; - ulong lock_flags; - ulong lock_flags2; - u16 head = 0; - - if (!tty || tty->magic != TTY_MAGIC) - return; - - un = tty->driver_data; - if (!un || un->magic != DGAP_UNIT_MAGIC) - return; - - ch = un->un_ch; - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return; - - bd = ch->ch_bd; - if (!bd || bd->magic != DGAP_BOARD_MAGIC) - return; - - DPR_IOCTL(("dgap_tty_flush_buffer on port: %d start\n", ch->ch_portnum)); - - DGAP_LOCK(bd->bd_lock, lock_flags); - DGAP_LOCK(ch->ch_lock, lock_flags2); - - ch->ch_flags &= ~CH_STOP; - head = readw(&(ch->ch_bs->tx_head)); - dgap_cmdw(ch, FLUSHTX, (u16) head, 0); - dgap_cmdw(ch, RESUMETX, 0, 0); - if (ch->ch_tun.un_flags & (UN_LOW|UN_EMPTY)) { - ch->ch_tun.un_flags &= ~(UN_LOW|UN_EMPTY); - wake_up_interruptible(&ch->ch_tun.un_flags_wait); - } - if (ch->ch_pun.un_flags & (UN_LOW|UN_EMPTY)) { - ch->ch_pun.un_flags &= ~(UN_LOW|UN_EMPTY); - wake_up_interruptible(&ch->ch_pun.un_flags_wait); - } - - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - if (waitqueue_active(&tty->write_wait)) - wake_up_interruptible(&tty->write_wait); - tty_wakeup(tty); - - DPR_IOCTL(("dgap_tty_flush_buffer finish\n")); -} - - - -/***************************************************************************** - * - * The IOCTL function and all of its helpers - * - *****************************************************************************/ - -/* - * dgap_tty_ioctl() - * - * The usual assortment of ioctl's - */ -static int dgap_tty_ioctl(struct tty_struct *tty, unsigned int cmd, - unsigned long arg) -{ - struct board_t *bd; - struct channel_t *ch; - struct un_t *un; - int rc; - u16 head = 0; - ulong lock_flags = 0; - ulong lock_flags2 = 0; - void __user *uarg = (void __user *) arg; - - if (!tty || tty->magic != TTY_MAGIC) - return (-ENODEV); - - un = tty->driver_data; - if (!un || un->magic != DGAP_UNIT_MAGIC) - return (-ENODEV); - - ch = un->un_ch; - if (!ch || ch->magic != DGAP_CHANNEL_MAGIC) - return (-ENODEV); - - bd = ch->ch_bd; - if (!bd || bd->magic != DGAP_BOARD_MAGIC) - return (-ENODEV); - - DPR_IOCTL(("dgap_tty_ioctl start on port %d - cmd %s (%x), arg %lx\n", - ch->ch_portnum, dgap_ioctl_name(cmd), cmd, arg)); - - DGAP_LOCK(bd->bd_lock, lock_flags); - DGAP_LOCK(ch->ch_lock, lock_flags2); - - if (un->un_open_count <= 0) { - DPR_BASIC(("dgap_tty_ioctl - unit not open.\n")); - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - return(-EIO); - } - - switch (cmd) { - - /* Here are all the standard ioctl's that we MUST implement */ - - case TCSBRK: - /* - * TCSBRK is SVID version: non-zero arg --> no break - * this behaviour is exploited by tcdrain(). - * - * According to POSIX.1 spec (7.2.2.1.2) breaks should be - * between 0.25 and 0.5 seconds so we'll ask for something - * in the middle: 0.375 seconds. - */ - rc = tty_check_change(tty); - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - if (rc) { - return(rc); - } - - rc = dgap_wait_for_drain(tty); - - if (rc) { - DPR_IOCTL(("dgap_tty_ioctl - bad return: %d ", rc)); - return(-EINTR); - } - - DGAP_LOCK(bd->bd_lock, lock_flags); - DGAP_LOCK(ch->ch_lock, lock_flags2); - - if(((cmd == TCSBRK) && (!arg)) || (cmd == TCSBRKP)) { - dgap_cmdw(ch, SBREAK, (u16) SBREAK_TIME, 0); - } - - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - - DPR_IOCTL(("dgap_tty_ioctl finish on port %d - cmd %s (%x), arg %lx\n", - ch->ch_portnum, dgap_ioctl_name(cmd), cmd, arg)); - - return(0); - - - case TCSBRKP: - /* support for POSIX tcsendbreak() - - * According to POSIX.1 spec (7.2.2.1.2) breaks should be - * between 0.25 and 0.5 seconds so we'll ask for something - * in the middle: 0.375 seconds. - */ - rc = tty_check_change(tty); - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - if (rc) { - return(rc); - } - - rc = dgap_wait_for_drain(tty); - if (rc) { - DPR_IOCTL(("dgap_tty_ioctl - bad return: %d ", rc)); - return(-EINTR); - } - - DGAP_LOCK(bd->bd_lock, lock_flags); - DGAP_LOCK(ch->ch_lock, lock_flags2); - - dgap_cmdw(ch, SBREAK, (u16) SBREAK_TIME, 0); - - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - - DPR_IOCTL(("dgap_tty_ioctl finish on port %d - cmd %s (%x), arg %lx\n", - ch->ch_portnum, dgap_ioctl_name(cmd), cmd, arg)); - - return(0); - - case TIOCSBRK: - /* - * FEP5 doesn't support turning on a break unconditionally. - * The FEP5 device will stop sending a break automatically - * after the specified time value that was sent when turning on - * the break. - */ - rc = tty_check_change(tty); - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - if (rc) { - return(rc); - } - - rc = dgap_wait_for_drain(tty); - if (rc) { - DPR_IOCTL(("dgap_tty_ioctl - bad return: %d ", rc)); - return(-EINTR); - } - - DGAP_LOCK(bd->bd_lock, lock_flags); - DGAP_LOCK(ch->ch_lock, lock_flags2); - - dgap_cmdw(ch, SBREAK, (u16) SBREAK_TIME, 0); - - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - - DPR_IOCTL(("dgap_tty_ioctl finish on port %d - cmd %s (%x), arg %lx\n", - ch->ch_portnum, dgap_ioctl_name(cmd), cmd, arg)); - - return 0; - - case TIOCCBRK: - /* - * FEP5 doesn't support turning off a break unconditionally. - * The FEP5 device will stop sending a break automatically - * after the specified time value that was sent when turning on - * the break. - */ - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - return 0; - - case TIOCGSOFTCAR: - - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - - rc = put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long __user *) arg); - return(rc); - - case TIOCSSOFTCAR: - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - - rc = get_user(arg, (unsigned long __user *) arg); - if (rc) - return(rc); - - DGAP_LOCK(bd->bd_lock, lock_flags); - DGAP_LOCK(ch->ch_lock, lock_flags2); - tty->termios.c_cflag = ((tty->termios.c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0)); - dgap_param(tty); - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - - return(0); - - case TIOCMGET: - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - return(dgap_get_modem_info(ch, uarg)); - - case TIOCMBIS: - case TIOCMBIC: - case TIOCMSET: - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - return(dgap_set_modem_info(tty, cmd, uarg)); - - /* - * Here are any additional ioctl's that we want to implement - */ - - case TCFLSH: - /* - * The linux tty driver doesn't have a flush - * input routine for the driver, assuming all backed - * up data is in the line disc. buffers. However, - * we all know that's not the case. Here, we - * act on the ioctl, but then lie and say we didn't - * so the line discipline will process the flush - * also. - */ - rc = tty_check_change(tty); - if (rc) { - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - return(rc); - } - - if ((arg == TCIFLUSH) || (arg == TCIOFLUSH)) { - if (!(un->un_type == DGAP_PRINT)) { - head = readw(&(ch->ch_bs->rx_head)); - writew(head, &(ch->ch_bs->rx_tail)); - writeb(0, &(ch->ch_bs->orun)); - } - } - - if ((arg == TCOFLUSH) || (arg == TCIOFLUSH)) { - ch->ch_flags &= ~CH_STOP; - head = readw(&(ch->ch_bs->tx_head)); - dgap_cmdw(ch, FLUSHTX, (u16) head, 0 ); - dgap_cmdw(ch, RESUMETX, 0, 0); - if (ch->ch_tun.un_flags & (UN_LOW|UN_EMPTY)) { - ch->ch_tun.un_flags &= ~(UN_LOW|UN_EMPTY); - wake_up_interruptible(&ch->ch_tun.un_flags_wait); - } - if (ch->ch_pun.un_flags & (UN_LOW|UN_EMPTY)) { - ch->ch_pun.un_flags &= ~(UN_LOW|UN_EMPTY); - wake_up_interruptible(&ch->ch_pun.un_flags_wait); - } - if (waitqueue_active(&tty->write_wait)) - wake_up_interruptible(&tty->write_wait); - - /* Can't hold any locks when calling tty_wakeup! */ - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - tty_wakeup(tty); - DGAP_LOCK(bd->bd_lock, lock_flags); - DGAP_LOCK(ch->ch_lock, lock_flags2); - } - - /* pretend we didn't recognize this IOCTL */ - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - - DPR_IOCTL(("dgap_tty_ioctl (LINE:%d) finish on port %d - cmd %s (%x), arg %lx\n", - __LINE__, ch->ch_portnum, dgap_ioctl_name(cmd), cmd, arg)); - - return(-ENOIOCTLCMD); - - case TCSETSF: - case TCSETSW: - /* - * The linux tty driver doesn't have a flush - * input routine for the driver, assuming all backed - * up data is in the line disc. buffers. However, - * we all know that's not the case. Here, we - * act on the ioctl, but then lie and say we didn't - * so the line discipline will process the flush - * also. - */ - if (cmd == TCSETSF) { - /* flush rx */ - ch->ch_flags &= ~CH_STOP; - head = readw(&(ch->ch_bs->rx_head)); - writew(head, &(ch->ch_bs->rx_tail)); - } - - /* now wait for all the output to drain */ - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - rc = dgap_wait_for_drain(tty); - if (rc) { - DPR_IOCTL(("dgap_tty_ioctl - bad return: %d ", rc)); - return(-EINTR); - } - - DPR_IOCTL(("dgap_tty_ioctl finish on port %d - cmd %s (%x), arg %lx\n", - ch->ch_portnum, dgap_ioctl_name(cmd), cmd, arg)); - - /* pretend we didn't recognize this */ - return(-ENOIOCTLCMD); - - case TCSETAW: - - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - rc = dgap_wait_for_drain(tty); - if (rc) { - DPR_IOCTL(("dgap_tty_ioctl - bad return: %d ", rc)); - return(-EINTR); - } - - /* pretend we didn't recognize this */ - return(-ENOIOCTLCMD); - - case TCXONC: - /* - * The Linux Line Discipline (LD) would do this for us if we - * let it, but we have the special firmware options to do this - * the "right way" regardless of hardware or software flow - * control so we'll do it outselves instead of letting the LD - * do it. - */ - rc = tty_check_change(tty); - if (rc) { - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - return(rc); - } - - DPR_IOCTL(("dgap_ioctl - in TCXONC - %d\n", cmd)); - switch (arg) { - - case TCOON: - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - dgap_tty_start(tty); - return(0); - case TCOOFF: - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - dgap_tty_stop(tty); - return(0); - case TCION: - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - /* Make the ld do it */ - return(-ENOIOCTLCMD); - case TCIOFF: - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - /* Make the ld do it */ - return(-ENOIOCTLCMD); - default: - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - return(-EINVAL); - } - - case DIGI_GETA: - /* get information for ditty */ - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - return(dgap_tty_digigeta(tty, uarg)); - - case DIGI_SETAW: - case DIGI_SETAF: - - /* set information for ditty */ - if (cmd == (DIGI_SETAW)) { - - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - rc = dgap_wait_for_drain(tty); - if (rc) { - DPR_IOCTL(("dgap_tty_ioctl - bad return: %d ", rc)); - return(-EINTR); - } - DGAP_LOCK(bd->bd_lock, lock_flags); - DGAP_LOCK(ch->ch_lock, lock_flags2); - } - else { - tty_ldisc_flush(tty); - } - /* fall thru */ - - case DIGI_SETA: - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - return(dgap_tty_digiseta(tty, uarg)); - - case DIGI_GEDELAY: - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - return(dgap_tty_digigetedelay(tty, uarg)); - - case DIGI_SEDELAY: - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - return(dgap_tty_digisetedelay(tty, uarg)); - - case DIGI_GETCUSTOMBAUD: - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - return(dgap_tty_digigetcustombaud(tty, uarg)); - - case DIGI_SETCUSTOMBAUD: - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - return(dgap_tty_digisetcustombaud(tty, uarg)); - - case DIGI_RESET_PORT: - dgap_firmware_reset_port(ch); - dgap_param(tty); - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - return 0; - - default: - DGAP_UNLOCK(ch->ch_lock, lock_flags2); - DGAP_UNLOCK(bd->bd_lock, lock_flags); - - DPR_IOCTL(("dgap_tty_ioctl - in default\n")); - DPR_IOCTL(("dgap_tty_ioctl end - cmd %s (%x), arg %lx\n", - dgap_ioctl_name(cmd), cmd, arg)); - - return(-ENOIOCTLCMD); - } -} diff --git a/drivers/staging/dgap/dgap_tty.h b/drivers/staging/dgap/dgap_tty.h deleted file mode 100644 index 464a460b6be..00000000000 --- a/drivers/staging/dgap/dgap_tty.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2003 Digi International (www.digi.com) - * Scott H Kilau <Scott_Kilau at digi dot com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the - * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!! - */ - -#ifndef __DGAP_TTY_H -#define __DGAP_TTY_H - -#include "dgap_driver.h" - -int dgap_tty_register(struct board_t *brd); - -int dgap_tty_preinit(void); -int dgap_tty_init(struct board_t *); - -void dgap_tty_post_uninit(void); -void dgap_tty_uninit(struct board_t *); - -void dgap_carrier(struct channel_t *ch); -void dgap_input(struct channel_t *ch); - - -#endif diff --git a/drivers/staging/dgap/dgap_types.h b/drivers/staging/dgap/dgap_types.h deleted file mode 100644 index eca38c7f359..00000000000 --- a/drivers/staging/dgap/dgap_types.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2003 Digi International (www.digi.com) - * Scott H Kilau <Scott_Kilau at digi dot com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the - * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!! - */ - -#ifndef __DGAP_TYPES_H -#define __DGAP_TYPES_H - -#ifndef TRUE -# define TRUE 1 -#endif - -#ifndef FALSE -# define FALSE 0 -#endif - -/* Required for our shared headers! */ -typedef unsigned char uchar; - -#endif diff --git a/drivers/staging/dgap/digi.h b/drivers/staging/dgap/digi.h deleted file mode 100644 index fe879039671..00000000000 --- a/drivers/staging/dgap/digi.h +++ /dev/null @@ -1,376 +0,0 @@ -/* - * Copyright 2003 Digi International (www.digi.com) - * Scott H Kilau <Scott_Kilau at digi dot com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the - * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * $Id: digi.h,v 1.1 2009/10/23 14:01:57 markh Exp $ - * - * NOTE: THIS IS A SHARED HEADER. DO NOT CHANGE CODING STYLE!!! - */ - -#ifndef __DIGI_H -#define __DIGI_H - -/************************************************************************ - *** Definitions for Digi ditty(1) command. - ************************************************************************/ - - -/* - * Copyright (c) 1988-96 Digi International Inc., All Rights Reserved. - */ - -/************************************************************************ - * This module provides application access to special Digi - * serial line enhancements which are not standard UNIX(tm) features. - ************************************************************************/ - -#if !defined(TIOCMODG) - -#define TIOCMODG ('d'<<8) | 250 /* get modem ctrl state */ -#define TIOCMODS ('d'<<8) | 251 /* set modem ctrl state */ - -#ifndef TIOCM_LE -#define TIOCM_LE 0x01 /* line enable */ -#define TIOCM_DTR 0x02 /* data terminal ready */ -#define TIOCM_RTS 0x04 /* request to send */ -#define TIOCM_ST 0x08 /* secondary transmit */ -#define TIOCM_SR 0x10 /* secondary receive */ -#define TIOCM_CTS 0x20 /* clear to send */ -#define TIOCM_CAR 0x40 /* carrier detect */ -#define TIOCM_RNG 0x80 /* ring indicator */ -#define TIOCM_DSR 0x100 /* data set ready */ -#define TIOCM_RI TIOCM_RNG /* ring (alternate) */ -#define TIOCM_CD TIOCM_CAR /* carrier detect (alt) */ -#endif - -#endif - -#if !defined(TIOCMSET) -#define TIOCMSET ('d'<<8) | 252 /* set modem ctrl state */ -#define TIOCMGET ('d'<<8) | 253 /* set modem ctrl state */ -#endif - -#if !defined(TIOCMBIC) -#define TIOCMBIC ('d'<<8) | 254 /* set modem ctrl state */ -#define TIOCMBIS ('d'<<8) | 255 /* set modem ctrl state */ -#endif - - -#if !defined(TIOCSDTR) -#define TIOCSDTR ('e'<<8) | 0 /* set DTR */ -#define TIOCCDTR ('e'<<8) | 1 /* clear DTR */ -#endif - -/************************************************************************ - * Ioctl command arguments for DIGI parameters. - ************************************************************************/ -#define DIGI_GETA ('e'<<8) | 94 /* Read params */ - -#define DIGI_SETA ('e'<<8) | 95 /* Set params */ -#define DIGI_SETAW ('e'<<8) | 96 /* Drain & set params */ -#define DIGI_SETAF ('e'<<8) | 97 /* Drain, flush & set params */ - -#define DIGI_KME ('e'<<8) | 98 /* Read/Write Host */ - /* Adapter Memory */ - -#define DIGI_GETFLOW ('e'<<8) | 99 /* Get startc/stopc flow */ - /* control characters */ -#define DIGI_SETFLOW ('e'<<8) | 100 /* Set startc/stopc flow */ - /* control characters */ -#define DIGI_GETAFLOW ('e'<<8) | 101 /* Get Aux. startc/stopc */ - /* flow control chars */ -#define DIGI_SETAFLOW ('e'<<8) | 102 /* Set Aux. startc/stopc */ - /* flow control chars */ - -#define DIGI_GEDELAY ('d'<<8) | 246 /* Get edelay */ -#define DIGI_SEDELAY ('d'<<8) | 247 /* Set edelay */ - -struct digiflow_t { - unsigned char startc; /* flow cntl start char */ - unsigned char stopc; /* flow cntl stop char */ -}; - - -#ifdef FLOW_2200 -#define F2200_GETA ('e'<<8) | 104 /* Get 2x36 flow cntl flags */ -#define F2200_SETAW ('e'<<8) | 105 /* Set 2x36 flow cntl flags */ -#define F2200_MASK 0x03 /* 2200 flow cntl bit mask */ -#define FCNTL_2200 0x01 /* 2x36 terminal flow cntl */ -#define PCNTL_2200 0x02 /* 2x36 printer flow cntl */ -#define F2200_XON 0xf8 -#define P2200_XON 0xf9 -#define F2200_XOFF 0xfa -#define P2200_XOFF 0xfb - -#define FXOFF_MASK 0x03 /* 2200 flow status mask */ -#define RCVD_FXOFF 0x01 /* 2x36 Terminal XOFF rcvd */ -#define RCVD_PXOFF 0x02 /* 2x36 Printer XOFF rcvd */ -#endif - -/************************************************************************ - * Values for digi_flags - ************************************************************************/ -#define DIGI_IXON 0x0001 /* Handle IXON in the FEP */ -#define DIGI_FAST 0x0002 /* Fast baud rates */ -#define RTSPACE 0x0004 /* RTS input flow control */ -#define CTSPACE 0x0008 /* CTS output flow control */ -#define DSRPACE 0x0010 /* DSR output flow control */ -#define DCDPACE 0x0020 /* DCD output flow control */ -#define DTRPACE 0x0040 /* DTR input flow control */ -#define DIGI_COOK 0x0080 /* Cooked processing done in FEP */ -#define DIGI_FORCEDCD 0x0100 /* Force carrier */ -#define DIGI_ALTPIN 0x0200 /* Alternate RJ-45 pin config */ -#define DIGI_AIXON 0x0400 /* Aux flow control in fep */ -#define DIGI_PRINTER 0x0800 /* Hold port open for flow cntrl*/ -#define DIGI_PP_INPUT 0x1000 /* Change parallel port to input*/ -#define DIGI_DTR_TOGGLE 0x2000 /* Support DTR Toggle */ -#define DIGI_422 0x4000 /* for 422/232 selectable panel */ -#define DIGI_RTS_TOGGLE 0x8000 /* Support RTS Toggle */ - -/************************************************************************ - * These options are not supported on the comxi. - ************************************************************************/ -#define DIGI_COMXI (DIGI_FAST|DIGI_COOK|DSRPACE|DCDPACE|DTRPACE) - -#define DIGI_PLEN 28 /* String length */ -#define DIGI_TSIZ 10 /* Terminal string len */ - -/************************************************************************ - * Structure used with ioctl commands for DIGI parameters. - ************************************************************************/ -struct digi_t { - unsigned short digi_flags; /* Flags (see above) */ - unsigned short digi_maxcps; /* Max printer CPS */ - unsigned short digi_maxchar; /* Max chars in print queue */ - unsigned short digi_bufsize; /* Buffer size */ - unsigned char digi_onlen; /* Length of ON string */ - unsigned char digi_offlen; /* Length of OFF string */ - char digi_onstr[DIGI_PLEN]; /* Printer on string */ - char digi_offstr[DIGI_PLEN]; /* Printer off string */ - char digi_term[DIGI_TSIZ]; /* terminal string */ -}; - -/************************************************************************ - * KME definitions and structures. - ************************************************************************/ -#define RW_IDLE 0 /* Operation complete */ -#define RW_READ 1 /* Read Concentrator Memory */ -#define RW_WRITE 2 /* Write Concentrator Memory */ - -struct rw_t { - unsigned char rw_req; /* Request type */ - unsigned char rw_board; /* Host Adapter board number */ - unsigned char rw_conc; /* Concentrator number */ - unsigned char rw_reserved; /* Reserved for expansion */ - unsigned long rw_addr; /* Address in concentrator */ - unsigned short rw_size; /* Read/write request length */ - unsigned char rw_data[128]; /* Data to read/write */ -}; - -/*********************************************************************** - * Shrink Buffer and Board Information definitions and structures. - - ************************************************************************/ - /* Board type return codes */ -#define PCXI_TYPE 1 /* Board type at the designated port is a PC/Xi */ -#define PCXM_TYPE 2 /* Board type at the designated port is a PC/Xm */ -#define PCXE_TYPE 3 /* Board type at the designated port is a PC/Xe */ -#define MCXI_TYPE 4 /* Board type at the designated port is a MC/Xi */ -#define COMXI_TYPE 5 /* Board type at the designated port is a COM/Xi */ - - /* Non-Zero Result codes. */ -#define RESULT_NOBDFND 1 /* A Digi product at that port is not config installed */ -#define RESULT_NODESCT 2 /* A memory descriptor was not obtainable */ -#define RESULT_NOOSSIG 3 /* FEP/OS signature was not detected on the board */ -#define RESULT_TOOSML 4 /* Too small an area to shrink. */ -#define RESULT_NOCHAN 5 /* Channel structure for the board was not found */ - -struct shrink_buf_struct { - unsigned long shrink_buf_vaddr; /* Virtual address of board */ - unsigned long shrink_buf_phys; /* Physical address of board */ - unsigned long shrink_buf_bseg; /* Amount of board memory */ - unsigned long shrink_buf_hseg; /* '186 Beginning of Dual-Port */ - - unsigned long shrink_buf_lseg; /* '186 Beginning of freed memory */ - unsigned long shrink_buf_mseg; /* Linear address from start of - dual-port were freed memory - begins, host viewpoint. */ - - unsigned long shrink_buf_bdparam; /* Parameter for xxmemon and - xxmemoff */ - - unsigned long shrink_buf_reserva; /* Reserved */ - unsigned long shrink_buf_reservb; /* Reserved */ - unsigned long shrink_buf_reservc; /* Reserved */ - unsigned long shrink_buf_reservd; /* Reserved */ - - unsigned char shrink_buf_result; /* Reason for call failing - Zero is Good return */ - unsigned char shrink_buf_init; /* Non-Zero if it caused an - xxinit call. */ - - unsigned char shrink_buf_anports; /* Number of async ports */ - unsigned char shrink_buf_snports; /* Number of sync ports */ - unsigned char shrink_buf_type; /* Board type 1 = PC/Xi, - 2 = PC/Xm, - 3 = PC/Xe - 4 = MC/Xi - 5 = COMX/i */ - unsigned char shrink_buf_card; /* Card number */ - -}; - -/************************************************************************ - * Structure to get driver status information - ************************************************************************/ -struct digi_dinfo { - unsigned long dinfo_nboards; /* # boards configured */ - char dinfo_reserved[12]; /* for future expansion */ - char dinfo_version[16]; /* driver version */ -}; - -#define DIGI_GETDD ('d'<<8) | 248 /* get driver info */ - -/************************************************************************ - * Structure used with ioctl commands for per-board information - * - * physsize and memsize differ when board has "windowed" memory - ************************************************************************/ -struct digi_info { - unsigned long info_bdnum; /* Board number (0 based) */ - unsigned long info_ioport; /* io port address */ - unsigned long info_physaddr; /* memory address */ - unsigned long info_physsize; /* Size of host mem window */ - unsigned long info_memsize; /* Amount of dual-port mem */ - /* on board */ - unsigned short info_bdtype; /* Board type */ - unsigned short info_nports; /* number of ports */ - char info_bdstate; /* board state */ - char info_reserved[7]; /* for future expansion */ -}; - -#define DIGI_GETBD ('d'<<8) | 249 /* get board info */ - -struct digi_stat { - unsigned int info_chan; /* Channel number (0 based) */ - unsigned int info_brd; /* Board number (0 based) */ - unsigned long info_cflag; /* cflag for channel */ - unsigned long info_iflag; /* iflag for channel */ - unsigned long info_oflag; /* oflag for channel */ - unsigned long info_mstat; /* mstat for channel */ - unsigned long info_tx_data; /* tx_data for channel */ - unsigned long info_rx_data; /* rx_data for channel */ - unsigned long info_hflow; /* hflow for channel */ - unsigned long info_reserved[8]; /* for future expansion */ -}; - -#define DIGI_GETSTAT ('d'<<8) | 244 /* get board info */ -/************************************************************************ - * - * Structure used with ioctl commands for per-channel information - * - ************************************************************************/ -struct digi_ch { - unsigned long info_bdnum; /* Board number (0 based) */ - unsigned long info_channel; /* Channel index number */ - unsigned long info_ch_cflag; /* Channel cflag */ - unsigned long info_ch_iflag; /* Channel iflag */ - unsigned long info_ch_oflag; /* Channel oflag */ - unsigned long info_chsize; /* Channel structure size */ - unsigned long info_sleep_stat; /* sleep status */ - dev_t info_dev; /* device number */ - unsigned char info_initstate; /* Channel init state */ - unsigned char info_running; /* Channel running state */ - long reserved[8]; /* reserved for future use */ -}; - -/* -* This structure is used with the DIGI_FEPCMD ioctl to -* tell the driver which port to send the command for. -*/ -struct digi_cmd { - int cmd; - int word; - int ncmds; - int chan; /* channel index (zero based) */ - int bdid; /* board index (zero based) */ -}; - -/* -* info_sleep_stat defines -*/ -#define INFO_RUNWAIT 0x0001 -#define INFO_WOPEN 0x0002 -#define INFO_TTIOW 0x0004 -#define INFO_CH_RWAIT 0x0008 -#define INFO_CH_WEMPTY 0x0010 -#define INFO_CH_WLOW 0x0020 -#define INFO_XXBUF_BUSY 0x0040 - -#define DIGI_GETCH ('d'<<8) | 245 /* get board info */ - -/* Board type definitions */ - -#define SUBTYPE 0007 -#define T_PCXI 0000 -#define T_PCXM 0001 -#define T_PCXE 0002 -#define T_PCXR 0003 -#define T_SP 0004 -#define T_SP_PLUS 0005 -# define T_HERC 0000 -# define T_HOU 0001 -# define T_LON 0002 -# define T_CHA 0003 -#define FAMILY 0070 -#define T_COMXI 0000 -#define T_PCXX 0010 -#define T_CX 0020 -#define T_EPC 0030 -#define T_PCLITE 0040 -#define T_SPXX 0050 -#define T_AVXX 0060 -#define T_DXB 0070 -#define T_A2K_4_8 0070 -#define BUSTYPE 0700 -#define T_ISABUS 0000 -#define T_MCBUS 0100 -#define T_EISABUS 0200 -#define T_PCIBUS 0400 - -/* Board State Definitions */ - -#define BD_RUNNING 0x0 -#define BD_REASON 0x7f -#define BD_NOTFOUND 0x1 -#define BD_NOIOPORT 0x2 -#define BD_NOMEM 0x3 -#define BD_NOBIOS 0x4 -#define BD_NOFEP 0x5 -#define BD_FAILED 0x6 -#define BD_ALLOCATED 0x7 -#define BD_TRIBOOT 0x8 -#define BD_BADKME 0x80 - -#define DIGI_LOOPBACK ('d'<<8) | 252 /* Enable/disable UART internal loopback */ -#define DIGI_SPOLL ('d'<<8) | 254 /* change poller rate */ - -#define DIGI_SETCUSTOMBAUD _IOW('e', 106, int) /* Set integer baud rate */ -#define DIGI_GETCUSTOMBAUD _IOR('e', 107, int) /* Get integer baud rate */ -#define DIGI_RESET_PORT ('e'<<8) | 93 /* Reset port */ - -#endif /* DIGI_H */ diff --git a/drivers/staging/dgap/downld.c b/drivers/staging/dgap/downld.c deleted file mode 100644 index 1f4aa2eca43..00000000000 --- a/drivers/staging/dgap/downld.c +++ /dev/null @@ -1,798 +0,0 @@ -/* - * Copyright 2003 Digi International (www.digi.com) - * Scott H Kilau <Scott_Kilau at digi dot com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the - * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * $Id: downld.c,v 1.6 2009/01/14 14:10:54 markh Exp $ - */ - -/* -** downld.c -** -** This is the daemon that sends the fep, bios, and concentrator images -** from user space to the driver. -** BUGS: -** If the file changes in the middle of the download, you probably -** will get what you deserve. -** -*/ - -#include <stdlib.h> -#include <stdio.h> -#include <fcntl.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <sys/errno.h> - -#include "dgap_types.h" -#include "digi.h" -#include "dgap_fep5.h" - -#include "dgap_downld.h" - -#include <string.h> -#include <malloc.h> -#include <stddef.h> -#include <unistd.h> - -char *pgm; -void myperror(); - -/* -** This structure is used to keep track of the different images available -** to give to the driver. It is arranged so that the things that are -** constants or that have defaults are first inthe strucutre to simplify -** the table of initializers. -*/ -struct image_info { - short type; /* bios, fep, conc */ - short family; /* boards this applies to */ - short subtype; /* subtype */ - int len; /* size of image */ - char *image; /* ioctl struct + image */ - char *name; - char *fname; /* filename of binary (i.e. "asfep.bin") */ - char *pathname; /* pathname to this binary ("/etc/dgap/xrfep.bin"); */ - time_t mtime; /* Last modification time */ -}; - -#define IBIOS 0 -#define IFEP 1 -#define ICONC 2 -#define ICONFIG 3 -#define IBAD 4 - -#define DEFAULT_LOC "/lib/firmware/dgap/" - -struct image_info *image_list; -int nimages, count; - -struct image_info images[] = { -{IBIOS, T_EPC, SUBTYPE, 0, NULL, "EPC/X", "fxbios.bin", DEFAULT_LOC "fxbios.bin", 0 }, -{IFEP, T_EPC, SUBTYPE, 0, NULL, "EPC/X", "fxfep.bin", DEFAULT_LOC "fxfep.bin", 0 }, -{ICONC, T_EPC, SUBTYPE, 0, NULL, "EPC/X", "fxcon.bin", DEFAULT_LOC "fxcon.bin", 0 }, - -{IBIOS, T_CX, SUBTYPE, 0, NULL, "C/X", "cxbios.bin", DEFAULT_LOC "cxbios.bin", 0 }, -{IFEP, T_CX, SUBTYPE, 0, NULL, "C/X", "cxhost.bin", DEFAULT_LOC "cxhost.bin", 0 }, - -{IBIOS, T_CX, T_PCIBUS, 0, NULL, "C/X PCI", "cxpbios.bin", DEFAULT_LOC "cxpbios.bin", 0 }, -{IFEP, T_CX, T_PCIBUS, 0, NULL, "C/X PCI", "cxpfep.bin", DEFAULT_LOC "cxpfep.bin", 0 }, - -{ICONC, T_CX, SUBTYPE, 0, NULL, "C/X", "cxcon.bin", DEFAULT_LOC "cxcon.bin", 0 }, -{ICONC, T_CX, SUBTYPE, 0, NULL, "C/X", "ibmcxcon.bin", DEFAULT_LOC "ibmcxcon.bin", 0 }, -{ICONC, T_CX, SUBTYPE, 0, NULL, "C/X", "ibmencon.bin", DEFAULT_LOC "ibmencon.bin", 0 }, - -{IBIOS, FAMILY, T_PCXR, 0, NULL, "PCXR", "xrbios.bin", DEFAULT_LOC "xrbios.bin", 0 }, -{IFEP, FAMILY, T_PCXR, 0, NULL, "PCXR", "xrfep.bin", DEFAULT_LOC "xrfep.bin", 0 }, - -{IBIOS, T_PCLITE, SUBTYPE, 0, NULL, "X/em", "sxbios.bin", DEFAULT_LOC "sxbios.bin", 0 }, -{IFEP, T_PCLITE, SUBTYPE, 0, NULL, "X/em", "sxfep.bin", DEFAULT_LOC "sxfep.bin", 0 }, - -{IBIOS, T_EPC, T_PCIBUS, 0, NULL, "PCI", "pcibios.bin", DEFAULT_LOC "pcibios.bin", 0 }, -{IFEP, T_EPC, T_PCIBUS, 0, NULL, "PCI", "pcifep.bin", DEFAULT_LOC "pcifep.bin", 0 }, -{ICONFIG, 0, 0, 0, NULL, NULL, "dgap.conf", "/etc/dgap.conf", 0 }, - -/* IBAD/NULL entry indicating end-of-table */ - -{IBAD, 0, 0, 0, NULL, NULL, NULL, NULL, 0 } - -} ; - -int errorprint = 1; -int nodldprint = 1; -int debugflag; -int fd; - -struct downld_t *ip; /* Image pointer in current image */ -struct downld_t *dp; /* conc. download */ - - -/* - * The same for either the FEP or the BIOS. - * Append the downldio header, issue the ioctl, then free - * the buffer. Not horribly CPU efficient, but quite RAM efficient. - */ - -void squirt(int req_type, int bdid, struct image_info *ii) -{ - struct downldio *dliop; - int size_buf; - int sfd; - struct stat sb; - - /* - * If this binary comes from a file, stat it to see how - * large it is. Yes, we intentionally do this each - * time for the binary may change between loads. - */ - - if (ii->pathname) { - sfd = open(ii->pathname, O_RDONLY); - - if (sfd < 0 ) { - myperror(ii->pathname); - goto squirt_end; - } - - if (fstat(sfd, &sb) == -1 ) { - myperror(ii->pathname); - goto squirt_end; - } - - ii->len = sb.st_size; - } - - size_buf = ii->len + sizeof(struct downldio); - - /* - * This buffer will be freed at the end of this function. It is - * not resilient and should be around only long enough for the d/l - * to happen. - */ - dliop = (struct downldio *) malloc(size_buf); - - if (dliop == NULL) { - fprintf(stderr,"%s: can't get %d bytes of memory; aborting\n", - pgm, size_buf); - exit (1); - } - - /* Now, stick the image in fepimage. This can come from either - * the compiled-in image or from the filesystem. - */ - if (ii->pathname) - read(sfd, dliop->image.fi.fepimage, ii->len); - else - memcpy(dliop ->image.fi.fepimage, ii->image, ii->len); - - dliop->req_type = req_type; - dliop->bdid = bdid; - - dliop->image.fi.len = ii->len; - - if (debugflag) - printf("sending %d bytes of %s %s from %s\n", - ii->len, - (ii->type == IFEP) ? "FEP" : (ii->type == IBIOS) ? "BIOS" : "CONFIG", - ii->name ? ii->name : "", - (ii->pathname) ? ii->pathname : "internal image" ); - - if (ioctl(fd, DIGI_DLREQ_SET, (char *) dliop) == -1) { - if(errorprint) { - fprintf(stderr, - "%s: warning - download ioctl failed\n",pgm); - errorprint = 0; - } - sleep(2); - } - -squirt_end: - - if (ii->pathname) { - close(sfd); - } - free(dliop); -} - - -/* - * See if we need to reload the download image in core - * - */ -void consider_file_rescan(struct image_info *ii) -{ - int sfd; - int len; - struct stat sb; - - /* This operation only makes sense when we're working from a file */ - - if (ii->pathname) { - - sfd = open (ii->pathname, O_RDONLY) ; - if (sfd < 0 ) { - myperror(ii->pathname); - exit(1) ; - } - - if( fstat(sfd,&sb) == -1 ) { - myperror(ii->pathname); - exit(1); - } - - /* If the file hasn't changed since we last did this, - * and we have not done a free() on the image, bail - */ - if (ii->image && (sb.st_mtime == ii->mtime)) - goto end_rescan; - - ii->len = len = sb.st_size; - - /* Record the timestamp of the file */ - ii->mtime = sb.st_mtime; - - /* image should be NULL unless there is an image malloced - * in already. Before we malloc again, make sure we don't - * have a memory leak. - */ - if ( ii->image ) { - free( ii->image ); - /* ii->image = NULL; */ /* not necessary */ - } - - /* This image will be kept only long enough for the - * download to happen. After sending the last block, - * it will be freed - */ - ii->image = malloc(len) ; - - if (ii->image == NULL) { - fprintf(stderr, - "%s: can't get %d bytes of memory; aborting\n", - pgm, len); - exit (1); - } - - if (read(sfd, ii->image, len) < len) { - fprintf(stderr,"%s: read error on %s; aborting\n", - pgm, ii->pathname); - exit (1); - } - -end_rescan: - close(sfd); - - } -} - -/* - * Scan for images to match the driver requests - */ - -struct image_info * find_conc_image() -{ - int x; - struct image_info *i = NULL; - - for ( x = 0; x < nimages; x++ ) { - i=&image_list[x]; - - if(i->type != ICONC) - continue; - - consider_file_rescan(i) ; - - ip = (struct downld_t *) image_list[x].image; - if (ip == NULL) continue; - - /* - * When I removed Clusterport, I kept only the code that I - * was SURE wasn't ClusterPort. We may not need the next two - * lines of code. - */ - if ((dp->dl_type != 'P' ) && ( ip->dl_srev == dp->dl_srev )) - return i; - } - return NULL; -} - - -int main(int argc, char **argv) -{ - struct downldio dlio; - int offset, bsize; - int x; - char *down, *image, *fname; - struct image_info *ii; - - pgm = argv[0]; - dp = &dlio.image.dl; /* conc. download */ - - while((argc > 2) && !strcmp(argv[1],"-d")) { - debugflag++ ; - argc-- ; - argv++ ; - } - - if(argc < 2) { - fprintf(stderr, - "usage: %s download-device [image-file] ...\n", - pgm); - exit(1); - } - - - - /* - * Daemonize, unless debugging is turned on. - */ - if (debugflag == 0) { - switch (fork()) - { - case 0: - break; - - case -1: - return 1; - - default: - return 0; - } - - setsid(); - - /* - * The child no longer needs "stdin", "stdout", or "stderr", - * and should not block processes waiting for them to close. - */ - fclose(stdin); - fclose(stdout); - fclose(stderr); - - } - - while (1) { - if( (fd = open(argv[1], O_RDWR)) == -1 ) { - sleep(1); - } - else - break; - } - - /* - ** create a list of images to search through when trying to match - ** requests from the driver. Put images from the command line in - ** the list before built in images so that the command line images - ** can override the built in ones. - */ - - /* allocate space for the list */ - - nimages = argc - 2; - - /* count the number of default list entries */ - - for (count = 0; images[count].type != IBAD; ++count) ; - - nimages += count; - - /* Really should just remove the variable "image_list".... robertl */ - image_list = images; - - /* get the images from the command line */ - for(x = 2; x < argc; x++) { - int xx; - - /* - * strip off any leading path information for - * determining file type - */ - if( (fname = strrchr(argv[x],'/')) == NULL) - fname = argv[x]; - else - fname++; /* skip the slash */ - - for (xx = 0; xx < count; xx++) { - if (strcmp(fname, images[xx].fname) == 0 ) { - images[xx].pathname = argv[x]; - - /* image should be NULL until */ - /* space is malloced */ - images[xx].image = NULL; - } - } - } - - sleep(3); - - /* - ** Endless loop: get a request from the fep, and service that request. - */ - for(;;) { - /* get the request */ - if (debugflag) - printf("b4 get ioctl..."); - - if (ioctl(fd,DIGI_DLREQ_GET, &dlio) == -1 ) { - if (errorprint) { - fprintf(stderr, - "%s: warning - download ioctl failed\n", - pgm); - errorprint = 0; - } - sleep(2); - } else { - if (debugflag) - printf("dlio.req_type is %d bd %d\n", - dlio.req_type,dlio.bdid); - - switch(dlio.req_type) { - case DLREQ_BIOS: - /* - ** find the bios image for this type - */ - for ( x = 0; x < nimages; x++ ) { - if(image_list[x].type != IBIOS) - continue; - - if ((dlio.image.fi.type & FAMILY) == - image_list[x].family) { - - if ( image_list[x].family == T_CX ) { - if ((dlio.image.fi.type & BUSTYPE) - == T_PCIBUS ) { - if ( image_list[x].subtype - == T_PCIBUS ) - break; - } - else { - break; - } - } - else if ( image_list[x].family == T_EPC ) { - /* If subtype of image is T_PCIBUS, it is */ - /* a PCI EPC image, so the board must */ - /* have bus type T_PCIBUS to match */ - if ((dlio.image.fi.type & BUSTYPE) - == T_PCIBUS ) { - if ( image_list[x].subtype - == T_PCIBUS ) - break; - } - else { - /* NON PCI EPC doesn't use PCI image */ - if ( image_list[x].subtype - != T_PCIBUS ) - break; - } - } - else - break; - } - else if ((dlio.image.fi.type & SUBTYPE) == image_list[x].subtype) { - /* PCXR board will break out of the loop here */ - if ( image_list[x].subtype == T_PCXR ) { - break; - } - } - } - - if ( x >= nimages) { - /* - ** no valid images exist - */ - if(nodldprint) { - fprintf(stderr, - "%s: cannot find correct BIOS image\n", - pgm); - nodldprint = 0; - } - dlio.image.fi.type = -1; - if (ioctl(fd, DIGI_DLREQ_SET, &dlio) == -1) { - if (errorprint) { - fprintf(stderr, - "%s: warning - download ioctl failed\n", - pgm); - errorprint = 0; - } - sleep(2); - } - break; - } - squirt(dlio.req_type, dlio.bdid, &image_list[x]); - break ; - - case DLREQ_FEP: - /* - ** find the fep image for this type - */ - for ( x = 0; x < nimages; x++ ) { - if(image_list[x].type != IFEP) - continue; - if( (dlio.image.fi.type & FAMILY) == - image_list[x].family ) { - if ( image_list[x].family == T_CX ) { - /* C/X PCI board */ - if ((dlio.image.fi.type & BUSTYPE) - == T_PCIBUS ) { - if ( image_list[x].subtype - == T_PCIBUS ) - break; - } - else { - /* Regular CX */ - break; - } - } - else if ( image_list[x].family == T_EPC ) { - /* If subtype of image is T_PCIBUS, it is */ - /* a PCI EPC image, so the board must */ - /* have bus type T_PCIBUS to match */ - if ((dlio.image.fi.type & BUSTYPE) - == T_PCIBUS ) { - if ( image_list[x].subtype - == T_PCIBUS ) - break; - } - else { - /* NON PCI EPC doesn't use PCI image */ - if ( image_list[x].subtype - != T_PCIBUS ) - break; - } - } - else - break; - } - else if ((dlio.image.fi.type & SUBTYPE) == image_list[x].subtype) { - /* PCXR board will break out of the loop here */ - if ( image_list[x].subtype == T_PCXR ) { - break; - } - } - } - - if ( x >= nimages) { - /* - ** no valid images exist - */ - if(nodldprint) { - fprintf(stderr, - "%s: cannot find correct FEP image\n", - pgm); - nodldprint = 0; - } - dlio.image.fi.type=-1; - if( ioctl(fd,DIGI_DLREQ_SET,&dlio) == -1 ) { - if(errorprint) { - fprintf(stderr, - "%s: warning - download ioctl failed\n", - pgm); - errorprint=0; - } - sleep(2); - } - break; - } - squirt(dlio.req_type, dlio.bdid, &image_list[x]); - break; - - case DLREQ_DEVCREATE: - { - char string[1024]; -#if 0 - sprintf(string, "%s /proc/dgap/%d/mknod", DEFSHELL, dlio.bdid); -#endif - sprintf(string, "%s /usr/sbin/dgap_updatedevs %d", DEFSHELL, dlio.bdid); - system(string); - - if (debugflag) - printf("Created Devices.\n"); - if (ioctl(fd, DIGI_DLREQ_SET, &dlio) == -1 ) { - if(errorprint) { - fprintf(stderr, "%s: warning - DEVCREATE ioctl failed\n",pgm); - errorprint = 0; - } - sleep(2); - } - if (debugflag) - printf("After ioctl set - Created Device.\n"); - } - - break; - - case DLREQ_CONFIG: - for ( x = 0; x < nimages; x++ ) { - if(image_list[x].type != ICONFIG) - continue; - else - break; - } - - if ( x >= nimages) { - /* - ** no valid images exist - */ - if(nodldprint) { - fprintf(stderr, - "%s: cannot find correct CONFIG image\n", - pgm); - nodldprint = 0; - } - dlio.image.fi.type=-1; - if (ioctl(fd, DIGI_DLREQ_SET, &dlio) == -1 ) { - if(errorprint) { - fprintf(stderr, - "%s: warning - download ioctl failed\n", - pgm); - errorprint=0; - } - sleep(2); - } - break; - } - - squirt(dlio.req_type, dlio.bdid, &image_list[x]); - break; - - case DLREQ_CONC: - /* - ** find the image needed for this download - */ - if ( dp->dl_seq == 0 ) { - /* - ** find image for hardware rev range - */ - for ( x = 0; x < nimages; x++ ) { - ii=&image_list[x]; - - if(image_list[x].type != ICONC) - continue; - - consider_file_rescan(ii) ; - - ip = (struct downld_t *) image_list[x].image; - if (ip == NULL) continue; - - /* - * When I removed Clusterport, I kept only the - * code that I was SURE wasn't ClusterPort. - * We may not need the next four lines of code. - */ - - if ((dp->dl_type != 'P' ) && - (ip->dl_lrev <= dp->dl_lrev ) && - ( dp->dl_lrev <= ip->dl_hrev)) - break; - } - - if ( x >= nimages ) { - /* - ** No valid images exist - */ - if(nodldprint) { - fprintf(stderr, - "%s: cannot find correct download image %d\n", - pgm, dp->dl_lrev); - nodldprint=0; - } - continue; - } - - } else { - /* - ** find image version required - */ - if ((ii = find_conc_image()) == NULL ) { - /* - ** No valid images exist - */ - fprintf(stderr, - "%s: can't find rest of download image??\n", - pgm); - continue; - } - } - - /* - ** download block of image - */ - - offset = 1024 * dp->dl_seq; - - /* - ** test if block requested within image - */ - if ( offset < ii->len ) { - - /* - ** if it is, determine block size, set segment, - ** set size, set pointers, and copy block - */ - if (( bsize = ii->len - offset ) > 1024 ) - bsize = 1024; - - /* - ** copy image version info to download area - */ - dp->dl_srev = ip->dl_srev; - dp->dl_lrev = ip->dl_lrev; - dp->dl_hrev = ip->dl_hrev; - - dp->dl_seg = (64 * dp->dl_seq) + ip->dl_seg; - dp->dl_size = bsize; - - down = (char *)&dp->dl_data[0]; - image = (char *)((char *)ip + offset); - - memcpy(down, image, bsize); - } - else { - /* - ** Image has been downloaded, set segment and - ** size to indicate no more blocks - */ - dp->dl_seg = ip->dl_seg; - dp->dl_size = 0; - - /* Now, we can release the concentrator */ - /* image from memory if we're running */ - /* from filesystem images */ - - if (ii->pathname) - if (ii->image) { - free(ii->image); - ii->image = NULL; - } - } - - if (debugflag) - printf( - "sending conc dl section %d to %s from %s\n", - dp->dl_seq, ii->name, - ii->pathname ? ii->pathname : "Internal Image"); - - if (ioctl(fd, DIGI_DLREQ_SET, &dlio) == -1 ) { - if (errorprint) { - fprintf(stderr, - "%s: warning - download ioctl failed\n", - pgm); - errorprint=0; - } - sleep(2); - } - break; - } /* switch */ - } - if (debugflag > 1) { - printf("pausing: "); fflush(stdout); - fflush(stdin); - while(getchar() != '\n'); - printf("continuing\n"); - } - } -} - -/* -** myperror() -** -** Same as normal perror(), but places the program name at the beginning -** of the message. -*/ -void myperror(char *s) -{ - fprintf(stderr,"%s: %s: %s.\n",pgm, s, strerror(errno)); -} diff --git a/drivers/staging/echo/TODO b/drivers/staging/echo/TODO deleted file mode 100644 index 72a311a5a9c..00000000000 --- a/drivers/staging/echo/TODO +++ /dev/null @@ -1,5 +0,0 @@ -TODO: - - send to lkml for review - -Please send patches to Greg Kroah-Hartman <greg@kroah.com> and Cc: Steve -Underwood <steveu@coppice.org> and David Rowe <david@rowetel.com> diff --git a/drivers/staging/iio/adc/mxs-lradc.c b/drivers/staging/iio/adc/mxs-lradc.c index ab3c0d4ba68..25bea0556c1 100644 --- a/drivers/staging/iio/adc/mxs-lradc.c +++ b/drivers/staging/iio/adc/mxs-lradc.c @@ -757,6 +757,7 @@ static void mxs_lradc_finish_touch_event(struct mxs_lradc *lradc, bool valid) } /* if it is released, wait for the next touch via IRQ */ + lradc->cur_plate = LRADC_TOUCH; mxs_lradc_reg_clear(lradc, LRADC_CTRL1_TOUCH_DETECT_IRQ, LRADC_CTRL1); mxs_lradc_reg_set(lradc, LRADC_CTRL1_TOUCH_DETECT_IRQ_EN, LRADC_CTRL1); } diff --git a/drivers/staging/imx-drm/Kconfig b/drivers/staging/imx-drm/Kconfig index 78319ad176c..c6e8ba7b3e4 100644 --- a/drivers/staging/imx-drm/Kconfig +++ b/drivers/staging/imx-drm/Kconfig @@ -20,6 +20,7 @@ config DRM_IMX_FB_HELPER config DRM_IMX_PARALLEL_DISPLAY tristate "Support for parallel displays" + select DRM_PANEL depends on DRM_IMX select VIDEOMODE_HELPERS diff --git a/drivers/staging/imx-drm/Makefile b/drivers/staging/imx-drm/Makefile index 4677585b5ad..129e3a3f59f 100644 --- a/drivers/staging/imx-drm/Makefile +++ b/drivers/staging/imx-drm/Makefile @@ -1,12 +1,11 @@ -imxdrm-objs := imx-drm-core.o imx-fb.o +imxdrm-objs := imx-drm-core.o obj-$(CONFIG_DRM_IMX) += imxdrm.o obj-$(CONFIG_DRM_IMX_PARALLEL_DISPLAY) += parallel-display.o obj-$(CONFIG_DRM_IMX_TVE) += imx-tve.o obj-$(CONFIG_DRM_IMX_LDB) += imx-ldb.o -obj-$(CONFIG_DRM_IMX_FB_HELPER) += imx-fbdev.o obj-$(CONFIG_DRM_IMX_IPUV3_CORE) += ipu-v3/ imx-ipuv3-crtc-objs := ipuv3-crtc.o ipuv3-plane.o diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c index 236ed66f116..6b91c8e6717 100644 --- a/drivers/staging/imx-drm/imx-drm-core.c +++ b/drivers/staging/imx-drm/imx-drm-core.c @@ -13,14 +13,14 @@ * GNU General Public License for more details. * */ - +#include <linux/component.h> #include <linux/device.h> +#include <linux/fb.h> +#include <linux/module.h> #include <linux/platform_device.h> #include <drm/drmP.h> #include <drm/drm_fb_helper.h> #include <drm/drm_crtc_helper.h> -#include <linux/fb.h> -#include <linux/module.h> #include <drm/drm_gem_cma_helper.h> #include <drm/drm_fb_cma_helper.h> @@ -28,45 +28,26 @@ #define MAX_CRTC 4 -struct crtc_cookie { - void *cookie; - int id; - struct list_head list; -}; +struct imx_drm_crtc; struct imx_drm_device { struct drm_device *drm; - struct device *dev; - struct list_head crtc_list; - struct list_head encoder_list; - struct list_head connector_list; - struct mutex mutex; + struct imx_drm_crtc *crtc[MAX_CRTC]; int pipes; struct drm_fbdev_cma *fbhelper; }; struct imx_drm_crtc { struct drm_crtc *crtc; - struct list_head list; - struct imx_drm_device *imxdrm; int pipe; struct imx_drm_crtc_helper_funcs imx_drm_helper_funcs; - struct module *owner; - struct crtc_cookie cookie; -}; - -struct imx_drm_encoder { - struct drm_encoder *encoder; - struct list_head list; - struct module *owner; - struct list_head possible_crtcs; + void *cookie; + int id; + int mux_id; }; -struct imx_drm_connector { - struct drm_connector *connector; - struct list_head list; - struct module *owner; -}; +static int legacyfb_depth = 16; +module_param(legacyfb_depth, int, 0444); int imx_drm_crtc_id(struct imx_drm_crtc *crtc) { @@ -76,69 +57,71 @@ EXPORT_SYMBOL_GPL(imx_drm_crtc_id); static void imx_drm_driver_lastclose(struct drm_device *drm) { +#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER) struct imx_drm_device *imxdrm = drm->dev_private; if (imxdrm->fbhelper) drm_fbdev_cma_restore_mode(imxdrm->fbhelper); +#endif } static int imx_drm_driver_unload(struct drm_device *drm) { +#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER) struct imx_drm_device *imxdrm = drm->dev_private; +#endif - imx_drm_device_put(); + drm_kms_helper_poll_fini(drm); + +#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER) + if (imxdrm->fbhelper) + drm_fbdev_cma_fini(imxdrm->fbhelper); +#endif + + component_unbind_all(drm->dev, drm); drm_vblank_cleanup(drm); - drm_kms_helper_poll_fini(drm); drm_mode_config_cleanup(drm); return 0; } -/* - * We don't care at all for crtc numbers, but the core expects the - * crtcs to be numbered - */ -static struct imx_drm_crtc *imx_drm_crtc_by_num(struct imx_drm_device *imxdrm, - int num) +static struct imx_drm_crtc *imx_drm_find_crtc(struct drm_crtc *crtc) { - struct imx_drm_crtc *imx_drm_crtc; + struct imx_drm_device *imxdrm = crtc->dev->dev_private; + unsigned i; + + for (i = 0; i < MAX_CRTC; i++) + if (imxdrm->crtc[i] && imxdrm->crtc[i]->crtc == crtc) + return imxdrm->crtc[i]; - list_for_each_entry(imx_drm_crtc, &imxdrm->crtc_list, list) - if (imx_drm_crtc->pipe == num) - return imx_drm_crtc; return NULL; } -int imx_drm_crtc_panel_format_pins(struct drm_crtc *crtc, u32 encoder_type, +int imx_drm_panel_format_pins(struct drm_encoder *encoder, u32 interface_pix_fmt, int hsync_pin, int vsync_pin) { - struct imx_drm_device *imxdrm = crtc->dev->dev_private; - struct imx_drm_crtc *imx_crtc; struct imx_drm_crtc_helper_funcs *helper; + struct imx_drm_crtc *imx_crtc; - list_for_each_entry(imx_crtc, &imxdrm->crtc_list, list) - if (imx_crtc->crtc == crtc) - goto found; + imx_crtc = imx_drm_find_crtc(encoder->crtc); + if (!imx_crtc) + return -EINVAL; - return -EINVAL; -found: helper = &imx_crtc->imx_drm_helper_funcs; if (helper->set_interface_pix_fmt) - return helper->set_interface_pix_fmt(crtc, - encoder_type, interface_pix_fmt, + return helper->set_interface_pix_fmt(encoder->crtc, + encoder->encoder_type, interface_pix_fmt, hsync_pin, vsync_pin); return 0; } -EXPORT_SYMBOL_GPL(imx_drm_crtc_panel_format_pins); +EXPORT_SYMBOL_GPL(imx_drm_panel_format_pins); -int imx_drm_crtc_panel_format(struct drm_crtc *crtc, u32 encoder_type, - u32 interface_pix_fmt) +int imx_drm_panel_format(struct drm_encoder *encoder, u32 interface_pix_fmt) { - return imx_drm_crtc_panel_format_pins(crtc, encoder_type, - interface_pix_fmt, 2, 3); + return imx_drm_panel_format_pins(encoder, interface_pix_fmt, 2, 3); } -EXPORT_SYMBOL_GPL(imx_drm_crtc_panel_format); +EXPORT_SYMBOL_GPL(imx_drm_panel_format); int imx_drm_crtc_vblank_get(struct imx_drm_crtc *imx_drm_crtc) { @@ -161,10 +144,9 @@ EXPORT_SYMBOL_GPL(imx_drm_handle_vblank); static int imx_drm_enable_vblank(struct drm_device *drm, int crtc) { struct imx_drm_device *imxdrm = drm->dev_private; - struct imx_drm_crtc *imx_drm_crtc; + struct imx_drm_crtc *imx_drm_crtc = imxdrm->crtc[crtc]; int ret; - imx_drm_crtc = imx_drm_crtc_by_num(imxdrm, crtc); if (!imx_drm_crtc) return -EINVAL; @@ -180,9 +162,8 @@ static int imx_drm_enable_vblank(struct drm_device *drm, int crtc) static void imx_drm_disable_vblank(struct drm_device *drm, int crtc) { struct imx_drm_device *imxdrm = drm->dev_private; - struct imx_drm_crtc *imx_drm_crtc; + struct imx_drm_crtc *imx_drm_crtc = imxdrm->crtc[crtc]; - imx_drm_crtc = imx_drm_crtc_by_num(imxdrm, crtc); if (!imx_drm_crtc) return; @@ -215,172 +196,54 @@ static const struct file_operations imx_drm_driver_fops = { .llseek = noop_llseek, }; -static struct imx_drm_device *imx_drm_device; - -static struct imx_drm_device *__imx_drm_device(void) +int imx_drm_connector_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode) { - return imx_drm_device; + return MODE_OK; } +EXPORT_SYMBOL(imx_drm_connector_mode_valid); -struct drm_device *imx_drm_device_get(void) +void imx_drm_connector_destroy(struct drm_connector *connector) { - struct imx_drm_device *imxdrm = __imx_drm_device(); - struct imx_drm_encoder *enc; - struct imx_drm_connector *con; - struct imx_drm_crtc *crtc; - - list_for_each_entry(enc, &imxdrm->encoder_list, list) { - if (!try_module_get(enc->owner)) { - dev_err(imxdrm->dev, "could not get module %s\n", - module_name(enc->owner)); - goto unwind_enc; - } - } - - list_for_each_entry(con, &imxdrm->connector_list, list) { - if (!try_module_get(con->owner)) { - dev_err(imxdrm->dev, "could not get module %s\n", - module_name(con->owner)); - goto unwind_con; - } - } - - list_for_each_entry(crtc, &imxdrm->crtc_list, list) { - if (!try_module_get(crtc->owner)) { - dev_err(imxdrm->dev, "could not get module %s\n", - module_name(crtc->owner)); - goto unwind_crtc; - } - } - - return imxdrm->drm; - -unwind_crtc: - list_for_each_entry_continue_reverse(crtc, &imxdrm->crtc_list, list) - module_put(crtc->owner); -unwind_con: - list_for_each_entry_continue_reverse(con, &imxdrm->connector_list, list) - module_put(con->owner); -unwind_enc: - list_for_each_entry_continue_reverse(enc, &imxdrm->encoder_list, list) - module_put(enc->owner); - - mutex_unlock(&imxdrm->mutex); - - return NULL; - -} -EXPORT_SYMBOL_GPL(imx_drm_device_get); - -void imx_drm_device_put(void) -{ - struct imx_drm_device *imxdrm = __imx_drm_device(); - struct imx_drm_encoder *enc; - struct imx_drm_connector *con; - struct imx_drm_crtc *crtc; - - mutex_lock(&imxdrm->mutex); - - list_for_each_entry(crtc, &imxdrm->crtc_list, list) - module_put(crtc->owner); - - list_for_each_entry(con, &imxdrm->connector_list, list) - module_put(con->owner); - - list_for_each_entry(enc, &imxdrm->encoder_list, list) - module_put(enc->owner); - - mutex_unlock(&imxdrm->mutex); -} -EXPORT_SYMBOL_GPL(imx_drm_device_put); - -static int drm_mode_group_reinit(struct drm_device *dev) -{ - struct drm_mode_group *group = &dev->primary->mode_group; - uint32_t *id_list = group->id_list; - int ret; - - ret = drm_mode_group_init_legacy_group(dev, group); - if (ret < 0) - return ret; - - kfree(id_list); - return 0; + drm_sysfs_connector_remove(connector); + drm_connector_cleanup(connector); } +EXPORT_SYMBOL_GPL(imx_drm_connector_destroy); -/* - * register an encoder to the drm core - */ -static int imx_drm_encoder_register(struct imx_drm_encoder *imx_drm_encoder) +void imx_drm_encoder_destroy(struct drm_encoder *encoder) { - struct imx_drm_device *imxdrm = __imx_drm_device(); - - INIT_LIST_HEAD(&imx_drm_encoder->possible_crtcs); - - drm_encoder_init(imxdrm->drm, imx_drm_encoder->encoder, - imx_drm_encoder->encoder->funcs, - imx_drm_encoder->encoder->encoder_type); - - drm_mode_group_reinit(imxdrm->drm); - - return 0; + drm_encoder_cleanup(encoder); } +EXPORT_SYMBOL_GPL(imx_drm_encoder_destroy); -/* - * unregister an encoder from the drm core - */ -static void imx_drm_encoder_unregister(struct imx_drm_encoder - *imx_drm_encoder) +static void imx_drm_output_poll_changed(struct drm_device *drm) { - struct imx_drm_device *imxdrm = __imx_drm_device(); - - drm_encoder_cleanup(imx_drm_encoder->encoder); - - drm_mode_group_reinit(imxdrm->drm); -} - -/* - * register a connector to the drm core - */ -static int imx_drm_connector_register( - struct imx_drm_connector *imx_drm_connector) -{ - struct imx_drm_device *imxdrm = __imx_drm_device(); - - drm_connector_init(imxdrm->drm, imx_drm_connector->connector, - imx_drm_connector->connector->funcs, - imx_drm_connector->connector->connector_type); - drm_mode_group_reinit(imxdrm->drm); +#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER) + struct imx_drm_device *imxdrm = drm->dev_private; - return drm_sysfs_connector_add(imx_drm_connector->connector); + drm_fbdev_cma_hotplug_event(imxdrm->fbhelper); +#endif } -/* - * unregister a connector from the drm core - */ -static void imx_drm_connector_unregister( - struct imx_drm_connector *imx_drm_connector) -{ - struct imx_drm_device *imxdrm = __imx_drm_device(); - - drm_sysfs_connector_remove(imx_drm_connector->connector); - drm_connector_cleanup(imx_drm_connector->connector); - - drm_mode_group_reinit(imxdrm->drm); -} +static struct drm_mode_config_funcs imx_drm_mode_config_funcs = { + .fb_create = drm_fb_cma_create, + .output_poll_changed = imx_drm_output_poll_changed, +}; /* - * Called by the CRTC driver when all CRTCs are registered. This - * puts all the pieces together and initializes the driver. - * Once this is called no more CRTCs can be registered since - * the drm core has hardcoded the number of crtcs in several - * places. + * Main DRM initialisation. This binds, initialises and registers + * with DRM the subcomponents of the driver. */ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags) { - struct imx_drm_device *imxdrm = __imx_drm_device(); + struct imx_drm_device *imxdrm; + struct drm_connector *connector; int ret; + imxdrm = devm_kzalloc(drm->dev, sizeof(*imxdrm), GFP_KERNEL); + if (!imxdrm) + return -ENOMEM; + imxdrm->drm = drm; drm->dev_private = imxdrm; @@ -396,120 +259,123 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags) */ drm->irq_enabled = true; - drm_mode_config_init(drm); - imx_drm_mode_config_init(drm); - - mutex_lock(&imxdrm->mutex); - - drm_kms_helper_poll_init(drm); + /* + * set max width and height as default value(4096x4096). + * this value would be used to check framebuffer size limitation + * at drm_mode_addfb(). + */ + drm->mode_config.min_width = 64; + drm->mode_config.min_height = 64; + drm->mode_config.max_width = 4096; + drm->mode_config.max_height = 4096; + drm->mode_config.funcs = &imx_drm_mode_config_funcs; - /* setup the grouping for the legacy output */ - ret = drm_mode_group_init_legacy_group(drm, - &drm->primary->mode_group); - if (ret) - goto err_kms; + drm_mode_config_init(drm); ret = drm_vblank_init(drm, MAX_CRTC); if (ret) goto err_kms; /* - * with vblank_disable_allowed = true, vblank interrupt will be disabled - * by drm timer once a current process gives up ownership of - * vblank event.(after drm_vblank_put function is called) + * with vblank_disable_allowed = true, vblank interrupt will be + * disabled by drm timer once a current process gives up ownership + * of vblank event. (after drm_vblank_put function is called) */ drm->vblank_disable_allowed = true; - if (!imx_drm_device_get()) { - ret = -EINVAL; + platform_set_drvdata(drm->platformdev, drm); + + /* Now try and bind all our sub-components */ + ret = component_bind_all(drm->dev, drm); + if (ret) goto err_vblank; + + /* + * All components are now added, we can publish the connector sysfs + * entries to userspace. This will generate hotplug events and so + * userspace will expect to be able to access DRM at this point. + */ + list_for_each_entry(connector, &drm->mode_config.connector_list, head) { + ret = drm_sysfs_connector_add(connector); + if (ret) { + dev_err(drm->dev, + "[CONNECTOR:%d:%s] drm_sysfs_connector_add failed: %d\n", + connector->base.id, + drm_get_connector_name(connector), ret); + goto err_unbind; + } } - platform_set_drvdata(drm->platformdev, drm); - mutex_unlock(&imxdrm->mutex); + /* + * All components are now initialised, so setup the fb helper. + * The fb helper takes copies of key hardware information, so the + * crtcs/connectors/encoders must not change after this point. + */ +#if IS_ENABLED(CONFIG_DRM_IMX_FB_HELPER) + if (legacyfb_depth != 16 && legacyfb_depth != 32) { + dev_warn(drm->dev, "Invalid legacyfb_depth. Defaulting to 16bpp\n"); + legacyfb_depth = 16; + } + imxdrm->fbhelper = drm_fbdev_cma_init(drm, legacyfb_depth, + drm->mode_config.num_crtc, MAX_CRTC); + if (IS_ERR(imxdrm->fbhelper)) { + ret = PTR_ERR(imxdrm->fbhelper); + imxdrm->fbhelper = NULL; + goto err_unbind; + } +#endif + + drm_kms_helper_poll_init(drm); + return 0; +err_unbind: + component_unbind_all(drm->dev, drm); err_vblank: drm_vblank_cleanup(drm); err_kms: - drm_kms_helper_poll_fini(drm); drm_mode_config_cleanup(drm); - mutex_unlock(&imxdrm->mutex); return ret; } -static void imx_drm_update_possible_crtcs(void) -{ - struct imx_drm_device *imxdrm = __imx_drm_device(); - struct imx_drm_crtc *imx_drm_crtc; - struct imx_drm_encoder *enc; - struct crtc_cookie *cookie; - - list_for_each_entry(enc, &imxdrm->encoder_list, list) { - u32 possible_crtcs = 0; - - list_for_each_entry(cookie, &enc->possible_crtcs, list) { - list_for_each_entry(imx_drm_crtc, &imxdrm->crtc_list, list) { - if (imx_drm_crtc->cookie.cookie == cookie->cookie && - imx_drm_crtc->cookie.id == cookie->id) { - possible_crtcs |= 1 << imx_drm_crtc->pipe; - } - } - } - enc->encoder->possible_crtcs = possible_crtcs; - enc->encoder->possible_clones = possible_crtcs; - } -} - /* * imx_drm_add_crtc - add a new crtc * * The return value if !NULL is a cookie for the caller to pass to * imx_drm_remove_crtc later. */ -int imx_drm_add_crtc(struct drm_crtc *crtc, +int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc, struct imx_drm_crtc **new_crtc, const struct imx_drm_crtc_helper_funcs *imx_drm_helper_funcs, - struct module *owner, void *cookie, int id) + void *cookie, int id) { - struct imx_drm_device *imxdrm = __imx_drm_device(); + struct imx_drm_device *imxdrm = drm->dev_private; struct imx_drm_crtc *imx_drm_crtc; int ret; - mutex_lock(&imxdrm->mutex); - /* * The vblank arrays are dimensioned by MAX_CRTC - we can't * pass IDs greater than this to those functions. */ - if (imxdrm->pipes >= MAX_CRTC) { - ret = -EINVAL; - goto err_busy; - } + if (imxdrm->pipes >= MAX_CRTC) + return -EINVAL; - if (imxdrm->drm->open_count) { - ret = -EBUSY; - goto err_busy; - } + if (imxdrm->drm->open_count) + return -EBUSY; imx_drm_crtc = kzalloc(sizeof(*imx_drm_crtc), GFP_KERNEL); - if (!imx_drm_crtc) { - ret = -ENOMEM; - goto err_alloc; - } + if (!imx_drm_crtc) + return -ENOMEM; imx_drm_crtc->imx_drm_helper_funcs = *imx_drm_helper_funcs; imx_drm_crtc->pipe = imxdrm->pipes++; - imx_drm_crtc->cookie.cookie = cookie; - imx_drm_crtc->cookie.id = id; - + imx_drm_crtc->cookie = cookie; + imx_drm_crtc->id = id; + imx_drm_crtc->mux_id = imx_drm_crtc->pipe; imx_drm_crtc->crtc = crtc; - imx_drm_crtc->imxdrm = imxdrm; - imx_drm_crtc->owner = owner; - - list_add_tail(&imx_drm_crtc->list, &imxdrm->crtc_list); + imxdrm->crtc[imx_drm_crtc->pipe] = imx_drm_crtc; *new_crtc = imx_drm_crtc; @@ -520,23 +386,14 @@ int imx_drm_add_crtc(struct drm_crtc *crtc, drm_crtc_helper_add(crtc, imx_drm_crtc->imx_drm_helper_funcs.crtc_helper_funcs); - drm_crtc_init(imxdrm->drm, crtc, + drm_crtc_init(drm, crtc, imx_drm_crtc->imx_drm_helper_funcs.crtc_funcs); - drm_mode_group_reinit(imxdrm->drm); - - imx_drm_update_possible_crtcs(); - - mutex_unlock(&imxdrm->mutex); - return 0; err_register: - list_del(&imx_drm_crtc->list); + imxdrm->crtc[imx_drm_crtc->pipe] = NULL; kfree(imx_drm_crtc); -err_alloc: -err_busy: - mutex_unlock(&imxdrm->mutex); return ret; } EXPORT_SYMBOL_GPL(imx_drm_add_crtc); @@ -546,17 +403,11 @@ EXPORT_SYMBOL_GPL(imx_drm_add_crtc); */ int imx_drm_remove_crtc(struct imx_drm_crtc *imx_drm_crtc) { - struct imx_drm_device *imxdrm = imx_drm_crtc->imxdrm; - - mutex_lock(&imxdrm->mutex); + struct imx_drm_device *imxdrm = imx_drm_crtc->crtc->dev->dev_private; drm_crtc_cleanup(imx_drm_crtc->crtc); - list_del(&imx_drm_crtc->list); - - drm_mode_group_reinit(imxdrm->drm); - - mutex_unlock(&imxdrm->mutex); + imxdrm->crtc[imx_drm_crtc->pipe] = NULL; kfree(imx_drm_crtc); @@ -565,220 +416,78 @@ int imx_drm_remove_crtc(struct imx_drm_crtc *imx_drm_crtc) EXPORT_SYMBOL_GPL(imx_drm_remove_crtc); /* - * imx_drm_add_encoder - add a new encoder + * Find the DRM CRTC possible mask for the device node cookie/id. + * + * The encoder possible masks are defined by their position in the + * mode_config crtc_list. This means that CRTCs must not be added + * or removed once the DRM device has been fully initialised. */ -int imx_drm_add_encoder(struct drm_encoder *encoder, - struct imx_drm_encoder **newenc, struct module *owner) +static uint32_t imx_drm_find_crtc_mask(struct imx_drm_device *imxdrm, + void *cookie, int id) { - struct imx_drm_device *imxdrm = __imx_drm_device(); - struct imx_drm_encoder *imx_drm_encoder; - int ret; - - mutex_lock(&imxdrm->mutex); - - if (imxdrm->drm->open_count) { - ret = -EBUSY; - goto err_busy; - } + unsigned i; - imx_drm_encoder = kzalloc(sizeof(*imx_drm_encoder), GFP_KERNEL); - if (!imx_drm_encoder) { - ret = -ENOMEM; - goto err_alloc; + for (i = 0; i < MAX_CRTC; i++) { + struct imx_drm_crtc *imx_drm_crtc = imxdrm->crtc[i]; + if (imx_drm_crtc && imx_drm_crtc->id == id && + imx_drm_crtc->cookie == cookie) + return drm_crtc_mask(imx_drm_crtc->crtc); } - imx_drm_encoder->encoder = encoder; - imx_drm_encoder->owner = owner; - - ret = imx_drm_encoder_register(imx_drm_encoder); - if (ret) { - ret = -ENOMEM; - goto err_register; - } - - list_add_tail(&imx_drm_encoder->list, &imxdrm->encoder_list); - - *newenc = imx_drm_encoder; - - mutex_unlock(&imxdrm->mutex); - return 0; - -err_register: - kfree(imx_drm_encoder); -err_alloc: -err_busy: - mutex_unlock(&imxdrm->mutex); - - return ret; } -EXPORT_SYMBOL_GPL(imx_drm_add_encoder); -int imx_drm_encoder_add_possible_crtcs( - struct imx_drm_encoder *imx_drm_encoder, - struct device_node *np) +int imx_drm_encoder_parse_of(struct drm_device *drm, + struct drm_encoder *encoder, struct device_node *np) { - struct imx_drm_device *imxdrm = __imx_drm_device(); - struct of_phandle_args args; - struct crtc_cookie *c; - int ret = 0; - int i; - - if (!list_empty(&imx_drm_encoder->possible_crtcs)) - return -EBUSY; + struct imx_drm_device *imxdrm = drm->dev_private; + uint32_t crtc_mask = 0; + int i, ret = 0; for (i = 0; !ret; i++) { - ret = of_parse_phandle_with_args(np, "crtcs", - "#crtc-cells", i, &args); - if (ret < 0) - break; + struct of_phandle_args args; + uint32_t mask; + int id; - c = kzalloc(sizeof(*c), GFP_KERNEL); - if (!c) { - of_node_put(args.np); - return -ENOMEM; - } - - c->cookie = args.np; - c->id = args.args_count > 0 ? args.args[0] : 0; + ret = of_parse_phandle_with_args(np, "crtcs", "#crtc-cells", i, + &args); + if (ret == -ENOENT) + break; + if (ret < 0) + return ret; + id = args.args_count > 0 ? args.args[0] : 0; + mask = imx_drm_find_crtc_mask(imxdrm, args.np, id); of_node_put(args.np); - mutex_lock(&imxdrm->mutex); + /* + * If we failed to find the CRTC(s) which this encoder is + * supposed to be connected to, it's because the CRTC has + * not been registered yet. Defer probing, and hope that + * the required CRTC is added later. + */ + if (mask == 0) + return -EPROBE_DEFER; - list_add_tail(&c->list, &imx_drm_encoder->possible_crtcs); - - mutex_unlock(&imxdrm->mutex); + crtc_mask |= mask; } - imx_drm_update_possible_crtcs(); + encoder->possible_crtcs = crtc_mask; - return 0; -} -EXPORT_SYMBOL_GPL(imx_drm_encoder_add_possible_crtcs); - -int imx_drm_encoder_get_mux_id(struct imx_drm_encoder *imx_drm_encoder, - struct drm_crtc *crtc) -{ - struct imx_drm_device *imxdrm = __imx_drm_device(); - struct imx_drm_crtc *imx_crtc; - int i = 0; - - list_for_each_entry(imx_crtc, &imxdrm->crtc_list, list) { - if (imx_crtc->crtc == crtc) - goto found; - i++; - } - - return -EINVAL; -found: - return i; -} -EXPORT_SYMBOL_GPL(imx_drm_encoder_get_mux_id); - -/* - * imx_drm_remove_encoder - remove an encoder - */ -int imx_drm_remove_encoder(struct imx_drm_encoder *imx_drm_encoder) -{ - struct imx_drm_device *imxdrm = __imx_drm_device(); - struct crtc_cookie *c, *tmp; - - mutex_lock(&imxdrm->mutex); - - imx_drm_encoder_unregister(imx_drm_encoder); - - list_del(&imx_drm_encoder->list); - - list_for_each_entry_safe(c, tmp, &imx_drm_encoder->possible_crtcs, - list) - kfree(c); - - mutex_unlock(&imxdrm->mutex); - - kfree(imx_drm_encoder); - - return 0; -} -EXPORT_SYMBOL_GPL(imx_drm_remove_encoder); - -/* - * imx_drm_add_connector - add a connector - */ -int imx_drm_add_connector(struct drm_connector *connector, - struct imx_drm_connector **new_con, - struct module *owner) -{ - struct imx_drm_device *imxdrm = __imx_drm_device(); - struct imx_drm_connector *imx_drm_connector; - int ret; - - mutex_lock(&imxdrm->mutex); - - if (imxdrm->drm->open_count) { - ret = -EBUSY; - goto err_busy; - } - - imx_drm_connector = kzalloc(sizeof(*imx_drm_connector), GFP_KERNEL); - if (!imx_drm_connector) { - ret = -ENOMEM; - goto err_alloc; - } - - imx_drm_connector->connector = connector; - imx_drm_connector->owner = owner; - - ret = imx_drm_connector_register(imx_drm_connector); - if (ret) - goto err_register; - - list_add_tail(&imx_drm_connector->list, &imxdrm->connector_list); - - *new_con = imx_drm_connector; - - mutex_unlock(&imxdrm->mutex); + /* FIXME: this is the mask of outputs which can clone this output. */ + encoder->possible_clones = ~0; return 0; - -err_register: - kfree(imx_drm_connector); -err_alloc: -err_busy: - mutex_unlock(&imxdrm->mutex); - - return ret; } -EXPORT_SYMBOL_GPL(imx_drm_add_connector); +EXPORT_SYMBOL_GPL(imx_drm_encoder_parse_of); -void imx_drm_fb_helper_set(struct drm_fbdev_cma *fbdev_helper) +int imx_drm_encoder_get_mux_id(struct drm_encoder *encoder) { - struct imx_drm_device *imxdrm = __imx_drm_device(); + struct imx_drm_crtc *imx_crtc = imx_drm_find_crtc(encoder->crtc); - imxdrm->fbhelper = fbdev_helper; + return imx_crtc ? imx_crtc->mux_id : -EINVAL; } -EXPORT_SYMBOL_GPL(imx_drm_fb_helper_set); - -/* - * imx_drm_remove_connector - remove a connector - */ -int imx_drm_remove_connector(struct imx_drm_connector *imx_drm_connector) -{ - struct imx_drm_device *imxdrm = __imx_drm_device(); - - mutex_lock(&imxdrm->mutex); - - imx_drm_connector_unregister(imx_drm_connector); - - list_del(&imx_drm_connector->list); - - mutex_unlock(&imxdrm->mutex); - - kfree(imx_drm_connector); - - return 0; -} -EXPORT_SYMBOL_GPL(imx_drm_remove_connector); +EXPORT_SYMBOL_GPL(imx_drm_encoder_get_mux_id); static const struct drm_ioctl_desc imx_drm_ioctls[] = { /* none so far */ @@ -819,80 +528,103 @@ static struct drm_driver imx_drm_driver = { .patchlevel = 0, }; -static int imx_drm_platform_probe(struct platform_device *pdev) +static int compare_parent_of(struct device *dev, void *data) { - int ret; - - ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); - if (ret) - return ret; - - imx_drm_device->dev = &pdev->dev; - - return drm_platform_init(&imx_drm_driver, pdev); + struct of_phandle_args *args = data; + return dev->parent && dev->parent->of_node == args->np; } -static int imx_drm_platform_remove(struct platform_device *pdev) +static int compare_of(struct device *dev, void *data) { - drm_put_dev(platform_get_drvdata(pdev)); - - return 0; + return dev->of_node == data; } -static struct platform_driver imx_drm_pdrv = { - .probe = imx_drm_platform_probe, - .remove = imx_drm_platform_remove, - .driver = { - .owner = THIS_MODULE, - .name = "imx-drm", - }, -}; - -static struct platform_device *imx_drm_pdev; - -static int __init imx_drm_init(void) +static int imx_drm_add_components(struct device *master, struct master *m) { + struct device_node *np = master->of_node; + unsigned i; int ret; - imx_drm_device = kzalloc(sizeof(*imx_drm_device), GFP_KERNEL); - if (!imx_drm_device) - return -ENOMEM; + for (i = 0; ; i++) { + struct of_phandle_args args; + + ret = of_parse_phandle_with_fixed_args(np, "crtcs", 1, + i, &args); + if (ret) + break; - mutex_init(&imx_drm_device->mutex); - INIT_LIST_HEAD(&imx_drm_device->crtc_list); - INIT_LIST_HEAD(&imx_drm_device->connector_list); - INIT_LIST_HEAD(&imx_drm_device->encoder_list); + ret = component_master_add_child(m, compare_parent_of, &args); + of_node_put(args.np); - imx_drm_pdev = platform_device_register_simple("imx-drm", -1, NULL, 0); - if (IS_ERR(imx_drm_pdev)) { - ret = PTR_ERR(imx_drm_pdev); - goto err_pdev; + if (ret) + return ret; } - ret = platform_driver_register(&imx_drm_pdrv); - if (ret) - goto err_pdrv; + for (i = 0; ; i++) { + struct device_node *node; + + node = of_parse_phandle(np, "connectors", i); + if (!node) + break; + + ret = component_master_add_child(m, compare_of, node); + of_node_put(node); + if (ret) + return ret; + } return 0; +} -err_pdrv: - platform_device_unregister(imx_drm_pdev); -err_pdev: - kfree(imx_drm_device); +static int imx_drm_bind(struct device *dev) +{ + return drm_platform_init(&imx_drm_driver, to_platform_device(dev)); +} - return ret; +static void imx_drm_unbind(struct device *dev) +{ + drm_put_dev(dev_get_drvdata(dev)); } -static void __exit imx_drm_exit(void) +static const struct component_master_ops imx_drm_ops = { + .add_components = imx_drm_add_components, + .bind = imx_drm_bind, + .unbind = imx_drm_unbind, +}; + +static int imx_drm_platform_probe(struct platform_device *pdev) { - platform_device_unregister(imx_drm_pdev); - platform_driver_unregister(&imx_drm_pdrv); + int ret; + + ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); + if (ret) + return ret; - kfree(imx_drm_device); + return component_master_add(&pdev->dev, &imx_drm_ops); } -module_init(imx_drm_init); -module_exit(imx_drm_exit); +static int imx_drm_platform_remove(struct platform_device *pdev) +{ + component_master_del(&pdev->dev, &imx_drm_ops); + return 0; +} + +static const struct of_device_id imx_drm_dt_ids[] = { + { .compatible = "fsl,imx-drm", }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, imx_drm_dt_ids); + +static struct platform_driver imx_drm_pdrv = { + .probe = imx_drm_platform_probe, + .remove = imx_drm_platform_remove, + .driver = { + .owner = THIS_MODULE, + .name = "imx-drm", + .of_match_table = imx_drm_dt_ids, + }, +}; +module_platform_driver(imx_drm_pdrv); MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>"); MODULE_DESCRIPTION("i.MX drm driver core"); diff --git a/drivers/staging/imx-drm/imx-drm.h b/drivers/staging/imx-drm/imx-drm.h index ae90c9c1531..035ab6258ad 100644 --- a/drivers/staging/imx-drm/imx-drm.h +++ b/drivers/staging/imx-drm/imx-drm.h @@ -1,17 +1,15 @@ #ifndef _IMX_DRM_H_ #define _IMX_DRM_H_ -#include <linux/videodev2.h> - -#define IPU_PIX_FMT_GBR24 v4l2_fourcc('G', 'B', 'R', '3') - +struct device_node; struct drm_crtc; struct drm_connector; struct drm_device; +struct drm_display_mode; struct drm_encoder; -struct imx_drm_crtc; struct drm_fbdev_cma; struct drm_framebuffer; +struct imx_drm_crtc; struct platform_device; int imx_drm_crtc_id(struct imx_drm_crtc *crtc); @@ -25,10 +23,10 @@ struct imx_drm_crtc_helper_funcs { const struct drm_crtc_funcs *crtc_funcs; }; -int imx_drm_add_crtc(struct drm_crtc *crtc, +int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc, struct imx_drm_crtc **new_crtc, const struct imx_drm_crtc_helper_funcs *imx_helper_funcs, - struct module *owner, void *cookie, int id); + void *cookie, int id); int imx_drm_remove_crtc(struct imx_drm_crtc *); int imx_drm_init_drm(struct platform_device *pdev, int preferred_bpp); @@ -38,35 +36,22 @@ int imx_drm_crtc_vblank_get(struct imx_drm_crtc *imx_drm_crtc); void imx_drm_crtc_vblank_put(struct imx_drm_crtc *imx_drm_crtc); void imx_drm_handle_vblank(struct imx_drm_crtc *imx_drm_crtc); -struct imx_drm_encoder; -int imx_drm_add_encoder(struct drm_encoder *encoder, - struct imx_drm_encoder **new_enc, - struct module *owner); -int imx_drm_remove_encoder(struct imx_drm_encoder *); - -struct imx_drm_connector; -int imx_drm_add_connector(struct drm_connector *connector, - struct imx_drm_connector **new_con, - struct module *owner); -int imx_drm_remove_connector(struct imx_drm_connector *); - void imx_drm_mode_config_init(struct drm_device *drm); struct drm_gem_cma_object *imx_drm_fb_get_obj(struct drm_framebuffer *fb); -struct drm_device *imx_drm_device_get(void); -void imx_drm_device_put(void); -int imx_drm_crtc_panel_format_pins(struct drm_crtc *crtc, u32 encoder_type, +int imx_drm_panel_format_pins(struct drm_encoder *encoder, u32 interface_pix_fmt, int hsync_pin, int vsync_pin); -int imx_drm_crtc_panel_format(struct drm_crtc *crtc, u32 encoder_type, +int imx_drm_panel_format(struct drm_encoder *encoder, u32 interface_pix_fmt); -void imx_drm_fb_helper_set(struct drm_fbdev_cma *fbdev_helper); -struct device_node; +int imx_drm_encoder_get_mux_id(struct drm_encoder *encoder); +int imx_drm_encoder_parse_of(struct drm_device *drm, + struct drm_encoder *encoder, struct device_node *np); -int imx_drm_encoder_get_mux_id(struct imx_drm_encoder *imx_drm_encoder, - struct drm_crtc *crtc); -int imx_drm_encoder_add_possible_crtcs(struct imx_drm_encoder *imx_drm_encoder, - struct device_node *np); +int imx_drm_connector_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode); +void imx_drm_connector_destroy(struct drm_connector *connector); +void imx_drm_encoder_destroy(struct drm_encoder *encoder); #endif /* _IMX_DRM_H_ */ diff --git a/drivers/staging/imx-drm/imx-fb.c b/drivers/staging/imx-drm/imx-fb.c deleted file mode 100644 index 03a7b4e14f6..00000000000 --- a/drivers/staging/imx-drm/imx-fb.c +++ /dev/null @@ -1,47 +0,0 @@ -/* - * i.MX drm driver - * - * Copyright (C) 2012 Sascha Hauer, Pengutronix - * - * Based on Samsung Exynos code - * - * Copyright (c) 2011 Samsung Electronics Co., Ltd. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * 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 <drm/drmP.h> -#include <drm/drm_crtc.h> -#include <drm/drm_crtc_helper.h> -#include <drm/drm_gem_cma_helper.h> -#include <drm/drm_fb_cma_helper.h> - -#include "imx-drm.h" - -static struct drm_mode_config_funcs imx_drm_mode_config_funcs = { - .fb_create = drm_fb_cma_create, -}; - -void imx_drm_mode_config_init(struct drm_device *dev) -{ - dev->mode_config.min_width = 64; - dev->mode_config.min_height = 64; - - /* - * set max width and height as default value(4096x4096). - * this value would be used to check framebuffer size limitation - * at drm_mode_addfb(). - */ - dev->mode_config.max_width = 4096; - dev->mode_config.max_height = 4096; - - dev->mode_config.funcs = &imx_drm_mode_config_funcs; -} diff --git a/drivers/staging/imx-drm/imx-fbdev.c b/drivers/staging/imx-drm/imx-fbdev.c deleted file mode 100644 index 8331739c3d0..00000000000 --- a/drivers/staging/imx-drm/imx-fbdev.c +++ /dev/null @@ -1,74 +0,0 @@ -/* - * i.MX drm driver - * - * Copyright (C) 2012 Sascha Hauer, Pengutronix - * - * Based on Samsung Exynos code - * - * Copyright (c) 2011 Samsung Electronics Co., Ltd. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * 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 <drm/drmP.h> -#include <drm/drm_crtc.h> -#include <drm/drm_crtc_helper.h> -#include <drm/drm_fb_cma_helper.h> - -#include "imx-drm.h" - -#define MAX_CONNECTOR 4 -#define PREFERRED_BPP 16 - -static struct drm_fbdev_cma *fbdev_cma; - -static int legacyfb_depth = 16; - -module_param(legacyfb_depth, int, 0444); - -static int __init imx_fb_helper_init(void) -{ - struct drm_device *drm = imx_drm_device_get(); - - if (!drm) - return -EINVAL; - - if (legacyfb_depth != 16 && legacyfb_depth != 32) { - pr_warn("i.MX legacyfb: invalid legacyfb_depth setting. defaulting to 16bpp\n"); - legacyfb_depth = 16; - } - - fbdev_cma = drm_fbdev_cma_init(drm, legacyfb_depth, - drm->mode_config.num_crtc, MAX_CONNECTOR); - - if (IS_ERR(fbdev_cma)) { - imx_drm_device_put(); - return PTR_ERR(fbdev_cma); - } - - imx_drm_fb_helper_set(fbdev_cma); - - return 0; -} - -static void __exit imx_fb_helper_exit(void) -{ - imx_drm_fb_helper_set(NULL); - drm_fbdev_cma_fini(fbdev_cma); - imx_drm_device_put(); -} - -late_initcall(imx_fb_helper_init); -module_exit(imx_fb_helper_exit); - -MODULE_DESCRIPTION("Freescale i.MX legacy fb driver"); -MODULE_AUTHOR("Sascha Hauer, Pengutronix"); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c index f1aa48cb500..8384ceab932 100644 --- a/drivers/staging/imx-drm/imx-hdmi.c +++ b/drivers/staging/imx-drm/imx-hdmi.c @@ -12,6 +12,7 @@ * Copyright (C) 2010, Guennadi Liakhovetski <g.liakhovetski@gmx.de> */ +#include <linux/component.h> #include <linux/irq.h> #include <linux/delay.h> #include <linux/err.h> @@ -112,15 +113,15 @@ struct hdmi_data_info { struct imx_hdmi { struct drm_connector connector; - struct imx_drm_connector *imx_drm_connector; struct drm_encoder encoder; - struct imx_drm_encoder *imx_drm_encoder; enum imx_hdmi_devtype dev_type; struct device *dev; struct clk *isfr_clk; struct clk *iahb_clk; + enum drm_connector_status connector_status; + struct hdmi_data_info hdmi_data; int vic; @@ -134,7 +135,6 @@ struct imx_hdmi { struct i2c_adapter *ddc; void __iomem *regs; - unsigned long pixel_clk_rate; unsigned int sample_rate; int ratio; }; @@ -156,37 +156,34 @@ static inline u8 hdmi_readb(struct imx_hdmi *hdmi, int offset) return readb(hdmi->regs + offset); } +static void hdmi_modb(struct imx_hdmi *hdmi, u8 data, u8 mask, unsigned reg) +{ + u8 val = hdmi_readb(hdmi, reg) & ~mask; + val |= data & mask; + hdmi_writeb(hdmi, val, reg); +} + static void hdmi_mask_writeb(struct imx_hdmi *hdmi, u8 data, unsigned int reg, u8 shift, u8 mask) { - u8 value = hdmi_readb(hdmi, reg) & ~mask; - value |= (data << shift) & mask; - hdmi_writeb(hdmi, value, reg); + hdmi_modb(hdmi, data << shift, mask, reg); } static void hdmi_set_clock_regenerator_n(struct imx_hdmi *hdmi, unsigned int value) { - u8 val; - hdmi_writeb(hdmi, value & 0xff, HDMI_AUD_N1); hdmi_writeb(hdmi, (value >> 8) & 0xff, HDMI_AUD_N2); hdmi_writeb(hdmi, (value >> 16) & 0x0f, HDMI_AUD_N3); /* nshift factor = 0 */ - val = hdmi_readb(hdmi, HDMI_AUD_CTS3); - val &= ~HDMI_AUD_CTS3_N_SHIFT_MASK; - hdmi_writeb(hdmi, val, HDMI_AUD_CTS3); + hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_N_SHIFT_MASK, HDMI_AUD_CTS3); } static void hdmi_regenerate_cts(struct imx_hdmi *hdmi, unsigned int cts) { - u8 val; - /* Must be set/cleared first */ - val = hdmi_readb(hdmi, HDMI_AUD_CTS3); - val &= ~HDMI_AUD_CTS3_CTS_MANUAL; - hdmi_writeb(hdmi, val, HDMI_AUD_CTS3); + hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_CTS_MANUAL, HDMI_AUD_CTS3); hdmi_writeb(hdmi, cts & 0xff, HDMI_AUD_CTS1); hdmi_writeb(hdmi, (cts >> 8) & 0xff, HDMI_AUD_CTS2); @@ -331,34 +328,25 @@ static unsigned int hdmi_compute_cts(unsigned int freq, unsigned long pixel_clk, return (cts * ratio) / 100; } -static void hdmi_get_pixel_clk(struct imx_hdmi *hdmi) -{ - unsigned long rate; - - rate = 65000000; /* FIXME */ - - if (rate) - hdmi->pixel_clk_rate = rate; -} - -static void hdmi_set_clk_regenerator(struct imx_hdmi *hdmi) +static void hdmi_set_clk_regenerator(struct imx_hdmi *hdmi, + unsigned long pixel_clk) { unsigned int clk_n, clk_cts; - clk_n = hdmi_compute_n(hdmi->sample_rate, hdmi->pixel_clk_rate, + clk_n = hdmi_compute_n(hdmi->sample_rate, pixel_clk, hdmi->ratio); - clk_cts = hdmi_compute_cts(hdmi->sample_rate, hdmi->pixel_clk_rate, + clk_cts = hdmi_compute_cts(hdmi->sample_rate, pixel_clk, hdmi->ratio); if (!clk_cts) { dev_dbg(hdmi->dev, "%s: pixel clock not supported: %lu\n", - __func__, hdmi->pixel_clk_rate); + __func__, pixel_clk); return; } dev_dbg(hdmi->dev, "%s: samplerate=%d ratio=%d pixelclk=%lu N=%d cts=%d\n", __func__, hdmi->sample_rate, hdmi->ratio, - hdmi->pixel_clk_rate, clk_n, clk_cts); + pixel_clk, clk_n, clk_cts); hdmi_set_clock_regenerator_n(hdmi, clk_n); hdmi_regenerate_cts(hdmi, clk_cts); @@ -366,32 +354,12 @@ static void hdmi_set_clk_regenerator(struct imx_hdmi *hdmi) static void hdmi_init_clk_regenerator(struct imx_hdmi *hdmi) { - unsigned int clk_n, clk_cts; - - clk_n = hdmi_compute_n(hdmi->sample_rate, hdmi->pixel_clk_rate, - hdmi->ratio); - clk_cts = hdmi_compute_cts(hdmi->sample_rate, hdmi->pixel_clk_rate, - hdmi->ratio); - - if (!clk_cts) { - dev_dbg(hdmi->dev, "%s: pixel clock not supported: %lu\n", - __func__, hdmi->pixel_clk_rate); - return; - } - - dev_dbg(hdmi->dev, "%s: samplerate=%d ratio=%d pixelclk=%lu N=%d cts=%d\n", - __func__, hdmi->sample_rate, hdmi->ratio, - hdmi->pixel_clk_rate, clk_n, clk_cts); - - hdmi_set_clock_regenerator_n(hdmi, clk_n); - hdmi_regenerate_cts(hdmi, clk_cts); + hdmi_set_clk_regenerator(hdmi, 74250000); } static void hdmi_clk_regenerator_update_pixel_clock(struct imx_hdmi *hdmi) { - /* Get pixel clock from ipu */ - hdmi_get_pixel_clk(hdmi); - hdmi_set_clk_regenerator(hdmi); + hdmi_set_clk_regenerator(hdmi, hdmi->hdmi_data.video_mode.mpixelclock); } /* @@ -485,8 +453,8 @@ static int is_color_space_interpolation(struct imx_hdmi *hdmi) static void imx_hdmi_update_csc_coeffs(struct imx_hdmi *hdmi) { const u16 (*csc_coeff)[3][4] = &csc_coeff_default; + unsigned i; u32 csc_scale = 1; - u8 val; if (is_color_space_conversion(hdmi)) { if (hdmi->hdmi_data.enc_out_format == RGB) { @@ -503,37 +471,22 @@ static void imx_hdmi_update_csc_coeffs(struct imx_hdmi *hdmi) } } - hdmi_writeb(hdmi, ((*csc_coeff)[0][0] & 0xff), HDMI_CSC_COEF_A1_LSB); - hdmi_writeb(hdmi, ((*csc_coeff)[0][0] >> 8), HDMI_CSC_COEF_A1_MSB); - hdmi_writeb(hdmi, ((*csc_coeff)[0][1] & 0xff), HDMI_CSC_COEF_A2_LSB); - hdmi_writeb(hdmi, ((*csc_coeff)[0][1] >> 8), HDMI_CSC_COEF_A2_MSB); - hdmi_writeb(hdmi, ((*csc_coeff)[0][2] & 0xff), HDMI_CSC_COEF_A3_LSB); - hdmi_writeb(hdmi, ((*csc_coeff)[0][2] >> 8), HDMI_CSC_COEF_A3_MSB); - hdmi_writeb(hdmi, ((*csc_coeff)[0][3] & 0xff), HDMI_CSC_COEF_A4_LSB); - hdmi_writeb(hdmi, ((*csc_coeff)[0][3] >> 8), HDMI_CSC_COEF_A4_MSB); - - hdmi_writeb(hdmi, ((*csc_coeff)[1][0] & 0xff), HDMI_CSC_COEF_B1_LSB); - hdmi_writeb(hdmi, ((*csc_coeff)[1][0] >> 8), HDMI_CSC_COEF_B1_MSB); - hdmi_writeb(hdmi, ((*csc_coeff)[1][1] & 0xff), HDMI_CSC_COEF_B2_LSB); - hdmi_writeb(hdmi, ((*csc_coeff)[1][1] >> 8), HDMI_CSC_COEF_B2_MSB); - hdmi_writeb(hdmi, ((*csc_coeff)[1][2] & 0xff), HDMI_CSC_COEF_B3_LSB); - hdmi_writeb(hdmi, ((*csc_coeff)[1][2] >> 8), HDMI_CSC_COEF_B3_MSB); - hdmi_writeb(hdmi, ((*csc_coeff)[1][3] & 0xff), HDMI_CSC_COEF_B4_LSB); - hdmi_writeb(hdmi, ((*csc_coeff)[1][3] >> 8), HDMI_CSC_COEF_B4_MSB); - - hdmi_writeb(hdmi, ((*csc_coeff)[2][0] & 0xff), HDMI_CSC_COEF_C1_LSB); - hdmi_writeb(hdmi, ((*csc_coeff)[2][0] >> 8), HDMI_CSC_COEF_C1_MSB); - hdmi_writeb(hdmi, ((*csc_coeff)[2][1] & 0xff), HDMI_CSC_COEF_C2_LSB); - hdmi_writeb(hdmi, ((*csc_coeff)[2][1] >> 8), HDMI_CSC_COEF_C2_MSB); - hdmi_writeb(hdmi, ((*csc_coeff)[2][2] & 0xff), HDMI_CSC_COEF_C3_LSB); - hdmi_writeb(hdmi, ((*csc_coeff)[2][2] >> 8), HDMI_CSC_COEF_C3_MSB); - hdmi_writeb(hdmi, ((*csc_coeff)[2][3] & 0xff), HDMI_CSC_COEF_C4_LSB); - hdmi_writeb(hdmi, ((*csc_coeff)[2][3] >> 8), HDMI_CSC_COEF_C4_MSB); - - val = hdmi_readb(hdmi, HDMI_CSC_SCALE); - val &= ~HDMI_CSC_SCALE_CSCSCALE_MASK; - val |= csc_scale & HDMI_CSC_SCALE_CSCSCALE_MASK; - hdmi_writeb(hdmi, val, HDMI_CSC_SCALE); + /* The CSC registers are sequential, alternating MSB then LSB */ + for (i = 0; i < ARRAY_SIZE(csc_coeff_default[0]); i++) { + u16 coeff_a = (*csc_coeff)[0][i]; + u16 coeff_b = (*csc_coeff)[1][i]; + u16 coeff_c = (*csc_coeff)[2][i]; + + hdmi_writeb(hdmi, coeff_a & 0xff, HDMI_CSC_COEF_A1_LSB + i * 2); + hdmi_writeb(hdmi, coeff_a >> 8, HDMI_CSC_COEF_A1_MSB + i * 2); + hdmi_writeb(hdmi, coeff_b & 0xff, HDMI_CSC_COEF_B1_LSB + i * 2); + hdmi_writeb(hdmi, coeff_b >> 8, HDMI_CSC_COEF_B1_MSB + i * 2); + hdmi_writeb(hdmi, coeff_c & 0xff, HDMI_CSC_COEF_C1_LSB + i * 2); + hdmi_writeb(hdmi, coeff_c >> 8, HDMI_CSC_COEF_C1_MSB + i * 2); + } + + hdmi_modb(hdmi, csc_scale, HDMI_CSC_SCALE_CSCSCALE_MASK, + HDMI_CSC_SCALE); } static void hdmi_video_csc(struct imx_hdmi *hdmi) @@ -541,7 +494,6 @@ static void hdmi_video_csc(struct imx_hdmi *hdmi) int color_depth = 0; int interpolation = HDMI_CSC_CFG_INTMODE_DISABLE; int decimation = 0; - u8 val; /* YCC422 interpolation to 444 mode */ if (is_color_space_interpolation(hdmi)) @@ -562,10 +514,8 @@ static void hdmi_video_csc(struct imx_hdmi *hdmi) /* Configure the CSC registers */ hdmi_writeb(hdmi, interpolation | decimation, HDMI_CSC_CFG); - val = hdmi_readb(hdmi, HDMI_CSC_SCALE); - val &= ~HDMI_CSC_SCALE_CSC_COLORDE_PTH_MASK; - val |= color_depth; - hdmi_writeb(hdmi, val, HDMI_CSC_SCALE); + hdmi_modb(hdmi, color_depth, HDMI_CSC_SCALE_CSC_COLORDE_PTH_MASK, + HDMI_CSC_SCALE); imx_hdmi_update_csc_coeffs(hdmi); } @@ -581,7 +531,7 @@ static void hdmi_video_packetize(struct imx_hdmi *hdmi) unsigned int remap_size = HDMI_VP_REMAP_YCC422_16bit; unsigned int output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_PP; struct hdmi_data_info *hdmi_data = &hdmi->hdmi_data; - u8 val; + u8 val, vp_conf; if (hdmi_data->enc_out_format == RGB || hdmi_data->enc_out_format == YCBCR444) { @@ -620,107 +570,75 @@ static void hdmi_video_packetize(struct imx_hdmi *hdmi) HDMI_VP_PR_CD_DESIRED_PR_FACTOR_MASK); hdmi_writeb(hdmi, val, HDMI_VP_PR_CD); - val = hdmi_readb(hdmi, HDMI_VP_STUFF); - val &= ~HDMI_VP_STUFF_PR_STUFFING_MASK; - val |= HDMI_VP_STUFF_PR_STUFFING_STUFFING_MODE; - hdmi_writeb(hdmi, val, HDMI_VP_STUFF); + hdmi_modb(hdmi, HDMI_VP_STUFF_PR_STUFFING_STUFFING_MODE, + HDMI_VP_STUFF_PR_STUFFING_MASK, HDMI_VP_STUFF); /* Data from pixel repeater block */ if (hdmi_data->pix_repet_factor > 1) { - val = hdmi_readb(hdmi, HDMI_VP_CONF); - val &= ~(HDMI_VP_CONF_PR_EN_MASK | - HDMI_VP_CONF_BYPASS_SELECT_MASK); - val |= HDMI_VP_CONF_PR_EN_ENABLE | - HDMI_VP_CONF_BYPASS_SELECT_PIX_REPEATER; - hdmi_writeb(hdmi, val, HDMI_VP_CONF); + vp_conf = HDMI_VP_CONF_PR_EN_ENABLE | + HDMI_VP_CONF_BYPASS_SELECT_PIX_REPEATER; } else { /* data from packetizer block */ - val = hdmi_readb(hdmi, HDMI_VP_CONF); - val &= ~(HDMI_VP_CONF_PR_EN_MASK | - HDMI_VP_CONF_BYPASS_SELECT_MASK); - val |= HDMI_VP_CONF_PR_EN_DISABLE | - HDMI_VP_CONF_BYPASS_SELECT_VID_PACKETIZER; - hdmi_writeb(hdmi, val, HDMI_VP_CONF); + vp_conf = HDMI_VP_CONF_PR_EN_DISABLE | + HDMI_VP_CONF_BYPASS_SELECT_VID_PACKETIZER; } - val = hdmi_readb(hdmi, HDMI_VP_STUFF); - val &= ~HDMI_VP_STUFF_IDEFAULT_PHASE_MASK; - val |= 1 << HDMI_VP_STUFF_IDEFAULT_PHASE_OFFSET; - hdmi_writeb(hdmi, val, HDMI_VP_STUFF); + hdmi_modb(hdmi, vp_conf, + HDMI_VP_CONF_PR_EN_MASK | + HDMI_VP_CONF_BYPASS_SELECT_MASK, HDMI_VP_CONF); + + hdmi_modb(hdmi, 1 << HDMI_VP_STUFF_IDEFAULT_PHASE_OFFSET, + HDMI_VP_STUFF_IDEFAULT_PHASE_MASK, HDMI_VP_STUFF); hdmi_writeb(hdmi, remap_size, HDMI_VP_REMAP); if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_PP) { - val = hdmi_readb(hdmi, HDMI_VP_CONF); - val &= ~(HDMI_VP_CONF_BYPASS_EN_MASK | - HDMI_VP_CONF_PP_EN_ENMASK | - HDMI_VP_CONF_YCC422_EN_MASK); - val |= HDMI_VP_CONF_BYPASS_EN_DISABLE | - HDMI_VP_CONF_PP_EN_ENABLE | - HDMI_VP_CONF_YCC422_EN_DISABLE; - hdmi_writeb(hdmi, val, HDMI_VP_CONF); + vp_conf = HDMI_VP_CONF_BYPASS_EN_DISABLE | + HDMI_VP_CONF_PP_EN_ENABLE | + HDMI_VP_CONF_YCC422_EN_DISABLE; } else if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_YCC422) { - val = hdmi_readb(hdmi, HDMI_VP_CONF); - val &= ~(HDMI_VP_CONF_BYPASS_EN_MASK | - HDMI_VP_CONF_PP_EN_ENMASK | - HDMI_VP_CONF_YCC422_EN_MASK); - val |= HDMI_VP_CONF_BYPASS_EN_DISABLE | - HDMI_VP_CONF_PP_EN_DISABLE | - HDMI_VP_CONF_YCC422_EN_ENABLE; - hdmi_writeb(hdmi, val, HDMI_VP_CONF); + vp_conf = HDMI_VP_CONF_BYPASS_EN_DISABLE | + HDMI_VP_CONF_PP_EN_DISABLE | + HDMI_VP_CONF_YCC422_EN_ENABLE; } else if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS) { - val = hdmi_readb(hdmi, HDMI_VP_CONF); - val &= ~(HDMI_VP_CONF_BYPASS_EN_MASK | - HDMI_VP_CONF_PP_EN_ENMASK | - HDMI_VP_CONF_YCC422_EN_MASK); - val |= HDMI_VP_CONF_BYPASS_EN_ENABLE | - HDMI_VP_CONF_PP_EN_DISABLE | - HDMI_VP_CONF_YCC422_EN_DISABLE; - hdmi_writeb(hdmi, val, HDMI_VP_CONF); + vp_conf = HDMI_VP_CONF_BYPASS_EN_ENABLE | + HDMI_VP_CONF_PP_EN_DISABLE | + HDMI_VP_CONF_YCC422_EN_DISABLE; } else { return; } - val = hdmi_readb(hdmi, HDMI_VP_STUFF); - val &= ~(HDMI_VP_STUFF_PP_STUFFING_MASK | - HDMI_VP_STUFF_YCC422_STUFFING_MASK); - val |= HDMI_VP_STUFF_PP_STUFFING_STUFFING_MODE | - HDMI_VP_STUFF_YCC422_STUFFING_STUFFING_MODE; - hdmi_writeb(hdmi, val, HDMI_VP_STUFF); + hdmi_modb(hdmi, vp_conf, + HDMI_VP_CONF_BYPASS_EN_MASK | HDMI_VP_CONF_PP_EN_ENMASK | + HDMI_VP_CONF_YCC422_EN_MASK, HDMI_VP_CONF); + + hdmi_modb(hdmi, HDMI_VP_STUFF_PP_STUFFING_STUFFING_MODE | + HDMI_VP_STUFF_YCC422_STUFFING_STUFFING_MODE, + HDMI_VP_STUFF_PP_STUFFING_MASK | + HDMI_VP_STUFF_YCC422_STUFFING_MASK, HDMI_VP_STUFF); - val = hdmi_readb(hdmi, HDMI_VP_CONF); - val &= ~HDMI_VP_CONF_OUTPUT_SELECTOR_MASK; - val |= output_select; - hdmi_writeb(hdmi, val, HDMI_VP_CONF); + hdmi_modb(hdmi, output_select, HDMI_VP_CONF_OUTPUT_SELECTOR_MASK, + HDMI_VP_CONF); } static inline void hdmi_phy_test_clear(struct imx_hdmi *hdmi, unsigned char bit) { - u8 val = hdmi_readb(hdmi, HDMI_PHY_TST0); - val &= ~HDMI_PHY_TST0_TSTCLR_MASK; - val |= (bit << HDMI_PHY_TST0_TSTCLR_OFFSET) & - HDMI_PHY_TST0_TSTCLR_MASK; - hdmi_writeb(hdmi, val, HDMI_PHY_TST0); + hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTCLR_OFFSET, + HDMI_PHY_TST0_TSTCLR_MASK, HDMI_PHY_TST0); } static inline void hdmi_phy_test_enable(struct imx_hdmi *hdmi, unsigned char bit) { - u8 val = hdmi_readb(hdmi, HDMI_PHY_TST0); - val &= ~HDMI_PHY_TST0_TSTEN_MASK; - val |= (bit << HDMI_PHY_TST0_TSTEN_OFFSET) & - HDMI_PHY_TST0_TSTEN_MASK; - hdmi_writeb(hdmi, val, HDMI_PHY_TST0); + hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTEN_OFFSET, + HDMI_PHY_TST0_TSTEN_MASK, HDMI_PHY_TST0); } static inline void hdmi_phy_test_clock(struct imx_hdmi *hdmi, unsigned char bit) { - u8 val = hdmi_readb(hdmi, HDMI_PHY_TST0); - val &= ~HDMI_PHY_TST0_TSTCLK_MASK; - val |= (bit << HDMI_PHY_TST0_TSTCLK_OFFSET) & - HDMI_PHY_TST0_TSTCLK_MASK; - hdmi_writeb(hdmi, val, HDMI_PHY_TST0); + hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTCLK_OFFSET, + HDMI_PHY_TST0_TSTCLK_MASK, HDMI_PHY_TST0); } static inline void hdmi_phy_test_din(struct imx_hdmi *hdmi, @@ -811,19 +729,94 @@ static void imx_hdmi_phy_sel_interface_control(struct imx_hdmi *hdmi, u8 enable) HDMI_PHY_CONF0_SELDIPIF_MASK); } +enum { + RES_8, + RES_10, + RES_12, + RES_MAX, +}; + +struct mpll_config { + unsigned long mpixelclock; + struct { + u16 cpce; + u16 gmp; + } res[RES_MAX]; +}; + +static const struct mpll_config mpll_config[] = { + { + 45250000, { + { 0x01e0, 0x0000 }, + { 0x21e1, 0x0000 }, + { 0x41e2, 0x0000 } + }, + }, { + 92500000, { + { 0x0140, 0x0005 }, + { 0x2141, 0x0005 }, + { 0x4142, 0x0005 }, + }, + }, { + 148500000, { + { 0x00a0, 0x000a }, + { 0x20a1, 0x000a }, + { 0x40a2, 0x000a }, + }, + }, { + ~0UL, { + { 0x00a0, 0x000a }, + { 0x2001, 0x000f }, + { 0x4002, 0x000f }, + }, + } +}; + +struct curr_ctrl { + unsigned long mpixelclock; + u16 curr[RES_MAX]; +}; + +static const struct curr_ctrl curr_ctrl[] = { + /* pixelclk bpp8 bpp10 bpp12 */ + { + 54000000, { 0x091c, 0x091c, 0x06dc }, + }, { + 58400000, { 0x091c, 0x06dc, 0x06dc }, + }, { + 72000000, { 0x06dc, 0x06dc, 0x091c }, + }, { + 74250000, { 0x06dc, 0x0b5c, 0x091c }, + }, { + 118800000, { 0x091c, 0x091c, 0x06dc }, + }, { + 216000000, { 0x06dc, 0x0b5c, 0x091c }, + } +}; + static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep, unsigned char res, int cscon) { + unsigned res_idx, i; u8 val, msec; - /* color resolution 0 is 8 bit colour depth */ - if (!res) - res = 8; - if (prep) return -EINVAL; - else if (res != 8 && res != 12) + + switch (res) { + case 0: /* color resolution 0 is 8 bit colour depth */ + case 8: + res_idx = RES_8; + break; + case 10: + res_idx = RES_10; + break; + case 12: + res_idx = RES_12; + break; + default: return -EINVAL; + } /* Enable csc path */ if (cscon) @@ -850,165 +843,30 @@ static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep, HDMI_PHY_I2CM_SLAVE_ADDR); hdmi_phy_test_clear(hdmi, 0); - if (hdmi->hdmi_data.video_mode.mpixelclock <= 45250000) { - switch (res) { - case 8: - /* PLL/MPLL Cfg */ - hdmi_phy_i2c_write(hdmi, 0x01e0, 0x06); - hdmi_phy_i2c_write(hdmi, 0x0000, 0x15); /* GMPCTRL */ - break; - case 10: - hdmi_phy_i2c_write(hdmi, 0x21e1, 0x06); - hdmi_phy_i2c_write(hdmi, 0x0000, 0x15); - break; - case 12: - hdmi_phy_i2c_write(hdmi, 0x41e2, 0x06); - hdmi_phy_i2c_write(hdmi, 0x0000, 0x15); - break; - default: - return -EINVAL; - } - } else if (hdmi->hdmi_data.video_mode.mpixelclock <= 92500000) { - switch (res) { - case 8: - hdmi_phy_i2c_write(hdmi, 0x0140, 0x06); - hdmi_phy_i2c_write(hdmi, 0x0005, 0x15); - break; - case 10: - hdmi_phy_i2c_write(hdmi, 0x2141, 0x06); - hdmi_phy_i2c_write(hdmi, 0x0005, 0x15); - break; - case 12: - hdmi_phy_i2c_write(hdmi, 0x4142, 0x06); - hdmi_phy_i2c_write(hdmi, 0x0005, 0x15); - default: - return -EINVAL; - } - } else if (hdmi->hdmi_data.video_mode.mpixelclock <= 148500000) { - switch (res) { - case 8: - hdmi_phy_i2c_write(hdmi, 0x00a0, 0x06); - hdmi_phy_i2c_write(hdmi, 0x000a, 0x15); + /* PLL/MPLL Cfg - always match on final entry */ + for (i = 0; i < ARRAY_SIZE(mpll_config) - 1; i++) + if (hdmi->hdmi_data.video_mode.mpixelclock <= + mpll_config[i].mpixelclock) break; - case 10: - hdmi_phy_i2c_write(hdmi, 0x20a1, 0x06); - hdmi_phy_i2c_write(hdmi, 0x000a, 0x15); - break; - case 12: - hdmi_phy_i2c_write(hdmi, 0x40a2, 0x06); - hdmi_phy_i2c_write(hdmi, 0x000a, 0x15); - default: - return -EINVAL; - } - } else { - switch (res) { - case 8: - hdmi_phy_i2c_write(hdmi, 0x00a0, 0x06); - hdmi_phy_i2c_write(hdmi, 0x000a, 0x15); - break; - case 10: - hdmi_phy_i2c_write(hdmi, 0x2001, 0x06); - hdmi_phy_i2c_write(hdmi, 0x000f, 0x15); - break; - case 12: - hdmi_phy_i2c_write(hdmi, 0x4002, 0x06); - hdmi_phy_i2c_write(hdmi, 0x000f, 0x15); - default: - return -EINVAL; - } - } - if (hdmi->hdmi_data.video_mode.mpixelclock <= 54000000) { - switch (res) { - case 8: - hdmi_phy_i2c_write(hdmi, 0x091c, 0x10); /* CURRCTRL */ - break; - case 10: - hdmi_phy_i2c_write(hdmi, 0x091c, 0x10); - break; - case 12: - hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10); - break; - default: - return -EINVAL; - } - } else if (hdmi->hdmi_data.video_mode.mpixelclock <= 58400000) { - switch (res) { - case 8: - hdmi_phy_i2c_write(hdmi, 0x091c, 0x10); - break; - case 10: - hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10); - break; - case 12: - hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10); - break; - default: - return -EINVAL; - } - } else if (hdmi->hdmi_data.video_mode.mpixelclock <= 72000000) { - switch (res) { - case 8: - hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10); - break; - case 10: - hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10); - break; - case 12: - hdmi_phy_i2c_write(hdmi, 0x091c, 0x10); - break; - default: - return -EINVAL; - } - } else if (hdmi->hdmi_data.video_mode.mpixelclock <= 74250000) { - switch (res) { - case 8: - hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10); - break; - case 10: - hdmi_phy_i2c_write(hdmi, 0x0b5c, 0x10); - break; - case 12: - hdmi_phy_i2c_write(hdmi, 0x091c, 0x10); - break; - default: - return -EINVAL; - } - } else if (hdmi->hdmi_data.video_mode.mpixelclock <= 118800000) { - switch (res) { - case 8: - hdmi_phy_i2c_write(hdmi, 0x091c, 0x10); - break; - case 10: - hdmi_phy_i2c_write(hdmi, 0x091c, 0x10); - break; - case 12: - hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10); - break; - default: - return -EINVAL; - } - } else if (hdmi->hdmi_data.video_mode.mpixelclock <= 216000000) { - switch (res) { - case 8: - hdmi_phy_i2c_write(hdmi, 0x06dc, 0x10); - break; - case 10: - hdmi_phy_i2c_write(hdmi, 0x0b5c, 0x10); - break; - case 12: - hdmi_phy_i2c_write(hdmi, 0x091c, 0x10); + hdmi_phy_i2c_write(hdmi, mpll_config[i].res[res_idx].cpce, 0x06); + hdmi_phy_i2c_write(hdmi, mpll_config[i].res[res_idx].gmp, 0x15); + + for (i = 0; i < ARRAY_SIZE(curr_ctrl); i++) + if (hdmi->hdmi_data.video_mode.mpixelclock <= + curr_ctrl[i].mpixelclock) break; - default: - return -EINVAL; - } - } else { + + if (i >= ARRAY_SIZE(curr_ctrl)) { dev_err(hdmi->dev, "Pixel clock %d - unsupported by HDMI\n", hdmi->hdmi_data.video_mode.mpixelclock); return -EINVAL; } + /* CURRCTRL */ + hdmi_phy_i2c_write(hdmi, curr_ctrl[i].curr[res_idx], 0x10); + hdmi_phy_i2c_write(hdmi, 0x0000, 0x13); /* PLLPHBYCTRL */ hdmi_phy_i2c_write(hdmi, 0x0006, 0x17); /* RESISTANCE TERM 133Ohm Cfg */ @@ -1077,7 +935,7 @@ static int imx_hdmi_phy_init(struct imx_hdmi *hdmi) static void hdmi_tx_hdcp_config(struct imx_hdmi *hdmi) { - u8 de, val; + u8 de; if (hdmi->hdmi_data.video_mode.mdataenablepolarity) de = HDMI_A_VIDPOLCFG_DATAENPOL_ACTIVE_HIGH; @@ -1085,20 +943,13 @@ static void hdmi_tx_hdcp_config(struct imx_hdmi *hdmi) de = HDMI_A_VIDPOLCFG_DATAENPOL_ACTIVE_LOW; /* disable rx detect */ - val = hdmi_readb(hdmi, HDMI_A_HDCPCFG0); - val &= HDMI_A_HDCPCFG0_RXDETECT_MASK; - val |= HDMI_A_HDCPCFG0_RXDETECT_DISABLE; - hdmi_writeb(hdmi, val, HDMI_A_HDCPCFG0); + hdmi_modb(hdmi, HDMI_A_HDCPCFG0_RXDETECT_DISABLE, + HDMI_A_HDCPCFG0_RXDETECT_MASK, HDMI_A_HDCPCFG0); - val = hdmi_readb(hdmi, HDMI_A_VIDPOLCFG); - val &= HDMI_A_VIDPOLCFG_DATAENPOL_MASK; - val |= de; - hdmi_writeb(hdmi, val, HDMI_A_VIDPOLCFG); + hdmi_modb(hdmi, de, HDMI_A_VIDPOLCFG_DATAENPOL_MASK, HDMI_A_VIDPOLCFG); - val = hdmi_readb(hdmi, HDMI_A_HDCPCFG1); - val &= HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_MASK; - val |= HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_DISABLE; - hdmi_writeb(hdmi, val, HDMI_A_HDCPCFG1); + hdmi_modb(hdmi, HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_DISABLE, + HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_MASK, HDMI_A_HDCPCFG1); } static void hdmi_config_AVI(struct imx_hdmi *hdmi) @@ -1322,11 +1173,7 @@ static void imx_hdmi_enable_video_path(struct imx_hdmi *hdmi) static void hdmi_enable_audio_clk(struct imx_hdmi *hdmi) { - u8 clkdis; - - clkdis = hdmi_readb(hdmi, HDMI_MC_CLKDIS); - clkdis &= ~HDMI_MC_CLKDIS_AUDCLK_DISABLE; - hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS); + hdmi_modb(hdmi, 0, HDMI_MC_CLKDIS_AUDCLK_DISABLE, HDMI_MC_CLKDIS); } /* Workaround to clear the overflow condition */ @@ -1461,9 +1308,6 @@ static int imx_hdmi_fb_registered(struct imx_hdmi *hdmi) /* Clear Hotplug interrupts */ hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD, HDMI_IH_PHY_STAT0); - /* Unmute interrupts */ - hdmi_writeb(hdmi, ~HDMI_IH_PHY_STAT0_HPD, HDMI_IH_MUTE_PHY_STAT0); - return 0; } @@ -1532,12 +1376,9 @@ static void imx_hdmi_poweroff(struct imx_hdmi *hdmi) static enum drm_connector_status imx_hdmi_connector_detect(struct drm_connector *connector, bool force) { - /* FIXME */ - return connector_status_connected; -} - -static void imx_hdmi_connector_destroy(struct drm_connector *connector) -{ + struct imx_hdmi *hdmi = container_of(connector, struct imx_hdmi, + connector); + return hdmi->connector_status; } static int imx_hdmi_connector_get_modes(struct drm_connector *connector) @@ -1565,13 +1406,6 @@ static int imx_hdmi_connector_get_modes(struct drm_connector *connector) return 0; } -static int imx_hdmi_connector_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) -{ - - return MODE_OK; -} - static struct drm_encoder *imx_hdmi_connector_best_encoder(struct drm_connector *connector) { @@ -1619,28 +1453,21 @@ static void imx_hdmi_encoder_prepare(struct drm_encoder *encoder) struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder); imx_hdmi_poweroff(hdmi); - imx_drm_crtc_panel_format(encoder->crtc, DRM_MODE_ENCODER_NONE, - V4L2_PIX_FMT_RGB24); + imx_drm_panel_format(encoder, V4L2_PIX_FMT_RGB24); } static void imx_hdmi_encoder_commit(struct drm_encoder *encoder) { struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder); - int mux = imx_drm_encoder_get_mux_id(hdmi->imx_drm_encoder, - encoder->crtc); + int mux = imx_drm_encoder_get_mux_id(encoder); imx_hdmi_set_ipu_di_mux(hdmi, mux); imx_hdmi_poweron(hdmi); } -static void imx_hdmi_encoder_destroy(struct drm_encoder *encoder) -{ - return; -} - static struct drm_encoder_funcs imx_hdmi_encoder_funcs = { - .destroy = imx_hdmi_encoder_destroy, + .destroy = imx_drm_encoder_destroy, }; static struct drm_encoder_helper_funcs imx_hdmi_encoder_helper_funcs = { @@ -1656,21 +1483,32 @@ static struct drm_connector_funcs imx_hdmi_connector_funcs = { .dpms = drm_helper_connector_dpms, .fill_modes = drm_helper_probe_single_connector_modes, .detect = imx_hdmi_connector_detect, - .destroy = imx_hdmi_connector_destroy, + .destroy = imx_drm_connector_destroy, }; static struct drm_connector_helper_funcs imx_hdmi_connector_helper_funcs = { .get_modes = imx_hdmi_connector_get_modes, - .mode_valid = imx_hdmi_connector_mode_valid, + .mode_valid = imx_drm_connector_mode_valid, .best_encoder = imx_hdmi_connector_best_encoder, }; +static irqreturn_t imx_hdmi_hardirq(int irq, void *dev_id) +{ + struct imx_hdmi *hdmi = dev_id; + u8 intr_stat; + + intr_stat = hdmi_readb(hdmi, HDMI_IH_PHY_STAT0); + if (intr_stat) + hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0); + + return intr_stat ? IRQ_WAKE_THREAD : IRQ_NONE; +} + static irqreturn_t imx_hdmi_irq(int irq, void *dev_id) { struct imx_hdmi *hdmi = dev_id; u8 intr_stat; u8 phy_int_pol; - u8 val; intr_stat = hdmi_readb(hdmi, HDMI_IH_PHY_STAT0); @@ -1680,55 +1518,46 @@ static irqreturn_t imx_hdmi_irq(int irq, void *dev_id) if (phy_int_pol & HDMI_PHY_HPD) { dev_dbg(hdmi->dev, "EVENT=plugin\n"); - val = hdmi_readb(hdmi, HDMI_PHY_POL0); - val &= ~HDMI_PHY_HPD; - hdmi_writeb(hdmi, val, HDMI_PHY_POL0); + hdmi_modb(hdmi, 0, HDMI_PHY_HPD, HDMI_PHY_POL0); + hdmi->connector_status = connector_status_connected; imx_hdmi_poweron(hdmi); } else { dev_dbg(hdmi->dev, "EVENT=plugout\n"); - val = hdmi_readb(hdmi, HDMI_PHY_POL0); - val |= HDMI_PHY_HPD; - hdmi_writeb(hdmi, val, HDMI_PHY_POL0); + hdmi_modb(hdmi, HDMI_PHY_HPD, HDMI_PHY_HPD, HDMI_PHY_POL0); + hdmi->connector_status = connector_status_disconnected; imx_hdmi_poweroff(hdmi); } + drm_helper_hpd_irq_event(hdmi->connector.dev); } hdmi_writeb(hdmi, intr_stat, HDMI_IH_PHY_STAT0); + hdmi_writeb(hdmi, ~HDMI_IH_PHY_STAT0_HPD, HDMI_IH_MUTE_PHY_STAT0); return IRQ_HANDLED; } -static int imx_hdmi_register(struct imx_hdmi *hdmi) +static int imx_hdmi_register(struct drm_device *drm, struct imx_hdmi *hdmi) { int ret; - hdmi->connector.funcs = &imx_hdmi_connector_funcs; - hdmi->encoder.funcs = &imx_hdmi_encoder_funcs; + ret = imx_drm_encoder_parse_of(drm, &hdmi->encoder, + hdmi->dev->of_node); + if (ret) + return ret; - hdmi->encoder.encoder_type = DRM_MODE_ENCODER_TMDS; - hdmi->connector.connector_type = DRM_MODE_CONNECTOR_HDMIA; + hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD; drm_encoder_helper_add(&hdmi->encoder, &imx_hdmi_encoder_helper_funcs); - ret = imx_drm_add_encoder(&hdmi->encoder, &hdmi->imx_drm_encoder, - THIS_MODULE); - if (ret) { - dev_err(hdmi->dev, "adding encoder failed: %d\n", ret); - return ret; - } + drm_encoder_init(drm, &hdmi->encoder, &imx_hdmi_encoder_funcs, + DRM_MODE_ENCODER_TMDS); drm_connector_helper_add(&hdmi->connector, &imx_hdmi_connector_helper_funcs); - - ret = imx_drm_add_connector(&hdmi->connector, - &hdmi->imx_drm_connector, THIS_MODULE); - if (ret) { - imx_drm_remove_encoder(hdmi->imx_drm_encoder); - dev_err(hdmi->dev, "adding connector failed: %d\n", ret); - return ret; - } + drm_connector_init(drm, &hdmi->connector, &imx_hdmi_connector_funcs, + DRM_MODE_CONNECTOR_HDMIA); hdmi->connector.encoder = &hdmi->encoder; @@ -1755,21 +1584,26 @@ static const struct of_device_id imx_hdmi_dt_ids[] = { }; MODULE_DEVICE_TABLE(of, imx_hdmi_dt_ids); -static int imx_hdmi_platform_probe(struct platform_device *pdev) +static int imx_hdmi_bind(struct device *dev, struct device *master, void *data) { + struct platform_device *pdev = to_platform_device(dev); const struct of_device_id *of_id = - of_match_device(imx_hdmi_dt_ids, &pdev->dev); - struct device_node *np = pdev->dev.of_node; + of_match_device(imx_hdmi_dt_ids, dev); + struct drm_device *drm = data; + struct device_node *np = dev->of_node; struct device_node *ddc_node; struct imx_hdmi *hdmi; struct resource *iores; int ret, irq; - hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL); + hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL); if (!hdmi) return -ENOMEM; - hdmi->dev = &pdev->dev; + hdmi->dev = dev; + hdmi->connector_status = connector_status_disconnected; + hdmi->sample_rate = 48000; + hdmi->ratio = 100; if (of_id) { const struct platform_device_id *device_id = of_id->data; @@ -1791,13 +1625,14 @@ static int imx_hdmi_platform_probe(struct platform_device *pdev) if (irq < 0) return -EINVAL; - ret = devm_request_irq(&pdev->dev, irq, imx_hdmi_irq, 0, - dev_name(&pdev->dev), hdmi); + ret = devm_request_threaded_irq(dev, irq, imx_hdmi_hardirq, + imx_hdmi_irq, IRQF_SHARED, + dev_name(dev), hdmi); if (ret) return ret; iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); - hdmi->regs = devm_ioremap_resource(&pdev->dev, iores); + hdmi->regs = devm_ioremap_resource(dev, iores); if (IS_ERR(hdmi->regs)) return PTR_ERR(hdmi->regs); @@ -1836,7 +1671,7 @@ static int imx_hdmi_platform_probe(struct platform_device *pdev) } /* Product and revision IDs */ - dev_info(&pdev->dev, + dev_info(dev, "Detected HDMI controller 0x%x:0x%x:0x%x:0x%x\n", hdmi_readb(hdmi, HDMI_DESIGN_ID), hdmi_readb(hdmi, HDMI_REVISION_ID), @@ -1864,13 +1699,14 @@ static int imx_hdmi_platform_probe(struct platform_device *pdev) if (ret) goto err_iahb; - ret = imx_hdmi_register(hdmi); + ret = imx_hdmi_register(drm, hdmi); if (ret) goto err_iahb; - imx_drm_encoder_add_possible_crtcs(hdmi->imx_drm_encoder, np); + /* Unmute interrupts */ + hdmi_writeb(hdmi, ~HDMI_IH_PHY_STAT0_HPD, HDMI_IH_MUTE_PHY_STAT0); - platform_set_drvdata(pdev, hdmi); + dev_set_drvdata(dev, hdmi); return 0; @@ -1882,20 +1718,35 @@ err_isfr: return ret; } -static int imx_hdmi_platform_remove(struct platform_device *pdev) +static void imx_hdmi_unbind(struct device *dev, struct device *master, + void *data) { - struct imx_hdmi *hdmi = platform_get_drvdata(pdev); - struct drm_connector *connector = &hdmi->connector; - struct drm_encoder *encoder = &hdmi->encoder; + struct imx_hdmi *hdmi = dev_get_drvdata(dev); - drm_mode_connector_detach_encoder(connector, encoder); - imx_drm_remove_connector(hdmi->imx_drm_connector); - imx_drm_remove_encoder(hdmi->imx_drm_encoder); + /* Disable all interrupts */ + hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0); + + hdmi->connector.funcs->destroy(&hdmi->connector); + hdmi->encoder.funcs->destroy(&hdmi->encoder); clk_disable_unprepare(hdmi->iahb_clk); clk_disable_unprepare(hdmi->isfr_clk); i2c_put_adapter(hdmi->ddc); +} + +static const struct component_ops hdmi_ops = { + .bind = imx_hdmi_bind, + .unbind = imx_hdmi_unbind, +}; + +static int imx_hdmi_platform_probe(struct platform_device *pdev) +{ + return component_add(&pdev->dev, &hdmi_ops); +} +static int imx_hdmi_platform_remove(struct platform_device *pdev) +{ + component_del(&pdev->dev, &hdmi_ops); return 0; } diff --git a/drivers/staging/imx-drm/imx-ldb.c b/drivers/staging/imx-drm/imx-ldb.c index 7e593296ac4..daa54df4527 100644 --- a/drivers/staging/imx-drm/imx-ldb.c +++ b/drivers/staging/imx-drm/imx-ldb.c @@ -20,6 +20,7 @@ #include <linux/module.h> #include <linux/clk.h> +#include <linux/component.h> #include <drm/drmP.h> #include <drm/drm_fb_helper.h> #include <drm/drm_crtc_helper.h> @@ -58,9 +59,8 @@ struct imx_ldb; struct imx_ldb_channel { struct imx_ldb *ldb; struct drm_connector connector; - struct imx_drm_connector *imx_drm_connector; struct drm_encoder encoder; - struct imx_drm_encoder *imx_drm_encoder; + struct device_node *child; int chno; void *edid; int edid_len; @@ -91,11 +91,6 @@ static enum drm_connector_status imx_ldb_connector_detect( return connector_status_connected; } -static void imx_ldb_connector_destroy(struct drm_connector *connector) -{ - /* do not free here */ -} - static int imx_ldb_connector_get_modes(struct drm_connector *connector) { struct imx_ldb_channel *imx_ldb_ch = con_to_imx_ldb_ch(connector); @@ -111,6 +106,8 @@ static int imx_ldb_connector_get_modes(struct drm_connector *connector) struct drm_display_mode *mode; mode = drm_mode_create(connector->dev); + if (!mode) + return -EINVAL; drm_mode_copy(mode, &imx_ldb_ch->mode); mode->type |= DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; drm_mode_probed_add(connector, mode); @@ -120,12 +117,6 @@ static int imx_ldb_connector_get_modes(struct drm_connector *connector) return num_modes; } -static int imx_ldb_connector_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) -{ - return 0; -} - static struct drm_encoder *imx_ldb_connector_best_encoder( struct drm_connector *connector) { @@ -179,8 +170,7 @@ static void imx_ldb_encoder_prepare(struct drm_encoder *encoder) u32 pixel_fmt; unsigned long serial_clk; unsigned long di_clk = mode->clock * 1000; - int mux = imx_drm_encoder_get_mux_id(imx_ldb_ch->imx_drm_encoder, - encoder->crtc); + int mux = imx_drm_encoder_get_mux_id(encoder); if (ldb->ldb_ctrl & LDB_SPLIT_MODE_EN) { /* dual channel LVDS mode */ @@ -207,8 +197,7 @@ static void imx_ldb_encoder_prepare(struct drm_encoder *encoder) pixel_fmt = V4L2_PIX_FMT_RGB24; } - imx_drm_crtc_panel_format(encoder->crtc, DRM_MODE_ENCODER_LVDS, - pixel_fmt); + imx_drm_panel_format(encoder, pixel_fmt); } static void imx_ldb_encoder_commit(struct drm_encoder *encoder) @@ -216,8 +205,7 @@ static void imx_ldb_encoder_commit(struct drm_encoder *encoder) struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder); struct imx_ldb *ldb = imx_ldb_ch->ldb; int dual = ldb->ldb_ctrl & LDB_SPLIT_MODE_EN; - int mux = imx_drm_encoder_get_mux_id(imx_ldb_ch->imx_drm_encoder, - encoder->crtc); + int mux = imx_drm_encoder_get_mux_id(encoder); if (dual) { clk_prepare_enable(ldb->clk[0]); @@ -316,26 +304,21 @@ static void imx_ldb_encoder_disable(struct drm_encoder *encoder) } } -static void imx_ldb_encoder_destroy(struct drm_encoder *encoder) -{ - /* do not free here */ -} - static struct drm_connector_funcs imx_ldb_connector_funcs = { .dpms = drm_helper_connector_dpms, .fill_modes = drm_helper_probe_single_connector_modes, .detect = imx_ldb_connector_detect, - .destroy = imx_ldb_connector_destroy, + .destroy = imx_drm_connector_destroy, }; static struct drm_connector_helper_funcs imx_ldb_connector_helper_funcs = { .get_modes = imx_ldb_connector_get_modes, .best_encoder = imx_ldb_connector_best_encoder, - .mode_valid = imx_ldb_connector_mode_valid, + .mode_valid = imx_drm_connector_mode_valid, }; static struct drm_encoder_funcs imx_ldb_encoder_funcs = { - .destroy = imx_ldb_encoder_destroy, + .destroy = imx_drm_encoder_destroy, }; static struct drm_encoder_helper_funcs imx_ldb_encoder_helper_funcs = { @@ -351,56 +334,47 @@ static int imx_ldb_get_clk(struct imx_ldb *ldb, int chno) { char clkname[16]; - sprintf(clkname, "di%d", chno); + snprintf(clkname, sizeof(clkname), "di%d", chno); ldb->clk[chno] = devm_clk_get(ldb->dev, clkname); if (IS_ERR(ldb->clk[chno])) return PTR_ERR(ldb->clk[chno]); - sprintf(clkname, "di%d_pll", chno); + snprintf(clkname, sizeof(clkname), "di%d_pll", chno); ldb->clk_pll[chno] = devm_clk_get(ldb->dev, clkname); return PTR_ERR_OR_ZERO(ldb->clk_pll[chno]); } -static int imx_ldb_register(struct imx_ldb_channel *imx_ldb_ch) +static int imx_ldb_register(struct drm_device *drm, + struct imx_ldb_channel *imx_ldb_ch) { - int ret; struct imx_ldb *ldb = imx_ldb_ch->ldb; + int ret; + + ret = imx_drm_encoder_parse_of(drm, &imx_ldb_ch->encoder, + imx_ldb_ch->child); + if (ret) + return ret; ret = imx_ldb_get_clk(ldb, imx_ldb_ch->chno); if (ret) return ret; + if (ldb->ldb_ctrl & LDB_SPLIT_MODE_EN) { - ret |= imx_ldb_get_clk(ldb, 1); + ret = imx_ldb_get_clk(ldb, 1); if (ret) return ret; } - imx_ldb_ch->connector.funcs = &imx_ldb_connector_funcs; - imx_ldb_ch->encoder.funcs = &imx_ldb_encoder_funcs; - - imx_ldb_ch->encoder.encoder_type = DRM_MODE_ENCODER_LVDS; - imx_ldb_ch->connector.connector_type = DRM_MODE_CONNECTOR_LVDS; - drm_encoder_helper_add(&imx_ldb_ch->encoder, &imx_ldb_encoder_helper_funcs); - ret = imx_drm_add_encoder(&imx_ldb_ch->encoder, - &imx_ldb_ch->imx_drm_encoder, THIS_MODULE); - if (ret) { - dev_err(ldb->dev, "adding encoder failed with %d\n", ret); - return ret; - } + drm_encoder_init(drm, &imx_ldb_ch->encoder, &imx_ldb_encoder_funcs, + DRM_MODE_ENCODER_LVDS); drm_connector_helper_add(&imx_ldb_ch->connector, &imx_ldb_connector_helper_funcs); - - ret = imx_drm_add_connector(&imx_ldb_ch->connector, - &imx_ldb_ch->imx_drm_connector, THIS_MODULE); - if (ret) { - imx_drm_remove_encoder(imx_ldb_ch->imx_drm_encoder); - dev_err(ldb->dev, "adding connector failed with %d\n", ret); - return ret; - } + drm_connector_init(drm, &imx_ldb_ch->connector, + &imx_ldb_connector_funcs, DRM_MODE_CONNECTOR_LVDS); drm_mode_connector_attach_encoder(&imx_ldb_ch->connector, &imx_ldb_ch->encoder); @@ -459,11 +433,12 @@ static const struct of_device_id imx_ldb_dt_ids[] = { }; MODULE_DEVICE_TABLE(of, imx_ldb_dt_ids); -static int imx_ldb_probe(struct platform_device *pdev) +static int imx_ldb_bind(struct device *dev, struct device *master, void *data) { - struct device_node *np = pdev->dev.of_node; + struct drm_device *drm = data; + struct device_node *np = dev->of_node; const struct of_device_id *of_id = - of_match_device(imx_ldb_dt_ids, &pdev->dev); + of_match_device(imx_ldb_dt_ids, dev); struct device_node *child; const u8 *edidp; struct imx_ldb *imx_ldb; @@ -473,17 +448,17 @@ static int imx_ldb_probe(struct platform_device *pdev) int ret; int i; - imx_ldb = devm_kzalloc(&pdev->dev, sizeof(*imx_ldb), GFP_KERNEL); + imx_ldb = devm_kzalloc(dev, sizeof(*imx_ldb), GFP_KERNEL); if (!imx_ldb) return -ENOMEM; imx_ldb->regmap = syscon_regmap_lookup_by_phandle(np, "gpr"); if (IS_ERR(imx_ldb->regmap)) { - dev_err(&pdev->dev, "failed to get parent regmap\n"); + dev_err(dev, "failed to get parent regmap\n"); return PTR_ERR(imx_ldb->regmap); } - imx_ldb->dev = &pdev->dev; + imx_ldb->dev = dev; if (of_id) imx_ldb->lvds_mux = of_id->data; @@ -521,7 +496,7 @@ static int imx_ldb_probe(struct platform_device *pdev) return -EINVAL; if (dual && i > 0) { - dev_warn(&pdev->dev, "dual-channel mode, ignoring second output\n"); + dev_warn(dev, "dual-channel mode, ignoring second output\n"); continue; } @@ -531,6 +506,7 @@ static int imx_ldb_probe(struct platform_device *pdev) channel = &imx_ldb->channel[i]; channel->ldb = imx_ldb; channel->chno = i; + channel->child = child; edidp = of_get_property(child, "edid", &channel->edid_len); if (edidp) { @@ -560,7 +536,7 @@ static int imx_ldb_probe(struct platform_device *pdev) break; case LVDS_BIT_MAP_JEIDA: if (datawidth == 18) { - dev_err(&pdev->dev, "JEIDA standard only supported in 24 bit\n"); + dev_err(dev, "JEIDA standard only supported in 24 bit\n"); return -EINVAL; } if (i == 0 || dual) @@ -569,38 +545,47 @@ static int imx_ldb_probe(struct platform_device *pdev) imx_ldb->ldb_ctrl |= LDB_DATA_WIDTH_CH1_24 | LDB_BIT_MAP_CH1_JEIDA; break; default: - dev_err(&pdev->dev, "data mapping not specified or invalid\n"); + dev_err(dev, "data mapping not specified or invalid\n"); return -EINVAL; } - ret = imx_ldb_register(channel); + ret = imx_ldb_register(drm, channel); if (ret) return ret; - - imx_drm_encoder_add_possible_crtcs(channel->imx_drm_encoder, child); } - platform_set_drvdata(pdev, imx_ldb); + dev_set_drvdata(dev, imx_ldb); return 0; } -static int imx_ldb_remove(struct platform_device *pdev) +static void imx_ldb_unbind(struct device *dev, struct device *master, + void *data) { - struct imx_ldb *imx_ldb = platform_get_drvdata(pdev); + struct imx_ldb *imx_ldb = dev_get_drvdata(dev); int i; for (i = 0; i < 2; i++) { struct imx_ldb_channel *channel = &imx_ldb->channel[i]; - struct drm_connector *connector = &channel->connector; - struct drm_encoder *encoder = &channel->encoder; - - drm_mode_connector_detach_encoder(connector, encoder); - imx_drm_remove_connector(channel->imx_drm_connector); - imx_drm_remove_encoder(channel->imx_drm_encoder); + channel->connector.funcs->destroy(&channel->connector); + channel->encoder.funcs->destroy(&channel->encoder); } +} + +static const struct component_ops imx_ldb_ops = { + .bind = imx_ldb_bind, + .unbind = imx_ldb_unbind, +}; +static int imx_ldb_probe(struct platform_device *pdev) +{ + return component_add(&pdev->dev, &imx_ldb_ops); +} + +static int imx_ldb_remove(struct platform_device *pdev) +{ + component_del(&pdev->dev, &imx_ldb_ops); return 0; } diff --git a/drivers/staging/imx-drm/imx-tve.c b/drivers/staging/imx-drm/imx-tve.c index 9abc7ca8b6c..50b25f1a85d 100644 --- a/drivers/staging/imx-drm/imx-tve.c +++ b/drivers/staging/imx-drm/imx-tve.c @@ -20,6 +20,7 @@ #include <linux/clk.h> #include <linux/clk-provider.h> +#include <linux/component.h> #include <linux/module.h> #include <linux/i2c.h> #include <linux/regmap.h> @@ -30,6 +31,7 @@ #include <drm/drm_fb_helper.h> #include <drm/drm_crtc_helper.h> +#include "ipu-v3/imx-ipu-v3.h" #include "imx-drm.h" #define TVE_COM_CONF_REG 0x00 @@ -110,9 +112,7 @@ enum { struct imx_tve { struct drm_connector connector; - struct imx_drm_connector *imx_drm_connector; struct drm_encoder encoder; - struct imx_drm_encoder *imx_drm_encoder; struct device *dev; spinlock_t lock; /* register lock */ bool enabled; @@ -225,11 +225,6 @@ static enum drm_connector_status imx_tve_connector_detect( return connector_status_connected; } -static void imx_tve_connector_destroy(struct drm_connector *connector) -{ - /* do not free here */ -} - static int imx_tve_connector_get_modes(struct drm_connector *connector) { struct imx_tve *tve = con_to_tve(connector); @@ -254,6 +249,11 @@ static int imx_tve_connector_mode_valid(struct drm_connector *connector, { struct imx_tve *tve = con_to_tve(connector); unsigned long rate; + int ret; + + ret = imx_drm_connector_mode_valid(connector, mode); + if (ret != MODE_OK) + return ret; /* pixel clock with 2x oversampling */ rate = clk_round_rate(tve->clk, 2000UL * mode->clock) / 2000; @@ -305,13 +305,11 @@ static void imx_tve_encoder_prepare(struct drm_encoder *encoder) switch (tve->mode) { case TVE_MODE_VGA: - imx_drm_crtc_panel_format_pins(encoder->crtc, - DRM_MODE_ENCODER_DAC, IPU_PIX_FMT_GBR24, + imx_drm_panel_format_pins(encoder, IPU_PIX_FMT_GBR24, tve->hsync_pin, tve->vsync_pin); break; case TVE_MODE_TVOUT: - imx_drm_crtc_panel_format(encoder->crtc, DRM_MODE_ENCODER_TVDAC, - V4L2_PIX_FMT_YUV444); + imx_drm_panel_format(encoder, V4L2_PIX_FMT_YUV444); break; } } @@ -364,16 +362,11 @@ static void imx_tve_encoder_disable(struct drm_encoder *encoder) tve_disable(tve); } -static void imx_tve_encoder_destroy(struct drm_encoder *encoder) -{ - /* do not free here */ -} - static struct drm_connector_funcs imx_tve_connector_funcs = { .dpms = drm_helper_connector_dpms, .fill_modes = drm_helper_probe_single_connector_modes, .detect = imx_tve_connector_detect, - .destroy = imx_tve_connector_destroy, + .destroy = imx_drm_connector_destroy, }; static struct drm_connector_helper_funcs imx_tve_connector_helper_funcs = { @@ -383,7 +376,7 @@ static struct drm_connector_helper_funcs imx_tve_connector_helper_funcs = { }; static struct drm_encoder_funcs imx_tve_encoder_funcs = { - .destroy = imx_tve_encoder_destroy, + .destroy = imx_drm_encoder_destroy, }; static struct drm_encoder_helper_funcs imx_tve_encoder_helper_funcs = { @@ -503,34 +496,27 @@ static int tve_clk_init(struct imx_tve *tve, void __iomem *base) return 0; } -static int imx_tve_register(struct imx_tve *tve) +static int imx_tve_register(struct drm_device *drm, struct imx_tve *tve) { + int encoder_type; int ret; - tve->connector.funcs = &imx_tve_connector_funcs; - tve->encoder.funcs = &imx_tve_encoder_funcs; + encoder_type = tve->mode == TVE_MODE_VGA ? + DRM_MODE_ENCODER_DAC : DRM_MODE_ENCODER_TVDAC; - tve->encoder.encoder_type = DRM_MODE_ENCODER_NONE; - tve->connector.connector_type = DRM_MODE_CONNECTOR_VGA; + ret = imx_drm_encoder_parse_of(drm, &tve->encoder, + tve->dev->of_node); + if (ret) + return ret; drm_encoder_helper_add(&tve->encoder, &imx_tve_encoder_helper_funcs); - ret = imx_drm_add_encoder(&tve->encoder, &tve->imx_drm_encoder, - THIS_MODULE); - if (ret) { - dev_err(tve->dev, "adding encoder failed with %d\n", ret); - return ret; - } + drm_encoder_init(drm, &tve->encoder, &imx_tve_encoder_funcs, + encoder_type); drm_connector_helper_add(&tve->connector, &imx_tve_connector_helper_funcs); - - ret = imx_drm_add_connector(&tve->connector, - &tve->imx_drm_connector, THIS_MODULE); - if (ret) { - imx_drm_remove_encoder(tve->imx_drm_encoder); - dev_err(tve->dev, "adding connector failed with %d\n", ret); - return ret; - } + drm_connector_init(drm, &tve->connector, &imx_tve_connector_funcs, + DRM_MODE_CONNECTOR_VGA); drm_mode_connector_attach_encoder(&tve->connector, &tve->encoder); @@ -576,9 +562,11 @@ static const int of_get_tve_mode(struct device_node *np) return -EINVAL; } -static int imx_tve_probe(struct platform_device *pdev) +static int imx_tve_bind(struct device *dev, struct device *master, void *data) { - struct device_node *np = pdev->dev.of_node; + struct platform_device *pdev = to_platform_device(dev); + struct drm_device *drm = data; + struct device_node *np = dev->of_node; struct device_node *ddc_node; struct imx_tve *tve; struct resource *res; @@ -587,11 +575,11 @@ static int imx_tve_probe(struct platform_device *pdev) int irq; int ret; - tve = devm_kzalloc(&pdev->dev, sizeof(*tve), GFP_KERNEL); + tve = devm_kzalloc(dev, sizeof(*tve), GFP_KERNEL); if (!tve) return -ENOMEM; - tve->dev = &pdev->dev; + tve->dev = dev; spin_lock_init(&tve->lock); ddc_node = of_parse_phandle(np, "ddc", 0); @@ -602,7 +590,7 @@ static int imx_tve_probe(struct platform_device *pdev) tve->mode = of_get_tve_mode(np); if (tve->mode != TVE_MODE_VGA) { - dev_err(&pdev->dev, "only VGA mode supported, currently\n"); + dev_err(dev, "only VGA mode supported, currently\n"); return -EINVAL; } @@ -611,7 +599,7 @@ static int imx_tve_probe(struct platform_device *pdev) &tve->hsync_pin); if (ret < 0) { - dev_err(&pdev->dev, "failed to get vsync pin\n"); + dev_err(dev, "failed to get vsync pin\n"); return ret; } @@ -619,40 +607,40 @@ static int imx_tve_probe(struct platform_device *pdev) &tve->vsync_pin); if (ret < 0) { - dev_err(&pdev->dev, "failed to get vsync pin\n"); + dev_err(dev, "failed to get vsync pin\n"); return ret; } } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(&pdev->dev, res); + base = devm_ioremap_resource(dev, res); if (IS_ERR(base)) return PTR_ERR(base); tve_regmap_config.lock_arg = tve; - tve->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "tve", base, + tve->regmap = devm_regmap_init_mmio_clk(dev, "tve", base, &tve_regmap_config); if (IS_ERR(tve->regmap)) { - dev_err(&pdev->dev, "failed to init regmap: %ld\n", + dev_err(dev, "failed to init regmap: %ld\n", PTR_ERR(tve->regmap)); return PTR_ERR(tve->regmap); } irq = platform_get_irq(pdev, 0); if (irq < 0) { - dev_err(&pdev->dev, "failed to get irq\n"); + dev_err(dev, "failed to get irq\n"); return irq; } - ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, + ret = devm_request_threaded_irq(dev, irq, NULL, imx_tve_irq_handler, IRQF_ONESHOT, "imx-tve", tve); if (ret < 0) { - dev_err(&pdev->dev, "failed to request irq: %d\n", ret); + dev_err(dev, "failed to request irq: %d\n", ret); return ret; } - tve->dac_reg = devm_regulator_get(&pdev->dev, "dac"); + tve->dac_reg = devm_regulator_get(dev, "dac"); if (!IS_ERR(tve->dac_reg)) { regulator_set_voltage(tve->dac_reg, 2750000, 2750000); ret = regulator_enable(tve->dac_reg); @@ -660,17 +648,17 @@ static int imx_tve_probe(struct platform_device *pdev) return ret; } - tve->clk = devm_clk_get(&pdev->dev, "tve"); + tve->clk = devm_clk_get(dev, "tve"); if (IS_ERR(tve->clk)) { - dev_err(&pdev->dev, "failed to get high speed tve clock: %ld\n", + dev_err(dev, "failed to get high speed tve clock: %ld\n", PTR_ERR(tve->clk)); return PTR_ERR(tve->clk); } /* this is the IPU DI clock input selector, can be parented to tve_di */ - tve->di_sel_clk = devm_clk_get(&pdev->dev, "di_sel"); + tve->di_sel_clk = devm_clk_get(dev, "di_sel"); if (IS_ERR(tve->di_sel_clk)) { - dev_err(&pdev->dev, "failed to get ipu di mux clock: %ld\n", + dev_err(dev, "failed to get ipu di mux clock: %ld\n", PTR_ERR(tve->di_sel_clk)); return PTR_ERR(tve->di_sel_clk); } @@ -681,42 +669,51 @@ static int imx_tve_probe(struct platform_device *pdev) ret = regmap_read(tve->regmap, TVE_COM_CONF_REG, &val); if (ret < 0) { - dev_err(&pdev->dev, "failed to read configuration register: %d\n", ret); + dev_err(dev, "failed to read configuration register: %d\n", ret); return ret; } if (val != 0x00100000) { - dev_err(&pdev->dev, "configuration register default value indicates this is not a TVEv2\n"); + dev_err(dev, "configuration register default value indicates this is not a TVEv2\n"); return -ENODEV; } /* disable cable detection for VGA mode */ ret = regmap_write(tve->regmap, TVE_CD_CONT_REG, 0); - ret = imx_tve_register(tve); + ret = imx_tve_register(drm, tve); if (ret) return ret; - ret = imx_drm_encoder_add_possible_crtcs(tve->imx_drm_encoder, np); - - platform_set_drvdata(pdev, tve); + dev_set_drvdata(dev, tve); return 0; } -static int imx_tve_remove(struct platform_device *pdev) +static void imx_tve_unbind(struct device *dev, struct device *master, + void *data) { - struct imx_tve *tve = platform_get_drvdata(pdev); - struct drm_connector *connector = &tve->connector; - struct drm_encoder *encoder = &tve->encoder; + struct imx_tve *tve = dev_get_drvdata(dev); - drm_mode_connector_detach_encoder(connector, encoder); - - imx_drm_remove_connector(tve->imx_drm_connector); - imx_drm_remove_encoder(tve->imx_drm_encoder); + tve->connector.funcs->destroy(&tve->connector); + tve->encoder.funcs->destroy(&tve->encoder); if (!IS_ERR(tve->dac_reg)) regulator_disable(tve->dac_reg); +} + +static const struct component_ops imx_tve_ops = { + .bind = imx_tve_bind, + .unbind = imx_tve_unbind, +}; +static int imx_tve_probe(struct platform_device *pdev) +{ + return component_add(&pdev->dev, &imx_tve_ops); +} + +static int imx_tve_remove(struct platform_device *pdev) +{ + component_del(&pdev->dev, &imx_tve_ops); return 0; } diff --git a/drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h b/drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h index 4826b5c0249..c4d14ead583 100644 --- a/drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h +++ b/drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h @@ -25,6 +25,8 @@ enum ipuv3_type { IPUV3H, }; +#define IPU_PIX_FMT_GBR24 v4l2_fourcc('G', 'B', 'R', '3') + /* * Bitfield of Display Interface signal polarities. */ diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-dc.c b/drivers/staging/imx-drm/ipu-v3/ipu-dc.c index d0e3bc3c53e..d5de8bb5c80 100644 --- a/drivers/staging/imx-drm/ipu-v3/ipu-dc.c +++ b/drivers/staging/imx-drm/ipu-v3/ipu-dc.c @@ -262,7 +262,7 @@ void ipu_dc_disable_channel(struct ipu_dc *dc) /* Wait for DC triple buffer to empty */ while ((readl(priv->dc_reg + DC_STAT) & val) != val) { - msleep(2); + usleep_range(2000, 20000); timeout -= 2; if (timeout <= 0) break; diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-di.c b/drivers/staging/imx-drm/ipu-v3/ipu-di.c index 948a49b289e..82a9ebad697 100644 --- a/drivers/staging/imx-drm/ipu-v3/ipu-di.c +++ b/drivers/staging/imx-drm/ipu-v3/ipu-di.c @@ -19,9 +19,6 @@ #include <linux/io.h> #include <linux/err.h> #include <linux/platform_device.h> -#include <linux/clk.h> -#include <linux/clk-provider.h> -#include <linux/clkdev.h> #include "imx-ipu-v3.h" #include "ipu-prv.h" @@ -33,10 +30,7 @@ struct ipu_di { struct clk *clk_di; /* display input clock */ struct clk *clk_ipu; /* IPU bus clock */ struct clk *clk_di_pixel; /* resulting pixel clock */ - struct clk_hw clk_hw_out; - char *clk_name; bool inuse; - unsigned long clkflags; struct ipu_soc *ipu; }; @@ -141,130 +135,6 @@ static inline void ipu_di_write(struct ipu_di *di, u32 value, unsigned offset) writel(value, di->base + offset); } -static int ipu_di_clk_calc_div(unsigned long inrate, unsigned long outrate) -{ - u64 tmp = inrate; - int div; - - tmp *= 16; - - do_div(tmp, outrate); - - div = tmp; - - if (div < 0x10) - div = 0x10; - -#ifdef WTF_IS_THIS - /* - * Freescale has this in their Kernel. It is neither clear what - * it does nor why it does it - */ - if (div & 0x10) - div &= ~0x7; - else { - /* Round up divider if it gets us closer to desired pix clk */ - if ((div & 0xC) == 0xC) { - div += 0x10; - div &= ~0xF; - } - } -#endif - return div; -} - -static unsigned long clk_di_recalc_rate(struct clk_hw *hw, - unsigned long parent_rate) -{ - struct ipu_di *di = container_of(hw, struct ipu_di, clk_hw_out); - unsigned long outrate; - u32 div = ipu_di_read(di, DI_BS_CLKGEN0); - - if (div < 0x10) - div = 0x10; - - outrate = (parent_rate / div) * 16; - - return outrate; -} - -static long clk_di_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate) -{ - struct ipu_di *di = container_of(hw, struct ipu_di, clk_hw_out); - unsigned long outrate; - int div; - u32 val; - - div = ipu_di_clk_calc_div(*prate, rate); - - outrate = (*prate / div) * 16; - - val = ipu_di_read(di, DI_GENERAL); - - if (!(val & DI_GEN_DI_CLK_EXT) && outrate > *prate / 2) - outrate = *prate / 2; - - dev_dbg(di->ipu->dev, - "%s: inrate: %ld div: 0x%08x outrate: %ld wanted: %ld\n", - __func__, *prate, div, outrate, rate); - - return outrate; -} - -static int clk_di_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) -{ - struct ipu_di *di = container_of(hw, struct ipu_di, clk_hw_out); - int div; - u32 clkgen0; - - clkgen0 = ipu_di_read(di, DI_BS_CLKGEN0) & ~0xfff; - - div = ipu_di_clk_calc_div(parent_rate, rate); - - ipu_di_write(di, clkgen0 | div, DI_BS_CLKGEN0); - - dev_dbg(di->ipu->dev, "%s: inrate: %ld desired: %ld div: 0x%08x\n", - __func__, parent_rate, rate, div); - return 0; -} - -static u8 clk_di_get_parent(struct clk_hw *hw) -{ - struct ipu_di *di = container_of(hw, struct ipu_di, clk_hw_out); - u32 val; - - val = ipu_di_read(di, DI_GENERAL); - - return val & DI_GEN_DI_CLK_EXT ? 1 : 0; -} - -static int clk_di_set_parent(struct clk_hw *hw, u8 index) -{ - struct ipu_di *di = container_of(hw, struct ipu_di, clk_hw_out); - u32 val; - - val = ipu_di_read(di, DI_GENERAL); - - if (index) - val |= DI_GEN_DI_CLK_EXT; - else - val &= ~DI_GEN_DI_CLK_EXT; - - ipu_di_write(di, val, DI_GENERAL); - - return 0; -} - -static struct clk_ops clk_di_ops = { - .round_rate = clk_di_round_rate, - .set_rate = clk_di_set_rate, - .recalc_rate = clk_di_recalc_rate, - .set_parent = clk_di_set_parent, - .get_parent = clk_di_get_parent, -}; - static void ipu_di_data_wave_config(struct ipu_di *di, int wave_gen, int access_size, int component_size) @@ -528,15 +398,125 @@ static void ipu_di_sync_config_noninterlaced(struct ipu_di *di, ipu_di_sync_config(di, cfg_vga, 0, ARRAY_SIZE(cfg_vga)); } +static void ipu_di_config_clock(struct ipu_di *di, + const struct ipu_di_signal_cfg *sig) +{ + struct clk *clk; + unsigned clkgen0; + uint32_t val; + + if (sig->clkflags & IPU_DI_CLKMODE_EXT) { + /* + * CLKMODE_EXT means we must use the DI clock: this is + * needed for things like LVDS which needs to feed the + * DI and LDB with the same pixel clock. + */ + clk = di->clk_di; + + if (sig->clkflags & IPU_DI_CLKMODE_SYNC) { + /* + * CLKMODE_SYNC means that we want the DI to be + * clocked at the same rate as the parent clock. + * This is needed (eg) for LDB which needs to be + * fed with the same pixel clock. We assume that + * the LDB clock has already been set correctly. + */ + clkgen0 = 1 << 4; + } else { + /* + * We can use the divider. We should really have + * a flag here indicating whether the bridge can + * cope with a fractional divider or not. For the + * time being, let's go for simplicitly and + * reliability. + */ + unsigned long in_rate; + unsigned div; + + clk_set_rate(clk, sig->pixelclock); + + in_rate = clk_get_rate(clk); + div = (in_rate + sig->pixelclock / 2) / sig->pixelclock; + if (div == 0) + div = 1; + + clkgen0 = div << 4; + } + } else { + /* + * For other interfaces, we can arbitarily select between + * the DI specific clock and the internal IPU clock. See + * DI_GENERAL bit 20. We select the IPU clock if it can + * give us a clock rate within 1% of the requested frequency, + * otherwise we use the DI clock. + */ + unsigned long rate, clkrate; + unsigned div, error; + + clkrate = clk_get_rate(di->clk_ipu); + div = (clkrate + sig->pixelclock / 2) / sig->pixelclock; + rate = clkrate / div; + + error = rate / (sig->pixelclock / 1000); + + dev_dbg(di->ipu->dev, " IPU clock can give %lu with divider %u, error %d.%u%%\n", + rate, div, (signed)(error - 1000) / 10, error % 10); + + /* Allow a 1% error */ + if (error < 1010 && error >= 990) { + clk = di->clk_ipu; + + clkgen0 = div << 4; + } else { + unsigned long in_rate; + unsigned div; + + clk = di->clk_di; + + clk_set_rate(clk, sig->pixelclock); + + in_rate = clk_get_rate(clk); + div = (in_rate + sig->pixelclock / 2) / sig->pixelclock; + if (div == 0) + div = 1; + + clkgen0 = div << 4; + } + } + + di->clk_di_pixel = clk; + + /* Set the divider */ + ipu_di_write(di, clkgen0, DI_BS_CLKGEN0); + + /* + * Set the high/low periods. Bits 24:16 give us the falling edge, + * and bits 8:0 give the rising edge. LSB is fraction, and is + * based on the divider above. We want a 50% duty cycle, so set + * the falling edge to be half the divider. + */ + ipu_di_write(di, (clkgen0 >> 4) << 16, DI_BS_CLKGEN1); + + /* Finally select the input clock */ + val = ipu_di_read(di, DI_GENERAL) & ~DI_GEN_DI_CLK_EXT; + if (clk == di->clk_di) + val |= DI_GEN_DI_CLK_EXT; + ipu_di_write(di, val, DI_GENERAL); + + dev_dbg(di->ipu->dev, "Want %luHz IPU %luHz DI %luHz using %s, %luHz\n", + sig->pixelclock, + clk_get_rate(di->clk_ipu), + clk_get_rate(di->clk_di), + clk == di->clk_di ? "DI" : "IPU", + clk_get_rate(di->clk_di_pixel) / (clkgen0 >> 4)); +} + int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig) { u32 reg; u32 di_gen, vsync_cnt; u32 div; u32 h_total, v_total; - int ret; - unsigned long round; - struct clk *parent; dev_dbg(di->ipu->dev, "disp %d: panel size = %d x %d\n", di->id, sig->width, sig->height); @@ -544,33 +524,20 @@ int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig) if ((sig->v_sync_width == 0) || (sig->h_sync_width == 0)) return -EINVAL; - if (sig->clkflags & IPU_DI_CLKMODE_EXT) - parent = di->clk_di; - else - parent = di->clk_ipu; - - ret = clk_set_parent(di->clk_di_pixel, parent); - if (ret) { - dev_err(di->ipu->dev, - "setting pixel clock to parent %s failed with %d\n", - __clk_get_name(parent), ret); - return ret; - } - - if (sig->clkflags & IPU_DI_CLKMODE_SYNC) - round = clk_get_rate(parent); - else - round = clk_round_rate(di->clk_di_pixel, sig->pixelclock); - - ret = clk_set_rate(di->clk_di_pixel, round); - h_total = sig->width + sig->h_sync_width + sig->h_start_width + sig->h_end_width; v_total = sig->height + sig->v_sync_width + sig->v_start_width + sig->v_end_width; + dev_dbg(di->ipu->dev, "Clocks: IPU %luHz DI %luHz Needed %luHz\n", + clk_get_rate(di->clk_ipu), + clk_get_rate(di->clk_di), + sig->pixelclock); + mutex_lock(&di_mutex); + ipu_di_config_clock(di, sig); + div = ipu_di_read(di, DI_BS_CLKGEN0) & 0xfff; div = div / 16; /* Now divider is integer portion */ @@ -654,7 +621,11 @@ EXPORT_SYMBOL_GPL(ipu_di_init_sync_panel); int ipu_di_enable(struct ipu_di *di) { - int ret = clk_prepare_enable(di->clk_di_pixel); + int ret; + + WARN_ON(IS_ERR(di->clk_di_pixel)); + + ret = clk_prepare_enable(di->clk_di_pixel); if (ret) return ret; @@ -666,6 +637,8 @@ EXPORT_SYMBOL_GPL(ipu_di_enable); int ipu_di_disable(struct ipu_di *di) { + WARN_ON(IS_ERR(di->clk_di_pixel)); + ipu_module_disable(di->ipu, di->module); clk_disable_unprepare(di->clk_di_pixel); @@ -721,13 +694,6 @@ int ipu_di_init(struct ipu_soc *ipu, struct device *dev, int id, u32 module, struct clk *clk_ipu) { struct ipu_di *di; - int ret; - const char *di_parent[2]; - struct clk_init_data init = { - .ops = &clk_di_ops, - .num_parents = 2, - .flags = 0, - }; if (id > 1) return -ENODEV; @@ -749,45 +715,16 @@ int ipu_di_init(struct ipu_soc *ipu, struct device *dev, int id, if (!di->base) return -ENOMEM; - di_parent[0] = __clk_get_name(di->clk_ipu); - di_parent[1] = __clk_get_name(di->clk_di); - ipu_di_write(di, 0x10, DI_BS_CLKGEN0); - init.parent_names = (const char **)&di_parent; - di->clk_name = kasprintf(GFP_KERNEL, "%s_di%d_pixel", - dev_name(dev), id); - if (!di->clk_name) - return -ENOMEM; - - init.name = di->clk_name; - - di->clk_hw_out.init = &init; - di->clk_di_pixel = clk_register(dev, &di->clk_hw_out); - - if (IS_ERR(di->clk_di_pixel)) { - ret = PTR_ERR(di->clk_di_pixel); - goto failed_clk_register; - } - dev_dbg(dev, "DI%d base: 0x%08lx remapped to %p\n", id, base, di->base); di->inuse = false; di->ipu = ipu; return 0; - -failed_clk_register: - - kfree(di->clk_name); - - return ret; } void ipu_di_exit(struct ipu_soc *ipu, int id) { - struct ipu_di *di = ipu->di_priv[id]; - - clk_unregister(di->clk_di_pixel); - kfree(di->clk_name); } diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-dmfc.c b/drivers/staging/imx-drm/ipu-v3/ipu-dmfc.c index 98070dd8c92..45213017fa4 100644 --- a/drivers/staging/imx-drm/ipu-v3/ipu-dmfc.c +++ b/drivers/staging/imx-drm/ipu-v3/ipu-dmfc.c @@ -161,9 +161,6 @@ static int ipu_dmfc_setup_channel(struct dmfc_channel *dmfc, int slots, "dmfc: using %d slots starting from segment %d for IPU channel %d\n", slots, segment, dmfc->data->ipu_channel); - if (!dmfc) - return -EINVAL; - switch (slots) { case 1: field = DMFC_FIFO_SIZE_64; diff --git a/drivers/staging/imx-drm/ipuv3-crtc.c b/drivers/staging/imx-drm/ipuv3-crtc.c index 22be104fbda..e646017c32a 100644 --- a/drivers/staging/imx-drm/ipuv3-crtc.c +++ b/drivers/staging/imx-drm/ipuv3-crtc.c @@ -17,6 +17,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ +#include <linux/component.h> #include <linux/module.h> #include <linux/export.h> #include <linux/device.h> @@ -284,6 +285,7 @@ static int ipu_set_interface_pix_fmt(struct drm_crtc *crtc, u32 encoder_type, ipu_crtc->di_clkflags = IPU_DI_CLKMODE_SYNC | IPU_DI_CLKMODE_EXT; break; + case DRM_MODE_ENCODER_TMDS: case DRM_MODE_ENCODER_NONE: ipu_crtc->di_clkflags = 0; break; @@ -334,7 +336,7 @@ err_out: } static int ipu_crtc_init(struct ipu_crtc *ipu_crtc, - struct ipu_client_platformdata *pdata) + struct ipu_client_platformdata *pdata, struct drm_device *drm) { struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent); int dp = -EINVAL; @@ -348,9 +350,9 @@ static int ipu_crtc_init(struct ipu_crtc *ipu_crtc, return ret; } - ret = imx_drm_add_crtc(&ipu_crtc->base, + ret = imx_drm_add_crtc(drm, &ipu_crtc->base, &ipu_crtc->imx_crtc, - &ipu_crtc_helper_funcs, THIS_MODULE, + &ipu_crtc_helper_funcs, ipu_crtc->dev->parent->of_node, pdata->di); if (ret) { dev_err(ipu_crtc->dev, "adding crtc failed with %d.\n", ret); @@ -399,43 +401,61 @@ err_put_resources: return ret; } -static int ipu_drm_probe(struct platform_device *pdev) +static int ipu_drm_bind(struct device *dev, struct device *master, void *data) { - struct ipu_client_platformdata *pdata = pdev->dev.platform_data; + struct ipu_client_platformdata *pdata = dev->platform_data; + struct drm_device *drm = data; struct ipu_crtc *ipu_crtc; int ret; - if (!pdata) - return -EINVAL; - - ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); - if (ret) - return ret; - - ipu_crtc = devm_kzalloc(&pdev->dev, sizeof(*ipu_crtc), GFP_KERNEL); + ipu_crtc = devm_kzalloc(dev, sizeof(*ipu_crtc), GFP_KERNEL); if (!ipu_crtc) return -ENOMEM; - ipu_crtc->dev = &pdev->dev; + ipu_crtc->dev = dev; - ret = ipu_crtc_init(ipu_crtc, pdata); + ret = ipu_crtc_init(ipu_crtc, pdata, drm); if (ret) return ret; - platform_set_drvdata(pdev, ipu_crtc); + dev_set_drvdata(dev, ipu_crtc); return 0; } -static int ipu_drm_remove(struct platform_device *pdev) +static void ipu_drm_unbind(struct device *dev, struct device *master, + void *data) { - struct ipu_crtc *ipu_crtc = platform_get_drvdata(pdev); + struct ipu_crtc *ipu_crtc = dev_get_drvdata(dev); imx_drm_remove_crtc(ipu_crtc->imx_crtc); ipu_plane_put_resources(ipu_crtc->plane[0]); ipu_put_resources(ipu_crtc); +} + +static const struct component_ops ipu_crtc_ops = { + .bind = ipu_drm_bind, + .unbind = ipu_drm_unbind, +}; + +static int ipu_drm_probe(struct platform_device *pdev) +{ + int ret; + if (!pdev->dev.platform_data) + return -EINVAL; + + ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); + if (ret) + return ret; + + return component_add(&pdev->dev, &ipu_crtc_ops); +} + +static int ipu_drm_remove(struct platform_device *pdev) +{ + component_del(&pdev->dev, &ipu_crtc_ops); return 0; } diff --git a/drivers/staging/imx-drm/ipuv3-plane.c b/drivers/staging/imx-drm/ipuv3-plane.c index 34b642a12f8..b0c9b6ce485 100644 --- a/drivers/staging/imx-drm/ipuv3-plane.c +++ b/drivers/staging/imx-drm/ipuv3-plane.c @@ -72,8 +72,8 @@ int ipu_plane_set_base(struct ipu_plane *ipu_plane, struct drm_framebuffer *fb, return -EFAULT; } - dev_dbg(ipu_plane->base.dev->dev, "phys = 0x%x, x = %d, y = %d", - cma_obj->paddr, x, y); + dev_dbg(ipu_plane->base.dev->dev, "phys = %pad, x = %d, y = %d", + &cma_obj->paddr, x, y); cpmem = ipu_get_cpmem(ipu_plane->ipu_ch); ipu_cpmem_set_stride(cpmem, fb->pitches[0]); diff --git a/drivers/staging/imx-drm/parallel-display.c b/drivers/staging/imx-drm/parallel-display.c index 351d61dede0..c60b6c645f4 100644 --- a/drivers/staging/imx-drm/parallel-display.c +++ b/drivers/staging/imx-drm/parallel-display.c @@ -18,10 +18,12 @@ * MA 02110-1301, USA. */ +#include <linux/component.h> #include <linux/module.h> #include <drm/drmP.h> #include <drm/drm_fb_helper.h> #include <drm/drm_crtc_helper.h> +#include <drm/drm_panel.h> #include <linux/videodev2.h> #include <video/of_display_timing.h> @@ -32,15 +34,14 @@ struct imx_parallel_display { struct drm_connector connector; - struct imx_drm_connector *imx_drm_connector; struct drm_encoder encoder; - struct imx_drm_encoder *imx_drm_encoder; struct device *dev; void *edid; int edid_len; u32 interface_pix_fmt; int mode_valid; struct drm_display_mode mode; + struct drm_panel *panel; }; static enum drm_connector_status imx_pd_connector_detect( @@ -49,17 +50,19 @@ static enum drm_connector_status imx_pd_connector_detect( return connector_status_connected; } -static void imx_pd_connector_destroy(struct drm_connector *connector) -{ - /* do not free here */ -} - static int imx_pd_connector_get_modes(struct drm_connector *connector) { struct imx_parallel_display *imxpd = con_to_imxpd(connector); struct device_node *np = imxpd->dev->of_node; int num_modes = 0; + if (imxpd->panel && imxpd->panel->funcs && + imxpd->panel->funcs->get_modes) { + num_modes = imxpd->panel->funcs->get_modes(imxpd->panel); + if (num_modes > 0) + return num_modes; + } + if (imxpd->edid) { drm_mode_connector_update_edid_property(connector, imxpd->edid); num_modes = drm_add_edid_modes(connector, imxpd->edid); @@ -67,6 +70,8 @@ static int imx_pd_connector_get_modes(struct drm_connector *connector) if (imxpd->mode_valid) { struct drm_display_mode *mode = drm_mode_create(connector->dev); + if (!mode) + return -EINVAL; drm_mode_copy(mode, &imxpd->mode); mode->type |= DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED, drm_mode_probed_add(connector, mode); @@ -75,6 +80,8 @@ static int imx_pd_connector_get_modes(struct drm_connector *connector) if (np) { struct drm_display_mode *mode = drm_mode_create(connector->dev); + if (!mode) + return -EINVAL; of_get_drm_display_mode(np, &imxpd->mode, OF_USE_NATIVE_MODE); drm_mode_copy(mode, &imxpd->mode); mode->type |= DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED, @@ -85,12 +92,6 @@ static int imx_pd_connector_get_modes(struct drm_connector *connector) return num_modes; } -static int imx_pd_connector_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode) -{ - return 0; -} - static struct drm_encoder *imx_pd_connector_best_encoder( struct drm_connector *connector) { @@ -101,6 +102,12 @@ static struct drm_encoder *imx_pd_connector_best_encoder( static void imx_pd_encoder_dpms(struct drm_encoder *encoder, int mode) { + struct imx_parallel_display *imxpd = enc_to_imxpd(encoder); + + if (mode != DRM_MODE_DPMS_ON) + drm_panel_disable(imxpd->panel); + else + drm_panel_enable(imxpd->panel); } static bool imx_pd_encoder_mode_fixup(struct drm_encoder *encoder, @@ -114,8 +121,7 @@ static void imx_pd_encoder_prepare(struct drm_encoder *encoder) { struct imx_parallel_display *imxpd = enc_to_imxpd(encoder); - imx_drm_crtc_panel_format(encoder->crtc, DRM_MODE_ENCODER_NONE, - imxpd->interface_pix_fmt); + imx_drm_panel_format(encoder, imxpd->interface_pix_fmt); } static void imx_pd_encoder_commit(struct drm_encoder *encoder) @@ -132,26 +138,21 @@ static void imx_pd_encoder_disable(struct drm_encoder *encoder) { } -static void imx_pd_encoder_destroy(struct drm_encoder *encoder) -{ - /* do not free here */ -} - static struct drm_connector_funcs imx_pd_connector_funcs = { .dpms = drm_helper_connector_dpms, .fill_modes = drm_helper_probe_single_connector_modes, .detect = imx_pd_connector_detect, - .destroy = imx_pd_connector_destroy, + .destroy = imx_drm_connector_destroy, }; static struct drm_connector_helper_funcs imx_pd_connector_helper_funcs = { .get_modes = imx_pd_connector_get_modes, .best_encoder = imx_pd_connector_best_encoder, - .mode_valid = imx_pd_connector_mode_valid, + .mode_valid = imx_drm_connector_mode_valid, }; static struct drm_encoder_funcs imx_pd_encoder_funcs = { - .destroy = imx_pd_encoder_destroy, + .destroy = imx_drm_encoder_destroy, }; static struct drm_encoder_helper_funcs imx_pd_encoder_helper_funcs = { @@ -163,51 +164,46 @@ static struct drm_encoder_helper_funcs imx_pd_encoder_helper_funcs = { .disable = imx_pd_encoder_disable, }; -static int imx_pd_register(struct imx_parallel_display *imxpd) +static int imx_pd_register(struct drm_device *drm, + struct imx_parallel_display *imxpd) { int ret; - drm_mode_connector_attach_encoder(&imxpd->connector, &imxpd->encoder); - - imxpd->connector.funcs = &imx_pd_connector_funcs; - imxpd->encoder.funcs = &imx_pd_encoder_funcs; - - imxpd->encoder.encoder_type = DRM_MODE_ENCODER_NONE; - imxpd->connector.connector_type = DRM_MODE_CONNECTOR_VGA; + ret = imx_drm_encoder_parse_of(drm, &imxpd->encoder, + imxpd->dev->of_node); + if (ret) + return ret; drm_encoder_helper_add(&imxpd->encoder, &imx_pd_encoder_helper_funcs); - ret = imx_drm_add_encoder(&imxpd->encoder, &imxpd->imx_drm_encoder, - THIS_MODULE); - if (ret) { - dev_err(imxpd->dev, "adding encoder failed with %d\n", ret); - return ret; - } + drm_encoder_init(drm, &imxpd->encoder, &imx_pd_encoder_funcs, + DRM_MODE_ENCODER_NONE); drm_connector_helper_add(&imxpd->connector, &imx_pd_connector_helper_funcs); + drm_connector_init(drm, &imxpd->connector, &imx_pd_connector_funcs, + DRM_MODE_CONNECTOR_VGA); - ret = imx_drm_add_connector(&imxpd->connector, - &imxpd->imx_drm_connector, THIS_MODULE); - if (ret) { - imx_drm_remove_encoder(imxpd->imx_drm_encoder); - dev_err(imxpd->dev, "adding connector failed with %d\n", ret); - return ret; - } + if (imxpd->panel) + drm_panel_attach(imxpd->panel, &imxpd->connector); + + drm_mode_connector_attach_encoder(&imxpd->connector, &imxpd->encoder); imxpd->connector.encoder = &imxpd->encoder; return 0; } -static int imx_pd_probe(struct platform_device *pdev) +static int imx_pd_bind(struct device *dev, struct device *master, void *data) { - struct device_node *np = pdev->dev.of_node; + struct drm_device *drm = data; + struct device_node *np = dev->of_node; + struct device_node *panel_node; const u8 *edidp; struct imx_parallel_display *imxpd; int ret; const char *fmt; - imxpd = devm_kzalloc(&pdev->dev, sizeof(*imxpd), GFP_KERNEL); + imxpd = devm_kzalloc(dev, sizeof(*imxpd), GFP_KERNEL); if (!imxpd) return -ENOMEM; @@ -225,30 +221,43 @@ static int imx_pd_probe(struct platform_device *pdev) imxpd->interface_pix_fmt = V4L2_PIX_FMT_BGR666; } - imxpd->dev = &pdev->dev; + panel_node = of_parse_phandle(np, "fsl,panel", 0); + if (panel_node) + imxpd->panel = of_drm_find_panel(panel_node); - ret = imx_pd_register(imxpd); + imxpd->dev = dev; + + ret = imx_pd_register(drm, imxpd); if (ret) return ret; - ret = imx_drm_encoder_add_possible_crtcs(imxpd->imx_drm_encoder, np); - - platform_set_drvdata(pdev, imxpd); + dev_set_drvdata(dev, imxpd); return 0; } -static int imx_pd_remove(struct platform_device *pdev) +static void imx_pd_unbind(struct device *dev, struct device *master, + void *data) { - struct imx_parallel_display *imxpd = platform_get_drvdata(pdev); - struct drm_connector *connector = &imxpd->connector; - struct drm_encoder *encoder = &imxpd->encoder; + struct imx_parallel_display *imxpd = dev_get_drvdata(dev); - drm_mode_connector_detach_encoder(connector, encoder); + imxpd->encoder.funcs->destroy(&imxpd->encoder); + imxpd->connector.funcs->destroy(&imxpd->connector); +} - imx_drm_remove_connector(imxpd->imx_drm_connector); - imx_drm_remove_encoder(imxpd->imx_drm_encoder); +static const struct component_ops imx_pd_ops = { + .bind = imx_pd_bind, + .unbind = imx_pd_unbind, +}; +static int imx_pd_probe(struct platform_device *pdev) +{ + return component_add(&pdev->dev, &imx_pd_ops); +} + +static int imx_pd_remove(struct platform_device *pdev) +{ + component_del(&pdev->dev, &imx_pd_ops); return 0; } diff --git a/drivers/staging/line6/driver.c b/drivers/staging/line6/driver.c index 7a6d85ebb29..e7a9d8dae49 100644 --- a/drivers/staging/line6/driver.c +++ b/drivers/staging/line6/driver.c @@ -217,7 +217,7 @@ static int line6_send_raw_message_async_part(struct message *msg, Setup and start timer. */ void line6_start_timer(struct timer_list *timer, unsigned int msecs, - void (*function) (unsigned long), unsigned long data) + void (*function)(unsigned long), unsigned long data) { setup_timer(timer, function, data); timer->expires = jiffies + msecs * HZ / 1000; diff --git a/drivers/staging/line6/driver.h b/drivers/staging/line6/driver.h index 34ae95e7e51..16e3fc2f1f1 100644 --- a/drivers/staging/line6/driver.h +++ b/drivers/staging/line6/driver.h @@ -204,7 +204,7 @@ extern int line6_send_sysex_message(struct usb_line6 *line6, extern ssize_t line6_set_raw(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); extern void line6_start_timer(struct timer_list *timer, unsigned int msecs, - void (*function) (unsigned long), + void (*function)(unsigned long), unsigned long data); extern int line6_transmit_parameter(struct usb_line6 *line6, int param, u8 value); diff --git a/drivers/staging/line6/usbdefs.h b/drivers/staging/line6/usbdefs.h index 90cadddec56..eda04562d57 100644 --- a/drivers/staging/line6/usbdefs.h +++ b/drivers/staging/line6/usbdefs.h @@ -91,9 +91,9 @@ enum { LINE6_BITS_PODXTALL = LINE6_BIT_PODXT | LINE6_BIT_PODXTLIVE | LINE6_BIT_PODXTPRO, LINE6_BITS_PODX3ALL = LINE6_BIT_PODX3 | LINE6_BIT_PODX3LIVE, - LINE6_BITS_PODHDALL = LINE6_BIT_PODHD300 | - LINE6_BIT_PODHD400 | - LINE6_BIT_PODHD500, + LINE6_BITS_PODHDALL = LINE6_BIT_PODHD300 | + LINE6_BIT_PODHD400 | + LINE6_BIT_PODHD500, LINE6_BITS_BASSPODXTALL = LINE6_BIT_BASSPODXT | LINE6_BIT_BASSPODXTLIVE | LINE6_BIT_BASSPODXTPRO diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c index 644a0000130..0727998a766 100644 --- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c +++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c @@ -41,7 +41,7 @@ #include "o2iblnd.h" #include <asm/div64.h> -lnd_t the_o2iblnd = { +static lnd_t the_o2iblnd = { .lnd_type = O2IBLND, .lnd_startup = kiblnd_startup, .lnd_shutdown = kiblnd_shutdown, @@ -53,8 +53,8 @@ lnd_t the_o2iblnd = { kib_data_t kiblnd_data; -__u32 -kiblnd_cksum (void *ptr, int nob) +static __u32 +kiblnd_cksum(void *ptr, int nob) { char *c = ptr; __u32 sum = 0; @@ -429,8 +429,8 @@ kiblnd_unlink_peer_locked (kib_peer_t *peer) kiblnd_peer_decref(peer); } -int -kiblnd_get_peer_info (lnet_ni_t *ni, int index, +static int +kiblnd_get_peer_info(lnet_ni_t *ni, int index, lnet_nid_t *nidp, int *count) { kib_peer_t *peer; @@ -468,8 +468,8 @@ kiblnd_get_peer_info (lnet_ni_t *ni, int index, return -ENOENT; } -void -kiblnd_del_peer_locked (kib_peer_t *peer) +static void +kiblnd_del_peer_locked(kib_peer_t *peer) { struct list_head *ctmp; struct list_head *cnxt; @@ -489,8 +489,8 @@ kiblnd_del_peer_locked (kib_peer_t *peer) * last ref on it. */ } -int -kiblnd_del_peer (lnet_ni_t *ni, lnet_nid_t nid) +static int +kiblnd_del_peer(lnet_ni_t *ni, lnet_nid_t nid) { LIST_HEAD (zombies); struct list_head *ptmp; @@ -543,8 +543,8 @@ kiblnd_del_peer (lnet_ni_t *ni, lnet_nid_t nid) return rc; } -kib_conn_t * -kiblnd_get_conn_by_idx (lnet_ni_t *ni, int index) +static kib_conn_t * +kiblnd_get_conn_by_idx(lnet_ni_t *ni, int index) { kib_peer_t *peer; struct list_head *ptmp; @@ -584,16 +584,16 @@ kiblnd_get_conn_by_idx (lnet_ni_t *ni, int index) return NULL; } -void -kiblnd_debug_rx (kib_rx_t *rx) +static void +kiblnd_debug_rx(kib_rx_t *rx) { CDEBUG(D_CONSOLE, " %p status %d msg_type %x cred %d\n", rx, rx->rx_status, rx->rx_msg->ibm_type, rx->rx_msg->ibm_credits); } -void -kiblnd_debug_tx (kib_tx_t *tx) +static void +kiblnd_debug_tx(kib_tx_t *tx) { CDEBUG(D_CONSOLE, " %p snd %d q %d w %d rc %d dl %lx " "cookie "LPX64" msg %s%s type %x cred %d\n", @@ -604,8 +604,8 @@ kiblnd_debug_tx (kib_tx_t *tx) tx->tx_msg->ibm_type, tx->tx_msg->ibm_credits); } -void -kiblnd_debug_conn (kib_conn_t *conn) +static void +kiblnd_debug_conn(kib_conn_t *conn) { struct list_head *tmp; int i; @@ -1039,8 +1039,8 @@ kiblnd_close_stale_conns_locked (kib_peer_t *peer, return count; } -int -kiblnd_close_matching_conns (lnet_ni_t *ni, lnet_nid_t nid) +static int +kiblnd_close_matching_conns(lnet_ni_t *ni, lnet_nid_t nid) { kib_peer_t *peer; struct list_head *ptmp; @@ -1440,7 +1440,7 @@ kiblnd_find_rd_dma_mr(kib_hca_dev_t *hdev, kib_rdma_desc_t *rd) return mr; } -void +static void kiblnd_destroy_fmr_pool(kib_fmr_pool_t *pool) { LASSERT (pool->fpo_map_count == 0); @@ -1454,7 +1454,7 @@ kiblnd_destroy_fmr_pool(kib_fmr_pool_t *pool) LIBCFS_FREE(pool, sizeof(kib_fmr_pool_t)); } -void +static void kiblnd_destroy_fmr_pool_list(struct list_head *head) { kib_fmr_pool_t *pool; @@ -1480,7 +1480,7 @@ static int kiblnd_fmr_flush_trigger(int ncpts) return max(IBLND_FMR_POOL_FLUSH, size); } -int +static int kiblnd_create_fmr_pool(kib_fmr_poolset_t *fps, kib_fmr_pool_t **pp_fpo) { /* FMR pool for RDMA */ @@ -1719,7 +1719,7 @@ kiblnd_init_pool(kib_poolset_t *ps, kib_pool_t *pool, int size) pool->po_size = size; } -void +static void kiblnd_destroy_pool_list(struct list_head *head) { kib_pool_t *pool; @@ -2192,7 +2192,7 @@ kiblnd_tx_init(kib_pool_t *pool, struct list_head *node) tx->tx_cookie = tps->tps_next_tx_cookie ++; } -void +static void kiblnd_net_fini_pools(kib_net_t *net) { int i; @@ -2234,7 +2234,7 @@ kiblnd_net_fini_pools(kib_net_t *net) } } -int +static int kiblnd_net_init_pools(kib_net_t *net, __u32 *cpts, int ncpts) { unsigned long flags; @@ -2408,7 +2408,7 @@ kiblnd_hdev_get_attr(kib_hca_dev_t *hdev) return -EINVAL; } -void +static void kiblnd_hdev_cleanup_mrs(kib_hca_dev_t *hdev) { int i; @@ -2442,7 +2442,7 @@ kiblnd_hdev_destroy(kib_hca_dev_t *hdev) LIBCFS_FREE(hdev, sizeof(*hdev)); } -int +static int kiblnd_hdev_setup_mrs(kib_hca_dev_t *hdev) { struct ib_mr *mr; @@ -2746,7 +2746,7 @@ kiblnd_destroy_dev (kib_dev_t *dev) LIBCFS_FREE(dev, sizeof(*dev)); } -kib_dev_t * +static kib_dev_t * kiblnd_create_dev(char *ifname) { struct net_device *netdev; @@ -2800,7 +2800,7 @@ kiblnd_create_dev(char *ifname) return dev; } -void +static void kiblnd_base_shutdown(void) { struct kib_sched_info *sched; @@ -2940,7 +2940,7 @@ out: return; } -int +static int kiblnd_base_startup(void) { struct kib_sched_info *sched; @@ -3030,7 +3030,7 @@ kiblnd_base_startup(void) return -ENETDOWN; } -int +static int kiblnd_start_schedulers(struct kib_sched_info *sched) { int rc = 0; @@ -3071,7 +3071,7 @@ kiblnd_start_schedulers(struct kib_sched_info *sched) return rc; } -int +static int kiblnd_dev_start_threads(kib_dev_t *dev, int newdev, __u32 *cpts, int ncpts) { int cpt; @@ -3097,7 +3097,7 @@ kiblnd_dev_start_threads(kib_dev_t *dev, int newdev, __u32 *cpts, int ncpts) return 0; } -kib_dev_t * +static kib_dev_t * kiblnd_dev_search(char *ifname) { kib_dev_t *alias = NULL; @@ -3226,13 +3226,13 @@ failed: return -ENETDOWN; } -void __exit +static void __exit kiblnd_module_fini (void) { lnet_unregister_lnd(&the_o2iblnd); } -int __init +static int __init kiblnd_module_init (void) { int rc; diff --git a/drivers/staging/lustre/lustre/include/cl_object.h b/drivers/staging/lustre/lustre/include/cl_object.h index 4d692dcd96c..76e1b68b38e 100644 --- a/drivers/staging/lustre/lustre/include/cl_object.h +++ b/drivers/staging/lustre/lustre/include/cl_object.h @@ -2392,7 +2392,11 @@ struct cl_io { /** * file is released, restore has to to be triggered by vvp layer */ - ci_restore_needed:1; + ci_restore_needed:1, + /** + * O_NOATIME + */ + ci_noatime:1; /** * Number of pages owned by this IO. For invariant checking. */ diff --git a/drivers/staging/lustre/lustre/include/lustre/lustre_idl.h b/drivers/staging/lustre/lustre/include/lustre/lustre_idl.h index 4183a359f1f..5f5b0ba9ea9 100644 --- a/drivers/staging/lustre/lustre/include/lustre/lustre_idl.h +++ b/drivers/staging/lustre/lustre/include/lustre/lustre_idl.h @@ -1305,6 +1305,7 @@ extern void lustre_swab_ptlrpc_body(struct ptlrpc_body *pb); #define OBD_CONNECT_SHORTIO 0x2000000000000ULL/* short io */ #define OBD_CONNECT_PINGLESS 0x4000000000000ULL/* pings not required */ #define OBD_CONNECT_FLOCK_DEAD 0x8000000000000ULL/* flock deadlock detection */ +#define OBD_CONNECT_DISP_STRIPE 0x10000000000000ULL/*create stripe disposition*/ /* XXX README XXX: * Please DO NOT add flag values here before first ensuring that this same @@ -1344,7 +1345,9 @@ extern void lustre_swab_ptlrpc_body(struct ptlrpc_body *pb); OBD_CONNECT_LIGHTWEIGHT | OBD_CONNECT_UMASK | \ OBD_CONNECT_LVB_TYPE | OBD_CONNECT_LAYOUTLOCK |\ OBD_CONNECT_PINGLESS | OBD_CONNECT_MAX_EASIZE |\ - OBD_CONNECT_FLOCK_DEAD) + OBD_CONNECT_FLOCK_DEAD | \ + OBD_CONNECT_DISP_STRIPE) + #define OST_CONNECT_SUPPORTED (OBD_CONNECT_SRVLOCK | OBD_CONNECT_GRANT | \ OBD_CONNECT_REQPORTAL | OBD_CONNECT_VERSION | \ OBD_CONNECT_TRUNCLOCK | OBD_CONNECT_INDEX | \ @@ -2109,19 +2112,32 @@ extern void lustre_swab_generic_32s (__u32 *val); #define DISP_LOOKUP_POS 0x00000008 #define DISP_OPEN_CREATE 0x00000010 #define DISP_OPEN_OPEN 0x00000020 -#define DISP_ENQ_COMPLETE 0x00400000 +#define DISP_ENQ_COMPLETE 0x00400000 /* obsolete and unused */ #define DISP_ENQ_OPEN_REF 0x00800000 #define DISP_ENQ_CREATE_REF 0x01000000 #define DISP_OPEN_LOCK 0x02000000 #define DISP_OPEN_LEASE 0x04000000 +#define DISP_OPEN_STRIPE 0x08000000 /* INODE LOCK PARTS */ -#define MDS_INODELOCK_LOOKUP 0x000001 /* dentry, mode, owner, group */ -#define MDS_INODELOCK_UPDATE 0x000002 /* size, links, timestamps */ -#define MDS_INODELOCK_OPEN 0x000004 /* For opened files */ -#define MDS_INODELOCK_LAYOUT 0x000008 /* for layout */ -#define MDS_INODELOCK_PERM 0x000010 /* for permission */ -#define MDS_INODELOCK_XATTR 0x000020 /* extended attributes */ +#define MDS_INODELOCK_LOOKUP 0x000001 /* For namespace, dentry etc, and also + * was used to protect permission (mode, + * owner, group etc) before 2.4. */ +#define MDS_INODELOCK_UPDATE 0x000002 /* size, links, timestamps */ +#define MDS_INODELOCK_OPEN 0x000004 /* For opened files */ +#define MDS_INODELOCK_LAYOUT 0x000008 /* for layout */ + +/* The PERM bit is added int 2.4, and it is used to protect permission(mode, + * owner, group, acl etc), so to separate the permission from LOOKUP lock. + * Because for remote directories(in DNE), these locks will be granted by + * different MDTs(different ldlm namespace). + * + * For local directory, MDT will always grant UPDATE_LOCK|PERM_LOCK together. + * For Remote directory, the master MDT, where the remote directory is, will + * grant UPDATE_LOCK|PERM_LOCK, and the remote MDT, where the name entry is, + * will grant LOOKUP_LOCK. */ +#define MDS_INODELOCK_PERM 0x000010 +#define MDS_INODELOCK_XATTR 0x000020 /* extended attributes */ #define MDS_INODELOCK_MAXSHIFT 5 /* This FULL lock is useful to take on unlink sort of operations */ diff --git a/drivers/staging/lustre/lustre/include/lustre_export.h b/drivers/staging/lustre/lustre/include/lustre_export.h index 2feb38b51af..6f7f48c7f2f 100644 --- a/drivers/staging/lustre/lustre/include/lustre_export.h +++ b/drivers/staging/lustre/lustre/include/lustre_export.h @@ -380,6 +380,23 @@ static inline bool imp_connect_lvb_type(struct obd_import *imp) return false; } +static inline __u64 exp_connect_ibits(struct obd_export *exp) +{ + struct obd_connect_data *ocd; + + ocd = &exp->exp_connect_data; + return ocd->ocd_ibits_known; +} + +static inline bool imp_connect_disp_stripe(struct obd_import *imp) +{ + struct obd_connect_data *ocd; + + LASSERT(imp != NULL); + ocd = &imp->imp_connect_data; + return ocd->ocd_connect_flags & OBD_CONNECT_DISP_STRIPE; +} + extern struct obd_export *class_conn2export(struct lustre_handle *conn); extern struct obd_device *class_conn2obd(struct lustre_handle *conn); diff --git a/drivers/staging/lustre/lustre/include/lustre_import.h b/drivers/staging/lustre/lustre/include/lustre_import.h index 67259eb43cd..e9833ae8b17 100644 --- a/drivers/staging/lustre/lustre/include/lustre_import.h +++ b/drivers/staging/lustre/lustre/include/lustre_import.h @@ -180,6 +180,17 @@ struct obd_import { struct list_head imp_delayed_list; /** @} */ + /** + * List of requests that are retained for committed open replay. Once + * open is committed, open replay request will be moved from the + * imp_replay_list into the imp_committed_list. + * The imp_replay_cursor is for accelerating searching during replay. + * @{ + */ + struct list_head imp_committed_list; + struct list_head *imp_replay_cursor; + /** @} */ + /** obd device for this import */ struct obd_device *imp_obd; diff --git a/drivers/staging/lustre/lustre/include/lustre_net.h b/drivers/staging/lustre/lustre/include/lustre_net.h index d8d08803542..11382abf929 100644 --- a/drivers/staging/lustre/lustre/include/lustre_net.h +++ b/drivers/staging/lustre/lustre/include/lustre_net.h @@ -2621,6 +2621,8 @@ int ptlrpc_register_rqbd(struct ptlrpc_request_buffer_desc *rqbd); * request queues, request management, etc. * @{ */ +void ptlrpc_request_committed(struct ptlrpc_request *req, int force); + void ptlrpc_init_client(int req_portal, int rep_portal, char *name, struct ptlrpc_client *); void ptlrpc_cleanup_client(struct obd_import *imp); diff --git a/drivers/staging/lustre/lustre/include/obd.h b/drivers/staging/lustre/lustre/include/obd.h index c3470ce62cf..1b386955add 100644 --- a/drivers/staging/lustre/lustre/include/obd.h +++ b/drivers/staging/lustre/lustre/include/obd.h @@ -1323,7 +1323,8 @@ struct md_open_data { struct obd_client_handle *mod_och; struct ptlrpc_request *mod_open_req; struct ptlrpc_request *mod_close_req; - atomic_t mod_refcount; + atomic_t mod_refcount; + bool mod_is_create; }; struct lookup_intent; @@ -1392,7 +1393,7 @@ struct md_ops { int (*m_set_open_replay_data)(struct obd_export *, struct obd_client_handle *, - struct ptlrpc_request *); + struct lookup_intent *); int (*m_clear_open_replay_data)(struct obd_export *, struct obd_client_handle *); int (*m_set_lock_data)(struct obd_export *, __u64 *, void *, __u64 *); diff --git a/drivers/staging/lustre/lustre/include/obd_class.h b/drivers/staging/lustre/lustre/include/obd_class.h index 1c2ba19bd98..0a188207014 100644 --- a/drivers/staging/lustre/lustre/include/obd_class.h +++ b/drivers/staging/lustre/lustre/include/obd_class.h @@ -2001,11 +2001,11 @@ static inline int md_getxattr(struct obd_export *exp, static inline int md_set_open_replay_data(struct obd_export *exp, struct obd_client_handle *och, - struct ptlrpc_request *open_req) + struct lookup_intent *it) { EXP_CHECK_MD_OP(exp, set_open_replay_data); EXP_MD_COUNTER_INCREMENT(exp, set_open_replay_data); - return MDP(exp->exp_obd, set_open_replay_data)(exp, och, open_req); + return MDP(exp->exp_obd, set_open_replay_data)(exp, och, it); } static inline int md_clear_open_replay_data(struct obd_export *exp, diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_lockd.c b/drivers/staging/lustre/lustre/ldlm/ldlm_lockd.c index 3ed020eb89c..d87048dcc70 100644 --- a/drivers/staging/lustre/lustre/ldlm/ldlm_lockd.c +++ b/drivers/staging/lustre/lustre/ldlm/ldlm_lockd.c @@ -228,6 +228,7 @@ static void ldlm_handle_cp_callback(struct ptlrpc_request *req, lock_res_and_lock(lock); LASSERT(lock->l_lvb_data == NULL); + lock->l_lvb_type = LVB_T_LAYOUT; lock->l_lvb_data = lvb_data; lock->l_lvb_len = lvb_len; unlock_res_and_lock(lock); diff --git a/drivers/staging/lustre/lustre/libcfs/linux/linux-cpu.c b/drivers/staging/lustre/lustre/libcfs/linux/linux-cpu.c index 58bb256ee04..77b1ef64ecc 100644 --- a/drivers/staging/lustre/lustre/libcfs/linux/linux-cpu.c +++ b/drivers/staging/lustre/lustre/libcfs/linux/linux-cpu.c @@ -952,6 +952,7 @@ static int cfs_cpu_notify(struct notifier_block *self, unsigned long action, void *hcpu) { unsigned int cpu = (unsigned long)hcpu; + bool warn; switch (action) { case CPU_DEAD: @@ -962,9 +963,21 @@ cfs_cpu_notify(struct notifier_block *self, unsigned long action, void *hcpu) cpt_data.cpt_version++; spin_unlock(&cpt_data.cpt_lock); default: - CWARN("Lustre: can't support CPU hotplug well now, " - "performance and stability could be impacted" - "[CPU %u notify: %lx]\n", cpu, action); + if (action != CPU_DEAD && action != CPU_DEAD_FROZEN) { + CDEBUG(D_INFO, "CPU changed [cpu %u action %lx]\n", + cpu, action); + break; + } + + down(&cpt_data.cpt_mutex); + /* if all HTs in a core are offline, it may break affinity */ + cfs_cpu_ht_siblings(cpu, cpt_data.cpt_cpumask); + warn = any_online_cpu(*cpt_data.cpt_cpumask) >= nr_cpu_ids; + up(&cpt_data.cpt_mutex); + CDEBUG(warn ? D_WARNING : D_INFO, + "Lustre: can't support CPU plug-out well now, " + "performance and stability could be impacted " + "[CPU %u action: %lx]\n", cpu, action); } return NOTIFY_OK; diff --git a/drivers/staging/lustre/lustre/libcfs/workitem.c b/drivers/staging/lustre/lustre/libcfs/workitem.c index 1a55c81892e..53813fca536 100644 --- a/drivers/staging/lustre/lustre/libcfs/workitem.c +++ b/drivers/staging/lustre/lustre/libcfs/workitem.c @@ -389,11 +389,11 @@ cfs_wi_sched_create(char *name, struct cfs_cpt_table *cptab, spin_unlock(&cfs_wi_data.wi_glock); if (sched->ws_cptab != NULL && sched->ws_cpt >= 0) { - snprintf(name, sizeof(name), "%s_%02d_%02d", + snprintf(name, sizeof(name), "%s_%02d_%02u", sched->ws_name, sched->ws_cpt, sched->ws_nthreads); } else { - snprintf(name, sizeof(name), "%s_%02d", + snprintf(name, sizeof(name), "%s_%02u", sched->ws_name, sched->ws_nthreads); } diff --git a/drivers/staging/lustre/lustre/llite/dcache.c b/drivers/staging/lustre/lustre/llite/dcache.c index 3907c87c2ba..f971a543cb5 100644 --- a/drivers/staging/lustre/lustre/llite/dcache.c +++ b/drivers/staging/lustre/lustre/llite/dcache.c @@ -241,9 +241,6 @@ void ll_intent_release(struct lookup_intent *it) ptlrpc_req_finished(it->d.lustre.it_data); /* ll_file_open */ if (it_disposition(it, DISP_ENQ_CREATE_REF)) /* create rec */ ptlrpc_req_finished(it->d.lustre.it_data); - if (it_disposition(it, DISP_ENQ_COMPLETE)) /* saved req from revalidate - * to lookup */ - ptlrpc_req_finished(it->d.lustre.it_data); it->d.lustre.it_disposition = 0; it->d.lustre.it_data = NULL; @@ -328,262 +325,32 @@ void ll_frob_intent(struct lookup_intent **itp, struct lookup_intent *deft) } -int ll_revalidate_it(struct dentry *de, int lookup_flags, - struct lookup_intent *it) +static int ll_revalidate_dentry(struct dentry *dentry, + unsigned int lookup_flags) { - struct md_op_data *op_data; - struct ptlrpc_request *req = NULL; - struct lookup_intent lookup_it = { .it_op = IT_LOOKUP }; - struct obd_export *exp; - struct inode *parent = de->d_parent->d_inode; - int rc; - - CDEBUG(D_VFSTRACE, "VFS Op:name=%s,intent=%s\n", de->d_name.name, - LL_IT2STR(it)); - - LASSERT(de != de->d_sb->s_root); - - if (de->d_inode == NULL) { - __u64 ibits; - - /* We can only use negative dentries if this is stat or lookup, - for opens and stuff we do need to query server. */ - /* If there is IT_CREAT in intent op set, then we must throw - away this negative dentry and actually do the request to - kernel to create whatever needs to be created (if possible)*/ - if (it && (it->it_op & IT_CREAT)) - return 0; + struct inode *dir = dentry->d_parent->d_inode; - if (d_lustre_invalid(de)) - return 0; - - ibits = MDS_INODELOCK_UPDATE; - rc = ll_have_md_lock(parent, &ibits, LCK_MINMODE); - GOTO(out_sa, rc); - } - - /* Never execute intents for mount points. - * Attributes will be fixed up in ll_inode_revalidate_it */ - if (d_mountpoint(de)) - GOTO(out_sa, rc = 1); - - exp = ll_i2mdexp(de->d_inode); - - OBD_FAIL_TIMEOUT(OBD_FAIL_MDC_REVALIDATE_PAUSE, 5); - ll_frob_intent(&it, &lookup_it); - LASSERT(it); + /* + * if open&create is set, talk to MDS to make sure file is created if + * necessary, because we can't do this in ->open() later since that's + * called on an inode. return 0 here to let lookup to handle this. + */ + if ((lookup_flags & (LOOKUP_OPEN | LOOKUP_CREATE)) == + (LOOKUP_OPEN | LOOKUP_CREATE)) + return 0; - if (it->it_op == IT_LOOKUP && !d_lustre_invalid(de)) + if (lookup_flags & (LOOKUP_PARENT | LOOKUP_OPEN | LOOKUP_CREATE)) return 1; - if (it->it_op == IT_OPEN) { - struct inode *inode = de->d_inode; - struct ll_inode_info *lli = ll_i2info(inode); - struct obd_client_handle **och_p; - __u64 ibits; - - /* - * We used to check for MDS_INODELOCK_OPEN here, but in fact - * just having LOOKUP lock is enough to justify inode is the - * same. And if inode is the same and we have suitable - * openhandle, then there is no point in doing another OPEN RPC - * just to throw away newly received openhandle. There are no - * security implications too, if file owner or access mode is - * change, LOOKUP lock is revoked. - */ - - - if (it->it_flags & FMODE_WRITE) - och_p = &lli->lli_mds_write_och; - else if (it->it_flags & FMODE_EXEC) - och_p = &lli->lli_mds_exec_och; - else - och_p = &lli->lli_mds_read_och; - - /* Check for the proper lock. */ - ibits = MDS_INODELOCK_LOOKUP; - if (!ll_have_md_lock(inode, &ibits, LCK_MINMODE)) - goto do_lock; - mutex_lock(&lli->lli_och_mutex); - if (*och_p) { /* Everything is open already, do nothing */ - /* Originally it was idea to do not let them steal our - * open handle from under us by (*och_usecount)++ here. - * But in case we have the handle, but we cannot use it - * due to later checks (e.g. O_CREAT|O_EXCL flags set), - * nobody would decrement counter increased here. So we - * just hope the lock won't be invalidated in between. - * But if it would be, we'll reopen the open request to - * MDS later during file open path. - */ - mutex_unlock(&lli->lli_och_mutex); - return 1; - } - mutex_unlock(&lli->lli_och_mutex); - } - - if (it->it_op == IT_GETATTR) { - rc = ll_statahead_enter(parent, &de, 0); - if (rc == 1) - goto mark; - else if (rc != -EAGAIN && rc != 0) - GOTO(out, rc = 0); - } - -do_lock: - op_data = ll_prep_md_op_data(NULL, parent, de->d_inode, - de->d_name.name, de->d_name.len, - 0, LUSTRE_OPC_ANY, NULL); - if (IS_ERR(op_data)) - return PTR_ERR(op_data); - - if (!IS_POSIXACL(parent) || !exp_connect_umask(exp)) - it->it_create_mode &= ~current_umask(); - it->it_create_mode |= M_CHECK_STALE; - rc = md_intent_lock(exp, op_data, NULL, 0, it, - lookup_flags, - &req, ll_md_blocking_ast, 0); - it->it_create_mode &= ~M_CHECK_STALE; - ll_finish_md_op_data(op_data); - - /* If req is NULL, then md_intent_lock only tried to do a lock match; - * if all was well, it will return 1 if it found locks, 0 otherwise. */ - if (req == NULL && rc >= 0) { - if (!rc) - goto do_lookup; - GOTO(out, rc); - } - - if (rc < 0) { - if (rc != -ESTALE) { - CDEBUG(D_INFO, "ll_intent_lock: rc %d : it->it_status " - "%d\n", rc, it->d.lustre.it_status); - } - GOTO(out, rc = 0); - } - -revalidate_finish: - rc = ll_revalidate_it_finish(req, it, de); - if (rc != 0) { - if (rc != -ESTALE && rc != -ENOENT) - ll_intent_release(it); - GOTO(out, rc = 0); - } - - if ((it->it_op & IT_OPEN) && de->d_inode && - !S_ISREG(de->d_inode->i_mode) && - !S_ISDIR(de->d_inode->i_mode)) { - ll_release_openhandle(de, it); - } - rc = 1; - -out: - /* We do not free request as it may be reused during following lookup - * (see comment in mdc/mdc_locks.c::mdc_intent_lock()), request will - * be freed in ll_lookup_it or in ll_intent_release. But if - * request was not completed, we need to free it. (bug 5154, 9903) */ - if (req != NULL && !it_disposition(it, DISP_ENQ_COMPLETE)) - ptlrpc_req_finished(req); - if (rc == 0) { - /* mdt may grant layout lock for the newly created file, so - * release the lock to avoid leaking */ - ll_intent_drop_lock(it); - ll_invalidate_aliases(de->d_inode); - } else { - __u64 bits = 0; - __u64 matched_bits = 0; - - CDEBUG(D_DENTRY, "revalidated dentry %.*s (%p) parent %p " - "inode %p refc %d\n", de->d_name.len, - de->d_name.name, de, de->d_parent, de->d_inode, - d_count(de)); - - ll_set_lock_data(exp, de->d_inode, it, &bits); - - /* Note: We have to match both LOOKUP and PERM lock - * here to make sure the dentry is valid and no one - * changing the permission. - * But if the client connects < 2.4 server, which will - * only grant LOOKUP lock, so we can only Match LOOKUP - * lock for old server */ - if (exp_connect_flags(ll_i2mdexp(de->d_inode)) && - OBD_CONNECT_LVB_TYPE) - matched_bits = - MDS_INODELOCK_LOOKUP | MDS_INODELOCK_PERM; - else - matched_bits = MDS_INODELOCK_LOOKUP; - - if (((bits & matched_bits) == matched_bits) && - d_lustre_invalid(de)) - d_lustre_revalidate(de); - ll_lookup_finish_locks(it, de); - } - -mark: - if (it != NULL && it->it_op == IT_GETATTR && rc > 0) - ll_statahead_mark(parent, de); - return rc; + if (d_need_statahead(dir, dentry) <= 0) + return 1; - /* - * This part is here to combat evil-evil race in real_lookup on 2.6 - * kernels. The race details are: We enter do_lookup() looking for some - * name, there is nothing in dcache for this name yet and d_lookup() - * returns NULL. We proceed to real_lookup(), and while we do this, - * another process does open on the same file we looking up (most simple - * reproducer), open succeeds and the dentry is added. Now back to - * us. In real_lookup() we do d_lookup() again and suddenly find the - * dentry, so we call d_revalidate on it, but there is no lock, so - * without this code we would return 0, but unpatched real_lookup just - * returns -ENOENT in such a case instead of retrying the lookup. Once - * this is dealt with in real_lookup(), all of this ugly mess can go and - * we can just check locks in ->d_revalidate without doing any RPCs - * ever. - */ -do_lookup: - if (it != &lookup_it) { - /* MDS_INODELOCK_UPDATE needed for IT_GETATTR case. */ - if (it->it_op == IT_GETATTR) - lookup_it.it_op = IT_GETATTR; - ll_lookup_finish_locks(it, de); - it = &lookup_it; - } + if (lookup_flags & LOOKUP_RCU) + return -ECHILD; - /* Do real lookup here. */ - op_data = ll_prep_md_op_data(NULL, parent, NULL, de->d_name.name, - de->d_name.len, 0, (it->it_op & IT_CREAT ? - LUSTRE_OPC_CREATE : - LUSTRE_OPC_ANY), NULL); - if (IS_ERR(op_data)) - return PTR_ERR(op_data); - - rc = md_intent_lock(exp, op_data, NULL, 0, it, 0, &req, - ll_md_blocking_ast, 0); - if (rc >= 0) { - struct mdt_body *mdt_body; - struct lu_fid fid = {.f_seq = 0, .f_oid = 0, .f_ver = 0}; - mdt_body = req_capsule_server_get(&req->rq_pill, &RMF_MDT_BODY); - - if (de->d_inode) - fid = *ll_inode2fid(de->d_inode); - - /* see if we got same inode, if not - return error */ - if (lu_fid_eq(&fid, &mdt_body->fid1)) { - ll_finish_md_op_data(op_data); - op_data = NULL; - goto revalidate_finish; - } - ll_intent_release(it); - } - ll_finish_md_op_data(op_data); - GOTO(out, rc = 0); - -out_sa: - /* - * For rc == 1 case, should not return directly to prevent losing - * statahead windows; for rc == 0 case, the "lookup" will be done later. - */ - if (it != NULL && it->it_op == IT_GETATTR && rc == 1) - ll_statahead_enter(parent, &de, 1); - goto mark; + do_statahead_enter(dir, &dentry, dentry->d_inode == NULL); + ll_statahead_mark(dir, dentry); + return 1; } /* @@ -591,24 +358,13 @@ out_sa: */ int ll_revalidate_nd(struct dentry *dentry, unsigned int flags) { - struct inode *parent = dentry->d_parent->d_inode; - int unplug = 0; + int rc; - CDEBUG(D_VFSTRACE, "VFS Op:name=%s,flags=%u\n", + CDEBUG(D_VFSTRACE, "VFS Op:name=%s, flags=%u\n", dentry->d_name.name, flags); - if (!(flags & (LOOKUP_PARENT|LOOKUP_OPEN|LOOKUP_CREATE)) && - ll_need_statahead(parent, dentry) > 0) { - if (flags & LOOKUP_RCU) - return -ECHILD; - - if (dentry->d_inode == NULL) - unplug = 1; - do_statahead_enter(parent, &dentry, unplug); - ll_statahead_mark(parent, dentry); - } - - return 1; + rc = ll_revalidate_dentry(dentry, flags); + return rc; } diff --git a/drivers/staging/lustre/lustre/llite/dir.c b/drivers/staging/lustre/lustre/llite/dir.c index fd0dd20e117..7fbc18e3e65 100644 --- a/drivers/staging/lustre/lustre/llite/dir.c +++ b/drivers/staging/lustre/lustre/llite/dir.c @@ -362,7 +362,7 @@ struct page *ll_get_dir_page(struct inode *dir, __u64 hash, struct ptlrpc_request *request; struct md_op_data *op_data; - op_data = ll_prep_md_op_data(NULL, dir, NULL, NULL, 0, 0, + op_data = ll_prep_md_op_data(NULL, dir, dir, NULL, 0, 0, LUSTRE_OPC_ANY, NULL); if (IS_ERR(op_data)) return (void *)op_data; diff --git a/drivers/staging/lustre/lustre/llite/file.c b/drivers/staging/lustre/lustre/llite/file.c index 4c28f39e8b1..70b48ab30fe 100644 --- a/drivers/staging/lustre/lustre/llite/file.c +++ b/drivers/staging/lustre/lustre/llite/file.c @@ -205,7 +205,7 @@ out: return rc; } -int ll_md_real_close(struct inode *inode, int flags) +int ll_md_real_close(struct inode *inode, fmode_t fmode) { struct ll_inode_info *lli = ll_i2info(inode); struct obd_client_handle **och_p; @@ -213,30 +213,33 @@ int ll_md_real_close(struct inode *inode, int flags) __u64 *och_usecount; int rc = 0; - if (flags & FMODE_WRITE) { + if (fmode & FMODE_WRITE) { och_p = &lli->lli_mds_write_och; och_usecount = &lli->lli_open_fd_write_count; - } else if (flags & FMODE_EXEC) { + } else if (fmode & FMODE_EXEC) { och_p = &lli->lli_mds_exec_och; och_usecount = &lli->lli_open_fd_exec_count; } else { - LASSERT(flags & FMODE_READ); + LASSERT(fmode & FMODE_READ); och_p = &lli->lli_mds_read_och; och_usecount = &lli->lli_open_fd_read_count; } mutex_lock(&lli->lli_och_mutex); - if (*och_usecount) { /* There are still users of this handle, so - skip freeing it. */ + if (*och_usecount > 0) { + /* There are still users of this handle, so skip + * freeing it. */ mutex_unlock(&lli->lli_och_mutex); return 0; } + och=*och_p; *och_p = NULL; mutex_unlock(&lli->lli_och_mutex); - if (och) { /* There might be a race and somebody have freed this och - already */ + if (och != NULL) { + /* There might be a race and this handle may already + be closed. */ rc = ll_close_inode_openhandle(ll_i2sbi(inode)->ll_md_exp, inode, och, NULL); } @@ -443,8 +446,7 @@ static int ll_intent_file_open(struct file *file, void *lmm, itp, NULL); out: - ptlrpc_req_finished(itp->d.lustre.it_data); - it_clear_disposition(itp, DISP_ENQ_COMPLETE); + ptlrpc_req_finished(req); ll_intent_drop_lock(itp); return rc; @@ -477,7 +479,7 @@ static int ll_och_fill(struct obd_export *md_exp, struct lookup_intent *it, och->och_magic = OBD_CLIENT_HANDLE_MAGIC; och->och_flags = it->it_flags; - return md_set_open_replay_data(md_exp, och, req); + return md_set_open_replay_data(md_exp, och, it); } int ll_local_open(struct file *file, struct lookup_intent *it, @@ -812,10 +814,7 @@ struct obd_client_handle *ll_lease_open(struct inode *inode, struct file *file, * doesn't deal with openhandle, so normal openhandle will be leaked. */ LDLM_FL_NO_LRU | LDLM_FL_EXCL); ll_finish_md_op_data(op_data); - if (req != NULL) { - ptlrpc_req_finished(req); - it_clear_disposition(&it, DISP_ENQ_COMPLETE); - } + ptlrpc_req_finished(req); if (rc < 0) GOTO(out_release_it, rc); @@ -1032,6 +1031,33 @@ int ll_glimpse_ioctl(struct ll_sb_info *sbi, struct lov_stripe_md *lsm, return rc; } +static bool file_is_noatime(const struct file *file) +{ + const struct vfsmount *mnt = file->f_path.mnt; + const struct inode *inode = file->f_path.dentry->d_inode; + + /* Adapted from file_accessed() and touch_atime().*/ + if (file->f_flags & O_NOATIME) + return true; + + if (inode->i_flags & S_NOATIME) + return true; + + if (IS_NOATIME(inode)) + return true; + + if (mnt->mnt_flags & (MNT_NOATIME | MNT_READONLY)) + return true; + + if ((mnt->mnt_flags & MNT_NODIRATIME) && S_ISDIR(inode->i_mode)) + return true; + + if ((inode->i_sb->s_flags & MS_NODIRATIME) && S_ISDIR(inode->i_mode)) + return true; + + return false; +} + void ll_io_init(struct cl_io *io, const struct file *file, int write) { struct inode *inode = file->f_dentry->d_inode; @@ -1051,6 +1077,8 @@ void ll_io_init(struct cl_io *io, const struct file *file, int write) } else if (file->f_flags & O_APPEND) { io->ci_lockreq = CILR_MANDATORY; } + + io->ci_noatime = file_is_noatime(file); } static ssize_t @@ -2888,7 +2916,7 @@ int __ll_inode_revalidate_it(struct dentry *dentry, struct lookup_intent *it, oit.it_op = IT_LOOKUP; /* Call getattr by fid, so do not provide name at all. */ - op_data = ll_prep_md_op_data(NULL, dentry->d_parent->d_inode, + op_data = ll_prep_md_op_data(NULL, dentry->d_inode, dentry->d_inode, NULL, 0, 0, LUSTRE_OPC_ANY, NULL); if (IS_ERR(op_data)) diff --git a/drivers/staging/lustre/lustre/llite/llite_internal.h b/drivers/staging/lustre/lustre/llite/llite_internal.h index e27efd164fe..f67c5082943 100644 --- a/drivers/staging/lustre/lustre/llite/llite_internal.h +++ b/drivers/staging/lustre/lustre/llite/llite_internal.h @@ -775,7 +775,7 @@ int ll_local_open(struct file *file, int ll_release_openhandle(struct dentry *, struct lookup_intent *); int ll_md_close(struct obd_export *md_exp, struct inode *inode, struct file *file); -int ll_md_real_close(struct inode *inode, int flags); +int ll_md_real_close(struct inode *inode, fmode_t fmode); void ll_ioepoch_close(struct inode *inode, struct md_op_data *op_data, struct obd_client_handle **och, unsigned long flags); void ll_done_writing_attr(struct inode *inode, struct md_op_data *op_data); @@ -1309,7 +1309,7 @@ ll_statahead_mark(struct inode *dir, struct dentry *dentry) } static inline int -ll_need_statahead(struct inode *dir, struct dentry *dentryp) +d_need_statahead(struct inode *dir, struct dentry *dentryp) { struct ll_inode_info *lli; struct ll_dentry_data *ldd; @@ -1354,7 +1354,7 @@ ll_statahead_enter(struct inode *dir, struct dentry **dentryp, int only_unplug) { int ret; - ret = ll_need_statahead(dir, *dentryp); + ret = d_need_statahead(dir, *dentryp); if (ret <= 0) return ret; diff --git a/drivers/staging/lustre/lustre/llite/llite_lib.c b/drivers/staging/lustre/lustre/llite/llite_lib.c index 85c01e15568..7427f69e33b 100644 --- a/drivers/staging/lustre/lustre/llite/llite_lib.c +++ b/drivers/staging/lustre/lustre/llite/llite_lib.c @@ -208,7 +208,8 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt, OBD_CONNECT_LAYOUTLOCK | OBD_CONNECT_PINGLESS | OBD_CONNECT_MAX_EASIZE | - OBD_CONNECT_FLOCK_DEAD; + OBD_CONNECT_FLOCK_DEAD | + OBD_CONNECT_DISP_STRIPE; if (sbi->ll_flags & LL_SBI_SOM_PREVIEW) data->ocd_connect_flags |= OBD_CONNECT_SOM; diff --git a/drivers/staging/lustre/lustre/llite/namei.c b/drivers/staging/lustre/lustre/llite/namei.c index 93c3744e09f..86ff708c8e3 100644 --- a/drivers/staging/lustre/lustre/llite/namei.c +++ b/drivers/staging/lustre/lustre/llite/namei.c @@ -195,101 +195,107 @@ static void ll_invalidate_negative_children(struct inode *dir) int ll_md_blocking_ast(struct ldlm_lock *lock, struct ldlm_lock_desc *desc, void *data, int flag) { - int rc; struct lustre_handle lockh; + int rc; switch (flag) { case LDLM_CB_BLOCKING: ldlm_lock2handle(lock, &lockh); rc = ldlm_cli_cancel(&lockh, LCF_ASYNC); if (rc < 0) { - CDEBUG(D_INODE, "ldlm_cli_cancel: %d\n", rc); + CDEBUG(D_INODE, "ldlm_cli_cancel: rc = %d\n", rc); return rc; } break; case LDLM_CB_CANCELING: { struct inode *inode = ll_inode_from_resource_lock(lock); - struct ll_inode_info *lli; __u64 bits = lock->l_policy_data.l_inodebits.bits; - struct lu_fid *fid; - ldlm_mode_t mode = lock->l_req_mode; /* Inode is set to lock->l_resource->lr_lvb_inode * for mdc - bug 24555 */ LASSERT(lock->l_ast_data == NULL); - /* Invalidate all dentries associated with this inode */ if (inode == NULL) break; + /* Invalidate all dentries associated with this inode */ LASSERT(lock->l_flags & LDLM_FL_CANCELING); - if (bits & MDS_INODELOCK_XATTR) + if (!fid_res_name_eq(ll_inode2fid(inode), + &lock->l_resource->lr_name)) { + LDLM_ERROR(lock, "data mismatch with object "DFID"(%p)", + PFID(ll_inode2fid(inode)), inode); + LBUG(); + } + + if (bits & MDS_INODELOCK_XATTR) { ll_xattr_cache_destroy(inode); + bits &= ~MDS_INODELOCK_XATTR; + } /* For OPEN locks we differentiate between lock modes * LCK_CR, LCK_CW, LCK_PR - bug 22891 */ - if (bits & (MDS_INODELOCK_LOOKUP | MDS_INODELOCK_UPDATE | - MDS_INODELOCK_LAYOUT | MDS_INODELOCK_PERM)) - ll_have_md_lock(inode, &bits, LCK_MINMODE); - if (bits & MDS_INODELOCK_OPEN) - ll_have_md_lock(inode, &bits, mode); - - fid = ll_inode2fid(inode); - if (!fid_res_name_eq(fid, &lock->l_resource->lr_name)) - LDLM_ERROR(lock, "data mismatch with object " - DFID" (%p)", PFID(fid), inode); + ll_have_md_lock(inode, &bits, lock->l_req_mode); if (bits & MDS_INODELOCK_OPEN) { - int flags = 0; + fmode_t fmode; + switch (lock->l_req_mode) { case LCK_CW: - flags = FMODE_WRITE; + fmode = FMODE_WRITE; break; case LCK_PR: - flags = FMODE_EXEC; + fmode = FMODE_EXEC; break; case LCK_CR: - flags = FMODE_READ; + fmode = FMODE_READ; break; default: - CERROR("Unexpected lock mode for OPEN lock " - "%d, inode %ld\n", lock->l_req_mode, - inode->i_ino); + LDLM_ERROR(lock, "bad lock mode for OPEN lock"); + LBUG(); } - ll_md_real_close(inode, flags); + + ll_md_real_close(inode, fmode); } - lli = ll_i2info(inode); + if (bits & (MDS_INODELOCK_LOOKUP | MDS_INODELOCK_UPDATE | + MDS_INODELOCK_LAYOUT | MDS_INODELOCK_PERM)) + ll_have_md_lock(inode, &bits, LCK_MINMODE); + if (bits & MDS_INODELOCK_LAYOUT) { - struct cl_object_conf conf = { { 0 } }; + struct cl_object_conf conf = { + .coc_opc = OBJECT_CONF_INVALIDATE, + .coc_inode = inode, + }; - conf.coc_opc = OBJECT_CONF_INVALIDATE; - conf.coc_inode = inode; rc = ll_layout_conf(inode, &conf); - if (rc) - CDEBUG(D_INODE, "invaliding layout %d.\n", rc); + if (rc < 0) + CDEBUG(D_INODE, "cannot invalidate layout of " + DFID": rc = %d\n", + PFID(ll_inode2fid(inode)), rc); } if (bits & MDS_INODELOCK_UPDATE) { + struct ll_inode_info *lli = ll_i2info(inode); + spin_lock(&lli->lli_lock); lli->lli_flags &= ~LLIF_MDS_SIZE_LOCK; spin_unlock(&lli->lli_lock); } - if (S_ISDIR(inode->i_mode) && - (bits & MDS_INODELOCK_UPDATE)) { + if ((bits & MDS_INODELOCK_UPDATE) && S_ISDIR(inode->i_mode)) { CDEBUG(D_INODE, "invalidating inode %lu\n", inode->i_ino); truncate_inode_pages(inode->i_mapping, 0); ll_invalidate_negative_children(inode); } - if (inode->i_sb->s_root && - inode != inode->i_sb->s_root->d_inode && - (bits & (MDS_INODELOCK_LOOKUP | MDS_INODELOCK_PERM))) + if ((bits & (MDS_INODELOCK_LOOKUP | MDS_INODELOCK_PERM)) && + inode->i_sb->s_root != NULL && + inode != inode->i_sb->s_root->d_inode) ll_invalidate_aliases(inode); + iput(inode); break; } diff --git a/drivers/staging/lustre/lustre/lmv/lmv_intent.c b/drivers/staging/lustre/lustre/lmv/lmv_intent.c index 56dedceaf0a..9ba5a0a5739 100644 --- a/drivers/staging/lustre/lustre/lmv/lmv_intent.c +++ b/drivers/staging/lustre/lustre/lmv/lmv_intent.c @@ -119,7 +119,6 @@ static int lmv_intent_remote(struct obd_export *exp, void *lmm, CDEBUG(D_INODE, "REMOTE_INTENT with fid="DFID" -> mds #%d\n", PFID(&body->fid1), tgt->ltd_idx); - it->d.lustre.it_disposition &= ~DISP_ENQ_COMPLETE; rc = md_intent_lock(tgt->ltd_exp, op_data, lmm, lmmsize, it, flags, &req, cb_blocking, extra_lock_flags); if (rc) diff --git a/drivers/staging/lustre/lustre/lmv/lmv_obd.c b/drivers/staging/lustre/lustre/lmv/lmv_obd.c index 1bddd8f62fb..3ba0a0a1d94 100644 --- a/drivers/staging/lustre/lustre/lmv/lmv_obd.c +++ b/drivers/staging/lustre/lustre/lmv/lmv_obd.c @@ -1744,7 +1744,6 @@ lmv_enqueue_remote(struct obd_export *exp, struct ldlm_enqueue_info *einfo, it->d.lustre.it_data = NULL; fid1 = body->fid1; - it->d.lustre.it_disposition &= ~DISP_ENQ_COMPLETE; ptlrpc_req_finished(req); tgt = lmv_find_target(lmv, &fid1); @@ -2593,7 +2592,7 @@ int lmv_free_lustre_md(struct obd_export *exp, struct lustre_md *md) int lmv_set_open_replay_data(struct obd_export *exp, struct obd_client_handle *och, - struct ptlrpc_request *open_req) + struct lookup_intent *it) { struct obd_device *obd = exp->exp_obd; struct lmv_obd *lmv = &obd->u.lmv; @@ -2603,7 +2602,7 @@ int lmv_set_open_replay_data(struct obd_export *exp, if (IS_ERR(tgt)) return PTR_ERR(tgt); - return md_set_open_replay_data(tgt->ltd_exp, och, open_req); + return md_set_open_replay_data(tgt->ltd_exp, och, it); } int lmv_clear_open_replay_data(struct obd_export *exp, diff --git a/drivers/staging/lustre/lustre/lov/lov_io.c b/drivers/staging/lustre/lustre/lov/lov_io.c index 5a6ab70ed0a..65133ea308b 100644 --- a/drivers/staging/lustre/lustre/lov/lov_io.c +++ b/drivers/staging/lustre/lustre/lov/lov_io.c @@ -194,6 +194,7 @@ static int lov_io_sub_init(const struct lu_env *env, struct lov_io *lio, sub_io->ci_lockreq = io->ci_lockreq; sub_io->ci_type = io->ci_type; sub_io->ci_no_srvlock = io->ci_no_srvlock; + sub_io->ci_noatime = io->ci_noatime; lov_sub_enter(sub); result = cl_io_sub_init(sub->sub_env, sub_io, diff --git a/drivers/staging/lustre/lustre/mdc/mdc_internal.h b/drivers/staging/lustre/lustre/mdc/mdc_internal.h index fc21777b53c..c78bf003c2c 100644 --- a/drivers/staging/lustre/lustre/mdc/mdc_internal.h +++ b/drivers/staging/lustre/lustre/mdc/mdc_internal.h @@ -122,7 +122,7 @@ int mdc_free_lustre_md(struct obd_export *exp, struct lustre_md *md); int mdc_set_open_replay_data(struct obd_export *exp, struct obd_client_handle *och, - struct ptlrpc_request *open_req); + struct lookup_intent *it); int mdc_clear_open_replay_data(struct obd_export *exp, struct obd_client_handle *och); diff --git a/drivers/staging/lustre/lustre/mdc/mdc_locks.c b/drivers/staging/lustre/lustre/mdc/mdc_locks.c index 288a41ec60c..b0d0e2a1744 100644 --- a/drivers/staging/lustre/lustre/mdc/mdc_locks.c +++ b/drivers/staging/lustre/lustre/mdc/mdc_locks.c @@ -37,15 +37,15 @@ #define DEBUG_SUBSYSTEM S_MDC # include <linux/module.h> -# include <linux/pagemap.h> -# include <linux/miscdevice.h> -#include <lustre_acl.h> +#include <linux/lustre_intent.h> +#include <obd.h> #include <obd_class.h> #include <lustre_dlm.h> -/* fid_res_name_eq() */ -#include <lustre_fid.h> -#include <lprocfs_status.h> +#include <lustre_fid.h> /* fid_res_name_eq() */ +#include <lustre_mdc.h> +#include <lustre_net.h> +#include <lustre_req_layout.h> #include "mdc_internal.h" struct mdc_getattr_args { @@ -160,6 +160,8 @@ ldlm_mode_t mdc_lock_match(struct obd_export *exp, __u64 flags, ldlm_mode_t rc; fid_build_reg_res_name(fid, &res_id); + /* LU-4405: Clear bits not supported by server */ + policy->l_inodebits.bits &= exp_connect_ibits(exp); rc = ldlm_lock_match(class_exp2obd(exp)->obd_namespace, flags, &res_id, type, policy, mode, lockh, 0); return rc; @@ -334,9 +336,9 @@ static struct ptlrpc_request *mdc_intent_open_pack(struct obd_export *exp, max(lmmsize, obddev->u.cli.cl_default_mds_easize)); rc = ldlm_prep_enqueue_req(exp, req, &cancels, count); - if (rc) { + if (rc < 0) { ptlrpc_request_free(req); - return NULL; + return ERR_PTR(rc); } spin_lock(&req->rq_lock); @@ -639,7 +641,7 @@ static int mdc_finish_enqueue(struct obd_export *exp, * happens immediately after swabbing below, new reply * is swabbed by that handler correctly. */ - mdc_set_open_replay_data(NULL, NULL, req); + mdc_set_open_replay_data(NULL, NULL, it); } if ((body->valid & (OBD_MD_FLDIREA | OBD_MD_FLEASIZE)) != 0) { @@ -751,6 +753,7 @@ static int mdc_finish_enqueue(struct obd_export *exp, /* install lvb_data */ lock_res_and_lock(lock); if (lock->l_lvb_data == NULL) { + lock->l_lvb_type = LVB_T_LAYOUT; lock->l_lvb_data = lmm; lock->l_lvb_len = lvb_len; lmm = NULL; @@ -966,7 +969,6 @@ static int mdc_finish_intent_lock(struct obd_export *exp, if (fid_is_sane(&op_data->op_fid2) && it->it_create_mode & M_CHECK_STALE && it->it_op != IT_GETATTR) { - it_set_disposition(it, DISP_ENQ_COMPLETE); /* Also: did we find the same inode? */ /* sever can return one of two fids: @@ -1061,7 +1063,23 @@ int mdc_revalidate_lock(struct obd_export *exp, struct lookup_intent *it, fid_build_reg_res_name(fid, &res_id); switch (it->it_op) { case IT_GETATTR: - policy.l_inodebits.bits = MDS_INODELOCK_UPDATE; + /* File attributes are held under multiple bits: + * nlink is under lookup lock, size and times are + * under UPDATE lock and recently we've also got + * a separate permissions lock for owner/group/acl that + * were protected by lookup lock before. + * Getattr must provide all of that information, + * so we need to ensure we have all of those locks. + * Unfortunately, if the bits are split across multiple + * locks, there's no easy way to match all of them here, + * so an extra RPC would be performed to fetch all + * of those bits at once for now. */ + /* For new MDTs(> 2.4), UPDATE|PERM should be enough, + * but for old MDTs (< 2.4), permission is covered + * by LOOKUP lock, so it needs to match all bits here.*/ + policy.l_inodebits.bits = MDS_INODELOCK_UPDATE | + MDS_INODELOCK_LOOKUP | + MDS_INODELOCK_PERM; break; case IT_LAYOUT: policy.l_inodebits.bits = MDS_INODELOCK_LAYOUT; @@ -1070,10 +1088,11 @@ int mdc_revalidate_lock(struct obd_export *exp, struct lookup_intent *it, policy.l_inodebits.bits = MDS_INODELOCK_LOOKUP; break; } - mode = ldlm_lock_match(exp->exp_obd->obd_namespace, - LDLM_FL_BLOCK_GRANTED, &res_id, + + mode = mdc_lock_match(exp, LDLM_FL_BLOCK_GRANTED, fid, LDLM_IBITS, &policy, - LCK_CR|LCK_CW|LCK_PR|LCK_PW, &lockh, 0); + LCK_CR | LCK_CW | LCK_PR | LCK_PW, + &lockh); } if (mode) { @@ -1120,6 +1139,12 @@ int mdc_intent_lock(struct obd_export *exp, struct md_op_data *op_data, ldlm_blocking_callback cb_blocking, __u64 extra_lock_flags) { + struct ldlm_enqueue_info einfo = { + .ei_type = LDLM_IBITS, + .ei_mode = it_to_lock_mode(it), + .ei_cb_bl = cb_blocking, + .ei_cb_cp = ldlm_completion_ast, + }; struct lustre_handle lockh; int rc = 0; @@ -1145,42 +1170,19 @@ int mdc_intent_lock(struct obd_export *exp, struct md_op_data *op_data, return rc; } - /* lookup_it may be called only after revalidate_it has run, because - * revalidate_it cannot return errors, only zero. Returning zero causes - * this call to lookup, which *can* return an error. - * - * We only want to execute the request associated with the intent one - * time, however, so don't send the request again. Instead, skip past - * this and use the request from revalidate. In this case, revalidate - * never dropped its reference, so the refcounts are all OK */ - if (!it_disposition(it, DISP_ENQ_COMPLETE)) { - struct ldlm_enqueue_info einfo = { - .ei_type = LDLM_IBITS, - .ei_mode = it_to_lock_mode(it), - .ei_cb_bl = cb_blocking, - .ei_cb_cp = ldlm_completion_ast, - }; - - /* For case if upper layer did not alloc fid, do it now. */ - if (!fid_is_sane(&op_data->op_fid2) && it->it_op & IT_CREAT) { - rc = mdc_fid_alloc(exp, &op_data->op_fid2, op_data); - if (rc < 0) { - CERROR("Can't alloc new fid, rc %d\n", rc); - return rc; - } - } - rc = mdc_enqueue(exp, &einfo, it, op_data, &lockh, - lmm, lmmsize, NULL, extra_lock_flags); - if (rc < 0) + /* For case if upper layer did not alloc fid, do it now. */ + if (!fid_is_sane(&op_data->op_fid2) && it->it_op & IT_CREAT) { + rc = mdc_fid_alloc(exp, &op_data->op_fid2, op_data); + if (rc < 0) { + CERROR("Can't alloc new fid, rc %d\n", rc); return rc; - } else if (!fid_is_sane(&op_data->op_fid2) || - !(it->it_create_mode & M_CHECK_STALE)) { - /* DISP_ENQ_COMPLETE set means there is extra reference on - * request referenced from this intent, saved for subsequent - * lookup. This path is executed when we proceed to this - * lookup, so we clear DISP_ENQ_COMPLETE */ - it_clear_disposition(it, DISP_ENQ_COMPLETE); + } } + rc = mdc_enqueue(exp, &einfo, it, op_data, &lockh, lmm, lmmsize, NULL, + extra_lock_flags); + if (rc < 0) + return rc; + *reqp = it->d.lustre.it_data; rc = mdc_finish_intent_lock(exp, *reqp, op_data, it, &lockh); return rc; @@ -1262,8 +1264,8 @@ int mdc_intent_getattr_async(struct obd_export *exp, fid_build_reg_res_name(&op_data->op_fid1, &res_id); req = mdc_intent_getattr_pack(exp, it, op_data); - if (!req) - return -ENOMEM; + if (IS_ERR(req)) + return PTR_ERR(req); rc = mdc_enter_request(&obddev->u.cli); if (rc != 0) { diff --git a/drivers/staging/lustre/lustre/mdc/mdc_reint.c b/drivers/staging/lustre/lustre/mdc/mdc_reint.c index 1aea154e122..d79aa1641fe 100644 --- a/drivers/staging/lustre/lustre/mdc/mdc_reint.c +++ b/drivers/staging/lustre/lustre/mdc/mdc_reint.c @@ -165,6 +165,7 @@ int mdc_setattr(struct obd_export *exp, struct md_op_data *op_data, req->rq_cb_data = *mod; (*mod)->mod_open_req = req; req->rq_commit_cb = mdc_commit_open; + (*mod)->mod_is_create = true; /** * Take an extra reference on \var mod, it protects \var * mod from being freed on eviction (commit callback is diff --git a/drivers/staging/lustre/lustre/mdc/mdc_request.c b/drivers/staging/lustre/lustre/mdc/mdc_request.c index 17c8e1486da..d9ddb393491 100644 --- a/drivers/staging/lustre/lustre/mdc/mdc_request.c +++ b/drivers/staging/lustre/lustre/mdc/mdc_request.c @@ -722,11 +722,12 @@ void mdc_commit_open(struct ptlrpc_request *req) int mdc_set_open_replay_data(struct obd_export *exp, struct obd_client_handle *och, - struct ptlrpc_request *open_req) + struct lookup_intent *it) { struct md_open_data *mod; struct mdt_rec_create *rec; struct mdt_body *body; + struct ptlrpc_request *open_req = it->d.lustre.it_data; struct obd_import *imp = open_req->rq_import; if (!open_req->rq_replay) @@ -760,6 +761,8 @@ int mdc_set_open_replay_data(struct obd_export *exp, spin_lock(&open_req->rq_lock); och->och_mod = mod; mod->mod_och = och; + mod->mod_is_create = it_disposition(it, DISP_OPEN_CREATE) || + it_disposition(it, DISP_OPEN_STRIPE); mod->mod_open_req = open_req; open_req->rq_cb_data = mod; open_req->rq_commit_cb = mdc_commit_open; @@ -780,6 +783,23 @@ int mdc_set_open_replay_data(struct obd_export *exp, return 0; } +static void mdc_free_open(struct md_open_data *mod) +{ + int committed = 0; + + if (mod->mod_is_create == 0 && + imp_connect_disp_stripe(mod->mod_open_req->rq_import)) + committed = 1; + + LASSERT(mod->mod_open_req->rq_replay == 0); + + DEBUG_REQ(D_RPCTRACE, mod->mod_open_req, "free open request\n"); + + ptlrpc_request_committed(mod->mod_open_req, committed); + if (mod->mod_close_req) + ptlrpc_request_committed(mod->mod_close_req, committed); +} + int mdc_clear_open_replay_data(struct obd_export *exp, struct obd_client_handle *och) { @@ -793,6 +813,8 @@ int mdc_clear_open_replay_data(struct obd_export *exp, return 0; LASSERT(mod != LP_POISON); + LASSERT(mod->mod_open_req != NULL); + mdc_free_open(mod); mod->mod_och = NULL; och->och_mod = NULL; @@ -991,6 +1013,9 @@ int mdc_done_writing(struct obd_export *exp, struct md_op_data *op_data, if (mod) { if (rc != 0) mod->mod_close_req = NULL; + LASSERT(mod->mod_open_req != NULL); + mdc_free_open(mod); + /* Since now, mod is accessed through setattr req only, * thus DW req does not keep a reference on mod anymore. */ obd_mod_put(mod); diff --git a/drivers/staging/lustre/lustre/obdclass/genops.c b/drivers/staging/lustre/lustre/obdclass/genops.c index d27f0411d35..169c9ed5652 100644 --- a/drivers/staging/lustre/lustre/obdclass/genops.c +++ b/drivers/staging/lustre/lustre/obdclass/genops.c @@ -1010,6 +1010,8 @@ struct obd_import *class_new_import(struct obd_device *obd) INIT_LIST_HEAD(&imp->imp_replay_list); INIT_LIST_HEAD(&imp->imp_sending_list); INIT_LIST_HEAD(&imp->imp_delayed_list); + INIT_LIST_HEAD(&imp->imp_committed_list); + imp->imp_replay_cursor = &imp->imp_committed_list; spin_lock_init(&imp->imp_lock); imp->imp_last_success_conn = 0; imp->imp_state = LUSTRE_IMP_NEW; diff --git a/drivers/staging/lustre/lustre/obdclass/lprocfs_status.c b/drivers/staging/lustre/lustre/obdclass/lprocfs_status.c index 6e7d2e56106..1432dd74fe9 100644 --- a/drivers/staging/lustre/lustre/obdclass/lprocfs_status.c +++ b/drivers/staging/lustre/lustre/obdclass/lprocfs_status.c @@ -99,6 +99,7 @@ static const char * const obd_connect_names[] = { "short_io", "pingless", "flock_deadlock", + "disp_stripe", "unknown", NULL }; diff --git a/drivers/staging/lustre/lustre/osc/osc_cache.c b/drivers/staging/lustre/lustre/osc/osc_cache.c index b92a02efad4..af25c19c88f 100644 --- a/drivers/staging/lustre/lustre/osc/osc_cache.c +++ b/drivers/staging/lustre/lustre/osc/osc_cache.c @@ -2394,6 +2394,12 @@ int osc_flush_async_page(const struct lu_env *env, struct cl_io *io, * really sending the RPC. */ case OES_TRUNC: /* race with truncate, page will be redirtied */ + case OES_ACTIVE: + /* The extent is active so we need to abort and let the caller + * re-dirty the page. If we continued on here, and we were the + * one making the extent active, we could deadlock waiting for + * the page writeback to clear but it won't because the extent + * is active and won't be written out. */ GOTO(out, rc = -EAGAIN); default: break; diff --git a/drivers/staging/lustre/lustre/osc/osc_io.c b/drivers/staging/lustre/lustre/osc/osc_io.c index 777ae24bbff..5f3c545418d 100644 --- a/drivers/staging/lustre/lustre/osc/osc_io.c +++ b/drivers/staging/lustre/lustre/osc/osc_io.c @@ -512,19 +512,15 @@ static int osc_io_read_start(const struct lu_env *env, struct osc_io *oio = cl2osc_io(env, slice); struct cl_object *obj = slice->cis_obj; struct cl_attr *attr = &osc_env_info(env)->oti_attr; - int result = 0; + int rc = 0; - if (oio->oi_lockless == 0) { + if (oio->oi_lockless == 0 && !slice->cis_io->ci_noatime) { cl_object_attr_lock(obj); - result = cl_object_attr_get(env, obj, attr); - if (result == 0) { - attr->cat_atime = LTIME_S(CURRENT_TIME); - result = cl_object_attr_set(env, obj, attr, - CAT_ATIME); - } + attr->cat_atime = LTIME_S(CURRENT_TIME); + rc = cl_object_attr_set(env, obj, attr, CAT_ATIME); cl_object_attr_unlock(obj); } - return result; + return rc; } static int osc_io_write_start(const struct lu_env *env, diff --git a/drivers/staging/lustre/lustre/osc/osc_quota.c b/drivers/staging/lustre/lustre/osc/osc_quota.c index 6045a78a2ba..f395ae4ec94 100644 --- a/drivers/staging/lustre/lustre/osc/osc_quota.c +++ b/drivers/staging/lustre/lustre/osc/osc_quota.c @@ -51,11 +51,8 @@ int osc_quota_chkdq(struct client_obd *cli, const unsigned int qid[]) oqi = cfs_hash_lookup(cli->cl_quota_hash[type], &qid[type]); if (oqi) { - obd_uid id = oqi->oqi_id; - - LASSERTF(id == qid[type], - "The ids don't match %u != %u\n", - id, qid[type]); + /* do not try to access oqi here, it could have been + * freed by osc_quota_setdq() */ /* the slot is busy, the user is about to run out of * quota space on this OST */ diff --git a/drivers/staging/lustre/lustre/ptlrpc/client.c b/drivers/staging/lustre/lustre/ptlrpc/client.c index eb33bb7c86a..4c9e0069508 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/client.c +++ b/drivers/staging/lustre/lustre/ptlrpc/client.c @@ -48,6 +48,7 @@ #include "ptlrpc_internal.h" static int ptlrpc_send_new_req(struct ptlrpc_request *req); +static int ptlrpcd_check_work(struct ptlrpc_request *req); /** * Initialize passed in client structure \a cl. @@ -1190,7 +1191,9 @@ static int after_reply(struct ptlrpc_request *req) * will roundup it */ req->rq_replen = req->rq_nob_received; req->rq_nob_received = 0; + spin_lock(&req->rq_lock); req->rq_resend = 1; + spin_unlock(&req->rq_lock); return 0; } @@ -1313,7 +1316,11 @@ static int after_reply(struct ptlrpc_request *req) /** version recovery */ ptlrpc_save_versions(req); ptlrpc_retain_replayable_request(req, imp); - } else if (req->rq_commit_cb != NULL) { + } else if (req->rq_commit_cb != NULL && + list_empty(&req->rq_replay_list)) { + /* NB: don't call rq_commit_cb if it's already on + * rq_replay_list, ptlrpc_free_committed() will call + * it later, see LU-3618 for details */ spin_unlock(&imp->imp_lock); req->rq_commit_cb(req); spin_lock(&imp->imp_lock); @@ -1408,7 +1415,9 @@ static int ptlrpc_send_new_req(struct ptlrpc_request *req) req->rq_status = rc; return 1; } else { + spin_lock(&req->rq_lock); req->rq_wait_ctx = 1; + spin_unlock(&req->rq_lock); return 0; } } @@ -1423,7 +1432,9 @@ static int ptlrpc_send_new_req(struct ptlrpc_request *req) rc = ptl_send_rpc(req, 0); if (rc) { DEBUG_REQ(D_HA, req, "send failed (%d); expect timeout", rc); + spin_lock(&req->rq_lock); req->rq_net_err = 1; + spin_unlock(&req->rq_lock); return rc; } return 0; @@ -1688,6 +1699,7 @@ int ptlrpc_check_set(const struct lu_env *env, struct ptlrpc_request_set *set) spin_lock(&req->rq_lock); req->rq_net_err = 1; spin_unlock(&req->rq_lock); + continue; } /* need to reset the timeout */ force_timer_recalc = 1; @@ -1773,6 +1785,10 @@ interpret: ptlrpc_req_interpret(env, req, req->rq_status); + if (ptlrpcd_check_work(req)) { + atomic_dec(&set->set_remaining); + continue; + } ptlrpc_rqphase_move(req, RQ_PHASE_COMPLETE); CDEBUG(req->rq_reqmsg != NULL ? D_RPCTRACE : 0, @@ -2360,6 +2376,39 @@ int ptlrpc_unregister_reply(struct ptlrpc_request *request, int async) } EXPORT_SYMBOL(ptlrpc_unregister_reply); +static void ptlrpc_free_request(struct ptlrpc_request *req) +{ + spin_lock(&req->rq_lock); + req->rq_replay = 0; + spin_unlock(&req->rq_lock); + + if (req->rq_commit_cb != NULL) + req->rq_commit_cb(req); + list_del_init(&req->rq_replay_list); + + __ptlrpc_req_finished(req, 1); +} + +/** + * the request is committed and dropped from the replay list of its import + */ +void ptlrpc_request_committed(struct ptlrpc_request *req, int force) +{ + struct obd_import *imp = req->rq_import; + + spin_lock(&imp->imp_lock); + if (list_empty(&req->rq_replay_list)) { + spin_unlock(&imp->imp_lock); + return; + } + + if (force || req->rq_transno <= imp->imp_peer_committed_transno) + ptlrpc_free_request(req); + + spin_unlock(&imp->imp_lock); +} +EXPORT_SYMBOL(ptlrpc_request_committed); + /** * Iterates through replay_list on import and prunes * all requests have transno smaller than last_committed for the @@ -2370,9 +2419,9 @@ EXPORT_SYMBOL(ptlrpc_unregister_reply); */ void ptlrpc_free_committed(struct obd_import *imp) { - struct list_head *tmp, *saved; - struct ptlrpc_request *req; + struct ptlrpc_request *req, *saved; struct ptlrpc_request *last_req = NULL; /* temporary fire escape */ + bool skip_committed_list = true; LASSERT(imp != NULL); @@ -2388,13 +2437,15 @@ void ptlrpc_free_committed(struct obd_import *imp) CDEBUG(D_RPCTRACE, "%s: committing for last_committed "LPU64" gen %d\n", imp->imp_obd->obd_name, imp->imp_peer_committed_transno, imp->imp_generation); + + if (imp->imp_generation != imp->imp_last_generation_checked) + skip_committed_list = false; + imp->imp_last_transno_checked = imp->imp_peer_committed_transno; imp->imp_last_generation_checked = imp->imp_generation; - list_for_each_safe(tmp, saved, &imp->imp_replay_list) { - req = list_entry(tmp, struct ptlrpc_request, - rq_replay_list); - + list_for_each_entry_safe(req, saved, &imp->imp_replay_list, + rq_replay_list) { /* XXX ok to remove when 1357 resolved - rread 05/29/03 */ LASSERT(req != last_req); last_req = req; @@ -2408,27 +2459,34 @@ void ptlrpc_free_committed(struct obd_import *imp) GOTO(free_req, 0); } - if (req->rq_replay) { - DEBUG_REQ(D_RPCTRACE, req, "keeping (FL_REPLAY)"); - continue; - } - /* not yet committed */ if (req->rq_transno > imp->imp_peer_committed_transno) { DEBUG_REQ(D_RPCTRACE, req, "stopping search"); break; } + if (req->rq_replay) { + DEBUG_REQ(D_RPCTRACE, req, "keeping (FL_REPLAY)"); + list_move_tail(&req->rq_replay_list, + &imp->imp_committed_list); + continue; + } + DEBUG_REQ(D_INFO, req, "commit (last_committed "LPU64")", imp->imp_peer_committed_transno); free_req: - spin_lock(&req->rq_lock); - req->rq_replay = 0; - spin_unlock(&req->rq_lock); - if (req->rq_commit_cb != NULL) - req->rq_commit_cb(req); - list_del_init(&req->rq_replay_list); - __ptlrpc_req_finished(req, 1); + ptlrpc_free_request(req); + } + if (skip_committed_list) + return; + + list_for_each_entry_safe(req, saved, &imp->imp_committed_list, + rq_replay_list) { + LASSERT(req->rq_transno != 0); + if (req->rq_import_generation < imp->imp_generation) { + DEBUG_REQ(D_RPCTRACE, req, "free stale open request"); + ptlrpc_free_request(req); + } } } @@ -2904,22 +2962,50 @@ EXPORT_SYMBOL(ptlrpc_sample_next_xid); * have delay before it really runs by ptlrpcd thread. */ struct ptlrpc_work_async_args { - __u64 magic; int (*cb)(const struct lu_env *, void *); void *cbdata; }; -#define PTLRPC_WORK_MAGIC 0x6655436b676f4f44ULL /* magic code */ +static void ptlrpcd_add_work_req(struct ptlrpc_request *req) +{ + /* re-initialize the req */ + req->rq_timeout = obd_timeout; + req->rq_sent = cfs_time_current_sec(); + req->rq_deadline = req->rq_sent + req->rq_timeout; + req->rq_reply_deadline = req->rq_deadline; + req->rq_phase = RQ_PHASE_INTERPRET; + req->rq_next_phase = RQ_PHASE_COMPLETE; + req->rq_xid = ptlrpc_next_xid(); + req->rq_import_generation = req->rq_import->imp_generation; + + ptlrpcd_add_req(req, PDL_POLICY_ROUND, -1); +} static int work_interpreter(const struct lu_env *env, struct ptlrpc_request *req, void *data, int rc) { struct ptlrpc_work_async_args *arg = data; - LASSERT(arg->magic == PTLRPC_WORK_MAGIC); + LASSERT(ptlrpcd_check_work(req)); LASSERT(arg->cb != NULL); - return arg->cb(env, arg->cbdata); + rc = arg->cb(env, arg->cbdata); + + list_del_init(&req->rq_set_chain); + req->rq_set = NULL; + + if (atomic_dec_return(&req->rq_refcount) > 1) { + atomic_set(&req->rq_refcount, 2); + ptlrpcd_add_work_req(req); + } + return rc; +} + +static int worker_format; + +static int ptlrpcd_check_work(struct ptlrpc_request *req) +{ + return req->rq_pill.rc_fmt == (void *)&worker_format; } /** @@ -2952,6 +3038,7 @@ void *ptlrpcd_alloc_work(struct obd_import *imp, req->rq_receiving_reply = 0; req->rq_must_unlink = 0; req->rq_no_delay = req->rq_no_resend = 1; + req->rq_pill.rc_fmt = (void *)&worker_format; spin_lock_init(&req->rq_lock); INIT_LIST_HEAD(&req->rq_list); @@ -2965,7 +3052,6 @@ void *ptlrpcd_alloc_work(struct obd_import *imp, CLASSERT(sizeof(*args) <= sizeof(req->rq_async_args)); args = ptlrpc_req_async_args(req); - args->magic = PTLRPC_WORK_MAGIC; args->cb = cb; args->cbdata = cbdata; @@ -2995,25 +3081,8 @@ int ptlrpcd_queue_work(void *handler) * req as opaque data. - Jinshan */ LASSERT(atomic_read(&req->rq_refcount) > 0); - if (atomic_read(&req->rq_refcount) > 1) - return -EBUSY; - - if (atomic_inc_return(&req->rq_refcount) > 2) { /* race */ - atomic_dec(&req->rq_refcount); - return -EBUSY; - } - - /* re-initialize the req */ - req->rq_timeout = obd_timeout; - req->rq_sent = cfs_time_current_sec(); - req->rq_deadline = req->rq_sent + req->rq_timeout; - req->rq_reply_deadline = req->rq_deadline; - req->rq_phase = RQ_PHASE_INTERPRET; - req->rq_next_phase = RQ_PHASE_COMPLETE; - req->rq_xid = ptlrpc_next_xid(); - req->rq_import_generation = req->rq_import->imp_generation; - - ptlrpcd_add_req(req, PDL_POLICY_ROUND, -1); + if (atomic_inc_return(&req->rq_refcount) == 2) + ptlrpcd_add_work_req(req); return 0; } EXPORT_SYMBOL(ptlrpcd_queue_work); diff --git a/drivers/staging/lustre/lustre/ptlrpc/import.c b/drivers/staging/lustre/lustre/ptlrpc/import.c index 82db0ed6065..537aa6204a5 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/import.c +++ b/drivers/staging/lustre/lustre/ptlrpc/import.c @@ -560,17 +560,30 @@ static int ptlrpc_first_transno(struct obd_import *imp, __u64 *transno) struct ptlrpc_request *req; struct list_head *tmp; - if (list_empty(&imp->imp_replay_list)) - return 0; - tmp = imp->imp_replay_list.next; - req = list_entry(tmp, struct ptlrpc_request, rq_replay_list); - *transno = req->rq_transno; - if (req->rq_transno == 0) { - DEBUG_REQ(D_ERROR, req, "zero transno in replay"); - LBUG(); + /* The requests in committed_list always have smaller transnos than + * the requests in replay_list */ + if (!list_empty(&imp->imp_committed_list)) { + tmp = imp->imp_committed_list.next; + req = list_entry(tmp, struct ptlrpc_request, rq_replay_list); + *transno = req->rq_transno; + if (req->rq_transno == 0) { + DEBUG_REQ(D_ERROR, req, + "zero transno in committed_list"); + LBUG(); + } + return 1; } - - return 1; + if (!list_empty(&imp->imp_replay_list)) { + tmp = imp->imp_replay_list.next; + req = list_entry(tmp, struct ptlrpc_request, rq_replay_list); + *transno = req->rq_transno; + if (req->rq_transno == 0) { + DEBUG_REQ(D_ERROR, req, "zero transno in replay_list"); + LBUG(); + } + return 1; + } + return 0; } /** diff --git a/drivers/staging/lustre/lustre/ptlrpc/niobuf.c b/drivers/staging/lustre/lustre/ptlrpc/niobuf.c index 1e94597eaea..a47a8d807d5 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/niobuf.c +++ b/drivers/staging/lustre/lustre/ptlrpc/niobuf.c @@ -511,7 +511,9 @@ int ptl_send_rpc(struct ptlrpc_request *request, int noreply) CDEBUG(D_HA, "muting rpc for failed imp obd %s\n", request->rq_import->imp_obd->obd_name); /* this prevents us from waiting in ptlrpc_queue_wait */ + spin_lock(&request->rq_lock); request->rq_err = 1; + spin_unlock(&request->rq_lock); request->rq_status = -ENODEV; return -ENODEV; } @@ -553,7 +555,9 @@ int ptl_send_rpc(struct ptlrpc_request *request, int noreply) if (rc) { /* this prevents us from looping in * ptlrpc_queue_wait */ + spin_lock(&request->rq_lock); request->rq_err = 1; + spin_unlock(&request->rq_lock); request->rq_status = rc; GOTO(cleanup_bulk, rc); } diff --git a/drivers/staging/lustre/lustre/ptlrpc/recover.c b/drivers/staging/lustre/lustre/ptlrpc/recover.c index 84c39e083ea..48ae328ce24 100644 --- a/drivers/staging/lustre/lustre/ptlrpc/recover.c +++ b/drivers/staging/lustre/lustre/ptlrpc/recover.c @@ -105,24 +105,59 @@ int ptlrpc_replay_next(struct obd_import *imp, int *inflight) * imp_lock is being held by ptlrpc_replay, but it's not. it's * just a little race... */ - list_for_each_safe(tmp, pos, &imp->imp_replay_list) { + + /* Replay all the committed open requests on committed_list first */ + if (!list_empty(&imp->imp_committed_list)) { + tmp = imp->imp_committed_list.prev; req = list_entry(tmp, struct ptlrpc_request, rq_replay_list); - /* If need to resend the last sent transno (because a - reconnect has occurred), then stop on the matching - req and send it again. If, however, the last sent - transno has been committed then we continue replay - from the next request. */ + /* The last request on committed_list hasn't been replayed */ if (req->rq_transno > last_transno) { - if (imp->imp_resend_replay) - lustre_msg_add_flags(req->rq_reqmsg, - MSG_RESENT); - break; + /* Since the imp_committed_list is immutable before + * all of it's requests being replayed, it's safe to + * use a cursor to accelerate the search */ + imp->imp_replay_cursor = imp->imp_replay_cursor->next; + + while (imp->imp_replay_cursor != + &imp->imp_committed_list) { + req = list_entry(imp->imp_replay_cursor, + struct ptlrpc_request, + rq_replay_list); + if (req->rq_transno > last_transno) + break; + + req = NULL; + imp->imp_replay_cursor = + imp->imp_replay_cursor->next; + } + } else { + /* All requests on committed_list have been replayed */ + imp->imp_replay_cursor = &imp->imp_committed_list; + req = NULL; + } + } + + /* All the requests in committed list have been replayed, let's replay + * the imp_replay_list */ + if (req == NULL) { + list_for_each_safe(tmp, pos, &imp->imp_replay_list) { + req = list_entry(tmp, struct ptlrpc_request, + rq_replay_list); + + if (req->rq_transno > last_transno) + break; + req = NULL; } - req = NULL; } + /* If need to resend the last sent transno (because a reconnect + * has occurred), then stop on the matching req and send it again. + * If, however, the last sent transno has been committed then we + * continue replay from the next request. */ + if (req != NULL && imp->imp_resend_replay) + lustre_msg_add_flags(req->rq_reqmsg, MSG_RESENT); + spin_lock(&imp->imp_lock); imp->imp_resend_replay = 0; spin_unlock(&imp->imp_lock); diff --git a/drivers/staging/netlogic/xlr_net.c b/drivers/staging/netlogic/xlr_net.c index d8ea25486a3..31b269a5fff 100644 --- a/drivers/staging/netlogic/xlr_net.c +++ b/drivers/staging/netlogic/xlr_net.c @@ -307,7 +307,7 @@ static netdev_tx_t xlr_net_start_xmit(struct sk_buff *skb, } static u16 xlr_net_select_queue(struct net_device *ndev, struct sk_buff *skb, - void *accel_priv) + void *accel_priv, select_queue_fallback_t fallback) { return (u16)smp_processor_id(); } diff --git a/drivers/staging/octeon/ethernet-defines.h b/drivers/staging/octeon/ethernet-defines.h index bdaec8d2ca0..2a98a2153e1 100644 --- a/drivers/staging/octeon/ethernet-defines.h +++ b/drivers/staging/octeon/ethernet-defines.h @@ -33,10 +33,6 @@ * driver will use this memory instead of kernel memory for pools. This * allows 32bit userspace application to access the buffers, but also * requires all received packets to be copied. - * CONFIG_CAVIUM_OCTEON_NUM_PACKET_BUFFERS - * This kernel config option allows the user to control the number of - * packet and work queue buffers allocated by the driver. If this is zero, - * the driver uses the default from below. * USE_SKBUFFS_IN_HW * Tells the driver to populate the packet buffers with kernel skbuffs. * This allows the driver to receive packets without copying them. It also diff --git a/drivers/staging/octeon/ethernet-mem.c b/drivers/staging/octeon/ethernet-mem.c index 199059d64c9..55c13481a56 100644 --- a/drivers/staging/octeon/ethernet-mem.c +++ b/drivers/staging/octeon/ethernet-mem.c @@ -30,6 +30,7 @@ #include <asm/octeon/octeon.h> +#include "ethernet-mem.h" #include "ethernet-defines.h" #include <asm/octeon/cvmx-fpa.h> diff --git a/drivers/staging/octeon/ethernet-rgmii.c b/drivers/staging/octeon/ethernet-rgmii.c index ea53af30dfa..40297ceb86a 100644 --- a/drivers/staging/octeon/ethernet-rgmii.c +++ b/drivers/staging/octeon/ethernet-rgmii.c @@ -43,7 +43,7 @@ #include <asm/octeon/cvmx-npi-defs.h> #include <asm/octeon/cvmx-gmxx-defs.h> -DEFINE_SPINLOCK(global_register_lock); +static DEFINE_SPINLOCK(global_register_lock); static int number_rgmii_ports; diff --git a/drivers/staging/octeon/ethernet-tx.c b/drivers/staging/octeon/ethernet-tx.c index 47541e1608f..8ca55c4e9db 100644 --- a/drivers/staging/octeon/ethernet-tx.c +++ b/drivers/staging/octeon/ethernet-tx.c @@ -95,7 +95,7 @@ static void cvm_oct_kick_tx_poll_watchdog(void) cvmx_write_csr(CVMX_CIU_TIMX(1), ciu_timx.u64); } -void cvm_oct_free_tx_skbs(struct net_device *dev) +static void cvm_oct_free_tx_skbs(struct net_device *dev) { int32_t skb_to_free; int qos, queues_per_port; diff --git a/drivers/staging/octeon/ethernet.c b/drivers/staging/octeon/ethernet.c index 089dc4b9efd..ff7214aac9d 100644 --- a/drivers/staging/octeon/ethernet.c +++ b/drivers/staging/octeon/ethernet.c @@ -55,17 +55,11 @@ #include <asm/octeon/cvmx-gmxx-defs.h> #include <asm/octeon/cvmx-smix-defs.h> -#if defined(CONFIG_CAVIUM_OCTEON_NUM_PACKET_BUFFERS) \ - && CONFIG_CAVIUM_OCTEON_NUM_PACKET_BUFFERS -int num_packet_buffers = CONFIG_CAVIUM_OCTEON_NUM_PACKET_BUFFERS; -#else -int num_packet_buffers = 1024; -#endif +static int num_packet_buffers = 1024; module_param(num_packet_buffers, int, 0444); MODULE_PARM_DESC(num_packet_buffers, "\n" "\tNumber of packet buffers to allocate and store in the\n" - "\tFPA. By default, 1024 packet buffers are used unless\n" - "\tCONFIG_CAVIUM_OCTEON_NUM_PACKET_BUFFERS is defined."); + "\tFPA. By default, 1024 packet buffers are used.\n"); int pow_receive_group = 15; module_param(pow_receive_group, int, 0444); diff --git a/drivers/staging/ozwpan/ozpd.c b/drivers/staging/ozwpan/ozpd.c index 74369507734..29a23a325d7 100644 --- a/drivers/staging/ozwpan/ozpd.c +++ b/drivers/staging/ozwpan/ozpd.c @@ -284,11 +284,11 @@ int oz_services_start(struct oz_pd *pd, u16 apps, int resume) ai->app_id); break; } - oz_polling_lock_bh(); + spin_lock_bh(&g_polling_lock); pd->total_apps |= (1<<ai->app_id); if (resume) pd->paused_apps &= ~(1<<ai->app_id); - oz_polling_unlock_bh(); + spin_unlock_bh(&g_polling_lock); } } return rc; @@ -304,14 +304,14 @@ void oz_services_stop(struct oz_pd *pd, u16 apps, int pause) oz_pd_dbg(pd, ON, "%s: (0x%x) pause(%d)\n", __func__, apps, pause); for (ai = g_app_if; ai < &g_app_if[OZ_APPID_MAX]; ai++) { if (apps & (1<<ai->app_id)) { - oz_polling_lock_bh(); + spin_lock_bh(&g_polling_lock); if (pause) { pd->paused_apps |= (1<<ai->app_id); } else { pd->total_apps &= ~(1<<ai->app_id); pd->paused_apps &= ~(1<<ai->app_id); } - oz_polling_unlock_bh(); + spin_unlock_bh(&g_polling_lock); ai->stop(pd, pause); } } @@ -349,17 +349,17 @@ void oz_pd_stop(struct oz_pd *pd) oz_dbg(ON, "oz_pd_stop() State = 0x%x\n", pd->state); oz_pd_indicate_farewells(pd); - oz_polling_lock_bh(); + spin_lock_bh(&g_polling_lock); stop_apps = pd->total_apps; pd->total_apps = 0; pd->paused_apps = 0; - oz_polling_unlock_bh(); + spin_unlock_bh(&g_polling_lock); oz_services_stop(pd, stop_apps, 0); - oz_polling_lock_bh(); + spin_lock_bh(&g_polling_lock); oz_pd_set_state(pd, OZ_PD_S_STOPPED); /* Remove from PD list.*/ list_del(&pd->link); - oz_polling_unlock_bh(); + spin_unlock_bh(&g_polling_lock); oz_dbg(ON, "pd ref count = %d\n", atomic_read(&pd->ref_count)); oz_pd_put(pd); } @@ -372,9 +372,9 @@ int oz_pd_sleep(struct oz_pd *pd) int do_stop = 0; u16 stop_apps; - oz_polling_lock_bh(); + spin_lock_bh(&g_polling_lock); if (pd->state & (OZ_PD_S_SLEEP | OZ_PD_S_STOPPED)) { - oz_polling_unlock_bh(); + spin_unlock_bh(&g_polling_lock); return 0; } if (pd->keep_alive && pd->session_id) @@ -383,7 +383,7 @@ int oz_pd_sleep(struct oz_pd *pd) do_stop = 1; stop_apps = pd->total_apps; - oz_polling_unlock_bh(); + spin_unlock_bh(&g_polling_lock); if (do_stop) { oz_pd_stop(pd); } else { @@ -999,15 +999,15 @@ void oz_pd_indicate_farewells(struct oz_pd *pd) const struct oz_app_if *ai = &g_app_if[OZ_APPID_USB-1]; while (1) { - oz_polling_lock_bh(); + spin_lock_bh(&g_polling_lock); if (list_empty(&pd->farewell_list)) { - oz_polling_unlock_bh(); + spin_unlock_bh(&g_polling_lock); break; } f = list_first_entry(&pd->farewell_list, struct oz_farewell, link); list_del(&f->link); - oz_polling_unlock_bh(); + spin_unlock_bh(&g_polling_lock); if (ai->farewell) ai->farewell(pd, f->ep_num, f->report, f->len); kfree(f); diff --git a/drivers/staging/ozwpan/ozpd.h b/drivers/staging/ozwpan/ozpd.h index 12c71295688..56e6fdf9b0b 100644 --- a/drivers/staging/ozwpan/ozpd.h +++ b/drivers/staging/ozwpan/ozpd.h @@ -22,6 +22,11 @@ #define OZ_TIMER_HEARTBEAT 2 #define OZ_TIMER_STOP 3 +/* + *External spinlock variable + */ +extern spinlock_t g_polling_lock; + /* Data structure that hold information on a frame for transmisson. This is * built when the frame is first transmitted and is used to rebuild the frame * if a re-transmission is required. diff --git a/drivers/staging/ozwpan/ozproto.c b/drivers/staging/ozwpan/ozproto.c index e7138ed325d..c1325a67d32 100644 --- a/drivers/staging/ozwpan/ozproto.c +++ b/drivers/staging/ozwpan/ozproto.c @@ -38,9 +38,13 @@ struct oz_binding { }; /* + * External variable + */ + +DEFINE_SPINLOCK(g_polling_lock); +/* * Static external variables. */ -static DEFINE_SPINLOCK(g_polling_lock); static LIST_HEAD(g_pd_list); static LIST_HEAD(g_binding); static DEFINE_SPINLOCK(g_binding_lock); @@ -794,12 +798,3 @@ int oz_get_pd_list(struct oz_mac_addr *addr, int max_count) return count; } -void oz_polling_lock_bh(void) -{ - spin_lock_bh(&g_polling_lock); -} - -void oz_polling_unlock_bh(void) -{ - spin_unlock_bh(&g_polling_lock); -} diff --git a/drivers/staging/ozwpan/ozproto.h b/drivers/staging/ozwpan/ozproto.h index 0c49c8a0e81..cb38e02c968 100644 --- a/drivers/staging/ozwpan/ozproto.h +++ b/drivers/staging/ozwpan/ozproto.h @@ -59,8 +59,6 @@ void oz_binding_remove(const char *net_dev); void oz_timer_add(struct oz_pd *pd, int type, unsigned long due_time); void oz_timer_delete(struct oz_pd *pd, int type); void oz_pd_request_heartbeat(struct oz_pd *pd); -void oz_polling_lock_bh(void); -void oz_polling_unlock_bh(void); void oz_pd_heartbeat_handler(unsigned long data); void oz_pd_timeout_handler(unsigned long data); enum hrtimer_restart oz_pd_heartbeat_event(struct hrtimer *timer); diff --git a/drivers/staging/panel/panel.c b/drivers/staging/panel/panel.c index ec4b1fd1402..08f9a489611 100644 --- a/drivers/staging/panel/panel.c +++ b/drivers/staging/panel/panel.c @@ -171,8 +171,8 @@ struct logical_input { union { struct { /* valid when type == INPUT_TYPE_STD */ - void (*press_fct) (int); - void (*release_fct) (int); + void (*press_fct)(int); + void (*release_fct)(int); int press_data; int release_data; } std; @@ -417,9 +417,9 @@ static char lcd_must_clear; static char lcd_left_shift; static char init_in_progress; -static void (*lcd_write_cmd) (int); -static void (*lcd_write_data) (int); -static void (*lcd_clear_fast) (void); +static void (*lcd_write_cmd)(int); +static void (*lcd_write_data)(int); +static void (*lcd_clear_fast)(void); static DEFINE_SPINLOCK(pprt_lock); static struct timer_list scan_timer; @@ -457,14 +457,12 @@ MODULE_PARM_DESC(keypad_enabled, "Deprecated option, use keypad_type instead"); static int lcd_type = -1; module_param(lcd_type, int, 0000); MODULE_PARM_DESC(lcd_type, - "LCD type: 0=none, 1=old //, 2=serial ks0074, " - "3=hantronix //, 4=nexcom //, 5=compiled-in"); + "LCD type: 0=none, 1=old //, 2=serial ks0074, 3=hantronix //, 4=nexcom //, 5=compiled-in"); static int lcd_proto = -1; module_param(lcd_proto, int, 0000); MODULE_PARM_DESC(lcd_proto, - "LCD communication: 0=parallel (//), 1=serial," - "2=TI LCD Interface"); + "LCD communication: 0=parallel (//), 1=serial, 2=TI LCD Interface"); static int lcd_charset = -1; module_param(lcd_charset, int, 0000); @@ -473,8 +471,7 @@ MODULE_PARM_DESC(lcd_charset, "LCD character set: 0=standard, 1=KS0074"); static int keypad_type = -1; module_param(keypad_type, int, 0000); MODULE_PARM_DESC(keypad_type, - "Keypad type: 0=none, 1=old 6 keys, 2=new 6+1 keys, " - "3=nexcom 4 keys"); + "Keypad type: 0=none, 1=old 6 keys, 2=new 6+1 keys, 3=nexcom 4 keys"); static int profile = DEFAULT_PROFILE; module_param(profile, int, 0000); @@ -494,38 +491,32 @@ MODULE_PARM_DESC(profile, static int lcd_e_pin = PIN_NOT_SET; module_param(lcd_e_pin, int, 0000); MODULE_PARM_DESC(lcd_e_pin, - "# of the // port pin connected to LCD 'E' signal, " - "with polarity (-17..17)"); + "# of the // port pin connected to LCD 'E' signal, with polarity (-17..17)"); static int lcd_rs_pin = PIN_NOT_SET; module_param(lcd_rs_pin, int, 0000); MODULE_PARM_DESC(lcd_rs_pin, - "# of the // port pin connected to LCD 'RS' signal, " - "with polarity (-17..17)"); + "# of the // port pin connected to LCD 'RS' signal, with polarity (-17..17)"); static int lcd_rw_pin = PIN_NOT_SET; module_param(lcd_rw_pin, int, 0000); MODULE_PARM_DESC(lcd_rw_pin, - "# of the // port pin connected to LCD 'RW' signal, " - "with polarity (-17..17)"); + "# of the // port pin connected to LCD 'RW' signal, with polarity (-17..17)"); static int lcd_bl_pin = PIN_NOT_SET; module_param(lcd_bl_pin, int, 0000); MODULE_PARM_DESC(lcd_bl_pin, - "# of the // port pin connected to LCD backlight, " - "with polarity (-17..17)"); + "# of the // port pin connected to LCD backlight, with polarity (-17..17)"); static int lcd_da_pin = PIN_NOT_SET; module_param(lcd_da_pin, int, 0000); MODULE_PARM_DESC(lcd_da_pin, - "# of the // port pin connected to serial LCD 'SDA' " - "signal, with polarity (-17..17)"); + "# of the // port pin connected to serial LCD 'SDA' signal, with polarity (-17..17)"); static int lcd_cl_pin = PIN_NOT_SET; module_param(lcd_cl_pin, int, 0000); MODULE_PARM_DESC(lcd_cl_pin, - "# of the // port pin connected to serial LCD 'SCL' " - "signal, with polarity (-17..17)"); + "# of the // port pin connected to serial LCD 'SCL' signal, with polarity (-17..17)"); static const unsigned char *lcd_char_conv; @@ -2017,9 +2008,9 @@ static struct logical_input *panel_bind_key(const char *name, const char *press, * be bound. */ static struct logical_input *panel_bind_callback(char *name, - void (*press_fct) (int), + void (*press_fct)(int), int press_data, - void (*release_fct) (int), + void (*release_fct)(int), int release_data) { struct logical_input *callback; diff --git a/drivers/staging/rtl8187se/Module.symvers b/drivers/staging/rtl8187se/Module.symvers new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/drivers/staging/rtl8187se/Module.symvers diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211.h b/drivers/staging/rtl8187se/ieee80211/ieee80211.h index 09ffd9bc899..4978b2bba18 100644 --- a/drivers/staging/rtl8187se/ieee80211/ieee80211.h +++ b/drivers/staging/rtl8187se/ieee80211/ieee80211.h @@ -709,10 +709,10 @@ enum {WMM_all_frame, WMM_two_frame, WMM_four_frame, WMM_six_frame}; #define MAX_IE_LEN 0xFF //+YJ,080625 -typedef struct _CHANNEL_LIST{ - u8 Channel[MAX_CHANNEL_NUMBER + 1]; - u8 Len; -}CHANNEL_LIST, *PCHANNEL_LIST; +struct rtl8187se_channel_list { + u8 channel[MAX_CHANNEL_NUMBER + 1]; + u8 len; +}; //by amy for ps #define IEEE80211_WATCH_DOG_TIME 2000 diff --git a/drivers/staging/rtl8187se/r8180.h b/drivers/staging/rtl8187se/r8180.h index 8999ec62450..5ac46737157 100644 --- a/drivers/staging/rtl8187se/r8180.h +++ b/drivers/staging/rtl8187se/r8180.h @@ -1,19 +1,18 @@ /* - This is part of rtl8180 OpenSource driver. - Copyright (C) Andrea Merello 2004-2005 <andrea.merello@gmail.com> - Released under the terms of GPL (General Public Licence) - - Parts of this driver are based on the GPL part of the - official realtek driver - - Parts of this driver are based on the rtl8180 driver skeleton - from Patric Schenke & Andres Salomon - - Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver - - We want to thanks the Authors of those projects and the Ndiswrapper - project Authors. -*/ + * This is part of rtl8180 OpenSource driver. + * Copyright (C) Andrea Merello 2004-2005 <andrea.merello@gmail.com> + * Released under the terms of GPL (General Public Licence) + * + * Parts of this driver are based on the GPL part of the official realtek driver + * + * Parts of this driver are based on the rtl8180 driver skeleton from Patric + * Schenke & Andres Salomon + * + * Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver + * + * We want to thanks the Authors of those projects and the Ndiswrapper project + * Authors. + */ #ifndef R8180H #define R8180H @@ -21,13 +20,13 @@ #include <linux/interrupt.h> #define RTL8180_MODULE_NAME "r8180" -#define DMESG(x,a...) printk(KERN_INFO RTL8180_MODULE_NAME ": " x "\n", ## a) -#define DMESGW(x,a...) printk(KERN_WARNING RTL8180_MODULE_NAME ": WW:" x "\n", ## a) -#define DMESGE(x,a...) printk(KERN_WARNING RTL8180_MODULE_NAME ": EE:" x "\n", ## a) +#define DMESG(x, a...) printk(KERN_INFO RTL8180_MODULE_NAME ": " x "\n", ## a) +#define DMESGW(x, a...) printk(KERN_WARNING RTL8180_MODULE_NAME ": WW:" x "\n", ## a) +#define DMESGE(x, a...) printk(KERN_WARNING RTL8180_MODULE_NAME ": EE:" x "\n", ## a) #include <linux/module.h> #include <linux/kernel.h> -//#include <linux/config.h> +/* #include <linux/config.h> */ #include <linux/ioport.h> #include <linux/sched.h> #include <linux/types.h> @@ -36,22 +35,22 @@ #include <linux/pci.h> #include <linux/etherdevice.h> #include <linux/delay.h> -#include <linux/rtnetlink.h> //for rtnl_lock() +#include <linux/rtnetlink.h> /* for rtnl_lock() */ #include <linux/wireless.h> #include <linux/timer.h> -#include <linux/proc_fs.h> // Necessary because we use the proc fs +#include <linux/proc_fs.h> /* Necessary because we use the proc fs. */ #include <linux/if_arp.h> #include "ieee80211/ieee80211.h" #include <asm/io.h> -//#include <asm/semaphore.h> +/* #include <asm/semaphore.h> */ #define EPROM_93c46 0 #define EPROM_93c56 1 -#define RTL_IOCTL_WPA_SUPPLICANT SIOCIWFIRSTPRIV+30 +#define RTL_IOCTL_WPA_SUPPLICANT (SIOCIWFIRSTPRIV + 30) #define DEFAULT_FRAG_THRESHOLD 2342U -#define MIN_FRAG_THRESHOLD 256U +#define MIN_FRAG_THRESHOLD 256U #define DEFAULT_RTS_THRESHOLD 2342U #define MIN_RTS_THRESHOLD 0U #define MAX_RTS_THRESHOLD 2342U @@ -60,14 +59,14 @@ #define DEFAULT_RETRY_RTS 7 #define DEFAULT_RETRY_DATA 7 -#define BEACON_QUEUE 6 +#define BEACON_QUEUE 6 -#define aSifsTime 10 +#define aSifsTime 10 -#define sCrcLng 4 -#define sAckCtsLng 112 // bits in ACK and CTS frames -//+by amy 080312 -#define RATE_ADAPTIVE_TIMER_PERIOD 300 +#define sCrcLng 4 +#define sAckCtsLng 112 /* bits in ACK and CTS frames. */ +/* +by amy 080312. */ +#define RATE_ADAPTIVE_TIMER_PERIOD 300 typedef enum _WIRELESS_MODE { WIRELESS_MODE_UNKNOWN = 0x00, @@ -77,115 +76,111 @@ typedef enum _WIRELESS_MODE { WIRELESS_MODE_AUTO = 0x08, } WIRELESS_MODE; -typedef struct ChnlAccessSetting { - u16 SIFS_Timer; - u16 DIFS_Timer; - u16 SlotTimeTimer; - u16 EIFS_Timer; - u16 CWminIndex; - u16 CWmaxIndex; -}*PCHANNEL_ACCESS_SETTING,CHANNEL_ACCESS_SETTING; +struct chnl_access_setting { + u16 sifs_timer; + u16 difs_timer; + u16 slot_time_timer; + u16 eifs_timer; + u16 cwmin_index; + u16 cwmax_index; +}; -typedef enum{ - NIC_8185 = 1, - NIC_8185B - } nic_t; +typedef enum { + NIC_8185 = 1, + NIC_8185B + } nic_t; typedef u32 AC_CODING; -#define AC0_BE 0 // ACI: 0x00 // Best Effort -#define AC1_BK 1 // ACI: 0x01 // Background -#define AC2_VI 2 // ACI: 0x10 // Video -#define AC3_VO 3 // ACI: 0x11 // Voice -#define AC_MAX 4 // Max: define total number; Should not to be used as a real enum. - -// -// ECWmin/ECWmax field. -// Ref: WMM spec 2.2.2: WME Parameter Element, p.13. -// -typedef union _ECW{ - u8 charData; - struct - { - u8 ECWmin:4; - u8 ECWmax:4; - }f; // Field -}ECW, *PECW; - -// -// ACI/AIFSN Field. -// Ref: WMM spec 2.2.2: WME Parameter Element, p.12. -// -typedef union _ACI_AIFSN{ - u8 charData; - - struct - { - u8 AIFSN:4; - u8 ACM:1; - u8 ACI:2; - u8 Reserved:1; - }f; // Field -}ACI_AIFSN, *PACI_AIFSN; - -// -// AC Parameters Record Format. -// Ref: WMM spec 2.2.2: WME Parameter Element, p.12. -// -typedef union _AC_PARAM{ - u32 longData; - u8 charData[4]; - - struct - { - ACI_AIFSN AciAifsn; - ECW Ecw; - u16 TXOPLimit; - }f; // Field -}AC_PARAM, *PAC_PARAM; +#define AC0_BE 0 /* ACI: 0x00 */ /* Best Effort. */ +#define AC1_BK 1 /* ACI: 0x01 */ /* Background. */ +#define AC2_VI 2 /* ACI: 0x10 */ /* Video. */ +#define AC3_VO 3 /* ACI: 0x11 */ /* Voice. */ +#define AC_MAX 4 /* Max: define total number; Should not to be used as a real + * enum. + */ -/* it is a wrong definition. -xiong-2006-11-17 -typedef struct ThreeWireReg { - u16 longData; +/* + * ECWmin/ECWmax field. + * Ref: WMM spec 2.2.2: WME Parameter Element, p.13. + */ +typedef union _ECW { + u8 charData; struct { - u8 enableB; - u8 data; - u8 clk; - u8 read_write; + u8 ECWmin:4; + u8 ECWmax:4; + } f; /* Field */ +} ECW, *PECW; + +/* + * ACI/AIFSN Field. Ref: WMM spec 2.2.2: WME Parameter Element, p.12. + */ +typedef union _ACI_AIFSN { + u8 charData; + + struct { + u8 AIFSN:4; + u8 ACM:1; + u8 ACI:2; + u8 Reserved:1; + } f; /* Field */ +} ACI_AIFSN, *PACI_AIFSN; + +/* + * AC Parameters Record Format. + * Ref: WMM spec 2.2.2: WME Parameter Element, p.12. + */ +typedef union _AC_PARAM { + u32 longData; + u8 charData[4]; + + struct { + ACI_AIFSN AciAifsn; + ECW Ecw; + u16 TXOPLimit; + } f; /* Field */ +} AC_PARAM, *PAC_PARAM; + +/* it is a wrong definition. -xiong-2006-11-17 + * typedef struct ThreeWireReg { + * u16 longData; + * struct { + * u8 enableB; + * u8 data; + * u8 clk; + * u8 read_write; + * } struc; + * } ThreeWireReg; + */ + +typedef union _ThreeWire { + struct _ThreeWireStruc { + u16 data:1; + u16 clk:1; + u16 enableB:1; + u16 read_write:1; + u16 resv1:12; + /* u2Byte resv2:14; */ + /* u2Byte ThreeWireEnable:1; */ + /* u2Byte resv3:1; */ } struc; + u16 longData; } ThreeWireReg; -*/ - -typedef union _ThreeWire{ - struct _ThreeWireStruc{ - u16 data:1; - u16 clk:1; - u16 enableB:1; - u16 read_write:1; - u16 resv1:12; -// u2Byte resv2:14; -// u2Byte ThreeWireEnable:1; -// u2Byte resv3:1; - }struc; - u16 longData; -}ThreeWireReg; - - -typedef struct buffer -{ + + +typedef struct buffer { struct buffer *next; u32 *buf; dma_addr_t dma; } buffer; -//YJ,modified,080828 -typedef struct Stats -{ +/* YJ,modified,080828. */ +struct stats { unsigned long txrdu; unsigned long rxrdu; unsigned long rxnolast; unsigned long rxnodata; -// unsigned long rxreset; -// unsigned long rxwrkaround; + /* unsigned long rxreset; */ + /* unsigned long rxwrkaround; */ unsigned long rxnopointer; unsigned long txnperr; unsigned long txresumed; @@ -207,52 +202,59 @@ typedef struct Stats unsigned long txbeaconerr; unsigned long txlpokint; unsigned long txlperr; - unsigned long txretry;//retry number tony 20060601 - unsigned long rxcrcerrmin;//crc error (0-500) - unsigned long rxcrcerrmid;//crc error (500-1000) - unsigned long rxcrcerrmax;//crc error (>1000) - unsigned long rxicverr;//ICV error -} Stats; + unsigned long txretry; /* retry number tony 20060601 */ + unsigned long rxcrcerrmin; /* crc error (0-500) */ + unsigned long rxcrcerrmid; /* crc error (500-1000) */ + unsigned long rxcrcerrmax; /* crc error (>1000) */ + unsigned long rxicverr; /* ICV error */ +}; #define MAX_LD_SLOT_NUM 10 -#define KEEP_ALIVE_INTERVAL 20 // in seconds. -#define CHECK_FOR_HANG_PERIOD 2 //be equal to watchdog check time -#define DEFAULT_KEEP_ALIVE_LEVEL 1 -#define DEFAULT_SLOT_NUM 2 -#define POWER_PROFILE_AC 0 -#define POWER_PROFILE_BATTERY 1 - -typedef struct _link_detect_t -{ - u32 RxFrameNum[MAX_LD_SLOT_NUM]; // number of Rx Frame / CheckForHang_period to determine link status - u16 SlotNum; // number of CheckForHang period to determine link status, default is 2 - u16 SlotIndex; - - u32 NumTxOkInPeriod; //number of packet transmitted during CheckForHang - u32 NumRxOkInPeriod; //number of packet received during CheckForHang - - u8 IdleCount; // (KEEP_ALIVE_INTERVAL / CHECK_FOR_HANG_PERIOD) - u32 LastNumTxUnicast; - u32 LastNumRxUnicast; - - bool bBusyTraffic; //when it is set to 1, UI cann't scan at will. -}link_detect_t, *plink_detect_t; - -//YJ,modified,080828,end - -//by amy for led -//================================================================================ -// LED customization. -//================================================================================ - -typedef enum _LED_STRATEGY_8185{ - SW_LED_MODE0, // - SW_LED_MODE1, // - HW_LED, // HW control 2 LEDs, LED0 and LED1 (there are 4 different control modes) -}LED_STRATEGY_8185, *PLED_STRATEGY_8185; -//by amy for led -//by amy for power save -typedef enum _LED_CTL_MODE{ +#define KEEP_ALIVE_INTERVAL 20 /* in seconds. */ +#define CHECK_FOR_HANG_PERIOD 2 /* be equal to watchdog check time. */ +#define DEFAULT_KEEP_ALIVE_LEVEL 1 +#define DEFAULT_SLOT_NUM 2 +#define POWER_PROFILE_AC 0 +#define POWER_PROFILE_BATTERY 1 + +struct link_detect_t { + u32 rx_frame_num[MAX_LD_SLOT_NUM]; /* number of Rx Frame. + * CheckForHang_period to determine + * link status. + */ + u16 slot_num; /* number of CheckForHang period to determine link status, + * default is 2. + */ + u16 slot_index; + u32 num_tx_ok_in_period; /* number of packet transmitted during + * CheckForHang. + */ + u32 num_rx_ok_in_period; /* number of packet received during + * CheckForHang. + */ + u8 idle_count; /* (KEEP_ALIVE_INTERVAL / CHECK_FOR_HANG_PERIOD) */ + u32 last_num_tx_unicast; + u32 last_num_rx_unicast; + + bool b_busy_traffic; /* when it is set to 1, UI cann't scan at will. */ +}; + +/* YJ,modified,080828,end */ + +/* by amy for led + * ========================================================================== + * LED customization. + * ========================================================================== + */ +typedef enum _LED_STRATEGY_8185 { + SW_LED_MODE0, + SW_LED_MODE1, + HW_LED, /* HW control 2 LEDs, LED0 and LED1 (there are 4 different + * control modes). */ +} LED_STRATEGY_8185, *PLED_STRATEGY_8185; +/* by amy for led. */ +/* by amy for power save. */ +typedef enum _LED_CTL_MODE { LED_CTL_POWER_ON = 1, LED_CTL_LINK = 2, LED_CTL_NO_LINK = 3, @@ -260,73 +262,74 @@ typedef enum _LED_CTL_MODE{ LED_CTL_RX = 5, LED_CTL_SITE_SURVEY = 6, LED_CTL_POWER_OFF = 7 -}LED_CTL_MODE; +} LED_CTL_MODE; -typedef enum _RT_RF_POWER_STATE -{ +typedef enum _RT_RF_POWER_STATE { eRfOn, eRfSleep, eRfOff -}RT_RF_POWER_STATE; - -enum _ReasonCode{ - unspec_reason = 0x1, - auth_not_valid = 0x2, - deauth_lv_ss = 0x3, - inactivity = 0x4, - ap_overload = 0x5, - class2_err = 0x6, - class3_err = 0x7, - disas_lv_ss = 0x8, - asoc_not_auth = 0x9, - - //----MIC_CHECK - mic_failure = 0xe, - //----END MIC_CHECK - - // Reason code defined in 802.11i D10.0 p.28. - invalid_IE = 0x0d, - four_way_tmout = 0x0f, - two_way_tmout = 0x10, - IE_dismatch = 0x11, +} RT_RF_POWER_STATE; + +enum _ReasonCode { + unspec_reason = 0x1, + auth_not_valid = 0x2, + deauth_lv_ss = 0x3, + inactivity = 0x4, + ap_overload = 0x5, + class2_err = 0x6, + class3_err = 0x7, + disas_lv_ss = 0x8, + asoc_not_auth = 0x9, + + /* ----MIC_CHECK */ + mic_failure = 0xe, + /* ----END MIC_CHECK */ + + /* Reason code defined in 802.11i D10.0 p.28. */ + invalid_IE = 0x0d, + four_way_tmout = 0x0f, + two_way_tmout = 0x10, + IE_dismatch = 0x11, invalid_Gcipher = 0x12, invalid_Pcipher = 0x13, - invalid_AKMP = 0x14, + invalid_AKMP = 0x14, unsup_RSNIEver = 0x15, - invalid_RSNIE = 0x16, - auth_802_1x_fail= 0x17, - ciper_reject = 0x18, - - // Reason code defined in 7.3.1.7, 802.1e D13.0, p.42. Added by Annie, 2005-11-15. - QoS_unspec = 0x20, // 32 - QAP_bandwidth = 0x21, // 33 - poor_condition = 0x22, // 34 - no_facility = 0x23, // 35 - // Where is 36??? - req_declined = 0x25, // 37 - invalid_param = 0x26, // 38 - req_not_honored= 0x27, // 39 - TS_not_created = 0x2F, // 47 - DL_not_allowed = 0x30, // 48 - dest_not_exist = 0x31, // 49 - dest_not_QSTA = 0x32, // 50 + invalid_RSNIE = 0x16, + auth_802_1x_fail = 0x17, + ciper_reject = 0x18, + + /* Reason code defined in 7.3.1.7, 802.1e D13.0, p.42. Added by Annie, + * 2005-11-15. + */ + QoS_unspec = 0x20, /* 32 */ + QAP_bandwidth = 0x21, /* 33 */ + poor_condition = 0x22, /* 34 */ + no_facility = 0x23, /* 35 */ + /* Where is 36??? */ + req_declined = 0x25, /* 37 */ + invalid_param = 0x26, /* 38 */ + req_not_honored = 0x27, /* 39 */ + TS_not_created = 0x2F, /* 47 */ + DL_not_allowed = 0x30, /* 48 */ + dest_not_exist = 0x31, /* 49 */ + dest_not_QSTA = 0x32, /* 50 */ }; -typedef enum _RT_PS_MODE -{ - eActive, // Active/Continuous access. - eMaxPs, // Max power save mode. - eFastPs // Fast power save mode. -}RT_PS_MODE; -//by amy for power save -typedef struct r8180_priv -{ + +typedef enum _RT_PS_MODE { + eActive, /* Active/Continuous access. */ + eMaxPs, /* Max power save mode. */ + eFastPs /* Fast power save mode. */ +} RT_PS_MODE; + +/* by amy for power save. */ +typedef struct r8180_priv { struct pci_dev *pdev; short epromtype; int irq; struct ieee80211_device *ieee80211; - short plcp_preamble_mode; // 0:auto 1:short 2:long + short plcp_preamble_mode; /* 0:auto 1:short 2:long */ spinlock_t irq_th_lock; spinlock_t tx_lock; @@ -339,19 +342,20 @@ typedef struct r8180_priv short chan; short sens; short max_sens; - u8 chtxpwr[15]; //channels from 1 to 14, 0 not used - u8 chtxpwr_ofdm[15]; //channels from 1 to 14, 0 not used - //u8 challow[15]; //channels from 1 to 14, 0 not used - u8 channel_plan; // it's the channel plan index + u8 chtxpwr[15]; /* channels from 1 to 14, 0 not used. */ + u8 chtxpwr_ofdm[15]; /* channels from 1 to 14, 0 not used. */ + /* u8 challow[15]; */ /* channels from 1 to 14, 0 not used. */ + u8 channel_plan; /* it's the channel plan index. */ short up; - short crcmon; //if 1 allow bad crc frame reception in monitor mode + short crcmon; /* if 1 allow bad crc frame reception in monitor mode. */ struct timer_list scan_timer; - /*short scanpending; - short stopscan;*/ + /* short scanpending; + * short stopscan; + */ spinlock_t scan_lock; u8 active_probe; - //u8 active_scan_num; + /* u8 active_scan_num; */ struct semaphore wx_sem; short hw_wep; @@ -359,20 +363,20 @@ typedef struct r8180_priv short antb; short diversity; u32 key0[4]; - short (*rf_set_sens)(struct net_device *dev,short sens); - void (*rf_set_chan)(struct net_device *dev,short ch); + short (*rf_set_sens)(struct net_device *dev, short sens); + void (*rf_set_chan)(struct net_device *dev, short ch); void (*rf_close)(struct net_device *dev); void (*rf_init)(struct net_device *dev); void (*rf_sleep)(struct net_device *dev); void (*rf_wakeup)(struct net_device *dev); - //short rate; + /* short rate; */ short promisc; - /*stats*/ - struct Stats stats; - struct _link_detect_t link_detect; //YJ,add,080828 + /* stats */ + struct stats stats; + struct link_detect_t link_detect; /* YJ,add,080828 */ struct iw_statistics wstats; - /*RX stuff*/ + /* RX stuff. */ u32 *rxring; u32 *rxringtail; dma_addr_t rxringdma; @@ -387,27 +391,27 @@ typedef struct r8180_priv u32 rx_prevlen; - /*TX stuff*/ -/* - u32 *txlpring; - u32 *txhpring; - u32 *txnpring; - dma_addr_t txlpringdma; - dma_addr_t txhpringdma; - dma_addr_t txnpringdma; - u32 *txlpringtail; - u32 *txhpringtail; - u32 *txnpringtail; - u32 *txlpringhead; - u32 *txhpringhead; - u32 *txnpringhead; - struct buffer *txlpbufs; - struct buffer *txhpbufs; - struct buffer *txnpbufs; - struct buffer *txlpbufstail; - struct buffer *txhpbufstail; - struct buffer *txnpbufstail; -*/ + /* TX stuff */ + /* + * u32 *txlpring; + * u32 *txhpring; + * u32 *txnpring; + * dma_addr_t txlpringdma; + * dma_addr_t txhpringdma; + * dma_addr_t txnpringdma; + * u32 *txlpringtail; + * u32 *txhpringtail; + * u32 *txnpringtail; + * u32 *txlpringhead; + * u32 *txhpringhead; + * u32 *txnpringhead; + * struct buffer *txlpbufs; + * struct buffer *txhpbufs; + * struct buffer *txnpbufs; + * struct buffer *txlpbufstail; + * struct buffer *txhpbufstail; + * struct buffer *txnpbufstail; + */ u32 *txmapring; u32 *txbkpring; u32 *txbepring; @@ -447,54 +451,56 @@ typedef struct r8180_priv int txringcount; int txbuffsize; - //struct tx_pendingbuf txnp_pending; - //struct tasklet_struct irq_tx_tasklet; + /* struct tx_pendingbuf txnp_pending; */ + /* struct tasklet_struct irq_tx_tasklet; */ struct tasklet_struct irq_rx_tasklet; u8 dma_poll_mask; - //short tx_suspend; + /* short tx_suspend; */ - /* adhoc/master mode stuff */ + /* adhoc/master mode stuff. */ u32 *txbeaconringtail; dma_addr_t txbeaconringdma; u32 *txbeaconring; int txbeaconcount; struct buffer *txbeaconbufs; struct buffer *txbeaconbufstail; - //char *master_essid; - //u16 master_beaconinterval; - //u32 master_beaconsize; - //u16 beacon_interval; + /* char *master_essid; */ + /* u16 master_beaconinterval; */ + /* u32 master_beaconsize; */ + /* u16 beacon_interval; */ u8 retry_data; u8 retry_rts; u16 rts; -//by amy for led + /* by amy for led. */ LED_STRATEGY_8185 LedStrategy; -//by amy for led + /* by amy for led. */ -//by amy for power save + /* by amy for power save. */ struct timer_list watch_dog_timer; bool bInactivePs; bool bSwRfProcessing; - RT_RF_POWER_STATE eInactivePowerState; + RT_RF_POWER_STATE eInactivePowerState; RT_RF_POWER_STATE eRFPowerState; u32 RfOffReason; bool RFChangeInProgress; bool SetRFPowerStateInProgress; - u8 RFProgType; + u8 RFProgType; bool bLeisurePs; RT_PS_MODE dot11PowerSaveMode; - //u32 NumRxOkInPeriod; //YJ,del,080828 - //u32 NumTxOkInPeriod; //YJ,del,080828 - u8 TxPollingTimes; - - bool bApBufOurFrame;// TRUE if AP buffer our unicast data , we will keep eAwake until receive data or timeout. - u8 WaitBufDataBcnCount; - u8 WaitBufDataTimeOut; - -//by amy for power save -//by amy for antenna + /* u32 NumRxOkInPeriod;*/ /* YJ,del,080828 */ + /* u32 NumTxOkInPeriod;*/ /* YJ,del,080828 */ + u8 TxPollingTimes; + + bool bApBufOurFrame; /* TRUE if AP buffer our unicast data , we will + * keep eAwake until receive data or timeout. + */ + u8 WaitBufDataBcnCount; + u8 WaitBufDataTimeOut; + + /* by amy for power save. */ + /* by amy for antenna. */ u8 EEPROMSwAntennaDiversity; bool EEPROMDefaultAntenna1; u8 RegSwAntennaDiversityMechanism; @@ -503,115 +509,133 @@ typedef struct r8180_priv bool bDefaultAntenna1; u8 SignalStrength; long Stats_SignalStrength; - long LastSignalStrengthInPercent; // In percentage, used for smoothing, e.g. Moving Average. - u8 SignalQuality; // in 0-100 index. + long LastSignalStrengthInPercent; /* In percentage, used for smoothing, + * e.g. Moving Average. + */ + u8 SignalQuality; /* in 0-100 index. */ long Stats_SignalQuality; - long RecvSignalPower; // in dBm. + long RecvSignalPower; /* in dBm. */ long Stats_RecvSignalPower; - u8 LastRxPktAntenna; // +by amy 080312 Antenna which received the lasted packet. 0: Aux, 1:Main. Added by Roger, 2008.01.25. + u8 LastRxPktAntenna; /* +by amy 080312 Antenna which received the lasted + * packet. 0: Aux, 1:Main. Added by Roger, + * 2008.01.25. + */ u32 AdRxOkCnt; long AdRxSignalStrength; - u8 CurrAntennaIndex; // Index to current Antenna (both Tx and Rx). - u8 AdTickCount; // Times of SwAntennaDiversityTimer happened. - u8 AdCheckPeriod; // # of period SwAntennaDiversityTimer to check Rx signal strength for SW Antenna Diversity. - u8 AdMinCheckPeriod; // Min value of AdCheckPeriod. - u8 AdMaxCheckPeriod; // Max value of AdCheckPeriod. - long AdRxSsThreshold; // Signal strength threshold to switch antenna. - long AdMaxRxSsThreshold; // Max value of AdRxSsThreshold. - bool bAdSwitchedChecking; // TRUE if we shall shall check Rx signal strength for last time switching antenna. - long AdRxSsBeforeSwitched; // Rx signal strength before we switched antenna. + u8 CurrAntennaIndex; /* Index to current Antenna (both Tx and Rx). */ + u8 AdTickCount; /* Times of SwAntennaDiversityTimer happened. */ + u8 AdCheckPeriod; /* # of period SwAntennaDiversityTimer to check Rx + * signal strength for SW Antenna Diversity. + */ + u8 AdMinCheckPeriod; /* Min value of AdCheckPeriod. */ + u8 AdMaxCheckPeriod; /* Max value of AdCheckPeriod. */ + long AdRxSsThreshold; /* Signal strength threshold to switch antenna. */ + long AdMaxRxSsThreshold; /* Max value of AdRxSsThreshold. */ + bool bAdSwitchedChecking; /* TRUE if we shall shall check Rx signal + * strength for last time switching antenna. + */ + long AdRxSsBeforeSwitched; /* Rx signal strength before we switched + * antenna. + */ struct timer_list SwAntennaDiversityTimer; -//by amy for antenna -//{by amy 080312 -// - // Crystal calibration. - // Added by Roger, 2007.12.11. - // - bool bXtalCalibration; // Crystal calibration. - u8 XtalCal_Xin; // Crystal calibration for Xin. 0~7.5pF - u8 XtalCal_Xout; // Crystal calibration for Xout. 0~7.5pF - // - // Tx power tracking with thermal meter indication. - // Added by Roger, 2007.12.11. - // - bool bTxPowerTrack; // Tx Power tracking. - u8 ThermalMeter; // Thermal meter reference indication. - // - // Dynamic Initial Gain Adjustment Mechanism. Added by Bruce, 2007-02-14. - // - bool bDigMechanism; // TRUE if DIG is enabled, FALSE ow. - bool bRegHighPowerMechanism; // For High Power Mechanism. 061010, by rcnjko. - u32 FalseAlarmRegValue; - u8 RegDigOfdmFaUpTh; // Upper threshold of OFDM false alarm, which is used in DIG. - u8 DIG_NumberFallbackVote; - u8 DIG_NumberUpgradeVote; - // For HW antenna diversity, added by Roger, 2008.01.30. - u32 AdMainAntennaRxOkCnt; // Main antenna Rx OK count. - u32 AdAuxAntennaRxOkCnt; // Aux antenna Rx OK count. - bool bHWAdSwitched; // TRUE if we has switched default antenna by HW evaluation. - // RF High Power upper/lower threshold. - u8 RegHiPwrUpperTh; - u8 RegHiPwrLowerTh; - // RF RSSI High Power upper/lower Threshold. - u8 RegRSSIHiPwrUpperTh; - u8 RegRSSIHiPwrLowerTh; - // Current CCK RSSI value to determine CCK high power, asked by SD3 DZ, by Bruce, 2007-04-12. - u8 CurCCKRSSI; - bool bCurCCKPkt; - // - // High Power Mechanism. Added by amy, 080312. - // - bool bToUpdateTxPwr; - long UndecoratedSmoothedSS; - long UndercorateSmoothedRxPower; - u8 RSSI; - char RxPower; - u8 InitialGain; - //For adjust Dig Threshold during Legacy/Leisure Power Save Mode - u32 DozePeriodInPast2Sec; - // Don't access BB/RF under disable PLL situation. - u8 InitialGainBackUp; - u8 RegBModeGainStage; -//by amy for rate adaptive - struct timer_list rateadapter_timer; - u32 RateAdaptivePeriod; - bool bEnhanceTxPwr; - bool bUpdateARFR; - int ForcedDataRate; // Force Data Rate. 0: Auto, 0x02: 1M ~ 0x6C: 54M.) - u32 NumTxUnicast; //YJ,add,080828,for keep alive - u8 keepAliveLevel; //YJ,add,080828,for KeepAlive - unsigned long NumTxOkTotal; - u16 LastRetryCnt; - u16 LastRetryRate; - unsigned long LastTxokCnt; - unsigned long LastRxokCnt; - u16 CurrRetryCnt; - unsigned long LastTxOKBytes; - unsigned long NumTxOkBytesTotal; - u8 LastFailTxRate; - long LastFailTxRateSS; - u8 FailTxRateCount; - u32 LastTxThroughput; - //for up rate - unsigned short bTryuping; - u8 CurrTxRate; //the rate before up - u16 CurrRetryRate; - u16 TryupingCount; - u8 TryDownCountLowData; - u8 TryupingCountNoData; - - u8 CurrentOperaRate; -//by amy for rate adaptive -//by amy 080312} -// short wq_hurryup; -// struct workqueue_struct *workqueue; + /* by amy for antenna {by amy 080312 */ + + /* Crystal calibration. Added by Roger, 2007.12.11. */ + + bool bXtalCalibration; /* Crystal calibration.*/ + u8 XtalCal_Xin; /* Crystal calibration for Xin. 0~7.5pF */ + u8 XtalCal_Xout; /* Crystal calibration for Xout. 0~7.5pF */ + + /* Tx power tracking with thermal meter indication. + * Added by Roger, 2007.12.11. + */ + + bool bTxPowerTrack; /* Tx Power tracking. */ + u8 ThermalMeter; /* Thermal meter reference indication. */ + + /* Dynamic Initial Gain Adjustment Mechanism. Added by Bruce, + * 2007-02-14. + */ + bool bDigMechanism; /* TRUE if DIG is enabled, FALSE ow. */ + bool bRegHighPowerMechanism; /* For High Power Mechanism. 061010, + * by rcnjko. + */ + u32 FalseAlarmRegValue; + u8 RegDigOfdmFaUpTh; /* Upper threshold of OFDM false alarm, which is + * used in DIG. + */ + u8 DIG_NumberFallbackVote; + u8 DIG_NumberUpgradeVote; + /* For HW antenna diversity, added by Roger, 2008.01.30. */ + u32 AdMainAntennaRxOkCnt; /* Main antenna Rx OK count. */ + u32 AdAuxAntennaRxOkCnt; /* Aux antenna Rx OK count. */ + bool bHWAdSwitched; /* TRUE if we has switched default antenna by HW + * evaluation. + */ + /* RF High Power upper/lower threshold. */ + u8 RegHiPwrUpperTh; + u8 RegHiPwrLowerTh; + /* RF RSSI High Power upper/lower Threshold. */ + u8 RegRSSIHiPwrUpperTh; + u8 RegRSSIHiPwrLowerTh; + /* Current CCK RSSI value to determine CCK high power, asked by SD3 DZ, + * by Bruce, 2007-04-12. + */ + u8 CurCCKRSSI; + bool bCurCCKPkt; + /* High Power Mechanism. Added by amy, 080312. */ + bool bToUpdateTxPwr; + long UndecoratedSmoothedSS; + long UndecoratedSmoothedRxPower; + u8 RSSI; + char RxPower; + u8 InitialGain; + /* For adjust Dig Threshold during Legacy/Leisure Power Save Mode. */ + u32 DozePeriodInPast2Sec; + /* Don't access BB/RF under disable PLL situation. */ + u8 InitialGainBackUp; + u8 RegBModeGainStage; + /* by amy for rate adaptive */ + struct timer_list rateadapter_timer; + u32 RateAdaptivePeriod; + bool bEnhanceTxPwr; + bool bUpdateARFR; + int ForcedDataRate; /* Force Data Rate. 0: Auto, 0x02: 1M ~ 0x6C: 54M.) + */ + u32 NumTxUnicast; /* YJ,add,080828,for keep alive. */ + u8 keepAliveLevel; /*YJ,add,080828,for KeepAlive. */ + unsigned long NumTxOkTotal; + u16 LastRetryCnt; + u16 LastRetryRate; + unsigned long LastTxokCnt; + unsigned long LastRxokCnt; + u16 CurrRetryCnt; + unsigned long LastTxOKBytes; + unsigned long NumTxOkBytesTotal; + u8 LastFailTxRate; + long LastFailTxRateSS; + u8 FailTxRateCount; + u32 LastTxThroughput; + /* for up rate. */ + unsigned short bTryuping; + u8 CurrTxRate; /* the rate before up. */ + u16 CurrRetryRate; + u16 TryupingCount; + u8 TryDownCountLowData; + u8 TryupingCountNoData; + + u8 CurrentOperaRate; + /* by amy for rate adaptive. */ + /* by amy 080312} */ + /* short wq_hurryup; */ + /* struct workqueue_struct *workqueue; */ struct work_struct reset_wq; struct work_struct watch_dog_wq; short ack_tx_to_ieee; u8 dma_poll_stop_mask; - //u8 RegThreeWireMode; + /* u8 RegThreeWireMode; */ u16 ShortRetryLimit; u16 LongRetryLimit; u16 EarlyRxThreshold; @@ -619,8 +643,8 @@ typedef struct r8180_priv u32 ReceiveConfig; u32 IntrMask; - struct ChnlAccessSetting ChannelAccessSetting; -}r8180_priv; + struct chnl_access_setting ChannelAccessSetting; +} r8180_priv; #define MANAGE_PRIORITY 0 #define BK_PRIORITY 1 @@ -632,7 +656,7 @@ typedef struct r8180_priv #define LOW_PRIORITY VI_PRIORITY #define NORM_PRIORITY VO_PRIORITY -//AC2Queue mapping +/* AC2Queue mapping. */ #define AC2Q(_ac) (((_ac) == WME_AC_VO) ? VO_PRIORITY : \ ((_ac) == WME_AC_VI) ? VI_PRIORITY : \ ((_ac) == WME_AC_BK) ? BK_PRIORITY : \ @@ -673,7 +697,7 @@ void UpdateInitialGain(struct net_device *dev); bool SetAntennaConfig87SE(struct net_device *dev, u8 DefaultAnt, bool bAntDiversity); -//#ifdef CONFIG_RTL8185B +/* #ifdef CONFIG_RTL8185B */ void rtl8185b_adapter_start(struct net_device *dev); void rtl8185b_rx_enable(struct net_device *dev); void rtl8185b_tx_enable(struct net_device *dev); @@ -682,8 +706,8 @@ void rtl8185b_irq_enable(struct net_device *dev); void fix_rx_fifo(struct net_device *dev); void fix_tx_fifo(struct net_device *dev); void rtl8225z2_SetTXPowerLevel(struct net_device *dev, short ch); -void rtl8180_rate_adapter(struct work_struct * work); -//#endif +void rtl8180_rate_adapter(struct work_struct *work); +/* #endif */ bool MgntActSet_RF_State(struct net_device *dev, RT_RF_POWER_STATE StateToSet, u32 ChangeSource); diff --git a/drivers/staging/rtl8187se/r8180_core.c b/drivers/staging/rtl8187se/r8180_core.c index 6cafee22bec..dc434b88dcc 100644 --- a/drivers/staging/rtl8187se/r8180_core.c +++ b/drivers/staging/rtl8187se/r8180_core.c @@ -1,31 +1,31 @@ /* - This is part of rtl818x pci OpenSource driver - v 0.1 - Copyright (C) Andrea Merello 2004-2005 <andrea.merello@gmail.com> - Released under the terms of GPL (General Public License) - - Parts of this driver are based on the GPL part of the official - Realtek driver. - - Parts of this driver are based on the rtl8180 driver skeleton - from Patric Schenke & Andres Salomon. - - Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver. - - Parts of BB/RF code are derived from David Young rtl8180 netbsd driver. - - RSSI calc function from 'The Deuce' - - Some ideas borrowed from the 8139too.c driver included in linux kernel. - - We (I?) want to thanks the Authors of those projecs and also the - Ndiswrapper's project Authors. - - A big big thanks goes also to Realtek corp. for their help in my attempt to - add RTL8185 and RTL8225 support, and to David Young also. - - Power management interface routines. - Written by Mariusz Matuszek. -*/ + * This is part of rtl818x pci OpenSource driver - v 0.1 + * Copyright (C) Andrea Merello 2004-2005 <andrea.merello@gmail.com> + * Released under the terms of GPL (General Public License) + * + * Parts of this driver are based on the GPL part of the official + * Realtek driver. + * + * Parts of this driver are based on the rtl8180 driver skeleton + * from Patric Schenke & Andres Salomon. + * + * Parts of this driver are based on the Intel Pro Wireless 2100 GPL driver. + * + * Parts of BB/RF code are derived from David Young rtl8180 netbsd driver. + * + * RSSI calc function from 'The Deuce' + * + * Some ideas borrowed from the 8139too.c driver included in linux kernel. + * + * We (I?) want to thanks the Authors of those projecs and also the + * Ndiswrapper's project Authors. + * + * A big big thanks goes also to Realtek corp. for their help in my attempt to + * add RTL8185 and RTL8225 support, and to David Young also. + * + * Power management interface routines. + * Written by Mariusz Matuszek. + */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -258,7 +258,9 @@ static int proc_get_stats_tx(struct seq_file *m, void *v) struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); unsigned long totalOK; - totalOK = priv->stats.txnpokint+priv->stats.txhpokint+priv->stats.txlpokint; + totalOK = priv->stats.txnpokint + priv->stats.txhpokint + + priv->stats.txlpokint; + seq_printf(m, "TX OK: %lu\n" "TX Error: %lu\n" @@ -347,9 +349,9 @@ static void rtl8180_proc_init_one(struct net_device *dev) } /* - FIXME: check if we can use some standard already-existent - data type+functions in kernel -*/ + * FIXME: check if we can use some standard already-existent + * data type+functions in kernel. + */ static short buffer_add(struct buffer **buffer, u32 *buf, dma_addr_t dma, struct buffer **bufferhead) @@ -468,9 +470,11 @@ static short check_nic_enought_desc(struct net_device *dev, int priority) { struct r8180_priv *priv = ieee80211_priv(dev); struct ieee80211_device *ieee = netdev_priv(dev); - int requiredbyte, required; + int requiredbyte; + int required; - requiredbyte = priv->ieee80211->fts + sizeof(struct ieee80211_header_data); + requiredbyte = priv->ieee80211->fts + + sizeof(struct ieee80211_header_data); if (ieee->current_network.QoS_Enable) requiredbyte += 2; @@ -484,7 +488,7 @@ static short check_nic_enought_desc(struct net_device *dev, int priority) * between the tail and the head */ - return (required+2 < get_curr_tx_free_desc(dev, priority)); + return required + 2 < get_curr_tx_free_desc(dev, priority); } void fix_tx_fifo(struct net_device *dev) @@ -649,7 +653,7 @@ void rtl8180_set_chan(struct net_device *dev, short ch) struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); if ((ch > 14) || (ch < 1)) { - printk("In %s: Invalid chnanel %d\n", __func__, ch); + netdev_err(dev, "In %s: Invalid channel %d\n", __func__, ch); return; } @@ -742,43 +746,50 @@ static short alloc_tx_desc_ring(struct net_device *dev, int bufsize, int count, switch (addr) { case TX_MANAGEPRIORITY_RING_ADDR: - if (-1 == buffer_add(&(priv->txmapbufs), buf, dma_tmp, NULL)) { + if (-1 == buffer_add(&priv->txmapbufs, + buf, dma_tmp, NULL)) { DMESGE("Unable to allocate mem for buffer NP"); return -ENOMEM; } break; case TX_BKPRIORITY_RING_ADDR: - if (-1 == buffer_add(&(priv->txbkpbufs), buf, dma_tmp, NULL)) { + if (-1 == buffer_add(&priv->txbkpbufs, + buf, dma_tmp, NULL)) { DMESGE("Unable to allocate mem for buffer LP"); return -ENOMEM; } break; case TX_BEPRIORITY_RING_ADDR: - if (-1 == buffer_add(&(priv->txbepbufs), buf, dma_tmp, NULL)) { + if (-1 == buffer_add(&priv->txbepbufs, + buf, dma_tmp, NULL)) { DMESGE("Unable to allocate mem for buffer NP"); return -ENOMEM; } break; case TX_VIPRIORITY_RING_ADDR: - if (-1 == buffer_add(&(priv->txvipbufs), buf, dma_tmp, NULL)) { + if (-1 == buffer_add(&priv->txvipbufs, + buf, dma_tmp, NULL)) { DMESGE("Unable to allocate mem for buffer LP"); return -ENOMEM; } break; case TX_VOPRIORITY_RING_ADDR: - if (-1 == buffer_add(&(priv->txvopbufs), buf, dma_tmp, NULL)) { + if (-1 == buffer_add(&priv->txvopbufs, + buf, dma_tmp, NULL)) { DMESGE("Unable to allocate mem for buffer NP"); return -ENOMEM; } break; case TX_HIGHPRIORITY_RING_ADDR: - if (-1 == buffer_add(&(priv->txhpbufs), buf, dma_tmp, NULL)) { + if (-1 == buffer_add(&priv->txhpbufs, + buf, dma_tmp, NULL)) { DMESGE("Unable to allocate mem for buffer HP"); return -ENOMEM; } break; case TX_BEACON_RING_ADDR: - if (-1 == buffer_add(&(priv->txbeaconbufs), buf, dma_tmp, NULL)) { + if (-1 == buffer_add(&priv->txbeaconbufs, + buf, dma_tmp, NULL)) { DMESGE("Unable to allocate mem for buffer BP"); return -ENOMEM; } @@ -897,8 +908,8 @@ static short alloc_rx_desc_ring(struct net_device *dev, u16 bufsize, int count) return -1; } - desc = (u32 *)pci_alloc_consistent(pdev, sizeof(u32)*rx_desc_size*count+256, - &dma_desc); + desc = (u32 *)pci_alloc_consistent(pdev, + sizeof(u32) * rx_desc_size * count + 256, &dma_desc); if (dma_desc & 0xff) /* @@ -935,7 +946,8 @@ static short alloc_rx_desc_ring(struct net_device *dev, u16 bufsize, int count) tmp = tmp+rx_desc_size; } - *(tmp-rx_desc_size) = *(tmp-rx_desc_size) | (1<<30); /* this is the last descriptor */ + /* this is the last descriptor */ + *(tmp - rx_desc_size) = *(tmp - rx_desc_size) | (1 << 30); return 0; } @@ -1009,7 +1021,8 @@ inline u16 ieeerate2rtlrate(int rate) } } -static u16 rtl_rate[] = {10, 20, 55, 110, 60, 90, 120, 180, 240, 360, 480, 540, 720}; +static u16 rtl_rate[] = {10, 20, 55, 110, 60, + 90, 120, 180, 240, 360, 480, 540, 720}; inline u16 rtl8180_rate2rate(short rate) { @@ -1143,23 +1156,30 @@ static long TranslateToDbm8185(u8 SignalStrengthIndex) /* * Perform signal smoothing for dynamic mechanism. * This is different with PerformSignalSmoothing8185 in smoothing formula. - * No dramatic adjustion is apply because dynamic mechanism need some degree - * of correctness. Ported from 8187B. + * No dramatic adjustment is applied because dynamic mechanism need some + * degree of correctness. Ported from 8187B. */ static void PerformUndecoratedSignalSmoothing8185(struct r8180_priv *priv, bool bCckRate) { - /* Determin the current packet is CCK rate. */ + long smoothedSS; + long smoothedRx; + + /* Determine the current packet is CCK rate. */ priv->bCurCCKPkt = bCckRate; + smoothedSS = priv->SignalStrength * 10; + if (priv->UndecoratedSmoothedSS >= 0) - priv->UndecoratedSmoothedSS = ((priv->UndecoratedSmoothedSS * 5) + - (priv->SignalStrength * 10)) / 6; - else - priv->UndecoratedSmoothedSS = priv->SignalStrength * 10; + smoothedSS = ((priv->UndecoratedSmoothedSS * 5) + + smoothedSS) / 6; - priv->UndercorateSmoothedRxPower = ((priv->UndercorateSmoothedRxPower * 50) + - (priv->RxPower * 11)) / 60; + priv->UndecoratedSmoothedSS = smoothedSS; + + smoothedRx = ((priv->UndecoratedSmoothedRxPower * 50) + + (priv->RxPower * 11)) / 60; + + priv->UndecoratedSmoothedRxPower = smoothedRx; if (bCckRate) priv->CurCCKRSSI = priv->RSSI; @@ -1206,8 +1226,9 @@ static void rtl8180_rx(struct net_device *dev) rx_desc_size = 8; if ((*(priv->rxringtail)) & (1<<31)) { - /* we have got an RX int, but the descriptor - * we are pointing is empty */ + /* we have got an RX int, but the descriptor. we are pointing + * is empty. + */ priv->stats.rxnodata++; priv->ieee80211->stats.rx_errors++; @@ -1216,7 +1237,8 @@ static void rtl8180_rx(struct net_device *dev) tmp = priv->rxringtail; do { if (tmp == priv->rxring) - tmp = priv->rxring + (priv->rxringcount - 1)*rx_desc_size; + tmp = priv->rxring + (priv->rxringcount - 1) * + rx_desc_size; else tmp -= rx_desc_size; @@ -1254,10 +1276,9 @@ static void rtl8180_rx(struct net_device *dev) if (last) { lastlen = ((*priv->rxringtail) & 0xfff); - /* if the last descriptor (that should - * tell us the total packet len) tell - * us something less than the descriptors - * len we had until now, then there is some + /* if the last descriptor (that should tell us the total + * packet len) tell us something less than the + * descriptors len we had until now, then there is some * problem.. * workaround to prevent kernel panic */ @@ -1293,31 +1314,36 @@ static void rtl8180_rx(struct net_device *dev) priv->rx_prevlen += len; if (priv->rx_prevlen > MAX_FRAG_THRESHOLD + 100) { - /* HW is probably passing several buggy frames - * without FD or LD flag set. - * Throw this garbage away to prevent skb - * memory exhausting - */ + /* HW is probably passing several buggy frames without + * FD or LD flag set. + * Throw this garbage away to prevent skb memory + * exhausting + */ if (!priv->rx_skb_complete) dev_kfree_skb_any(priv->rx_skb); priv->rx_skb_complete = 1; } - signal = (unsigned char)(((*(priv->rxringtail+3)) & (0x00ff0000))>>16); + signal = (unsigned char)(*(priv->rxringtail + 3) & + 0x00ff0000) >> 16; signal = (signal & 0xfe) >> 1; quality = (unsigned char)((*(priv->rxringtail+3)) & (0xff)); stats.mac_time[0] = *(priv->rxringtail+1); stats.mac_time[1] = *(priv->rxringtail+2); - rxpower = ((char)(((*(priv->rxringtail+4)) & (0x00ff0000))>>16))/2 - 42; - RSSI = ((u8)(((*(priv->rxringtail+3)) & (0x0000ff00))>>8)) & (0x7f); + + rxpower = ((char)((*(priv->rxringtail + 4) & + 0x00ff0000) >> 16)) / 2 - 42; + + RSSI = ((u8)((*(priv->rxringtail + 3) & + 0x0000ff00) >> 8)) & 0x7f; rate = ((*(priv->rxringtail)) & ((1<<23)|(1<<22)|(1<<21)|(1<<20)))>>20; stats.rate = rtl8180_rate2rate(rate); - Antenna = (((*(priv->rxringtail+3)) & (0x00008000)) == 0) ? 0 : 1; + Antenna = (*(priv->rxringtail + 3) & 0x00008000) == 0 ? 0 : 1; if (!rtl8180_IsWirelessBMode(stats.rate)) { /* OFDM rate. */ RxAGC_dBm = rxpower+1; /* bias */ } else { /* CCK rate. */ @@ -1326,7 +1352,8 @@ static void rtl8180_rx(struct net_device *dev) LNA = (u8) (RxAGC_dBm & 0x60) >> 5; /* bit 6~ bit 5 */ BB = (u8) (RxAGC_dBm & 0x1F); /* bit 4 ~ bit 0 */ - RxAGC_dBm = -(LNA_gain[LNA] + (BB*2)); /* Pin_11b=-(LNA_gain+BB_gain) (dBm) */ + /* Pin_11b=-(LNA_gain+BB_gain) (dBm) */ + RxAGC_dBm = -(LNA_gain[LNA] + (BB * 2)); RxAGC_dBm += 4; /* bias */ } @@ -1354,21 +1381,25 @@ static void rtl8180_rx(struct net_device *dev) priv->RSSI = RSSI; /* SQ translation formula is provided by SD3 DZ. 2006.06.27 */ if (quality >= 127) - quality = 1; /*0; */ /* 0 will cause epc to show signal zero , walk around now; */ + /* 0 causes epc to show signal zero, walk around now */ + quality = 1; else if (quality < 27) quality = 100; else quality = 127 - quality; priv->SignalQuality = quality; - stats.signal = (u8)quality; /*priv->wstats.qual.level = priv->SignalStrength; */ + /*priv->wstats.qual.level = priv->SignalStrength; */ + stats.signal = (u8) quality; + stats.signalstrength = RXAGC; if (stats.signalstrength > 100) stats.signalstrength = 100; - stats.signalstrength = (stats.signalstrength * 70)/100 + 30; + stats.signalstrength = (stats.signalstrength * 70) / 100 + 30; /* printk("==========================>rx : RXAGC is %d,signalstrength is %d\n",RXAGC,stats.signalstrength); */ stats.rssi = priv->wstats.qual.qual = priv->SignalQuality; - stats.noise = priv->wstats.qual.noise = 100 - priv->wstats.qual.qual; + stats.noise = priv->wstats.qual.noise = + 100 - priv->wstats.qual.qual; bHwError = (((*(priv->rxringtail)) & (0x00000fff)) == 4080) | (((*(priv->rxringtail)) & (0x04000000)) != 0) | (((*(priv->rxringtail)) & (0x08000000)) != 0) | @@ -1397,27 +1428,40 @@ static void rtl8180_rx(struct net_device *dev) /* For good-looking singal strength. */ SignalStrengthIndex = NetgearSignalStrengthTranslate( - priv->LastSignalStrengthInPercent, - priv->SignalStrength); + priv->LastSignalStrengthInPercent, + priv->SignalStrength); priv->LastSignalStrengthInPercent = SignalStrengthIndex; - priv->Stats_SignalStrength = TranslateToDbm8185((u8)SignalStrengthIndex); - /* - * We need more correct power of received packets and the "SignalStrength" of RxStats is beautified, - * so we record the correct power here. - */ - priv->Stats_SignalQuality = (long)(priv->Stats_SignalQuality * 5 + (long)priv->SignalQuality + 5) / 6; - priv->Stats_RecvSignalPower = (long)(priv->Stats_RecvSignalPower * 5 + priv->RecvSignalPower - 1) / 6; + priv->Stats_SignalStrength = + TranslateToDbm8185((u8)SignalStrengthIndex); + + /* + * We need more correct power of received packets and + * the "SignalStrength" of RxStats is beautified, so we + * record the correct power here. + */ - /* Figure out which antenna that received the last packet. */ - priv->LastRxPktAntenna = Antenna ? 1 : 0; /* 0: aux, 1: main. */ + priv->Stats_SignalQuality = (long)( + priv->Stats_SignalQuality * 5 + + (long)priv->SignalQuality + 5) / 6; + + priv->Stats_RecvSignalPower = (long)( + priv->Stats_RecvSignalPower * 5 + + priv->RecvSignalPower - 1) / 6; + + /* + * Figure out which antenna received the last packet. + * 0: aux, 1: main + */ + priv->LastRxPktAntenna = Antenna ? 1 : 0; SwAntennaDiversityRxOk8185(dev, priv->SignalStrength); } if (first) { if (!priv->rx_skb_complete) { /* seems that HW sometimes fails to receive and - doesn't provide the last descriptor */ + * doesn't provide the last descriptor. + */ dev_kfree_skb_any(priv->rx_skb); priv->stats.rxnolast++; } @@ -1428,15 +1472,16 @@ static void rtl8180_rx(struct net_device *dev) priv->rx_skb_complete = 0; priv->rx_skb->dev = dev; } else { - /* if we are here we should have already RXed - * the first frame. - * If we get here and the skb is not allocated then - * we have just throw out garbage (skb not allocated) - * and we are still rxing garbage.... - */ + /* if we are here we should have already RXed the first + * frame. + * If we get here and the skb is not allocated then + * we have just throw out garbage (skb not allocated) + * and we are still rxing garbage.... + */ if (!priv->rx_skb_complete) { - tmp_skb = dev_alloc_skb(priv->rx_skb->len+len+2); + tmp_skb = dev_alloc_skb( + priv->rx_skb->len + len + 2); if (!tmp_skb) goto drop; @@ -1454,13 +1499,8 @@ static void rtl8180_rx(struct net_device *dev) } if (!priv->rx_skb_complete) { - if (padding) { - memcpy(skb_put(priv->rx_skb, len), - (((unsigned char *)priv->rxbuffer->buf) + 2), len); - } else { - memcpy(skb_put(priv->rx_skb, len), - priv->rxbuffer->buf, len); - } + memcpy(skb_put(priv->rx_skb, len), ((unsigned char *) + priv->rxbuffer->buf) + (padding ? 2 : 0), len); } if (last && !priv->rx_skb_complete) { @@ -1538,7 +1578,7 @@ static void rtl8180_hard_data_xmit(struct sk_buff *skb, struct net_device *dev, { struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); int mode; - struct ieee80211_hdr_3addr *h = (struct ieee80211_hdr_3addr *) skb->data; + struct ieee80211_hdr_3addr *h = (struct ieee80211_hdr_3addr *)skb->data; short morefrag = (h->frame_control) & IEEE80211_FCTL_MOREFRAGS; unsigned long flags; int priority; @@ -1547,11 +1587,10 @@ static void rtl8180_hard_data_xmit(struct sk_buff *skb, struct net_device *dev, rate = ieeerate2rtlrate(rate); /* - * This function doesn't require lock because we make - * sure it's called with the tx_lock already acquired. - * this come from the kernel's hard_xmit callback (through - * the ieee stack, or from the try_wake_queue (again through - * the ieee stack. + * This function doesn't require lock because we make sure it's called + * with the tx_lock already acquired. + * This come from the kernel's hard_xmit callback (through the ieee + * stack, or from the try_wake_queue (again through the ieee stack. */ priority = AC2Q(skb->priority); spin_lock_irqsave(&priv->tx_lock, flags); @@ -1613,55 +1652,6 @@ static int rtl8180_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_OK; } -/* longpre 144+48 shortpre 72+24 */ -u16 rtl8180_len2duration(u32 len, short rate, short *ext) -{ - u16 duration; - u16 drift; - *ext = 0; - - switch (rate) { - case 0: /* 1mbps */ - *ext = 0; - duration = ((len+4)<<4) / 0x2; - drift = ((len+4)<<4) % 0x2; - if (drift == 0) - break; - duration++; - break; - case 1: /* 2mbps */ - *ext = 0; - duration = ((len+4)<<4) / 0x4; - drift = ((len+4)<<4) % 0x4; - if (drift == 0) - break; - duration++; - break; - case 2: /* 5.5mbps */ - *ext = 0; - duration = ((len+4)<<4) / 0xb; - drift = ((len+4)<<4) % 0xb; - if (drift == 0) - break; - duration++; - break; - default: - case 3: /* 11mbps */ - *ext = 0; - duration = ((len+4)<<4) / 0x16; - drift = ((len+4)<<4) % 0x16; - if (drift == 0) - break; - duration++; - if (drift > 6) - break; - *ext = 1; - break; - } - - return duration; -} - static void rtl8180_prepare_beacon(struct net_device *dev) { struct r8180_priv *priv = (struct r8180_priv *)ieee80211_priv(dev); @@ -1669,7 +1659,10 @@ static void rtl8180_prepare_beacon(struct net_device *dev) u16 word = read_nic_word(dev, BcnItv); word &= ~BcnItv_BcnItv; /* clear Bcn_Itv */ - word |= cpu_to_le16(priv->ieee80211->current_network.beacon_interval); /* 0x64; */ + + /* word |= 0x64; */ + word |= cpu_to_le16(priv->ieee80211->current_network.beacon_interval); + write_nic_word(dev, BcnItv, word); skb = ieee80211_get_beacon(priv->ieee80211); @@ -1681,9 +1674,9 @@ static void rtl8180_prepare_beacon(struct net_device *dev) } /* - * This function do the real dirty work: it enqueues a TX command - * descriptor in the ring buffer, copyes the frame in a TX buffer - * and kicks the NIC to ensure it does the DMA transfer. + * This function do the real dirty work: it enqueues a TX command descriptor in + * the ring buffer, copyes the frame in a TX buffer and kicks the NIC to ensure + * it does the DMA transfer. */ short rtl8180_tx(struct net_device *dev, u8 *txbuf, int len, int priority, short morefrag, short descfrag, int rate) @@ -1697,16 +1690,17 @@ short rtl8180_tx(struct net_device *dev, u8 *txbuf, int len, int priority, int buflen; int count; struct buffer *buflist; - struct ieee80211_hdr_3addr *frag_hdr = (struct ieee80211_hdr_3addr *)txbuf; + struct ieee80211_hdr_3addr *frag_hdr = + (struct ieee80211_hdr_3addr *)txbuf; u8 dest[ETH_ALEN]; - u8 bUseShortPreamble = 0; - u8 bCTSEnable = 0; - u8 bRTSEnable = 0; - u16 Duration = 0; - u16 RtsDur = 0; - u16 ThisFrameTime = 0; - u16 TxDescDuration = 0; - bool ownbit_flag = false; + u8 bUseShortPreamble = 0; + u8 bCTSEnable = 0; + u8 bRTSEnable = 0; + u16 Duration = 0; + u16 RtsDur = 0; + u16 ThisFrameTime = 0; + u16 TxDescDuration = 0; + bool ownbit_flag = false; switch (priority) { case MANAGE_PRIORITY: @@ -1756,74 +1750,80 @@ short rtl8180_tx(struct net_device *dev, u8 *txbuf, int len, int priority, break; } - memcpy(&dest, frag_hdr->addr1, ETH_ALEN); - if (is_multicast_ether_addr(dest)) { - Duration = 0; - RtsDur = 0; - bRTSEnable = 0; + memcpy(&dest, frag_hdr->addr1, ETH_ALEN); + if (is_multicast_ether_addr(dest)) { + Duration = 0; + RtsDur = 0; + bRTSEnable = 0; + bCTSEnable = 0; + + ThisFrameTime = ComputeTxTime(len + sCrcLng, + rtl8180_rate2rate(rate), 0, bUseShortPreamble); + TxDescDuration = ThisFrameTime; + } else { /* Unicast packet */ + u16 AckTime; + + /* YJ,add,080828,for Keep alive */ + priv->NumTxUnicast++; + + /* Figure out ACK rate according to BSS basic rate + * and Tx rate. + * AckCTSLng = 14 use 1M bps send + */ + AckTime = ComputeTxTime(14, 10, 0, 0); + + if (((len + sCrcLng) > priv->rts) && priv->rts) { /* RTS/CTS. */ + u16 RtsTime, CtsTime; + /* u16 CtsRate; */ + bRTSEnable = 1; bCTSEnable = 0; - ThisFrameTime = ComputeTxTime(len + sCrcLng, rtl8180_rate2rate(rate), - 0, bUseShortPreamble); - TxDescDuration = ThisFrameTime; - } else { /* Unicast packet */ - u16 AckTime; - - /* YJ,add,080828,for Keep alive */ - priv->NumTxUnicast++; - - /* Figure out ACK rate according to BSS basic rate - * and Tx rate. */ - AckTime = ComputeTxTime(14, 10, 0, 0); /* AckCTSLng = 14 use 1M bps send */ - - if (((len + sCrcLng) > priv->rts) && priv->rts) { /* RTS/CTS. */ - u16 RtsTime, CtsTime; - /* u16 CtsRate; */ - bRTSEnable = 1; - bCTSEnable = 0; - - /* Rate and time required for RTS. */ - RtsTime = ComputeTxTime(sAckCtsLng/8, priv->ieee80211->basic_rate, 0, 0); - /* Rate and time required for CTS. */ - CtsTime = ComputeTxTime(14, 10, 0, 0); /* AckCTSLng = 14 use 1M bps send */ - - /* Figure out time required to transmit this frame. */ - ThisFrameTime = ComputeTxTime(len + sCrcLng, - rtl8180_rate2rate(rate), - 0, - bUseShortPreamble); - - /* RTS-CTS-ThisFrame-ACK. */ - RtsDur = CtsTime + ThisFrameTime + AckTime + 3*aSifsTime; - - TxDescDuration = RtsTime + RtsDur; - } else { /* Normal case. */ - bCTSEnable = 0; - bRTSEnable = 0; - RtsDur = 0; - - ThisFrameTime = ComputeTxTime(len + sCrcLng, rtl8180_rate2rate(rate), - 0, bUseShortPreamble); - TxDescDuration = ThisFrameTime + aSifsTime + AckTime; - } + /* Rate and time required for RTS. */ + RtsTime = ComputeTxTime(sAckCtsLng / 8, + priv->ieee80211->basic_rate, 0, 0); - if (!(frag_hdr->frame_control & IEEE80211_FCTL_MOREFRAGS)) { - /* ThisFrame-ACK. */ - Duration = aSifsTime + AckTime; - } else { /* One or more fragments remained. */ - u16 NextFragTime; - NextFragTime = ComputeTxTime(len + sCrcLng, /* pretend following packet length equal current packet */ - rtl8180_rate2rate(rate), - 0, - bUseShortPreamble); - - /* ThisFrag-ACk-NextFrag-ACK. */ - Duration = NextFragTime + 3*aSifsTime + 2*AckTime; - } + /* Rate and time required for CTS. + * AckCTSLng = 14 use 1M bps send + */ + CtsTime = ComputeTxTime(14, 10, 0, 0); - } /* End of Unicast packet */ + /* Figure out time required to transmit this frame. */ + ThisFrameTime = ComputeTxTime(len + sCrcLng, + rtl8180_rate2rate(rate), 0, + bUseShortPreamble); - frag_hdr->duration_id = Duration; + /* RTS-CTS-ThisFrame-ACK. */ + RtsDur = CtsTime + ThisFrameTime + + AckTime + 3 * aSifsTime; + + TxDescDuration = RtsTime + RtsDur; + } else { /* Normal case. */ + bCTSEnable = 0; + bRTSEnable = 0; + RtsDur = 0; + + ThisFrameTime = ComputeTxTime(len + sCrcLng, + rtl8180_rate2rate(rate), 0, bUseShortPreamble); + TxDescDuration = ThisFrameTime + aSifsTime + AckTime; + } + + if (!(frag_hdr->frame_control & IEEE80211_FCTL_MOREFRAGS)) { + /* ThisFrame-ACK. */ + Duration = aSifsTime + AckTime; + } else { /* One or more fragments remained. */ + u16 NextFragTime; + + /* pretend following packet length = current packet */ + NextFragTime = ComputeTxTime(len + sCrcLng, + rtl8180_rate2rate(rate), 0, bUseShortPreamble); + + /* ThisFrag-ACk-NextFrag-ACK. */ + Duration = NextFragTime + 3 * aSifsTime + 2 * AckTime; + } + + } /* End of Unicast packet */ + + frag_hdr->duration_id = Duration; buflen = priv->txbuffsize; remain = len; @@ -1832,7 +1832,8 @@ short rtl8180_tx(struct net_device *dev, u8 *txbuf, int len, int priority, while (remain != 0) { mb(); if (!buflist) { - DMESGE("TX buffer error, cannot TX frames. pri %d.", priority); + DMESGE("TX buffer error, cannot TX frames. pri %d.", + priority); return -1; } buf = buflist->buf; @@ -1851,43 +1852,54 @@ short rtl8180_tx(struct net_device *dev, u8 *txbuf, int len, int priority, *(tail+6) = 0; *(tail+7) = 0; - /* FIXME: this should be triggered by HW encryption parameters.*/ + /* FIXME: should be triggered by HW encryption parameters.*/ *tail |= (1<<15); /* no encrypt */ if (remain == len && !descfrag) { ownbit_flag = false; - *tail = *tail | (1<<29); /* fist segment of the packet */ + *tail = *tail | (1 << 29); /* first segment of packet */ *tail = *tail | (len); } else { ownbit_flag = true; } for (i = 0; i < buflen && remain > 0; i++, remain--) { - ((u8 *)buf)[i] = txbuf[i]; /* copy data into descriptor pointed DMAble buffer */ + /* copy data into descriptor pointed DMAble buffer */ + ((u8 *)buf)[i] = txbuf[i]; + if (remain == 4 && i+4 >= buflen) break; /* ensure the last desc has at least 4 bytes payload */ - } txbuf = txbuf + i; *(tail+3) = *(tail+3) & ~0xfff; *(tail+3) = *(tail+3) | i; /* buffer length */ - /* Use short preamble or not */ - if (priv->ieee80211->current_network.capability&WLAN_CAPABILITY_SHORT_PREAMBLE) - if (priv->plcp_preamble_mode == 1 && rate != 0) /* short mode now, not long! */ - ; /* *tail |= (1<<16); */ /* enable short preamble mode. */ + + /* Use short preamble or not - if true, enable short preamble */ + /* + if (priv->ieee80211->current_network.capability & + WLAN_CAPABILITY_SHORT_PREAMBLE && + priv->plcp_preamble_mode == 1 && rate != 0) { + *tail |= (1 << 16); + } + */ if (bCTSEnable) *tail |= (1<<18); if (bRTSEnable) { /* rts enable */ - *tail |= ((ieeerate2rtlrate(priv->ieee80211->basic_rate))<<19); /* RTS RATE */ + /* RTS RATE */ + *tail |= (ieeerate2rtlrate( + priv->ieee80211->basic_rate) << 19); + *tail |= (1<<23); /* rts enable */ *(tail+1) |= (RtsDur&0xffff); /* RTS Duration */ } *(tail+3) |= ((TxDescDuration&0xffff)<<16); /* DURATION */ /* *(tail+3) |= (0xe6<<16); */ - *(tail+5) |= (11<<8); /* (priv->retry_data<<8); */ /* retry lim; */ + + /* (priv->retry_data<<8); */ + *(tail + 5) |= (11 << 8); /* retry lim; */ *tail = *tail | ((rate&0xf) << 24); @@ -1901,7 +1913,8 @@ short rtl8180_tx(struct net_device *dev, u8 *txbuf, int len, int priority, wmb(); if (ownbit_flag) - *tail = *tail | (1<<31); /* descriptor ready to be txed */ + /* descriptor ready to be txed */ + *tail |= (1 << 31); if ((tail - begin)/8 == count-1) tail = begin; @@ -1983,7 +1996,8 @@ static void rtl8180_rq_tx_ack(struct net_device *dev) struct r8180_priv *priv = ieee80211_priv(dev); - write_nic_byte(dev, CONFIG4, read_nic_byte(dev, CONFIG4) | CONFIG4_PWRMGT); + write_nic_byte(dev, CONFIG4, + read_nic_byte(dev, CONFIG4) | CONFIG4_PWRMGT); priv->ack_tx_to_ieee = 1; } @@ -2031,7 +2045,8 @@ static void rtl8180_hw_wakeup(struct net_device *dev) struct r8180_priv *priv = ieee80211_priv(dev); spin_lock_irqsave(&priv->ps_lock, flags); - write_nic_byte(dev, CONFIG4, read_nic_byte(dev, CONFIG4) & ~CONFIG4_PWRMGT); + write_nic_byte(dev, CONFIG4, + read_nic_byte(dev, CONFIG4) & ~CONFIG4_PWRMGT); if (priv->rf_wakeup) priv->rf_wakeup(dev); spin_unlock_irqrestore(&priv->ps_lock, flags); @@ -2063,13 +2078,13 @@ static void rtl8180_hw_sleep(struct net_device *dev, u32 th, u32 tl) tl -= MSECS(4+16+7); /* - * If the interval in witch we are requested to sleep is too + * If the interval in which we are requested to sleep is too * short then give up and remain awake */ if (((tl >= rb) && (tl-rb) <= MSECS(MIN_SLEEP_TIME)) || ((rb > tl) && (rb-tl) < MSECS(MIN_SLEEP_TIME))) { spin_unlock_irqrestore(&priv->ps_lock, flags); - printk("too short to sleep\n"); + netdev_warn(dev, "too short to sleep\n"); return; } @@ -2078,7 +2093,8 @@ static void rtl8180_hw_sleep(struct net_device *dev, u32 th, u32 tl) priv->DozePeriodInPast2Sec += jiffies_to_msecs(tmp); /* as tl may be less than rb */ - queue_delayed_work(priv->ieee80211->wq, &priv->ieee80211->hw_wakeup_wq, tmp); + queue_delayed_work(priv->ieee80211->wq, + &priv->ieee80211->hw_wakeup_wq, tmp); } /* * If we suspect the TimerInt is gone beyond tl @@ -2095,16 +2111,49 @@ static void rtl8180_hw_sleep(struct net_device *dev, u32 th, u32 tl) spin_unlock_irqrestore(&priv->ps_lock, flags); } +static void rtl8180_wmm_single_param_update(struct net_device *dev, + u8 mode, AC_CODING eACI, PAC_PARAM param) +{ + u8 u1bAIFS; + u32 u4bAcParam; + + /* Retrieve parameters to update. */ + /* Mode G/A: slotTimeTimer = 9; Mode B: 20 */ + u1bAIFS = param->f.AciAifsn.f.AIFSN * ((mode & IEEE_G) == IEEE_G ? + 9 : 20) + aSifsTime; + u4bAcParam = (((u32)param->f.TXOPLimit << AC_PARAM_TXOP_LIMIT_OFFSET) | + ((u32)param->f.Ecw.f.ECWmax << AC_PARAM_ECW_MAX_OFFSET) | + ((u32)param->f.Ecw.f.ECWmin << AC_PARAM_ECW_MIN_OFFSET) | + ((u32)u1bAIFS << AC_PARAM_AIFS_OFFSET)); + + switch (eACI) { + case AC1_BK: + write_nic_dword(dev, AC_BK_PARAM, u4bAcParam); + return; + case AC0_BE: + write_nic_dword(dev, AC_BE_PARAM, u4bAcParam); + return; + case AC2_VI: + write_nic_dword(dev, AC_VI_PARAM, u4bAcParam); + return; + case AC3_VO: + write_nic_dword(dev, AC_VO_PARAM, u4bAcParam); + return; + default: + pr_warn("SetHwReg8185(): invalid ACI: %d!\n", eACI); + return; + } +} + static void rtl8180_wmm_param_update(struct work_struct *work) { - struct ieee80211_device *ieee = container_of(work, struct ieee80211_device, wmm_param_update_wq); + struct ieee80211_device *ieee = container_of(work, + struct ieee80211_device, wmm_param_update_wq); struct net_device *dev = ieee->dev; u8 *ac_param = (u8 *)(ieee->current_network.wmm_param); u8 mode = ieee->current_network.mode; - AC_CODING eACI; - AC_PARAM AcParam; - PAC_PARAM pAcParam; - u8 i; + AC_CODING eACI; + AC_PARAM AcParam; if (!ieee->current_network.QoS_Enable) { /* legacy ac_xx_param update */ @@ -2114,78 +2163,24 @@ static void rtl8180_wmm_param_update(struct work_struct *work) AcParam.f.Ecw.f.ECWmin = 3; /* Follow 802.11 CWmin. */ AcParam.f.Ecw.f.ECWmax = 7; /* Follow 802.11 CWmax. */ AcParam.f.TXOPLimit = 0; + for (eACI = 0; eACI < AC_MAX; eACI++) { AcParam.f.AciAifsn.f.ACI = (u8)eACI; - { - u8 u1bAIFS; - u32 u4bAcParam; - pAcParam = (PAC_PARAM)(&AcParam); - /* Retrieve parameters to update. */ - u1bAIFS = pAcParam->f.AciAifsn.f.AIFSN * (((mode&IEEE_G) == IEEE_G) ? 9 : 20) + aSifsTime; - u4bAcParam = ((((u32)(pAcParam->f.TXOPLimit))<<AC_PARAM_TXOP_LIMIT_OFFSET)| - (((u32)(pAcParam->f.Ecw.f.ECWmax))<<AC_PARAM_ECW_MAX_OFFSET)| - (((u32)(pAcParam->f.Ecw.f.ECWmin))<<AC_PARAM_ECW_MIN_OFFSET)| - (((u32)u1bAIFS) << AC_PARAM_AIFS_OFFSET)); - switch (eACI) { - case AC1_BK: - write_nic_dword(dev, AC_BK_PARAM, u4bAcParam); - break; - case AC0_BE: - write_nic_dword(dev, AC_BE_PARAM, u4bAcParam); - break; - case AC2_VI: - write_nic_dword(dev, AC_VI_PARAM, u4bAcParam); - break; - case AC3_VO: - write_nic_dword(dev, AC_VO_PARAM, u4bAcParam); - break; - default: - pr_warn("SetHwReg8185():invalid ACI: %d!\n", - eACI); - break; - } - } + + rtl8180_wmm_single_param_update(dev, mode, eACI, + (PAC_PARAM)&AcParam); } return; } - for (i = 0; i < AC_MAX; i++) { + for (eACI = 0; eACI < AC_MAX; eACI++) { /* AcParam.longData = 0; */ - pAcParam = (AC_PARAM *)ac_param; - { - AC_CODING eACI; - u8 u1bAIFS; - u32 u4bAcParam; - - /* Retrieve parameters to update. */ - eACI = pAcParam->f.AciAifsn.f.ACI; - /* Mode G/A: slotTimeTimer = 9; Mode B: 20 */ - u1bAIFS = pAcParam->f.AciAifsn.f.AIFSN * (((mode&IEEE_G) == IEEE_G) ? 9 : 20) + aSifsTime; - u4bAcParam = ((((u32)(pAcParam->f.TXOPLimit)) << AC_PARAM_TXOP_LIMIT_OFFSET) | - (((u32)(pAcParam->f.Ecw.f.ECWmax)) << AC_PARAM_ECW_MAX_OFFSET) | - (((u32)(pAcParam->f.Ecw.f.ECWmin)) << AC_PARAM_ECW_MIN_OFFSET) | - (((u32)u1bAIFS) << AC_PARAM_AIFS_OFFSET)); - - switch (eACI) { - case AC1_BK: - write_nic_dword(dev, AC_BK_PARAM, u4bAcParam); - break; - case AC0_BE: - write_nic_dword(dev, AC_BE_PARAM, u4bAcParam); - break; - case AC2_VI: - write_nic_dword(dev, AC_VI_PARAM, u4bAcParam); - break; - case AC3_VO: - write_nic_dword(dev, AC_VO_PARAM, u4bAcParam); - break; - default: - pr_warn("SetHwReg8185(): invalid ACI: %d !\n", - eACI); - break; - } - } - ac_param += (sizeof(AC_PARAM)); + + rtl8180_wmm_single_param_update(dev, mode, + ((PAC_PARAM)ac_param)->f.AciAifsn.f.ACI, + (PAC_PARAM)ac_param); + + ac_param += sizeof(AC_PARAM); } } @@ -2208,7 +2203,8 @@ static void watch_dog_adaptive(unsigned long data) /* Tx High Power Mechanism. */ if (CheckHighPower((struct net_device *)data)) - queue_work(priv->ieee80211->wq, (void *)&priv->ieee80211->tx_pw_wq); + queue_work(priv->ieee80211->wq, + (void *)&priv->ieee80211->tx_pw_wq); /* Tx Power Tracking on 87SE. */ if (CheckTxPwrTracking((struct net_device *)data)) @@ -2216,27 +2212,59 @@ static void watch_dog_adaptive(unsigned long data) /* Perform DIG immediately. */ if (CheckDig((struct net_device *)data)) - queue_work(priv->ieee80211->wq, (void *)&priv->ieee80211->hw_dig_wq); + queue_work(priv->ieee80211->wq, + (void *)&priv->ieee80211->hw_dig_wq); + rtl8180_watch_dog((struct net_device *)data); - queue_work(priv->ieee80211->wq, (void *)&priv->ieee80211->GPIOChangeRFWorkItem); + queue_work(priv->ieee80211->wq, + (void *)&priv->ieee80211->GPIOChangeRFWorkItem); + + priv->watch_dog_timer.expires = jiffies + + MSECS(IEEE80211_WATCH_DOG_TIME); - priv->watch_dog_timer.expires = jiffies + MSECS(IEEE80211_WATCH_DOG_TIME); add_timer(&priv->watch_dog_timer); } -static CHANNEL_LIST ChannelPlan[] = { - {{1,2,3,4,5,6,7,8,9,10,11,36,40,44,48,52,56,60,64},19}, /* FCC */ - {{1,2,3,4,5,6,7,8,9,10,11},11}, /* IC */ - {{1,2,3,4,5,6,7,8,9,10,11,12,13,36,40,44,48,52,56,60,64},21}, /* ETSI */ - {{1,2,3,4,5,6,7,8,9,10,11,12,13,36,40,44,48,52,56,60,64},21}, /* Spain. Change to ETSI. */ - {{1,2,3,4,5,6,7,8,9,10,11,12,13,36,40,44,48,52,56,60,64},21}, /* France. Change to ETSI. */ - {{14,36,40,44,48,52,56,60,64},9}, /* MKK */ - {{1,2,3,4,5,6,7,8,9,10,11,12,13,14, 36,40,44,48,52,56,60,64},22},/* MKK1 */ - {{1,2,3,4,5,6,7,8,9,10,11,12,13,36,40,44,48,52,56,60,64},21}, /* Israel. */ - {{1,2,3,4,5,6,7,8,9,10,11,12,13,34,38,42,46},17}, /* For 11a , TELEC */ - {{1,2,3,4,5,6,7,8,9,10,11,12,13,14},14}, /* For Global Domain. 1-11:active scan, 12-14 passive scan. //+YJ, 080626 */ - {{1,2,3,4,5,6,7,8,9,10,11,12,13},13} /* world wide 13: ch1~ch11 active scan, ch12~13 passive //lzm add 080826 */ +static struct rtl8187se_channel_list channel_plan_list[] = { + /* FCC */ + {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 36, 40, + 44, 48, 52, 56, 60, 64}, 19}, + + /* IC */ + {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 11}, + + /* ETSI */ + {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 36, 40, + 44, 48, 52, 56, 60, 64}, 21}, + + /* Spain. Change to ETSI. */ + {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 36, 40, + 44, 48, 52, 56, 60, 64}, 21}, + + /* France. Change to ETSI. */ + {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 36, 40, + 44, 48, 52, 56, 60, 64}, 21}, + + /* MKK */ + {{14, 36, 40, 44, 48, 52, 56, 60, 64}, 9}, + + /* MKK1 */ + {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 36, + 40, 44, 48, 52, 56, 60, 64}, 22}, + + /* Israel. */ + {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 36, 40, + 44, 48, 52, 56, 60, 64}, 21}, + + /* For 11a , TELEC */ + {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 34, 38, 42, 46}, 17}, + + /* For Global Domain. 1-11 active, 12-14 passive. //+YJ, 080626 */ + {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}, 14}, + + /* world wide 13: ch1~ch11 active, ch12~13 passive //lzm add 080826 */ + {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}, 13} }; static void rtl8180_set_channel_map(u8 channel_plan, @@ -2261,13 +2289,13 @@ static void rtl8180_set_channel_map(u8 channel_plan, { Dot11d_Init(ieee); ieee->bGlobalDomain = false; - if (ChannelPlan[channel_plan].Len != 0) { + if (channel_plan_list[channel_plan].len != 0) { /* Clear old channel map */ memset(GET_DOT11D_INFO(ieee)->channel_map, 0, sizeof(GET_DOT11D_INFO(ieee)->channel_map)); /* Set new channel map */ - for (i = 0; i < ChannelPlan[channel_plan].Len; i++) { - if (ChannelPlan[channel_plan].Channel[i] <= 14) - GET_DOT11D_INFO(ieee)->channel_map[ChannelPlan[channel_plan].Channel[i]] = 1; + for (i = 0; i < channel_plan_list[channel_plan].len; i++) { + if (channel_plan_list[channel_plan].channel[i] <= 14) + GET_DOT11D_INFO(ieee)->channel_map[channel_plan_list[channel_plan].channel[i]] = 1; } } break; @@ -2300,15 +2328,15 @@ static void rtl8180_set_channel_map(u8 channel_plan, void GPIOChangeRFWorkItemCallBack(struct work_struct *work); /* YJ,add,080828 */ -static void rtl8180_statistics_init(struct Stats *pstats) +static void rtl8180_statistics_init(struct stats *pstats) { - memset(pstats, 0, sizeof(struct Stats)); + memset(pstats, 0, sizeof(struct stats)); } -static void rtl8180_link_detect_init(plink_detect_t plink_detect) +static void rtl8180_link_detect_init(struct link_detect_t *plink_detect) { - memset(plink_detect, 0, sizeof(link_detect_t)); - plink_detect->SlotNum = DEFAULT_SLOT_NUM; + memset(plink_detect, 0, sizeof(struct link_detect_t)); + plink_detect->slot_num = DEFAULT_SLOT_NUM; } /* YJ,add,080828,end */ @@ -2360,7 +2388,7 @@ static short rtl8180_init(struct net_device *dev) eeprom_93cx6_read(&eeprom, EEPROM_COUNTRY_CODE>>1, &eeprom_val); priv->channel_plan = eeprom_val & 0xFF; if (priv->channel_plan > COUNTRY_CODE_GLOBAL_DOMAIN) { - printk("rtl8180_init:Error channel plan! Set to default.\n"); + netdev_err(dev, "rtl8180_init: Invalid channel plan! Set to default.\n"); priv->channel_plan = 0; } @@ -2385,7 +2413,8 @@ static short rtl8180_init(struct net_device *dev) rtl8180_link_detect_init(&priv->link_detect); priv->ack_tx_to_ieee = 0; - priv->ieee80211->current_network.beacon_interval = DEFAULT_BEACONINTERVAL; + priv->ieee80211->current_network.beacon_interval = + DEFAULT_BEACONINTERVAL; priv->ieee80211->iw_mode = IW_MODE_INFRA; priv->ieee80211->softmac_features = IEEE_SOFTMAC_SCAN | IEEE_SOFTMAC_ASSOCIATE | IEEE_SOFTMAC_PROBERQ | @@ -2431,7 +2460,8 @@ static short rtl8180_init(struct net_device *dev) priv->AdRxSsBeforeSwitched = 0; init_timer(&priv->SwAntennaDiversityTimer); priv->SwAntennaDiversityTimer.data = (unsigned long)dev; - priv->SwAntennaDiversityTimer.function = (void *)SwAntennaDiversityTimerCallback; + priv->SwAntennaDiversityTimer.function = + (void *)SwAntennaDiversityTimerCallback; priv->bDigMechanism = true; priv->InitialGain = 6; priv->bXtalCalibration = false; @@ -2440,7 +2470,8 @@ static short rtl8180_init(struct net_device *dev) priv->bTxPowerTrack = false; priv->ThermalMeter = 0; priv->FalseAlarmRegValue = 0; - priv->RegDigOfdmFaUpTh = 0xc; /* Upper threshold of OFDM false alarm, which is used in DIG. */ + priv->RegDigOfdmFaUpTh = 0xc; /* Upper threshold of OFDM false alarm, + which is used in DIG. */ priv->DIG_NumberFallbackVote = 0; priv->DIG_NumberUpgradeVote = 0; priv->LastSignalStrengthInPercent = 0; @@ -2585,7 +2616,8 @@ static short rtl8180_init(struct net_device *dev) priv->bSwAntennaDiverity = priv->EEPROMSwAntennaDiversity; else /* 1:disable antenna diversity, 2: enable antenna diversity. */ - priv->bSwAntennaDiverity = priv->RegSwAntennaDiversityMechanism == 2; + priv->bSwAntennaDiverity = + priv->RegSwAntennaDiversityMechanism == 2; if (priv->RegDefaultAntenna == 0) /* 0: default from EEPROM. */ @@ -2669,7 +2701,8 @@ static short rtl8180_init(struct net_device *dev) TX_BEACON_RING_ADDR)) return -ENOMEM; - if (request_irq(dev->irq, rtl8180_interrupt, IRQF_SHARED, dev->name, dev)) { + if (request_irq(dev->irq, rtl8180_interrupt, + IRQF_SHARED, dev->name, dev)) { DMESGE("Error allocating IRQ %d", dev->irq); return -1; } else { @@ -2768,16 +2801,19 @@ static void rtl8185_write_phy(struct net_device *dev, u8 adr, u32 data) phyw = ((data<<8) | adr); - /* Note that, we must write 0xff7c after 0x7d-0x7f to write BB register. */ + /* Note: we must write 0xff7c after 0x7d-0x7f to write BB register. */ write_nic_byte(dev, 0x7f, ((phyw & 0xff000000) >> 24)); write_nic_byte(dev, 0x7e, ((phyw & 0x00ff0000) >> 16)); write_nic_byte(dev, 0x7d, ((phyw & 0x0000ff00) >> 8)); write_nic_byte(dev, 0x7c, ((phyw & 0x000000ff))); - /* this is ok to fail when we write AGC table. check for AGC table might be - * done by masking with 0x7f instead of 0xff + /* this is ok to fail when we write AGC table. check for AGC table + * might be done by masking with 0x7f instead of 0xff */ - /* if (phyr != (data&0xff)) DMESGW("Phy write timeout %x %x %x", phyr, data, adr); */ + /* + if (phyr != (data&0xff)) + DMESGW("Phy write timeout %x %x %x", phyr, data, adr); + */ } inline void write_phy_ofdm(struct net_device *dev, u8 adr, u32 data) @@ -2812,9 +2848,9 @@ void rtl8180_start_tx_beacon(struct net_device *dev) word = read_nic_word(dev, BintrItv); word &= ~BintrItv_BintrItv; word |= 1000; /* priv->ieee80211->current_network.beacon_interval * - ((priv->txbeaconcount > 1)?(priv->txbeaconcount-1):1); - // FIXME: check if correct ^^ worked with 0x3e8; - */ + * ((priv->txbeaconcount > 1)?(priv->txbeaconcount-1):1); + * FIXME: check if correct ^^ worked with 0x3e8; + */ write_nic_word(dev, BintrItv, word); rtl8180_set_mode(dev, EPROM_CMD_NORMAL); @@ -2846,25 +2882,26 @@ static bool MgntActSet_802_11_PowerSaveMode(struct r8180_priv *priv, static void LeisurePSEnter(struct r8180_priv *priv) { - if (priv->bLeisurePs) { + if (priv->bLeisurePs) if (priv->ieee80211->ps == IEEE80211_PS_DISABLED) /* IEEE80211_PS_ENABLE */ - MgntActSet_802_11_PowerSaveMode(priv, IEEE80211_PS_MBCAST|IEEE80211_PS_UNICAST); - } + MgntActSet_802_11_PowerSaveMode(priv, + IEEE80211_PS_MBCAST | IEEE80211_PS_UNICAST); } static void LeisurePSLeave(struct r8180_priv *priv) { - if (priv->bLeisurePs) { + if (priv->bLeisurePs) if (priv->ieee80211->ps != IEEE80211_PS_DISABLED) - MgntActSet_802_11_PowerSaveMode(priv, IEEE80211_PS_DISABLED); - } + MgntActSet_802_11_PowerSaveMode( + priv, IEEE80211_PS_DISABLED); } void rtl8180_hw_wakeup_wq(struct work_struct *work) { struct delayed_work *dwork = to_delayed_work(work); - struct ieee80211_device *ieee = container_of(dwork, struct ieee80211_device, hw_wakeup_wq); + struct ieee80211_device *ieee = container_of( + dwork, struct ieee80211_device, hw_wakeup_wq); struct net_device *dev = ieee->dev; rtl8180_hw_wakeup(dev); @@ -2873,7 +2910,8 @@ void rtl8180_hw_wakeup_wq(struct work_struct *work) void rtl8180_hw_sleep_wq(struct work_struct *work) { struct delayed_work *dwork = to_delayed_work(work); - struct ieee80211_device *ieee = container_of(dwork, struct ieee80211_device, hw_sleep_wq); + struct ieee80211_device *ieee = container_of( + dwork, struct ieee80211_device, hw_sleep_wq); struct net_device *dev = ieee->dev; rtl8180_hw_sleep_down(dev); @@ -2890,23 +2928,30 @@ static void MgntLinkKeepAlive(struct r8180_priv *priv) */ if ((priv->keepAliveLevel == 2) || - (priv->link_detect.LastNumTxUnicast == priv->NumTxUnicast && - priv->link_detect.LastNumRxUnicast == priv->ieee80211->NumRxUnicast) + (priv->link_detect.last_num_tx_unicast == + priv->NumTxUnicast && + priv->link_detect.last_num_rx_unicast == + priv->ieee80211->NumRxUnicast) ) { - priv->link_detect.IdleCount++; + priv->link_detect.idle_count++; /* - * Send a Keep-Alive packet packet to AP if we had been idle for a while. + * Send a Keep-Alive packet packet to AP if we had + * been idle for a while. */ - if (priv->link_detect.IdleCount >= ((KEEP_ALIVE_INTERVAL / CHECK_FOR_HANG_PERIOD)-1)) { - priv->link_detect.IdleCount = 0; - ieee80211_sta_ps_send_null_frame(priv->ieee80211, false); + if (priv->link_detect.idle_count >= + KEEP_ALIVE_INTERVAL / + CHECK_FOR_HANG_PERIOD - 1) { + priv->link_detect.idle_count = 0; + ieee80211_sta_ps_send_null_frame( + priv->ieee80211, false); } } else { - priv->link_detect.IdleCount = 0; + priv->link_detect.idle_count = 0; } - priv->link_detect.LastNumTxUnicast = priv->NumTxUnicast; - priv->link_detect.LastNumRxUnicast = priv->ieee80211->NumRxUnicast; + priv->link_detect.last_num_tx_unicast = priv->NumTxUnicast; + priv->link_detect.last_num_rx_unicast = + priv->ieee80211->NumRxUnicast; } } @@ -2926,15 +2971,22 @@ void rtl8180_watch_dog(struct net_device *dev) IPSEnter(dev); } /* YJ,add,080828,for link state check */ - if ((priv->ieee80211->state == IEEE80211_LINKED) && (priv->ieee80211->iw_mode == IW_MODE_INFRA)) { - SlotIndex = (priv->link_detect.SlotIndex++) % priv->link_detect.SlotNum; - priv->link_detect.RxFrameNum[SlotIndex] = priv->ieee80211->NumRxDataInPeriod + priv->ieee80211->NumRxBcnInPeriod; - for (i = 0; i < priv->link_detect.SlotNum; i++) - TotalRxNum += priv->link_detect.RxFrameNum[i]; + if ((priv->ieee80211->state == IEEE80211_LINKED) && + (priv->ieee80211->iw_mode == IW_MODE_INFRA)) { + SlotIndex = (priv->link_detect.slot_index++) % + priv->link_detect.slot_num; + + priv->link_detect.rx_frame_num[SlotIndex] = + priv->ieee80211->NumRxDataInPeriod + + priv->ieee80211->NumRxBcnInPeriod; + + for (i = 0; i < priv->link_detect.slot_num; i++) + TotalRxNum += priv->link_detect.rx_frame_num[i]; if (TotalRxNum == 0) { priv->ieee80211->state = IEEE80211_ASSOCIATING; - queue_work(priv->ieee80211->wq, &priv->ieee80211->associate_procedure_wq); + queue_work(priv->ieee80211->wq, + &priv->ieee80211->associate_procedure_wq); } } @@ -2945,13 +2997,15 @@ void rtl8180_watch_dog(struct net_device *dev) LeisurePSLeave(priv); if (priv->ieee80211->state == IEEE80211_LINKED) { - priv->link_detect.NumRxOkInPeriod = priv->ieee80211->NumRxDataInPeriod; - if (priv->link_detect.NumRxOkInPeriod > 666 || - priv->link_detect.NumTxOkInPeriod > 666) { + priv->link_detect.num_rx_ok_in_period = + priv->ieee80211->NumRxDataInPeriod; + if (priv->link_detect.num_rx_ok_in_period > 666 || + priv->link_detect.num_tx_ok_in_period > 666) { bBusyTraffic = true; } - if (((priv->link_detect.NumRxOkInPeriod + priv->link_detect.NumTxOkInPeriod) > 8) - || (priv->link_detect.NumRxOkInPeriod > 2)) { + if ((priv->link_detect.num_rx_ok_in_period + + priv->link_detect.num_tx_ok_in_period > 8) + || (priv->link_detect.num_rx_ok_in_period > 2)) { bEnterPS = false; } else bEnterPS = true; @@ -2962,9 +3016,9 @@ void rtl8180_watch_dog(struct net_device *dev) LeisurePSLeave(priv); } else LeisurePSLeave(priv); - priv->link_detect.bBusyTraffic = bBusyTraffic; - priv->link_detect.NumRxOkInPeriod = 0; - priv->link_detect.NumTxOkInPeriod = 0; + priv->link_detect.b_busy_traffic = bBusyTraffic; + priv->link_detect.num_rx_ok_in_period = 0; + priv->link_detect.num_tx_ok_in_period = 0; priv->ieee80211->NumRxDataInPeriod = 0; priv->ieee80211->NumRxBcnInPeriod = 0; } @@ -3048,14 +3102,16 @@ int rtl8180_down(struct net_device *dev) cancel_delayed_work(&priv->ieee80211->tx_pw_wq); del_timer_sync(&priv->SwAntennaDiversityTimer); SetZebraRFPowerState8185(dev, eRfOff); - memset(&(priv->ieee80211->current_network), 0, sizeof(struct ieee80211_network)); + memset(&priv->ieee80211->current_network, + 0, sizeof(struct ieee80211_network)); priv->ieee80211->state = IEEE80211_NOLINK; return 0; } void rtl8180_restart_wq(struct work_struct *work) { - struct r8180_priv *priv = container_of(work, struct r8180_priv, reset_wq); + struct r8180_priv *priv = container_of( + work, struct r8180_priv, reset_wq); struct net_device *dev = priv->dev; down(&priv->wx_sem); @@ -3116,7 +3172,8 @@ static int r8180_set_mac_adr(struct net_device *dev, void *mac) memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN); if (priv->ieee80211->iw_mode == IW_MODE_MASTER) - memcpy(priv->ieee80211->current_network.bssid, dev->dev_addr, ETH_ALEN); + memcpy(priv->ieee80211->current_network.bssid, + dev->dev_addr, ETH_ALEN); if (priv->up) { rtl8180_down(dev); @@ -3137,7 +3194,8 @@ static int rtl8180_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) switch (cmd) { case RTL_IOCTL_WPA_SUPPLICANT: - ret = ieee80211_wpa_supplicant_ioctl(priv->ieee80211, &wrq->u.data); + ret = ieee80211_wpa_supplicant_ioctl( + priv->ieee80211, &wrq->u.data); return ret; default: return -EOPNOTSUPP; @@ -3586,7 +3644,7 @@ static irqreturn_t rtl8180_interrupt(int irq, void *netdev) } if (inta & ISR_THPDOK) { /* High priority tx ok */ - priv->link_detect.NumTxOkInPeriod++; /* YJ,add,080828 */ + priv->link_detect.num_tx_ok_in_period++; /* YJ,add,080828 */ priv->stats.txhpokint++; rtl8180_tx_isr(dev, HI_PRIORITY, 0); } @@ -3649,14 +3707,14 @@ static irqreturn_t rtl8180_interrupt(int irq, void *netdev) priv->stats.txoverflow++; if (inta & ISR_TNPDOK) { /* Normal priority tx ok */ - priv->link_detect.NumTxOkInPeriod++; /* YJ,add,080828 */ + priv->link_detect.num_tx_ok_in_period++; /* YJ,add,080828 */ priv->stats.txnpokint++; rtl8180_tx_isr(dev, NORM_PRIORITY, 0); rtl8180_try_wake_queue(dev, NORM_PRIORITY); } if (inta & ISR_TLPDOK) { /* Low priority tx ok */ - priv->link_detect.NumTxOkInPeriod++; /* YJ,add,080828 */ + priv->link_detect.num_tx_ok_in_period++; /* YJ,add,080828 */ priv->stats.txlpokint++; rtl8180_tx_isr(dev, LOW_PRIORITY, 0); rtl8180_try_wake_queue(dev, LOW_PRIORITY); @@ -3664,14 +3722,14 @@ static irqreturn_t rtl8180_interrupt(int irq, void *netdev) if (inta & ISR_TBKDOK) { /* corresponding to BK_PRIORITY */ priv->stats.txbkpokint++; - priv->link_detect.NumTxOkInPeriod++; /* YJ,add,080828 */ + priv->link_detect.num_tx_ok_in_period++; /* YJ,add,080828 */ rtl8180_tx_isr(dev, BK_PRIORITY, 0); rtl8180_try_wake_queue(dev, BE_PRIORITY); } if (inta & ISR_TBEDOK) { /* corresponding to BE_PRIORITY */ priv->stats.txbeperr++; - priv->link_detect.NumTxOkInPeriod++; /* YJ,add,080828 */ + priv->link_detect.num_tx_ok_in_period++; /* YJ,add,080828 */ rtl8180_tx_isr(dev, BE_PRIORITY, 0); rtl8180_try_wake_queue(dev, BE_PRIORITY); } @@ -3688,7 +3746,8 @@ void rtl8180_irq_rx_tasklet(struct r8180_priv *priv) void GPIOChangeRFWorkItemCallBack(struct work_struct *work) { - struct ieee80211_device *ieee = container_of(work, struct ieee80211_device, GPIOChangeRFWorkItem.work); + struct ieee80211_device *ieee = container_of( + work, struct ieee80211_device, GPIOChangeRFWorkItem.work); struct net_device *dev = ieee->dev; struct r8180_priv *priv = ieee80211_priv(dev); u8 btPSR; @@ -3698,7 +3757,8 @@ void GPIOChangeRFWorkItemCallBack(struct work_struct *work) char *argv[3]; static char *RadioPowerPath = "/etc/acpi/events/RadioPower.sh"; - static char *envp[] = {"HOME=/", "TERM=linux", "PATH=/usr/bin:/bin", NULL}; + static char *envp[] = {"HOME=/", "TERM=linux", + "PATH=/usr/bin:/bin", NULL}; static int readf_count; readf_count = (readf_count+1)%0xffff; diff --git a/drivers/staging/rtl8187se/r8180_wx.c b/drivers/staging/rtl8187se/r8180_wx.c index 9b676e027ca..b55249170f1 100644 --- a/drivers/staging/rtl8187se/r8180_wx.c +++ b/drivers/staging/rtl8187se/r8180_wx.c @@ -29,7 +29,7 @@ static u32 rtl8180_rates[] = {1000000, 2000000, 5500000, 11000000, #define RATE_COUNT ARRAY_SIZE(rtl8180_rates) -static CHANNEL_LIST DefaultChannelPlan[] = { +static struct rtl8187se_channel_list default_channel_plan[] = { {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 36, 40, 44, 48, 52, 56, 60, 64}, 19}, /* FCC */ {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 11}, /* IC */ {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 36, 40, 44, 48, 52, 56, 60, 64}, 21}, /* ETSI */ @@ -337,7 +337,7 @@ static int r8180_wx_set_scan(struct net_device *dev, struct iw_request_info *a, } else { /* prevent scan in BusyTraffic */ /* FIXME: Need to consider last scan time */ - if ((priv->link_detect.bBusyTraffic) && (true)) { + if ((priv->link_detect.b_busy_traffic) && (true)) { ret = 0; printk("Now traffic is busy, please try later!\n"); } else @@ -1030,15 +1030,15 @@ static int r8180_wx_set_channelplan(struct net_device *dev, /* unsigned long flags; */ down(&priv->wx_sem); - if (DefaultChannelPlan[*val].Len != 0) { + if (default_channel_plan[*val].len != 0) { priv->channel_plan = *val; /* Clear old channel map 8 */ for (i = 1; i <= MAX_CHANNEL_NUMBER; i++) GET_DOT11D_INFO(priv->ieee80211)->channel_map[i] = 0; /* Set new channel map */ - for (i = 1; i <= DefaultChannelPlan[*val].Len; i++) - GET_DOT11D_INFO(priv->ieee80211)->channel_map[DefaultChannelPlan[*val].Channel[i-1]] = 1; + for (i = 1; i <= default_channel_plan[*val].len; i++) + GET_DOT11D_INFO(priv->ieee80211)->channel_map[default_channel_plan[*val].channel[i-1]] = 1; } up(&priv->wx_sem); diff --git a/drivers/staging/rtl8187se/r8185b_init.c b/drivers/staging/rtl8187se/r8185b_init.c index c8b9baff1db..48eda5564ba 100644 --- a/drivers/staging/rtl8187se/r8185b_init.c +++ b/drivers/staging/rtl8187se/r8185b_init.c @@ -873,7 +873,7 @@ static u8 GetSupportedWirelessMode8185(struct net_device *dev) static void ActUpdateChannelAccessSetting(struct net_device *dev, WIRELESS_MODE WirelessMode, - PCHANNEL_ACCESS_SETTING ChnlAccessSetting) + struct chnl_access_setting *chnl_access_setting) { AC_CODING eACI; @@ -890,25 +890,25 @@ ActUpdateChannelAccessSetting(struct net_device *dev, */ /* Suggested by Jong, 2005.12.08. */ - ChnlAccessSetting->SIFS_Timer = 0x22; - ChnlAccessSetting->DIFS_Timer = 0x1C; /* 2006.06.02, by rcnjko. */ - ChnlAccessSetting->SlotTimeTimer = 9; /* 2006.06.02, by rcnjko. */ + chnl_access_setting->sifs_timer = 0x22; + chnl_access_setting->difs_timer = 0x1C; /* 2006.06.02, by rcnjko. */ + chnl_access_setting->slot_time_timer = 9; /* 2006.06.02, by rcnjko. */ /* * Suggested by wcchu, it is the default value of EIFS register, * 2005.12.08. */ - ChnlAccessSetting->EIFS_Timer = 0x5B; - ChnlAccessSetting->CWminIndex = 3; /* 2006.06.02, by rcnjko. */ - ChnlAccessSetting->CWmaxIndex = 7; /* 2006.06.02, by rcnjko. */ + chnl_access_setting->eifs_timer = 0x5B; + chnl_access_setting->cwmin_index = 3; /* 2006.06.02, by rcnjko. */ + chnl_access_setting->cwmax_index = 7; /* 2006.06.02, by rcnjko. */ - write_nic_byte(dev, SIFS, ChnlAccessSetting->SIFS_Timer); + write_nic_byte(dev, SIFS, chnl_access_setting->sifs_timer); /* * Rewrited from directly use PlatformEFIOWrite1Byte(), * by Annie, 2006-03-29. */ - write_nic_byte(dev, SLOT, ChnlAccessSetting->SlotTimeTimer); + write_nic_byte(dev, SLOT, chnl_access_setting->slot_time_timer); - write_nic_byte(dev, EIFS, ChnlAccessSetting->EIFS_Timer); + write_nic_byte(dev, EIFS, chnl_access_setting->eifs_timer); /* * <RJ_EXPR_QOS> Suggested by wcchu, it is the default value of EIFS diff --git a/drivers/staging/rtl8188eu/core/rtw_ap.c b/drivers/staging/rtl8188eu/core/rtw_ap.c index 62a61470630..0f1c1e5d25d 100644 --- a/drivers/staging/rtl8188eu/core/rtw_ap.c +++ b/drivers/staging/rtl8188eu/core/rtw_ap.c @@ -94,7 +94,7 @@ static void update_BCNTIM(struct adapter *padapter) } else { tim_ielen = 0; - /* calucate head_len */ + /* calculate head_len */ offset = _FIXED_IE_LENGTH_; offset += pnetwork_mlmeext->Ssid.SsidLength + 2; @@ -129,7 +129,7 @@ static void update_BCNTIM(struct adapter *padapter) *dst_ie++ = tim_ielen; *dst_ie++ = 0;/* DTIM count */ - *dst_ie++ = 1;/* DTIM peroid */ + *dst_ie++ = 1;/* DTIM period */ if (pstapriv->tim_bitmap&BIT(0))/* for bc/mc frames */ *dst_ie++ = BIT(0);/* bitmap ctrl */ @@ -821,7 +821,7 @@ static void start_bss_network(struct adapter *padapter, u8 *pbuf) /* update cur_wireless_mode */ update_wireless_mode(padapter); - /* udpate capability after cur_wireless_mode updated */ + /* update capability after cur_wireless_mode updated */ update_capinfo(padapter, rtw_get_capability((struct wlan_bssid_ex *)pnetwork)); /* let pnetwork_mlmeext == pnetwork_mlme. */ @@ -1415,7 +1415,7 @@ void update_beacon(struct adapter *padapter, u8 ie_id, u8 *oui, u8 tx) /* op_mode -Set to 0 (HT pure) under the followign conditions +Set to 0 (HT pure) under the following conditions - all STAs in the BSS are 20/40 MHz HT in 20/40 MHz BSS or - all STAs in the BSS are 20 MHz HT in 20 MHz BSS Set to 1 (HT non-member protection) if there may be non-HT STAs @@ -1494,7 +1494,7 @@ static int rtw_ht_operation_update(struct adapter *padapter) void associated_clients_update(struct adapter *padapter, u8 updated) { - /* update associcated stations cap. */ + /* update associated stations cap. */ if (updated) { struct list_head *phead, *plist; struct sta_info *psta = NULL; @@ -1647,7 +1647,7 @@ void bss_cap_update_on_sta_join(struct adapter *padapter, struct sta_info *psta) update_beacon(padapter, _HT_ADD_INFO_IE_, NULL, true); } - /* update associcated stations cap. */ + /* update associated stations cap. */ associated_clients_update(padapter, beacon_updated); DBG_88E("%s, updated =%d\n", __func__, beacon_updated); @@ -1711,7 +1711,7 @@ u8 bss_cap_update_on_sta_leave(struct adapter *padapter, struct sta_info *psta) update_beacon(padapter, _HT_ADD_INFO_IE_, NULL, true); } - /* update associcated stations cap. */ + /* update associated stations cap. */ DBG_88E("%s, updated =%d\n", __func__, beacon_updated); diff --git a/drivers/staging/rtl8188eu/core/rtw_br_ext.c b/drivers/staging/rtl8188eu/core/rtw_br_ext.c index 75e38d4ff4c..96c8a93ad97 100644 --- a/drivers/staging/rtl8188eu/core/rtw_br_ext.c +++ b/drivers/staging/rtl8188eu/core/rtw_br_ext.c @@ -543,10 +543,10 @@ int nat25_db_handle(struct adapter *priv, struct sk_buff *skb, int method) if (!__nat25_db_network_lookup_and_replace(priv, skb, networkAddr)) { if (*((unsigned char *)&iph->daddr + 3) == 0xff) { /* L2 is unicast but L3 is broadcast, make L2 bacome broadcast */ - DEBUG_INFO("NAT25: Set DA as boardcast\n"); + DEBUG_INFO("NAT25: Set DA as broadcast\n"); memset(skb->data, 0xff, ETH_ALEN); } else { - /* forward unknow IP packet to upper TCP/IP */ + /* forward unknown IP packet to upper TCP/IP */ DEBUG_INFO("NAT25: Replace DA with BR's MAC\n"); if ((*(u32 *)priv->br_mac) == 0 && (*(u16 *)(priv->br_mac+4)) == 0) { printk("Re-init netdev_br_init() due to br_mac == 0!\n"); @@ -932,7 +932,7 @@ int nat25_db_handle(struct adapter *priv, struct sk_buff *skb, int method) (ph->code == PADO_CODE ? "PADO" : "PADS"), skb->dev->name); } else { /* not add relay tag */ if (!priv->pppoe_connection_in_progress) { - DEBUG_ERR("Discard PPPoE packet due to no connection in progresss!\n"); + DEBUG_ERR("Discard PPPoE packet due to no connection in progress!\n"); return -1; } memcpy(skb->data, priv->pppoe_addr, ETH_ALEN); diff --git a/drivers/staging/rtl8188eu/core/rtw_debug.c b/drivers/staging/rtl8188eu/core/rtw_debug.c index 1812ba9659b..78a7adf6160 100644 --- a/drivers/staging/rtl8188eu/core/rtw_debug.c +++ b/drivers/staging/rtl8188eu/core/rtw_debug.c @@ -233,7 +233,7 @@ int proc_get_rf_info(char *page, char **start, struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; int len = 0; - len += snprintf(page + len, count - len, "cur_ch=%d, cur_bw=%d, cur_ch_offet=%d\n", + len += snprintf(page + len, count - len, "cur_ch=%d, cur_bw=%d, cur_ch_offset=%d\n", pmlmeext->cur_channel, pmlmeext->cur_bwmode, pmlmeext->cur_ch_offset); *eof = 1; return len; diff --git a/drivers/staging/rtl8188eu/core/rtw_ioctl_set.c b/drivers/staging/rtl8188eu/core/rtw_ioctl_set.c index 807b7d4beff..2a54e3369f6 100644 --- a/drivers/staging/rtl8188eu/core/rtw_ioctl_set.c +++ b/drivers/staging/rtl8188eu/core/rtw_ioctl_set.c @@ -401,7 +401,7 @@ u8 rtw_set_802_11_infrastructure_mode(struct adapter *padapter, if ((*pold_state == Ndis802_11Infrastructure) || (*pold_state == Ndis802_11IBSS)) { if (check_fwstate(pmlmepriv, _FW_LINKED) == true) - rtw_indicate_disconnect(padapter); /* will clr Linked_state; before this function, we must have chked whether issue dis-assoc_cmd or not */ + rtw_indicate_disconnect(padapter); /* will clr Linked_state; before this function, we must have checked whether issue dis-assoc_cmd or not */ } *pold_state = networktype; @@ -563,7 +563,7 @@ u8 rtw_set_802_11_add_wep(struct adapter *padapter, struct ndis_802_11_wep *wep) break; } RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, - ("rtw_set_802_11_add_wep:befor memcpy, wep->KeyLength = 0x%x wep->KeyIndex = 0x%x keyid =%x\n", + ("rtw_set_802_11_add_wep:before memcpy, wep->KeyLength = 0x%x wep->KeyIndex = 0x%x keyid =%x\n", wep->KeyLength, wep->KeyIndex, keyid)); memcpy(&(psecuritypriv->dot11DefKey[keyid].skey[0]), &(wep->KeyMaterial), wep->KeyLength); diff --git a/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c b/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c index c197b228071..4942759b19c 100644 --- a/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c +++ b/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c @@ -171,7 +171,7 @@ static struct rt_channel_plan_map RTW_ChannelPlanMap[RT_CHANNEL_DOMAIN_MAX] = { {0x03}, /* 0x41, RT_CHANNEL_DOMAIN_GLOBAL_DOAMIN_2G */ }; -static struct rt_channel_plan_map RTW_CHANNEL_PLAN_MAP_REALTEK_DEFINE = {0x03}; /* use the conbination for max channel numbers */ +static struct rt_channel_plan_map RTW_CHANNEL_PLAN_MAP_REALTEK_DEFINE = {0x03}; /* use the combination for max channel numbers */ /* * Search the @param channel_num in given @param channel_set @@ -1942,7 +1942,7 @@ void issue_p2p_GO_request(struct adapter *padapter, u8 *raddr) p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */ /* Commented by Albert 20110306 */ - /* According to the P2P Specification, the group negoitation request frame should contain 9 P2P attributes */ + /* According to the P2P Specification, the group negotiation request frame should contain 9 P2P attributes */ /* 1. P2P Capability */ /* 2. Group Owner Intent */ /* 3. Configuration Timeout */ @@ -2307,7 +2307,7 @@ static void issue_p2p_GO_response(struct adapter *padapter, u8 *raddr, u8 *frame p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */ /* Commented by Albert 20100908 */ - /* According to the P2P Specification, the group negoitation response frame should contain 9 P2P attributes */ + /* According to the P2P Specification, the group negotiation response frame should contain 9 P2P attributes */ /* 1. Status */ /* 2. P2P Capability */ /* 3. Group Owner Intent */ @@ -2609,7 +2609,7 @@ static void issue_p2p_GO_confirm(struct adapter *padapter, u8 *raddr, u8 result) p2pie[p2pielen++] = 0x09; /* WFA P2P v1.0 */ /* Commented by Albert 20110306 */ - /* According to the P2P Specification, the group negoitation request frame should contain 5 P2P attributes */ + /* According to the P2P Specification, the group negotiation request frame should contain 5 P2P attributes */ /* 1. Status */ /* 2. P2P Capability */ /* 3. Operating Channel */ @@ -4347,7 +4347,7 @@ struct xmit_frame *alloc_mgtxmitframe(struct xmit_priv *pxmitpriv) /**************************************************************************** -Following are some TX fuctions for WiFi MLME +Following are some TX functions for WiFi MLME *****************************************************************************/ @@ -5001,7 +5001,7 @@ exit: return ret; } -/* if psta == NULL, indiate we are station(client) now... */ +/* if psta == NULL, indicate we are station(client) now... */ void issue_auth(struct adapter *padapter, struct sta_info *psta, unsigned short status) { struct xmit_frame *pmgntframe; @@ -5612,7 +5612,7 @@ exit: return; } -/* when wait_ack is ture, this function shoule be called at process context */ +/* when wait_ack is true, this function should be called at process context */ static int _issue_nulldata(struct adapter *padapter, unsigned char *da, unsigned int power_mode, int wait_ack) { int ret = _FAIL; @@ -5682,7 +5682,7 @@ exit: } -/* when wait_ms > 0 , this function shoule be called at process context */ +/* when wait_ms > 0 , this function should be called at process context */ /* da == NULL for station mode */ int issue_nulldata(struct adapter *padapter, unsigned char *da, unsigned int power_mode, int try_cnt, int wait_ms) { @@ -5692,7 +5692,7 @@ int issue_nulldata(struct adapter *padapter, unsigned char *da, unsigned int pow struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); - /* da == NULL, assum it's null data for sta to ap*/ + /* da == NULL, assume it's null data for sta to ap*/ if (da == NULL) da = get_my_bssid(&(pmlmeinfo->network)); @@ -5727,7 +5727,7 @@ exit: return ret; } -/* when wait_ack is ture, this function shoule be called at process context */ +/* when wait_ack is true, this function should be called at process context */ static int _issue_qos_nulldata(struct adapter *padapter, unsigned char *da, u16 tid, int wait_ack) { int ret = _FAIL; @@ -5805,7 +5805,7 @@ exit: return ret; } -/* when wait_ms > 0 , this function shoule be called at process context */ +/* when wait_ms > 0 , this function should be called at process context */ /* da == NULL for station mode */ int issue_qos_nulldata(struct adapter *padapter, unsigned char *da, u16 tid, int try_cnt, int wait_ms) { @@ -5815,7 +5815,7 @@ int issue_qos_nulldata(struct adapter *padapter, unsigned char *da, u16 tid, int struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv); struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); - /* da == NULL, assum it's null data for sta to ap*/ + /* da == NULL, assume it's null data for sta to ap*/ if (da == NULL) da = get_my_bssid(&(pmlmeinfo->network)); @@ -6361,7 +6361,7 @@ unsigned int send_beacon(struct adapter *padapter) /**************************************************************************** -Following are some utitity fuctions for WiFi MLME +Following are some utility functions for WiFi MLME *****************************************************************************/ @@ -6474,7 +6474,7 @@ void site_survey(struct adapter *padapter) { /* 20100721:Interrupt scan operation here. */ /* For SW antenna diversity before link, it needs to switch to another antenna and scan again. */ - /* It compares the scan result and select beter one to do connection. */ + /* It compares the scan result and select better one to do connection. */ if (rtw_hal_antdiv_before_linked(padapter)) { pmlmeext->sitesurvey_res.bss_cnt = 0; pmlmeext->sitesurvey_res.channel_idx = -1; @@ -6713,7 +6713,7 @@ void start_create_ibss(struct adapter *padapter) /* update wireless mode */ update_wireless_mode(padapter); - /* udpate capability */ + /* update capability */ caps = rtw_get_capability((struct wlan_bssid_ex *)pnetwork); update_capinfo(padapter, caps); if (caps&cap_IBSS) {/* adhoc master */ @@ -6765,7 +6765,7 @@ void start_clnt_join(struct adapter *padapter) /* update wireless mode */ update_wireless_mode(padapter); - /* udpate capability */ + /* update capability */ caps = rtw_get_capability((struct wlan_bssid_ex *)pnetwork); update_capinfo(padapter, caps); if (caps&cap_ESS) { @@ -7378,7 +7378,7 @@ void mlmeext_joinbss_event_callback(struct adapter *padapter, int join_res) /* turn on dynamic functions */ Switch_DM_Func(padapter, DYNAMIC_ALL_FUNC_ENABLE, true); - /* update IOT-releated issue */ + /* update IOT-related issue */ update_IOT_info(padapter); rtw_hal_set_hwreg(padapter, HW_VAR_BASIC_RATE, cur_network->SupportedRates); @@ -7386,7 +7386,7 @@ void mlmeext_joinbss_event_callback(struct adapter *padapter, int join_res) /* BCN interval */ rtw_hal_set_hwreg(padapter, HW_VAR_BEACON_INTERVAL, (u8 *)(&pmlmeinfo->bcn_interval)); - /* udpate capability */ + /* update capability */ update_capinfo(padapter, pmlmeinfo->capability); /* WMM, Update EDCA param */ diff --git a/drivers/staging/rtl8188eu/core/rtw_mp.c b/drivers/staging/rtl8188eu/core/rtw_mp.c index 99c06c45a1c..2e02b2063c2 100644 --- a/drivers/staging/rtl8188eu/core/rtw_mp.c +++ b/drivers/staging/rtl8188eu/core/rtw_mp.c @@ -407,7 +407,7 @@ s32 mp_start_test(struct adapter *padapter) goto end_of_mp_start_test; } - /* 3 3. join psudo AdHoc */ + /* 3 3. join pseudo AdHoc */ tgt_network->join_res = 1; tgt_network->aid = 1; psta->aid = 1; @@ -443,7 +443,7 @@ void mp_stop_test(struct adapter *padapter) if (check_fwstate(pmlmepriv, WIFI_MP_STATE) == false) goto end_of_mp_stop_test; - /* 3 1. disconnect psudo AdHoc */ + /* 3 1. disconnect pseudo AdHoc */ rtw_indicate_disconnect(padapter); /* 3 2. clear psta used in mp test mode. */ diff --git a/drivers/staging/rtl8188eu/core/rtw_pwrctrl.c b/drivers/staging/rtl8188eu/core/rtw_pwrctrl.c index 491d6af2e24..f6583734aef 100644 --- a/drivers/staging/rtl8188eu/core/rtw_pwrctrl.c +++ b/drivers/staging/rtl8188eu/core/rtw_pwrctrl.c @@ -515,7 +515,7 @@ inline void rtw_set_ips_deny(struct adapter *padapter, u32 ms) /* * rtw_pwr_wakeup - Wake the NIC up from: 1)IPS. 2)USB autosuspend * @adapter: pointer to struct adapter structure -* @ips_deffer_ms: the ms wiil prevent from falling into IPS after wakeup +* @ips_deffer_ms: the ms will prevent from falling into IPS after wakeup * Return _SUCCESS or _FAIL */ diff --git a/drivers/staging/rtl8188eu/core/rtw_recv.c b/drivers/staging/rtl8188eu/core/rtw_recv.c index 0c8b338dc6d..636ec553ae8 100644 --- a/drivers/staging/rtl8188eu/core/rtw_recv.c +++ b/drivers/staging/rtl8188eu/core/rtw_recv.c @@ -1123,7 +1123,7 @@ static int validate_recv_ctrl_frame(struct adapter *padapter, if (psta->sleepq_len == 0) { pstapriv->tim_bitmap &= ~BIT(psta->aid); - /* upate BCN for TIM IE */ + /* update BCN for TIM IE */ /* update_BCNTIM(padapter); */ update_beacon(padapter, _TIM_IE_, NULL, false); } @@ -1141,7 +1141,7 @@ static int validate_recv_ctrl_frame(struct adapter *padapter, pstapriv->tim_bitmap &= ~BIT(psta->aid); - /* upate BCN for TIM IE */ + /* update BCN for TIM IE */ /* update_BCNTIM(padapter); */ update_beacon(padapter, _TIM_IE_, NULL, false); } @@ -2236,13 +2236,13 @@ void rtw_signal_stat_timer_hdl(RTW_TIMER_HDL_ARGS) } else { if (recvpriv->signal_strength_data.update_req == 0) {/* update_req is clear, means we got rx */ avg_signal_strength = recvpriv->signal_strength_data.avg_val; - /* after avg_vals are accquired, we can re-stat the signal values */ + /* after avg_vals are acquired, we can re-stat the signal values */ recvpriv->signal_strength_data.update_req = 1; } if (recvpriv->signal_qual_data.update_req == 0) {/* update_req is clear, means we got rx */ avg_signal_qual = recvpriv->signal_qual_data.avg_val; - /* after avg_vals are accquired, we can re-stat the signal values */ + /* after avg_vals are acquired, we can re-stat the signal values */ recvpriv->signal_qual_data.update_req = 1; } diff --git a/drivers/staging/rtl8188eu/core/rtw_wlan_util.c b/drivers/staging/rtl8188eu/core/rtw_wlan_util.c index f64b9795a71..3dd90599fd4 100644 --- a/drivers/staging/rtl8188eu/core/rtw_wlan_util.c +++ b/drivers/staging/rtl8188eu/core/rtw_wlan_util.c @@ -1050,7 +1050,7 @@ int rtw_check_bcn_info(struct adapter *Adapter, u8 *pframe, u32 packet_len) } if (cur_network->BcnInfo.encryp_protocol != encryp_protocol) { - DBG_88E("%s(): enctyp is not match , return FAIL\n", __func__); + DBG_88E("%s(): encryption protocol is not match , return FAIL\n", __func__); goto _mismatch; } diff --git a/drivers/staging/rtl8188eu/core/rtw_xmit.c b/drivers/staging/rtl8188eu/core/rtw_xmit.c index b0e9798da75..8d4265fb486 100644 --- a/drivers/staging/rtl8188eu/core/rtw_xmit.c +++ b/drivers/staging/rtl8188eu/core/rtw_xmit.c @@ -1950,7 +1950,7 @@ int xmitframe_enqueue_for_sleeping_sta(struct adapter *padapter, struct xmit_fra pstapriv->tim_bitmap |= BIT(0);/* */ pstapriv->sta_dz_bitmap |= BIT(0); - update_beacon(padapter, _TIM_IE_, NULL, false);/* tx bc/mc packets after upate bcn */ + update_beacon(padapter, _TIM_IE_, NULL, false);/* tx bc/mc packets after update bcn */ ret = true; } @@ -2000,7 +2000,7 @@ int xmitframe_enqueue_for_sleeping_sta(struct adapter *padapter, struct xmit_fra pstapriv->tim_bitmap |= BIT(psta->aid); if (psta->sleepq_len == 1) { - /* upate BCN for TIM IE */ + /* update BCN for TIM IE */ update_beacon(padapter, _TIM_IE_, NULL, false); } } @@ -2269,7 +2269,7 @@ void xmit_delivery_enabled_frames(struct adapter *padapter, struct sta_info *pst if ((psta->sleepq_ac_len == 0) && (!psta->has_legacy_ac) && (wmmps_ac)) { pstapriv->tim_bitmap &= ~BIT(psta->aid); - /* upate BCN for TIM IE */ + /* update BCN for TIM IE */ update_beacon(padapter, _TIM_IE_, NULL, false); } } diff --git a/drivers/staging/rtl8188eu/os_dep/os_intfs.c b/drivers/staging/rtl8188eu/os_dep/os_intfs.c index f123a930c01..b225d1c0721 100644 --- a/drivers/staging/rtl8188eu/os_dep/os_intfs.c +++ b/drivers/staging/rtl8188eu/os_dep/os_intfs.c @@ -651,7 +651,7 @@ static unsigned int rtw_classify8021d(struct sk_buff *skb) } static u16 rtw_select_queue(struct net_device *dev, struct sk_buff *skb, - void *accel_priv) + void *accel_priv, select_queue_fallback_t fallback) { struct adapter *padapter = rtw_netdev_priv(dev); struct mlme_priv *pmlmepriv = &padapter->mlmepriv; diff --git a/drivers/staging/rtl8188eu/os_dep/usb_intf.c b/drivers/staging/rtl8188eu/os_dep/usb_intf.c index 6f3a609e86e..2e49cd58321 100644 --- a/drivers/staging/rtl8188eu/os_dep/usb_intf.c +++ b/drivers/staging/rtl8188eu/os_dep/usb_intf.c @@ -56,6 +56,7 @@ static struct usb_device_id rtw_usb_id_tbl[] = { /****** 8188EUS ********/ {USB_DEVICE(0x07b8, 0x8179)}, /* Abocom - Abocom */ {USB_DEVICE(0x2001, 0x330F)}, /* DLink DWA-125 REV D1 */ + {USB_DEVICE(0x2001, 0x3310)}, /* Dlink DWA-123 REV D1 */ {} /* Terminating entry */ }; diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_pci.h b/drivers/staging/rtl8192e/rtl8192e/rtl_pci.h index 356aec43796..4b94653c50d 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_pci.h +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_pci.h @@ -28,31 +28,6 @@ #include <linux/types.h> #include <linux/pci.h> -static inline void NdisRawWritePortUlong(u32 port, u32 val) -{ - outl(val, port); -} - -static inline void NdisRawWritePortUchar(u32 port, u8 val) -{ - outb(val, port); -} - -static inline void NdisRawReadPortUchar(u32 port, u8 *pval) -{ - *pval = inb(port); -} - -static inline void NdisRawReadPortUshort(u32 port, u16 *pval) -{ - *pval = inw(port); -} - -static inline void NdisRawReadPortUlong(u32 port, u32 *pval) -{ - *pval = inl(port); -} - struct mp_adapter { u8 LinkCtrlReg; @@ -70,33 +45,6 @@ struct mp_adapter { u8 PciBridgeLinkCtrlReg; }; -struct rt_pci_capab_header { - unsigned char CapabilityID; - unsigned char Next; -}; - -#define PCI_MAX_BRIDGE_NUMBER 255 -#define PCI_MAX_DEVICES 32 -#define PCI_MAX_FUNCTION 8 - -#define PCI_CONF_ADDRESS 0x0CF8 -#define PCI_CONF_DATA 0x0CFC - -#define PCI_CLASS_BRIDGE_DEV 0x06 -#define PCI_SUBCLASS_BR_PCI_TO_PCI 0x04 - -#define U1DONTCARE 0xFF -#define U2DONTCARE 0xFFFF -#define U4DONTCARE 0xFFFFFFFF - -#define INTEL_VENDOR_ID 0x8086 -#define SIS_VENDOR_ID 0x1039 -#define ATI_VENDOR_ID 0x1002 -#define ATI_DEVICE_ID 0x7914 -#define AMD_VENDOR_ID 0x1022 - -#define PCI_CAPABILITY_ID_PCI_EXPRESS 0x10 - struct net_device; bool rtl8192_pci_findadapter(struct pci_dev *pdev, struct net_device *dev); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c b/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c index 6202358c298..498995d833e 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_wx.c @@ -609,7 +609,7 @@ static int r8192_wx_set_nick(struct net_device *dev, if (wrqu->data.length > IW_ESSID_MAX_SIZE) return -E2BIG; down(&priv->wx_sem); - 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); up(&priv->wx_sem); diff --git a/drivers/staging/rtl8821ae/base.c b/drivers/staging/rtl8821ae/base.c index da04f034e11..fce9c3fb217 100644 --- a/drivers/staging/rtl8821ae/base.c +++ b/drivers/staging/rtl8821ae/base.c @@ -39,10 +39,10 @@ #include "pci.h" /* - *NOTICE!!!: This file will be very big, we hsould - *keep it clear under follwing roles: + *NOTICE!!!: This file will be very big, we should + *keep it clear under following roles: * - *This file include follwing part, so, if you add new + *This file include following part, so, if you add new *functions into this file, please check which part it *should includes. or check if you should add new part *for this file: @@ -662,7 +662,7 @@ static void _rtl_txrate_selectmode(struct ieee80211_hw *hw, if (rtlpriv->dm.b_useramask) { tcb_desc->ratr_index = ratr_index; - /* TODO we will differentiate adhoc and station futrue */ + /* TODO we will differentiate adhoc and station future */ if (mac->opmode == NL80211_IFTYPE_STATION || mac->opmode == NL80211_IFTYPE_MESH_POINT) { tcb_desc->mac_id = 0; @@ -772,10 +772,10 @@ void rtl_get_tcb_desc(struct ieee80211_hw *hw, tcb_desc->disable_ratefallback = 1; } else { /* - *because hw will nerver use hw_rate + *because hw will never use hw_rate *when tcb_desc->use_driver_rate = false *so we never set highest N rate here, - *and N rate will all be controled by FW + *and N rate will all be controlled by FW *when tcb_desc->use_driver_rate = false */ if (sta && (sta->ht_cap.ht_supported)) { @@ -1671,7 +1671,7 @@ void rtl_recognize_peer(struct ieee80211_hw *hw, u8 *data, unsigned int len) (memcmp(mac->bssid, ap4_2, 3) == 0) || (memcmp(mac->bssid, ap4_3, 3) == 0) || vendor == PEER_RAL) { - RT_TRACE(COMP_MAC80211, DBG_LOUD, ("=>ral findn\n")); + RT_TRACE(COMP_MAC80211, DBG_LOUD, ("=>ral find\n")); vendor = PEER_RAL; } else if (memcmp(mac->bssid, ap6_1, 3) == 0 || vendor == PEER_CISCO) { diff --git a/drivers/staging/rtl8821ae/btcoexist/HalBtc8812a1Ant.c b/drivers/staging/rtl8821ae/btcoexist/HalBtc8812a1Ant.c index b30f17ae021..5a54bb10698 100644 --- a/drivers/staging/rtl8821ae/btcoexist/HalBtc8812a1Ant.c +++ b/drivers/staging/rtl8821ae/btcoexist/HalBtc8812a1Ant.c @@ -1653,7 +1653,7 @@ halbtc8812a1ant_TdmaDurationAdjustForAcl( } else { - //accquire the BT TRx retry count from BT_Info byte2 + //acquire the BT TRx retry count from BT_Info byte2 retry_count = coex_sta->bt_retry_cnt; bt_info_ext = coex_sta->bt_info_ext; BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], retry_count = %d\n", retry_count)); diff --git a/drivers/staging/rtl8821ae/btcoexist/habtc8723a1ant.c b/drivers/staging/rtl8821ae/btcoexist/habtc8723a1ant.c index e619923ef0a..8e4293a3587 100644 --- a/drivers/staging/rtl8821ae/btcoexist/habtc8723a1ant.c +++ b/drivers/staging/rtl8821ae/btcoexist/habtc8723a1ant.c @@ -629,7 +629,7 @@ halbtc8723a1ant_TdmaDurationAdjust( } else { - //accquire the BT TRx retry count from BT_Info byte2 + //acquire the BT TRx retry count from BT_Info byte2 retryCount = pCoexSta->btRetryCnt; BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE, ("[BTCoex], retryCount = %d\n", retryCount)); result = 0; diff --git a/drivers/staging/rtl8821ae/btcoexist/halbtc8192e1ant.c b/drivers/staging/rtl8821ae/btcoexist/halbtc8192e1ant.c index 973d0ea82cb..1b04530d46b 100644 --- a/drivers/staging/rtl8821ae/btcoexist/halbtc8192e1ant.c +++ b/drivers/staging/rtl8821ae/btcoexist/halbtc8192e1ant.c @@ -1721,7 +1721,7 @@ halbtc8192e1ant_TdmaDurationAdjustForAcl( } else { - //accquire the BT TRx retry count from BT_Info byte2 + //acquire the BT TRx retry count from BT_Info byte2 retryCount = pCoexSta->btRetryCnt; btInfoExt = pCoexSta->btInfoExt; BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], retryCount = %d\n", retryCount)); diff --git a/drivers/staging/rtl8821ae/btcoexist/halbtc8192e2ant.c b/drivers/staging/rtl8821ae/btcoexist/halbtc8192e2ant.c index 44ec78562e2..115908928ae 100644 --- a/drivers/staging/rtl8821ae/btcoexist/halbtc8192e2ant.c +++ b/drivers/staging/rtl8821ae/btcoexist/halbtc8192e2ant.c @@ -1803,7 +1803,7 @@ void halbtc8192e2ant_tdma_duration_adjust(struct btc_coexist *btcoexist, result = 0; wait_cnt = 0; } else { - /* accquire the BT TRx retry count from BT_Info byte2 */ + /* acquire the BT TRx retry count from BT_Info byte2 */ retry_cnt = coex_sta->bt_retry_cnt; BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, "[BTCoex], retry_cnt = %d\n", retry_cnt); diff --git a/drivers/staging/rtl8821ae/btcoexist/halbtc8723a2ant.c b/drivers/staging/rtl8821ae/btcoexist/halbtc8723a2ant.c index 180d6f12e7b..3f5c4fd2e73 100644 --- a/drivers/staging/rtl8821ae/btcoexist/halbtc8723a2ant.c +++ b/drivers/staging/rtl8821ae/btcoexist/halbtc8723a2ant.c @@ -1687,7 +1687,7 @@ halbtc8723a2ant_TdmaDurationAdjust( } else { - //accquire the BT TRx retry count from BT_Info byte2 + //acquire the BT TRx retry count from BT_Info byte2 retryCount = pCoexSta->btRetryCnt; BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], retryCount = %d\n", retryCount)); BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, ("[BTCoex], up=%d, dn=%d, m=%d, n=%d, WaitCount=%d\n", diff --git a/drivers/staging/rtl8821ae/btcoexist/halbtc8723b1ant.c b/drivers/staging/rtl8821ae/btcoexist/halbtc8723b1ant.c index 3414ba78cc4..9677943fc20 100644 --- a/drivers/staging/rtl8821ae/btcoexist/halbtc8723b1ant.c +++ b/drivers/staging/rtl8821ae/btcoexist/halbtc8723b1ant.c @@ -1950,7 +1950,7 @@ void halbtc8723b1ant_tdma_duration_adjust_for_acl(struct btc_coexist *btcoexist, result = 0; wait_count = 0; } else { - /*accquire the BT TRx retry count from BT_Info byte2 */ + /*acquire the BT TRx retry count from BT_Info byte2 */ retry_count = coex_sta->bt_retry_cnt; bt_info_ext = coex_sta->bt_info_ext; result = 0; diff --git a/drivers/staging/rtl8821ae/btcoexist/halbtc8723b2ant.c b/drivers/staging/rtl8821ae/btcoexist/halbtc8723b2ant.c index 83b1b421833..d337bd0b3c1 100644 --- a/drivers/staging/rtl8821ae/btcoexist/halbtc8723b2ant.c +++ b/drivers/staging/rtl8821ae/btcoexist/halbtc8723b2ant.c @@ -1830,7 +1830,7 @@ void halbtc8723b2ant_tdma_duration_adjust(struct btc_coexist *btcoexist, result = 0; wait_count = 0; } else { - /*accquire the BT TRx retry count from BT_Info byte2*/ + /*acquire the BT TRx retry count from BT_Info byte2*/ retryCount = coex_sta->bt_retry_cnt; BTC_PRINT(BTC_MSG_ALGORITHM, ALGO_TRACE_FW_DETAIL, "[BTCoex], retryCount = %d\n", retryCount); diff --git a/drivers/staging/rtl8821ae/core.c b/drivers/staging/rtl8821ae/core.c index 40de6089039..ff3139b6da6 100644 --- a/drivers/staging/rtl8821ae/core.c +++ b/drivers/staging/rtl8821ae/core.c @@ -373,7 +373,7 @@ static int rtl_op_config(struct ieee80211_hw *hw, u32 changed) /* sleep here is must, or we may recv the beacon and * cause mac80211 into wrong ps state, this will cause * power save nullfunc send fail, and further cause - * pkt loss, So sleep must quickly but not immediatly + * pkt loss, So sleep must quickly but not immediately * because that will cause nullfunc send by mac80211 * fail, and cause pkt loss, we have tested that 5mA * is worked very well */ @@ -1200,8 +1200,8 @@ static int rtl_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, key_type = AESCMAC_ENCRYPTION; RT_TRACE(COMP_SEC, DBG_DMESG, ("alg:CMAC\n")); RT_TRACE(COMP_SEC, DBG_DMESG, - ("HW don't support CMAC encrypiton, " - "use software CMAC encrypiton\n")); + ("HW don't support CMAC encryption, " + "use software CMAC encryption\n")); err = -EOPNOTSUPP; goto out_unlock; default: @@ -1235,8 +1235,8 @@ static int rtl_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, key_type = AESCMAC_ENCRYPTION; RT_TRACE(COMP_SEC, DBG_DMESG, ("alg:CMAC\n")); RT_TRACE(COMP_SEC, DBG_DMESG, - ("HW don't support CMAC encrypiton, " - "use software CMAC encrypiton\n")); + ("HW don't support CMAC encryption, " + "use software CMAC encryption\n")); err = -EOPNOTSUPP; goto out_unlock; default: @@ -1411,7 +1411,7 @@ static void rtl_op_rfkill_poll(struct ieee80211_hw *hw) } /* this function is called by mac80211 to flush tx buffer - * before switch channle or power save, or tx buffer packet + * before switch channel or power save, or tx buffer packet * maybe send after offchannel or rf sleep, this may cause * dis-association by AP */ #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0)) diff --git a/drivers/staging/rtl8821ae/core.h b/drivers/staging/rtl8821ae/core.h index 4b247db2861..f0c74e9239f 100644 --- a/drivers/staging/rtl8821ae/core.h +++ b/drivers/staging/rtl8821ae/core.h @@ -2,20 +2,20 @@ * * Copyright(c) 2009-2010 Realtek Corporation. * - * Tmis program is free software; you can redistribute it and/or modify it + * 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. * - * Tmis program is distributed in the hope that it will be useful, but WITHOUT + * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along with - * tmis program; if not, write to the Free Software Foundation, Inc., + * this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA * - * Tme full GNU General Public License is included in this distribution in the + * The full GNU General Public License is included in this distribution in the * file called LICENSE. * * Contact Information: diff --git a/drivers/staging/rtl8821ae/debug.c b/drivers/staging/rtl8821ae/debug.c index cb051223c68..8a6c794bda4 100644 --- a/drivers/staging/rtl8821ae/debug.c +++ b/drivers/staging/rtl8821ae/debug.c @@ -2,20 +2,20 @@ * * Copyright(c) 2009-2010 Realtek Corporation. * - * Tmis program is free software; you can redistribute it and/or modify it + * 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. * - * Tmis program is distributed in the hope that it will be useful, but WITHOUT + * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along with - * tmis program; if not, write to the Free Software Foundation, Inc., + * this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA * - * Tme full GNU General Public License is included in this distribution in the + * The full GNU General Public License is included in this distribution in the * file called LICENSE. * * Contact Information: @@ -985,4 +985,4 @@ void rtl_proc_remove_topdir(void) { if (proc_topdir) remove_proc_entry("rtlwifi", init_net.proc_net); -}
\ No newline at end of file +} diff --git a/drivers/staging/rtl8821ae/debug.h b/drivers/staging/rtl8821ae/debug.h index 5eb6251b89d..6c0a553e98b 100644 --- a/drivers/staging/rtl8821ae/debug.h +++ b/drivers/staging/rtl8821ae/debug.h @@ -2,20 +2,20 @@ * * Copyright(c) 2009-2010 Realtek Corporation. * - * Tmis program is free software; you can redistribute it and/or modify it + * 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. * - * Tmis program is distributed in the hope that it will be useful, but WITHOUT + * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along with - * tmis program; if not, write to the Free Software Foundation, Inc., + * this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA * - * Tme full GNU General Public License is included in this distribution in the + * The full GNU General Public License is included in this distribution in the * file called LICENSE. * * Contact Information: @@ -44,7 +44,7 @@ #define DBG_EMERG 0 /* - *Abnormal, rare, or unexpeted cases. + *Abnormal, rare, or unexpected cases. *For example, Packet/IO Ctl canceled, *device suprisely unremoved and so on. */ @@ -54,7 +54,7 @@ *Normal case driver developer should *open, we can see link status like *assoc/AddBA/DHCP/adapter start and - *so on basic and useful infromations. + *so on basic and useful informations. */ #define DBG_DMESG 3 diff --git a/drivers/staging/rtl8821ae/efuse.c b/drivers/staging/rtl8821ae/efuse.c index 74c19ecc95a..250aae1ce63 100644 --- a/drivers/staging/rtl8821ae/efuse.c +++ b/drivers/staging/rtl8821ae/efuse.c @@ -2,20 +2,20 @@ * * Copyright(c) 2009-2010 Realtek Corporation. * - * Tmis program is free software; you can redistribute it and/or modify it + * 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. * - * Tmis program is distributed in the hope that it will be useful, but WITHOUT + * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along with - * tmis program; if not, write to the Free Software Foundation, Inc., + * this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA * - * Tme full GNU General Public License is included in this distribution in the + * The full GNU General Public License is included in this distribution in the * file called LICENSE. * * Contact Information: @@ -149,7 +149,7 @@ u8 efuse_read_1byte(struct ieee80211_hw *hw, u16 address) return 0xFF; } -//EXPORT_SYMBOL(efuse_read_1byte); +/* EXPORT_SYMBOL(efuse_read_1byte); */ void efuse_write_1byte(struct ieee80211_hw *hw, u16 address, u8 value) { @@ -517,7 +517,7 @@ void rtl_efuse_shadow_map_update(struct ieee80211_hw *hw) rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE]); } -//EXPORT_SYMBOL(rtl_efuse_shadow_map_update); +/* EXPORT_SYMBOL(rtl_efuse_shadow_map_update); */ void efuse_force_write_vendor_Id(struct ieee80211_hw *hw) { @@ -628,7 +628,7 @@ int efuse_one_byte_read(struct ieee80211_hw *hw, u16 addr, u8 *data) } return bresult; } -//EXPORT_SYMBOL(efuse_one_byte_read); +/* EXPORT_SYMBOL(efuse_one_byte_read); */ static int efuse_one_byte_write(struct ieee80211_hw *hw, u16 addr, u8 data) { @@ -1120,16 +1120,16 @@ static void efuse_power_switch(struct ieee80211_hw *hw, u8 bwrite, u8 pwrstate) { rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_ACCESS], 0x69); - // 1.2V Power: From VDDON with Power Cut(0x0000h[15]), defualt valid + /* 1.2V Power: From VDDON with Power Cut(0x0000h[15]), default valid */ tmpV16 = rtl_read_word(rtlpriv, rtlpriv->cfg->maps[SYS_ISO_CTRL]); printk("SYS_ISO_CTRL=%04x.\n",tmpV16); if( ! (tmpV16 & PWC_EV12V ) ){ tmpV16 |= PWC_EV12V ; - //PlatformEFIOWrite2Byte(pAdapter,REG_SYS_ISO_CTRL,tmpV16); + /* PlatformEFIOWrite2Byte(pAdapter,REG_SYS_ISO_CTRL,tmpV16); */ } - // Reset: 0x0000h[28], default valid + /* Reset: 0x0000h[28], default valid */ tmpV16 = rtl_read_word(rtlpriv, rtlpriv->cfg->maps[SYS_FUNC_EN]); printk("SYS_FUNC_EN=%04x.\n",tmpV16); if( !(tmpV16 & FEN_ELDR) ){ @@ -1137,7 +1137,7 @@ static void efuse_power_switch(struct ieee80211_hw *hw, u8 bwrite, u8 pwrstate) rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[SYS_FUNC_EN], tmpV16); } - // Clock: Gated(0x0008h[5]) 8M(0x0008h[1]) clock from ANA, default valid + /* Clock: Gated(0x0008h[5]) 8M(0x0008h[1]) clock from ANA, default valid */ tmpV16 = rtl_read_word(rtlpriv, rtlpriv->cfg->maps[SYS_CLK] ); printk("SYS_CLK=%04x.\n",tmpV16); if( (!(tmpV16 & LOADER_CLK_EN) ) ||(!(tmpV16 & ANA8M) ) ) @@ -1148,7 +1148,7 @@ static void efuse_power_switch(struct ieee80211_hw *hw, u8 bwrite, u8 pwrstate) if(bwrite == true) { - // Enable LDO 2.5V before read/write action + /* Enable LDO 2.5V before read/write action */ tempval = rtl_read_word(rtlpriv, rtlpriv->cfg->maps[EFUSE_TEST] + 3); printk("EFUSE_TEST=%04x.\n",tmpV16); tempval &= ~(BIT(3) | BIT(4) |BIT(5) | BIT(6)); @@ -1161,7 +1161,7 @@ static void efuse_power_switch(struct ieee80211_hw *hw, u8 bwrite, u8 pwrstate) { rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_ACCESS], 0x00); if(bwrite == true){ - // Disable LDO 2.5V after read/write action + /* Disable LDO 2.5V after read/write action */ tempval = rtl_read_word(rtlpriv, rtlpriv->cfg->maps[EFUSE_TEST] + 3); rtl_write_byte(rtlpriv, rtlpriv->cfg->maps[EFUSE_TEST] + 3, (tempval & 0x7F)); } diff --git a/drivers/staging/rtl8821ae/pci.c b/drivers/staging/rtl8821ae/pci.c index 618a3cb4a0c..a562aa60d59 100644 --- a/drivers/staging/rtl8821ae/pci.c +++ b/drivers/staging/rtl8821ae/pci.c @@ -583,7 +583,7 @@ static void _rtl_pci_tx_chk_waitq(struct ieee80211_hw *hw) (rtlpriv->buddy_priv && rtlpriv->buddy_priv->easy_concurrent_ctl.bswitch_in_process))) return; - /* we juse use em for BE/BK/VI/VO */ + /* we just use em for BE/BK/VI/VO */ for (tid = 7; tid >= 0; tid--) { u8 hw_queue = ac_to_hwq[rtl_tid_to_ac(hw, tid)]; struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[hw_queue]; @@ -672,7 +672,7 @@ static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio) } /* for sw LPS, just after NULL skb send out, we can - * sure AP kown we are sleeped, our we should not let + * sure AP known we are slept, our we should not let * rf to sleep*/ fc = rtl_get_fc(skb); if (ieee80211_is_nullfunc(fc)) { @@ -772,7 +772,7 @@ static int _rtl_pci_init_one_rxdesc(struct ieee80211_hw *hw, return 1; } -/* inorder to receive 8K AMSDU we have set skb to +/* In order to receive 8K AMSDU we have set skb to * 9100bytes in init rx ring, but if this packet is * not a AMSDU, this so big packet will be sent to * TCP/IP directly, this cause big packet ping fail @@ -783,7 +783,7 @@ static int _rtl_pci_init_one_rxdesc(struct ieee80211_hw *hw, /* but some platform will fail when alloc skb sometimes. * in this condition, we will send the old skb to * mac80211 directly, this will not cause any other - * issues, but only be losted by TCP/IP */ + * issues, but only be lost by TCP/IP */ static void _rtl_pci_rx_to_mac80211(struct ieee80211_hw *hw, struct sk_buff *skb, struct ieee80211_rx_status rx_status) { @@ -1029,7 +1029,7 @@ static irqreturn_t _rtl_pci_interrupt(int irq, void *dev_id) rtlpriv->cfg->ops->interrupt_recognized(hw, &inta, &intb); - /*Shared IRQ or HW disappared */ + /*Shared IRQ or HW disappeared */ if (!inta || inta == 0xffff) goto done; /*<1> beacon related */ @@ -1936,7 +1936,7 @@ void rtl_pci_stop(struct ieee80211_hw *hw) u8 RFInProgressTimeOut = 0; /* - *should before disable interrrupt&adapter + *should before disable interrupt&adapter *and will do it immediately. */ set_hal_stop(rtlhal); @@ -2293,7 +2293,7 @@ int __devinit rtl_pci_probe(struct pci_dev *pdev, /* *init dbgp flags before all *other functions, because we will - *use it in other funtions like + *use it in other functions like *RT_TRACE/RT_PRINT/RTL_PRINT_DATA *you can not use these macro *before this @@ -2428,13 +2428,13 @@ fail1: return -ENODEV; } -//EXPORT_SYMBOL(rtl_pci_probe); +/* EXPORT_SYMBOL(rtl_pci_probe); */ struct ieee80211_hw *rtl_pci_get_hw_pointer(void) { return hw_export; } -//EXPORT_SYMBOL(rtl_pci_get_hw_pointer); +/* EXPORT_SYMBOL(rtl_pci_get_hw_pointer); */ void rtl_pci_disconnect(struct pci_dev *pdev) { @@ -2491,7 +2491,7 @@ void rtl_pci_disconnect(struct pci_dev *pdev) ieee80211_free_hw(hw); } -//EXPORT_SYMBOL(rtl_pci_disconnect); +/* EXPORT_SYMBOL(rtl_pci_disconnect); */ /*************************************** kernel pci power state define: @@ -2519,7 +2519,7 @@ int rtl_pci_suspend(struct device *dev) return 0; } -//EXPORT_SYMBOL(rtl_pci_suspend); +/* EXPORT_SYMBOL(rtl_pci_suspend); */ int rtl_pci_resume(struct device *dev) { @@ -2532,7 +2532,7 @@ int rtl_pci_resume(struct device *dev) return 0; } -//EXPORT_SYMBOL(rtl_pci_resume); +/* EXPORT_SYMBOL(rtl_pci_resume); */ struct rtl_intf_ops rtl_pci_ops = { .read_efuse_byte = read_efuse_byte, diff --git a/drivers/staging/rtl8821ae/pci.h b/drivers/staging/rtl8821ae/pci.h index 9f206550a65..06eaa521e0e 100644 --- a/drivers/staging/rtl8821ae/pci.h +++ b/drivers/staging/rtl8821ae/pci.h @@ -148,11 +148,11 @@ struct rtl_pci_capabilities_header { * RX wifi info == RX descriptor in old flow */ struct rtl_tx_buffer_desc { #if (RTL8192EE_SEG_NUM == 2) - u32 dword[2*(DMA_IS_64BIT + 1)*8]; //seg = 8 + u32 dword[2*(DMA_IS_64BIT + 1)*8]; /* seg = 8 */ #elif (RTL8192EE_SEG_NUM == 1) - u32 dword[2*(DMA_IS_64BIT + 1)*4]; //seg = 4 + u32 dword[2*(DMA_IS_64BIT + 1)*4]; /* seg = 4 */ #elif (RTL8192EE_SEG_NUM == 0) - u32 dword[2*(DMA_IS_64BIT + 1)*2]; //seg = 2 + u32 dword[2*(DMA_IS_64BIT + 1)*2]; /* seg = 2 */ #endif } __packed; @@ -187,7 +187,7 @@ struct rtl8192_tx_ring { }; struct rtl8192_rx_ring { - struct rtl_rx_desc *desc;/*for old trx flow, not uesd in new trx*/ + struct rtl_rx_desc *desc;/*for old trx flow, not used in new trx*/ /*dma matches either 'desc' or 'buffer_desc'*/ dma_addr_t dma; unsigned int idx; diff --git a/drivers/staging/rtl8821ae/ps.c b/drivers/staging/rtl8821ae/ps.c index f12ffa83c58..7876442417f 100644 --- a/drivers/staging/rtl8821ae/ps.c +++ b/drivers/staging/rtl8821ae/ps.c @@ -257,7 +257,7 @@ void rtl_ips_nic_off_wq_callback(void *data) *Do not enter IPS in the following conditions: *(1) RF is already OFF or Sleep *(2) b_swrf_processing (indicates the IPS is still under going) - *(3) Connectted (only disconnected can trigger IPS) + *(3) Connected (only disconnected can trigger IPS) *(4) IBSS (send Beacon) *(5) AP mode (send Beacon) *(6) monitor mode (rcv packet) diff --git a/drivers/staging/rtl8821ae/regd.c b/drivers/staging/rtl8821ae/regd.c index d89f15cb808..0a4b3984b7e 100644 --- a/drivers/staging/rtl8821ae/regd.c +++ b/drivers/staging/rtl8821ae/regd.c @@ -243,7 +243,7 @@ static void _rtl_reg_apply_active_scan_flags(struct wiphy *wiphy, } /* - *If a country IE has been recieved check its rule for this + *If a country IE has been received check its rule for this *channel first before enabling active scan. The passive scan *would have been enforced by the initial processing of our *custom regulatory domain. @@ -455,7 +455,7 @@ int rtl_regd_init(struct ieee80211_hw *hw, if (rtlpriv->regd.country_code >= COUNTRY_CODE_MAX) { RT_TRACE(COMP_REGD, DBG_DMESG, - (KERN_DEBUG "rtl: EEPROM indicates invalid contry code" + (KERN_DEBUG "rtl: EEPROM indicates invalid country code" "world wide 13 should be used\n")); rtlpriv->regd.country_code = COUNTRY_CODE_WORLD_WIDE_13; diff --git a/drivers/staging/rtl8821ae/rtl8821ae/dm.c b/drivers/staging/rtl8821ae/rtl8821ae/dm.c index 8634206b892..e0efcd281df 100644 --- a/drivers/staging/rtl8821ae/rtl8821ae/dm.c +++ b/drivers/staging/rtl8821ae/rtl8821ae/dm.c @@ -731,7 +731,7 @@ void rtl8821ae_dm_find_minimum_rssi(struct ieee80211_hw *hw) rtl_dm_dig->min_undecorated_pwdb_for_dm = rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb; RT_TRACE(COMP_BB_POWERSAVING, DBG_LOUD, - ("AP Ext Port or disconnet PWDB = 0x%x \n", + ("AP Ext Port or disconnect PWDB = 0x%x \n", rtl_dm_dig->min_undecorated_pwdb_for_dm)); } RT_TRACE(COMP_DIG, DBG_LOUD, ("MinUndecoratedPWDBForDM =%d\n", @@ -925,7 +925,7 @@ static void rtl8821ae_dm_dig(struct ieee80211_hw *hw) if (rtlpriv->falsealm_cnt.cnt_all > 10000) { RT_TRACE(COMP_DIG, DBG_LOUD, - ("rtl8821ae_dm_dig(): Abnornally false alarm case. \n")); + ("rtl8821ae_dm_dig(): Abnormally false alarm case. \n")); if (dm_digtable.large_fa_hit != 3) dm_digtable.large_fa_hit++; @@ -1087,7 +1087,7 @@ static void rtl8821ae_dm_false_alarm_counter_statistics(struct ieee80211_hw *hw) else falsealm_cnt->cnt_all = falsealm_cnt->cnt_ofdm_fail; - /*reset OFDM FA coutner*/ + /*reset OFDM FA counter*/ rtl_set_bbreg(hw, ODM_REG_OFDM_FA_RST_11AC, BIT(17), 1); rtl_set_bbreg(hw, ODM_REG_OFDM_FA_RST_11AC, BIT(17), 0); /* reset CCK FA counter*/ @@ -1316,7 +1316,7 @@ u8 rtl8812ae_hw_rate_to_mrate( /*----------------------------------------------------------------------------- * Function: odm_TxPwrTrackSetPwr88E() * - * Overview: 88E change all channel tx power accordign to flag. + * Overview: 88E change all channel tx power according to flag. * OFDM & CCK are all different. * * Input: NONE @@ -1537,7 +1537,7 @@ void rtl8812ae_dm_txpwr_track_set_pwr(struct ieee80211_hw *hw, rtldm->modify_txagc_flag_path_b = false; RT_TRACE(COMP_POWER_TRACKING, DBG_LOUD, - ("******Path_B pDM_Odm->Modify_TxAGC_Flag = FALSE \n")); + ("******Path_B dm_Odm->Modify_TxAGC_Flag = FALSE \n")); } } } @@ -1654,7 +1654,7 @@ void rtl8812ae_dm_txpower_tracking_callback_thermalmeter if (delta > 0 && rtldm->txpower_track_control) { - /*"delta" here is used to record the absolute value of differrence.*/ + /*"delta" here is used to record the absolute value of difference.*/ delta = thermal_value > rtlefuse->eeprom_thermalmeter ? \ (thermal_value - rtlefuse->eeprom_thermalmeter) : \ (rtlefuse->eeprom_thermalmeter - thermal_value); @@ -1976,7 +1976,7 @@ void rtl8821ae_phy_lccalibrate( /*----------------------------------------------------------------------------- * Function: odm_TxPwrTrackSetPwr88E() * - * Overview: 88E change all channel tx power accordign to flag. + * Overview: 88E change all channel tx power according to flag. * OFDM & CCK are all different. * * Input: NONE @@ -2159,7 +2159,7 @@ void rtl8821ae_dm_txpower_tracking_callback_thermalmeter u8 *delta_swing_table_idx_tup_b; u8 *delta_swing_table_idx_tdown_b; - /*2. Initilization ( 7 steps in total )*/ + /*2. Initialization ( 7 steps in total )*/ rtl8821ae_get_delta_swing_table(hw, (u8**)&delta_swing_table_idx_tup_a, (u8**)&delta_swing_table_idx_tdown_a, (u8**)&delta_swing_table_idx_tup_b, @@ -2244,7 +2244,7 @@ void rtl8821ae_dm_txpower_tracking_callback_thermalmeter if (delta > 0 && rtldm->txpower_track_control) { - /*"delta" here is used to record the absolute value of differrence.*/ + /*"delta" here is used to record the absolute value of difference.*/ delta = thermal_value > rtlefuse->eeprom_thermalmeter ? \ (thermal_value - rtlefuse->eeprom_thermalmeter) : \ (rtlefuse->eeprom_thermalmeter - thermal_value); @@ -2613,11 +2613,11 @@ static void rtl8821ae_dm_check_edca_turbo(struct ieee80211_hw *hw) RT_TRACE(COMP_TURBO, DBG_LOUD, ("rtl8821ae_dm_check_edca_turbo=====>")); RT_TRACE(COMP_TURBO, DBG_LOUD, - ("Orginial BE PARAM: 0x%x\n", + ("Original BE PARAM: 0x%x\n", rtl_read_dword(rtlpriv, DM_REG_EDCA_BE_11N))); /*=============================== - list paramter for different platform + list parameter for different platform ===============================*/ b_last_is_cur_rdl_state = rtlpriv->dm.bis_cur_rdlstate; pb_is_cur_rdl_state = &( rtlpriv->dm.bis_cur_rdlstate); @@ -2963,7 +2963,7 @@ void rtl8821ae_dm_dynamic_atc_switch(struct ieee80211_hw *hw) "Crystal cap = 0x%x, Crystal cap offset = %d\n", rtldm->crystal_cap, adjust_xtal)); - /*3.Adjudt Crystal Cap.*/ + /*3.Adjust Crystal Cap.*/ if (adjust_xtal != 0){ rtldm->is_freeze = 0; rtldm->crystal_cap += adjust_xtal; diff --git a/drivers/staging/rtl8821ae/rtl8821ae/fw.c b/drivers/staging/rtl8821ae/rtl8821ae/fw.c index 4083cab926a..46eb4125d18 100644 --- a/drivers/staging/rtl8821ae/rtl8821ae/fw.c +++ b/drivers/staging/rtl8821ae/rtl8821ae/fw.c @@ -164,7 +164,7 @@ static int _rtl8821ae_fw_free_to_go(struct ieee80211_hw *hw) if (counter >= FW_8821AE_POLLING_TIMEOUT_COUNT) { RT_TRACE(COMP_ERR, DBG_LOUD, - ("chksum report faill ! REG_MCUFWDL:0x%08x .\n", + ("chksum report fail ! REG_MCUFWDL:0x%08x .\n", value32)); goto exit; } @@ -368,7 +368,7 @@ static void _rtl8821ae_fill_h2c_command(struct ieee80211_hw *hw, wait_h2c_limmit--; if (wait_h2c_limmit == 0) { RT_TRACE(COMP_CMD, DBG_LOUD, - ("Wating too long for FW read " + ("Waiting too long for FW read " "clear HMEBox(%d)!\n", boxnum)); break; } @@ -378,7 +378,7 @@ static void _rtl8821ae_fill_h2c_command(struct ieee80211_hw *hw, isfw_read = _rtl8821ae_check_fw_read_last_h2c(hw, boxnum); u1b_tmp = rtl_read_byte(rtlpriv, 0x130); RT_TRACE(COMP_CMD, DBG_LOUD, - ("Wating for FW read clear HMEBox(%d)!!! " + ("Waiting for FW read clear HMEBox(%d)!!! " "0x130 = %2x\n", boxnum, u1b_tmp)); } } @@ -1179,7 +1179,7 @@ void rtl8821ae_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished) ("Set RSVD page location to Fw FAIL!!!!!!.\n")); } -/*Shoud check FW support p2p or not.*/ +/*Should check FW support p2p or not.*/ void rtl8821ae_set_p2p_ctw_period_cmd(struct ieee80211_hw *hw, u8 ctwindow) { u8 u1_ctwindow_period[1] ={ ctwindow}; diff --git a/drivers/staging/rtl8821ae/rtl8821ae/hal_bt_coexist.h b/drivers/staging/rtl8821ae/rtl8821ae/hal_bt_coexist.h index 799cc6f95cc..b365f82f481 100644 --- a/drivers/staging/rtl8821ae/rtl8821ae/hal_bt_coexist.h +++ b/drivers/staging/rtl8821ae/rtl8821ae/hal_bt_coexist.h @@ -142,7 +142,7 @@ void rtl8821ae_dm_bt_hw_coex_all_off(struct ieee80211_hw *hw); long rtl8821ae_dm_bt_get_rx_ss(struct ieee80211_hw *hw); void rtl8821ae_dm_bt_balance(struct ieee80211_hw *hw, bool b_balance_on, u8 ms0, u8 ms1); -void rtl8821ae_dm_bt_agc_table(struct ieee80211_hw *hw, u8 tyep); +void rtl8821ae_dm_bt_agc_table(struct ieee80211_hw *hw, u8 type); void rtl8821ae_dm_bt_bb_back_off_level(struct ieee80211_hw *hw, u8 type); u8 rtl8821ae_dm_bt_check_coex_rssi_state(struct ieee80211_hw *hw, u8 level_num, u8 rssi_thresh, u8 rssi_thresh1); diff --git a/drivers/staging/rtl8821ae/rtl8821ae/hal_btc.c b/drivers/staging/rtl8821ae/rtl8821ae/hal_btc.c index 79386ee142f..6898868ce6e 100644 --- a/drivers/staging/rtl8821ae/rtl8821ae/hal_btc.c +++ b/drivers/staging/rtl8821ae/rtl8821ae/hal_btc.c @@ -157,7 +157,7 @@ bool rtl8821ae_dm_bt_is_same_coexist_state(struct ieee80211_hw *hw) &&(rtlpcipriv->btcoexist.previous_state_h == rtlpcipriv->btcoexist.current_state_h)) { RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, - ("[DM][BT], Coexist state do not chang!!\n")); + ("[DM][BT], Coexist state do not change!!\n")); return true; } else { RT_TRACE(COMP_BT_COEXIST, DBG_DMESG, @@ -902,7 +902,7 @@ void rtl8821ae_dm_bt_set_bt_dm(struct ieee80211_hw *hw, struct btdm_8821ae *p_bt /* * Note: - * We should add delay for making sure sw DacSwing can be set sucessfully. + * We should add delay for making sure sw DacSwing can be set successfully. * because of that rtl8821ae_dm_bt_set_fw_2_ant_hid() and rtl8821ae_dm_bt_set_fw_tdma_ctrl() * will overwrite the reg 0x880. */ diff --git a/drivers/staging/rtl8821ae/rtl8821ae/hw.c b/drivers/staging/rtl8821ae/rtl8821ae/hw.c index d3e9b93400b..1b8583b689d 100644 --- a/drivers/staging/rtl8821ae/rtl8821ae/hw.c +++ b/drivers/staging/rtl8821ae/rtl8821ae/hw.c @@ -1017,7 +1017,7 @@ static void _rtl8821ae_hw_configure(struct ieee80211_hw *hw) /* ARFB table 12 for 11ac 24G 1SS */ rtl_write_dword(rtlpriv, REG_ARFR3, 0x00000015); rtl_write_dword(rtlpriv, REG_ARFR3 + 4, 0xffcff000); - /* 0x420[7] = 0 , enable retry AMPDU in new AMPD not singal MPDU. */ + /* 0x420[7] = 0 , enable retry AMPDU in new AMPD not signal MPDU. */ rtl_write_word(rtlpriv, REG_FWHW_TXQ_CTRL, 0x1F00); rtl_write_byte(rtlpriv, REG_AMPDU_MAX_TIME, 0x70); @@ -1407,7 +1407,7 @@ int rtl8821ae_hw_init(struct ieee80211_hw *hw) rtl8821ae_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 + * is wrong, RX RCR_ACRC32 will cause TP unstable & 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); @@ -1563,7 +1563,7 @@ static enum version_8821ae _rtl8821ae_read_chip_version(struct ieee80211_hw *hw) break; default: RT_TRACE(COMP_INIT, DBG_LOUD, - ("Chip Version ID: Unknow (0x%X).\n", version)); + ("Chip Version ID: Unknown (0x%X).\n", version)); break; } @@ -2372,7 +2372,7 @@ static void _rtl8812ae_read_adapter_info(struct ieee80211_hw *hw, bool b_pseudo_ if (rtlefuse->eeprom_channelplan == 0xff) rtlefuse->eeprom_channelplan = 0x7F; - /* set channel paln to world wide 13 */ + /* set channel plan to world wide 13 */ //rtlefuse->channel_plan = (u8) rtlefuse->eeprom_channelplan; /*parse xtal*/ @@ -2535,7 +2535,7 @@ static void _rtl8821ae_read_adapter_info(struct ieee80211_hw *hw, bool b_pseudo_ if (rtlefuse->eeprom_channelplan == 0xff) rtlefuse->eeprom_channelplan = 0x7F; - /* set channel paln to world wide 13 */ + /* set channel plan to world wide 13 */ //rtlefuse->channel_plan = (u8) rtlefuse->eeprom_channelplan; /*parse xtal*/ diff --git a/drivers/staging/rtl8821ae/rtl8821ae/phy.c b/drivers/staging/rtl8821ae/rtl8821ae/phy.c index d02fca38a2b..c66129087a6 100644 --- a/drivers/staging/rtl8821ae/rtl8821ae/phy.c +++ b/drivers/staging/rtl8821ae/rtl8821ae/phy.c @@ -86,7 +86,7 @@ void rtl8812ae_fixspur( /* 0x8AC[11:10] = 2'b10*/ - /* <20120914, Kordan> A workarould to resolve + /* <20120914, Kordan> A workaround to resolve 2480Mhz spur by setting ADC clock as 160M. (Asked by Binson)*/ if (band_width == HT_CHANNEL_WIDTH_20 && (channel == 13 || channel == 14)) { @@ -107,7 +107,7 @@ void rtl8812ae_fixspur( } else if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) { - /* <20120914, Kordan> A workarould to resolve + /* <20120914, Kordan> A workaround to resolve 2480Mhz spur by setting ADC clock as 160M. (Asked by Binson)*/ if (band_width == HT_CHANNEL_WIDTH_20 && (channel == 13 || channel == 14)) diff --git a/drivers/staging/rtl8821ae/rtl8821ae/phy.h b/drivers/staging/rtl8821ae/rtl8821ae/phy.h index a932d8c9d45..a80bf739940 100644 --- a/drivers/staging/rtl8821ae/rtl8821ae/phy.h +++ b/drivers/staging/rtl8821ae/rtl8821ae/phy.h @@ -30,7 +30,7 @@ #ifndef __RTL8821AE_PHY_H__ #define __RTL8821AE_PHY_H__ -/*It must always set to 4, otherwise read efuse table secquence will be wrong.*/ +/*It must always set to 4, otherwise read efuse table sequence will be wrong.*/ #define MAX_TX_COUNT 4 #define TX_1S 0 #define TX_2S 1 diff --git a/drivers/staging/rtl8821ae/rtl8821ae/pwrseq.h b/drivers/staging/rtl8821ae/rtl8821ae/pwrseq.h index 8b39c042fa9..480a6bb6d76 100644 --- a/drivers/staging/rtl8821ae/rtl8821ae/pwrseq.h +++ b/drivers/staging/rtl8821ae/rtl8821ae/pwrseq.h @@ -81,7 +81,7 @@ {0x0047, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0},/* 0x47[7:0] = 00 gpio mode */ \ {0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0},/* suspend option all off */ \ {0x0014, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0x80, BIT7},/*0x14[7] = 1 turn on ZCD */ \ - {0x0015, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0x01, BIT0},/* 0x15[0] =1 trun on ZCD */ \ + {0x0015, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0x01, BIT0},/* 0x15[0] =1 turn on ZCD */ \ {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0x10, BIT4},/*0x23[4] = 1 hpon LDO sleep mode */ \ {0x0008, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0x02, 0},/*0x8[1] = 0 ANA clk =500k */ \ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT3, BIT3}, /*0x04[11] = 2b'11 enable WL suspend for PCIe*/ @@ -91,7 +91,7 @@ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT3, 0}, /*0x04[11] = 2b'01enable WL suspend*/ \ {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0x10, 0},/*0x23[4] = 0 hpon LDO sleep mode leave */ \ - {0x0015, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0x01, 0},/* 0x15[0] =0 trun off ZCD */ \ + {0x0015, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0x01, 0},/* 0x15[0] =0 turn off ZCD */ \ {0x0014, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0x80, 0},/*0x14[7] = 0 turn off ZCD */ \ {0x0046, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0x00},/* gpio0~7 input mode */ \ {0x0043, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0x00},/* gpio11 input mode, gpio10~8 input mode */ @@ -110,7 +110,7 @@ {0x0046, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0xff},/* gpio0~7 output mode */ \ {0x0047, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0},/* 0x47[7:0] = 00 gpio mode */ \ {0x0014, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0x80, BIT7},/*0x14[7] = 1 turn on ZCD */ \ - {0x0015, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0x01, BIT0},/* 0x15[0] =1 trun on ZCD */ \ + {0x0015, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0x01, BIT0},/* 0x15[0] =1 turn on ZCD */ \ {0x0012, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0x01, 0},/*0x12[0] = 0 force PFM mode */ \ {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0x10, BIT4},/*0x23[4] = 1 hpon LDO sleep mode */ \ {0x0008, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0x02, 0},/*0x8[1] = 0 ANA clk =500k */ \ @@ -124,7 +124,7 @@ /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, // comments here*/ \ {0x0012, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, BIT0, BIT0},/*0x12[0] = 1 force PWM mode */ \ {0x0014, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0x80, 0},/*0x14[7] = 0 turn off ZCD */ \ - {0x0015, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0x01, 0},/* 0x15[0] =0 trun off ZCD */ \ + {0x0015, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0x01, 0},/* 0x15[0] =0 turn off ZCD */ \ {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0x10, 0},/*0x23[4] = 0 hpon LDO leave sleep mode */ \ {0x0046, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0x00},/* gpio0~7 input mode */ \ {0x0043, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,PWR_BASEADDR_MAC,PWR_CMD_WRITE, 0xFF, 0x00},/* gpio11 input mode, gpio10~8 input mode */ \ @@ -204,7 +204,7 @@ extern struct wlan_pwr_cfg rtl8812_leave_lps_flow[RTL8812_TRANS_LPS_TO_ACT_STEP 4: LPS--Low Power State 5: SUS--Suspend - The transision from different states are defined below + The transition from different states are defined below TRANS_CARDEMU_TO_ACT TRANS_ACT_TO_CARDEMU TRANS_CARDEMU_TO_SUS diff --git a/drivers/staging/rtl8821ae/rtl8821ae/pwrseqcmd.c b/drivers/staging/rtl8821ae/rtl8821ae/pwrseqcmd.c index 710bc015251..ff188718777 100644 --- a/drivers/staging/rtl8821ae/rtl8821ae/pwrseqcmd.c +++ b/drivers/staging/rtl8821ae/rtl8821ae/pwrseqcmd.c @@ -82,7 +82,7 @@ bool rtl_hal_pwrseqcmdparsing (struct rtl_priv* rtlpriv, u8 cut_version, value = value | (GET_PWR_CFG_VALUE(pwr_cfg_cmd) & GET_PWR_CFG_MASK(pwr_cfg_cmd)); - /*Write the value back to sytem register*/ + /*Write the value back to system register*/ rtl_write_byte(rtlpriv, offset, value); } break; diff --git a/drivers/staging/rtl8821ae/rtl8821ae/reg.h b/drivers/staging/rtl8821ae/rtl8821ae/reg.h index 09c5f00d260..beffb4243b1 100644 --- a/drivers/staging/rtl8821ae/rtl8821ae/reg.h +++ b/drivers/staging/rtl8821ae/rtl8821ae/reg.h @@ -596,13 +596,13 @@ #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_BCNDOK7 BIT(20) /* Beacon Queue DMA OK Interrupt 7 */ +#define IMR_BCNDOK6 BIT(19) /* Beacon Queue DMA OK Interrupt 6 */ +#define IMR_BCNDOK5 BIT(18) /* Beacon Queue DMA OK Interrupt 5 */ +#define IMR_BCNDOK4 BIT(17) /* Beacon Queue DMA OK Interrupt 4 */ +#define IMR_BCNDOK3 BIT(16) /* Beacon Queue DMA OK Interrupt 3 */ +#define IMR_BCNDOK2 BIT(15) /* Beacon Queue DMA OK Interrupt 2 */ +#define IMR_BCNDOK1 BIT(14) /* Beacon Queue DMA OK Interrupt 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 */ @@ -613,7 +613,7 @@ #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 EFUSE_OOB_PROTECT_BYTES 18 /* PG data exclude header, dummy 7 bytes from CP test and reserved 1byte.*/ #define EEPROM_DEFAULT_TSSI 0x0 @@ -1511,7 +1511,7 @@ #define ROFDM0_TXCOEFF5 0xcb4 #define ROFDM0_TXCOEFF6 0xcb8 -/*Path_A RFE cotrol */ +/*Path_A RFE control */ #define RA_RFE_CTRL_8812 0xcb8 /*Path_B RFE control*/ #define RB_RFE_CTRL_8812 0xeb8 @@ -2336,19 +2336,19 @@ #define WOL_REASON_DEAUTH BIT(3) #define WOL_REASON_FW_DISCONNECT BIT(4) -#define RA_RFE_PINMUX 0xcb0 /* Path_A RFE cotrol pinmux*/ +#define RA_RFE_PINMUX 0xcb0 /* Path_A RFE control pinmux*/ #define RB_RFE_PINMUX 0xeb0 /* Path_B RFE control pinmux*/ #define RA_RFE_INV 0xcb4 #define RB_RFE_INV 0xeb4 /* RXIQC */ -#define RA_RXIQC_AB 0xc10 /*RxIQ imblance matrix coeff. A & B*/ -#define RA_RXIQC_CD 0xc14 /*RxIQ imblance matrix coeff. C & D*/ +#define RA_RXIQC_AB 0xc10 /*RxIQ imbalance matrix coeff. A & B*/ +#define RA_RXIQC_CD 0xc14 /*RxIQ imbalance matrix coeff. C & D*/ #define RA_TXSCALE 0xc1c /* Pah_A TX scaling factor*/ #define RB_TXSCALE 0xe1c /* Path_B TX scaling factor*/ -#define RB_RXIQC_AB 0xe10 /*RxIQ imblance matrix coeff. A & B*/ -#define RB_RXIQC_CD 0xe14 /*RxIQ imblance matrix coeff. C & D*/ +#define RB_RXIQC_AB 0xe10 /*RxIQ imbalance matrix coeff. A & B*/ +#define RB_RXIQC_CD 0xe14 /*RxIQ imbalance matrix coeff. C & D*/ #define RXIQC_AC 0x02ff /*bit mask for IQC matrix element A & C*/ #define RXIQC_BD 0x02ff0000 /*bit mask for IQC matrix element A & C*/ diff --git a/drivers/staging/rtl8821ae/rtl8821ae/sw.c b/drivers/staging/rtl8821ae/rtl8821ae/sw.c index 85a3474fc09..a8d17556977 100644 --- a/drivers/staging/rtl8821ae/rtl8821ae/sw.c +++ b/drivers/staging/rtl8821ae/rtl8821ae/sw.c @@ -57,9 +57,9 @@ void rtl8821ae_init_aspm_vars(struct ieee80211_hw *hw) * 0 - Disable ASPM, * 1 - Enable ASPM without Clock Req, * 2 - Enable ASPM with Clock Req, - * 3 - Alwyas Enable ASPM with Clock Req, + * 3 - Always Enable ASPM with Clock Req, * 4 - Always Enable ASPM without Clock Req. - * set defult to RTL8192CE:3 RTL8192E:2 + * set default to RTL8192CE:3 RTL8192E:2 * */ rtlpci->const_pci_aspm = 3; diff --git a/drivers/staging/rtl8821ae/rtl8821ae/trx.c b/drivers/staging/rtl8821ae/rtl8821ae/trx.c index f82ed5143b3..5f3246454e3 100644 --- a/drivers/staging/rtl8821ae/rtl8821ae/trx.c +++ b/drivers/staging/rtl8821ae/rtl8821ae/trx.c @@ -244,7 +244,7 @@ static void _rtl8821ae_query_rxphystatus(struct ieee80211_hw *hw, cck_agc_rpt = cck_buf->cck_agc_rpt; /* (1)Hardware does not provide RSSI for CCK */ - /* (2)PWDB, Average PWDB cacluated by + /* (2)PWDB, Average PWDB calculated by * hardware (for rate adaptive) */ if (ppsc->rfpwr_state == ERFON) cck_highpwr = (u8) rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, @@ -363,7 +363,7 @@ static void _rtl8821ae_query_rxphystatus(struct ieee80211_hw *hw, pstatus->rx_mimo_signalstrength[i] = (u8) rssi; } - /* (2)PWDB, Average PWDB cacluated by + /* (2)PWDB, Average PWDB calculated by * hardware (for rate adaptive) */ rx_pwr_all = ((p_drvinfo->pwdb_all >> 1) & 0x7f) - 110; @@ -603,7 +603,7 @@ bool rtl8821ae_rx_query_desc(struct ieee80211_hw *hw, /* 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 + /* So hw will not decryption robust management 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 diff --git a/drivers/staging/rtl8821ae/wifi.h b/drivers/staging/rtl8821ae/wifi.h index 3b5b2e7fc35..17a9d9f8781 100644 --- a/drivers/staging/rtl8821ae/wifi.h +++ b/drivers/staging/rtl8821ae/wifi.h @@ -76,7 +76,7 @@ #define RTL_SLOT_TIME_20 20 /*related with tcp/ip. */ -/*if_ehther.h*/ +/*if_ether.h*/ #define ETH_P_PAE 0x888E /*Port Access Entity *(IEEE 802.1X) */ #define ETH_P_IP 0x0800 /*Internet Protocol packet */ @@ -112,7 +112,7 @@ #define MAX_NUM_RATES 264 /*for 88E use*/ -/*It must always set to 4, otherwise read efuse table secquence will be wrong.*/ +/*It must always set to 4, otherwise read efuse table sequence will be wrong.*/ #define MAX_TX_COUNT 4 #define MAX_RF_PATH 4 #define MAX_CHNL_GROUP_24G 6 @@ -435,7 +435,7 @@ enum ht_channel_width { HT_CHANNEL_WIDTH_80 = 2, }; -/* Ref: 802.11i sepc D10.0 7.3.2.25.1 +/* Ref: 802.11i spec D10.0 7.3.2.25.1 Cipher Suites Encryption Algorithms */ enum rt_enc_alg { NO_ENCRYPTION = 0, @@ -499,14 +499,14 @@ enum rtl_var_map { RTL_IMR_BCNDMAINT3, /*Beacon DMA Interrupt 3 */ RTL_IMR_BCNDMAINT2, /*Beacon DMA Interrupt 2 */ RTL_IMR_BCNDMAINT1, /*Beacon DMA Interrupt 1 */ - RTL_IMR_BCNDOK8, /*Beacon Queue DMA OK Interrup 8 */ - RTL_IMR_BCNDOK7, /*Beacon Queue DMA OK Interrup 7 */ - RTL_IMR_BCNDOK6, /*Beacon Queue DMA OK Interrup 6 */ - RTL_IMR_BCNDOK5, /*Beacon Queue DMA OK Interrup 5 */ - RTL_IMR_BCNDOK4, /*Beacon Queue DMA OK Interrup 4 */ - RTL_IMR_BCNDOK3, /*Beacon Queue DMA OK Interrup 3 */ - RTL_IMR_BCNDOK2, /*Beacon Queue DMA OK Interrup 2 */ - RTL_IMR_BCNDOK1, /*Beacon Queue DMA OK Interrup 1 */ + RTL_IMR_BCNDOK8, /*Beacon Queue DMA OK Interrupt 8 */ + RTL_IMR_BCNDOK7, /*Beacon Queue DMA OK Interrupt 7 */ + RTL_IMR_BCNDOK6, /*Beacon Queue DMA OK Interrupt 6 */ + RTL_IMR_BCNDOK5, /*Beacon Queue DMA OK Interrupt 5 */ + RTL_IMR_BCNDOK4, /*Beacon Queue DMA OK Interrupt 4 */ + RTL_IMR_BCNDOK3, /*Beacon Queue DMA OK Interrupt 3 */ + RTL_IMR_BCNDOK2, /*Beacon Queue DMA OK Interrupt 2 */ + RTL_IMR_BCNDOK1, /*Beacon Queue DMA OK Interrupt 1 */ RTL_IMR_TIMEOUT2, /*Timeout interrupt 2 */ RTL_IMR_TIMEOUT1, /*Timeout interrupt 1 */ RTL_IMR_TXFOVW, /*Transmit FIFO Overflow */ @@ -515,10 +515,10 @@ enum rtl_var_map { RTL_IMR_RXFOVW, /*Receive FIFO Overflow */ RTL_IMR_RDU, /*Receive Descriptor Unavailable */ RTL_IMR_ATIMEND, /*For 92C,ATIM Window End Interrupt */ - RTL_IMR_BDOK, /*Beacon Queue DMA OK Interrup */ + RTL_IMR_BDOK, /*Beacon Queue DMA OK Interrupt */ RTL_IMR_HIGHDOK, /*High Queue DMA OK Interrupt */ RTL_IMR_COMDOK, /*Command Queue DMA OK Interrupt*/ - RTL_IMR_TBDOK, /*Transmit Beacon OK interrup */ + RTL_IMR_TBDOK, /*Transmit Beacon OK interrupt */ RTL_IMR_MGNTDOK, /*Management Queue DMA OK Interrupt */ RTL_IMR_TBDER, /*For 92C,Transmit Beacon Error Interrupt */ RTL_IMR_BKDOK, /*AC_BK DMA OK Interrupt */ @@ -1256,7 +1256,7 @@ struct rtl_security { bool use_defaultkey; /*Encryption Algorithm for Unicast Packet */ enum rt_enc_alg pairwise_enc_algorithm; - /*Encryption Algorithm for Brocast/Multicast */ + /*Encryption Algorithm for Broadcast/Multicast */ enum rt_enc_alg group_enc_algorithm; /*Cam Entry Bitmap */ u32 hwsec_cam_bitmap; @@ -1691,7 +1691,7 @@ struct rtl_stats { }; struct rt_link_detect { - /* count for raoming */ + /* count for roaming */ u32 bcn_rx_inperiod; u32 roam_times; @@ -2089,7 +2089,7 @@ struct rtl_priv { /* *hal_cfg : for diff cards - *intf_ops : for diff interrface usb/pcie + *intf_ops : for diff interface usb/pcie */ struct rtl_hal_cfg *cfg; struct rtl_intf_ops *intf_ops; @@ -2107,7 +2107,7 @@ struct rtl_priv { /*for bt coexist use*/ struct rtl_bt_coexist btcoexist; - /* seperate 92ee from other ICs, + /* separate 92ee from other ICs, * 92ee use new trx flow. */ bool use_new_trx_flow; /*This must be the last item so @@ -2385,7 +2385,7 @@ Set subfield of little-endian 4-byte value to specified value. */ #define RT_RF_PS_LEVEL_ALWAYS_ASPM BIT(6) /* no matter RFOFF or SLEEP we set PS_ASPM_LEVL*/ #define RT_PS_LEVEL_ASPM BIT(7) -/*When LPS is on, disable 2R if no packet is received or transmittd.*/ +/*When LPS is on, disable 2R if no packet is received or transmitted.*/ #define RT_RF_LPS_DISALBE_2R BIT(30) #define RT_RF_LPS_LEVEL_ASPM BIT(31) /*LPS with ASPM */ #define RT_IN_PS_LEVEL(ppsc, _ps_flg) \ diff --git a/drivers/staging/rts5208/ms.c b/drivers/staging/rts5208/ms.c index edf979f18a6..d22916a4b9d 100644 --- a/drivers/staging/rts5208/ms.c +++ b/drivers/staging/rts5208/ms.c @@ -259,7 +259,7 @@ static int ms_read_bytes(struct rtsx_chip *chip, MS_TRANSFER_END, MS_TRANSFER_END); for (i = 0; i < data_len - 1; i++) - rtsx_add_cmd(chip, READ_REG_CMD, PPBUF_BASE2 + i, 0, 0); + rtsx_add_cmd(chip, READ_REG_CMD, PPBUF_BASE2 + i, 0, 0); if (data_len % 2) rtsx_add_cmd(chip, READ_REG_CMD, PPBUF_BASE2 + data_len, 0, 0); diff --git a/drivers/staging/sb105x/Kconfig b/drivers/staging/sb105x/Kconfig deleted file mode 100644 index 245e7847a35..00000000000 --- a/drivers/staging/sb105x/Kconfig +++ /dev/null @@ -1,9 +0,0 @@ -config SB105X - tristate "SystemBase PCI Multiport UART" - select SERIAL_CORE - depends on PCI && X86 && TTY && BROKEN - help - A driver for the SystemBase Multi-2/PCI serial card - - To compile this driver a module, choose M here: the module - will be called "sb105x". diff --git a/drivers/staging/sb105x/Makefile b/drivers/staging/sb105x/Makefile deleted file mode 100644 index b1bf3779aca..00000000000 --- a/drivers/staging/sb105x/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -obj-$(CONFIG_SB105X) += sb105x.o - -sb105x-y := sb_pci_mp.o diff --git a/drivers/staging/sb105x/sb_mp_register.h b/drivers/staging/sb105x/sb_mp_register.h deleted file mode 100644 index 276c1bbcc18..00000000000 --- a/drivers/staging/sb105x/sb_mp_register.h +++ /dev/null @@ -1,295 +0,0 @@ - -/* - * SB105X_UART.h - * - * Copyright (C) 2008 systembase - * - * UART registers. - * - * This 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 UART_SB105X_H -#define UART_SB105X_H - -/* - * option register - */ - -/* Device Information Register */ -#define MP_OPTR_DIR0 0x04 /* port0 ~ port8 */ -#define MP_OPTR_DIR1 0x05 /* port8 ~ port15 */ -#define MP_OPTR_DIR2 0x06 /* port16 ~ port23 */ -#define MP_OPTR_DIR3 0x07 /* port24 ~ port31 */ - -#define DIR_UART_16C550 0 -#define DIR_UART_16C1050 1 -#define DIR_UART_16C1050A 2 - -#define DIR_CLK_1843200 0x0 /* input clock 1843200 Hz */ -#define DIR_CLK_3686400 0x1 /* input clock 3686400 Hz */ -#define DIR_CLK_7372800 0x2 /* input clock 7372800 Hz */ -#define DIR_CLK_14745600 0x3 /* input clock 14745600 Hz */ -#define DIR_CLK_29491200 0x4 /* input clock 29491200 Hz */ -#define DIR_CLK_58985400 0x5 /* input clock 58985400 Hz */ - -/* Interface Information Register */ -#define MP_OPTR_IIR0 0x08 /* port0 ~ port8 */ -#define MP_OPTR_IIR1 0x09 /* port8 ~ port15 */ -#define MP_OPTR_IIR2 0x0A /* port16 ~ port23 */ -#define MP_OPTR_IIR3 0x0B /* port24 ~ port31 */ - -#define IIR_RS232 0x00 /* RS232 type */ -#define IIR_RS422 0x10 /* RS422 type */ -#define IIR_RS485 0x20 /* RS485 type */ -#define IIR_TYPE_MASK 0x30 - -/* Interrupt Mask Register */ -#define MP_OPTR_IMR0 0x0C /* port0 ~ port8 */ -#define MP_OPTR_IMR1 0x0D /* port8 ~ port15 */ -#define MP_OPTR_IMR2 0x0E /* port16 ~ port23 */ -#define MP_OPTR_IMR3 0x0F /* port24 ~ port31 */ - -/* Interrupt Poll Register */ -#define MP_OPTR_IPR0 0x10 /* port0 ~ port8 */ -#define MP_OPTR_IPR1 0x11 /* port8 ~ port15 */ -#define MP_OPTR_IPR2 0x12 /* port16 ~ port23 */ -#define MP_OPTR_IPR3 0x13 /* port24 ~ port31 */ - -/* General Purpose Output Control Register */ -#define MP_OPTR_GPOCR 0x20 - -/* General Purpose Output Data Register */ -#define MP_OPTR_GPODR 0x21 - -/* Parallel Additional Function Register */ -#define MP_OPTR_PAFR 0x23 - -/* - * systembase 16c105x UART register - */ - -#define PAGE_0 0 -#define PAGE_1 1 -#define PAGE_2 2 -#define PAGE_3 3 -#define PAGE_4 4 - -/* - * ****************************************************************** - * * DLAB=0 =============== Page 0 Registers * - * ****************************************************************** - */ - -#define SB105X_RX 0 /* In: Receive buffer */ -#define SB105X_TX 0 /* Out: Transmit buffer */ - -#define SB105X_IER 1 /* Out: Interrupt Enable Register */ - -#define SB105X_IER_CTSI 0x80 /* CTS# Interrupt Enable (Requires EFR[4] = 1) */ -#define SB105X_IER_RTSI 0x40 /* RTS# Interrupt Enable (Requires EFR[4] = 1) */ -#define SB105X_IER_XOI 0x20 /* Xoff Interrupt Enable (Requires EFR[4] = 1) */ -#define SB105X_IER_SME 0x10 /* Sleep Mode Enable (Requires EFR[4] = 1) */ -#define SB105X_IER_MSI 0x08 /* Enable Modem status interrupt */ -#define SB105X_IER_RLSI 0x04 /* Enable receiver line status interrupt */ -#define SB105X_IER_THRI 0x02 /* Enable Transmitter holding register int. */ -#define SB105X_IER_RDI 0x01 /* Enable receiver data interrupt */ - -#define SB105X_ISR 2 /* In: Interrupt ID Register */ - -#define SB105X_ISR_NOINT 0x01 /* No interrupts pending */ -#define SB105X_ISR_RLSI 0x06 /* Receiver line status interrupt (Priority = 1)*/ -#define SB105X_ISR_RDAI 0x0c /* Receive Data Available interrupt */ -#define SB105X_ISR_CTII 0x04 /* Character Timeout Indication interrupt */ -#define SB105X_ISR_THRI 0x02 /* Transmitter holding register empty */ -#define SB105X_ISR_MSI 0x00 /* Modem status interrupt */ -#define SB105X_ISR_RXCI 0x10 /* Receive Xoff or Special Character interrupt */ -#define SB105X_ISR_RCSI 0x20 /* RTS#, CTS# status interrupt during Auto RTS/CTS flow control */ - -#define SB105X_FCR 2 /* Out: FIFO Control Register */ - -#define SB105X_FCR_FEN 0x01 /* FIFO Enable */ -#define SB105X_FCR_RXFR 0x02 /* RX FIFO Reset */ -#define SB105X_FCR_TXFR 0x04 /* TX FIFO Reset */ -#define SB105X_FCR_DMS 0x08 /* DMA Mode Select */ - -#define SB105X_FCR_RTR08 0x00 /* Receive Trigger Level set at 8 */ -#define SB105X_FCR_RTR16 0x40 /* Receive Trigger Level set at 16 */ -#define SB105X_FCR_RTR56 0x80 /* Receive Trigger Level set at 56 */ -#define SB105X_FCR_RTR60 0xc0 /* Receive Trigger Level set at 60 */ -#define SB105X_FCR_TTR08 0x00 /* Transmit Trigger Level set at 8 */ -#define SB105X_FCR_TTR16 0x10 /* Transmit Trigger Level set at 16 */ -#define SB105X_FCR_TTR32 0x20 /* Transmit Trigger Level set at 32 */ -#define SB105X_FCR_TTR56 0x30 /* Transmit Trigger Level set at 56 */ - -#define SB105X_LCR 3 /* Out: Line Control Register */ -/* - * * Note: if the word length is 5 bits (SB105X_LCR_WLEN5), then setting - * * SB105X_LCR_STOP will select 1.5 stop bits, not 2 stop bits. - */ -#define SB105X_LCR_DLAB 0x80 /* Divisor Latch Enable */ -#define SB105X_LCR_SBC 0x40 /* Break Enable*/ -#define SB105X_LCR_SPAR 0x20 /* Set Stick parity */ -#define SB105X_LCR_EPAR 0x10 /* Even parity select */ -#define SB105X_LCR_PAREN 0x08 /* Parity Enable */ -#define SB105X_LCR_STOP 0x04 /* Stop bits: 0->1 bit, 1->2 bits, 1 and SB105X_LCR_WLEN5 -> 1.5 bit */ -#define SB105X_LCR_WLEN5 0x00 /* Wordlength: 5 bits */ -#define SB105X_LCR_WLEN6 0x01 /* Wordlength: 6 bits */ -#define SB105X_LCR_WLEN7 0x02 /* Wordlength: 7 bits */ -#define SB105X_LCR_WLEN8 0x03 /* Wordlength: 8 bits */ - -#define SB105X_LCR_BF 0xBF - -#define SB105X_MCR 4 /* Out: Modem Control Register */ -#define SB105X_MCR_CPS 0x80 /* Clock Prescaler Select */ -#define SB105X_MCR_P2S 0x40 /* Page 2 Select /Xoff Re-Transmit Access Enable */ -#define SB105X_MCR_XOA 0x20 /* Xon Any Enable */ -#define SB105X_MCR_ILB 0x10 /* Internal Loopback Enable */ -#define SB105X_MCR_OUT2 0x08 /* Out2/Interrupt Output Enable*/ -#define SB105X_MCR_OUT1 0x04 /* Out1/Interrupt Output Enable */ -#define SB105X_MCR_RTS 0x02 /* RTS# Output */ -#define SB105X_MCR_DTR 0x01 /* DTR# Output */ - -#define SB105X_LSR 5 /* In: Line Status Register */ -#define SB105X_LSR_RFEI 0x80 /* Receive FIFO data error Indicator */ -#define SB105X_LSR_TEMI 0x40 /* THR and TSR Empty Indicator */ -#define SB105X_LSR_THRE 0x20 /* THR Empty Indicator */ -#define SB105X_LSR_BII 0x10 /* Break interrupt indicator */ -#define SB105X_LSR_FEI 0x08 /* Frame error indicator */ -#define SB105X_LSR_PEI 0x04 /* Parity error indicator */ -#define SB105X_LSR_OEI 0x02 /* Overrun error indicator */ -#define SB105X_LSR_RDRI 0x01 /* Receive data ready Indicator*/ - -#define SB105X_MSR 6 /* In: Modem Status Register */ -#define SB105X_MSR_DCD 0x80 /* Data Carrier Detect */ -#define SB105X_MSR_RI 0x40 /* Ring Indicator */ -#define SB105X_MSR_DSR 0x20 /* Data Set Ready */ -#define SB105X_MSR_CTS 0x10 /* Clear to Send */ -#define SB105X_MSR_DDCD 0x08 /* Delta DCD */ -#define SB105X_MSR_DRI 0x04 /* Delta ring indicator */ -#define SB105X_MSR_DDSR 0x02 /* Delta DSR */ -#define SB105X_MSR_DCTS 0x01 /* Delta CTS */ - -#define SB105XA_MDR 6 /* Out: Multi Drop mode Register */ -#define SB105XA_MDR_NPS 0x08 /* 9th Bit Polarity Select */ -#define SB105XA_MDR_AME 0x02 /* Auto Multi-drop Enable */ -#define SB105XA_MDR_MDE 0x01 /* Multi Drop Enable */ - -#define SB105X_SPR 7 /* I/O: Scratch Register */ - -/* - * DLAB=1 - */ -#define SB105X_DLL 0 /* Out: Divisor Latch Low */ -#define SB105X_DLM 1 /* Out: Divisor Latch High */ - -/* - * ****************************************************************** - * * DLAB(LCR[7]) = 0 , MCR[6] = 1 ============= Page 2 Registers * - * ****************************************************************** - */ -#define SB105X_GICR 1 /* Global Interrupt Control Register */ -#define SB105X_GICR_GIM 0x01 /* Global Interrupt Mask */ - -#define SB105X_GISR 2 /* Global Interrupt Status Register */ -#define SB105X_GISR_MGICR0 0x80 /* Mirror the content of GICR[0] */ -#define SB105X_GISR_CS3IS 0x08 /* SB105X of CS3# Interrupt Status */ -#define SB105X_GISR_CS2IS 0x04 /* SB105X of CS2# Interrupt Status */ -#define SB105X_GISR_CS1IS 0x02 /* SB105X of CS1# Interrupt Status */ -#define SB105X_GISR_CS0IS 0x01 /* SB105X of CS0# Interrupt Status */ - -#define SB105X_TFCR 5 /* Transmit FIFO Count Register */ - -#define SB105X_RFCR 6 /* Receive FIFO Count Register */ - -#define SB105X_FSR 7 /* Flow Control Status Register */ -#define SB105X_FSR_THFS 0x20 /* Transmit Hardware Flow Control Status */ -#define SB105X_FSR_TSFS 0x10 /* Transmit Software Flow Control Status */ -#define SB105X_FSR_RHFS 0x02 /* Receive Hardware Flow Control Status */ -#define SB105X_FSR_RSFS 0x01 /* Receive Software Flow Control Status */ - -/* - * ****************************************************************** - * * LCR = 0xBF, PSR[0] = 0 ============= Page 3 Registers * - * ****************************************************************** - */ - -#define SB105X_PSR 0 /* Page Select Register */ -#define SB105X_PSR_P3KEY 0xA4 /* Page 3 Select Key */ -#define SB105X_PSR_P4KEY 0xA5 /* Page 5 Select Key */ - -#define SB105X_ATR 1 /* Auto Toggle Control Register */ -#define SB105X_ATR_RPS 0x80 /* RXEN Polarity Select */ -#define SB105X_ATR_RCMS 0x40 /* RXEN Control Mode Select */ -#define SB105X_ATR_TPS 0x20 /* TXEN Polarity Select */ -#define SB105X_ATR_TCMS 0x10 /* TXEN Control Mode Select */ -#define SB105X_ATR_ATDIS 0x00 /* Auto Toggle is disabled */ -#define SB105X_ATR_ART 0x01 /* RTS#/TXEN pin operates as TXEN */ -#define SB105X_ATR_ADT 0x02 /* DTR#/TXEN pin operates as TXEN */ -#define SB105X_ATR_A80 0x03 /* only in 80 pin use */ - -#define SB105X_EFR 2 /* (Auto) Enhanced Feature Register */ -#define SB105X_EFR_ACTS 0x80 /* Auto-CTS Flow Control Enable */ -#define SB105X_EFR_ARTS 0x40 /* Auto-RTS Flow Control Enable */ -#define SB105X_EFR_SCD 0x20 /* Special Character Detect */ -#define SB105X_EFR_EFBEN 0x10 /* Enhanced Function Bits Enable */ - -#define SB105X_XON1 4 /* Xon1 Character Register */ -#define SB105X_XON2 5 /* Xon2 Character Register */ -#define SB105X_XOFF1 6 /* Xoff1 Character Register */ -#define SB105X_XOFF2 7 /* Xoff2 Character Register */ - -/* - * ****************************************************************** - * * LCR = 0xBF, PSR[0] = 1 ============ Page 4 Registers * - * ****************************************************************** - */ - -#define SB105X_AFR 1 /* Additional Feature Register */ -#define SB105X_AFR_GIPS 0x20 /* Global Interrupt Polarity Select */ -#define SB105X_AFR_GIEN 0x10 /* Global Interrupt Enable */ -#define SB105X_AFR_AFEN 0x01 /* 256-byte FIFO Enable */ - -#define SB105X_XRCR 2 /* Xoff Re-transmit Count Register */ -#define SB105X_XRCR_NRC1 0x00 /* Transmits Xoff Character whenever the number of received data is 1 during XOFF status */ -#define SB105X_XRCR_NRC4 0x01 /* Transmits Xoff Character whenever the number of received data is 4 during XOFF status */ -#define SB105X_XRCR_NRC8 0x02 /* Transmits Xoff Character whenever the number of received data is 8 during XOFF status */ -#define SB105X_XRCR_NRC16 0x03 /* Transmits Xoff Character whenever the number of received data is 16 during XOFF status */ - -#define SB105X_TTR 4 /* Transmit FIFO Trigger Level Register */ -#define SB105X_RTR 5 /* Receive FIFO Trigger Level Register */ -#define SB105X_FUR 6 /* Flow Control Upper Threshold Register */ -#define SB105X_FLR 7 /* Flow Control Lower Threshold Register */ - - -/* page 0 */ - -#define SB105X_GET_CHAR(port) inb((port)->iobase + SB105X_RX) -#define SB105X_GET_IER(port) inb((port)->iobase + SB105X_IER) -#define SB105X_GET_ISR(port) inb((port)->iobase + SB105X_ISR) -#define SB105X_GET_LCR(port) inb((port)->iobase + SB105X_LCR) -#define SB105X_GET_MCR(port) inb((port)->iobase + SB105X_MCR) -#define SB105X_GET_LSR(port) inb((port)->iobase + SB105X_LSR) -#define SB105X_GET_MSR(port) inb((port)->iobase + SB105X_MSR) -#define SB105X_GET_SPR(port) inb((port)->iobase + SB105X_SPR) - -#define SB105X_PUT_CHAR(port,v) outb((v),(port)->iobase + SB105X_TX ) -#define SB105X_PUT_IER(port,v) outb((v),(port)->iobase + SB105X_IER ) -#define SB105X_PUT_FCR(port,v) outb((v),(port)->iobase + SB105X_FCR ) -#define SB105X_PUT_LCR(port,v) outb((v),(port)->iobase + SB105X_LCR ) -#define SB105X_PUT_MCR(port,v) outb((v),(port)->iobase + SB105X_MCR ) -#define SB105X_PUT_SPR(port,v) outb((v),(port)->iobase + SB105X_SPR ) - - -/* page 1 */ -#define SB105X_GET_REG(port,reg) inb((port)->iobase + (reg)) -#define SB105X_PUT_REG(port,reg,v) outb((v),(port)->iobase + (reg)) - -/* page 2 */ - -#define SB105X_PUT_PSR(port,v) outb((v),(port)->iobase + SB105X_PSR ) - -#endif diff --git a/drivers/staging/sb105x/sb_pci_mp.c b/drivers/staging/sb105x/sb_pci_mp.c deleted file mode 100644 index c9d6ee3903a..00000000000 --- a/drivers/staging/sb105x/sb_pci_mp.c +++ /dev/null @@ -1,3189 +0,0 @@ -#include "sb_pci_mp.h" -#include <linux/module.h> -#include <linux/parport.h> - -extern struct parport *parport_pc_probe_port(unsigned long base_lo, - unsigned long base_hi, - int irq, int dma, - struct device *dev, - int irqflags); - -static struct mp_device_t mp_devs[MAX_MP_DEV]; -static int mp_nrpcibrds = sizeof(mp_pciboards)/sizeof(mppcibrd_t); -static int NR_BOARD=0; -static int NR_PORTS=0; -static struct mp_port multi_ports[MAX_MP_PORT]; -static struct irq_info irq_lists[NR_IRQS]; - -static _INLINE_ unsigned int serial_in(struct mp_port *mtpt, int offset); -static _INLINE_ void serial_out(struct mp_port *mtpt, int offset, int value); -static _INLINE_ unsigned int read_option_register(struct mp_port *mtpt, int offset); -static int sb1054_get_register(struct sb_uart_port *port, int page, int reg); -static int sb1054_set_register(struct sb_uart_port *port, int page, int reg, int value); -static void SendATCommand(struct mp_port *mtpt); -static int set_deep_fifo(struct sb_uart_port *port, int status); -static int get_deep_fifo(struct sb_uart_port *port); -static int get_device_type(int arg); -static int set_auto_rts(struct sb_uart_port *port, int status); -static void mp_stop(struct tty_struct *tty); -static void __mp_start(struct tty_struct *tty); -static void mp_start(struct tty_struct *tty); -static void mp_tasklet_action(unsigned long data); -static inline void mp_update_mctrl(struct sb_uart_port *port, unsigned int set, unsigned int clear); -static int mp_startup(struct sb_uart_state *state, int init_hw); -static void mp_shutdown(struct sb_uart_state *state); -static void mp_change_speed(struct sb_uart_state *state, struct MP_TERMIOS *old_termios); - -static inline int __mp_put_char(struct sb_uart_port *port, struct circ_buf *circ, unsigned char c); -static int mp_put_char(struct tty_struct *tty, unsigned char ch); - -static void mp_put_chars(struct tty_struct *tty); -static int mp_write(struct tty_struct *tty, const unsigned char *buf, int count); -static int mp_write_room(struct tty_struct *tty); -static int mp_chars_in_buffer(struct tty_struct *tty); -static void mp_flush_buffer(struct tty_struct *tty); -static void mp_send_xchar(struct tty_struct *tty, char ch); -static void mp_throttle(struct tty_struct *tty); -static void mp_unthrottle(struct tty_struct *tty); -static int mp_get_info(struct sb_uart_state *state, struct serial_struct *retinfo); -static int mp_set_info(struct sb_uart_state *state, struct serial_struct *newinfo); -static int mp_get_lsr_info(struct sb_uart_state *state, unsigned int *value); - -static int mp_tiocmget(struct tty_struct *tty); -static int mp_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear); -static int mp_break_ctl(struct tty_struct *tty, int break_state); -static int mp_do_autoconfig(struct sb_uart_state *state); -static int mp_wait_modem_status(struct sb_uart_state *state, unsigned long arg); -static int mp_get_count(struct sb_uart_state *state, struct serial_icounter_struct *icnt); -static int mp_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg); -static void mp_set_termios(struct tty_struct *tty, struct MP_TERMIOS *old_termios); -static void mp_close(struct tty_struct *tty, struct file *filp); -static void mp_wait_until_sent(struct tty_struct *tty, int timeout); -static void mp_hangup(struct tty_struct *tty); -static void mp_update_termios(struct sb_uart_state *state); -static int mp_block_til_ready(struct file *filp, struct sb_uart_state *state); -static struct sb_uart_state *uart_get(struct uart_driver *drv, int line); -static int mp_open(struct tty_struct *tty, struct file *filp); -static const char *mp_type(struct sb_uart_port *port); -static void mp_change_pm(struct sb_uart_state *state, int pm_state); -static inline void mp_report_port(struct uart_driver *drv, struct sb_uart_port *port); -static void mp_configure_port(struct uart_driver *drv, struct sb_uart_state *state, struct sb_uart_port *port); -static void mp_unconfigure_port(struct uart_driver *drv, struct sb_uart_state *state); -static int mp_register_driver(struct uart_driver *drv); -static void mp_unregister_driver(struct uart_driver *drv); -static int mp_add_one_port(struct uart_driver *drv, struct sb_uart_port *port); -static int mp_remove_one_port(struct uart_driver *drv, struct sb_uart_port *port); -static void autoconfig(struct mp_port *mtpt, unsigned int probeflags); -static void autoconfig_irq(struct mp_port *mtpt); -static void multi_stop_tx(struct sb_uart_port *port); -static void multi_start_tx(struct sb_uart_port *port); -static void multi_stop_rx(struct sb_uart_port *port); -static void multi_enable_ms(struct sb_uart_port *port); -static _INLINE_ void receive_chars(struct mp_port *mtpt, int *status ); -static _INLINE_ void transmit_chars(struct mp_port *mtpt); -static _INLINE_ void check_modem_status(struct mp_port *mtpt); -static inline void multi_handle_port(struct mp_port *mtpt); -static irqreturn_t multi_interrupt(int irq, void *dev_id); -static void serial_do_unlink(struct irq_info *i, struct mp_port *mtpt); -static int serial_link_irq_chain(struct mp_port *mtpt); -static void serial_unlink_irq_chain(struct mp_port *mtpt); -static void multi_timeout(unsigned long data); -static unsigned int multi_tx_empty(struct sb_uart_port *port); -static unsigned int multi_get_mctrl(struct sb_uart_port *port); -static void multi_set_mctrl(struct sb_uart_port *port, unsigned int mctrl); -static void multi_break_ctl(struct sb_uart_port *port, int break_state); -static int multi_startup(struct sb_uart_port *port); -static void multi_shutdown(struct sb_uart_port *port); -static unsigned int multi_get_divisor(struct sb_uart_port *port, unsigned int baud); -static void multi_set_termios(struct sb_uart_port *port, struct MP_TERMIOS *termios, struct MP_TERMIOS *old); -static void multi_pm(struct sb_uart_port *port, unsigned int state, unsigned int oldstate); -static void multi_release_std_resource(struct mp_port *mtpt); -static void multi_release_port(struct sb_uart_port *port); -static int multi_request_port(struct sb_uart_port *port); -static void multi_config_port(struct sb_uart_port *port, int flags); -static int multi_verify_port(struct sb_uart_port *port, struct serial_struct *ser); -static const char *multi_type(struct sb_uart_port *port); -static void __init multi_init_ports(void); -static void __init multi_register_ports(struct uart_driver *drv); -static int init_mp_dev(struct pci_dev *pcidev, mppcibrd_t brd); - -static int deep[256]; -static int deep_count; -static int fcr_arr[256]; -static int fcr_count; -static int ttr[256]; -static int ttr_count; -static int rtr[256]; -static int rtr_count; - -module_param_array(deep,int,&deep_count,0); -module_param_array(fcr_arr,int,&fcr_count,0); -module_param_array(ttr,int,&ttr_count,0); -module_param_array(rtr,int,&rtr_count,0); - -static _INLINE_ unsigned int serial_in(struct mp_port *mtpt, int offset) -{ - return inb(mtpt->port.iobase + offset); -} - -static _INLINE_ void serial_out(struct mp_port *mtpt, int offset, int value) -{ - outb(value, mtpt->port.iobase + offset); -} - -static _INLINE_ unsigned int read_option_register(struct mp_port *mtpt, int offset) -{ - return inb(mtpt->option_base_addr + offset); -} - -static int sb1053a_get_interface(struct mp_port *mtpt, int port_num) -{ - unsigned long option_base_addr = mtpt->option_base_addr; - unsigned int interface = 0; - - switch (port_num) - { - case 0: - case 1: - /* set GPO[1:0] = 00 */ - outb(0x00, option_base_addr + MP_OPTR_GPODR); - break; - case 2: - case 3: - /* set GPO[1:0] = 01 */ - outb(0x01, option_base_addr + MP_OPTR_GPODR); - break; - case 4: - case 5: - /* set GPO[1:0] = 10 */ - outb(0x02, option_base_addr + MP_OPTR_GPODR); - break; - default: - break; - } - - port_num &= 0x1; - - /* get interface */ - interface = inb(option_base_addr + MP_OPTR_IIR0 + port_num); - - /* set GPO[1:0] = 11 */ - outb(0x03, option_base_addr + MP_OPTR_GPODR); - - return (interface); -} - -static int sb1054_get_register(struct sb_uart_port *port, int page, int reg) -{ - int ret = 0; - unsigned int lcr = 0; - unsigned int mcr = 0; - unsigned int tmp = 0; - - if( page <= 0) - { - printk(" page 0 can not use this function\n"); - return -1; - } - - switch(page) - { - case 1: - lcr = SB105X_GET_LCR(port); - tmp = lcr | SB105X_LCR_DLAB; - SB105X_PUT_LCR(port, tmp); - - tmp = SB105X_GET_LCR(port); - - ret = SB105X_GET_REG(port,reg); - SB105X_PUT_LCR(port,lcr); - break; - case 2: - mcr = SB105X_GET_MCR(port); - tmp = mcr | SB105X_MCR_P2S; - SB105X_PUT_MCR(port,tmp); - - ret = SB105X_GET_REG(port,reg); - - SB105X_PUT_MCR(port,mcr); - break; - case 3: - lcr = SB105X_GET_LCR(port); - tmp = lcr | SB105X_LCR_BF; - SB105X_PUT_LCR(port,tmp); - SB105X_PUT_REG(port,SB105X_PSR,SB105X_PSR_P3KEY); - - ret = SB105X_GET_REG(port,reg); - - SB105X_PUT_LCR(port,lcr); - break; - case 4: - lcr = SB105X_GET_LCR(port); - tmp = lcr | SB105X_LCR_BF; - SB105X_PUT_LCR(port,tmp); - SB105X_PUT_REG(port,SB105X_PSR,SB105X_PSR_P4KEY); - - ret = SB105X_GET_REG(port,reg); - - SB105X_PUT_LCR(port,lcr); - break; - default: - printk(" error invalid page number \n"); - return -1; - } - - return ret; -} - -static int sb1054_set_register(struct sb_uart_port *port, int page, int reg, int value) -{ - int lcr = 0; - int mcr = 0; - int ret = 0; - - if( page <= 0) - { - printk(" page 0 can not use this function\n"); - return -1; - } - switch(page) - { - case 1: - lcr = SB105X_GET_LCR(port); - SB105X_PUT_LCR(port, lcr | SB105X_LCR_DLAB); - - SB105X_PUT_REG(port,reg,value); - - SB105X_PUT_LCR(port, lcr); - ret = 1; - break; - case 2: - mcr = SB105X_GET_MCR(port); - SB105X_PUT_MCR(port, mcr | SB105X_MCR_P2S); - - SB105X_PUT_REG(port,reg,value); - - SB105X_PUT_MCR(port, mcr); - ret = 1; - break; - case 3: - lcr = SB105X_GET_LCR(port); - SB105X_PUT_LCR(port, lcr | SB105X_LCR_BF); - SB105X_PUT_PSR(port, SB105X_PSR_P3KEY); - - SB105X_PUT_REG(port,reg,value); - - SB105X_PUT_LCR(port, lcr); - ret = 1; - break; - case 4: - lcr = SB105X_GET_LCR(port); - SB105X_PUT_LCR(port, lcr | SB105X_LCR_BF); - SB105X_PUT_PSR(port, SB105X_PSR_P4KEY); - - SB105X_PUT_REG(port,reg,value); - - SB105X_PUT_LCR(port, lcr); - ret = 1; - break; - default: - printk(" error invalid page number \n"); - return -1; - } - - return ret; -} - -static int set_multidrop_mode(struct sb_uart_port *port, unsigned int mode) -{ - int mdr = SB105XA_MDR_NPS; - - if (mode & MDMODE_ENABLE) - { - mdr |= SB105XA_MDR_MDE; - } - - if (1) //(mode & MDMODE_AUTO) - { - int efr = 0; - mdr |= SB105XA_MDR_AME; - efr = sb1054_get_register(port, PAGE_3, SB105X_EFR); - efr |= SB105X_EFR_SCD; - sb1054_set_register(port, PAGE_3, SB105X_EFR, efr); - } - - sb1054_set_register(port, PAGE_1, SB105XA_MDR, mdr); - port->mdmode &= ~0x6; - port->mdmode |= mode; - printk("[%d] multidrop init: %x\n", port->line, port->mdmode); - - return 0; -} - -static int get_multidrop_addr(struct sb_uart_port *port) -{ - return sb1054_get_register(port, PAGE_3, SB105X_XOFF2); -} - -static int set_multidrop_addr(struct sb_uart_port *port, unsigned int addr) -{ - sb1054_set_register(port, PAGE_3, SB105X_XOFF2, addr); - - return 0; -} - -static void SendATCommand(struct mp_port *mtpt) -{ - // a t cr lf - unsigned char ch[] = {0x61,0x74,0x0d,0x0a,0x0}; - unsigned char lineControl; - unsigned char i=0; - unsigned char Divisor = 0xc; - - lineControl = serial_inp(mtpt,UART_LCR); - serial_outp(mtpt,UART_LCR,(lineControl | UART_LCR_DLAB)); - serial_outp(mtpt,UART_DLL,(Divisor & 0xff)); - serial_outp(mtpt,UART_DLM,(Divisor & 0xff00)>>8); //baudrate is 4800 - - - serial_outp(mtpt,UART_LCR,lineControl); - serial_outp(mtpt,UART_LCR,0x03); // N-8-1 - serial_outp(mtpt,UART_FCR,7); - serial_outp(mtpt,UART_MCR,0x3); - while(ch[i]){ - while((serial_inp(mtpt,UART_LSR) & 0x60) !=0x60){ - ; - } - serial_outp(mtpt,0,ch[i++]); - } - - -}// end of SendATCommand() - -static int set_deep_fifo(struct sb_uart_port *port, int status) -{ - int afr_status = 0; - afr_status = sb1054_get_register(port, PAGE_4, SB105X_AFR); - - if(status == ENABLE) - { - afr_status |= SB105X_AFR_AFEN; - } - else - { - afr_status &= ~SB105X_AFR_AFEN; - } - - sb1054_set_register(port,PAGE_4,SB105X_AFR,afr_status); - sb1054_set_register(port,PAGE_4,SB105X_TTR,ttr[port->line]); - sb1054_set_register(port,PAGE_4,SB105X_RTR,rtr[port->line]); - afr_status = sb1054_get_register(port, PAGE_4, SB105X_AFR); - - return afr_status; -} - -static int get_device_type(int arg) -{ - int ret; - ret = inb(mp_devs[arg].option_reg_addr+MP_OPTR_DIR0); - ret = (ret & 0xf0) >> 4; - switch (ret) - { - case DIR_UART_16C550: - return PORT_16C55X; - case DIR_UART_16C1050: - return PORT_16C105X; - case DIR_UART_16C1050A: - /* - if (mtpt->port.line < 2) - { - return PORT_16C105XA; - } - else - { - if (mtpt->device->device_id & 0x50) - { - return PORT_16C55X; - } - else - { - return PORT_16C105X; - } - }*/ - return PORT_16C105XA; - default: - return PORT_UNKNOWN; - } - -} -static int get_deep_fifo(struct sb_uart_port *port) -{ - int afr_status = 0; - afr_status = sb1054_get_register(port, PAGE_4, SB105X_AFR); - return afr_status; -} - -static int set_auto_rts(struct sb_uart_port *port, int status) -{ - int atr_status = 0; - -#if 0 - int efr_status = 0; - - efr_status = sb1054_get_register(port, PAGE_3, SB105X_EFR); - if(status == ENABLE) - efr_status |= SB105X_EFR_ARTS; - else - efr_status &= ~SB105X_EFR_ARTS; - sb1054_set_register(port,PAGE_3,SB105X_EFR,efr_status); - efr_status = sb1054_get_register(port, PAGE_3, SB105X_EFR); -#endif - -//ATR - atr_status = sb1054_get_register(port, PAGE_3, SB105X_ATR); - switch(status) - { - case RS422PTP: - atr_status = (SB105X_ATR_TPS) | (SB105X_ATR_A80); - break; - case RS422MD: - atr_status = (SB105X_ATR_TPS) | (SB105X_ATR_TCMS) | (SB105X_ATR_A80); - break; - case RS485NE: - atr_status = (SB105X_ATR_RCMS) | (SB105X_ATR_TPS) | (SB105X_ATR_TCMS) | (SB105X_ATR_A80); - break; - case RS485ECHO: - atr_status = (SB105X_ATR_TPS) | (SB105X_ATR_TCMS) | (SB105X_ATR_A80); - break; - } - - sb1054_set_register(port,PAGE_3,SB105X_ATR,atr_status); - atr_status = sb1054_get_register(port, PAGE_3, SB105X_ATR); - - return atr_status; -} - -static void mp_stop(struct tty_struct *tty) -{ - struct sb_uart_state *state = tty->driver_data; - struct sb_uart_port *port = state->port; - unsigned long flags; - - spin_lock_irqsave(&port->lock, flags); - port->ops->stop_tx(port); - spin_unlock_irqrestore(&port->lock, flags); -} - -static void __mp_start(struct tty_struct *tty) -{ - struct sb_uart_state *state = tty->driver_data; - struct sb_uart_port *port = state->port; - - if (!uart_circ_empty(&state->info->xmit) && state->info->xmit.buf && - !tty->stopped && !tty->hw_stopped) - port->ops->start_tx(port); -} - -static void mp_start(struct tty_struct *tty) -{ - __mp_start(tty); -} - -static void mp_tasklet_action(unsigned long data) -{ - struct sb_uart_state *state = (struct sb_uart_state *)data; - struct tty_struct *tty; - - printk("tasklet is called!\n"); - tty = state->info->tty; - tty_wakeup(tty); -} - -static inline void mp_update_mctrl(struct sb_uart_port *port, unsigned int set, unsigned int clear) -{ - unsigned int old; - - old = port->mctrl; - port->mctrl = (old & ~clear) | set; - if (old != port->mctrl) - port->ops->set_mctrl(port, port->mctrl); -} - -#define uart_set_mctrl(port,set) mp_update_mctrl(port,set,0) -#define uart_clear_mctrl(port,clear) mp_update_mctrl(port,0,clear) - -static int mp_startup(struct sb_uart_state *state, int init_hw) -{ - struct sb_uart_info *info = state->info; - struct sb_uart_port *port = state->port; - unsigned long page; - int retval = 0; - - if (info->flags & UIF_INITIALIZED) - return 0; - - if (info->tty) - set_bit(TTY_IO_ERROR, &info->tty->flags); - - if (port->type == PORT_UNKNOWN) - return 0; - - if (!info->xmit.buf) { - page = get_zeroed_page(GFP_KERNEL); - if (!page) - return -ENOMEM; - - info->xmit.buf = (unsigned char *) page; - - uart_circ_clear(&info->xmit); - } - - retval = port->ops->startup(port); - if (retval == 0) { - if (init_hw) { - mp_change_speed(state, NULL); - - if (info->tty && (info->tty->termios.c_cflag & CBAUD)) - uart_set_mctrl(port, TIOCM_RTS | TIOCM_DTR); - } - - info->flags |= UIF_INITIALIZED; - - if (info->tty) - clear_bit(TTY_IO_ERROR, &info->tty->flags); - } - - if (retval && capable(CAP_SYS_ADMIN)) - retval = 0; - - return retval; -} - -static void mp_shutdown(struct sb_uart_state *state) -{ - struct sb_uart_info *info = state->info; - struct sb_uart_port *port = state->port; - - if (info->tty) - set_bit(TTY_IO_ERROR, &info->tty->flags); - - if (info->flags & UIF_INITIALIZED) { - info->flags &= ~UIF_INITIALIZED; - - if (!info->tty || (info->tty->termios.c_cflag & HUPCL)) - uart_clear_mctrl(port, TIOCM_DTR | TIOCM_RTS); - - wake_up_interruptible(&info->delta_msr_wait); - - port->ops->shutdown(port); - - synchronize_irq(port->irq); - } - tasklet_kill(&info->tlet); - - if (info->xmit.buf) { - free_page((unsigned long)info->xmit.buf); - info->xmit.buf = NULL; - } -} - -static void mp_change_speed(struct sb_uart_state *state, struct MP_TERMIOS *old_termios) -{ - struct tty_struct *tty = state->info->tty; - struct sb_uart_port *port = state->port; - - if (!tty || port->type == PORT_UNKNOWN) - return; - - if (tty->termios.c_cflag & CRTSCTS) - state->info->flags |= UIF_CTS_FLOW; - else - state->info->flags &= ~UIF_CTS_FLOW; - - if (tty->termios.c_cflag & CLOCAL) - state->info->flags &= ~UIF_CHECK_CD; - else - state->info->flags |= UIF_CHECK_CD; - - port->ops->set_termios(port, &tty->termios, old_termios); -} - -static inline int __mp_put_char(struct sb_uart_port *port, struct circ_buf *circ, unsigned char c) -{ - unsigned long flags; - int ret = 0; - - if (!circ->buf) - return 0; - - spin_lock_irqsave(&port->lock, flags); - if (uart_circ_chars_free(circ) != 0) { - circ->buf[circ->head] = c; - circ->head = (circ->head + 1) & (UART_XMIT_SIZE - 1); - ret = 1; - } - spin_unlock_irqrestore(&port->lock, flags); - return ret; -} - -static int mp_put_char(struct tty_struct *tty, unsigned char ch) -{ - struct sb_uart_state *state = tty->driver_data; - - return __mp_put_char(state->port, &state->info->xmit, ch); -} - -static void mp_put_chars(struct tty_struct *tty) -{ - mp_start(tty); -} - -static int mp_write(struct tty_struct *tty, const unsigned char *buf, int count) -{ - struct sb_uart_state *state = tty->driver_data; - struct sb_uart_port *port; - struct circ_buf *circ; - int c, ret = 0; - - if (!state || !state->info) { - return -EL3HLT; - } - - port = state->port; - circ = &state->info->xmit; - - if (!circ->buf) - return 0; - - while (1) { - c = CIRC_SPACE_TO_END(circ->head, circ->tail, UART_XMIT_SIZE); - if (count < c) - c = count; - if (c <= 0) - break; - memcpy(circ->buf + circ->head, buf, c); - - circ->head = (circ->head + c) & (UART_XMIT_SIZE - 1); - buf += c; - count -= c; - ret += c; - } - mp_start(tty); - return ret; -} - -static int mp_write_room(struct tty_struct *tty) -{ - struct sb_uart_state *state = tty->driver_data; - - return uart_circ_chars_free(&state->info->xmit); -} - -static int mp_chars_in_buffer(struct tty_struct *tty) -{ - struct sb_uart_state *state = tty->driver_data; - - return uart_circ_chars_pending(&state->info->xmit); -} - -static void mp_flush_buffer(struct tty_struct *tty) -{ - struct sb_uart_state *state = tty->driver_data; - struct sb_uart_port *port; - unsigned long flags; - - if (!state || !state->info) { - return; - } - - port = state->port; - spin_lock_irqsave(&port->lock, flags); - uart_circ_clear(&state->info->xmit); - spin_unlock_irqrestore(&port->lock, flags); - wake_up_interruptible(&tty->write_wait); - tty_wakeup(tty); -} - -static void mp_send_xchar(struct tty_struct *tty, char ch) -{ - struct sb_uart_state *state = tty->driver_data; - struct sb_uart_port *port = state->port; - unsigned long flags; - - if (port->ops->send_xchar) - port->ops->send_xchar(port, ch); - else { - port->x_char = ch; - if (ch) { - spin_lock_irqsave(&port->lock, flags); - port->ops->start_tx(port); - spin_unlock_irqrestore(&port->lock, flags); - } - } -} - -static void mp_throttle(struct tty_struct *tty) -{ - struct sb_uart_state *state = tty->driver_data; - - if (I_IXOFF(tty)) - mp_send_xchar(tty, STOP_CHAR(tty)); - - if (tty->termios.c_cflag & CRTSCTS) - uart_clear_mctrl(state->port, TIOCM_RTS); -} - -static void mp_unthrottle(struct tty_struct *tty) -{ - struct sb_uart_state *state = tty->driver_data; - struct sb_uart_port *port = state->port; - - if (I_IXOFF(tty)) { - if (port->x_char) - port->x_char = 0; - else - mp_send_xchar(tty, START_CHAR(tty)); - } - - if (tty->termios.c_cflag & CRTSCTS) - uart_set_mctrl(port, TIOCM_RTS); -} - -static int mp_get_info(struct sb_uart_state *state, struct serial_struct *retinfo) -{ - struct sb_uart_port *port = state->port; - struct serial_struct tmp; - - memset(&tmp, 0, sizeof(tmp)); - tmp.type = port->type; - tmp.line = port->line; - tmp.port = port->iobase; - if (HIGH_BITS_OFFSET) - tmp.port_high = (long) port->iobase >> HIGH_BITS_OFFSET; - tmp.irq = port->irq; - tmp.flags = port->flags; - tmp.xmit_fifo_size = port->fifosize; - tmp.baud_base = port->uartclk / 16; - tmp.close_delay = state->close_delay; - tmp.closing_wait = state->closing_wait == USF_CLOSING_WAIT_NONE ? - ASYNC_CLOSING_WAIT_NONE : - state->closing_wait; - tmp.custom_divisor = port->custom_divisor; - tmp.hub6 = port->hub6; - tmp.io_type = port->iotype; - tmp.iomem_reg_shift = port->regshift; - tmp.iomem_base = (void *)port->mapbase; - - if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) - return -EFAULT; - return 0; -} - -static int mp_set_info(struct sb_uart_state *state, struct serial_struct *newinfo) -{ - struct serial_struct new_serial; - struct sb_uart_port *port = state->port; - unsigned long new_port; - unsigned int change_irq, change_port, closing_wait; - unsigned int old_custom_divisor; - unsigned int old_flags, new_flags; - int retval = 0; - - if (copy_from_user(&new_serial, newinfo, sizeof(new_serial))) - return -EFAULT; - - new_port = new_serial.port; - if (HIGH_BITS_OFFSET) - new_port += (unsigned long) new_serial.port_high << HIGH_BITS_OFFSET; - - new_serial.irq = irq_canonicalize(new_serial.irq); - - closing_wait = new_serial.closing_wait == ASYNC_CLOSING_WAIT_NONE ? - USF_CLOSING_WAIT_NONE : new_serial.closing_wait; - MP_STATE_LOCK(state); - - change_irq = new_serial.irq != port->irq; - change_port = new_port != port->iobase || - (unsigned long)new_serial.iomem_base != port->mapbase || - new_serial.hub6 != port->hub6 || - new_serial.io_type != port->iotype || - new_serial.iomem_reg_shift != port->regshift || - new_serial.type != port->type; - old_flags = port->flags; - new_flags = new_serial.flags; - old_custom_divisor = port->custom_divisor; - - if (!capable(CAP_SYS_ADMIN)) { - retval = -EPERM; - if (change_irq || change_port || - (new_serial.baud_base != port->uartclk / 16) || - (new_serial.close_delay != state->close_delay) || - (closing_wait != state->closing_wait) || - (new_serial.xmit_fifo_size != port->fifosize) || - (((new_flags ^ old_flags) & ~UPF_USR_MASK) != 0)) - goto exit; - port->flags = ((port->flags & ~UPF_USR_MASK) | - (new_flags & UPF_USR_MASK)); - port->custom_divisor = new_serial.custom_divisor; - goto check_and_exit; - } - - if (port->ops->verify_port) - retval = port->ops->verify_port(port, &new_serial); - - if ((new_serial.irq >= NR_IRQS) || (new_serial.irq < 0) || - (new_serial.baud_base < 9600)) - retval = -EINVAL; - - if (retval) - goto exit; - - if (change_port || change_irq) { - retval = -EBUSY; - - if (uart_users(state) > 1) - goto exit; - - mp_shutdown(state); - } - - if (change_port) { - unsigned long old_iobase, old_mapbase; - unsigned int old_type, old_iotype, old_hub6, old_shift; - - old_iobase = port->iobase; - old_mapbase = port->mapbase; - old_type = port->type; - old_hub6 = port->hub6; - old_iotype = port->iotype; - old_shift = port->regshift; - - if (old_type != PORT_UNKNOWN) - port->ops->release_port(port); - - port->iobase = new_port; - port->type = new_serial.type; - port->hub6 = new_serial.hub6; - port->iotype = new_serial.io_type; - port->regshift = new_serial.iomem_reg_shift; - port->mapbase = (unsigned long)new_serial.iomem_base; - - if (port->type != PORT_UNKNOWN) { - retval = port->ops->request_port(port); - } else { - retval = 0; - } - - if (retval && old_type != PORT_UNKNOWN) { - port->iobase = old_iobase; - port->type = old_type; - port->hub6 = old_hub6; - port->iotype = old_iotype; - port->regshift = old_shift; - port->mapbase = old_mapbase; - retval = port->ops->request_port(port); - if (retval) - port->type = PORT_UNKNOWN; - - retval = -EBUSY; - } - } - - port->irq = new_serial.irq; - port->uartclk = new_serial.baud_base * 16; - port->flags = (port->flags & ~UPF_CHANGE_MASK) | - (new_flags & UPF_CHANGE_MASK); - port->custom_divisor = new_serial.custom_divisor; - state->close_delay = new_serial.close_delay; - state->closing_wait = closing_wait; - port->fifosize = new_serial.xmit_fifo_size; - if (state->info->tty) - state->info->tty->low_latency = - (port->flags & UPF_LOW_LATENCY) ? 1 : 0; - -check_and_exit: - retval = 0; - if (port->type == PORT_UNKNOWN) - goto exit; - if (state->info->flags & UIF_INITIALIZED) { - if (((old_flags ^ port->flags) & UPF_SPD_MASK) || - old_custom_divisor != port->custom_divisor) { - if (port->flags & UPF_SPD_MASK) { - printk(KERN_NOTICE - "%s sets custom speed on ttyMP%d. This " - "is deprecated.\n", current->comm, - port->line); - } - mp_change_speed(state, NULL); - } - } else - retval = mp_startup(state, 1); -exit: - MP_STATE_UNLOCK(state); - return retval; -} - - -static int mp_get_lsr_info(struct sb_uart_state *state, unsigned int *value) -{ - struct sb_uart_port *port = state->port; - unsigned int result; - - result = port->ops->tx_empty(port); - - if (port->x_char || - ((uart_circ_chars_pending(&state->info->xmit) > 0) && - !state->info->tty->stopped && !state->info->tty->hw_stopped)) - result &= ~TIOCSER_TEMT; - - return put_user(result, value); -} - -static int mp_tiocmget(struct tty_struct *tty) -{ - struct sb_uart_state *state = tty->driver_data; - struct sb_uart_port *port = state->port; - int result = -EIO; - - MP_STATE_LOCK(state); - if (!(tty->flags & (1 << TTY_IO_ERROR))) { - result = port->mctrl; - spin_lock_irq(&port->lock); - result |= port->ops->get_mctrl(port); - spin_unlock_irq(&port->lock); - } - MP_STATE_UNLOCK(state); - return result; -} - -static int mp_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear) -{ - struct sb_uart_state *state = tty->driver_data; - struct sb_uart_port *port = state->port; - int ret = -EIO; - - - MP_STATE_LOCK(state); - if (!(tty->flags & (1 << TTY_IO_ERROR))) { - mp_update_mctrl(port, set, clear); - ret = 0; - } - MP_STATE_UNLOCK(state); - - return ret; -} - -static int mp_break_ctl(struct tty_struct *tty, int break_state) -{ - struct sb_uart_state *state = tty->driver_data; - struct sb_uart_port *port = state->port; - - MP_STATE_LOCK(state); - - if (port->type != PORT_UNKNOWN) - port->ops->break_ctl(port, break_state); - - MP_STATE_UNLOCK(state); - return 0; -} - -static int mp_do_autoconfig(struct sb_uart_state *state) -{ - struct sb_uart_port *port = state->port; - int flags, ret; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - if (mutex_lock_interruptible(&state->mutex)) - return -ERESTARTSYS; - ret = -EBUSY; - if (uart_users(state) == 1) { - mp_shutdown(state); - - if (port->type != PORT_UNKNOWN) - port->ops->release_port(port); - - flags = UART_CONFIG_TYPE; - if (port->flags & UPF_AUTO_IRQ) - flags |= UART_CONFIG_IRQ; - - port->ops->config_port(port, flags); - - ret = mp_startup(state, 1); - } - MP_STATE_UNLOCK(state); - return ret; -} - -static int mp_wait_modem_status(struct sb_uart_state *state, unsigned long arg) -{ - struct sb_uart_port *port = state->port; - DECLARE_WAITQUEUE(wait, current); - struct sb_uart_icount cprev, cnow; - int ret; - - spin_lock_irq(&port->lock); - memcpy(&cprev, &port->icount, sizeof(struct sb_uart_icount)); - - port->ops->enable_ms(port); - spin_unlock_irq(&port->lock); - - add_wait_queue(&state->info->delta_msr_wait, &wait); - for (;;) { - spin_lock_irq(&port->lock); - memcpy(&cnow, &port->icount, sizeof(struct sb_uart_icount)); - spin_unlock_irq(&port->lock); - - set_current_state(TASK_INTERRUPTIBLE); - - if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || - ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || - ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || - ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) { - ret = 0; - break; - } - - schedule(); - - if (signal_pending(current)) { - ret = -ERESTARTSYS; - break; - } - - cprev = cnow; - } - - current->state = TASK_RUNNING; - remove_wait_queue(&state->info->delta_msr_wait, &wait); - - return ret; -} - -static int mp_get_count(struct sb_uart_state *state, struct serial_icounter_struct *icnt) -{ - struct serial_icounter_struct icount = {}; - struct sb_uart_icount cnow; - struct sb_uart_port *port = state->port; - - spin_lock_irq(&port->lock); - memcpy(&cnow, &port->icount, sizeof(struct sb_uart_icount)); - spin_unlock_irq(&port->lock); - - icount.cts = cnow.cts; - icount.dsr = cnow.dsr; - icount.rng = cnow.rng; - icount.dcd = cnow.dcd; - icount.rx = cnow.rx; - icount.tx = cnow.tx; - icount.frame = cnow.frame; - icount.overrun = cnow.overrun; - icount.parity = cnow.parity; - icount.brk = cnow.brk; - icount.buf_overrun = cnow.buf_overrun; - - return copy_to_user(icnt, &icount, sizeof(icount)) ? -EFAULT : 0; -} - -static int mp_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) -{ - struct sb_uart_state *state = tty->driver_data; - struct mp_port *info = (struct mp_port *)state->port; - int ret = -ENOIOCTLCMD; - - - switch (cmd) { - case TIOCSMULTIDROP: - /* set multi-drop mode enable or disable, and default operation mode is H/W mode */ - if (info->port.type == PORT_16C105XA) - { - //arg &= ~0x6; - //state->port->mdmode = 0; - return set_multidrop_mode((struct sb_uart_port *)info, (unsigned int)arg); - } - ret = -ENOTSUPP; - break; - case GETDEEPFIFO: - ret = get_deep_fifo(state->port); - return ret; - case SETDEEPFIFO: - ret = set_deep_fifo(state->port,arg); - deep[state->port->line] = arg; - return ret; - case SETTTR: - if (info->port.type == PORT_16C105X || info->port.type == PORT_16C105XA){ - ret = sb1054_set_register(state->port,PAGE_4,SB105X_TTR,arg); - ttr[state->port->line] = arg; - } - return ret; - case SETRTR: - if (info->port.type == PORT_16C105X || info->port.type == PORT_16C105XA){ - ret = sb1054_set_register(state->port,PAGE_4,SB105X_RTR,arg); - rtr[state->port->line] = arg; - } - return ret; - case GETTTR: - if (info->port.type == PORT_16C105X || info->port.type == PORT_16C105XA){ - ret = sb1054_get_register(state->port,PAGE_4,SB105X_TTR); - } - return ret; - case GETRTR: - if (info->port.type == PORT_16C105X || info->port.type == PORT_16C105XA){ - ret = sb1054_get_register(state->port,PAGE_4,SB105X_RTR); - } - return ret; - - case SETFCR: - if (info->port.type == PORT_16C105X || info->port.type == PORT_16C105XA){ - ret = sb1054_set_register(state->port,PAGE_1,SB105X_FCR,arg); - } - else{ - serial_out(info,2,arg); - } - - return ret; - case TIOCSMDADDR: - /* set multi-drop address */ - if (info->port.type == PORT_16C105XA) - { - state->port->mdmode |= MDMODE_ADDR; - return set_multidrop_addr((struct sb_uart_port *)info, (unsigned int)arg); - } - ret = -ENOTSUPP; - break; - - case TIOCGMDADDR: - /* set multi-drop address */ - if ((info->port.type == PORT_16C105XA) && (state->port->mdmode & MDMODE_ADDR)) - { - return get_multidrop_addr((struct sb_uart_port *)info); - } - ret = -ENOTSUPP; - break; - - case TIOCSENDADDR: - /* send address in multi-drop mode */ - if ((info->port.type == PORT_16C105XA) - && (state->port->mdmode & (MDMODE_ENABLE))) - { - if (mp_chars_in_buffer(tty) > 0) - { - tty_wait_until_sent(tty, 0); - } - //while ((serial_in(info, UART_LSR) & 0x60) != 0x60); - //while (sb1054_get_register(state->port, PAGE_2, SB105X_TFCR) != 0); - while ((serial_in(info, UART_LSR) & 0x60) != 0x60); - serial_out(info, UART_SCR, (int)arg); - } - break; - - case TIOCGSERIAL: - ret = mp_get_info(state, (struct serial_struct *)arg); - break; - - case TIOCSSERIAL: - ret = mp_set_info(state, (struct serial_struct *)arg); - break; - - case TIOCSERCONFIG: - ret = mp_do_autoconfig(state); - break; - - case TIOCSERGWILD: /* obsolete */ - case TIOCSERSWILD: /* obsolete */ - ret = 0; - break; - /* for Multiport */ - case TIOCGNUMOFPORT: /* Get number of ports */ - return NR_PORTS; - case TIOCGGETDEVID: - return mp_devs[arg].device_id; - case TIOCGGETREV: - return mp_devs[arg].revision; - case TIOCGGETNRPORTS: - return mp_devs[arg].nr_ports; - case TIOCGGETBDNO: - return NR_BOARD; - case TIOCGGETINTERFACE: - if (mp_devs[arg].revision == 0xc0) - { - /* for SB16C1053APCI */ - return (sb1053a_get_interface(info, info->port.line)); - } - else - { - return (inb(mp_devs[arg].option_reg_addr+MP_OPTR_IIR0+(state->port->line/8))); - } - case TIOCGGETPORTTYPE: - ret = get_device_type(arg); - return ret; - case TIOCSMULTIECHO: /* set to multi-drop mode(RS422) or echo mode(RS485)*/ - outb( ( inb(info->interface_config_addr) & ~0x03 ) | 0x01 , - info->interface_config_addr); - return 0; - case TIOCSPTPNOECHO: /* set to multi-drop mode(RS422) or echo mode(RS485) */ - outb( ( inb(info->interface_config_addr) & ~0x03 ) , - info->interface_config_addr); - return 0; - } - - if (ret != -ENOIOCTLCMD) - goto out; - - if (tty->flags & (1 << TTY_IO_ERROR)) { - ret = -EIO; - goto out; - } - - switch (cmd) { - case TIOCMIWAIT: - ret = mp_wait_modem_status(state, arg); - break; - - case TIOCGICOUNT: - ret = mp_get_count(state, (struct serial_icounter_struct *)arg); - break; - } - - if (ret != -ENOIOCTLCMD) - goto out; - - MP_STATE_LOCK(state); - switch (cmd) { - case TIOCSERGETLSR: /* Get line status register */ - ret = mp_get_lsr_info(state, (unsigned int *)arg); - break; - - default: { - struct sb_uart_port *port = state->port; - if (port->ops->ioctl) - ret = port->ops->ioctl(port, cmd, arg); - break; - } - } - - MP_STATE_UNLOCK(state); -out: - return ret; -} - -static void mp_set_termios(struct tty_struct *tty, struct MP_TERMIOS *old_termios) -{ - struct sb_uart_state *state = tty->driver_data; - unsigned long flags; - unsigned int cflag = tty->termios.c_cflag; - -#define RELEVANT_IFLAG(iflag) ((iflag) & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) - - if ((cflag ^ old_termios->c_cflag) == 0 && - RELEVANT_IFLAG(tty->termios.c_iflag ^ old_termios->c_iflag) == 0) - return; - - mp_change_speed(state, old_termios); - - if ((old_termios->c_cflag & CBAUD) && !(cflag & CBAUD)) - uart_clear_mctrl(state->port, TIOCM_RTS | TIOCM_DTR); - - if (!(old_termios->c_cflag & CBAUD) && (cflag & CBAUD)) { - unsigned int mask = TIOCM_DTR; - if (!(cflag & CRTSCTS) || - !test_bit(TTY_THROTTLED, &tty->flags)) - mask |= TIOCM_RTS; - uart_set_mctrl(state->port, mask); - } - - if ((old_termios->c_cflag & CRTSCTS) && !(cflag & CRTSCTS)) { - spin_lock_irqsave(&state->port->lock, flags); - tty->hw_stopped = 0; - __mp_start(tty); - spin_unlock_irqrestore(&state->port->lock, flags); - } - - if (!(old_termios->c_cflag & CRTSCTS) && (cflag & CRTSCTS)) { - spin_lock_irqsave(&state->port->lock, flags); - if (!(state->port->ops->get_mctrl(state->port) & TIOCM_CTS)) { - tty->hw_stopped = 1; - state->port->ops->stop_tx(state->port); - } - spin_unlock_irqrestore(&state->port->lock, flags); - } -} - -static void mp_close(struct tty_struct *tty, struct file *filp) -{ - struct sb_uart_state *state = tty->driver_data; - struct sb_uart_port *port; - - printk("mp_close!\n"); - if (!state || !state->port) - return; - - port = state->port; - - printk("close1 %d\n", __LINE__); - MP_STATE_LOCK(state); - - printk("close2 %d\n", __LINE__); - if (tty_hung_up_p(filp)) - goto done; - - printk("close3 %d\n", __LINE__); - if ((tty->count == 1) && (state->count != 1)) { - printk("mp_close: bad serial port count; tty->count is 1, " - "state->count is %d\n", state->count); - state->count = 1; - } - printk("close4 %d\n", __LINE__); - if (--state->count < 0) { - printk("rs_close: bad serial port count for ttyMP%d: %d\n", - port->line, state->count); - state->count = 0; - } - if (state->count) - goto done; - - tty->closing = 1; - - printk("close5 %d\n", __LINE__); - if (state->closing_wait != USF_CLOSING_WAIT_NONE) - tty_wait_until_sent(tty, state->closing_wait); - - printk("close6 %d\n", __LINE__); - if (state->info->flags & UIF_INITIALIZED) { - unsigned long flags; - spin_lock_irqsave(&port->lock, flags); - port->ops->stop_rx(port); - spin_unlock_irqrestore(&port->lock, flags); - mp_wait_until_sent(tty, port->timeout); - } - printk("close7 %d\n", __LINE__); - - mp_shutdown(state); - printk("close8 %d\n", __LINE__); - mp_flush_buffer(tty); - tty_ldisc_flush(tty); - tty->closing = 0; - state->info->tty = NULL; - if (state->info->blocked_open) - { - if (state->close_delay) - { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(state->close_delay); - } - } - else - { - mp_change_pm(state, 3); - } - printk("close8 %d\n", __LINE__); - - state->info->flags &= ~UIF_NORMAL_ACTIVE; - wake_up_interruptible(&state->info->open_wait); - -done: - printk("close done\n"); - MP_STATE_UNLOCK(state); - module_put(THIS_MODULE); -} - -static void mp_wait_until_sent(struct tty_struct *tty, int timeout) -{ - struct sb_uart_state *state = tty->driver_data; - struct sb_uart_port *port = state->port; - unsigned long char_time, expire; - - if (port->type == PORT_UNKNOWN || port->fifosize == 0) - return; - - char_time = (port->timeout - HZ/50) / port->fifosize; - char_time = char_time / 5; - if (char_time == 0) - char_time = 1; - if (timeout && timeout < char_time) - char_time = timeout; - - if (timeout == 0 || timeout > 2 * port->timeout) - timeout = 2 * port->timeout; - - expire = jiffies + timeout; - - while (!port->ops->tx_empty(port)) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(char_time); - if (signal_pending(current)) - break; - if (time_after(jiffies, expire)) - break; - } - set_current_state(TASK_RUNNING); /* might not be needed */ -} - -static void mp_hangup(struct tty_struct *tty) -{ - struct sb_uart_state *state = tty->driver_data; - - MP_STATE_LOCK(state); - if (state->info && state->info->flags & UIF_NORMAL_ACTIVE) { - mp_flush_buffer(tty); - mp_shutdown(state); - state->count = 0; - state->info->flags &= ~UIF_NORMAL_ACTIVE; - state->info->tty = NULL; - wake_up_interruptible(&state->info->open_wait); - wake_up_interruptible(&state->info->delta_msr_wait); - } - MP_STATE_UNLOCK(state); -} - -static void mp_update_termios(struct sb_uart_state *state) -{ - struct tty_struct *tty = state->info->tty; - struct sb_uart_port *port = state->port; - - if (!(tty->flags & (1 << TTY_IO_ERROR))) { - mp_change_speed(state, NULL); - - if (tty->termios.c_cflag & CBAUD) - uart_set_mctrl(port, TIOCM_DTR | TIOCM_RTS); - } -} - -static int mp_block_til_ready(struct file *filp, struct sb_uart_state *state) -{ - DECLARE_WAITQUEUE(wait, current); - struct sb_uart_info *info = state->info; - struct sb_uart_port *port = state->port; - unsigned int mctrl; - - info->blocked_open++; - state->count--; - - add_wait_queue(&info->open_wait, &wait); - while (1) { - set_current_state(TASK_INTERRUPTIBLE); - - if (tty_hung_up_p(filp) || info->tty == NULL) - break; - - if (!(info->flags & UIF_INITIALIZED)) - break; - - if ((filp->f_flags & O_NONBLOCK) || - (info->tty->termios.c_cflag & CLOCAL) || - (info->tty->flags & (1 << TTY_IO_ERROR))) { - break; - } - - if (info->tty->termios.c_cflag & CBAUD) - uart_set_mctrl(port, TIOCM_DTR); - - spin_lock_irq(&port->lock); - port->ops->enable_ms(port); - mctrl = port->ops->get_mctrl(port); - spin_unlock_irq(&port->lock); - if (mctrl & TIOCM_CAR) - break; - - MP_STATE_UNLOCK(state); - schedule(); - MP_STATE_LOCK(state); - - if (signal_pending(current)) - break; - } - set_current_state(TASK_RUNNING); - remove_wait_queue(&info->open_wait, &wait); - - state->count++; - info->blocked_open--; - - if (signal_pending(current)) - return -ERESTARTSYS; - - if (!info->tty || tty_hung_up_p(filp)) - return -EAGAIN; - - return 0; -} - -static struct sb_uart_state *uart_get(struct uart_driver *drv, int line) -{ - struct sb_uart_state *state; - - MP_MUTEX_LOCK(mp_mutex); - state = drv->state + line; - if (mutex_lock_interruptible(&state->mutex)) { - state = ERR_PTR(-ERESTARTSYS); - goto out; - } - state->count++; - if (!state->port) { - state->count--; - MP_STATE_UNLOCK(state); - state = ERR_PTR(-ENXIO); - goto out; - } - - if (!state->info) { - state->info = kmalloc(sizeof(struct sb_uart_info), GFP_KERNEL); - if (state->info) { - memset(state->info, 0, sizeof(struct sb_uart_info)); - init_waitqueue_head(&state->info->open_wait); - init_waitqueue_head(&state->info->delta_msr_wait); - - state->port->info = state->info; - - tasklet_init(&state->info->tlet, mp_tasklet_action, - (unsigned long)state); - } else { - state->count--; - MP_STATE_UNLOCK(state); - state = ERR_PTR(-ENOMEM); - } - } - -out: - MP_MUTEX_UNLOCK(mp_mutex); - return state; -} - -static int mp_open(struct tty_struct *tty, struct file *filp) -{ - struct uart_driver *drv = (struct uart_driver *)tty->driver->driver_state; - struct sb_uart_state *state; - int retval; - int line = tty->index; - struct mp_port *mtpt; - - retval = -ENODEV; - if (line >= tty->driver->num) - goto fail; - - state = uart_get(drv, line); - - if (IS_ERR(state)) { - retval = PTR_ERR(state); - goto fail; - } - - mtpt = (struct mp_port *)state->port; - - tty->driver_data = state; - tty->low_latency = (state->port->flags & UPF_LOW_LATENCY) ? 1 : 0; - tty->alt_speed = 0; - state->info->tty = tty; - - if (tty_hung_up_p(filp)) { - retval = -EAGAIN; - state->count--; - MP_STATE_UNLOCK(state); - goto fail; - } - - if (state->count == 1) - mp_change_pm(state, 0); - - retval = mp_startup(state, 0); - - if (retval == 0) - retval = mp_block_til_ready(filp, state); - MP_STATE_UNLOCK(state); - - if (retval == 0 && !(state->info->flags & UIF_NORMAL_ACTIVE)) { - state->info->flags |= UIF_NORMAL_ACTIVE; - - mp_update_termios(state); - } - - uart_clear_mctrl(state->port, TIOCM_RTS); - try_module_get(THIS_MODULE); -fail: - return retval; -} - - -static const char *mp_type(struct sb_uart_port *port) -{ - const char *str = NULL; - - if (port->ops->type) - str = port->ops->type(port); - - if (!str) - str = "unknown"; - - return str; -} - -static void mp_change_pm(struct sb_uart_state *state, int pm_state) -{ - struct sb_uart_port *port = state->port; - if (port->ops->pm) - port->ops->pm(port, pm_state, state->pm_state); - state->pm_state = pm_state; -} - -static inline void mp_report_port(struct uart_driver *drv, struct sb_uart_port *port) -{ - char address[64]; - - switch (port->iotype) { - case UPIO_PORT: - snprintf(address, sizeof(address),"I/O 0x%x", port->iobase); - break; - case UPIO_HUB6: - snprintf(address, sizeof(address),"I/O 0x%x offset 0x%x", port->iobase, port->hub6); - break; - case UPIO_MEM: - snprintf(address, sizeof(address),"MMIO 0x%lx", port->mapbase); - break; - default: - snprintf(address, sizeof(address),"*unknown*" ); - strlcpy(address, "*unknown*", sizeof(address)); - break; - } - - printk( "%s%d at %s (irq = %d) is a %s\n", - drv->dev_name, port->line, address, port->irq, mp_type(port)); - -} - -static void mp_configure_port(struct uart_driver *drv, struct sb_uart_state *state, struct sb_uart_port *port) -{ - unsigned int flags; - - - if (!port->iobase && !port->mapbase && !port->membase) - { - DPRINTK("%s error \n",__FUNCTION__); - return; - } - flags = UART_CONFIG_TYPE; - if (port->flags & UPF_AUTO_IRQ) - flags |= UART_CONFIG_IRQ; - if (port->flags & UPF_BOOT_AUTOCONF) { - port->type = PORT_UNKNOWN; - port->ops->config_port(port, flags); - } - - if (port->type != PORT_UNKNOWN) { - unsigned long flags; - - mp_report_port(drv, port); - - spin_lock_irqsave(&port->lock, flags); - port->ops->set_mctrl(port, 0); - spin_unlock_irqrestore(&port->lock, flags); - - mp_change_pm(state, 3); - } -} - -static void mp_unconfigure_port(struct uart_driver *drv, struct sb_uart_state *state) -{ - struct sb_uart_port *port = state->port; - struct sb_uart_info *info = state->info; - - if (info && info->tty) - tty_hangup(info->tty); - - MP_STATE_LOCK(state); - - state->info = NULL; - - if (port->type != PORT_UNKNOWN) - port->ops->release_port(port); - - port->type = PORT_UNKNOWN; - - if (info) { - tasklet_kill(&info->tlet); - kfree(info); - } - - MP_STATE_UNLOCK(state); -} -static struct tty_operations mp_ops = { - .open = mp_open, - .close = mp_close, - .write = mp_write, - .put_char = mp_put_char, - .flush_chars = mp_put_chars, - .write_room = mp_write_room, - .chars_in_buffer= mp_chars_in_buffer, - .flush_buffer = mp_flush_buffer, - .ioctl = mp_ioctl, - .throttle = mp_throttle, - .unthrottle = mp_unthrottle, - .send_xchar = mp_send_xchar, - .set_termios = mp_set_termios, - .stop = mp_stop, - .start = mp_start, - .hangup = mp_hangup, - .break_ctl = mp_break_ctl, - .wait_until_sent= mp_wait_until_sent, -#ifdef CONFIG_PROC_FS - .proc_fops = NULL, -#endif - .tiocmget = mp_tiocmget, - .tiocmset = mp_tiocmset, -}; - -static int mp_register_driver(struct uart_driver *drv) -{ - struct tty_driver *normal = NULL; - int i, retval; - - drv->state = kmalloc(sizeof(struct sb_uart_state) * drv->nr, GFP_KERNEL); - retval = -ENOMEM; - if (!drv->state) - { - printk("SB PCI Error: Kernel memory allocation error!\n"); - goto out; - } - memset(drv->state, 0, sizeof(struct sb_uart_state) * drv->nr); - - normal = alloc_tty_driver(drv->nr); - if (!normal) - { - printk("SB PCI Error: tty allocation error!\n"); - goto out; - } - - drv->tty_driver = normal; - - normal->owner = drv->owner; - normal->magic = TTY_DRIVER_MAGIC; - normal->driver_name = drv->driver_name; - normal->name = drv->dev_name; - normal->major = drv->major; - normal->minor_start = drv->minor; - - normal->num = MAX_MP_PORT ; - - normal->type = TTY_DRIVER_TYPE_SERIAL; - normal->subtype = SERIAL_TYPE_NORMAL; - normal->init_termios = tty_std_termios; - normal->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; - normal->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; - normal->driver_state = drv; - - tty_set_operations(normal, &mp_ops); - -for (i = 0; i < drv->nr; i++) { - struct sb_uart_state *state = drv->state + i; - - state->close_delay = 500; - state->closing_wait = 30000; - - mutex_init(&state->mutex); - } - - retval = tty_register_driver(normal); -out: - if (retval < 0) { - printk("Register tty driver Fail!\n"); - put_tty_driver(normal); - kfree(drv->state); - } - - return retval; -} - -void mp_unregister_driver(struct uart_driver *drv) -{ - struct tty_driver *normal = NULL; - - normal = drv->tty_driver; - - if (!normal) - { - return; - } - - tty_unregister_driver(normal); - put_tty_driver(normal); - drv->tty_driver = NULL; - - - kfree(drv->state); - -} - -static int mp_add_one_port(struct uart_driver *drv, struct sb_uart_port *port) -{ - struct sb_uart_state *state; - int ret = 0; - - - if (port->line >= drv->nr) - return -EINVAL; - - state = drv->state + port->line; - - MP_MUTEX_LOCK(mp_mutex); - if (state->port) { - ret = -EINVAL; - goto out; - } - - state->port = port; - - spin_lock_init(&port->lock); - port->cons = drv->cons; - port->info = state->info; - - mp_configure_port(drv, state, port); - - tty_register_device(drv->tty_driver, port->line, port->dev); - -out: - MP_MUTEX_UNLOCK(mp_mutex); - - - return ret; -} - -static int mp_remove_one_port(struct uart_driver *drv, struct sb_uart_port *port) -{ - struct sb_uart_state *state = drv->state + port->line; - - if (state->port != port) - printk(KERN_ALERT "Removing wrong port: %p != %p\n", - state->port, port); - - MP_MUTEX_LOCK(mp_mutex); - - tty_unregister_device(drv->tty_driver, port->line); - - mp_unconfigure_port(drv, state); - state->port = NULL; - MP_MUTEX_UNLOCK(mp_mutex); - - return 0; -} - -static void autoconfig(struct mp_port *mtpt, unsigned int probeflags) -{ - unsigned char status1, scratch, scratch2, scratch3; - unsigned char save_lcr, save_mcr; - unsigned long flags; - - unsigned char u_type; - unsigned char b_ret = 0; - - if (!mtpt->port.iobase && !mtpt->port.mapbase && !mtpt->port.membase) - return; - - DEBUG_AUTOCONF("ttyMP%d: autoconf (0x%04x, 0x%p): ", - mtpt->port.line, mtpt->port.iobase, mtpt->port.membase); - - spin_lock_irqsave(&mtpt->port.lock, flags); - - if (!(mtpt->port.flags & UPF_BUGGY_UART)) { - scratch = serial_inp(mtpt, UART_IER); - serial_outp(mtpt, UART_IER, 0); -#ifdef __i386__ - outb(0xff, 0x080); -#endif - scratch2 = serial_inp(mtpt, UART_IER) & 0x0f; - serial_outp(mtpt, UART_IER, 0x0F); -#ifdef __i386__ - outb(0, 0x080); -#endif - scratch3 = serial_inp(mtpt, UART_IER) & 0x0F; - serial_outp(mtpt, UART_IER, scratch); - if (scratch2 != 0 || scratch3 != 0x0F) { - DEBUG_AUTOCONF("IER test failed (%02x, %02x) ", - scratch2, scratch3); - goto out; - } - } - - save_mcr = serial_in(mtpt, UART_MCR); - save_lcr = serial_in(mtpt, UART_LCR); - - if (!(mtpt->port.flags & UPF_SKIP_TEST)) { - serial_outp(mtpt, UART_MCR, UART_MCR_LOOP | 0x0A); - status1 = serial_inp(mtpt, UART_MSR) & 0xF0; - serial_outp(mtpt, UART_MCR, save_mcr); - if (status1 != 0x90) { - DEBUG_AUTOCONF("LOOP test failed (%02x) ", - status1); - goto out; - } - } - - serial_outp(mtpt, UART_LCR, 0xBF); - serial_outp(mtpt, UART_EFR, 0); - serial_outp(mtpt, UART_LCR, 0); - - serial_outp(mtpt, UART_FCR, UART_FCR_ENABLE_FIFO); - scratch = serial_in(mtpt, UART_IIR) >> 6; - - DEBUG_AUTOCONF("iir=%d ", scratch); - if(mtpt->device->nr_ports >= 8) - b_ret = read_option_register(mtpt,(MP_OPTR_DIR0 + ((mtpt->port.line)/8))); - else - b_ret = read_option_register(mtpt,MP_OPTR_DIR0); - u_type = (b_ret & 0xf0) >> 4; - if(mtpt->port.type == PORT_UNKNOWN ) - { - switch (u_type) - { - case DIR_UART_16C550: - mtpt->port.type = PORT_16C55X; - break; - case DIR_UART_16C1050: - mtpt->port.type = PORT_16C105X; - break; - case DIR_UART_16C1050A: - if (mtpt->port.line < 2) - { - mtpt->port.type = PORT_16C105XA; - } - else - { - if (mtpt->device->device_id & 0x50) - { - mtpt->port.type = PORT_16C55X; - } - else - { - mtpt->port.type = PORT_16C105X; - } - } - break; - default: - mtpt->port.type = PORT_UNKNOWN; - break; - } - } - - if(mtpt->port.type == PORT_UNKNOWN ) - { -printk("unknow2\n"); - switch (scratch) { - case 0: - case 1: - mtpt->port.type = PORT_UNKNOWN; - break; - case 2: - case 3: - mtpt->port.type = PORT_16C55X; - break; - } - } - - serial_outp(mtpt, UART_LCR, save_lcr); - - mtpt->port.fifosize = uart_config[mtpt->port.type].dfl_xmit_fifo_size; - mtpt->capabilities = uart_config[mtpt->port.type].flags; - - if (mtpt->port.type == PORT_UNKNOWN) - goto out; - serial_outp(mtpt, UART_MCR, save_mcr); - serial_outp(mtpt, UART_FCR, (UART_FCR_ENABLE_FIFO | - UART_FCR_CLEAR_RCVR | - UART_FCR_CLEAR_XMIT)); - serial_outp(mtpt, UART_FCR, 0); - (void)serial_in(mtpt, UART_RX); - serial_outp(mtpt, UART_IER, 0); - -out: - spin_unlock_irqrestore(&mtpt->port.lock, flags); - DEBUG_AUTOCONF("type=%s\n", uart_config[mtpt->port.type].name); -} - -static void autoconfig_irq(struct mp_port *mtpt) -{ - unsigned char save_mcr, save_ier; - unsigned long irqs; - int irq; - - /* forget possible initially masked and pending IRQ */ - probe_irq_off(probe_irq_on()); - save_mcr = serial_inp(mtpt, UART_MCR); - save_ier = serial_inp(mtpt, UART_IER); - serial_outp(mtpt, UART_MCR, UART_MCR_OUT1 | UART_MCR_OUT2); - - irqs = probe_irq_on(); - serial_outp(mtpt, UART_MCR, 0); - serial_outp(mtpt, UART_MCR, - UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2); - - serial_outp(mtpt, UART_IER, 0x0f); /* enable all intrs */ - (void)serial_inp(mtpt, UART_LSR); - (void)serial_inp(mtpt, UART_RX); - (void)serial_inp(mtpt, UART_IIR); - (void)serial_inp(mtpt, UART_MSR); - serial_outp(mtpt, UART_TX, 0xFF); - irq = probe_irq_off(irqs); - - serial_outp(mtpt, UART_MCR, save_mcr); - serial_outp(mtpt, UART_IER, save_ier); - - mtpt->port.irq = (irq > 0) ? irq : 0; -} - -static void multi_stop_tx(struct sb_uart_port *port) -{ - struct mp_port *mtpt = (struct mp_port *)port; - - if (mtpt->ier & UART_IER_THRI) { - mtpt->ier &= ~UART_IER_THRI; - serial_out(mtpt, UART_IER, mtpt->ier); - } - - tasklet_schedule(&port->info->tlet); -} - -static void multi_start_tx(struct sb_uart_port *port) -{ - struct mp_port *mtpt = (struct mp_port *)port; - - if (!(mtpt->ier & UART_IER_THRI)) { - mtpt->ier |= UART_IER_THRI; - serial_out(mtpt, UART_IER, mtpt->ier); - } -} - -static void multi_stop_rx(struct sb_uart_port *port) -{ - struct mp_port *mtpt = (struct mp_port *)port; - - mtpt->ier &= ~UART_IER_RLSI; - mtpt->port.read_status_mask &= ~UART_LSR_DR; - serial_out(mtpt, UART_IER, mtpt->ier); -} - -static void multi_enable_ms(struct sb_uart_port *port) -{ - struct mp_port *mtpt = (struct mp_port *)port; - - mtpt->ier |= UART_IER_MSI; - serial_out(mtpt, UART_IER, mtpt->ier); -} - - -static _INLINE_ void receive_chars(struct mp_port *mtpt, int *status ) -{ - struct tty_struct *tty = mtpt->port.info->tty; - unsigned char lsr = *status; - int max_count = 256; - unsigned char ch; - char flag; - - //lsr &= mtpt->port.read_status_mask; - - do { - if ((lsr & UART_LSR_PE) && (mtpt->port.mdmode & MDMODE_ENABLE)) - { - ch = serial_inp(mtpt, UART_RX); - } - else if (lsr & UART_LSR_SPECIAL) - { - flag = 0; - ch = serial_inp(mtpt, UART_RX); - - if (lsr & UART_LSR_BI) - { - - mtpt->port.icount.brk++; - flag = TTY_BREAK; - - if (sb_uart_handle_break(&mtpt->port)) - goto ignore_char; - } - if (lsr & UART_LSR_PE) - { - mtpt->port.icount.parity++; - flag = TTY_PARITY; - } - if (lsr & UART_LSR_FE) - { - mtpt->port.icount.frame++; - flag = TTY_FRAME; - } - if (lsr & UART_LSR_OE) - { - mtpt->port.icount.overrun++; - flag = TTY_OVERRUN; - } - tty_insert_flip_char(tty, ch, flag); - } - else - { - ch = serial_inp(mtpt, UART_RX); - tty_insert_flip_char(tty, ch, 0); - } -ignore_char: - lsr = serial_inp(mtpt, UART_LSR); - } while ((lsr & UART_LSR_DR) && (max_count-- > 0)); - - tty_flip_buffer_push(tty); -} - - - - -static _INLINE_ void transmit_chars(struct mp_port *mtpt) -{ - struct circ_buf *xmit = &mtpt->port.info->xmit; - int count; - - if (mtpt->port.x_char) { - serial_outp(mtpt, UART_TX, mtpt->port.x_char); - mtpt->port.icount.tx++; - mtpt->port.x_char = 0; - return; - } - if (uart_circ_empty(xmit) || uart_tx_stopped(&mtpt->port)) { - multi_stop_tx(&mtpt->port); - return; - } - - count = uart_circ_chars_pending(xmit); - - if(count > mtpt->port.fifosize) - { - count = mtpt->port.fifosize; - } - - printk("[%d] mdmode: %x\n", mtpt->port.line, mtpt->port.mdmode); - do { -#if 0 - /* check multi-drop mode */ - if ((mtpt->port.mdmode & (MDMODE_ENABLE | MDMODE_ADDR)) == (MDMODE_ENABLE | MDMODE_ADDR)) - { - printk("send address\n"); - /* send multi-drop address */ - serial_out(mtpt, UART_SCR, xmit->buf[xmit->tail]); - } - else -#endif - { - serial_out(mtpt, UART_TX, xmit->buf[xmit->tail]); - } - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - mtpt->port.icount.tx++; - } while (--count > 0); -} - - - -static _INLINE_ void check_modem_status(struct mp_port *mtpt) -{ - int status; - - status = serial_in(mtpt, UART_MSR); - - if ((status & UART_MSR_ANY_DELTA) == 0) - return; - - if (status & UART_MSR_TERI) - mtpt->port.icount.rng++; - if (status & UART_MSR_DDSR) - mtpt->port.icount.dsr++; - if (status & UART_MSR_DDCD) - sb_uart_handle_dcd_change(&mtpt->port, status & UART_MSR_DCD); - if (status & UART_MSR_DCTS) - sb_uart_handle_cts_change(&mtpt->port, status & UART_MSR_CTS); - - wake_up_interruptible(&mtpt->port.info->delta_msr_wait); -} - -static inline void multi_handle_port(struct mp_port *mtpt) -{ - unsigned int status = serial_inp(mtpt, UART_LSR); - - //printk("lsr: %x\n", status); - - if ((status & UART_LSR_DR) || (status & UART_LSR_SPECIAL)) - receive_chars(mtpt, &status); - check_modem_status(mtpt); - if (status & UART_LSR_THRE) - { - if ((mtpt->port.type == PORT_16C105X) - || (mtpt->port.type == PORT_16C105XA)) - transmit_chars(mtpt); - else - { - if (mtpt->interface >= RS485NE) - uart_set_mctrl(&mtpt->port, TIOCM_RTS); - - transmit_chars(mtpt); - - - if (mtpt->interface >= RS485NE) - { - while((status=serial_in(mtpt,UART_LSR) &0x60)!=0x60); - uart_clear_mctrl(&mtpt->port, TIOCM_RTS); - } - } - } -} - - - -static irqreturn_t multi_interrupt(int irq, void *dev_id) -{ - struct irq_info *iinfo = dev_id; - struct list_head *lhead, *end = NULL; - int pass_counter = 0; - - - spin_lock(&iinfo->lock); - - lhead = iinfo->head; - do { - struct mp_port *mtpt; - unsigned int iir; - - mtpt = list_entry(lhead, struct mp_port, list); - - iir = serial_in(mtpt, UART_IIR); - printk("interrupt! port %d, iir 0x%x\n", mtpt->port.line, iir); //wlee - if (!(iir & UART_IIR_NO_INT)) - { - printk("interrupt handle\n"); - spin_lock(&mtpt->port.lock); - multi_handle_port(mtpt); - spin_unlock(&mtpt->port.lock); - - end = NULL; - } else if (end == NULL) - end = lhead; - - lhead = lhead->next; - if (lhead == iinfo->head && pass_counter++ > PASS_LIMIT) - { - printk(KERN_ERR "multi: too much work for " - "irq%d\n", irq); - printk( "multi: too much work for " - "irq%d\n", irq); - break; - } - } while (lhead != end); - - spin_unlock(&iinfo->lock); - - - return IRQ_HANDLED; -} - -static void serial_do_unlink(struct irq_info *i, struct mp_port *mtpt) -{ - spin_lock_irq(&i->lock); - - if (!list_empty(i->head)) { - if (i->head == &mtpt->list) - i->head = i->head->next; - list_del(&mtpt->list); - } else { - i->head = NULL; - } - - spin_unlock_irq(&i->lock); -} - -static int serial_link_irq_chain(struct mp_port *mtpt) -{ - struct irq_info *i = irq_lists + mtpt->port.irq; - int ret, irq_flags = mtpt->port.flags & UPF_SHARE_IRQ ? IRQF_SHARED : 0; - spin_lock_irq(&i->lock); - - if (i->head) { - list_add(&mtpt->list, i->head); - spin_unlock_irq(&i->lock); - - ret = 0; - } else { - INIT_LIST_HEAD(&mtpt->list); - i->head = &mtpt->list; - spin_unlock_irq(&i->lock); - - ret = request_irq(mtpt->port.irq, multi_interrupt, - irq_flags, "serial", i); - if (ret < 0) - serial_do_unlink(i, mtpt); - } - - return ret; -} - - - - -static void serial_unlink_irq_chain(struct mp_port *mtpt) -{ - struct irq_info *i = irq_lists + mtpt->port.irq; - - if (list_empty(i->head)) - { - free_irq(mtpt->port.irq, i); - } - serial_do_unlink(i, mtpt); -} - -static void multi_timeout(unsigned long data) -{ - struct mp_port *mtpt = (struct mp_port *)data; - - - spin_lock(&mtpt->port.lock); - multi_handle_port(mtpt); - spin_unlock(&mtpt->port.lock); - - mod_timer(&mtpt->timer, jiffies+1 ); -} - -static unsigned int multi_tx_empty(struct sb_uart_port *port) -{ - struct mp_port *mtpt = (struct mp_port *)port; - unsigned long flags; - unsigned int ret; - - spin_lock_irqsave(&mtpt->port.lock, flags); - ret = serial_in(mtpt, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0; - spin_unlock_irqrestore(&mtpt->port.lock, flags); - - return ret; -} - - -static unsigned int multi_get_mctrl(struct sb_uart_port *port) -{ - struct mp_port *mtpt = (struct mp_port *)port; - unsigned char status; - unsigned int ret; - - status = serial_in(mtpt, UART_MSR); - - ret = 0; - if (status & UART_MSR_DCD) - ret |= TIOCM_CAR; - if (status & UART_MSR_RI) - ret |= TIOCM_RNG; - if (status & UART_MSR_DSR) - ret |= TIOCM_DSR; - if (status & UART_MSR_CTS) - ret |= TIOCM_CTS; - return ret; -} - -static void multi_set_mctrl(struct sb_uart_port *port, unsigned int mctrl) -{ - struct mp_port *mtpt = (struct mp_port *)port; - unsigned char mcr = 0; - - mctrl &= 0xff; - - if (mctrl & TIOCM_RTS) - mcr |= UART_MCR_RTS; - if (mctrl & TIOCM_DTR) - mcr |= UART_MCR_DTR; - if (mctrl & TIOCM_OUT1) - mcr |= UART_MCR_OUT1; - if (mctrl & TIOCM_OUT2) - mcr |= UART_MCR_OUT2; - if (mctrl & TIOCM_LOOP) - mcr |= UART_MCR_LOOP; - - - serial_out(mtpt, UART_MCR, mcr); -} - - -static void multi_break_ctl(struct sb_uart_port *port, int break_state) -{ - struct mp_port *mtpt = (struct mp_port *)port; - unsigned long flags; - - spin_lock_irqsave(&mtpt->port.lock, flags); - if (break_state == -1) - mtpt->lcr |= UART_LCR_SBC; - else - mtpt->lcr &= ~UART_LCR_SBC; - serial_out(mtpt, UART_LCR, mtpt->lcr); - spin_unlock_irqrestore(&mtpt->port.lock, flags); -} - - - -static int multi_startup(struct sb_uart_port *port) -{ - struct mp_port *mtpt = (struct mp_port *)port; - unsigned long flags; - int retval; - - mtpt->capabilities = uart_config[mtpt->port.type].flags; - mtpt->mcr = 0; - - if (mtpt->capabilities & UART_CLEAR_FIFO) { - serial_outp(mtpt, UART_FCR, UART_FCR_ENABLE_FIFO); - serial_outp(mtpt, UART_FCR, UART_FCR_ENABLE_FIFO | - UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); - serial_outp(mtpt, UART_FCR, 0); - } - - (void) serial_inp(mtpt, UART_LSR); - (void) serial_inp(mtpt, UART_RX); - (void) serial_inp(mtpt, UART_IIR); - (void) serial_inp(mtpt, UART_MSR); - //test-wlee 9-bit disable - serial_outp(mtpt, UART_MSR, 0); - - - if (!(mtpt->port.flags & UPF_BUGGY_UART) && - (serial_inp(mtpt, UART_LSR) == 0xff)) { - printk("ttyS%d: LSR safety check engaged!\n", mtpt->port.line); - //return -ENODEV; - } - - if ((!is_real_interrupt(mtpt->port.irq)) || (mtpt->poll_type==TYPE_POLL)) { - unsigned int timeout = mtpt->port.timeout; - - timeout = timeout > 6 ? (timeout / 2 - 2) : 1; - - mtpt->timer.data = (unsigned long)mtpt; - mod_timer(&mtpt->timer, jiffies + timeout); - } - else - { - retval = serial_link_irq_chain(mtpt); - if (retval) - return retval; - } - - serial_outp(mtpt, UART_LCR, UART_LCR_WLEN8); - - spin_lock_irqsave(&mtpt->port.lock, flags); - if ((is_real_interrupt(mtpt->port.irq))||(mtpt->poll_type==TYPE_INTERRUPT)) - mtpt->port.mctrl |= TIOCM_OUT2; - - multi_set_mctrl(&mtpt->port, mtpt->port.mctrl); - spin_unlock_irqrestore(&mtpt->port.lock, flags); - - - mtpt->ier = UART_IER_RLSI | UART_IER_RDI; - serial_outp(mtpt, UART_IER, mtpt->ier); - - (void) serial_inp(mtpt, UART_LSR); - (void) serial_inp(mtpt, UART_RX); - (void) serial_inp(mtpt, UART_IIR); - (void) serial_inp(mtpt, UART_MSR); - - return 0; -} - - - -static void multi_shutdown(struct sb_uart_port *port) -{ - struct mp_port *mtpt = (struct mp_port *)port; - unsigned long flags; - - - mtpt->ier = 0; - serial_outp(mtpt, UART_IER, 0); - - spin_lock_irqsave(&mtpt->port.lock, flags); - mtpt->port.mctrl &= ~TIOCM_OUT2; - - multi_set_mctrl(&mtpt->port, mtpt->port.mctrl); - spin_unlock_irqrestore(&mtpt->port.lock, flags); - - serial_out(mtpt, UART_LCR, serial_inp(mtpt, UART_LCR) & ~UART_LCR_SBC); - serial_outp(mtpt, UART_FCR, UART_FCR_ENABLE_FIFO | - UART_FCR_CLEAR_RCVR | - UART_FCR_CLEAR_XMIT); - serial_outp(mtpt, UART_FCR, 0); - - - (void) serial_in(mtpt, UART_RX); - - if ((!is_real_interrupt(mtpt->port.irq))||(mtpt->poll_type==TYPE_POLL)) - { - del_timer_sync(&mtpt->timer); - } - else - { - serial_unlink_irq_chain(mtpt); - } -} - - - -static unsigned int multi_get_divisor(struct sb_uart_port *port, unsigned int baud) -{ - unsigned int quot; - - if ((port->flags & UPF_MAGIC_MULTIPLIER) && - baud == (port->uartclk/4)) - quot = 0x8001; - else if ((port->flags & UPF_MAGIC_MULTIPLIER) && - baud == (port->uartclk/8)) - quot = 0x8002; - else - quot = sb_uart_get_divisor(port, baud); - - return quot; -} - - - - -static void multi_set_termios(struct sb_uart_port *port, struct MP_TERMIOS *termios, struct MP_TERMIOS *old) -{ - struct mp_port *mtpt = (struct mp_port *)port; - unsigned char cval, fcr = 0; - unsigned long flags; - unsigned int baud, quot; - - switch (termios->c_cflag & CSIZE) { - case CS5: - cval = 0x00; - break; - case CS6: - cval = 0x01; - break; - case CS7: - cval = 0x02; - break; - default: - case CS8: - cval = 0x03; - break; - } - - if (termios->c_cflag & CSTOPB) - cval |= 0x04; - if (termios->c_cflag & PARENB) - cval |= UART_LCR_PARITY; - if (!(termios->c_cflag & PARODD)) - cval |= UART_LCR_EPAR; - -#ifdef CMSPAR - if (termios->c_cflag & CMSPAR) - cval |= UART_LCR_SPAR; -#endif - - baud = sb_uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); - quot = multi_get_divisor(port, baud); - - if (mtpt->capabilities & UART_USE_FIFO) { - //if (baud < 2400) - // fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1; - //else - // fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_8; - - // fcr = UART_FCR_ENABLE_FIFO | 0x90; - fcr = fcr_arr[mtpt->port.line]; - } - - spin_lock_irqsave(&mtpt->port.lock, flags); - - sb_uart_update_timeout(port, termios->c_cflag, baud); - - mtpt->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR; - if (termios->c_iflag & INPCK) - mtpt->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE; - if (termios->c_iflag & (BRKINT | PARMRK)) - mtpt->port.read_status_mask |= UART_LSR_BI; - - mtpt->port.ignore_status_mask = 0; - if (termios->c_iflag & IGNPAR) - mtpt->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE; - if (termios->c_iflag & IGNBRK) { - mtpt->port.ignore_status_mask |= UART_LSR_BI; - if (termios->c_iflag & IGNPAR) - mtpt->port.ignore_status_mask |= UART_LSR_OE; - } - - if ((termios->c_cflag & CREAD) == 0) - mtpt->port.ignore_status_mask |= UART_LSR_DR; - - mtpt->ier &= ~UART_IER_MSI; - if (UART_ENABLE_MS(&mtpt->port, termios->c_cflag)) - mtpt->ier |= UART_IER_MSI; - - serial_out(mtpt, UART_IER, mtpt->ier); - - if (mtpt->capabilities & UART_STARTECH) { - serial_outp(mtpt, UART_LCR, 0xBF); - serial_outp(mtpt, UART_EFR, - termios->c_cflag & CRTSCTS ? UART_EFR_CTS :0); - } - - serial_outp(mtpt, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */ - - serial_outp(mtpt, UART_DLL, quot & 0xff); /* LS of divisor */ - serial_outp(mtpt, UART_DLM, quot >> 8); /* MS of divisor */ - - serial_outp(mtpt, UART_LCR, cval); /* reset DLAB */ - mtpt->lcr = cval; /* Save LCR */ - - if (fcr & UART_FCR_ENABLE_FIFO) { - /* emulated UARTs (Lucent Venus 167x) need two steps */ - serial_outp(mtpt, UART_FCR, UART_FCR_ENABLE_FIFO); - } - - serial_outp(mtpt, UART_FCR, fcr); /* set fcr */ - - - if ((mtpt->port.type == PORT_16C105X) - || (mtpt->port.type == PORT_16C105XA)) - { - if(deep[mtpt->port.line]!=0) - set_deep_fifo(port, ENABLE); - - if (mtpt->interface != RS232) - set_auto_rts(port,mtpt->interface); - - } - else - { - if (mtpt->interface >= RS485NE) - { - uart_clear_mctrl(&mtpt->port, TIOCM_RTS); - } - } - - if(mtpt->device->device_id == PCI_DEVICE_ID_MP4M) - { - SendATCommand(mtpt); - printk("SendATCommand\n"); - } - multi_set_mctrl(&mtpt->port, mtpt->port.mctrl); - spin_unlock_irqrestore(&mtpt->port.lock, flags); -} - -static void multi_pm(struct sb_uart_port *port, unsigned int state, unsigned int oldstate) -{ - struct mp_port *mtpt = (struct mp_port *)port; - if (state) { - if (mtpt->capabilities & UART_STARTECH) { - serial_outp(mtpt, UART_LCR, 0xBF); - serial_outp(mtpt, UART_EFR, UART_EFR_ECB); - serial_outp(mtpt, UART_LCR, 0); - serial_outp(mtpt, UART_IER, UART_IERX_SLEEP); - serial_outp(mtpt, UART_LCR, 0xBF); - serial_outp(mtpt, UART_EFR, 0); - serial_outp(mtpt, UART_LCR, 0); - } - - if (mtpt->pm) - mtpt->pm(port, state, oldstate); - } - else - { - if (mtpt->capabilities & UART_STARTECH) { - serial_outp(mtpt, UART_LCR, 0xBF); - serial_outp(mtpt, UART_EFR, UART_EFR_ECB); - serial_outp(mtpt, UART_LCR, 0); - serial_outp(mtpt, UART_IER, 0); - serial_outp(mtpt, UART_LCR, 0xBF); - serial_outp(mtpt, UART_EFR, 0); - serial_outp(mtpt, UART_LCR, 0); - } - - if (mtpt->pm) - mtpt->pm(port, state, oldstate); - } -} - -static void multi_release_std_resource(struct mp_port *mtpt) -{ - unsigned int size = 8 << mtpt->port.regshift; - - switch (mtpt->port.iotype) { - case UPIO_MEM: - if (!mtpt->port.mapbase) - break; - - if (mtpt->port.flags & UPF_IOREMAP) { - iounmap(mtpt->port.membase); - mtpt->port.membase = NULL; - } - - release_mem_region(mtpt->port.mapbase, size); - break; - - case UPIO_HUB6: - case UPIO_PORT: - release_region(mtpt->port.iobase,size); - break; - } -} - -static void multi_release_port(struct sb_uart_port *port) -{ -} - -static int multi_request_port(struct sb_uart_port *port) -{ - return 0; -} - -static void multi_config_port(struct sb_uart_port *port, int flags) -{ - struct mp_port *mtpt = (struct mp_port *)port; - int probeflags = PROBE_ANY; - - if (flags & UART_CONFIG_TYPE) - autoconfig(mtpt, probeflags); - if (mtpt->port.type != PORT_UNKNOWN && flags & UART_CONFIG_IRQ) - autoconfig_irq(mtpt); - - if (mtpt->port.type == PORT_UNKNOWN) - multi_release_std_resource(mtpt); -} - -static int multi_verify_port(struct sb_uart_port *port, struct serial_struct *ser) -{ - if (ser->irq >= NR_IRQS || ser->irq < 0 || - ser->baud_base < 9600 || ser->type < PORT_UNKNOWN || - ser->type == PORT_STARTECH) - return -EINVAL; - return 0; -} - -static const char *multi_type(struct sb_uart_port *port) -{ - int type = port->type; - - if (type >= ARRAY_SIZE(uart_config)) - type = 0; - return uart_config[type].name; -} - -static struct sb_uart_ops multi_pops = { - .tx_empty = multi_tx_empty, - .set_mctrl = multi_set_mctrl, - .get_mctrl = multi_get_mctrl, - .stop_tx = multi_stop_tx, - .start_tx = multi_start_tx, - .stop_rx = multi_stop_rx, - .enable_ms = multi_enable_ms, - .break_ctl = multi_break_ctl, - .startup = multi_startup, - .shutdown = multi_shutdown, - .set_termios = multi_set_termios, - .pm = multi_pm, - .type = multi_type, - .release_port = multi_release_port, - .request_port = multi_request_port, - .config_port = multi_config_port, - .verify_port = multi_verify_port, -}; - -static struct uart_driver multi_reg = { - .owner = THIS_MODULE, - .driver_name = "goldel_tulip", - .dev_name = "ttyMP", - .major = SB_TTY_MP_MAJOR, - .minor = 0, - .nr = MAX_MP_PORT, - .cons = NULL, -}; - -static void __init multi_init_ports(void) -{ - struct mp_port *mtpt; - static int first = 1; - int i,j,k; - unsigned char osc; - unsigned char b_ret = 0; - static struct mp_device_t *sbdev; - - if (!first) - return; - first = 0; - - mtpt = multi_ports; - - for (k=0;k<NR_BOARD;k++) - { - sbdev = &mp_devs[k]; - - for (i = 0; i < sbdev->nr_ports; i++, mtpt++) - { - mtpt->device = sbdev; - mtpt->port.iobase = sbdev->uart_access_addr + 8*i; - mtpt->port.irq = sbdev->irq; - if ( ((sbdev->device_id == PCI_DEVICE_ID_MP4)&&(sbdev->revision==0x91))) - mtpt->interface_config_addr = sbdev->option_reg_addr + 0x08 + i; - else if (sbdev->revision == 0xc0) - mtpt->interface_config_addr = sbdev->option_reg_addr + 0x08 + (i & 0x1); - else - mtpt->interface_config_addr = sbdev->option_reg_addr + 0x08 + i/8; - - mtpt->option_base_addr = sbdev->option_reg_addr; - - mtpt->poll_type = sbdev->poll_type; - - mtpt->port.uartclk = BASE_BAUD * 16; - - /* get input clock information */ - osc = inb(sbdev->option_reg_addr + MP_OPTR_DIR0 + i/8) & 0x0F; - if (osc==0x0f) - osc = 0; - for(j=0;j<osc;j++) - mtpt->port.uartclk *= 2; - mtpt->port.flags |= STD_COM_FLAGS | UPF_SHARE_IRQ ; - mtpt->port.iotype = UPIO_PORT; - mtpt->port.ops = &multi_pops; - - if (sbdev->revision == 0xc0) - { - /* for SB16C1053APCI */ - b_ret = sb1053a_get_interface(mtpt, i); - } - else - { - b_ret = read_option_register(mtpt,(MP_OPTR_IIR0 + i/8)); - printk("IIR_RET = %x\n",b_ret); - } - - /* default to RS232 */ - mtpt->interface = RS232; - if (IIR_RS422 == (b_ret & IIR_TYPE_MASK)) - mtpt->interface = RS422PTP; - if (IIR_RS485 == (b_ret & IIR_TYPE_MASK)) - mtpt->interface = RS485NE; - } - } -} - -static void __init multi_register_ports(struct uart_driver *drv) -{ - int i; - - multi_init_ports(); - - for (i = 0; i < NR_PORTS; i++) { - struct mp_port *mtpt = &multi_ports[i]; - - mtpt->port.line = i; - mtpt->port.ops = &multi_pops; - init_timer(&mtpt->timer); - mtpt->timer.function = multi_timeout; - mp_add_one_port(drv, &mtpt->port); - } -} - -/** - * pci_remap_base - remap BAR value of pci device - * - * PARAMETERS - * pcidev - pci_dev structure address - * offset - BAR offset PCI_BASE_ADDRESS_0 ~ PCI_BASE_ADDRESS_4 - * address - address to be changed BAR value - * size - size of address space - * - * RETURNS - * If this function performs successful, it returns 0. Otherwise, It returns -1. - */ -static int pci_remap_base(struct pci_dev *pcidev, unsigned int offset, - unsigned int address, unsigned int size) -{ -#if 0 - struct resource *root; - unsigned index = (offset - 0x10) >> 2; -#endif - - pci_write_config_dword(pcidev, offset, address); -#if 0 - root = pcidev->resource[index].parent; - release_resource(&pcidev->resource[index]); - address &= ~0x1; - pcidev->resource[index].start = address; - pcidev->resource[index].end = address + size - 1; - - if (request_resource(root, &pcidev->resource[index]) != NULL) - { - printk(KERN_ERR "pci remap conflict!! 0x%x\n", address); - return (-1); - } -#endif - - return (0); -} - -static int init_mp_dev(struct pci_dev *pcidev, mppcibrd_t brd) -{ - static struct mp_device_t *sbdev = mp_devs; - unsigned long addr = 0; - int j; - struct resource *ret = NULL; - - sbdev->device_id = brd.device_id; - pci_read_config_byte(pcidev, PCI_CLASS_REVISION, &(sbdev->revision)); - sbdev->name = brd.name; - sbdev->uart_access_addr = pcidev->resource[0].start & PCI_BASE_ADDRESS_IO_MASK; - - /* check revision. The SB16C1053APCI's option i/o address is BAR4 */ - if (sbdev->revision == 0xc0) - { - /* SB16C1053APCI */ - sbdev->option_reg_addr = pcidev->resource[4].start & PCI_BASE_ADDRESS_IO_MASK; - } - else - { - sbdev->option_reg_addr = pcidev->resource[1].start & PCI_BASE_ADDRESS_IO_MASK; - } -#if 1 - if (sbdev->revision == 0xc0) - { - outb(0x00, sbdev->option_reg_addr + MP_OPTR_GPOCR); - inb(sbdev->option_reg_addr + MP_OPTR_GPOCR); - outb(0x83, sbdev->option_reg_addr + MP_OPTR_GPOCR); - } -#endif - - sbdev->irq = pcidev->irq; - - if ((brd.device_id & 0x0800) || !(brd.device_id &0xff00)) - { - sbdev->poll_type = TYPE_INTERRUPT; - } - else - { - sbdev->poll_type = TYPE_POLL; - } - - /* codes which is specific to each board*/ - switch(brd.device_id){ - case PCI_DEVICE_ID_MP1 : - case PCIE_DEVICE_ID_MP1 : - case PCIE_DEVICE_ID_MP1E : - case PCIE_DEVICE_ID_GT_MP1 : - sbdev->nr_ports = 1; - break; - case PCI_DEVICE_ID_MP2 : - case PCIE_DEVICE_ID_MP2 : - case PCIE_DEVICE_ID_GT_MP2 : - case PCIE_DEVICE_ID_MP2B : - case PCIE_DEVICE_ID_MP2E : - sbdev->nr_ports = 2; - - /* serial base address remap */ - if (sbdev->revision == 0xc0) - { - int prev_port_addr = 0; - - pci_read_config_dword(pcidev, PCI_BASE_ADDRESS_0, &prev_port_addr); - pci_remap_base(pcidev, PCI_BASE_ADDRESS_1, prev_port_addr + 8, 8); - } - break; - case PCI_DEVICE_ID_MP4 : - case PCI_DEVICE_ID_MP4A : - case PCIE_DEVICE_ID_MP4 : - case PCI_DEVICE_ID_GT_MP4 : - case PCI_DEVICE_ID_GT_MP4A : - case PCIE_DEVICE_ID_GT_MP4 : - case PCI_DEVICE_ID_MP4M : - case PCIE_DEVICE_ID_MP4B : - sbdev->nr_ports = 4; - - if(sbdev->revision == 0x91){ - sbdev->reserved_addr[0] = pcidev->resource[0].start & PCI_BASE_ADDRESS_IO_MASK; - outb(0x03 , sbdev->reserved_addr[0] + 0x01); - outb(0x03 , sbdev->reserved_addr[0] + 0x02); - outb(0x01 , sbdev->reserved_addr[0] + 0x20); - outb(0x00 , sbdev->reserved_addr[0] + 0x21); - request_region(sbdev->reserved_addr[0], 32, sbdev->name); - sbdev->uart_access_addr = pcidev->resource[1].start & PCI_BASE_ADDRESS_IO_MASK; - sbdev->option_reg_addr = pcidev->resource[2].start & PCI_BASE_ADDRESS_IO_MASK; - } - - /* SB16C1053APCI */ - if (sbdev->revision == 0xc0) - { - int prev_port_addr = 0; - - pci_read_config_dword(pcidev, PCI_BASE_ADDRESS_0, &prev_port_addr); - pci_remap_base(pcidev, PCI_BASE_ADDRESS_1, prev_port_addr + 8, 8); - pci_remap_base(pcidev, PCI_BASE_ADDRESS_2, prev_port_addr + 16, 8); - pci_remap_base(pcidev, PCI_BASE_ADDRESS_3, prev_port_addr + 24, 8); - } - break; - case PCI_DEVICE_ID_MP6 : - case PCI_DEVICE_ID_MP6A : - case PCI_DEVICE_ID_GT_MP6 : - case PCI_DEVICE_ID_GT_MP6A : - sbdev->nr_ports = 6; - - /* SB16C1053APCI */ - if (sbdev->revision == 0xc0) - { - int prev_port_addr = 0; - - pci_read_config_dword(pcidev, PCI_BASE_ADDRESS_0, &prev_port_addr); - pci_remap_base(pcidev, PCI_BASE_ADDRESS_1, prev_port_addr + 8, 8); - pci_remap_base(pcidev, PCI_BASE_ADDRESS_2, prev_port_addr + 16, 16); - pci_remap_base(pcidev, PCI_BASE_ADDRESS_3, prev_port_addr + 32, 16); - } - break; - case PCI_DEVICE_ID_MP8 : - case PCIE_DEVICE_ID_MP8 : - case PCI_DEVICE_ID_GT_MP8 : - case PCIE_DEVICE_ID_GT_MP8 : - case PCIE_DEVICE_ID_MP8B : - sbdev->nr_ports = 8; - break; - case PCI_DEVICE_ID_MP32 : - case PCIE_DEVICE_ID_MP32 : - case PCI_DEVICE_ID_GT_MP32 : - case PCIE_DEVICE_ID_GT_MP32 : - { - int portnum_hex=0; - portnum_hex = inb(sbdev->option_reg_addr); - sbdev->nr_ports = ((portnum_hex/16)*10) + (portnum_hex % 16); - } - break; -#ifdef CONFIG_PARPORT_PC - case PCI_DEVICE_ID_MP2S1P : - sbdev->nr_ports = 2; - - /* SB16C1053APCI */ - if (sbdev->revision == 0xc0) - { - int prev_port_addr = 0; - - pci_read_config_dword(pcidev, PCI_BASE_ADDRESS_0, &prev_port_addr); - pci_remap_base(pcidev, PCI_BASE_ADDRESS_1, prev_port_addr + 8, 8); - } - - /* add PC compatible parallel port */ - parport_pc_probe_port(pcidev->resource[2].start, pcidev->resource[3].start, PARPORT_IRQ_NONE, PARPORT_DMA_NONE, &pcidev->dev, 0); - break; - case PCI_DEVICE_ID_MP1P : - /* add PC compatible parallel port */ - parport_pc_probe_port(pcidev->resource[2].start, pcidev->resource[3].start, PARPORT_IRQ_NONE, PARPORT_DMA_NONE, &pcidev->dev, 0); - break; -#endif - } - - ret = request_region(sbdev->uart_access_addr, (8*sbdev->nr_ports), sbdev->name); - - if (sbdev->revision == 0xc0) - { - ret = request_region(sbdev->option_reg_addr, 0x40, sbdev->name); - } - else - { - ret = request_region(sbdev->option_reg_addr, 0x20, sbdev->name); - } - - - NR_BOARD++; - NR_PORTS += sbdev->nr_ports; - - /* Enable PCI interrupt */ - addr = sbdev->option_reg_addr + MP_OPTR_IMR0; - for(j=0; j < (sbdev->nr_ports/8)+1; j++) - { - if (sbdev->poll_type == TYPE_INTERRUPT) - { - outb(0xff,addr +j); - } - } - sbdev++; - - return 0; -} - -static int __init multi_init(void) -{ - int ret, i; - struct pci_dev *dev = NULL; - - if(fcr_count==0) - { - for(i=0;i<256;i++) - { - fcr_arr[i] = 0x01; - - } - } - if(deep_count==0) - { - for(i=0;i<256;i++) - { - deep[i] = 1; - - } - } - if(rtr_count==0) - { - for(i=0;i<256;i++) - { - rtr[i] = 0x10; - } - } - if(ttr_count==0) - { - for(i=0;i<256;i++) - { - ttr[i] = 0x38; - } - } - - -printk("MULTI INIT\n"); - for( i=0; i< mp_nrpcibrds; i++) - { - - while( (dev = pci_get_device(mp_pciboards[i].vendor_id, mp_pciboards[i].device_id, dev) ) ) - - { -printk("FOUND~~~\n"); -// Cent OS bug fix -// if (mp_pciboards[i].device_id & 0x0800) - { - int status; - pci_disable_device(dev); - status = pci_enable_device(dev); - - if (status != 0) - { - printk("Multiport Board Enable Fail !\n\n"); - status = -ENXIO; - return status; - } - } - - init_mp_dev(dev, mp_pciboards[i]); - } - } - - for (i = 0; i < NR_IRQS; i++) - spin_lock_init(&irq_lists[i].lock); - - ret = mp_register_driver(&multi_reg); - - if (ret >= 0) - multi_register_ports(&multi_reg); - - return ret; -} - -static void __exit multi_exit(void) -{ - int i; - - for (i = 0; i < NR_PORTS; i++) - mp_remove_one_port(&multi_reg, &multi_ports[i].port); - - mp_unregister_driver(&multi_reg); -} - -module_init(multi_init); -module_exit(multi_exit); - -MODULE_DESCRIPTION("SystemBase Multiport PCI/PCIe CORE"); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/sb105x/sb_pci_mp.h b/drivers/staging/sb105x/sb_pci_mp.h deleted file mode 100644 index 80ae4ab0460..00000000000 --- a/drivers/staging/sb105x/sb_pci_mp.h +++ /dev/null @@ -1,291 +0,0 @@ -#include <linux/errno.h> -#include <linux/signal.h> -#include <linux/tty.h> -#include <linux/tty_flip.h> -#include <linux/serial.h> -#include <linux/serial_reg.h> -#include <linux/ioport.h> -#include <linux/mm.h> -#include <linux/sched.h> - -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/wait.h> -#include <linux/tty_driver.h> -#include <linux/pci.h> -#include <linux/circ_buf.h> - -#include <asm/uaccess.h> -#include <asm/io.h> -#include <asm/irq.h> -#include <asm/serial.h> -#include <linux/interrupt.h> - - -#include <linux/parport.h> -#include <linux/ctype.h> -#include <linux/poll.h> - - -#define MP_TERMIOS ktermios - -#include "sb_mp_register.h" -#include "sb_ser_core.h" - -#define DRIVER_VERSION "1.1" -#define DRIVER_DATE "2012/01/05" -#define DRIVER_AUTHOR "SYSTEMBASE<tech@sysbas.com>" -#define DRIVER_DESC "SystemBase PCI/PCIe Multiport Core" - -#define SB_TTY_MP_MAJOR 54 -#define PCI_VENDOR_ID_MULTIPORT 0x14A1 - -#define PCI_DEVICE_ID_MP1 0x4d01 -#define PCI_DEVICE_ID_MP2 0x4d02 -#define PCI_DEVICE_ID_MP4 0x4d04 -#define PCI_DEVICE_ID_MP4A 0x4d54 -#define PCI_DEVICE_ID_MP6 0x4d06 -#define PCI_DEVICE_ID_MP6A 0x4d56 -#define PCI_DEVICE_ID_MP8 0x4d08 -#define PCI_DEVICE_ID_MP32 0x4d32 -/* Parallel port */ -#define PCI_DEVICE_ID_MP1P 0x4301 -#define PCI_DEVICE_ID_MP2S1P 0x4303 - -#define PCIE_DEVICE_ID_MP1 0x4501 -#define PCIE_DEVICE_ID_MP2 0x4502 -#define PCIE_DEVICE_ID_MP4 0x4504 -#define PCIE_DEVICE_ID_MP8 0x4508 -#define PCIE_DEVICE_ID_MP32 0x4532 - -#define PCIE_DEVICE_ID_MP1E 0x4e01 -#define PCIE_DEVICE_ID_MP2E 0x4e02 -#define PCIE_DEVICE_ID_MP2B 0x4b02 -#define PCIE_DEVICE_ID_MP4B 0x4b04 -#define PCIE_DEVICE_ID_MP8B 0x4b08 - -#define PCI_DEVICE_ID_GT_MP4 0x0004 -#define PCI_DEVICE_ID_GT_MP4A 0x0054 -#define PCI_DEVICE_ID_GT_MP6 0x0006 -#define PCI_DEVICE_ID_GT_MP6A 0x0056 -#define PCI_DEVICE_ID_GT_MP8 0x0008 -#define PCI_DEVICE_ID_GT_MP32 0x0032 - -#define PCIE_DEVICE_ID_GT_MP1 0x1501 -#define PCIE_DEVICE_ID_GT_MP2 0x1502 -#define PCIE_DEVICE_ID_GT_MP4 0x1504 -#define PCIE_DEVICE_ID_GT_MP8 0x1508 -#define PCIE_DEVICE_ID_GT_MP32 0x1532 - -#define PCI_DEVICE_ID_MP4M 0x4604 //modem - -#define MAX_MP_DEV 8 -#define BD_MAX_PORT 32 /* Max serial port in one board */ -#define MAX_MP_PORT 256 /* Max serial port in one PC */ - -#define PORT_16C105XA 3 -#define PORT_16C105X 2 -#define PORT_16C55X 1 - -#define ENABLE 1 -#define DISABLE 0 - -/* ioctls */ -#define TIOCGNUMOFPORT 0x545F -#define TIOCSMULTIECHO 0x5440 -#define TIOCSPTPNOECHO 0x5441 - -#define TIOCGOPTIONREG 0x5461 -#define TIOCGDISABLEIRQ 0x5462 -#define TIOCGENABLEIRQ 0x5463 -#define TIOCGSOFTRESET 0x5464 -#define TIOCGSOFTRESETR 0x5465 -#define TIOCGREGINFO 0x5466 -#define TIOCGGETLSR 0x5467 -#define TIOCGGETDEVID 0x5468 -#define TIOCGGETBDNO 0x5469 -#define TIOCGGETINTERFACE 0x546A -#define TIOCGGETREV 0x546B -#define TIOCGGETNRPORTS 0x546C -#define TIOCGGETPORTTYPE 0x546D -#define GETDEEPFIFO 0x54AA -#define SETDEEPFIFO 0x54AB -#define SETFCR 0x54BA -#define SETTTR 0x54B1 -#define SETRTR 0x54B2 -#define GETTTR 0x54B3 -#define GETRTR 0x54B4 - -/* multi-drop mode related ioctl commands */ -#define TIOCSMULTIDROP 0x5470 -#define TIOCSMDADDR 0x5471 -#define TIOCGMDADDR 0x5472 -#define TIOCSENDADDR 0x5473 - - -/* serial interface */ -#define RS232 1 -#define RS422PTP 2 -#define RS422MD 3 -#define RS485NE 4 -#define RS485ECHO 5 - -#define serial_inp(up, offset) serial_in(up, offset) -#define serial_outp(up, offset, value) serial_out(up, offset, value) - -#define PASS_LIMIT 256 -#define is_real_interrupt(irq) ((irq) != 0) - -#define PROBE_ANY (~0) - -static DEFINE_MUTEX(mp_mutex); -#define MP_MUTEX_LOCK(x) mutex_lock(&(x)) -#define MP_MUTEX_UNLOCK(x) mutex_unlock(&(x)) -#define MP_STATE_LOCK(x) mutex_lock(&((x)->mutex)) -#define MP_STATE_UNLOCK(x) mutex_unlock(&((x)->mutex)) - - -#define UART_LSR_SPECIAL 0x1E - -#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8) -#define uart_users(state) ((state)->count + ((state)->info ? (state)->info->blocked_open : 0)) - - -//#define MP_DEBUG 1 -#undef MP_DEBUG - -#ifdef MP_DEBUG -#define DPRINTK(x...) printk(x) -#else -#define DPRINTK(x...) do { } while (0) -#endif - -#ifdef MP_DEBUG -#define DEBUG_AUTOCONF(fmt...) printk(fmt) -#else -#define DEBUG_AUTOCONF(fmt...) do { } while (0) -#endif - -#ifdef MP_DEBUG -#define DEBUG_INTR(fmt...) printk(fmt) -#else -#define DEBUG_INTR(fmt...) do { } while (0) -#endif - -#if defined(__i386__) && defined(CONFIG_M486) -#define SERIAL_INLINE -#endif -#ifdef SERIAL_INLINE -#define _INLINE_ inline -#else -#define _INLINE_ -#endif - -#define TYPE_POLL 1 -#define TYPE_INTERRUPT 2 - - -struct mp_device_t { - unsigned short device_id; - unsigned char revision; - char *name; - unsigned long uart_access_addr; - unsigned long option_reg_addr; - unsigned long reserved_addr[4]; - int irq; - int nr_ports; - int poll_type; -}; - -typedef struct mppcibrd { - char *name; - unsigned short vendor_id; - unsigned short device_id; -} mppcibrd_t; - -static mppcibrd_t mp_pciboards[] = { - - { "Multi-1 PCI", PCI_VENDOR_ID_MULTIPORT , PCI_DEVICE_ID_MP1} , - { "Multi-2 PCI", PCI_VENDOR_ID_MULTIPORT , PCI_DEVICE_ID_MP2} , - { "Multi-4 PCI", PCI_VENDOR_ID_MULTIPORT , PCI_DEVICE_ID_MP4} , - { "Multi-4 PCI", PCI_VENDOR_ID_MULTIPORT , PCI_DEVICE_ID_MP4A} , - { "Multi-6 PCI", PCI_VENDOR_ID_MULTIPORT , PCI_DEVICE_ID_MP6} , - { "Multi-6 PCI", PCI_VENDOR_ID_MULTIPORT , PCI_DEVICE_ID_MP6A} , - { "Multi-8 PCI", PCI_VENDOR_ID_MULTIPORT , PCI_DEVICE_ID_MP8} , - { "Multi-32 PCI", PCI_VENDOR_ID_MULTIPORT , PCI_DEVICE_ID_MP32} , - - { "Multi-1P PCI", PCI_VENDOR_ID_MULTIPORT , PCI_DEVICE_ID_MP1P} , - { "Multi-2S1P PCI", PCI_VENDOR_ID_MULTIPORT , PCI_DEVICE_ID_MP2S1P} , - - { "Multi-4(GT) PCI", PCI_VENDOR_ID_MULTIPORT , PCI_DEVICE_ID_GT_MP4} , - { "Multi-4(GT) PCI", PCI_VENDOR_ID_MULTIPORT , PCI_DEVICE_ID_GT_MP4A} , - { "Multi-6(GT) PCI", PCI_VENDOR_ID_MULTIPORT , PCI_DEVICE_ID_GT_MP6} , - { "Multi-6(GT) PCI", PCI_VENDOR_ID_MULTIPORT , PCI_DEVICE_ID_GT_MP6A} , - { "Multi-8(GT) PCI", PCI_VENDOR_ID_MULTIPORT , PCI_DEVICE_ID_GT_MP8} , - { "Multi-32(GT) PCI", PCI_VENDOR_ID_MULTIPORT , PCI_DEVICE_ID_GT_MP32} , - - { "Multi-1 PCIe", PCI_VENDOR_ID_MULTIPORT , PCIE_DEVICE_ID_MP1} , - { "Multi-2 PCIe", PCI_VENDOR_ID_MULTIPORT , PCIE_DEVICE_ID_MP2} , - { "Multi-4 PCIe", PCI_VENDOR_ID_MULTIPORT , PCIE_DEVICE_ID_MP4} , - { "Multi-8 PCIe", PCI_VENDOR_ID_MULTIPORT , PCIE_DEVICE_ID_MP8} , - { "Multi-32 PCIe", PCI_VENDOR_ID_MULTIPORT , PCIE_DEVICE_ID_MP32} , - - { "Multi-1 PCIe E", PCI_VENDOR_ID_MULTIPORT , PCIE_DEVICE_ID_MP1E} , - { "Multi-2 PCIe E", PCI_VENDOR_ID_MULTIPORT , PCIE_DEVICE_ID_MP2E} , - { "Multi-2 PCIe B", PCI_VENDOR_ID_MULTIPORT , PCIE_DEVICE_ID_MP2B} , - { "Multi-4 PCIe B", PCI_VENDOR_ID_MULTIPORT , PCIE_DEVICE_ID_MP4B} , - { "Multi-8 PCIe B", PCI_VENDOR_ID_MULTIPORT , PCIE_DEVICE_ID_MP8B} , - - { "Multi-1(GT) PCIe", PCI_VENDOR_ID_MULTIPORT , PCIE_DEVICE_ID_GT_MP1} , - { "Multi-2(GT) PCIe", PCI_VENDOR_ID_MULTIPORT , PCIE_DEVICE_ID_GT_MP2} , - { "Multi-4(GT) PCIe", PCI_VENDOR_ID_MULTIPORT , PCIE_DEVICE_ID_GT_MP4} , - { "Multi-8(GT) PCIe", PCI_VENDOR_ID_MULTIPORT , PCIE_DEVICE_ID_GT_MP8} , - { "Multi-32(GT) PCIe", PCI_VENDOR_ID_MULTIPORT , PCIE_DEVICE_ID_GT_MP32} , - - { "Multi-4M PCI", PCI_VENDOR_ID_MULTIPORT , PCI_DEVICE_ID_MP4M} , -}; - -struct mp_port { - struct sb_uart_port port; - - struct timer_list timer; /* "no irq" timer */ - struct list_head list; /* ports on this IRQ */ - unsigned int capabilities; /* port capabilities */ - unsigned short rev; - unsigned char acr; - unsigned char ier; - unsigned char lcr; - unsigned char mcr; - unsigned char mcr_mask; /* mask of user bits */ - unsigned char mcr_force; /* mask of forced bits */ - unsigned char lsr_break_flag; - - void (*pm)(struct sb_uart_port *port, - unsigned int state, unsigned int old); - struct mp_device_t *device; - unsigned long interface_config_addr; - unsigned long option_base_addr; - unsigned char interface; - unsigned char poll_type; -}; - -struct irq_info { - spinlock_t lock; - struct list_head *head; -}; - -struct sb105x_uart_config { - char *name; - int dfl_xmit_fifo_size; - int flags; -}; - -static const struct sb105x_uart_config uart_config[] = { - { "unknown", 1, 0 }, - { "16550A", 16, UART_CLEAR_FIFO | UART_USE_FIFO }, - { "SB16C1050", 128, UART_CLEAR_FIFO | UART_USE_FIFO | UART_STARTECH }, - { "SB16C1050A", 128, UART_CLEAR_FIFO | UART_USE_FIFO | UART_STARTECH }, -}; - - - diff --git a/drivers/staging/sb105x/sb_ser_core.h b/drivers/staging/sb105x/sb_ser_core.h deleted file mode 100644 index c8fb9917329..00000000000 --- a/drivers/staging/sb105x/sb_ser_core.h +++ /dev/null @@ -1,368 +0,0 @@ -#include <linux/wait.h> - -#define UART_CONFIG_TYPE (1 << 0) -#define UART_CONFIG_IRQ (1 << 1) -#define UPIO_PORT (0) -#define UPIO_HUB6 (1) -#define UPIO_MEM (2) -#define UPIO_MEM32 (3) -#define UPIO_AU (4) /* Au1x00 type IO */ -#define UPIO_TSI (5) /* Tsi108/109 type IO */ -#define UPF_FOURPORT (1 << 1) -#define UPF_SAK (1 << 2) -#define UPF_SPD_MASK (0x1030) -#define UPF_SPD_HI (0x0010) -#define UPF_SPD_VHI (0x0020) -#define UPF_SPD_CUST (0x0030) -#define UPF_SPD_SHI (0x1000) -#define UPF_SPD_WARP (0x1010) -#define UPF_SKIP_TEST (1 << 6) -#define UPF_AUTO_IRQ (1 << 7) -#define UPF_HARDPPS_CD (1 << 11) -#define UPF_LOW_LATENCY (1 << 13) -#define UPF_BUGGY_UART (1 << 14) -#define UPF_MAGIC_MULTIPLIER (1 << 16) -#define UPF_CONS_FLOW (1 << 23) -#define UPF_SHARE_IRQ (1 << 24) -#define UPF_BOOT_AUTOCONF (1 << 28) -#define UPF_DEAD (1 << 30) -#define UPF_IOREMAP (1 << 31) -#define UPF_CHANGE_MASK (0x17fff) -#define UPF_USR_MASK (UPF_SPD_MASK|UPF_LOW_LATENCY) -#define USF_CLOSING_WAIT_INF (0) -#define USF_CLOSING_WAIT_NONE (~0U) - -#define UART_XMIT_SIZE PAGE_SIZE - -#define UIF_CHECK_CD (1 << 25) -#define UIF_CTS_FLOW (1 << 26) -#define UIF_NORMAL_ACTIVE (1 << 29) -#define UIF_INITIALIZED (1 << 31) -#define UIF_SUSPENDED (1 << 30) - -#define WAKEUP_CHARS 256 - -#define uart_circ_empty(circ) ((circ)->head == (circ)->tail) -#define uart_circ_clear(circ) ((circ)->head = (circ)->tail = 0) - -#define uart_circ_chars_pending(circ) \ - (CIRC_CNT((circ)->head, (circ)->tail, UART_XMIT_SIZE)) - -#define uart_circ_chars_free(circ) \ - (CIRC_SPACE((circ)->head, (circ)->tail, UART_XMIT_SIZE)) - -#define uart_tx_stopped(port) \ - ((port)->info->tty->stopped || (port)->info->tty->hw_stopped) - -#define UART_ENABLE_MS(port,cflag) ((port)->flags & UPF_HARDPPS_CD || \ - (cflag) & CRTSCTS || \ - !((cflag) & CLOCAL)) - - -struct sb_uart_port; -struct sb_uart_info; -struct serial_struct; -struct device; - -struct sb_uart_ops { - unsigned int (*tx_empty)(struct sb_uart_port *); - void (*set_mctrl)(struct sb_uart_port *, unsigned int mctrl); - unsigned int (*get_mctrl)(struct sb_uart_port *); - void (*stop_tx)(struct sb_uart_port *); - void (*start_tx)(struct sb_uart_port *); - void (*send_xchar)(struct sb_uart_port *, char ch); - void (*stop_rx)(struct sb_uart_port *); - void (*enable_ms)(struct sb_uart_port *); - void (*break_ctl)(struct sb_uart_port *, int ctl); - int (*startup)(struct sb_uart_port *); - void (*shutdown)(struct sb_uart_port *); - void (*set_termios)(struct sb_uart_port *, struct MP_TERMIOS *new, - struct MP_TERMIOS *old); - void (*pm)(struct sb_uart_port *, unsigned int state, - unsigned int oldstate); - int (*set_wake)(struct sb_uart_port *, unsigned int state); - - const char *(*type)(struct sb_uart_port *); - - void (*release_port)(struct sb_uart_port *); - - int (*request_port)(struct sb_uart_port *); - void (*config_port)(struct sb_uart_port *, int); - int (*verify_port)(struct sb_uart_port *, struct serial_struct *); - int (*ioctl)(struct sb_uart_port *, unsigned int, unsigned long); -}; - - -struct sb_uart_icount { - __u32 cts; - __u32 dsr; - __u32 rng; - __u32 dcd; - __u32 rx; - __u32 tx; - __u32 frame; - __u32 overrun; - __u32 parity; - __u32 brk; - __u32 buf_overrun; -}; -typedef unsigned int upf_t; - -struct sb_uart_port { - spinlock_t lock; /* port lock */ - unsigned int iobase; /* in/out[bwl] */ - unsigned char __iomem *membase; /* read/write[bwl] */ - unsigned int irq; /* irq number */ - unsigned int uartclk; /* base uart clock */ - unsigned int fifosize; /* tx fifo size */ - unsigned char x_char; /* xon/xoff char */ - unsigned char regshift; /* reg offset shift */ - unsigned char iotype; /* io access style */ - unsigned char unused1; - - - unsigned int read_status_mask; /* driver specific */ - unsigned int ignore_status_mask; /* driver specific */ - struct sb_uart_info *info; /* pointer to parent info */ - struct sb_uart_icount icount; /* statistics */ - - struct console *cons; /* struct console, if any */ -#ifdef CONFIG_SERIAL_CORE_CONSOLE - unsigned long sysrq; /* sysrq timeout */ -#endif - - upf_t flags; - - unsigned int mctrl; /* current modem ctrl settings */ - unsigned int timeout; /* character-based timeout */ - unsigned int type; /* port type */ - const struct sb_uart_ops *ops; - unsigned int custom_divisor; - unsigned int line; /* port index */ - unsigned long mapbase; /* for ioremap */ - struct device *dev; /* parent device */ - unsigned char hub6; /* this should be in the 8250 driver */ - unsigned char unused[3]; -}; - -#define mdmode unused[2] -#define MDMODE_ADDR 0x1 -#define MDMODE_ENABLE 0x2 -#define MDMODE_AUTO 0x4 -#define MDMODE_ADDRSEND 0x8 - -struct sb_uart_state { - unsigned int close_delay; /* msec */ - unsigned int closing_wait; /* msec */ - - - int count; - int pm_state; - struct sb_uart_info *info; - struct sb_uart_port *port; - - struct mutex mutex; -}; - -typedef unsigned int uif_t; - -struct sb_uart_info { - struct tty_struct *tty; - struct circ_buf xmit; - uif_t flags; - - int blocked_open; - - struct tasklet_struct tlet; - - wait_queue_head_t open_wait; - wait_queue_head_t delta_msr_wait; -}; - - -struct module; -struct tty_driver; - -struct uart_driver { - struct module *owner; - const char *driver_name; - const char *dev_name; - int major; - int minor; - int nr; - struct console *cons; - - struct sb_uart_state *state; - struct tty_driver *tty_driver; -}; - -void sb_uart_write_wakeup(struct sb_uart_port *port) -{ - struct sb_uart_info *info = port->info; - tasklet_schedule(&info->tlet); -} - -void sb_uart_update_timeout(struct sb_uart_port *port, unsigned int cflag, - unsigned int baud) -{ - unsigned int bits; - - switch (cflag & CSIZE) - { - case CS5: - bits = 7; - break; - - case CS6: - bits = 8; - break; - - case CS7: - bits = 9; - break; - - default: - bits = 10; - break; - } - - if (cflag & CSTOPB) - { - bits++; - } - - if (cflag & PARENB) - { - bits++; - } - - bits = bits * port->fifosize; - - port->timeout = (HZ * bits) / baud + HZ/50; -} -unsigned int sb_uart_get_baud_rate(struct sb_uart_port *port, struct MP_TERMIOS *termios, - struct MP_TERMIOS *old, unsigned int min, - unsigned int max) -{ - unsigned int try, baud, altbaud = 38400; - upf_t flags = port->flags & UPF_SPD_MASK; - - if (flags == UPF_SPD_HI) - altbaud = 57600; - if (flags == UPF_SPD_VHI) - altbaud = 115200; - if (flags == UPF_SPD_SHI) - altbaud = 230400; - if (flags == UPF_SPD_WARP) - altbaud = 460800; - - for (try = 0; try < 2; try++) { - - switch (termios->c_cflag & (CBAUD | CBAUDEX)) - { - case B921600 : baud = 921600; break; - case B460800 : baud = 460800; break; - case B230400 : baud = 230400; break; - case B115200 : baud = 115200; break; - case B57600 : baud = 57600; break; - case B38400 : baud = 38400; break; - case B19200 : baud = 19200; break; - case B9600 : baud = 9600; break; - case B4800 : baud = 4800; break; - case B2400 : baud = 2400; break; - case B1800 : baud = 1800; break; - case B1200 : baud = 1200; break; - case B600 : baud = 600; break; - case B300 : baud = 300; break; - case B200 : baud = 200; break; - case B150 : baud = 150; break; - case B134 : baud = 134; break; - case B110 : baud = 110; break; - case B75 : baud = 75; break; - case B50 : baud = 50; break; - default : baud = 9600; break; - } - - if (baud == 38400) - baud = altbaud; - - if (baud == 0) - baud = 9600; - - if (baud >= min && baud <= max) - return baud; - - termios->c_cflag &= ~CBAUD; - if (old) { - termios->c_cflag |= old->c_cflag & CBAUD; - old = NULL; - continue; - } - - termios->c_cflag |= B9600; - } - - return 0; -} -unsigned int sb_uart_get_divisor(struct sb_uart_port *port, unsigned int baud) -{ - unsigned int quot; - - if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST) - quot = port->custom_divisor; - else - quot = (port->uartclk + (8 * baud)) / (16 * baud); - - return quot; -} - - - -static inline int sb_uart_handle_break(struct sb_uart_port *port) -{ - struct sb_uart_info *info = port->info; - - if (port->flags & UPF_SAK) - do_SAK(info->tty); - return 0; -} - -static inline void sb_uart_handle_dcd_change(struct sb_uart_port *port, unsigned int status) -{ - struct sb_uart_info *info = port->info; - - port->icount.dcd++; - - if (info->flags & UIF_CHECK_CD) { - if (status) - wake_up_interruptible(&info->open_wait); - else if (info->tty) - tty_hangup(info->tty); - } -} - -static inline void sb_uart_handle_cts_change(struct sb_uart_port *port, unsigned int status) -{ - struct sb_uart_info *info = port->info; - struct tty_struct *tty = info->tty; - - port->icount.cts++; - - if (info->flags & UIF_CTS_FLOW) { - if (tty->hw_stopped) { - if (status) { - tty->hw_stopped = 0; - port->ops->start_tx(port); - sb_uart_write_wakeup(port); - } - } else { - if (!status) { - tty->hw_stopped = 1; - port->ops->stop_tx(port); - } - } - } -} - - - diff --git a/drivers/staging/sep/sep_crypto.c b/drivers/staging/sep/sep_crypto.c index 7fc267550c6..965485f71fe 100644 --- a/drivers/staging/sep/sep_crypto.c +++ b/drivers/staging/sep/sep_crypto.c @@ -112,7 +112,7 @@ static void sep_do_callback(struct work_struct *work) * on what operation is to be done */ static int sep_submit_work(struct workqueue_struct *work_queue, - void(*funct)(void *), + void (*funct)(void *), void *data) { struct sep_work_struct *sep_work; diff --git a/drivers/staging/sep/sep_main.c b/drivers/staging/sep/sep_main.c index 122614c4092..cbfc0cffb1d 100644 --- a/drivers/staging/sep/sep_main.c +++ b/drivers/staging/sep/sep_main.c @@ -1266,9 +1266,8 @@ static int sep_lock_user_pages(struct sep_device *sep, /* Check the number of pages locked - if not all then exit with error */ if (result != num_pages) { dev_warn(&sep->pdev->dev, - "[PID%d] not all pages locked by get_user_pages, " - "result 0x%X, num_pages 0x%X\n", - current->pid, result, num_pages); + "[PID%d] not all pages locked by get_user_pages, result 0x%X, num_pages 0x%X\n", + current->pid, result, num_pages); error = -ENOMEM; goto end_function_with_error3; } @@ -1293,9 +1292,9 @@ static int sep_lock_user_pages(struct sep_device *sep, lli_array[count].block_size = PAGE_SIZE; dev_dbg(&sep->pdev->dev, - "[PID%d] lli_array[%x].bus_address is %08lx, " - "lli_array[%x].block_size is (hex) %x\n", current->pid, - count, (unsigned long)lli_array[count].bus_address, + "[PID%d] lli_array[%x].bus_address is %08lx, lli_array[%x].block_size is (hex) %x\n", + current->pid, count, + (unsigned long)lli_array[count].bus_address, count, lli_array[count].block_size); } @@ -1314,8 +1313,7 @@ static int sep_lock_user_pages(struct sep_device *sep, "[PID%d] After check if page 0 has all data\n", current->pid); dev_dbg(&sep->pdev->dev, - "[PID%d] lli_array[0].bus_address is (hex) %08lx, " - "lli_array[0].block_size is (hex) %x\n", + "[PID%d] lli_array[0].bus_address is (hex) %08lx, lli_array[0].block_size is (hex) %x\n", current->pid, (unsigned long)lli_array[0].bus_address, lli_array[0].block_size); @@ -1332,8 +1330,7 @@ static int sep_lock_user_pages(struct sep_device *sep, "[PID%d] After last page size adjustment\n", current->pid); dev_dbg(&sep->pdev->dev, - "[PID%d] lli_array[%x].bus_address is (hex) %08lx, " - "lli_array[%x].block_size is (hex) %x\n", + "[PID%d] lli_array[%x].bus_address is (hex) %08lx, lli_array[%x].block_size is (hex) %x\n", current->pid, num_pages - 1, (unsigned long)lli_array[num_pages - 1].bus_address, @@ -1449,8 +1446,7 @@ static int sep_lli_table_secure_dma(struct sep_device *sep, start_page += PAGE_SIZE; dev_dbg(&sep->pdev->dev, - "[PID%d] lli_array[%x].bus_address is %08lx, " - "lli_array[%x].block_size is (hex) %x\n", + "[PID%d] lli_array[%x].bus_address is %08lx, lli_array[%x].block_size is (hex) %x\n", current->pid, count, (unsigned long)lli_array[count].bus_address, count, lli_array[count].block_size); @@ -1469,8 +1465,7 @@ static int sep_lli_table_secure_dma(struct sep_device *sep, dev_dbg(&sep->pdev->dev, "[PID%d] After check if page 0 has all data\n" - "lli_array[0].bus_address is (hex) %08lx, " - "lli_array[0].block_size is (hex) %x\n", + "lli_array[0].bus_address is (hex) %08lx, lli_array[0].block_size is (hex) %x\n", current->pid, (unsigned long)lli_array[0].bus_address, lli_array[0].block_size); @@ -1484,8 +1479,7 @@ static int sep_lli_table_secure_dma(struct sep_device *sep, dev_dbg(&sep->pdev->dev, "[PID%d] After last page size adjustment\n" - "lli_array[%x].bus_address is (hex) %08lx, " - "lli_array[%x].block_size is (hex) %x\n", + "lli_array[%x].bus_address is (hex) %08lx, lli_array[%x].block_size is (hex) %x\n", current->pid, num_pages - 1, (unsigned long)lli_array[num_pages - 1].bus_address, num_pages - 1, @@ -1745,9 +1739,8 @@ static void sep_debug_print_lli_tables(struct sep_device *sep, while ((unsigned long) lli_table_ptr->bus_address != 0xffffffff) { dev_dbg(&sep->pdev->dev, - "[PID%d] lli table %08lx, " - "table_data_size is (hex) %lx\n", - current->pid, table_count, table_data_size); + "[PID%d] lli table %08lx, table_data_size is (hex) %lx\n", + current->pid, table_count, table_data_size); dev_dbg(&sep->pdev->dev, "[PID%d] num_table_entries is (hex) %lx\n", current->pid, num_table_entries); @@ -1762,8 +1755,8 @@ static void sep_debug_print_lli_tables(struct sep_device *sep, (unsigned long) lli_table_ptr); dev_dbg(&sep->pdev->dev, - "[PID%d] phys address is %08lx " - "block size is (hex) %x\n", current->pid, + "[PID%d] phys address is %08lx block size is (hex) %x\n", + current->pid, (unsigned long)lli_table_ptr->bus_address, lli_table_ptr->block_size); } @@ -1772,14 +1765,12 @@ static void sep_debug_print_lli_tables(struct sep_device *sep, lli_table_ptr--; dev_dbg(&sep->pdev->dev, - "[PID%d] phys lli_table_ptr->block_size " - "is (hex) %x\n", + "[PID%d] phys lli_table_ptr->block_size is (hex) %x\n", current->pid, lli_table_ptr->block_size); dev_dbg(&sep->pdev->dev, - "[PID%d] phys lli_table_ptr->physical_address " - "is %08lx\n", + "[PID%d] phys lli_table_ptr->physical_address is %08lx\n", current->pid, (unsigned long)lli_table_ptr->bus_address); @@ -1788,13 +1779,11 @@ static void sep_debug_print_lli_tables(struct sep_device *sep, num_table_entries = (lli_table_ptr->block_size >> 24) & 0xff; dev_dbg(&sep->pdev->dev, - "[PID%d] phys table_data_size is " - "(hex) %lx num_table_entries is" - " %lx bus_address is%lx\n", - current->pid, - table_data_size, - num_table_entries, - (unsigned long)lli_table_ptr->bus_address); + "[PID%d] phys table_data_size is (hex) %lx num_table_entries is %lx bus_address is%lx\n", + current->pid, + table_data_size, + num_table_entries, + (unsigned long)lli_table_ptr->bus_address); if ((unsigned long)lli_table_ptr->bus_address != 0xffffffff) lli_table_ptr = (struct sep_lli_entry *) @@ -2244,14 +2233,12 @@ static int sep_construct_dma_tables_from_lli( table_data_size = out_table_data_size; dev_dbg(&sep->pdev->dev, - "[PID%d] construct tables from lli" - " in_table_data_size is (hex) %x\n", current->pid, - in_table_data_size); + "[PID%d] construct tables from lli in_table_data_size is (hex) %x\n", + current->pid, in_table_data_size); dev_dbg(&sep->pdev->dev, - "[PID%d] construct tables from lli" - "out_table_data_size is (hex) %x\n", current->pid, - out_table_data_size); + "[PID%d] construct tables from lli out_table_data_size is (hex) %x\n", + current->pid, out_table_data_size); /* Construct input lli table */ sep_build_lli_table(sep, &lli_in_array[current_in_entry], @@ -2316,8 +2303,7 @@ static int sep_construct_dma_tables_from_lli( info_in_entry_ptr->block_size); dev_dbg(&sep->pdev->dev, - "[PID%d] output lli_table_out_ptr:" - "%08lx %08x\n", + "[PID%d] output lli_table_out_ptr: %08lx %08x\n", current->pid, (unsigned long)info_out_entry_ptr->bus_address, info_out_entry_ptr->block_size); @@ -2446,8 +2432,8 @@ static int sep_prepare_input_output_dma_table(struct sep_device *sep, dma_ctx); if (error) { dev_warn(&sep->pdev->dev, - "[PID%d] sep_lock_kernel_pages for input " - "virtual buffer failed\n", current->pid); + "[PID%d] sep_lock_kernel_pages for input virtual buffer failed\n", + current->pid); goto end_function; } @@ -2460,8 +2446,8 @@ static int sep_prepare_input_output_dma_table(struct sep_device *sep, if (error) { dev_warn(&sep->pdev->dev, - "[PID%d] sep_lock_kernel_pages for output " - "virtual buffer failed\n", current->pid); + "[PID%d] sep_lock_kernel_pages for output virtual buffer failed\n", + current->pid); goto end_function_free_lli_in; } @@ -2476,8 +2462,8 @@ static int sep_prepare_input_output_dma_table(struct sep_device *sep, dma_ctx); if (error) { dev_warn(&sep->pdev->dev, - "[PID%d] sep_lock_user_pages for input " - "virtual buffer failed\n", current->pid); + "[PID%d] sep_lock_user_pages for input virtual buffer failed\n", + current->pid); goto end_function; } @@ -2491,8 +2477,7 @@ static int sep_prepare_input_output_dma_table(struct sep_device *sep, SEP_DRIVER_OUT_FLAG, dma_ctx); if (error) { dev_warn(&sep->pdev->dev, - "[PID%d] secure dma table setup " - " for output virtual buffer failed\n", + "[PID%d] secure dma table setup for output virtual buffer failed\n", current->pid); goto end_function_free_lli_in; @@ -2512,8 +2497,7 @@ static int sep_prepare_input_output_dma_table(struct sep_device *sep, if (error) { dev_warn(&sep->pdev->dev, - "[PID%d] sep_lock_user_pages" - " for output virtual buffer failed\n", + "[PID%d] sep_lock_user_pages for output virtual buffer failed\n", current->pid); goto end_function_free_lli_in; @@ -2826,8 +2810,7 @@ int sep_prepare_input_output_dma_table_in_dcb(struct sep_device *sep, if (error) { dev_warn(&sep->pdev->dev, - "prepare DMA table call failed " - "from prepare DCB call\n"); + "prepare DMA table call failed from prepare DCB call\n"); goto end_function_error; } @@ -2889,7 +2872,8 @@ static int sep_free_dma_tables_and_dcb(struct sep_device *sep, bool isapplet, * Go over each DCB and see if * tail pointer must be updated */ - for (i = 0; i < (*dma_ctx)->nr_dcb_creat; i++, dcb_table_ptr++) { + for (i = 0; i < (*dma_ctx)->nr_dcb_creat; + i++, dcb_table_ptr++) { if (dcb_table_ptr->out_vr_tail_pt) { pt_hold = (unsigned long)dcb_table_ptr-> out_vr_tail_pt; @@ -3762,8 +3746,7 @@ static inline ssize_t sep_fastcall_args_get(struct sep_device *sep, if (actual_count != count_user) { dev_warn(&sep->pdev->dev, - "[PID%d] inconsistent message " - "sizes 0x%08zX vs 0x%08zX\n", + "[PID%d] inconsistent message sizes 0x%08zX vs 0x%08zX\n", current->pid, actual_count, count_user); error = -EMSGSIZE; goto end_function; diff --git a/drivers/staging/slicoss/slic.h b/drivers/staging/slicoss/slic.h index 4c7822bd535..702902cdb46 100644 --- a/drivers/staging/slicoss/slic.h +++ b/drivers/staging/slicoss/slic.h @@ -464,9 +464,12 @@ struct adapter { /* * SLIC Handles */ - struct slic_handle slic_handles[SLIC_CMDQ_MAXCMDS+1]; /* Object handles*/ - struct slic_handle *pfree_slic_handles; /* Free object handles*/ - struct slic_spinlock handle_lock; /* Object handle list lock*/ + /* Object handles*/ + struct slic_handle slic_handles[SLIC_CMDQ_MAXCMDS+1]; + /* Free object handles*/ + struct slic_handle *pfree_slic_handles; + /* Object handle list lock*/ + struct slic_spinlock handle_lock; ushort slic_handle_ix; u32 xmitq_full; diff --git a/drivers/staging/slicoss/slicoss.c b/drivers/staging/slicoss/slicoss.c index e0de4979e1c..758c4efea0d 100644 --- a/drivers/staging/slicoss/slicoss.c +++ b/drivers/staging/slicoss/slicoss.c @@ -1830,7 +1830,7 @@ static int slic_debug_card_show(struct seq_file *seq, void *v) #endif seq_printf(seq, "driver_version : %s\n", slic_proc_version); - seq_puts(seq, "Microcode versions: \n"); + seq_puts(seq, "Microcode versions:\n"); seq_printf(seq, " Gigabit (gb) : %s %s\n", MOJAVE_UCODE_VERS_STRING, MOJAVE_UCODE_VERS_DATE); seq_printf(seq, " Gigabit Receiver : %s %s\n", @@ -1917,16 +1917,14 @@ static int slic_debug_card_show(struct seq_file *seq, void *v) if (config->OEMFruFormat == VENDOR4_FRU_FORMAT) { seq_printf(seq, - "Serial # : " - "%c%c%c%c%c%c%c%c%c%c%c%c\n", + "Serial # : %c%c%c%c%c%c%c%c%c%c%c%c\n", fru[8], fru[9], fru[10], fru[11], fru[12], fru[13], fru[16], fru[17], fru[18], fru[19], fru[20], fru[21]); } else { seq_printf(seq, - "Serial # : " - "%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n", + "Serial # : %c%c%c%c%c%c%c%c%c%c%c%c%c%c\n", fru[8], fru[9], fru[10], fru[11], fru[12], fru[13], fru[14], fru[15], fru[16], @@ -1974,8 +1972,7 @@ static int slic_debug_card_show(struct seq_file *seq, void *v) { seq_puts(seq, "FRU Information:\n"); seq_printf(seq, - " Part # : " - "%c%c%c%c%c%c%c%c\n", + " Part # : %c%c%c%c%c%c%c%c\n", oemfru[0], oemfru[1], oemfru[2], oemfru[3], oemfru[4], oemfru[5], oemfru[6], oemfru[7]); @@ -2002,20 +1999,17 @@ static int slic_debug_card_show(struct seq_file *seq, void *v) { seq_puts(seq, "FRU Information:\n"); seq_printf(seq, - " FRU Number : " - "%c%c%c%c%c%c%c%c\n", + " FRU Number : %c%c%c%c%c%c%c%c\n", oemfru[0], oemfru[1], oemfru[2], oemfru[3], oemfru[4], oemfru[5], oemfru[6], oemfru[7]); seq_sprintf(seq, - " Part Number : " - "%c%c%c%c%c%c%c%c\n", + " Part Number : %c%c%c%c%c%c%c%c\n", oemfru[8], oemfru[9], oemfru[10], oemfru[11], oemfru[12], oemfru[13], oemfru[14], oemfru[15]); seq_printf(seq, - " EC Level : " - "%c%c%c%c%c%c%c%c\n", + " EC Level : %c%c%c%c%c%c%c%c\n", oemfru[16], oemfru[17], oemfru[18], oemfru[19], oemfru[20], oemfru[21], oemfru[22], oemfru[23]); @@ -2412,8 +2406,7 @@ static void slic_xmit_fail(struct adapter *adapter, switch (status) { case XMIT_FAIL_LINK_STATE: dev_err(&adapter->netdev->dev, - "reject xmit skb[%p: %x] linkstate[%s] " - "adapter[%s:%d] card[%s:%d]\n", + "reject xmit skb[%p: %x] linkstate[%s] adapter[%s:%d] card[%s:%d]\n", skb, skb->pkt_type, SLIC_LINKSTATE(adapter->linkstate), SLIC_ADAPTER_STATE(adapter->state), @@ -2428,8 +2421,7 @@ static void slic_xmit_fail(struct adapter *adapter, break; case XMIT_FAIL_HOSTCMD_FAIL: dev_err(&adapter->netdev->dev, - "xmit_start skb[%p] type[%x] No host commands " - "available\n", skb, skb->pkt_type); + "xmit_start skb[%p] type[%x] No host commands available\n", skb, skb->pkt_type); break; } } @@ -2642,8 +2634,7 @@ static void slic_interrupt_card_up(u32 isr, struct adapter *adapter, } } else if (isr & ISR_XDROP) { dev_err(&dev->dev, - "isr & ISR_ERR [%x] " - "ISR_XDROP \n", isr); + "isr & ISR_ERR [%x] ISR_XDROP\n", isr); } else { dev_err(&dev->dev, "isr & ISR_ERR [%x]\n", @@ -3269,8 +3260,7 @@ static int slic_card_init(struct sliccard *card, struct adapter *adapter) if (!peeprom) { dev_err(&adapter->pcidev->dev, - "eeprom read failed to get memory " - "bus %d slot %d\n", adapter->busnumber, + "eeprom read failed to get memory bus %d slot %d\n", adapter->busnumber, adapter->slotnumber); return -ENOMEM; } else { diff --git a/drivers/staging/sm7xxfb/Kconfig b/drivers/staging/sm7xxfb/Kconfig deleted file mode 100644 index e2922ae3a3e..00000000000 --- a/drivers/staging/sm7xxfb/Kconfig +++ /dev/null @@ -1,13 +0,0 @@ -config FB_SM7XX - tristate "Silicon Motion SM7XX framebuffer support" - depends on FB && PCI - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - Frame buffer driver for the Silicon Motion SM710, SM712, SM721 - and SM722 chips. - - This driver is also available as a module. The module will be - called sm7xxfb. If you want to compile it as a module, say M - here and read <file:Documentation/kbuild/modules.txt>. diff --git a/drivers/staging/sm7xxfb/Makefile b/drivers/staging/sm7xxfb/Makefile deleted file mode 100644 index 48f471cf9f3..00000000000 --- a/drivers/staging/sm7xxfb/Makefile +++ /dev/null @@ -1 +0,0 @@ -obj-$(CONFIG_FB_SM7XX) += sm7xxfb.o diff --git a/drivers/staging/sm7xxfb/TODO b/drivers/staging/sm7xxfb/TODO deleted file mode 100644 index 1fcead591c1..00000000000 --- a/drivers/staging/sm7xxfb/TODO +++ /dev/null @@ -1,9 +0,0 @@ -TODO: -- Dual head support -- 2D acceleration support -- use kernel coding style -- refine the code and remove unused code -- move it to drivers/video/sm7xxfb.c - -Please send any patches to Greg Kroah-Hartman <greg@kroah.com> and -Teddy Wang <teddy.wang@siliconmotion.com.cn>. diff --git a/drivers/staging/sm7xxfb/sm7xx.h b/drivers/staging/sm7xxfb/sm7xx.h deleted file mode 100644 index 85998615b80..00000000000 --- a/drivers/staging/sm7xxfb/sm7xx.h +++ /dev/null @@ -1,779 +0,0 @@ -/* - * Silicon Motion SM712 frame buffer device - * - * Copyright (C) 2006 Silicon Motion Technology Corp. - * Authors: Ge Wang, gewang@siliconmotion.com - * Boyod boyod.yang@siliconmotion.com.cn - * - * Copyright (C) 2009 Lemote, Inc. - * Author: Wu Zhangjin, wuzhangjin@gmail.com - * - * 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. - */ - -#define NR_PALETTE 256 - -#define FB_ACCEL_SMI_LYNX 88 - -#define SCREEN_X_RES 1024 -#define SCREEN_Y_RES 600 -#define SCREEN_BPP 16 - -/*Assume SM712 graphics chip has 4MB VRAM */ -#define SM712_VIDEOMEMORYSIZE 0x00400000 -/*Assume SM722 graphics chip has 8MB VRAM */ -#define SM722_VIDEOMEMORYSIZE 0x00800000 - -#define dac_reg (0x3c8) -#define dac_val (0x3c9) - -extern void __iomem *smtc_RegBaseAddress; -#define smtc_mmiowb(dat, reg) writeb(dat, smtc_RegBaseAddress + reg) -#define smtc_mmioww(dat, reg) writew(dat, smtc_RegBaseAddress + reg) -#define smtc_mmiowl(dat, reg) writel(dat, smtc_RegBaseAddress + reg) - -#define smtc_mmiorb(reg) readb(smtc_RegBaseAddress + reg) -#define smtc_mmiorw(reg) readw(smtc_RegBaseAddress + reg) -#define smtc_mmiorl(reg) readl(smtc_RegBaseAddress + reg) - -#define SIZE_SR00_SR04 (0x04 - 0x00 + 1) -#define SIZE_SR10_SR24 (0x24 - 0x10 + 1) -#define SIZE_SR30_SR75 (0x75 - 0x30 + 1) -#define SIZE_SR80_SR93 (0x93 - 0x80 + 1) -#define SIZE_SRA0_SRAF (0xAF - 0xA0 + 1) -#define SIZE_GR00_GR08 (0x08 - 0x00 + 1) -#define SIZE_AR00_AR14 (0x14 - 0x00 + 1) -#define SIZE_CR00_CR18 (0x18 - 0x00 + 1) -#define SIZE_CR30_CR4D (0x4D - 0x30 + 1) -#define SIZE_CR90_CRA7 (0xA7 - 0x90 + 1) -#define SIZE_VPR (0x6C + 1) -#define SIZE_DPR (0x44 + 1) - -static inline void smtc_crtcw(int reg, int val) -{ - smtc_mmiowb(reg, 0x3d4); - smtc_mmiowb(val, 0x3d5); -} - -static inline unsigned int smtc_crtcr(int reg) -{ - smtc_mmiowb(reg, 0x3d4); - return smtc_mmiorb(0x3d5); -} - -static inline void smtc_grphw(int reg, int val) -{ - smtc_mmiowb(reg, 0x3ce); - smtc_mmiowb(val, 0x3cf); -} - -static inline unsigned int smtc_grphr(int reg) -{ - smtc_mmiowb(reg, 0x3ce); - return smtc_mmiorb(0x3cf); -} - -static inline void smtc_attrw(int reg, int val) -{ - smtc_mmiorb(0x3da); - smtc_mmiowb(reg, 0x3c0); - smtc_mmiorb(0x3c1); - smtc_mmiowb(val, 0x3c0); -} - -static inline void smtc_seqw(int reg, int val) -{ - smtc_mmiowb(reg, 0x3c4); - smtc_mmiowb(val, 0x3c5); -} - -static inline unsigned int smtc_seqr(int reg) -{ - smtc_mmiowb(reg, 0x3c4); - return smtc_mmiorb(0x3c5); -} - -/* The next structure holds all information relevant for a specific video mode. - */ - -struct ModeInit { - int mmSizeX; - int mmSizeY; - int bpp; - int hz; - unsigned char Init_MISC; - unsigned char Init_SR00_SR04[SIZE_SR00_SR04]; - unsigned char Init_SR10_SR24[SIZE_SR10_SR24]; - unsigned char Init_SR30_SR75[SIZE_SR30_SR75]; - unsigned char Init_SR80_SR93[SIZE_SR80_SR93]; - unsigned char Init_SRA0_SRAF[SIZE_SRA0_SRAF]; - unsigned char Init_GR00_GR08[SIZE_GR00_GR08]; - unsigned char Init_AR00_AR14[SIZE_AR00_AR14]; - unsigned char Init_CR00_CR18[SIZE_CR00_CR18]; - unsigned char Init_CR30_CR4D[SIZE_CR30_CR4D]; - unsigned char Init_CR90_CRA7[SIZE_CR90_CRA7]; -}; - -/********************************************************************** - SM712 Mode table. - **********************************************************************/ -struct ModeInit VGAMode[] = { - { - /* mode#0: 640 x 480 16Bpp 60Hz */ - 640, 480, 16, 60, - /* Init_MISC */ - 0xE3, - { /* Init_SR0_SR4 */ - 0x03, 0x01, 0x0F, 0x00, 0x0E, - }, - { /* Init_SR10_SR24 */ - 0xFF, 0xBE, 0xEF, 0xFF, 0x00, 0x0E, 0x17, 0x2C, - 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xC4, 0x30, 0x02, 0x01, 0x01, - }, - { /* Init_SR30_SR75 */ - 0x32, 0x03, 0xA0, 0x09, 0xC0, 0x32, 0x32, 0x32, - 0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x03, 0xFF, - 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, - 0x20, 0x0C, 0x44, 0x20, 0x00, 0x32, 0x32, 0x32, - 0x04, 0x24, 0x63, 0x4F, 0x52, 0x0B, 0xDF, 0xEA, - 0x04, 0x50, 0x19, 0x32, 0x32, 0x00, 0x00, 0x32, - 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, - 0x50, 0x03, 0x74, 0x14, 0x07, 0x82, 0x07, 0x04, - 0x00, 0x45, 0x30, 0x30, 0x40, 0x30, - }, - { /* Init_SR80_SR93 */ - 0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x32, - 0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x32, 0x32, - 0x00, 0x00, 0x00, 0x00, - }, - { /* Init_SRA0_SRAF */ - 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED, - 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xFF, 0xDF, - }, - { /* Init_GR00_GR08 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, - 0xFF, - }, - { /* Init_AR00_AR14 */ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, - 0x41, 0x00, 0x0F, 0x00, 0x00, - }, - { /* Init_CR00_CR18 */ - 0x5F, 0x4F, 0x4F, 0x00, 0x53, 0x1F, 0x0B, 0x3E, - 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xEA, 0x0C, 0xDF, 0x50, 0x40, 0xDF, 0x00, 0xE3, - 0xFF, - }, - { /* Init_CR30_CR4D */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x03, 0x20, - 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xFF, 0xFD, - 0x5F, 0x4F, 0x00, 0x54, 0x00, 0x0B, 0xDF, 0x00, - 0xEA, 0x0C, 0x2E, 0x00, 0x4F, 0xDF, - }, - { /* Init_CR90_CRA7 */ - 0x56, 0xDD, 0x5E, 0xEA, 0x87, 0x44, 0x8F, 0x55, - 0x0A, 0x8F, 0x55, 0x0A, 0x00, 0x00, 0x18, 0x00, - 0x11, 0x10, 0x0B, 0x0A, 0x0A, 0x0A, 0x0A, 0x00, - }, - }, - { - /* mode#1: 640 x 480 24Bpp 60Hz */ - 640, 480, 24, 60, - /* Init_MISC */ - 0xE3, - { /* Init_SR0_SR4 */ - 0x03, 0x01, 0x0F, 0x00, 0x0E, - }, - { /* Init_SR10_SR24 */ - 0xFF, 0xBE, 0xEF, 0xFF, 0x00, 0x0E, 0x17, 0x2C, - 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xC4, 0x30, 0x02, 0x01, 0x01, - }, - { /* Init_SR30_SR75 */ - 0x32, 0x03, 0xA0, 0x09, 0xC0, 0x32, 0x32, 0x32, - 0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x03, 0xFF, - 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, - 0x20, 0x0C, 0x44, 0x20, 0x00, 0x32, 0x32, 0x32, - 0x04, 0x24, 0x63, 0x4F, 0x52, 0x0B, 0xDF, 0xEA, - 0x04, 0x50, 0x19, 0x32, 0x32, 0x00, 0x00, 0x32, - 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, - 0x50, 0x03, 0x74, 0x14, 0x07, 0x82, 0x07, 0x04, - 0x00, 0x45, 0x30, 0x30, 0x40, 0x30, - }, - { /* Init_SR80_SR93 */ - 0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x32, - 0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x32, 0x32, - 0x00, 0x00, 0x00, 0x00, - }, - { /* Init_SRA0_SRAF */ - 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED, - 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xFF, 0xDF, - }, - { /* Init_GR00_GR08 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, - 0xFF, - }, - { /* Init_AR00_AR14 */ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, - 0x41, 0x00, 0x0F, 0x00, 0x00, - }, - { /* Init_CR00_CR18 */ - 0x5F, 0x4F, 0x4F, 0x00, 0x53, 0x1F, 0x0B, 0x3E, - 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xEA, 0x0C, 0xDF, 0x50, 0x40, 0xDF, 0x00, 0xE3, - 0xFF, - }, - { /* Init_CR30_CR4D */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x03, 0x20, - 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xFF, 0xFD, - 0x5F, 0x4F, 0x00, 0x54, 0x00, 0x0B, 0xDF, 0x00, - 0xEA, 0x0C, 0x2E, 0x00, 0x4F, 0xDF, - }, - { /* Init_CR90_CRA7 */ - 0x56, 0xDD, 0x5E, 0xEA, 0x87, 0x44, 0x8F, 0x55, - 0x0A, 0x8F, 0x55, 0x0A, 0x00, 0x00, 0x18, 0x00, - 0x11, 0x10, 0x0B, 0x0A, 0x0A, 0x0A, 0x0A, 0x00, - }, - }, - { - /* mode#0: 640 x 480 32Bpp 60Hz */ - 640, 480, 32, 60, - /* Init_MISC */ - 0xE3, - { /* Init_SR0_SR4 */ - 0x03, 0x01, 0x0F, 0x00, 0x0E, - }, - { /* Init_SR10_SR24 */ - 0xFF, 0xBE, 0xEF, 0xFF, 0x00, 0x0E, 0x17, 0x2C, - 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xC4, 0x30, 0x02, 0x01, 0x01, - }, - { /* Init_SR30_SR75 */ - 0x32, 0x03, 0xA0, 0x09, 0xC0, 0x32, 0x32, 0x32, - 0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x03, 0xFF, - 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, - 0x20, 0x0C, 0x44, 0x20, 0x00, 0x32, 0x32, 0x32, - 0x04, 0x24, 0x63, 0x4F, 0x52, 0x0B, 0xDF, 0xEA, - 0x04, 0x50, 0x19, 0x32, 0x32, 0x00, 0x00, 0x32, - 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, - 0x50, 0x03, 0x74, 0x14, 0x07, 0x82, 0x07, 0x04, - 0x00, 0x45, 0x30, 0x30, 0x40, 0x30, - }, - { /* Init_SR80_SR93 */ - 0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x32, - 0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x32, 0x32, - 0x00, 0x00, 0x00, 0x00, - }, - { /* Init_SRA0_SRAF */ - 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED, - 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xFF, 0xDF, - }, - { /* Init_GR00_GR08 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, - 0xFF, - }, - { /* Init_AR00_AR14 */ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, - 0x41, 0x00, 0x0F, 0x00, 0x00, - }, - { /* Init_CR00_CR18 */ - 0x5F, 0x4F, 0x4F, 0x00, 0x53, 0x1F, 0x0B, 0x3E, - 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xEA, 0x0C, 0xDF, 0x50, 0x40, 0xDF, 0x00, 0xE3, - 0xFF, - }, - { /* Init_CR30_CR4D */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x03, 0x20, - 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xFF, 0xFD, - 0x5F, 0x4F, 0x00, 0x54, 0x00, 0x0B, 0xDF, 0x00, - 0xEA, 0x0C, 0x2E, 0x00, 0x4F, 0xDF, - }, - { /* Init_CR90_CRA7 */ - 0x56, 0xDD, 0x5E, 0xEA, 0x87, 0x44, 0x8F, 0x55, - 0x0A, 0x8F, 0x55, 0x0A, 0x00, 0x00, 0x18, 0x00, - 0x11, 0x10, 0x0B, 0x0A, 0x0A, 0x0A, 0x0A, 0x00, - }, - }, - - { /* mode#2: 800 x 600 16Bpp 60Hz */ - 800, 600, 16, 60, - /* Init_MISC */ - 0x2B, - { /* Init_SR0_SR4 */ - 0x03, 0x01, 0x0F, 0x03, 0x0E, - }, - { /* Init_SR10_SR24 */ - 0xFF, 0xBE, 0xEE, 0xFF, 0x00, 0x0E, 0x17, 0x2C, - 0x99, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xC4, 0x30, 0x02, 0x01, 0x01, - }, - { /* Init_SR30_SR75 */ - 0x34, 0x03, 0x20, 0x09, 0xC0, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x00, 0x00, 0x03, 0xFF, - 0x00, 0xFC, 0x00, 0x00, 0x20, 0x38, 0x00, 0xFC, - 0x20, 0x0C, 0x44, 0x20, 0x00, 0x24, 0x24, 0x24, - 0x04, 0x48, 0x83, 0x63, 0x68, 0x72, 0x57, 0x58, - 0x04, 0x55, 0x59, 0x24, 0x24, 0x00, 0x00, 0x24, - 0x01, 0x80, 0x7A, 0x1A, 0x1A, 0x00, 0x00, 0x00, - 0x50, 0x03, 0x74, 0x14, 0x1C, 0x85, 0x35, 0x13, - 0x02, 0x45, 0x30, 0x35, 0x40, 0x20, - }, - { /* Init_SR80_SR93 */ - 0x00, 0x00, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x24, - 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x24, 0x24, - 0x00, 0x00, 0x00, 0x00, - }, - { /* Init_SRA0_SRAF */ - 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED, - 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xBF, 0xDF, - }, - { /* Init_GR00_GR08 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, - 0xFF, - }, - { /* Init_AR00_AR14 */ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, - 0x41, 0x00, 0x0F, 0x00, 0x00, - }, - { /* Init_CR00_CR18 */ - 0x7F, 0x63, 0x63, 0x00, 0x68, 0x18, 0x72, 0xF0, - 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x58, 0x0C, 0x57, 0x64, 0x40, 0x57, 0x00, 0xE3, - 0xFF, - }, - { /* Init_CR30_CR4D */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x03, 0x20, - 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xBF, 0xFD, - 0x7F, 0x63, 0x00, 0x69, 0x18, 0x72, 0x57, 0x00, - 0x58, 0x0C, 0xE0, 0x20, 0x63, 0x57, - }, - { /* Init_CR90_CRA7 */ - 0x56, 0x4B, 0x5E, 0x55, 0x86, 0x9D, 0x8E, 0xAA, - 0xDB, 0x2A, 0xDF, 0x33, 0x00, 0x00, 0x18, 0x00, - 0x20, 0x1F, 0x1A, 0x19, 0x0F, 0x0F, 0x0F, 0x00, - }, - }, - { /* mode#3: 800 x 600 24Bpp 60Hz */ - 800, 600, 24, 60, - 0x2B, - { /* Init_SR0_SR4 */ - 0x03, 0x01, 0x0F, 0x03, 0x0E, - }, - { /* Init_SR10_SR24 */ - 0xFF, 0xBE, 0xEE, 0xFF, 0x00, 0x0E, 0x17, 0x2C, - 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xC4, 0x30, 0x02, 0x01, 0x01, - }, - { /* Init_SR30_SR75 */ - 0x36, 0x03, 0x20, 0x09, 0xC0, 0x36, 0x36, 0x36, - 0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x03, 0xFF, - 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, - 0x20, 0x0C, 0x44, 0x20, 0x00, 0x36, 0x36, 0x36, - 0x04, 0x48, 0x83, 0x63, 0x68, 0x72, 0x57, 0x58, - 0x04, 0x55, 0x59, 0x36, 0x36, 0x00, 0x00, 0x36, - 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, - 0x50, 0x03, 0x74, 0x14, 0x1C, 0x85, 0x35, 0x13, - 0x02, 0x45, 0x30, 0x30, 0x40, 0x20, - }, - { /* Init_SR80_SR93 */ - 0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x36, - 0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x36, 0x36, - 0x00, 0x00, 0x00, 0x00, - }, - { /* Init_SRA0_SRAF */ - 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED, - 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xBF, 0xDF, - }, - { /* Init_GR00_GR08 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, - 0xFF, - }, - { /* Init_AR00_AR14 */ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, - 0x41, 0x00, 0x0F, 0x00, 0x00, - }, - { /* Init_CR00_CR18 */ - 0x7F, 0x63, 0x63, 0x00, 0x68, 0x18, 0x72, 0xF0, - 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x58, 0x0C, 0x57, 0x64, 0x40, 0x57, 0x00, 0xE3, - 0xFF, - }, - { /* Init_CR30_CR4D */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x03, 0x20, - 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xBF, 0xFD, - 0x7F, 0x63, 0x00, 0x69, 0x18, 0x72, 0x57, 0x00, - 0x58, 0x0C, 0xE0, 0x20, 0x63, 0x57, - }, - { /* Init_CR90_CRA7 */ - 0x56, 0x4B, 0x5E, 0x55, 0x86, 0x9D, 0x8E, 0xAA, - 0xDB, 0x2A, 0xDF, 0x33, 0x00, 0x00, 0x18, 0x00, - 0x20, 0x1F, 0x1A, 0x19, 0x0F, 0x0F, 0x0F, 0x00, - }, - }, - { /* mode#7: 800 x 600 32Bpp 60Hz */ - 800, 600, 32, 60, - /* Init_MISC */ - 0x2B, - { /* Init_SR0_SR4 */ - 0x03, 0x01, 0x0F, 0x03, 0x0E, - }, - { /* Init_SR10_SR24 */ - 0xFF, 0xBE, 0xEE, 0xFF, 0x00, 0x0E, 0x17, 0x2C, - 0x99, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xC4, 0x30, 0x02, 0x01, 0x01, - }, - { /* Init_SR30_SR75 */ - 0x34, 0x03, 0x20, 0x09, 0xC0, 0x24, 0x24, 0x24, - 0x24, 0x24, 0x24, 0x24, 0x00, 0x00, 0x03, 0xFF, - 0x00, 0xFC, 0x00, 0x00, 0x20, 0x38, 0x00, 0xFC, - 0x20, 0x0C, 0x44, 0x20, 0x00, 0x24, 0x24, 0x24, - 0x04, 0x48, 0x83, 0x63, 0x68, 0x72, 0x57, 0x58, - 0x04, 0x55, 0x59, 0x24, 0x24, 0x00, 0x00, 0x24, - 0x01, 0x80, 0x7A, 0x1A, 0x1A, 0x00, 0x00, 0x00, - 0x50, 0x03, 0x74, 0x14, 0x1C, 0x85, 0x35, 0x13, - 0x02, 0x45, 0x30, 0x35, 0x40, 0x20, - }, - { /* Init_SR80_SR93 */ - 0x00, 0x00, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x24, - 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x24, 0x24, - 0x00, 0x00, 0x00, 0x00, - }, - { /* Init_SRA0_SRAF */ - 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED, - 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xBF, 0xDF, - }, - { /* Init_GR00_GR08 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, - 0xFF, - }, - { /* Init_AR00_AR14 */ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, - 0x41, 0x00, 0x0F, 0x00, 0x00, - }, - { /* Init_CR00_CR18 */ - 0x7F, 0x63, 0x63, 0x00, 0x68, 0x18, 0x72, 0xF0, - 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x58, 0x0C, 0x57, 0x64, 0x40, 0x57, 0x00, 0xE3, - 0xFF, - }, - { /* Init_CR30_CR4D */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x03, 0x20, - 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xBF, 0xFD, - 0x7F, 0x63, 0x00, 0x69, 0x18, 0x72, 0x57, 0x00, - 0x58, 0x0C, 0xE0, 0x20, 0x63, 0x57, - }, - { /* Init_CR90_CRA7 */ - 0x56, 0x4B, 0x5E, 0x55, 0x86, 0x9D, 0x8E, 0xAA, - 0xDB, 0x2A, 0xDF, 0x33, 0x00, 0x00, 0x18, 0x00, - 0x20, 0x1F, 0x1A, 0x19, 0x0F, 0x0F, 0x0F, 0x00, - }, - }, - /* We use 1024x768 table to light 1024x600 panel for lemote */ - { /* mode#4: 1024 x 600 16Bpp 60Hz */ - 1024, 600, 16, 60, - /* Init_MISC */ - 0xEB, - { /* Init_SR0_SR4 */ - 0x03, 0x01, 0x0F, 0x00, 0x0E, - }, - { /* Init_SR10_SR24 */ - 0xC8, 0x40, 0x14, 0x60, 0x00, 0x0A, 0x17, 0x20, - 0x51, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xC4, 0x30, 0x02, 0x00, 0x01, - }, - { /* Init_SR30_SR75 */ - 0x22, 0x03, 0x24, 0x09, 0xC0, 0x22, 0x22, 0x22, - 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x03, 0xFF, - 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, - 0x20, 0x0C, 0x44, 0x20, 0x00, 0x22, 0x22, 0x22, - 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03, - 0x00, 0x60, 0x59, 0x22, 0x22, 0x00, 0x00, 0x22, - 0x01, 0x80, 0x7A, 0x1A, 0x1A, 0x00, 0x00, 0x00, - 0x50, 0x03, 0x16, 0x02, 0x0D, 0x82, 0x09, 0x02, - 0x04, 0x45, 0x3F, 0x30, 0x40, 0x20, - }, - { /* Init_SR80_SR93 */ - 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A, - 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A, - 0x00, 0x00, 0x00, 0x00, - }, - { /* Init_SRA0_SRAF */ - 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED, - 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF, - }, - { /* Init_GR00_GR08 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, - 0xFF, - }, - { /* Init_AR00_AR14 */ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, - 0x41, 0x00, 0x0F, 0x00, 0x00, - }, - { /* Init_CR00_CR18 */ - 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5, - 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3, - 0xFF, - }, - { /* Init_CR30_CR4D */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20, - 0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF, - 0xA3, 0x7F, 0x00, 0x82, 0x0b, 0x6f, 0x57, 0x00, - 0x5c, 0x0f, 0xE0, 0xe0, 0x7F, 0x57, - }, - { /* Init_CR90_CRA7 */ - 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26, - 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03, - }, - }, - { /* mode#5: 1024 x 768 24Bpp 60Hz */ - 1024, 768, 24, 60, - /* Init_MISC */ - 0xEB, - { /* Init_SR0_SR4 */ - 0x03, 0x01, 0x0F, 0x03, 0x0E, - }, - { /* Init_SR10_SR24 */ - 0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C, - 0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xC4, 0x30, 0x02, 0x01, 0x01, - }, - { /* Init_SR30_SR75 */ - 0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A, - 0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF, - 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, - 0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A, - 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03, - 0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A, - 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, - 0x50, 0x03, 0x74, 0x14, 0x3B, 0x0D, 0x09, 0x02, - 0x04, 0x45, 0x30, 0x30, 0x40, 0x20, - }, - { /* Init_SR80_SR93 */ - 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A, - 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A, - 0x00, 0x00, 0x00, 0x00, - }, - { /* Init_SRA0_SRAF */ - 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED, - 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF, - }, - { /* Init_GR00_GR08 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, - 0xFF, - }, - { /* Init_AR00_AR14 */ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, - 0x41, 0x00, 0x0F, 0x00, 0x00, - }, - { /* Init_CR00_CR18 */ - 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5, - 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3, - 0xFF, - }, - { /* Init_CR30_CR4D */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20, - 0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF, - 0xA3, 0x7F, 0x00, 0x86, 0x15, 0x24, 0xFF, 0x00, - 0x01, 0x07, 0xE5, 0x20, 0x7F, 0xFF, - }, - { /* Init_CR90_CRA7 */ - 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26, - 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03, - }, - }, - { /* mode#4: 1024 x 768 32Bpp 60Hz */ - 1024, 768, 32, 60, - /* Init_MISC */ - 0xEB, - { /* Init_SR0_SR4 */ - 0x03, 0x01, 0x0F, 0x03, 0x0E, - }, - { /* Init_SR10_SR24 */ - 0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C, - 0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xC4, 0x32, 0x02, 0x01, 0x01, - }, - { /* Init_SR30_SR75 */ - 0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A, - 0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF, - 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, - 0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A, - 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03, - 0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A, - 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, - 0x50, 0x03, 0x74, 0x14, 0x3B, 0x0D, 0x09, 0x02, - 0x04, 0x45, 0x30, 0x30, 0x40, 0x20, - }, - { /* Init_SR80_SR93 */ - 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A, - 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A, - 0x00, 0x00, 0x00, 0x00, - }, - { /* Init_SRA0_SRAF */ - 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED, - 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF, - }, - { /* Init_GR00_GR08 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, - 0xFF, - }, - { /* Init_AR00_AR14 */ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, - 0x41, 0x00, 0x0F, 0x00, 0x00, - }, - { /* Init_CR00_CR18 */ - 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5, - 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3, - 0xFF, - }, - { /* Init_CR30_CR4D */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20, - 0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF, - 0xA3, 0x7F, 0x00, 0x86, 0x15, 0x24, 0xFF, 0x00, - 0x01, 0x07, 0xE5, 0x20, 0x7F, 0xFF, - }, - { /* Init_CR90_CRA7 */ - 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26, - 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03, - }, - }, - { /* mode#6: 320 x 240 16Bpp 60Hz */ - 320, 240, 16, 60, - /* Init_MISC */ - 0xEB, - { /* Init_SR0_SR4 */ - 0x03, 0x01, 0x0F, 0x03, 0x0E, - }, - { /* Init_SR10_SR24 */ - 0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C, - 0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xC4, 0x32, 0x02, 0x01, 0x01, - }, - { /* Init_SR30_SR75 */ - 0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A, - 0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF, - 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, - 0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A, - 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03, - 0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A, - 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, - 0x50, 0x03, 0x74, 0x14, 0x08, 0x43, 0x08, 0x43, - 0x04, 0x45, 0x30, 0x30, 0x40, 0x20, - }, - { /* Init_SR80_SR93 */ - 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A, - 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A, - 0x00, 0x00, 0x00, 0x00, - }, - { /* Init_SRA0_SRAF */ - 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED, - 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF, - }, - { /* Init_GR00_GR08 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, - 0xFF, - }, - { /* Init_AR00_AR14 */ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, - 0x41, 0x00, 0x0F, 0x00, 0x00, - }, - { /* Init_CR00_CR18 */ - 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5, - 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3, - 0xFF, - }, - { /* Init_CR30_CR4D */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20, - 0x00, 0x00, 0x30, 0x40, 0x00, 0xFF, 0xBF, 0xFF, - 0x2E, 0x27, 0x00, 0x2b, 0x0c, 0x0F, 0xEF, 0x00, - 0xFe, 0x0f, 0x01, 0xC0, 0x27, 0xEF, - }, - { /* Init_CR90_CRA7 */ - 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26, - 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03, - }, - }, - - { /* mode#8: 320 x 240 32Bpp 60Hz */ - 320, 240, 32, 60, - /* Init_MISC */ - 0xEB, - { /* Init_SR0_SR4 */ - 0x03, 0x01, 0x0F, 0x03, 0x0E, - }, - { /* Init_SR10_SR24 */ - 0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C, - 0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xC4, 0x32, 0x02, 0x01, 0x01, - }, - { /* Init_SR30_SR75 */ - 0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A, - 0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF, - 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, - 0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A, - 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03, - 0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A, - 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, - 0x50, 0x03, 0x74, 0x14, 0x08, 0x43, 0x08, 0x43, - 0x04, 0x45, 0x30, 0x30, 0x40, 0x20, - }, - { /* Init_SR80_SR93 */ - 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A, - 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A, - 0x00, 0x00, 0x00, 0x00, - }, - { /* Init_SRA0_SRAF */ - 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED, - 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF, - }, - { /* Init_GR00_GR08 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, - 0xFF, - }, - { /* Init_AR00_AR14 */ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, - 0x41, 0x00, 0x0F, 0x00, 0x00, - }, - { /* Init_CR00_CR18 */ - 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5, - 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3, - 0xFF, - }, - { /* Init_CR30_CR4D */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20, - 0x00, 0x00, 0x30, 0x40, 0x00, 0xFF, 0xBF, 0xFF, - 0x2E, 0x27, 0x00, 0x2b, 0x0c, 0x0F, 0xEF, 0x00, - 0xFe, 0x0f, 0x01, 0xC0, 0x27, 0xEF, - }, - { /* Init_CR90_CRA7 */ - 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26, - 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00, - 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03, - }, - }, -}; - -#define numVGAModes ARRAY_SIZE(VGAMode) diff --git a/drivers/staging/sm7xxfb/sm7xxfb.c b/drivers/staging/sm7xxfb/sm7xxfb.c deleted file mode 100644 index 6176d98744c..00000000000 --- a/drivers/staging/sm7xxfb/sm7xxfb.c +++ /dev/null @@ -1,1028 +0,0 @@ -/* - * Silicon Motion SM7XX frame buffer device - * - * Copyright (C) 2006 Silicon Motion Technology Corp. - * Authors: Ge Wang, gewang@siliconmotion.com - * Boyod boyod.yang@siliconmotion.com.cn - * - * Copyright (C) 2009 Lemote, Inc. - * Author: Wu Zhangjin, wuzhangjin@gmail.com - * - * Copyright (C) 2011 Igalia, S.L. - * Author: Javier M. Mellid <jmunhoz@igalia.com> - * - * 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. - * - * Framebuffer driver for Silicon Motion SM710, SM712, SM721 and SM722 chips - */ - -#include <linux/io.h> -#include <linux/fb.h> -#include <linux/pci.h> -#include <linux/init.h> -#include <linux/slab.h> -#include <linux/uaccess.h> -#include <linux/module.h> -#include <linux/console.h> -#include <linux/screen_info.h> - -#ifdef CONFIG_PM -#include <linux/pm.h> -#endif - -#include "sm7xx.h" - -/* -* Private structure -*/ -struct smtcfb_info { - struct pci_dev *pdev; - struct fb_info fb; - u16 chip_id; - u8 chip_rev_id; - - void __iomem *lfb; /* linear frame buffer */ - void __iomem *dp_regs; /* drawing processor control regs */ - void __iomem *vp_regs; /* video processor control regs */ - void __iomem *cp_regs; /* capture processor control regs */ - void __iomem *mmio; /* memory map IO port */ - - u_int width; - u_int height; - u_int hz; - - u32 colreg[17]; -}; - -void __iomem *smtc_RegBaseAddress; /* Memory Map IO starting address */ - -static struct fb_var_screeninfo smtcfb_var = { - .xres = 1024, - .yres = 600, - .xres_virtual = 1024, - .yres_virtual = 600, - .bits_per_pixel = 16, - .red = {16, 8, 0}, - .green = {8, 8, 0}, - .blue = {0, 8, 0}, - .activate = FB_ACTIVATE_NOW, - .height = -1, - .width = -1, - .vmode = FB_VMODE_NONINTERLACED, - .nonstd = 0, - .accel_flags = FB_ACCELF_TEXT, -}; - -static struct fb_fix_screeninfo smtcfb_fix = { - .id = "smXXXfb", - .type = FB_TYPE_PACKED_PIXELS, - .visual = FB_VISUAL_TRUECOLOR, - .line_length = 800 * 3, - .accel = FB_ACCEL_SMI_LYNX, - .type_aux = 0, - .xpanstep = 0, - .ypanstep = 0, - .ywrapstep = 0, -}; - -struct vesa_mode { - char index[6]; - u16 lfb_width; - u16 lfb_height; - u16 lfb_depth; -}; - -static struct vesa_mode vesa_mode_table[] = { - {"0x301", 640, 480, 8}, - {"0x303", 800, 600, 8}, - {"0x305", 1024, 768, 8}, - {"0x307", 1280, 1024, 8}, - - {"0x311", 640, 480, 16}, - {"0x314", 800, 600, 16}, - {"0x317", 1024, 768, 16}, - {"0x31A", 1280, 1024, 16}, - - {"0x312", 640, 480, 24}, - {"0x315", 800, 600, 24}, - {"0x318", 1024, 768, 24}, - {"0x31B", 1280, 1024, 24}, -}; - -struct screen_info smtc_scr_info; - -/* process command line options, get vga parameter */ -static int __init sm7xx_vga_setup(char *options) -{ - int i; - - if (!options || !*options) - return -EINVAL; - - smtc_scr_info.lfb_width = 0; - smtc_scr_info.lfb_height = 0; - smtc_scr_info.lfb_depth = 0; - - pr_debug("sm7xx_vga_setup = %s\n", options); - - for (i = 0; i < ARRAY_SIZE(vesa_mode_table); i++) { - if (strstr(options, vesa_mode_table[i].index)) { - smtc_scr_info.lfb_width = vesa_mode_table[i].lfb_width; - smtc_scr_info.lfb_height = - vesa_mode_table[i].lfb_height; - smtc_scr_info.lfb_depth = vesa_mode_table[i].lfb_depth; - return 0; - } - } - - return -1; -} -__setup("vga=", sm7xx_vga_setup); - -static void sm712_setpalette(int regno, unsigned red, unsigned green, - unsigned blue, struct fb_info *info) -{ - /* set bit 5:4 = 01 (write LCD RAM only) */ - smtc_seqw(0x66, (smtc_seqr(0x66) & 0xC3) | 0x10); - - smtc_mmiowb(regno, dac_reg); - smtc_mmiowb(red >> 10, dac_val); - smtc_mmiowb(green >> 10, dac_val); - smtc_mmiowb(blue >> 10, dac_val); -} - -/* chan_to_field - * - * convert a colour value into a field position - * - * from pxafb.c - */ - -static inline unsigned int chan_to_field(unsigned int chan, - struct fb_bitfield *bf) -{ - chan &= 0xffff; - chan >>= 16 - bf->length; - return chan << bf->offset; -} - -static int smtc_blank(int blank_mode, struct fb_info *info) -{ - /* clear DPMS setting */ - switch (blank_mode) { - case FB_BLANK_UNBLANK: - /* Screen On: HSync: On, VSync : On */ - smtc_seqw(0x01, (smtc_seqr(0x01) & (~0x20))); - smtc_seqw(0x6a, 0x16); - smtc_seqw(0x6b, 0x02); - smtc_seqw(0x21, (smtc_seqr(0x21) & 0x77)); - smtc_seqw(0x22, (smtc_seqr(0x22) & (~0x30))); - smtc_seqw(0x23, (smtc_seqr(0x23) & (~0xc0))); - smtc_seqw(0x24, (smtc_seqr(0x24) | 0x01)); - smtc_seqw(0x31, (smtc_seqr(0x31) | 0x03)); - break; - case FB_BLANK_NORMAL: - /* Screen Off: HSync: On, VSync : On Soft blank */ - smtc_seqw(0x01, (smtc_seqr(0x01) & (~0x20))); - smtc_seqw(0x6a, 0x16); - smtc_seqw(0x6b, 0x02); - smtc_seqw(0x22, (smtc_seqr(0x22) & (~0x30))); - smtc_seqw(0x23, (smtc_seqr(0x23) & (~0xc0))); - smtc_seqw(0x24, (smtc_seqr(0x24) | 0x01)); - smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00)); - break; - case FB_BLANK_VSYNC_SUSPEND: - /* Screen On: HSync: On, VSync : Off */ - smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20)); - smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0))); - smtc_seqw(0x6a, 0x0c); - smtc_seqw(0x6b, 0x02); - smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88)); - smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x20)); - smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0x20)); - smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01))); - smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00)); - smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80)); - break; - case FB_BLANK_HSYNC_SUSPEND: - /* Screen On: HSync: Off, VSync : On */ - smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20)); - smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0))); - smtc_seqw(0x6a, 0x0c); - smtc_seqw(0x6b, 0x02); - smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88)); - smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x10)); - smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0xD8)); - smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01))); - smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00)); - smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80)); - break; - case FB_BLANK_POWERDOWN: - /* Screen On: HSync: Off, VSync : Off */ - smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20)); - smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0))); - smtc_seqw(0x6a, 0x0c); - smtc_seqw(0x6b, 0x02); - smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88)); - smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x30)); - smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0xD8)); - smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01))); - smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00)); - smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80)); - break; - default: - return -EINVAL; - } - - return 0; -} - -static int smtc_setcolreg(unsigned regno, unsigned red, unsigned green, - unsigned blue, unsigned trans, struct fb_info *info) -{ - struct smtcfb_info *sfb; - u32 val; - - sfb = info->par; - - if (regno > 255) - return 1; - - switch (sfb->fb.fix.visual) { - case FB_VISUAL_DIRECTCOLOR: - case FB_VISUAL_TRUECOLOR: - /* - * 16/32 bit true-colour, use pseudo-palette for 16 base color - */ - if (regno < 16) { - if (sfb->fb.var.bits_per_pixel == 16) { - u32 *pal = sfb->fb.pseudo_palette; - val = chan_to_field(red, &sfb->fb.var.red); - val |= chan_to_field(green, &sfb->fb.var.green); - val |= chan_to_field(blue, &sfb->fb.var.blue); -#ifdef __BIG_ENDIAN - pal[regno] = - ((red & 0xf800) >> 8) | - ((green & 0xe000) >> 13) | - ((green & 0x1c00) << 3) | - ((blue & 0xf800) >> 3); -#else - pal[regno] = val; -#endif - } else { - u32 *pal = sfb->fb.pseudo_palette; - val = chan_to_field(red, &sfb->fb.var.red); - val |= chan_to_field(green, &sfb->fb.var.green); - val |= chan_to_field(blue, &sfb->fb.var.blue); -#ifdef __BIG_ENDIAN - val = - (val & 0xff00ff00 >> 8) | - (val & 0x00ff00ff << 8); -#endif - pal[regno] = val; - } - } - break; - - case FB_VISUAL_PSEUDOCOLOR: - /* color depth 8 bit */ - sm712_setpalette(regno, red, green, blue, info); - break; - - default: - return 1; /* unknown type */ - } - - return 0; - -} - -#ifdef __BIG_ENDIAN -static ssize_t smtcfb_read(struct fb_info *info, char __user *buf, size_t - count, loff_t *ppos) -{ - unsigned long p = *ppos; - - u32 *buffer, *dst; - u32 __iomem *src; - int c, i, cnt = 0, err = 0; - unsigned long total_size; - - if (!info || !info->screen_base) - return -ENODEV; - - if (info->state != FBINFO_STATE_RUNNING) - return -EPERM; - - total_size = info->screen_size; - - if (total_size == 0) - total_size = info->fix.smem_len; - - if (p >= total_size) - return 0; - - if (count >= total_size) - count = total_size; - - if (count + p > total_size) - count = total_size - p; - - buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, GFP_KERNEL); - if (!buffer) - return -ENOMEM; - - src = (u32 __iomem *) (info->screen_base + p); - - if (info->fbops->fb_sync) - info->fbops->fb_sync(info); - - while (count) { - c = (count > PAGE_SIZE) ? PAGE_SIZE : count; - dst = buffer; - for (i = c >> 2; i--;) { - *dst = fb_readl(src++); - *dst = - (*dst & 0xff00ff00 >> 8) | - (*dst & 0x00ff00ff << 8); - dst++; - } - if (c & 3) { - u8 *dst8 = (u8 *) dst; - u8 __iomem *src8 = (u8 __iomem *) src; - - for (i = c & 3; i--;) { - if (i & 1) { - *dst8++ = fb_readb(++src8); - } else { - *dst8++ = fb_readb(--src8); - src8 += 2; - } - } - src = (u32 __iomem *) src8; - } - - if (copy_to_user(buf, buffer, c)) { - err = -EFAULT; - break; - } - *ppos += c; - buf += c; - cnt += c; - count -= c; - } - - kfree(buffer); - - return (err) ? err : cnt; -} - -static ssize_t -smtcfb_write(struct fb_info *info, const char __user *buf, size_t count, - loff_t *ppos) -{ - unsigned long p = *ppos; - - u32 *buffer, *src; - u32 __iomem *dst; - int c, i, cnt = 0, err = 0; - unsigned long total_size; - - if (!info || !info->screen_base) - return -ENODEV; - - if (info->state != FBINFO_STATE_RUNNING) - return -EPERM; - - total_size = info->screen_size; - - if (total_size == 0) - total_size = info->fix.smem_len; - - if (p > total_size) - return -EFBIG; - - if (count > total_size) { - err = -EFBIG; - count = total_size; - } - - if (count + p > total_size) { - if (!err) - err = -ENOSPC; - - count = total_size - p; - } - - buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, GFP_KERNEL); - if (!buffer) - return -ENOMEM; - - dst = (u32 __iomem *) (info->screen_base + p); - - if (info->fbops->fb_sync) - info->fbops->fb_sync(info); - - while (count) { - c = (count > PAGE_SIZE) ? PAGE_SIZE : count; - src = buffer; - - if (copy_from_user(src, buf, c)) { - err = -EFAULT; - break; - } - - for (i = c >> 2; i--;) { - fb_writel((*src & 0xff00ff00 >> 8) | - (*src & 0x00ff00ff << 8), dst++); - src++; - } - if (c & 3) { - u8 *src8 = (u8 *) src; - u8 __iomem *dst8 = (u8 __iomem *) dst; - - for (i = c & 3; i--;) { - if (i & 1) { - fb_writeb(*src8++, ++dst8); - } else { - fb_writeb(*src8++, --dst8); - dst8 += 2; - } - } - dst = (u32 __iomem *) dst8; - } - - *ppos += c; - buf += c; - cnt += c; - count -= c; - } - - kfree(buffer); - - return (cnt) ? cnt : err; -} -#endif /* ! __BIG_ENDIAN */ - -static void sm7xx_set_timing(struct smtcfb_info *sfb) -{ - int i = 0, j = 0; - u32 m_nScreenStride; - - dev_dbg(&sfb->pdev->dev, - "sfb->width=%d sfb->height=%d " - "sfb->fb.var.bits_per_pixel=%d sfb->hz=%d\n", - sfb->width, sfb->height, sfb->fb.var.bits_per_pixel, sfb->hz); - - for (j = 0; j < numVGAModes; j++) { - if (VGAMode[j].mmSizeX == sfb->width && - VGAMode[j].mmSizeY == sfb->height && - VGAMode[j].bpp == sfb->fb.var.bits_per_pixel && - VGAMode[j].hz == sfb->hz) { - - dev_dbg(&sfb->pdev->dev, - "VGAMode[j].mmSizeX=%d VGAMode[j].mmSizeY=%d " - "VGAMode[j].bpp=%d VGAMode[j].hz=%d\n", - VGAMode[j].mmSizeX, VGAMode[j].mmSizeY, - VGAMode[j].bpp, VGAMode[j].hz); - - dev_dbg(&sfb->pdev->dev, "VGAMode index=%d\n", j); - - smtc_mmiowb(0x0, 0x3c6); - - smtc_seqw(0, 0x1); - - smtc_mmiowb(VGAMode[j].Init_MISC, 0x3c2); - - /* init SEQ register SR00 - SR04 */ - for (i = 0; i < SIZE_SR00_SR04; i++) - smtc_seqw(i, VGAMode[j].Init_SR00_SR04[i]); - - /* init SEQ register SR10 - SR24 */ - for (i = 0; i < SIZE_SR10_SR24; i++) - smtc_seqw(i + 0x10, - VGAMode[j].Init_SR10_SR24[i]); - - /* init SEQ register SR30 - SR75 */ - for (i = 0; i < SIZE_SR30_SR75; i++) - if ((i + 0x30) != 0x62 && - (i + 0x30) != 0x6a && - (i + 0x30) != 0x6b) - smtc_seqw(i + 0x30, - VGAMode[j].Init_SR30_SR75[i]); - - /* init SEQ register SR80 - SR93 */ - for (i = 0; i < SIZE_SR80_SR93; i++) - smtc_seqw(i + 0x80, - VGAMode[j].Init_SR80_SR93[i]); - - /* init SEQ register SRA0 - SRAF */ - for (i = 0; i < SIZE_SRA0_SRAF; i++) - smtc_seqw(i + 0xa0, - VGAMode[j].Init_SRA0_SRAF[i]); - - /* init Graphic register GR00 - GR08 */ - for (i = 0; i < SIZE_GR00_GR08; i++) - smtc_grphw(i, VGAMode[j].Init_GR00_GR08[i]); - - /* init Attribute register AR00 - AR14 */ - for (i = 0; i < SIZE_AR00_AR14; i++) - smtc_attrw(i, VGAMode[j].Init_AR00_AR14[i]); - - /* init CRTC register CR00 - CR18 */ - for (i = 0; i < SIZE_CR00_CR18; i++) - smtc_crtcw(i, VGAMode[j].Init_CR00_CR18[i]); - - /* init CRTC register CR30 - CR4D */ - for (i = 0; i < SIZE_CR30_CR4D; i++) - smtc_crtcw(i + 0x30, - VGAMode[j].Init_CR30_CR4D[i]); - - /* init CRTC register CR90 - CRA7 */ - for (i = 0; i < SIZE_CR90_CRA7; i++) - smtc_crtcw(i + 0x90, - VGAMode[j].Init_CR90_CRA7[i]); - } - } - smtc_mmiowb(0x67, 0x3c2); - - /* set VPR registers */ - writel(0x0, sfb->vp_regs + 0x0C); - writel(0x0, sfb->vp_regs + 0x40); - - /* set data width */ - m_nScreenStride = - (sfb->width * sfb->fb.var.bits_per_pixel) / 64; - switch (sfb->fb.var.bits_per_pixel) { - case 8: - writel(0x0, sfb->vp_regs + 0x0); - break; - case 16: - writel(0x00020000, sfb->vp_regs + 0x0); - break; - case 24: - writel(0x00040000, sfb->vp_regs + 0x0); - break; - case 32: - writel(0x00030000, sfb->vp_regs + 0x0); - break; - } - writel((u32) (((m_nScreenStride + 2) << 16) | m_nScreenStride), - sfb->vp_regs + 0x10); - -} - -static void smtc_set_timing(struct smtcfb_info *sfb) -{ - switch (sfb->chip_id) { - case 0x710: - case 0x712: - case 0x720: - sm7xx_set_timing(sfb); - break; - } -} - -static void smtcfb_setmode(struct smtcfb_info *sfb) -{ - switch (sfb->fb.var.bits_per_pixel) { - case 32: - sfb->fb.fix.visual = FB_VISUAL_TRUECOLOR; - sfb->fb.fix.line_length = sfb->fb.var.xres * 4; - sfb->fb.var.red.length = 8; - sfb->fb.var.green.length = 8; - sfb->fb.var.blue.length = 8; - sfb->fb.var.red.offset = 16; - sfb->fb.var.green.offset = 8; - sfb->fb.var.blue.offset = 0; - break; - case 24: - sfb->fb.fix.visual = FB_VISUAL_TRUECOLOR; - sfb->fb.fix.line_length = sfb->fb.var.xres * 3; - sfb->fb.var.red.length = 8; - sfb->fb.var.green.length = 8; - sfb->fb.var.blue.length = 8; - sfb->fb.var.red.offset = 16; - sfb->fb.var.green.offset = 8; - sfb->fb.var.blue.offset = 0; - break; - case 8: - sfb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR; - sfb->fb.fix.line_length = sfb->fb.var.xres; - sfb->fb.var.red.length = 3; - sfb->fb.var.green.length = 3; - sfb->fb.var.blue.length = 2; - sfb->fb.var.red.offset = 5; - sfb->fb.var.green.offset = 2; - sfb->fb.var.blue.offset = 0; - break; - case 16: - default: - sfb->fb.fix.visual = FB_VISUAL_TRUECOLOR; - sfb->fb.fix.line_length = sfb->fb.var.xres * 2; - sfb->fb.var.red.length = 5; - sfb->fb.var.green.length = 6; - sfb->fb.var.blue.length = 5; - sfb->fb.var.red.offset = 11; - sfb->fb.var.green.offset = 5; - sfb->fb.var.blue.offset = 0; - break; - } - - sfb->width = sfb->fb.var.xres; - sfb->height = sfb->fb.var.yres; - sfb->hz = 60; - smtc_set_timing(sfb); -} - -static int smtc_check_var(struct fb_var_screeninfo *var, struct fb_info *info) -{ - /* sanity checks */ - if (var->xres_virtual < var->xres) - var->xres_virtual = var->xres; - - if (var->yres_virtual < var->yres) - var->yres_virtual = var->yres; - - /* set valid default bpp */ - if ((var->bits_per_pixel != 8) && (var->bits_per_pixel != 16) && - (var->bits_per_pixel != 24) && (var->bits_per_pixel != 32)) - var->bits_per_pixel = 16; - - return 0; -} - -static int smtc_set_par(struct fb_info *info) -{ - smtcfb_setmode(info->par); - - return 0; -} - -static struct fb_ops smtcfb_ops = { - .owner = THIS_MODULE, - .fb_check_var = smtc_check_var, - .fb_set_par = smtc_set_par, - .fb_setcolreg = smtc_setcolreg, - .fb_blank = smtc_blank, - .fb_fillrect = cfb_fillrect, - .fb_imageblit = cfb_imageblit, - .fb_copyarea = cfb_copyarea, -#ifdef __BIG_ENDIAN - .fb_read = smtcfb_read, - .fb_write = smtcfb_write, -#endif -}; - -/* - * alloc struct smtcfb_info and assign default values - */ -static struct smtcfb_info *smtc_alloc_fb_info(struct pci_dev *pdev) -{ - struct smtcfb_info *sfb; - - sfb = kzalloc(sizeof(*sfb), GFP_KERNEL); - - if (!sfb) - return NULL; - - sfb->pdev = pdev; - - sfb->fb.flags = FBINFO_FLAG_DEFAULT; - sfb->fb.fbops = &smtcfb_ops; - sfb->fb.fix = smtcfb_fix; - sfb->fb.var = smtcfb_var; - sfb->fb.pseudo_palette = sfb->colreg; - sfb->fb.par = sfb; - - return sfb; -} - -/* - * free struct smtcfb_info - */ -static void smtc_free_fb_info(struct smtcfb_info *sfb) -{ - kfree(sfb); -} - -/* - * Unmap in the memory mapped IO registers - */ - -static void smtc_unmap_mmio(struct smtcfb_info *sfb) -{ - if (sfb && smtc_RegBaseAddress) - smtc_RegBaseAddress = NULL; -} - -/* - * Map in the screen memory - */ - -static int smtc_map_smem(struct smtcfb_info *sfb, - struct pci_dev *pdev, u_long smem_len) -{ - - sfb->fb.fix.smem_start = pci_resource_start(pdev, 0); - -#ifdef __BIG_ENDIAN - if (sfb->fb.var.bits_per_pixel == 32) - sfb->fb.fix.smem_start += 0x800000; -#endif - - sfb->fb.fix.smem_len = smem_len; - - sfb->fb.screen_base = sfb->lfb; - - if (!sfb->fb.screen_base) { - dev_err(&pdev->dev, - "%s: unable to map screen memory\n", sfb->fb.fix.id); - return -ENOMEM; - } - - return 0; -} - -/* - * Unmap in the screen memory - * - */ -static void smtc_unmap_smem(struct smtcfb_info *sfb) -{ - if (sfb && sfb->fb.screen_base) { - iounmap(sfb->fb.screen_base); - sfb->fb.screen_base = NULL; - } -} - -/* - * We need to wake up the device and make sure its in linear memory mode. - */ -static inline void sm7xx_init_hw(void) -{ - outb_p(0x18, 0x3c4); - outb_p(0x11, 0x3c5); -} - -static int smtcfb_pci_probe(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - struct smtcfb_info *sfb; - u_long smem_size = 0x00800000; /* default 8MB */ - int err; - unsigned long mmio_base; - - dev_info(&pdev->dev, "Silicon Motion display driver."); - - err = pci_enable_device(pdev); /* enable SMTC chip */ - if (err) - return err; - - sprintf(smtcfb_fix.id, "sm%Xfb", ent->device); - - sfb = smtc_alloc_fb_info(pdev); - - if (!sfb) { - err = -ENOMEM; - goto failed_free; - } - - sfb->chip_id = ent->device; - - pci_set_drvdata(pdev, sfb); - - sm7xx_init_hw(); - - /* get mode parameter from smtc_scr_info */ - if (smtc_scr_info.lfb_width != 0) { - sfb->fb.var.xres = smtc_scr_info.lfb_width; - sfb->fb.var.yres = smtc_scr_info.lfb_height; - sfb->fb.var.bits_per_pixel = smtc_scr_info.lfb_depth; - } else { - /* default resolution 1024x600 16bit mode */ - sfb->fb.var.xres = SCREEN_X_RES; - sfb->fb.var.yres = SCREEN_Y_RES; - sfb->fb.var.bits_per_pixel = SCREEN_BPP; - } - -#ifdef __BIG_ENDIAN - if (sfb->fb.var.bits_per_pixel == 24) - sfb->fb.var.bits_per_pixel = (smtc_scr_info.lfb_depth = 32); -#endif - /* Map address and memory detection */ - mmio_base = pci_resource_start(pdev, 0); - pci_read_config_byte(pdev, PCI_REVISION_ID, &sfb->chip_rev_id); - - switch (sfb->chip_id) { - case 0x710: - case 0x712: - sfb->fb.fix.mmio_start = mmio_base + 0x00400000; - sfb->fb.fix.mmio_len = 0x00400000; - smem_size = SM712_VIDEOMEMORYSIZE; -#ifdef __BIG_ENDIAN - sfb->lfb = ioremap(mmio_base, 0x00c00000); -#else - sfb->lfb = ioremap(mmio_base, 0x00800000); -#endif - sfb->mmio = (smtc_RegBaseAddress = - sfb->lfb + 0x00700000); - sfb->dp_regs = sfb->lfb + 0x00408000; - sfb->vp_regs = sfb->lfb + 0x0040c000; -#ifdef __BIG_ENDIAN - if (sfb->fb.var.bits_per_pixel == 32) { - sfb->lfb += 0x800000; - dev_info(&pdev->dev, "sfb->lfb=%p", sfb->lfb); - } -#endif - if (!smtc_RegBaseAddress) { - dev_err(&pdev->dev, - "%s: unable to map memory mapped IO!", - sfb->fb.fix.id); - err = -ENOMEM; - goto failed_fb; - } - - /* set MCLK = 14.31818 * (0x16 / 0x2) */ - smtc_seqw(0x6a, 0x16); - smtc_seqw(0x6b, 0x02); - smtc_seqw(0x62, 0x3e); - /* enable PCI burst */ - smtc_seqw(0x17, 0x20); - /* enable word swap */ -#ifdef __BIG_ENDIAN - if (sfb->fb.var.bits_per_pixel == 32) - smtc_seqw(0x17, 0x30); -#endif - break; - case 0x720: - sfb->fb.fix.mmio_start = mmio_base; - sfb->fb.fix.mmio_len = 0x00200000; - smem_size = SM722_VIDEOMEMORYSIZE; - sfb->dp_regs = ioremap(mmio_base, 0x00a00000); - sfb->lfb = sfb->dp_regs + 0x00200000; - sfb->mmio = (smtc_RegBaseAddress = - sfb->dp_regs + 0x000c0000); - sfb->vp_regs = sfb->dp_regs + 0x800; - - smtc_seqw(0x62, 0xff); - smtc_seqw(0x6a, 0x0d); - smtc_seqw(0x6b, 0x02); - break; - default: - dev_err(&pdev->dev, - "No valid Silicon Motion display chip was detected!"); - - goto failed_fb; - } - - /* can support 32 bpp */ - if (15 == sfb->fb.var.bits_per_pixel) - sfb->fb.var.bits_per_pixel = 16; - - sfb->fb.var.xres_virtual = sfb->fb.var.xres; - sfb->fb.var.yres_virtual = sfb->fb.var.yres; - err = smtc_map_smem(sfb, pdev, smem_size); - if (err) - goto failed; - - smtcfb_setmode(sfb); - - err = register_framebuffer(&sfb->fb); - if (err < 0) - goto failed; - - dev_info(&pdev->dev, - "Silicon Motion SM%X Rev%X primary display mode %dx%d-%d Init Complete.", - sfb->chip_id, sfb->chip_rev_id, sfb->fb.var.xres, - sfb->fb.var.yres, sfb->fb.var.bits_per_pixel); - - return 0; - -failed: - dev_err(&pdev->dev, "Silicon Motion, Inc. primary display init fail."); - - smtc_unmap_smem(sfb); - smtc_unmap_mmio(sfb); -failed_fb: - smtc_free_fb_info(sfb); - -failed_free: - pci_disable_device(pdev); - - return err; -} - -/* - * 0x710 (LynxEM) - * 0x712 (LynxEM+) - * 0x720 (Lynx3DM, Lynx3DM+) - */ -static const struct pci_device_id smtcfb_pci_table[] = { - { PCI_DEVICE(0x126f, 0x710), }, - { PCI_DEVICE(0x126f, 0x712), }, - { PCI_DEVICE(0x126f, 0x720), }, - {0,} -}; - -static void smtcfb_pci_remove(struct pci_dev *pdev) -{ - struct smtcfb_info *sfb; - - sfb = pci_get_drvdata(pdev); - smtc_unmap_smem(sfb); - smtc_unmap_mmio(sfb); - unregister_framebuffer(&sfb->fb); - smtc_free_fb_info(sfb); -} - -#ifdef CONFIG_PM -static int smtcfb_pci_suspend(struct device *device) -{ - struct pci_dev *pdev = to_pci_dev(device); - struct smtcfb_info *sfb; - - sfb = pci_get_drvdata(pdev); - - /* set the hw in sleep mode use external clock and self memory refresh - * so that we can turn off internal PLLs later on - */ - smtc_seqw(0x20, (smtc_seqr(0x20) | 0xc0)); - smtc_seqw(0x69, (smtc_seqr(0x69) & 0xf7)); - - console_lock(); - fb_set_suspend(&sfb->fb, 1); - console_unlock(); - - /* additionally turn off all function blocks including internal PLLs */ - smtc_seqw(0x21, 0xff); - - return 0; -} - -static int smtcfb_pci_resume(struct device *device) -{ - struct pci_dev *pdev = to_pci_dev(device); - struct smtcfb_info *sfb; - - sfb = pci_get_drvdata(pdev); - - /* reinit hardware */ - sm7xx_init_hw(); - switch (sfb->chip_id) { - case 0x710: - case 0x712: - /* set MCLK = 14.31818 * (0x16 / 0x2) */ - smtc_seqw(0x6a, 0x16); - smtc_seqw(0x6b, 0x02); - smtc_seqw(0x62, 0x3e); - /* enable PCI burst */ - smtc_seqw(0x17, 0x20); -#ifdef __BIG_ENDIAN - if (sfb->fb.var.bits_per_pixel == 32) - smtc_seqw(0x17, 0x30); -#endif - break; - case 0x720: - smtc_seqw(0x62, 0xff); - smtc_seqw(0x6a, 0x0d); - smtc_seqw(0x6b, 0x02); - break; - } - - smtc_seqw(0x34, (smtc_seqr(0x34) | 0xc0)); - smtc_seqw(0x33, ((smtc_seqr(0x33) | 0x08) & 0xfb)); - - smtcfb_setmode(sfb); - - console_lock(); - fb_set_suspend(&sfb->fb, 0); - console_unlock(); - - return 0; -} - -static SIMPLE_DEV_PM_OPS(sm7xx_pm_ops, smtcfb_pci_suspend, smtcfb_pci_resume); -#define SM7XX_PM_OPS (&sm7xx_pm_ops) - -#else /* !CONFIG_PM */ - -#define SM7XX_PM_OPS NULL - -#endif /* !CONFIG_PM */ - -static struct pci_driver smtcfb_driver = { - .name = "smtcfb", - .id_table = smtcfb_pci_table, - .probe = smtcfb_pci_probe, - .remove = smtcfb_pci_remove, - .driver.pm = SM7XX_PM_OPS, -}; - -module_pci_driver(smtcfb_driver); - -MODULE_AUTHOR("Siliconmotion "); -MODULE_DESCRIPTION("Framebuffer driver for SMI Graphic Cards"); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/tidspbridge/core/io_sm.c b/drivers/staging/tidspbridge/core/io_sm.c index e322fb7aebe..c2829aa7780 100644 --- a/drivers/staging/tidspbridge/core/io_sm.c +++ b/drivers/staging/tidspbridge/core/io_sm.c @@ -2127,7 +2127,7 @@ void dump_dl_modules(struct bridge_dev_context *bridge_context) u32 module_size; u32 module_struct_size = 0; u32 sect_ndx; - char *sect_str ; + char *sect_str; int status = 0; status = dev_get_intf_fxns(dev_object, &intf_fxns); diff --git a/drivers/staging/tidspbridge/core/tiomap3430_pwr.c b/drivers/staging/tidspbridge/core/tiomap3430_pwr.c index 1862afd80dc..657104f37f7 100644 --- a/drivers/staging/tidspbridge/core/tiomap3430_pwr.c +++ b/drivers/staging/tidspbridge/core/tiomap3430_pwr.c @@ -99,7 +99,8 @@ int handle_hibernation_from_dsp(struct bridge_dev_context *dev_context) return -EPERM; } pwr_state = (*pdata->dsp_prm_read)(OMAP3430_IVA2_MOD, - OMAP2_PM_PWSTST) & OMAP_POWERSTATEST_MASK; + OMAP2_PM_PWSTST) & + OMAP_POWERSTATEST_MASK; } if (timeout == 0) { pr_err("%s: Timed out waiting for DSP off mode\n", __func__); @@ -209,7 +210,8 @@ int sleep_dsp(struct bridge_dev_context *dev_context, u32 dw_cmd, return -EPERM; } pwr_state = (*pdata->dsp_prm_read)(OMAP3430_IVA2_MOD, - OMAP2_PM_PWSTST) & OMAP_POWERSTATEST_MASK; + OMAP2_PM_PWSTST) & + OMAP_POWERSTATEST_MASK; } if (!timeout) { @@ -355,7 +357,7 @@ int pre_scale_dsp(struct bridge_dev_context *dev_context, void *pargs) (dev_context->brd_state == BRD_DSP_HIBERNATION)) { dev_dbg(bridge, "OPP: %s IVA in sleep. No message to DSP\n"); return 0; - } else if ((dev_context->brd_state == BRD_RUNNING)) { + } else if (dev_context->brd_state == BRD_RUNNING) { /* Send a prenotification to DSP */ dev_dbg(bridge, "OPP: %s sent notification to DSP\n", __func__); sm_interrupt_dsp(dev_context, MBX_PM_SETPOINT_PRENOTIFY); @@ -396,13 +398,14 @@ int post_scale_dsp(struct bridge_dev_context *dev_context, io_sh_msetting(hio_mgr, SHM_CURROPP, &level); dev_dbg(bridge, "OPP: %s IVA in sleep. Wrote to shm\n", __func__); - } else if ((dev_context->brd_state == BRD_RUNNING)) { + } else if (dev_context->brd_state == BRD_RUNNING) { /* Update the OPP value in shared memory */ io_sh_msetting(hio_mgr, SHM_CURROPP, &level); /* Send a post notification to DSP */ sm_interrupt_dsp(dev_context, MBX_PM_SETPOINT_POSTNOTIFY); - dev_dbg(bridge, "OPP: %s wrote to shm. Sent post notification " - "to DSP\n", __func__); + dev_dbg(bridge, + "OPP: %s wrote to shm. Sent post notification to DSP\n", + __func__); } else { status = -EPERM; } diff --git a/drivers/staging/tidspbridge/dynload/tramp.c b/drivers/staging/tidspbridge/dynload/tramp.c index 404af189598..5f0431305fb 100644 --- a/drivers/staging/tidspbridge/dynload/tramp.c +++ b/drivers/staging/tidspbridge/dynload/tramp.c @@ -503,7 +503,7 @@ static int priv_tgt_img_gen(struct dload_state *dlthis, u32 base, * TRAMPOLINES ARE TREATED AS 2ND PASS even though this is really * the first (and only) relocation that will be performed on them. */ -static int priv_pkt_relo(struct dload_state *dlthis, tgt_au_t * data, +static int priv_pkt_relo(struct dload_state *dlthis, tgt_au_t *data, struct reloc_record_t *rp[], u32 relo_count) { int ret_val = 1; diff --git a/drivers/staging/tidspbridge/rmgr/dbdcd.c b/drivers/staging/tidspbridge/rmgr/dbdcd.c index 190ca3fe732..2ae48c9a936 100644 --- a/drivers/staging/tidspbridge/rmgr/dbdcd.c +++ b/drivers/staging/tidspbridge/rmgr/dbdcd.c @@ -101,14 +101,14 @@ static int dcd_uuid_from_string(char *sz_uuid, struct dsp_uuid *uuid_obj) * if the converted value doesn't fit in u32. So, convert the * last six bytes to u64 and memcpy what is needed */ - if(sscanf(sz_uuid, "%8x%c%4hx%c%4hx%c%2hhx%2hhx%c%llx", + if (sscanf(sz_uuid, "%8x%c%4hx%c%4hx%c%2hhx%2hhx%c%llx", &uuid_tmp.data1, &c, &uuid_tmp.data2, &c, &uuid_tmp.data3, &c, &uuid_tmp.data4, &uuid_tmp.data5, &c, &t) != 10) return -EINVAL; t = cpu_to_be64(t); - memcpy(&uuid_tmp.data6[0], ((char*)&t) + 2, 6); + memcpy(&uuid_tmp.data6[0], ((char *)&t) + 2, 6); *uuid_obj = uuid_tmp; return 0; diff --git a/drivers/staging/tidspbridge/rmgr/drv.c b/drivers/staging/tidspbridge/rmgr/drv.c index be26917a689..757ae20b38e 100644 --- a/drivers/staging/tidspbridge/rmgr/drv.c +++ b/drivers/staging/tidspbridge/rmgr/drv.c @@ -738,7 +738,7 @@ void mem_ext_phys_pool_release(void) * Allocate physically contiguous, uncached memory from external memory pool */ -static void *mem_ext_phys_mem_alloc(u32 bytes, u32 align, u32 * phys_addr) +static void *mem_ext_phys_mem_alloc(u32 bytes, u32 align, u32 *phys_addr) { u32 new_alloc_ptr; u32 offset; diff --git a/drivers/staging/tidspbridge/rmgr/nldr.c b/drivers/staging/tidspbridge/rmgr/nldr.c index ca3805046a7..5ac507ccd19 100644 --- a/drivers/staging/tidspbridge/rmgr/nldr.c +++ b/drivers/staging/tidspbridge/rmgr/nldr.c @@ -623,7 +623,7 @@ void nldr_delete(struct nldr_object *nldr_obj) * ======== nldr_get_fxn_addr ======== */ int nldr_get_fxn_addr(struct nldr_nodeobject *nldr_node_obj, - char *str_fxn, u32 * addr) + char *str_fxn, u32 *addr) { struct dbll_sym_val *dbll_sym; struct nldr_object *nldr_obj; @@ -1751,9 +1751,8 @@ static void unload_ovly(struct nldr_nodeobject *nldr_node_obj, } if (ref_count && (*ref_count > 0)) { *ref_count -= 1; - if (other_ref) { + if (other_ref) *other_ref -= 1; - } } if (ref_count && *ref_count == 0) { diff --git a/drivers/staging/tidspbridge/rmgr/node.c b/drivers/staging/tidspbridge/rmgr/node.c index 87dfa92ab45..9d3044a384e 100644 --- a/drivers/staging/tidspbridge/rmgr/node.c +++ b/drivers/staging/tidspbridge/rmgr/node.c @@ -246,7 +246,7 @@ static void fill_stream_def(struct node_object *hnode, struct node_strmdef *pstrm_def, struct dsp_strmattr *pattrs); static void free_stream(struct node_mgr *hnode_mgr, struct stream_chnl stream); -static int get_fxn_address(struct node_object *hnode, u32 * fxn_addr, +static int get_fxn_address(struct node_object *hnode, u32 *fxn_addr, u32 phase); static int get_node_props(struct dcd_manager *hdcd_mgr, struct node_object *hnode, @@ -406,7 +406,7 @@ int node_allocate(struct proc_object *hprocessor, /* check for page aligned Heap size */ if (((attr_in->heap_size) & (PG_SIZE4K - 1))) { - pr_err("%s: node heap size not aligned to 4K, size = 0x%x \n", + pr_err("%s: node heap size not aligned to 4K, size = 0x%x\n", __func__, attr_in->heap_size); status = -EINVAL; } else { @@ -703,9 +703,9 @@ DBAPI node_alloc_msg_buf(struct node_object *hnode, u32 usize, pattr = &node_dfltbufattrs; /* set defaults */ status = proc_get_processor_id(pnode->processor, &proc_id); - if (proc_id != DSP_UNIT) { + if (proc_id != DSP_UNIT) goto func_end; - } + /* If segment ID includes MEM_SETVIRTUALSEGID then pbuffer is a * virt address, so set this info in this node's translator * object for future ref. If MEM_GETVIRTUALSEGID then retrieve @@ -886,11 +886,10 @@ int node_connect(struct node_object *node1, u32 stream1, if (pattrs && pattrs->strm_mode != STRMMODE_PROCCOPY) return -EPERM; /* illegal stream mode */ - if (node1_type != NODE_GPP) { + if (node1_type != NODE_GPP) hnode_mgr = node1->node_mgr; - } else { + else hnode_mgr = node2->node_mgr; - } /* Enter critical section */ mutex_lock(&hnode_mgr->node_mgr_lock); @@ -1576,7 +1575,7 @@ func_end: * Purpose: * Frees the message buffer. */ -int node_free_msg_buf(struct node_object *hnode, u8 * pbuffer, +int node_free_msg_buf(struct node_object *hnode, u8 *pbuffer, struct dsp_bufferattr *pattr) { struct node_object *pnode = (struct node_object *)hnode; @@ -2322,7 +2321,8 @@ int node_terminate(struct node_object *hnode, int *pstatus) if (!hdeh_mgr) goto func_cont; - bridge_deh_notify(hdeh_mgr, DSP_SYSERROR, DSP_EXCEPTIONABORT); + bridge_deh_notify(hdeh_mgr, DSP_SYSERROR, + DSP_EXCEPTIONABORT); } } func_cont: @@ -2640,7 +2640,7 @@ static void free_stream(struct node_mgr *hnode_mgr, struct stream_chnl stream) * Purpose: * Retrieves the address for create, execute or delete phase for a node. */ -static int get_fxn_address(struct node_object *hnode, u32 * fxn_addr, +static int get_fxn_address(struct node_object *hnode, u32 *fxn_addr, u32 phase) { char *pstr_fxn_name = NULL; diff --git a/drivers/staging/unisys/Documentation/overview.txt b/drivers/staging/unisys/Documentation/overview.txt new file mode 100644 index 00000000000..8d078e4de3b --- /dev/null +++ b/drivers/staging/unisys/Documentation/overview.txt @@ -0,0 +1,174 @@ + +Overview + +This document describes the driver set for Unisys Secure Partitioning (s-Par®). + +s-Par is firmware that provides hardware partitioning capabilities for +splitting large-scale Intel x86 servers into multiple isolated +partitions. s-Par provides a set of para-virtualized device drivers to +allow guest partitions on the same server to share devices that would +normally be unsharable; specifically, PCI network interfaces and host +bus adapters that do not support shared access via SR-IOV. The shared +device is owned and managed by a small, single-purpose service +partition, which communicates with each guest partition sharing that +device through an area of shared memory called a channel. Additional +drivers provide support interfaces for communicating with s-Par +services, logging and diagnostics, and accessing the Linux console +from the s-Par user interface. + +The driver stack consists of a set of support modules, a set of bus +modules, and a set of device driver modules. The support modules +handle a number of common functions across each of the other +drivers. The bus modules provide organization for the device driver +modules, which provide the shared device functionality. + +These drivers are for the Unisys virtual PCI hardware model where the +hypervisor need not intervene (other than normal interrupt handling) +in the interactions between the client drivers and the virtual adapter +firmware in the adapter service partition. + +Driver Descriptions + +Device Modules + +The modules in this section handle shared devices and the virtual +buses required to support them. These modules use functions in and +depend on the modules described in the support modules section. + +visorchipset + +The visorchipset module receives device creation and destruction +events from the Command service partition of s-Par, as well as +controlling registration of shared device drivers with the s-Par +driver core. The events received are used to populate other s-Par +modules with their assigned shared devices. Visorchipset is required +for shared device drivers to function properly. Visorchipset also +stores information for handling dump disk device creation during +kdump. + +In operation, the visorchipset module processes device creation and +destruction messages sent by s-Par's Command service partition through +a channel. These messages result in creation (or destruction) of each +virtual bus and virtual device. Each bus and device is also associated +with a communication channel, which is used to communicate with one or +more IO service partitions to perform device IO on behalf of the +guest. + +virthba + +The virthba module provides access to a shared SCSI host bus adapter +and one or more disk devices, by proxying SCSI commands between the +guest and the service partition that owns the shared SCSI adapter, +using a channel between the guest and the service partition. The disks +that appear on the shared bus are defined by the s-Par configuration +and enforced by the service partition, while the guest driver handles +sending commands and handling responses. Each disk is shared as a +whole to a guest. Sharing the bus adapter in this way provides +resiliency; should the device encounter an error, only the service +partition is rebooted, and the device is reinitialized. This allows +guests to continue running and to recover from the error. + +virtnic + +The virtnic module provides a paravirtualized network interface to a +guest by proxying buffer information between the guest and the service +partition that owns the shared network interface, using a channel +between the guest and the service partition. The connectivity of this +interface with the shared interface and possibly other guest +partitions is defined by the s-Par configuration and enforced by the +service partition; the guest driver handles communication and link +status. + +visorserial + +The visorserial module allows the console of the linux guest to be +accessed via the s-Par console serial channel. It creates devices in +/dev/visorserialclientX which behave like a serial terminal and are +connected to the diagnostics system in s-Par. By assigning a getty to +the terminal in the guest, a user could log into and access the guest +from the s-Par diagnostics SWITCH RUN terminal. + +visorbus + +The visorbus module handles the bus functions for most functional +drivers except visorserial, visordiag, virthba, and virtnic. It +maintains the sysfs subtree /sys/devices/visorbus*/. It is responsible +for device creation and destruction of the devices on its bus. + +visorclientbus + +The visorclientbus module forwards the bus functions for virthba, and +virtnic to the virtpci driver. + +virtpci + +The virtpci module handles the bus functions for virthba, and virtnic. + +s-Par Integration Modules + +The modules in this section provide integration with s-Par guest +partition services like diagnostics and remote desktop. These modules +depend on functions in the modules described in the support modules +section. + +visorvideoclient + +The visorvideoclient module provides functionality for video support +for the Unisys s-Par Partition Desktop application. The guest OS must +also have the UEFI GOP protocol enabled for the partition desktop to +function. visorconinclient The visorconinclient module provides +keyboard and mouse support for the Unisys s-Par Partition Desktop +application. + +sparstop + +The sparstop module handles requests from the Unisys s-Par platform to +shutdown the linux guest. It allows a program on the guest to perform +clean-up functions on the guest before the guest is shut down or +rebooted using ACPI. + +visordiag + +This driver provides the ability for the guest to write information +into the s-Par diagnostics subsystem. It creates a set of devices +named /dev/visordiag.X which can be written to by the guest to add +text to the s-Par system log. + +Support Modules + +The modules described in this section provide functions and +abstractions to support the modules described in the previous +sections, to avoid having duplicated functionality. + +visornoop + +The visornoop module is a placeholder that responds to device +create/destroy messages that are currently not in use by linux guests. + +visoruislib + +The visoruislib module is a support library, used to handle requests +from virtpci. + +visorchannelstub + +The visorchannelstub module provides support routines for storing and +retrieving data from a channel. + +visorchannel + +The visorchannel module is a support library that abstracts reading +and writing a channel in memory. + +visorutil + +The visorutil module is a support library required by all other s-Par +driver modules. Among its features it abstracts reading, writing, and +manipulating a block of memory. + +Minimum Required Driver Set + +The drivers required to boot a Linux guest are visorchipset, visorbus, +visorvideoclient, visorconinclient, visoruislib, visorchannelstub, +visorchannel, and visorutil. The other drivers are required by the +product configurations that are currently being marketed. diff --git a/drivers/staging/unisys/Documentation/proc-entries.txt b/drivers/staging/unisys/Documentation/proc-entries.txt new file mode 100644 index 00000000000..426f92b1c57 --- /dev/null +++ b/drivers/staging/unisys/Documentation/proc-entries.txt @@ -0,0 +1,93 @@ + s-Par Proc Entries +This document describes the proc entries created by the Unisys s-Par modules. + +Support Module Entries +These entries are provided primarily for debugging. + +/proc/uislib/info: This entry contains debugging information for the +uislib module, including bus information and memory usage. + +/proc/visorchipset/controlvm: This directory contains debugging +entries for the controlvm channel used by visorchipset. + +/proc/uislib/platform: This entry is used to display the platform +number this node is in the system. For some guests, this may be +invalid. + +/proc/visorchipset/chipsetready: This entry is written to by scripts +to signify that any user level activity has been completed before the +guest can be considered running and is shown as running in the s-Par +UI. + +Device Entries +These entries provide status of the devices shared by a service partition. + +/proc/uislib/vbus: this is a directory containing entries for each +virtual bus. Each numbered sub-directory contains an info entry, which +describes the devices that appear on that bus. + +/proc/uislib/cycles_before_wait: This entry is used to tune +performance, by setting the number of cycles we wait before going idle +when in polling mode. A longer time will reduce message latency but +spend more processing time polling. + +/proc/uislib/smart_wakeup: This entry is used to tune performance, by +enabling or disabling smart wakeup. + +/proc/virthba/info: This entry contains debugging information for the +virthba module, including interrupt information and memory usage. + +/proc/virthba/enable_ints: This entry controls interrupt use by the +virthba module. Writing a 0 to this entry will disable interrupts. + +/proc/virtnic/info: This entry contains debugging information for the +virtnic module, including interrupt information, send and receive +counts, and other device information. + +/proc/virtnic/ethX: This is a directory containing entries for each +virtual NIC. Each named subdirectory contains two entries, +clientstring and zone. + +/proc/virtpci/info: This entry contains debugging information for the +virtpci module, including virtual PCI bus information and device +locations. + +/proc/virtnic/enable_ints: This entry controls interrupt use by the +virtnic module. Writing a 0 to this entry will disable interrupts. + +Visorconinclient, visordiag, visornoop, visorserialclient, and +visorvideoclient Entries + +The entries in proc for these modules all follow the same +pattern. Each module has its own proc directory with the same name, +e.g. visordiag presents a /proc/visordiag directory. Inside of the +module's directory are a device directory, which contains one numbered +directory for each device provided by that module. Each device has a +diag entry that presents the device number and visorbus name for that +device. The module directory also has a driver/diag entry, which +reports the corresponding s-Par version number of the driver. + +Automated Installation Entries + +These entries are used to pass information between the s-Par platform +and the Linux-based installation and recovery tool. These values are +read/write, however, the guest can only reset them to 0, or report an +error status through the installer entry. The values are only set via +s-Par's firmware interface, to help prevent accidentally booting into +the tool. + +/proc/visorchipset/boottotool: This entry instructs s-Par that the +next reboot will launch the installation and recovery tool. If set to +0, the next boot will happen according to the UEFI boot manager +settings. + +/proc/visorchipset/toolaction: This entry indicates the installation +and recovery tool mode requested for the next boot. + +/proc/visorchipset/installer: this entry is used by the installation +and recovery tool to pass status and result information back to the +s-Par firmware. + +/proc/visorchipset/partition: This directory contains the guest +partition configuration data for each virtual bus, for use during +installation and at runtime for s-Par service partitions. diff --git a/drivers/staging/unisys/Kconfig b/drivers/staging/unisys/Kconfig new file mode 100644 index 00000000000..ac080c9dcf4 --- /dev/null +++ b/drivers/staging/unisys/Kconfig @@ -0,0 +1,20 @@ +# +# Unisys SPAR driver configuration +# +menuconfig UNISYSSPAR + bool "Unisys SPAR driver support" + depends on X86_64 + ---help--- + Support for the Unisys SPAR drivers + +if UNISYSSPAR + +source "drivers/staging/unisys/visorutil/Kconfig" +source "drivers/staging/unisys/visorchannel/Kconfig" +source "drivers/staging/unisys/visorchipset/Kconfig" +source "drivers/staging/unisys/channels/Kconfig" +source "drivers/staging/unisys/uislib/Kconfig" +source "drivers/staging/unisys/virtpci/Kconfig" +source "drivers/staging/unisys/virthba/Kconfig" + +endif # UNISYSSPAR diff --git a/drivers/staging/unisys/MAINTAINERS b/drivers/staging/unisys/MAINTAINERS new file mode 100644 index 00000000000..c9cef0b9153 --- /dev/null +++ b/drivers/staging/unisys/MAINTAINERS @@ -0,0 +1,6 @@ +Unisys s-Par drivers +M: Ben Romer <sparmaintainer@unisys.com> +S: Maintained +F: Documentation/s-Par/overview.txt +F: Documentation/s-Par/proc-entries.txt +F: drivers/staging/unisys/ diff --git a/drivers/staging/unisys/Makefile b/drivers/staging/unisys/Makefile new file mode 100644 index 00000000000..b988d6940aa --- /dev/null +++ b/drivers/staging/unisys/Makefile @@ -0,0 +1,10 @@ +# +# Makefile for Unisys SPAR drivers +# +obj-$(CONFIG_UNISYS_VISORUTIL) += visorutil/ +obj-$(CONFIG_UNISYS_VISORCHANNEL) += visorchannel/ +obj-$(CONFIG_UNISYS_VISORCHIPSET) += visorchipset/ +obj-$(CONFIG_UNISYS_CHANNELSTUB) += channels/ +obj-$(CONFIG_UNISYS_UISLIB) += uislib/ +obj-$(CONFIG_UNISYS_VIRTPCI) += virtpci/ +obj-$(CONFIG_UNISYS_VIRTHBA) += virthba/ diff --git a/drivers/staging/unisys/TODO b/drivers/staging/unisys/TODO new file mode 100644 index 00000000000..c4265a2e73d --- /dev/null +++ b/drivers/staging/unisys/TODO @@ -0,0 +1,20 @@ +TODO: + -checkpatch warnings + -move /proc entries to /sys + -proper major number(s) + -add other drivers needed for full functionality: + -visorclientbus + -visorbus + -visordiag + -virtnic + -visornoop + -visorserial + -visorvideoclient + -visorconinclient + -sparstop + -move individual drivers into proper driver subsystems + + +Patches to: + Ken Cox <jkc@redhat.com> + Ben Romer <sparmaintainer@unisys.com> diff --git a/drivers/staging/unisys/channels/Kconfig b/drivers/staging/unisys/channels/Kconfig new file mode 100644 index 00000000000..47a23538556 --- /dev/null +++ b/drivers/staging/unisys/channels/Kconfig @@ -0,0 +1,10 @@ +# +# Unisys channels configuration +# + +config UNISYS_CHANNELSTUB + tristate "Unisys channelstub driver" + depends on UNISYSSPAR + ---help--- + If you say Y here, you will enable the Unisys channels driver. + diff --git a/drivers/staging/unisys/channels/Makefile b/drivers/staging/unisys/channels/Makefile new file mode 100644 index 00000000000..e60b0aef4dc --- /dev/null +++ b/drivers/staging/unisys/channels/Makefile @@ -0,0 +1,13 @@ +# +# Makefile for Unisys channelstub +# + +obj-$(CONFIG_UNISYS_CHANNELSTUB) += visorchannelstub.o + +visorchannelstub-y := channel.o chanstub.o + +ccflags-y += -Idrivers/staging/unisys/include +ccflags-y += -Idrivers/staging/unisys/common-spar/include +ccflags-y += -Idrivers/staging/unisys/common-spar/include/channels +ccflags-y += -DCONFIG_SPAR_GUEST -DGUESTDRIVERBUILD -DNOAUTOVERSION + diff --git a/drivers/staging/unisys/channels/channel.c b/drivers/staging/unisys/channels/channel.c new file mode 100644 index 00000000000..afe8ceac203 --- /dev/null +++ b/drivers/staging/unisys/channels/channel.c @@ -0,0 +1,307 @@ +/* Copyright © 2010 - 2013 UNISYS CORPORATION + * 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. + */ + +#include <linux/kernel.h> +#ifdef CONFIG_MODVERSIONS +#include <config/modversions.h> +#endif +#include <linux/module.h> +#include <linux/init.h> /* for module_init and module_exit */ +#include <linux/slab.h> /* for memcpy */ +#include <linux/types.h> + +/* Implementation of exported functions for Supervisor channels */ +#include "channel.h" + +/* + * Routine Description: + * Tries to insert the prebuilt signal pointed to by pSignal into the nth + * Queue of the Channel pointed to by pChannel + * + * Parameters: + * pChannel: (IN) points to the IO Channel + * Queue: (IN) nth Queue of the IO Channel + * pSignal: (IN) pointer to the signal + * + * Assumptions: + * - pChannel, Queue and pSignal are valid. + * - If insertion fails due to a full queue, the caller will determine the + * retry policy (e.g. wait & try again, report an error, etc.). + * + * Return value: + * 1 if the insertion succeeds, 0 if the queue was full. + */ +unsigned char +SignalInsert(pCHANNEL_HEADER pChannel, U32 Queue, void *pSignal) +{ + void *psignal; + unsigned int head, tail; + pSIGNAL_QUEUE_HEADER pqhdr = + (pSIGNAL_QUEUE_HEADER) ((char *) pChannel + + pChannel->oChannelSpace) + Queue; + + /* capture current head and tail */ + head = pqhdr->Head; + tail = pqhdr->Tail; + + /* queue is full if (head + 1) % n equals tail */ + if (((head + 1) % pqhdr->MaxSignalSlots) == tail) { + pqhdr->NumOverflows++; + return 0; + } + + /* increment the head index */ + head = (head + 1) % pqhdr->MaxSignalSlots; + + /* copy signal to the head location from the area pointed to + * by pSignal + */ + psignal = + (char *) pqhdr + pqhdr->oSignalBase + (head * pqhdr->SignalSize); + MEMCPY(psignal, pSignal, pqhdr->SignalSize); + + VolatileBarrier(); + pqhdr->Head = head; + + pqhdr->NumSignalsSent++; + return 1; +} +EXPORT_SYMBOL_GPL(SignalInsert); + +/* + * Routine Description: + * Removes one signal from Channel pChannel's nth Queue at the + * time of the call and copies it into the memory pointed to by + * pSignal. + * + * Parameters: + * pChannel: (IN) points to the IO Channel + * Queue: (IN) nth Queue of the IO Channel + * pSignal: (IN) pointer to where the signals are to be copied + * + * Assumptions: + * - pChannel and Queue are valid. + * - pSignal points to a memory area large enough to hold queue's SignalSize + * + * Return value: + * 1 if the removal succeeds, 0 if the queue was empty. + */ +unsigned char +SignalRemove(pCHANNEL_HEADER pChannel, U32 Queue, void *pSignal) +{ + void *psource; + unsigned int head, tail; + pSIGNAL_QUEUE_HEADER pqhdr = + (pSIGNAL_QUEUE_HEADER) ((char *) pChannel + + pChannel->oChannelSpace) + Queue; + + /* capture current head and tail */ + head = pqhdr->Head; + tail = pqhdr->Tail; + + /* queue is empty if the head index equals the tail index */ + if (head == tail) { + pqhdr->NumEmptyCnt++; + return 0; + } + + /* advance past the 'empty' front slot */ + tail = (tail + 1) % pqhdr->MaxSignalSlots; + + /* copy signal from tail location to the area pointed to by pSignal */ + psource = + (char *) pqhdr + pqhdr->oSignalBase + (tail * pqhdr->SignalSize); + MEMCPY(pSignal, psource, pqhdr->SignalSize); + + VolatileBarrier(); + pqhdr->Tail = tail; + + pqhdr->NumSignalsReceived++; + return 1; +} +EXPORT_SYMBOL_GPL(SignalRemove); + +/* + * Routine Description: + * Removes all signals present in Channel pChannel's nth Queue at the + * time of the call and copies them into the memory pointed to by + * pSignal. Returns the # of signals copied as the value of the routine. + * + * Parameters: + * pChannel: (IN) points to the IO Channel + * Queue: (IN) nth Queue of the IO Channel + * pSignal: (IN) pointer to where the signals are to be copied + * + * Assumptions: + * - pChannel and Queue are valid. + * - pSignal points to a memory area large enough to hold Queue's MaxSignals + * # of signals, each of which is Queue's SignalSize. + * + * Return value: + * # of signals copied. + */ +unsigned int +SignalRemoveAll(pCHANNEL_HEADER pChannel, U32 Queue, void *pSignal) +{ + void *psource; + unsigned int head, tail, signalCount = 0; + pSIGNAL_QUEUE_HEADER pqhdr = + (pSIGNAL_QUEUE_HEADER) ((char *) pChannel + + pChannel->oChannelSpace) + Queue; + + /* capture current head and tail */ + head = pqhdr->Head; + tail = pqhdr->Tail; + + /* queue is empty if the head index equals the tail index */ + if (head == tail) + return 0; + + while (head != tail) { + /* advance past the 'empty' front slot */ + tail = (tail + 1) % pqhdr->MaxSignalSlots; + + /* copy signal from tail location to the area pointed + * to by pSignal + */ + psource = + (char *) pqhdr + pqhdr->oSignalBase + + (tail * pqhdr->SignalSize); + MEMCPY((char *) pSignal + (pqhdr->SignalSize * signalCount), + psource, pqhdr->SignalSize); + + VolatileBarrier(); + pqhdr->Tail = tail; + + signalCount++; + pqhdr->NumSignalsReceived++; + } + + return signalCount; +} + +/* + * Routine Description: + * Copies one signal from channel pChannel's nth Queue at the given position + * at the time of the call into the memory pointed to by pSignal. + * + * Parameters: + * pChannel: (IN) points to the IO Channel + * Queue: (IN) nth Queue of the IO Channel + * Position: (IN) nth entry in Queue of the IO Channel + * pSignal: (IN) pointer to where the signals are to be copied + * + * Assumptions: + * - pChannel and Queue are valid. + * - pSignal points to a memory area large enough to hold queue's SignalSize + * + * Return value: + * 1 if the copy succeeds, 0 if the queue was empty or Position was invalid. + */ +unsigned char +SignalPeek(pCHANNEL_HEADER pChannel, U32 Queue, U32 Position, void *pSignal) +{ + void *psignal; + unsigned int head, tail; + pSIGNAL_QUEUE_HEADER pqhdr = + (pSIGNAL_QUEUE_HEADER) ((char *) pChannel + + pChannel->oChannelSpace) + Queue; + + head = pqhdr->Head; + tail = pqhdr->Tail; + + /* check if Position is out of range or queue is empty */ + if (Position >= pqhdr->MaxSignalSlots || Position == tail + || head == tail) + return 0; + + /* check if Position is between tail and head */ + if (head > tail) { + if (Position > head || Position < tail) + return 0; + } else if ((Position > head) && (Position < tail)) + return 0; + + /* copy signal from Position location to the area pointed to + * by pSignal + */ + psignal = + (char *) pqhdr + pqhdr->oSignalBase + + (Position * pqhdr->SignalSize); + MEMCPY(pSignal, psignal, pqhdr->SignalSize); + + return 1; +} + +/* + * Routine Description: + * Determine whether a signal queue is empty. + * + * Parameters: + * pChannel: (IN) points to the IO Channel + * Queue: (IN) nth Queue of the IO Channel + * + * Return value: + * 1 if the signal queue is empty, 0 otherwise. + */ +unsigned char +SignalQueueIsEmpty(pCHANNEL_HEADER pChannel, U32 Queue) +{ + pSIGNAL_QUEUE_HEADER pqhdr = + (pSIGNAL_QUEUE_HEADER) ((char *) pChannel + + pChannel->oChannelSpace) + Queue; + return pqhdr->Head == pqhdr->Tail; +} +EXPORT_SYMBOL_GPL(SignalQueueIsEmpty); + +/* + * Routine Description: + * Determine whether a signal queue is empty. + * + * Parameters: + * pChannel: (IN) points to the IO Channel + * Queue: (IN) nth Queue of the IO Channel + * + * Return value: + * 1 if the signal queue has 1 element, 0 otherwise. + */ +unsigned char +SignalQueueHasOneElement(pCHANNEL_HEADER pChannel, U32 Queue) +{ + pSIGNAL_QUEUE_HEADER pqhdr = + (pSIGNAL_QUEUE_HEADER) ((char *) pChannel + + pChannel->oChannelSpace) + Queue; + return ((pqhdr->Tail + 1) % pqhdr->MaxSignalSlots) == pqhdr->Head; +} + +/* + * Routine Description: + * Determine whether a signal queue is full. + * + * Parameters: + * pChannel: (IN) points to the IO Channel + * Queue: (IN) nth Queue of the IO Channel + * + * Return value: + * 1 if the signal queue is full, 0 otherwise. + */ +unsigned char +SignalQueueIsFull(pCHANNEL_HEADER pChannel, U32 Queue) +{ + pSIGNAL_QUEUE_HEADER pqhdr = + (pSIGNAL_QUEUE_HEADER) ((char *) pChannel + + pChannel->oChannelSpace) + Queue; + return ((pqhdr->Head + 1) % pqhdr->MaxSignalSlots) == pqhdr->Tail; +} diff --git a/drivers/staging/unisys/channels/chanstub.c b/drivers/staging/unisys/channels/chanstub.c new file mode 100644 index 00000000000..37e207d19bd --- /dev/null +++ b/drivers/staging/unisys/channels/chanstub.c @@ -0,0 +1,70 @@ +/* Copyright © 2010 - 2013 UNISYS CORPORATION + * 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. + */ + +#define EXPORT_SYMTAB +#include <linux/kernel.h> +#ifdef CONFIG_MODVERSIONS +#include <config/modversions.h> +#endif +#include <linux/module.h> +#include <linux/init.h> /* for module_init and module_exit */ +#include <linux/slab.h> /* for memcpy */ +#include <linux/types.h> + +#include "channel.h" +#include "chanstub.h" +#include "version.h" + +__init int +channel_mod_init(void) +{ + return 0; +} + +__exit void +channel_mod_exit(void) +{ +} + +unsigned char +SignalInsert_withLock(pCHANNEL_HEADER pChannel, U32 Queue, + void *pSignal, spinlock_t *lock) +{ + unsigned char result; + unsigned long flags; + spin_lock_irqsave(lock, flags); + result = SignalInsert(pChannel, Queue, pSignal); + spin_unlock_irqrestore(lock, flags); + return result; +} + +unsigned char +SignalRemove_withLock(pCHANNEL_HEADER pChannel, U32 Queue, + void *pSignal, spinlock_t *lock) +{ + unsigned char result; + spin_lock(lock); + result = SignalRemove(pChannel, Queue, pSignal); + spin_unlock(lock); + return result; +} + +module_init(channel_mod_init); +module_exit(channel_mod_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Bryan Glaudel"); +MODULE_ALIAS("uischan"); + /* this is extracted during depmod and kept in modules.dep */ diff --git a/drivers/staging/unisys/channels/chanstub.h b/drivers/staging/unisys/channels/chanstub.h new file mode 100644 index 00000000000..dadd7cd3124 --- /dev/null +++ b/drivers/staging/unisys/channels/chanstub.h @@ -0,0 +1,23 @@ +/* Copyright © 2010 - 2013 UNISYS CORPORATION + * 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. + */ + +#ifndef __CHANSTUB_H__ +#define __CHANSTUB_H__ +unsigned char SignalInsert_withLock(pCHANNEL_HEADER pChannel, U32 Queue, + void *pSignal, spinlock_t *lock); +unsigned char SignalRemove_withLock(pCHANNEL_HEADER pChannel, U32 Queue, + void *pSignal, spinlock_t *lock); + +#endif diff --git a/drivers/staging/unisys/common-spar/include/channels/channel.h b/drivers/staging/unisys/common-spar/include/channels/channel.h new file mode 100644 index 00000000000..83906b4e875 --- /dev/null +++ b/drivers/staging/unisys/common-spar/include/channels/channel.h @@ -0,0 +1,645 @@ +/* Copyright © 2010 - 2013 UNISYS CORPORATION + * 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. + */ + +#ifndef __CHANNEL_H__ +#define __CHANNEL_H__ + +/* +* Whenever this file is changed a corresponding change must be made in +* the Console/ServicePart/visordiag_early/supervisor_channel.h file +* which is needed for Linux kernel compiles. These two files must be +* in sync. +*/ + +/* define the following to prevent include nesting in kernel header + * files of similar abreviated content + */ +#define __SUPERVISOR_CHANNEL_H__ + +#include "commontypes.h" + +#define SIGNATURE_16(A, B) ((A) | (B<<8)) +#define SIGNATURE_32(A, B, C, D) \ + (SIGNATURE_16(A, B) | (SIGNATURE_16(C, D) << 16)) +#define SIGNATURE_64(A, B, C, D, E, F, G, H) \ + (SIGNATURE_32(A, B, C, D) | ((U64)(SIGNATURE_32(E, F, G, H)) << 32)) + +#ifndef lengthof +#define lengthof(TYPE, MEMBER) (sizeof(((TYPE *)0)->MEMBER)) +#endif +#ifndef COVERQ +#define COVERQ(v, d) (((v)+(d)-1) / (d)) +#endif +#ifndef COVER +#define COVER(v, d) ((d)*COVERQ(v, d)) +#endif + +#ifndef GUID0 +#define GUID0 {0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0} } +#endif + +/* The C language is inconsistent with respect to where it allows literal + * constants, especially literal constant structs. Literal constant structs + * are allowed for initialization only, whereas other types of literal + * constants are allowed anywhere. We get around this inconsistency by + * declaring a "static const" variable for each GUID. This variable can be + * used in expressions where the literal constant would not be allowed. + */ +static const GUID Guid0 = GUID0; + +#define ULTRA_CHANNEL_PROTOCOL_SIGNATURE SIGNATURE_32('E', 'C', 'N', 'L') + +typedef enum { + CHANNELSRV_UNINITIALIZED = 0, /* channel is in an undefined state */ + CHANNELSRV_READY = 1 /* channel has been initialized by server */ +} CHANNEL_SERVERSTATE; + +typedef enum { + CHANNELCLI_DETACHED = 0, + CHANNELCLI_DISABLED = 1, /* client can see channel but is NOT + * allowed to use it unless given TBD + * explicit request (should actually be + * < DETACHED) */ + CHANNELCLI_ATTACHING = 2, /* legacy EFI client request + * for EFI server to attach */ + CHANNELCLI_ATTACHED = 3, /* idle, but client may want + * to use channel any time */ + CHANNELCLI_BUSY = 4, /* client either wants to use or is + * using channel */ + CHANNELCLI_OWNED = 5 /* "no worries" state - client can + * access channel anytime */ +} CHANNEL_CLIENTSTATE; +static inline const U8 * +ULTRA_CHANNELCLI_STRING(U32 v) +{ + switch (v) { + case CHANNELCLI_DETACHED: + return (const U8 *) ("DETACHED"); + case CHANNELCLI_DISABLED: + return (const U8 *) ("DISABLED"); + case CHANNELCLI_ATTACHING: + return (const U8 *) ("ATTACHING"); + case CHANNELCLI_ATTACHED: + return (const U8 *) ("ATTACHED"); + case CHANNELCLI_BUSY: + return (const U8 *) ("BUSY"); + case CHANNELCLI_OWNED: + return (const U8 *) ("OWNED"); + default: + break; + } + return (const U8 *) ("?"); +} + +#define ULTRA_CHANNELSRV_IS_READY(x) ((x) == CHANNELSRV_READY) +#define ULTRA_CHANNEL_SERVER_READY(pChannel) \ + (ULTRA_CHANNELSRV_IS_READY((pChannel)->SrvState)) + +#define ULTRA_VALID_CHANNELCLI_TRANSITION(o, n) \ + (((((o) == CHANNELCLI_DETACHED) && ((n) == CHANNELCLI_DISABLED)) || \ + (((o) == CHANNELCLI_ATTACHING) && ((n) == CHANNELCLI_DISABLED)) || \ + (((o) == CHANNELCLI_ATTACHED) && ((n) == CHANNELCLI_DISABLED)) || \ + (((o) == CHANNELCLI_ATTACHING) && ((n) == CHANNELCLI_DETACHED)) || \ + (((o) == CHANNELCLI_ATTACHED) && ((n) == CHANNELCLI_DETACHED)) || \ + (((o) == CHANNELCLI_DETACHED) && ((n) == CHANNELCLI_ATTACHING)) || \ + (((o) == CHANNELCLI_ATTACHING) && ((n) == CHANNELCLI_ATTACHED)) || \ + (((o) == CHANNELCLI_DETACHED) && ((n) == CHANNELCLI_ATTACHED)) || \ + (((o) == CHANNELCLI_BUSY) && ((n) == CHANNELCLI_ATTACHED)) || \ + (((o) == CHANNELCLI_ATTACHED) && ((n) == CHANNELCLI_BUSY)) || \ + (((o) == CHANNELCLI_DETACHED) && ((n) == CHANNELCLI_OWNED)) || \ + (((o) == CHANNELCLI_DISABLED) && ((n) == CHANNELCLI_OWNED)) || \ + (((o) == CHANNELCLI_ATTACHING) && ((n) == CHANNELCLI_OWNED)) || \ + (((o) == CHANNELCLI_ATTACHED) && ((n) == CHANNELCLI_OWNED)) || \ + (((o) == CHANNELCLI_BUSY) && ((n) == CHANNELCLI_OWNED)) || (0)) \ + ? (1) : (0)) + +#define ULTRA_CHANNEL_CLIENT_CHK_TRANSITION(old, new, chanId, logCtx, \ + file, line) \ + do { \ + if (!ULTRA_VALID_CHANNELCLI_TRANSITION(old, new)) \ + UltraLogEvent(logCtx, \ + CHANNELSTATE_DIAG_EVENTID_TRANSITERR, \ + CHANNELSTATE_DIAG_SEVERITY, \ + CHANNELSTATE_DIAG_SUBSYS, \ + __func__, __LINE__, \ + "%s Channel StateTransition INVALID! (%s) %s(%d)-->%s(%d) @%s:%d\n", \ + chanId, "CliState<x>", \ + ULTRA_CHANNELCLI_STRING(old), \ + old, \ + ULTRA_CHANNELCLI_STRING(new), \ + new, \ + PathName_Last_N_Nodes((U8 *)file, 4), \ + line); \ + } while (0) + +#define ULTRA_CHANNEL_CLIENT_TRANSITION(pChan, chanId, field, \ + newstate, logCtx) \ + do { \ + ULTRA_CHANNEL_CLIENT_CHK_TRANSITION( \ + (((CHANNEL_HEADER *)(pChan))->field), newstate, \ + chanId, logCtx, __FILE__, __LINE__); \ + UltraLogEvent(logCtx, CHANNELSTATE_DIAG_EVENTID_TRANSITOK, \ + CHANNELSTATE_DIAG_SEVERITY, \ + CHANNELSTATE_DIAG_SUBSYS, \ + __func__, __LINE__, \ + "%s Channel StateTransition (%s) %s(%d)-->%s(%d) @%s:%d\n", \ + chanId, #field, \ + ULTRA_CHANNELCLI_STRING(((CHANNEL_HEADER *) \ + (pChan))->field), \ + ((CHANNEL_HEADER *)(pChan))->field, \ + ULTRA_CHANNELCLI_STRING(newstate), \ + newstate, \ + PathName_Last_N_Nodes(__FILE__, 4), __LINE__); \ + ((CHANNEL_HEADER *)(pChan))->field = newstate; \ + MEMORYBARRIER; \ + } while (0) + +#define ULTRA_CHANNEL_CLIENT_ACQUIRE_OS(pChan, chanId, logCtx) \ + ULTRA_channel_client_acquire_os(pChan, chanId, logCtx, \ + (char *)__FILE__, __LINE__, \ + (char *)__func__) +#define ULTRA_CHANNEL_CLIENT_RELEASE_OS(pChan, chanId, logCtx) \ + ULTRA_channel_client_release_os(pChan, chanId, logCtx, \ + (char *)__FILE__, __LINE__, (char *)__func__) + +/* Values for ULTRA_CHANNEL_PROTOCOL.CliErrorBoot: */ +/* throttling invalid boot channel statetransition error due to client + * disabled */ +#define ULTRA_CLIERRORBOOT_THROTTLEMSG_DISABLED 0x01 + +/* throttling invalid boot channel statetransition error due to client + * not attached */ +#define ULTRA_CLIERRORBOOT_THROTTLEMSG_NOTATTACHED 0x02 + +/* throttling invalid boot channel statetransition error due to busy channel */ +#define ULTRA_CLIERRORBOOT_THROTTLEMSG_BUSY 0x04 + +/* Values for ULTRA_CHANNEL_PROTOCOL.CliErrorOS: */ +/* throttling invalid guest OS channel statetransition error due to + * client disabled */ +#define ULTRA_CLIERROROS_THROTTLEMSG_DISABLED 0x01 + +/* throttling invalid guest OS channel statetransition error due to + * client not attached */ +#define ULTRA_CLIERROROS_THROTTLEMSG_NOTATTACHED 0x02 + +/* throttling invalid guest OS channel statetransition error due to + * busy channel */ +#define ULTRA_CLIERROROS_THROTTLEMSG_BUSY 0x04 + +/* Values for ULTRA_CHANNEL_PROTOCOL.Features: This define exists so +* that windows guest can look at the FeatureFlags in the io channel, +* and configure the windows driver to use interrupts or not based on +* this setting. This flag is set in uislib after the +* ULTRA_VHBA_init_channel is called. All feature bits for all +* channels should be defined here. The io channel feature bits are +* defined right here */ +#define ULTRA_IO_DRIVER_ENABLES_INTS (0x1ULL << 1) +#define ULTRA_IO_CHANNEL_IS_POLLING (0x1ULL << 3) +#define ULTRA_IO_IOVM_IS_OK_WITH_DRIVER_DISABLING_INTS (0x1ULL << 4) +#define ULTRA_IO_DRIVER_DISABLES_INTS (0x1ULL << 5) +#define ULTRA_IO_DRIVER_SUPPORTS_ENHANCED_RCVBUF_CHECKING (0x1ULL << 6) + +#pragma pack(push, 1) /* both GCC and VC now allow this pragma */ +/* Common Channel Header */ +typedef struct _CHANNEL_HEADER { + U64 Signature; /* Signature */ + U32 LegacyState; /* DEPRECATED - being replaced by */ + /* / SrvState, CliStateBoot, and CliStateOS below */ + U32 HeaderSize; /* sizeof(CHANNEL_HEADER) */ + U64 Size; /* Total size of this channel in bytes */ + U64 Features; /* Flags to modify behavior */ + GUID Type; /* Channel type: data, bus, control, etc. */ + U64 PartitionHandle; /* ID of guest partition */ + U64 Handle; /* Device number of this channel in client */ + U64 oChannelSpace; /* Offset in bytes to channel specific area */ + U32 VersionId; /* CHANNEL_HEADER Version ID */ + U32 PartitionIndex; /* Index of guest partition */ + GUID ZoneGuid; /* Guid of Channel's zone */ + U32 oClientString; /* offset from channel header to + * nul-terminated ClientString (0 if + * ClientString not present) */ + U32 CliStateBoot; /* CHANNEL_CLIENTSTATE of pre-boot + * EFI client of this channel */ + U32 CmdStateCli; /* CHANNEL_COMMANDSTATE (overloaded in + * Windows drivers, see ServerStateUp, + * ServerStateDown, etc) */ + U32 CliStateOS; /* CHANNEL_CLIENTSTATE of Guest OS + * client of this channel */ + U32 ChannelCharacteristics; /* CHANNEL_CHARACTERISTIC_<xxx> */ + U32 CmdStateSrv; /* CHANNEL_COMMANDSTATE (overloaded in + * Windows drivers, see ServerStateUp, + * ServerStateDown, etc) */ + U32 SrvState; /* CHANNEL_SERVERSTATE */ + U8 CliErrorBoot; /* bits to indicate err states for + * boot clients, so err messages can + * be throttled */ + U8 CliErrorOS; /* bits to indicate err states for OS + * clients, so err messages can be + * throttled */ + U8 Filler[1]; /* Pad out to 128 byte cacheline */ + /* Please add all new single-byte values below here */ + U8 RecoverChannel; +} CHANNEL_HEADER, *pCHANNEL_HEADER, ULTRA_CHANNEL_PROTOCOL; + +#define ULTRA_CHANNEL_ENABLE_INTS (0x1ULL << 0) + +/* Subheader for the Signal Type variation of the Common Channel */ +typedef struct _SIGNAL_QUEUE_HEADER { + /* 1st cache line */ + U32 VersionId; /* SIGNAL_QUEUE_HEADER Version ID */ + U32 Type; /* Queue type: storage, network */ + U64 Size; /* Total size of this queue in bytes */ + U64 oSignalBase; /* Offset to signal queue area */ + U64 FeatureFlags; /* Flags to modify behavior */ + U64 NumSignalsSent; /* Total # of signals placed in this queue */ + U64 NumOverflows; /* Total # of inserts failed due to + * full queue */ + U32 SignalSize; /* Total size of a signal for this queue */ + U32 MaxSignalSlots; /* Max # of slots in queue, 1 slot is + * always empty */ + U32 MaxSignals; /* Max # of signals in queue + * (MaxSignalSlots-1) */ + U32 Head; /* Queue head signal # */ + /* 2nd cache line */ + U64 NumSignalsReceived; /* Total # of signals removed from this queue */ + U32 Tail; /* Queue tail signal # (on separate + * cache line) */ + U32 Reserved1; /* Reserved field */ + U64 Reserved2; /* Resrved field */ + U64 ClientQueue; + U64 NumInterruptsReceived; /* Total # of Interrupts received. This + * is incremented by the ISR in the + * guest windows driver */ + U64 NumEmptyCnt; /* Number of times that SignalRemove + * is called and returned Empty + * Status. */ + U32 ErrorFlags; /* Error bits set during SignalReinit + * to denote trouble with client's + * fields */ + U8 Filler[12]; /* Pad out to 64 byte cacheline */ +} SIGNAL_QUEUE_HEADER, *pSIGNAL_QUEUE_HEADER; + +#pragma pack(pop) + +#define SignalInit(chan, QHDRFLD, QDATAFLD, QDATATYPE, ver, typ) \ + do { \ + MEMSET(&chan->QHDRFLD, 0, sizeof(chan->QHDRFLD)); \ + chan->QHDRFLD.VersionId = ver; \ + chan->QHDRFLD.Type = typ; \ + chan->QHDRFLD.Size = sizeof(chan->QDATAFLD); \ + chan->QHDRFLD.SignalSize = sizeof(QDATATYPE); \ + chan->QHDRFLD.oSignalBase = (UINTN)(chan->QDATAFLD)- \ + (UINTN)(&chan->QHDRFLD); \ + chan->QHDRFLD.MaxSignalSlots = \ + sizeof(chan->QDATAFLD)/sizeof(QDATATYPE); \ + chan->QHDRFLD.MaxSignals = chan->QHDRFLD.MaxSignalSlots-1; \ + } while (0) + +/* Generic function useful for validating any type of channel when it is + * received by the client that will be accessing the channel. + * Note that <logCtx> is only needed for callers in the EFI environment, and + * is used to pass the EFI_DIAG_CAPTURE_PROTOCOL needed to log messages. + */ +static inline int +ULTRA_check_channel_client(void *pChannel, + GUID expectedTypeGuid, + char *channelName, + U64 expectedMinBytes, + U32 expectedVersionId, + U64 expectedSignature, + char *fileName, int lineNumber, void *logCtx) +{ + if (MEMCMP(&expectedTypeGuid, &Guid0, sizeof(GUID)) != 0) + /* caller wants us to verify type GUID */ + if (MEMCMP(&(((CHANNEL_HEADER *) (pChannel))->Type), + &expectedTypeGuid, sizeof(GUID)) != 0) { + CHANNEL_GUID_MISMATCH(expectedTypeGuid, channelName, + "type", expectedTypeGuid, + ((CHANNEL_HEADER *) + (pChannel))->Type, fileName, + lineNumber, logCtx); + return 0; + } + if (expectedMinBytes > 0) /* caller wants us to verify + * channel size */ + if (((CHANNEL_HEADER *) (pChannel))->Size < expectedMinBytes) { + CHANNEL_U64_MISMATCH(expectedTypeGuid, channelName, + "size", expectedMinBytes, + ((CHANNEL_HEADER *) + (pChannel))->Size, fileName, + lineNumber, logCtx); + return 0; + } + if (expectedVersionId > 0) /* caller wants us to verify + * channel version */ + if (((CHANNEL_HEADER *) (pChannel))->VersionId != + expectedVersionId) { + CHANNEL_U32_MISMATCH(expectedTypeGuid, channelName, + "version", expectedVersionId, + ((CHANNEL_HEADER *) + (pChannel))->VersionId, fileName, + lineNumber, logCtx); + return 0; + } + if (expectedSignature > 0) /* caller wants us to verify + * channel signature */ + if (((CHANNEL_HEADER *) (pChannel))->Signature != + expectedSignature) { + CHANNEL_U64_MISMATCH(expectedTypeGuid, channelName, + "signature", expectedSignature, + ((CHANNEL_HEADER *) + (pChannel))->Signature, fileName, + lineNumber, logCtx); + return 0; + } + return 1; +} + +/* Generic function useful for validating any type of channel when it is about + * to be initialized by the server of the channel. + * Note that <logCtx> is only needed for callers in the EFI environment, and + * is used to pass the EFI_DIAG_CAPTURE_PROTOCOL needed to log messages. + */ +static inline int +ULTRA_check_channel_server(GUID typeGuid, + char *channelName, + U64 expectedMinBytes, + U64 actualBytes, + char *fileName, int lineNumber, void *logCtx) +{ + if (expectedMinBytes > 0) /* caller wants us to verify + * channel size */ + if (actualBytes < expectedMinBytes) { + CHANNEL_U64_MISMATCH(typeGuid, channelName, "size", + expectedMinBytes, actualBytes, + fileName, lineNumber, logCtx); + return 0; + } + return 1; +} + +/* Given a file pathname <s> (with '/' or '\' separating directory nodes), + * returns a pointer to the beginning of a node within that pathname such + * that the number of nodes from that pointer to the end of the string is + * NOT more than <n>. Note that if the pathname has less than <n> nodes + * in it, the return pointer will be to the beginning of the string. + */ +static inline U8 * +PathName_Last_N_Nodes(U8 *s, unsigned int n) +{ + U8 *p = s; + unsigned int node_count = 0; + while (*p != '\0') { + if ((*p == '/') || (*p == '\\')) + node_count++; + p++; + } + if (node_count <= n) + return s; + while (n > 0) { + p--; + if (p == s) + break; /* should never happen, unless someone + * is changing the string while we are + * looking at it!! */ + if ((*p == '/') || (*p == '\\')) + n--; + } + return p + 1; +} + +static inline int +ULTRA_channel_client_acquire_os(void *pChannel, U8 *chanId, void *logCtx, + char *file, int line, char *func) +{ + CHANNEL_HEADER *pChan = (CHANNEL_HEADER *) (pChannel); + + if (pChan->CliStateOS == CHANNELCLI_DISABLED) { + if ((pChan-> + CliErrorOS & ULTRA_CLIERROROS_THROTTLEMSG_DISABLED) == 0) { + /* we are NOT throttling this message */ + pChan->CliErrorOS |= + ULTRA_CLIERROROS_THROTTLEMSG_DISABLED; + /* throttle until acquire successful */ + + UltraLogEvent(logCtx, + CHANNELSTATE_DIAG_EVENTID_TRANSITERR, + CHANNELSTATE_DIAG_SEVERITY, + CHANNELSTATE_DIAG_SUBSYS, func, line, + "%s Channel StateTransition INVALID! - acquire failed because OS client DISABLED @%s:%d\n", + chanId, PathName_Last_N_Nodes( + (U8 *) file, 4), line); + } + return 0; + } + if ((pChan->CliStateOS != CHANNELCLI_OWNED) + && (pChan->CliStateBoot == CHANNELCLI_DISABLED)) { + /* Our competitor is DISABLED, so we can transition to OWNED */ + UltraLogEvent(logCtx, CHANNELSTATE_DIAG_EVENTID_TRANSITOK, + CHANNELSTATE_DIAG_SEVERITY, + CHANNELSTATE_DIAG_SUBSYS, func, line, + "%s Channel StateTransition (%s) %s(%d)-->%s(%d) @%s:%d\n", + chanId, "CliStateOS", + ULTRA_CHANNELCLI_STRING(pChan->CliStateOS), + pChan->CliStateOS, + ULTRA_CHANNELCLI_STRING(CHANNELCLI_OWNED), + CHANNELCLI_OWNED, + PathName_Last_N_Nodes((U8 *) file, 4), line); + pChan->CliStateOS = CHANNELCLI_OWNED; + MEMORYBARRIER; + } + if (pChan->CliStateOS == CHANNELCLI_OWNED) { + if (pChan->CliErrorOS != 0) { + /* we are in an error msg throttling state; + * come out of it */ + UltraLogEvent(logCtx, + CHANNELSTATE_DIAG_EVENTID_TRANSITOK, + CHANNELSTATE_DIAG_SEVERITY, + CHANNELSTATE_DIAG_SUBSYS, func, line, + "%s Channel OS client acquire now successful @%s:%d\n", + chanId, PathName_Last_N_Nodes((U8 *) file, + 4), line); + pChan->CliErrorOS = 0; + } + return 1; + } + + /* We have to do it the "hard way". We transition to BUSY, + * and can use the channel iff our competitor has not also + * transitioned to BUSY. */ + if (pChan->CliStateOS != CHANNELCLI_ATTACHED) { + if ((pChan-> + CliErrorOS & ULTRA_CLIERROROS_THROTTLEMSG_NOTATTACHED) == + 0) { + /* we are NOT throttling this message */ + pChan->CliErrorOS |= + ULTRA_CLIERROROS_THROTTLEMSG_NOTATTACHED; + /* throttle until acquire successful */ + UltraLogEvent(logCtx, + CHANNELSTATE_DIAG_EVENTID_TRANSITERR, + CHANNELSTATE_DIAG_SEVERITY, + CHANNELSTATE_DIAG_SUBSYS, func, line, + "%s Channel StateTransition INVALID! - acquire failed because OS client NOT ATTACHED (state=%s(%d)) @%s:%d\n", + chanId, + ULTRA_CHANNELCLI_STRING(pChan->CliStateOS), + pChan->CliStateOS, + PathName_Last_N_Nodes((U8 *) file, 4), + line); + } + return 0; + } + pChan->CliStateOS = CHANNELCLI_BUSY; + MEMORYBARRIER; + if (pChan->CliStateBoot == CHANNELCLI_BUSY) { + if ((pChan->CliErrorOS & ULTRA_CLIERROROS_THROTTLEMSG_BUSY) == + 0) { + /* we are NOT throttling this message */ + pChan->CliErrorOS |= ULTRA_CLIERROROS_THROTTLEMSG_BUSY; + /* throttle until acquire successful */ + UltraLogEvent(logCtx, + CHANNELSTATE_DIAG_EVENTID_TRANSITBUSY, + CHANNELSTATE_DIAG_SEVERITY, + CHANNELSTATE_DIAG_SUBSYS, func, line, + "%s Channel StateTransition failed - host OS acquire failed because boot BUSY @%s:%d\n", + chanId, PathName_Last_N_Nodes((U8 *) file, + 4), line); + } + pChan->CliStateOS = CHANNELCLI_ATTACHED; /* reset busy */ + MEMORYBARRIER; + return 0; + } + if (pChan->CliErrorOS != 0) { + /* we are in an error msg throttling state; come out of it */ + UltraLogEvent(logCtx, CHANNELSTATE_DIAG_EVENTID_TRANSITOK, + CHANNELSTATE_DIAG_SEVERITY, + CHANNELSTATE_DIAG_SUBSYS, func, line, + "%s Channel OS client acquire now successful @%s:%d\n", + chanId, PathName_Last_N_Nodes((U8 *) file, 4), + line); + pChan->CliErrorOS = 0; + } + return 1; +} + +static inline void +ULTRA_channel_client_release_os(void *pChannel, U8 *chanId, void *logCtx, + char *file, int line, char *func) +{ + CHANNEL_HEADER *pChan = (CHANNEL_HEADER *) (pChannel); + if (pChan->CliErrorOS != 0) { + /* we are in an error msg throttling state; come out of it */ + UltraLogEvent(logCtx, CHANNELSTATE_DIAG_EVENTID_TRANSITOK, + CHANNELSTATE_DIAG_SEVERITY, + CHANNELSTATE_DIAG_SUBSYS, func, line, + "%s Channel OS client error state cleared @%s:%d\n", + chanId, PathName_Last_N_Nodes((U8 *) file, 4), + line); + pChan->CliErrorOS = 0; + } + if (pChan->CliStateOS == CHANNELCLI_OWNED) + return; + if (pChan->CliStateOS != CHANNELCLI_BUSY) { + UltraLogEvent(logCtx, CHANNELSTATE_DIAG_EVENTID_TRANSITERR, + CHANNELSTATE_DIAG_SEVERITY, + CHANNELSTATE_DIAG_SUBSYS, func, line, + "%s Channel StateTransition INVALID! - release failed because OS client NOT BUSY (state=%s(%d)) @%s:%d\n", + chanId, + ULTRA_CHANNELCLI_STRING(pChan->CliStateOS), + pChan->CliStateOS, + PathName_Last_N_Nodes((U8 *) file, 4), line); + /* return; */ + } + pChan->CliStateOS = CHANNELCLI_ATTACHED; /* release busy */ +} + +/* +* Routine Description: +* Tries to insert the prebuilt signal pointed to by pSignal into the nth +* Queue of the Channel pointed to by pChannel +* +* Parameters: +* pChannel: (IN) points to the IO Channel +* Queue: (IN) nth Queue of the IO Channel +* pSignal: (IN) pointer to the signal +* +* Assumptions: +* - pChannel, Queue and pSignal are valid. +* - If insertion fails due to a full queue, the caller will determine the +* retry policy (e.g. wait & try again, report an error, etc.). +* +* Return value: 1 if the insertion succeeds, 0 if the queue was +* full. +*/ + +unsigned char SignalInsert(pCHANNEL_HEADER pChannel, U32 Queue, void *pSignal); + +/* +* Routine Description: +* Removes one signal from Channel pChannel's nth Queue at the +* time of the call and copies it into the memory pointed to by +* pSignal. +* +* Parameters: +* pChannel: (IN) points to the IO Channel +* Queue: (IN) nth Queue of the IO Channel +* pSignal: (IN) pointer to where the signals are to be copied +* +* Assumptions: +* - pChannel and Queue are valid. +* - pSignal points to a memory area large enough to hold queue's SignalSize +* +* Return value: 1 if the removal succeeds, 0 if the queue was +* empty. +*/ + +unsigned char SignalRemove(pCHANNEL_HEADER pChannel, U32 Queue, void *pSignal); + +/* +* Routine Description: +* Removes all signals present in Channel pChannel's nth Queue at the +* time of the call and copies them into the memory pointed to by +* pSignal. Returns the # of signals copied as the value of the routine. +* +* Parameters: +* pChannel: (IN) points to the IO Channel +* Queue: (IN) nth Queue of the IO Channel +* pSignal: (IN) pointer to where the signals are to be copied +* +* Assumptions: +* - pChannel and Queue are valid. +* - pSignal points to a memory area large enough to hold Queue's MaxSignals +* # of signals, each of which is Queue's SignalSize. +* +* Return value: +* # of signals copied. +*/ +unsigned int SignalRemoveAll(pCHANNEL_HEADER pChannel, U32 Queue, + void *pSignal); + +/* +* Routine Description: +* Determine whether a signal queue is empty. +* +* Parameters: +* pChannel: (IN) points to the IO Channel +* Queue: (IN) nth Queue of the IO Channel +* +* Return value: +* 1 if the signal queue is empty, 0 otherwise. +*/ +unsigned char SignalQueueIsEmpty(pCHANNEL_HEADER pChannel, U32 Queue); + +#endif diff --git a/drivers/staging/unisys/common-spar/include/channels/channel_guid.h b/drivers/staging/unisys/common-spar/include/channels/channel_guid.h new file mode 100644 index 00000000000..ae0dc2b2ad1 --- /dev/null +++ b/drivers/staging/unisys/common-spar/include/channels/channel_guid.h @@ -0,0 +1,64 @@ +/* Copyright © 2010 - 2013 UNISYS CORPORATION + * 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. + */ + +/* + * CHANNEL Guids + */ + +/* Used in IOChannel + * {414815ed-c58c-11da-95a9-00e08161165f} + */ +#define ULTRA_VHBA_CHANNEL_PROTOCOL_GUID \ + { 0x414815ed, 0xc58c, 0x11da, \ + { 0x95, 0xa9, 0x0, 0xe0, 0x81, 0x61, 0x16, 0x5f } } +static const GUID UltraVhbaChannelProtocolGuid = + ULTRA_VHBA_CHANNEL_PROTOCOL_GUID; + +/* Used in IOChannel + * {8cd5994d-c58e-11da-95a9-00e08161165f} + */ +#define ULTRA_VNIC_CHANNEL_PROTOCOL_GUID \ + { 0x8cd5994d, 0xc58e, 0x11da, \ + { 0x95, 0xa9, 0x0, 0xe0, 0x81, 0x61, 0x16, 0x5f } } +static const GUID UltraVnicChannelProtocolGuid = + ULTRA_VNIC_CHANNEL_PROTOCOL_GUID; + +/* Used in IOChannel + * {72120008-4AAB-11DC-8530-444553544200} + */ +#define ULTRA_SIOVM_GUID \ + { 0x72120008, 0x4AAB, 0x11DC, \ + { 0x85, 0x30, 0x44, 0x45, 0x53, 0x54, 0x42, 0x00 } } +static const GUID UltraSIOVMGuid = ULTRA_SIOVM_GUID; + + +/* Used in visornoop/visornoop_main.c + * {5b52c5ac-e5f5-4d42-8dff-429eaecd221f} + */ +#define ULTRA_CONTROLDIRECTOR_CHANNEL_PROTOCOL_GUID \ + { 0x5b52c5ac, 0xe5f5, 0x4d42, \ + { 0x8d, 0xff, 0x42, 0x9e, 0xae, 0xcd, 0x22, 0x1f } } + +static const GUID UltraControlDirectorChannelProtocolGuid = + ULTRA_CONTROLDIRECTOR_CHANNEL_PROTOCOL_GUID; + +/* Used in visorchipset/visorchipset_main.c + * {B4E79625-AEDE-4EAA-9E11-D3EDDCD4504C} + */ +#define ULTRA_DIAG_POOL_CHANNEL_PROTOCOL_GUID \ + {0xb4e79625, 0xaede, 0x4eaa, \ + { 0x9e, 0x11, 0xd3, 0xed, 0xdc, 0xd4, 0x50, 0x4c } } + + diff --git a/drivers/staging/unisys/common-spar/include/channels/controlframework.h b/drivers/staging/unisys/common-spar/include/channels/controlframework.h new file mode 100644 index 00000000000..51264334834 --- /dev/null +++ b/drivers/staging/unisys/common-spar/include/channels/controlframework.h @@ -0,0 +1,77 @@ +/* Copyright © 2010 - 2013 UNISYS CORPORATION + * 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. + */ + +/* + * Module Name: + * controlframework.h + * + * Abstract: This file defines common structures in the unmanaged + * Ultravisor (mostly EFI) space. + * + */ + +#ifndef _CONTROL_FRAMEWORK_H_ +#define _CONTROL_FRAMEWORK_H_ + +#include "commontypes.h" +#include "channel.h" + +#define ULTRA_MEMORY_COUNT_Ki 1024 + +/* Scale order 0 is one 32-bit (4-byte) word (in 64 or 128-bit + * architecture potentially 64 or 128-bit word) */ +#define ULTRA_MEMORY_PAGE_WORD 4 + +/* Define Ki scale page to be traditional 4KB page */ +#define ULTRA_MEMORY_PAGE_Ki (ULTRA_MEMORY_PAGE_WORD * ULTRA_MEMORY_COUNT_Ki) +typedef struct _ULTRA_SEGMENT_STATE { + U16 Enabled:1; /* Bit 0: May enter other states */ + U16 Active:1; /* Bit 1: Assigned to active partition */ + U16 Alive:1; /* Bit 2: Configure message sent to + * service/server */ + U16 Revoked:1; /* Bit 3: similar to partition state + * ShuttingDown */ + U16 Allocated:1; /* Bit 4: memory (device/port number) + * has been selected by Command */ + U16 Known:1; /* Bit 5: has been introduced to the + * service/guest partition */ + U16 Ready:1; /* Bit 6: service/Guest partition has + * responded to introduction */ + U16 Operating:1; /* Bit 7: resource is configured and + * operating */ + /* Note: don't use high bit unless we need to switch to ushort + * which is non-compliant */ +} ULTRA_SEGMENT_STATE; +static const ULTRA_SEGMENT_STATE SegmentStateRunning = { + 1, 1, 1, 0, 1, 1, 1, 1 +}; +static const ULTRA_SEGMENT_STATE SegmentStatePaused = { + 1, 1, 1, 0, 1, 1, 1, 0 +}; +static const ULTRA_SEGMENT_STATE SegmentStateStandby = { + 1, 1, 0, 0, 1, 1, 1, 0 +}; +typedef union { + U64 Full; + struct { + U8 Major; /* will be 1 for the first release and + * increment thereafter */ + U8 Minor; + U16 Maintenance; + U32 Revision; /* Subversion revision */ + } Part; +} ULTRA_COMPONENT_VERSION; + +#endif /* _CONTROL_FRAMEWORK_H_ not defined */ diff --git a/drivers/staging/unisys/common-spar/include/channels/controlvmchannel.h b/drivers/staging/unisys/common-spar/include/channels/controlvmchannel.h new file mode 100644 index 00000000000..47f1c4fa1e7 --- /dev/null +++ b/drivers/staging/unisys/common-spar/include/channels/controlvmchannel.h @@ -0,0 +1,619 @@ +/* Copyright © 2010 - 2013 UNISYS CORPORATION + * 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. + */ + +#ifndef __CONTROLVMCHANNEL_H__ +#define __CONTROLVMCHANNEL_H__ + +#include "commontypes.h" +#include "channel.h" +#include "controlframework.h" +enum { INVALID_GUEST_FIRMWARE, SAMPLE_GUEST_FIRMWARE, + TIANO32_GUEST_FIRMWARE, TIANO64_GUEST_FIRMWARE +}; + +/* {2B3C2D10-7EF5-4ad8-B966-3448B7386B3D} */ +#define ULTRA_CONTROLVM_CHANNEL_PROTOCOL_GUID \ + {0x2b3c2d10, 0x7ef5, 0x4ad8, \ + {0xb9, 0x66, 0x34, 0x48, 0xb7, 0x38, 0x6b, 0x3d} } + +static const GUID UltraControlvmChannelProtocolGuid = + ULTRA_CONTROLVM_CHANNEL_PROTOCOL_GUID; + +#define ULTRA_CONTROLVM_CHANNEL_PROTOCOL_SIGNATURE \ + ULTRA_CHANNEL_PROTOCOL_SIGNATURE +#define CONTROLVM_MESSAGE_MAX 64 + +/* Must increment this whenever you insert or delete fields within +* this channel struct. Also increment whenever you change the meaning +* of fields within this channel struct so as to break pre-existing +* software. Note that you can usually add fields to the END of the +* channel struct withOUT needing to increment this. */ +#define ULTRA_CONTROLVM_CHANNEL_PROTOCOL_VERSIONID 1 + +#define ULTRA_CONTROLVM_CHANNEL_OK_CLIENT(pChannel, logCtx) \ + (ULTRA_check_channel_client(pChannel, \ + UltraControlvmChannelProtocolGuid, \ + "controlvm", \ + sizeof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL), \ + ULTRA_CONTROLVM_CHANNEL_PROTOCOL_VERSIONID, \ + ULTRA_CONTROLVM_CHANNEL_PROTOCOL_SIGNATURE, \ + __FILE__, __LINE__, logCtx)) +#define ULTRA_CONTROLVM_CHANNEL_OK_SERVER(actualBytes, logCtx) \ + (ULTRA_check_channel_server(UltraControlvmChannelProtocolGuid, \ + "controlvm", \ + sizeof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL), \ + actualBytes, __FILE__, __LINE__, logCtx)) + +#define MY_DEVICE_INDEX 0 +#define MAX_MACDATA_LEN 8 /* number of bytes for MAC address in config packet */ +#define MAX_SERIAL_NUM 32 + +#define DISK_ZERO_PUN_NUMBER 1 /* Target ID on the SCSI bus for LUN 0 */ +#define DISK_ZERO_LUN_NUMBER 3 /* Logical Unit Number */ + +/* Defines for various channel queues... */ +#define CONTROLVM_QUEUE_REQUEST 0 +#define CONTROLVM_QUEUE_RESPONSE 1 +#define CONTROLVM_QUEUE_EVENT 2 +#define CONTROLVM_QUEUE_ACK 3 + +/* Max number of messages stored during IOVM creation to be reused + * after crash */ +#define CONTROLVM_CRASHMSG_MAX 2 + +/** Ids for commands that may appear in either queue of a ControlVm channel. + * + * Commands that are initiated by the command partition (CP), by an IO or + * console service partition (SP), or by a guest partition (GP)are: + * - issued on the RequestQueue queue (q #0) in the ControlVm channel + * - responded to on the ResponseQueue queue (q #1) in the ControlVm channel + * + * Events that are initiated by an IO or console service partition (SP) or + * by a guest partition (GP) are: + * - issued on the EventQueue queue (q #2) in the ControlVm channel + * - responded to on the EventAckQueue queue (q #3) in the ControlVm channel + */ +typedef enum { + CONTROLVM_INVALID = 0, + /* SWITCH commands required Parameter: SwitchNumber */ + /* BUS commands required Parameter: BusNumber */ + CONTROLVM_BUS_CREATE = 0x101, /* CP --> SP, GP */ + CONTROLVM_BUS_DESTROY = 0x102, /* CP --> SP, GP */ + CONTROLVM_BUS_CONFIGURE = 0x104, /* CP --> SP */ + CONTROLVM_BUS_CHANGESTATE = 0x105, /* CP --> SP, GP */ + CONTROLVM_BUS_CHANGESTATE_EVENT = 0x106, /* SP, GP --> CP */ +/* DEVICE commands required Parameter: BusNumber, DeviceNumber */ + + CONTROLVM_DEVICE_CREATE = 0x201, /* CP --> SP, GP */ + CONTROLVM_DEVICE_DESTROY = 0x202, /* CP --> SP, GP */ + CONTROLVM_DEVICE_CONFIGURE = 0x203, /* CP --> SP */ + CONTROLVM_DEVICE_CHANGESTATE = 0x204, /* CP --> SP, GP */ + CONTROLVM_DEVICE_CHANGESTATE_EVENT = 0x205, /* SP, GP --> CP */ + CONTROLVM_DEVICE_RECONFIGURE = 0x206, /* CP --> Boot */ +/* DISK commands required Parameter: BusNumber, DeviceNumber */ + CONTROLVM_DISK_CREATE = 0x221, /* CP --> SP */ + CONTROLVM_DISK_DESTROY = 0x222, /* CP --> SP */ + CONTROLVM_DISK_CONFIGURE = 0x223, /* CP --> SP */ + CONTROLVM_DISK_CHANGESTATE = 0x224, /* CP --> SP */ +/* CHIPSET commands */ + CONTROLVM_CHIPSET_INIT = 0x301, /* CP --> SP, GP */ + CONTROLVM_CHIPSET_STOP = 0x302, /* CP --> SP, GP */ + CONTROLVM_CHIPSET_SHUTDOWN = 0x303, /* CP --> SP */ + CONTROLVM_CHIPSET_READY = 0x304, /* CP --> SP */ + CONTROLVM_CHIPSET_SELFTEST = 0x305, /* CP --> SP */ + +} CONTROLVM_ID; + +struct InterruptInfo { + /**< specifies interrupt info. It is used to send interrupts + * for this channel. The peer at the end of this channel + * who has registered an interrupt (using recv fields + * above) will receive the interrupt. Passed as a parameter + * to Issue_VMCALL_IO_QUEUE_TRANSITION, which generates the + * interrupt. Currently this is used by IOPart-SP to wake + * up GP when Data Channel transitions from empty to + * non-empty.*/ + U64 sendInterruptHandle; + + /**< specifies interrupt handle. It is used to retrieve the + * corresponding interrupt pin from Monitor; and the + * interrupt pin is used to connect to the corresponding + * intrrupt. Used by IOPart-GP only. */ + U64 recvInterruptHandle; + + /**< specifies interrupt vector. It, interrupt pin, and shared are + * used to connect to the corresponding interrupt. Used by + * IOPart-GP only. */ + U32 recvInterruptVector; + + /**< specifies if the recvInterrupt is shared. It, interrupt pin + * and vector are used to connect to 0 = not shared; 1 = shared. + * the corresponding interrupt. Used by IOPart-GP only. */ + U8 recvInterruptShared; + U8 reserved[3]; /* Natural alignment purposes */ +}; + +struct PciId { + U16 Domain; + U8 Bus; + U8 Slot; + U8 Func; + U8 Reserved[3]; /* Natural alignment purposes */ +}; + +struct PciConfigHdr { + U16 VendorId; + U16 SubSysVendor; + U16 DeviceId; + U16 SubSysDevice; + U32 ClassCode; + U32 Reserved; /* Natural alignment purposes */ +}; + +struct ScsiId { + U32 Bus; + U32 Target; + U32 Lun; + U32 Host; /* Command should ignore this for * + * DiskArrival/RemovalEvents */ +}; + +struct WWID { + U32 wwid1; + U32 wwid2; +}; + +struct virtDiskInfo { + U32 switchNo; /* defined by SWITCH_CREATE */ + U32 externalPortNo; /* 0 for SAS RAID provided (external) + * virtual disks, 1 for virtual disk + * images, 2 for gold disk images */ + U16 VirtualDiskIndex; /* Index of disk descriptor in the + * VirtualDisk segment associated with + * externalPortNo */ + U16 Reserved1; + U32 Reserved2; +}; + +typedef enum { + CONTROLVM_ACTION_NONE = 0, + CONTROLVM_ACTION_SET_RESTORE = 0x05E7, + CONTROLVM_ACTION_CLEAR_RESTORE = 0x0C18, + CONTROLVM_ACTION_RESTORING = 0x08E5, + CONTROLVM_ACTION_RESTORE_BUSY = 0x0999, + CONTROLVM_ACTION_CLEAR_NVRAM = 0xB01 +} CONTROLVM_ACTION; + +typedef enum _ULTRA_TOOL_ACTIONS { + /* enumeration that defines intended action */ + ULTRA_TOOL_ACTION_NONE = 0, /* normal boot of boot disk */ + ULTRA_TOOL_ACTION_INSTALL = 1, /* install source disk(s) to boot + * disk */ + ULTRA_TOOL_ACTION_CAPTURE = 2, /* capture boot disk to target disk(s) + * as 'gold image' */ + ULTRA_TOOL_ACTION_REPAIR = 3, /* use source disk(s) to repair + * installation on boot disk */ + ULTRA_TOOL_ACTION_CLEAN = 4, /* 'scrub' virtual disk before + * releasing back to storage pool */ + ULTRA_TOOL_ACTION_UPGRADE = 5, /* upgrade to use content of images + * referenced from newer blueprint */ + ULTRA_TOOL_ACTION_DIAG = 6, /* use tool to invoke diagnostic script + * provided by blueprint */ + ULTRA_TOOL_ACTION_FAILED = 7, /* used when tool fails installation + and cannot continue */ + ULTRA_TOOL_ACTION_COUNT = 8 +} ULTRA_TOOL_ACTIONS; + +typedef struct _ULTRA_EFI_SPAR_INDICATION { + U64 BootToFirmwareUI:1; /* Bit 0: Stop in uefi ui */ + U64 ClearNvram:1; /* Bit 1: Clear NVRAM */ + U64 ClearCmos:1; /* Bit 2: Clear CMOS */ + U64 BootToTool:1; /* Bit 3: Run install tool */ + /* remaining bits are available */ +} ULTRA_EFI_SPAR_INDICATION; + +typedef enum { + ULTRA_CHIPSET_FEATURE_REPLY = 0x00000001, + ULTRA_CHIPSET_FEATURE_PARA_HOTPLUG = 0x00000002, + ULTRA_CHIPSET_FEATURE_PCIVBUS = 0x00000004 +} ULTRA_CHIPSET_FEATURE; + +/** This is the common structure that is at the beginning of every + * ControlVm message (both commands and responses) in any ControlVm + * queue. Commands are easily distinguished from responses by + * looking at the flags.response field. + */ +typedef struct _CONTROLVM_MESSAGE_HEADER { + U32 Id; /* See CONTROLVM_ID. */ + /* For requests, indicates the message type. */ + /* For responses, indicates the type of message we are responding to. */ + + U32 MessageSize; /* Includes size of this struct + size + * of message */ + U32 SegmentIndex; /* Index of segment containing Vm + * message/information */ + U32 CompletionStatus; /* Error status code or result of + * message completion */ + struct { + U32 failed:1; /**< =1 in a response to * signify + * failure */ + U32 responseExpected:1; /**< =1 in all messages that expect a + * response (Control ignores this + * bit) */ + U32 server:1; /**< =1 in all bus & device-related + * messages where the message + * receiver is to act as the bus or + * device server */ + U32 testMessage:1; /**< =1 for testing use only + * (Control and Command ignore this + * bit) */ + U32 partialCompletion:1; /**< =1 if there are forthcoming + * responses/acks associated + * with this message */ + U32 preserve:1; /**< =1 this is to let us know to + * preserve channel contents + * (for running guests)*/ + U32 writerInDiag:1; /**< =1 the DiagWriter is active in the + * Diagnostic Partition*/ + + /* remaining bits in this 32-bit word are available */ + } Flags; + U32 Reserved; /* Natural alignment */ + U64 MessageHandle; /* Identifies the particular message instance, + * and is used to match particular */ + /* request instances with the corresponding response instance. */ + U64 PayloadVmOffset; /* Offset of payload area from start of this + * instance of ControlVm segment */ + U32 PayloadMaxBytes; /* Maximum bytes allocated in payload + * area of ControlVm segment */ + U32 PayloadBytes; /* Actual number of bytes of payload + * area to copy between IO/Command; */ + /* if non-zero, there is a payload to copy. */ +} CONTROLVM_MESSAGE_HEADER; + +typedef struct _CONTROLVM_PACKET_DEVICE_CREATE { + U32 busNo; /**< bus # (0..n-1) from the msg receiver's + * perspective */ + + /* Control uses header SegmentIndex field to access bus number... */ + U32 devNo; /**< bus-relative (0..n-1) device number */ + U64 channelAddr; /**< Guest physical address of the channel, which + * can be dereferenced by the receiver + * of this ControlVm command */ + U64 channelBytes; /**< specifies size of the channel in bytes */ + GUID dataTypeGuid;/**< specifies format of data in channel */ + GUID devInstGuid; /**< instance guid for the device */ + struct InterruptInfo intr; /**< specifies interrupt information */ +} CONTROLVM_PACKET_DEVICE_CREATE; /* for CONTROLVM_DEVICE_CREATE */ + +typedef struct _CONTROLVM_PACKET_DEVICE_CONFIGURE { + U32 busNo; /**< bus # (0..n-1) from the msg + * receiver's perspective */ + + /* Control uses header SegmentIndex field to access bus number... */ + U32 devNo; /**< bus-relative (0..n-1) device number */ +} CONTROLVM_PACKET_DEVICE_CONFIGURE; /* for CONTROLVM_DEVICE_CONFIGURE */ + +typedef struct _CONTROLVM_MESSAGE_DEVICE_CREATE { + CONTROLVM_MESSAGE_HEADER Header; + CONTROLVM_PACKET_DEVICE_CREATE Packet; +} CONTROLVM_MESSAGE_DEVICE_CREATE; /* total 128 bytes */ + +typedef struct _CONTROLVM_MESSAGE_DEVICE_CONFIGURE { + CONTROLVM_MESSAGE_HEADER Header; + CONTROLVM_PACKET_DEVICE_CONFIGURE Packet; +} CONTROLVM_MESSAGE_DEVICE_CONFIGURE; /* total 56 bytes */ + +/* This is the format for a message in any ControlVm queue. */ +typedef struct _CONTROLVM_MESSAGE_PACKET { + union { + + /* BEGIN Request messages */ + struct { + U32 busNo; /*< bus # (0..n-1) from the msg + * receiver's perspective */ + + /* Control uses header SegmentIndex field to access bus number... */ + U32 deviceCount; /*< indicates the max number of + * devices on this bus */ + U64 channelAddr; /*< Guest physical address of the + * channel, which can be + * dereferenced by the receiver + * of this ControlVm command */ + U64 channelBytes; /*< size of the channel in bytes */ + GUID busDataTypeGuid;/*< indicates format of data in bus + * channel */ + GUID busInstGuid; /*< instance guid for the bus */ + } createBus; /* for CONTROLVM_BUS_CREATE */ + struct { + U32 busNo; /*< bus # (0..n-1) from the msg + * receiver's perspective */ + + /* Control uses header SegmentIndex field to access bus number... */ + U32 reserved; /* Natural alignment purposes */ + } destroyBus; /* for CONTROLVM_BUS_DESTROY */ + struct { + U32 busNo; /*< bus # (0..n-1) from the + * msg receiver's + * perspective */ + + /* Control uses header SegmentIndex field to access bus number... */ + U32 reserved1; /* for alignment purposes */ + U64 guestHandle; /* This is used to convert + * guest physical address to real + * physical address for DMA, for ex. */ + U64 recvBusInterruptHandle;/*< specifies interrupt + * info. It is used by SP to register + * to receive interrupts from the CP. + * This interrupt is used for bus + * level notifications. The + * corresponding + * sendBusInterruptHandle is kept in + * CP. */ + } configureBus; /* for CONTROLVM_BUS_CONFIGURE */ + + /* for CONTROLVM_DEVICE_CREATE */ + CONTROLVM_PACKET_DEVICE_CREATE createDevice; + struct { + U32 busNo; /*< bus # (0..n-1) from the msg + * receiver's perspective */ + + /* Control uses header SegmentIndex field to access bus number... */ + U32 devNo; /*< bus-relative (0..n-1) device + * number */ + } destroyDevice; /* for CONTROLVM_DEVICE_DESTROY */ + + /* for CONTROLVM_DEVICE_CONFIGURE */ + CONTROLVM_PACKET_DEVICE_CONFIGURE configureDevice; + struct { + U32 busNo; /*< bus # (0..n-1) from the msg + * receiver's perspective */ + + /* Control uses header SegmentIndex field to access bus number... */ + U32 devNo; /*< bus-relative (0..n-1) device + * number */ + } reconfigureDevice; /* for CONTROLVM_DEVICE_RECONFIGURE */ + struct { + U32 busNo; + ULTRA_SEGMENT_STATE state; + U8 reserved[2]; /* Natural alignment purposes */ + } busChangeState; /* for CONTROLVM_BUS_CHANGESTATE */ + struct { + U32 busNo; + U32 devNo; + ULTRA_SEGMENT_STATE state; + struct { + U32 physicalDevice:1; /* =1 if message is for + * a physical device */ + /* remaining bits in this 32-bit word are available */ + } flags; + U8 reserved[2]; /* Natural alignment purposes */ + } deviceChangeState; /* for CONTROLVM_DEVICE_CHANGESTATE */ + struct { + U32 busNo; + U32 devNo; + ULTRA_SEGMENT_STATE state; + U8 reserved[6]; /* Natural alignment purposes */ + } deviceChangeStateEvent; /* for CONTROLVM_DEVICE_CHANGESTATE_EVENT */ + struct { + U32 busCount; /*< indicates the max number of busses */ + U32 switchCount; /*< indicates the max number of + * switches (applicable for service + * partition only) */ + ULTRA_CHIPSET_FEATURE features; + U32 platformNumber; /* Platform Number */ + } initChipset; /* for CONTROLVM_CHIPSET_INIT */ + struct { + U32 Options; /*< reserved */ + U32 Test; /*< bit 0 set to run embedded selftest */ + } chipsetSelftest; /* for CONTROLVM_CHIPSET_SELFTEST */ + + /* END Request messages */ + + /* BEGIN Response messages */ + + /* END Response messages */ + + /* BEGIN Event messages */ + + /* END Event messages */ + + /* BEGIN Ack messages */ + + /* END Ack messages */ + U64 addr; /*< a physical address of something, that + * can be dereferenced by the receiver of + * this ControlVm command (depends on + * command id) */ + U64 handle; /*< a handle of something (depends on + * command id) */ + }; +} CONTROLVM_MESSAGE_PACKET; + +/* All messages in any ControlVm queue have this layout. */ +typedef struct _CONTROLVM_MESSAGE { + CONTROLVM_MESSAGE_HEADER hdr; + CONTROLVM_MESSAGE_PACKET cmd; +} CONTROLVM_MESSAGE; + +typedef struct _DEVICE_MAP { + GUEST_PHYSICAL_ADDRESS DeviceChannelAddress; + U64 DeviceChannelSize; + U32 CA_Index; + U32 Reserved; /* natural alignment */ + U64 Reserved2; /* Align structure on 32-byte boundary */ +} DEVICE_MAP; + +typedef struct _GUEST_DEVICES { + DEVICE_MAP VideoChannel; + DEVICE_MAP KeyboardChannel; + DEVICE_MAP NetworkChannel; + DEVICE_MAP StorageChannel; + DEVICE_MAP ConsoleChannel; + U32 PartitionIndex; + U32 Pad; +} GUEST_DEVICES; + +typedef struct _ULTRA_CONTROLVM_CHANNEL_PROTOCOL { + CHANNEL_HEADER Header; + GUEST_PHYSICAL_ADDRESS gpControlVm; /* guest physical address of + * this channel */ + GUEST_PHYSICAL_ADDRESS gpPartitionTables; /* guest physical address of + * partition tables */ + GUEST_PHYSICAL_ADDRESS gpDiagGuest; /* guest physical address of + * diagnostic channel */ + GUEST_PHYSICAL_ADDRESS gpBootRomDisk; /* guest phys addr of (read + * only) Boot ROM disk */ + GUEST_PHYSICAL_ADDRESS gpBootRamDisk; /* guest phys addr of writable + * Boot RAM disk */ + GUEST_PHYSICAL_ADDRESS gpAcpiTable; /* guest phys addr of acpi + * table */ + GUEST_PHYSICAL_ADDRESS gpControlChannel; /* guest phys addr of control + * channel */ + GUEST_PHYSICAL_ADDRESS gpDiagRomDisk; /* guest phys addr of diagnostic + * ROM disk */ + GUEST_PHYSICAL_ADDRESS gpNvram; /* guest phys addr of NVRAM + * channel */ + U64 RequestPayloadOffset; /* Offset to request payload area */ + U64 EventPayloadOffset; /* Offset to event payload area */ + U32 RequestPayloadBytes; /* Bytes available in request payload + * area */ + U32 EventPayloadBytes; /* Bytes available in event payload area */ + U32 ControlChannelBytes; + U32 NvramChannelBytes; /* Bytes in PartitionNvram segment */ + U32 MessageBytes; /* sizeof(CONTROLVM_MESSAGE) */ + U32 MessageCount; /* CONTROLVM_MESSAGE_MAX */ + GUEST_PHYSICAL_ADDRESS gpSmbiosTable; /* guest phys addr of SMBIOS + * tables */ + GUEST_PHYSICAL_ADDRESS gpPhysicalSmbiosTable; /* guest phys addr of + * SMBIOS table */ + /* ULTRA_MAX_GUESTS_PER_SERVICE */ + GUEST_DEVICES gpObsoleteGuestDevices[16]; + + /* guest physical address of EFI firmware image base */ + GUEST_PHYSICAL_ADDRESS VirtualGuestFirmwareImageBase; + + /* guest physical address of EFI firmware entry point */ + GUEST_PHYSICAL_ADDRESS VirtualGuestFirmwareEntryPoint; + + /* guest EFI firmware image size */ + U64 VirtualGuestFirmwareImageSize; + + /* GPA = 1MB where EFI firmware image is copied to */ + GUEST_PHYSICAL_ADDRESS VirtualGuestFirmwareBootBase; + GUEST_PHYSICAL_ADDRESS VirtualGuestImageBase; + GUEST_PHYSICAL_ADDRESS VirtualGuestImageSize; + U64 PrototypeControlChannelOffset; + GUEST_PHYSICAL_ADDRESS VirtualGuestPartitionHandle; + + U16 RestoreAction; /* Restore Action field to restore the guest + * partition */ + U16 DumpAction; /* For Windows guests it shows if the visordisk + * is running in dump mode */ + U16 NvramFailCount; + U16 SavedCrashMsgCount; /* = CONTROLVM_CRASHMSG_MAX */ + U32 SavedCrashMsgOffset; /* Offset to request payload area needed + * for crash dump */ + U32 InstallationError; /* Type of error encountered during + * installation */ + U32 InstallationTextId; /* Id of string to display */ + U16 InstallationRemainingSteps; /* Number of remaining installation + * steps (for progress bars) */ + U8 ToolAction; /* ULTRA_TOOL_ACTIONS Installation Action + * field */ + U8 Reserved; /* alignment */ + ULTRA_EFI_SPAR_INDICATION EfiSparIndication; + ULTRA_EFI_SPAR_INDICATION EfiSparIndicationSupported; + U32 SPReserved; + U8 Reserved2[28]; /* Force signals to begin on 128-byte cache + * line */ + SIGNAL_QUEUE_HEADER RequestQueue; /* Service or guest partition + * uses this queue to send + * requests to Control */ + SIGNAL_QUEUE_HEADER ResponseQueue; /* Control uses this queue to + * respond to service or guest + * partition requests */ + SIGNAL_QUEUE_HEADER EventQueue; /* Control uses this queue to + * send events to service or + * guest partition */ + SIGNAL_QUEUE_HEADER EventAckQueue; /* Service or guest partition + * uses this queue to ack + * Control events */ + + /* Request fixed-size message pool - does not include payload */ + CONTROLVM_MESSAGE RequestMsg[CONTROLVM_MESSAGE_MAX]; + + /* Response fixed-size message pool - does not include payload */ + CONTROLVM_MESSAGE ResponseMsg[CONTROLVM_MESSAGE_MAX]; + + /* Event fixed-size message pool - does not include payload */ + CONTROLVM_MESSAGE EventMsg[CONTROLVM_MESSAGE_MAX]; + + /* Ack fixed-size message pool - does not include payload */ + CONTROLVM_MESSAGE EventAckMsg[CONTROLVM_MESSAGE_MAX]; + + /* Message stored during IOVM creation to be reused after crash */ + CONTROLVM_MESSAGE SavedCrashMsg[CONTROLVM_CRASHMSG_MAX]; +} ULTRA_CONTROLVM_CHANNEL_PROTOCOL; + +/* Offsets for VM channel attributes... */ +#define VM_CH_REQ_QUEUE_OFFSET \ + offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL, RequestQueue) +#define VM_CH_RESP_QUEUE_OFFSET \ + offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL, ResponseQueue) +#define VM_CH_EVENT_QUEUE_OFFSET \ + offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL, EventQueue) +#define VM_CH_ACK_QUEUE_OFFSET \ + offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL, EventAckQueue) +#define VM_CH_REQ_MSG_OFFSET \ + offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL, RequestMsg) +#define VM_CH_RESP_MSG_OFFSET \ + offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL, ResponseMsg) +#define VM_CH_EVENT_MSG_OFFSET \ + offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL, EventMsg) +#define VM_CH_ACK_MSG_OFFSET \ + offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL, EventAckMsg) +#define VM_CH_CRASH_MSG_OFFSET \ + offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL, SavedCrashMsg) + +/* The following header will be located at the beginning of PayloadVmOffset for + * various ControlVm commands. The receiver of a ControlVm command with a + * PayloadVmOffset will dereference this address and then use ConnectionOffset, + * InitiatorOffset, and TargetOffset to get the location of UTF-8 formatted + * strings that can be parsed to obtain command-specific information. The value + * of TotalLength should equal PayloadBytes. The format of the strings at + * PayloadVmOffset will take different forms depending on the message. See the + * following Wiki page for more information: + * https://ustr-linux-1.na.uis.unisys.com/spar/index.php/ControlVm_Parameters_Area + */ +typedef struct _ULTRA_CONTROLVM_PARAMETERS_HEADER { + U32 TotalLength; + U32 HeaderLength; + U32 ConnectionOffset; + U32 ConnectionLength; + U32 InitiatorOffset; + U32 InitiatorLength; + U32 TargetOffset; + U32 TargetLength; + U32 ClientOffset; + U32 ClientLength; + U32 NameOffset; + U32 NameLength; + GUID Id; + U32 Revision; + U32 Reserved; /* Natural alignment */ +} ULTRA_CONTROLVM_PARAMETERS_HEADER; + +#endif /* __CONTROLVMCHANNEL_H__ */ diff --git a/drivers/staging/unisys/common-spar/include/channels/diagchannel.h b/drivers/staging/unisys/common-spar/include/channels/diagchannel.h new file mode 100644 index 00000000000..c93515eb211 --- /dev/null +++ b/drivers/staging/unisys/common-spar/include/channels/diagchannel.h @@ -0,0 +1,427 @@ +/* Copyright © 2010 - 2013 UNISYS CORPORATION + * 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. + */ + +/*++ + * + * Module Name: + * + * diagchannel.h + * + * Abstract: + * + * This file defines the DiagChannel protocol. This protocol is used to aid in + * preserving event data sent by external applications. This protocol provides + * a region for event data to reside in. This data will eventually be sent to + * the Boot Partition where it will be committed to memory and/or disk. This + * file contains platform-independent data that can be built using any + * Supervisor build environment (Windows, Linux, EFI). + * +*/ + +#ifndef _DIAG_CHANNEL_H_ +#define _DIAG_CHANNEL_H_ + +#include "commontypes.h" +#include "channel.h" + +/* {EEA7A573-DB82-447c-8716-EFBEAAAE4858} */ +#define ULTRA_DIAG_CHANNEL_PROTOCOL_GUID \ + {0xeea7a573, 0xdb82, 0x447c, \ + {0x87, 0x16, 0xef, 0xbe, 0xaa, 0xae, 0x48, 0x58} } + +static const GUID UltraDiagChannelProtocolGuid = + ULTRA_DIAG_CHANNEL_PROTOCOL_GUID; + +/* {E850F968-3263-4484-8CA5-2A35D087A5A8} */ +#define ULTRA_DIAG_ROOT_CHANNEL_PROTOCOL_GUID \ + {0xe850f968, 0x3263, 0x4484, \ + {0x8c, 0xa5, 0x2a, 0x35, 0xd0, 0x87, 0xa5, 0xa8} } + +#define ULTRA_DIAG_CHANNEL_PROTOCOL_SIGNATURE ULTRA_CHANNEL_PROTOCOL_SIGNATURE + +/* Must increment this whenever you insert or delete fields within this channel +* struct. Also increment whenever you change the meaning of fields within this +* channel struct so as to break pre-existing software. Note that you can +* usually add fields to the END of the channel struct withOUT needing to +* increment this. */ +#define ULTRA_DIAG_CHANNEL_PROTOCOL_VERSIONID 2 + +#define ULTRA_DIAG_CHANNEL_OK_CLIENT(pChannel, logCtx) \ + (ULTRA_check_channel_client(pChannel, \ + UltraDiagChannelProtocolGuid, \ + "diag", \ + sizeof(ULTRA_DIAG_CHANNEL_PROTOCOL), \ + ULTRA_DIAG_CHANNEL_PROTOCOL_VERSIONID, \ + ULTRA_DIAG_CHANNEL_PROTOCOL_SIGNATURE, \ + __FILE__, __LINE__, logCtx)) +#define ULTRA_DIAG_CHANNEL_OK_SERVER(actualBytes, logCtx) \ + (ULTRA_check_channel_server(UltraDiagChannelProtocolGuid, \ + "diag", \ + sizeof(ULTRA_DIAG_CHANNEL_PROTOCOL), \ + actualBytes, __FILE__, __LINE__, logCtx)) +#define MAX_MODULE_NAME_SIZE 128 /* Maximum length of module name... */ +#define MAX_ADDITIONAL_INFO_SIZE 256 /* Maximum length of any additional info + * accompanying event... */ +#define MAX_SUBSYSTEMS 64 /* Maximum number of subsystems allowed in + * DiagChannel... */ +#define LOW_SUBSYSTEMS 32 /* Half of MAX_SUBSYSTEMS to allow 64-bit + * math */ +#define SUBSYSTEM_DEBUG 0 /* Standard subsystem for debug events */ +#define SUBSYSTEM_DEFAULT 1 /* Default subsystem for legacy calls to + * ReportEvent */ + +/* few useful subsystem mask values */ +#define SUBSYSTEM_MASK_DEBUG 0x01 /* Standard subsystem for debug + * events */ +#define SUBSYSTEM_MASK_DEFAULT 0x02 /* Default subsystem for legacy calls to + * ReportEvents */ + +/* Event parameter "Severity" is overloaded with Cause in byte 2 and Severity in + * byte 0, bytes 1 and 3 are reserved */ +#define SEVERITY_MASK 0x0FF /* mask out all but the Severity in byte 0 */ +#define CAUSE_MASK 0x0FF0000 /* mask out all but the cause in byte 2 */ +#define CAUSE_SHIFT_AMT 16 /* shift 2 bytes to place it in byte 2 */ + +/* SubsystemSeverityFilter */ +#define SEVERITY_FILTER_MASK 0x0F /* mask out the Cause half, SeverityFilter is + * in the lower nibble */ +#define CAUSE_FILTER_MASK 0xF0 /* mask out the Severity half, CauseFilter is in + * the upper nibble */ +#define CAUSE_FILTER_SHIFT_AMT 4 /* shift amount to place it in lower or upper + * nibble */ + +/* Copied from EFI's EFI_TIME struct in efidef.h. EFI headers are not allowed +* in some of the Supervisor areas, such as Monitor, so it has been "ported" here +* for use in diagnostic event timestamps... */ +typedef struct _DIAG_EFI_TIME { + U16 Year; /* 1998 - 20XX */ + U8 Month; /* 1 - 12 */ + U8 Day; /* 1 - 31 */ + U8 Hour; /* 0 - 23 */ + U8 Minute; /* 0 - 59 */ + U8 Second; /* 0 - 59 */ + U8 Pad1; + U32 Nanosecond; /* 0 - 999, 999, 999 */ + S16 TimeZone; /* -1440 to 1440 or 2047 */ + U8 Daylight; + U8 Pad2; +} DIAG_EFI_TIME; + +typedef enum { + ULTRA_COMPONENT_GUEST = 0, + ULTRA_COMPONENT_MONITOR = 0x01, + ULTRA_COMPONENT_CCM = 0x02, /* Common Control module */ + /* RESERVED 0x03 - 0x7 */ + + /* Ultravisor Components */ + ULTRA_COMPONENT_BOOT = 0x08, + ULTRA_COMPONENT_IDLE = 0x09, + ULTRA_COMPONENT_CONTROL = 0x0A, + ULTRA_COMPONENT_LOGGER = 0x0B, + ULTRA_COMPONENT_ACPI = 0X0C, + /* RESERVED 0x0D - 0x0F */ + + /* sPAR Components */ + ULTRA_COMPONENT_COMMAND = 0x10, + ULTRA_COMPONENT_IODRIVER = 0x11, + ULTRA_COMPONENT_CONSOLE = 0x12, + ULTRA_COMPONENT_OPERATIONS = 0x13, + ULTRA_COMPONENT_MANAGEMENT = 0x14, + ULTRA_COMPONENT_DIAG = 0x15, + ULTRA_COMPONENT_HWDIAG = 0x16, + ULTRA_COMPONENT_PSERVICES = 0x17, + ULTRA_COMPONENT_PDIAG = 0x18 + /* RESERVED 0x18 - 0x1F */ +} ULTRA_COMPONENT_TYPES; + +/* Structure: DIAG_CHANNEL_EVENT Purpose: Contains attributes that make up an + * event to be written to the DIAG_CHANNEL memory. Attributes: EventId: Id of + * the diagnostic event to write to memory. Severity: Severity of the event + * (Error, Info, etc). ModuleName: Module/file name where event originated. + * LineNumber: Line number in module name where event originated. Timestamp: + * Date/time when event was received by ReportEvent, and written to DiagChannel. + * Reserved: Padding to align structure on a 64-byte cache line boundary. + * AdditionalInfo: Array of characters for additional event info (may be + * empty). */ +typedef struct _DIAG_CHANNEL_EVENT { + U32 EventId; + U32 Severity; + U8 ModuleName[MAX_MODULE_NAME_SIZE]; + U32 LineNumber; + DIAG_EFI_TIME Timestamp; /* Size = 16 bytes */ + U32 PartitionNumber; /* Filled in by Diag Switch as pool blocks are + * filled */ + U16 VirtualProcessorNumber; + U16 LogicalProcessorNumber; + U8 ComponentType; /* ULTRA_COMPONENT_TYPES */ + U8 Subsystem; + U16 Reserved0; /* pad to U64 alignment */ + U32 BlockNumber; /* filled in by DiagSwitch as pool blocks are + * filled */ + U32 BlockNumberHigh; + U32 EventNumber; /* filled in by DiagSwitch as pool blocks are + * filled */ + U32 EventNumberHigh; + + /* The BlockNumber and EventNumber fields are set only by DiagSwitch + * and referenced only by WinDiagDisplay formatting tool as + * additional diagnostic information. Other tools including + * WinDiagDisplay currently ignore these 'Reserved' bytes. */ + U8 Reserved[8]; + U8 AdditionalInfo[MAX_ADDITIONAL_INFO_SIZE]; + + /* NOTE: Changesto DIAG_CHANNEL_EVENT generally need to be reflected in + * existing copies * + * - for AppOS at + * GuestLinux/visordiag_early/supervisor_diagchannel.h * + * - for WinDiagDisplay at + * EFI/Ultra/Tools/WinDiagDisplay/WinDiagDisplay/diagstruct.h */ +} DIAG_CHANNEL_EVENT; + +/* Levels of severity for diagnostic events, in order from lowest severity to +* highest (i.e. fatal errors are the most severe, and should always be logged, +* but info events rarely need to be logged except during debugging). The values +* DIAG_SEVERITY_ENUM_BEGIN and DIAG_SEVERITY_ENUM_END are not valid severity +* values. They exist merely to dilineate the list, so that future additions +* won't require changes to the driver (i.e. when checking for out-of-range +* severities in SetSeverity). The values DIAG_SEVERITY_OVERRIDE and +* DIAG_SEVERITY_SHUTOFF are not valid severity values for logging events but +* they are valid for controlling the amount of event data. This enum is also +* defined in DotNet\sParFramework\ControlFramework\ControlFramework.cs. If a +* change is made to this enum, they should also be reflected in that file. */ +typedef enum { DIAG_SEVERITY_ENUM_BEGIN = 0, + DIAG_SEVERITY_OVERRIDE = DIAG_SEVERITY_ENUM_BEGIN, + DIAG_SEVERITY_VERBOSE = DIAG_SEVERITY_OVERRIDE, /* 0 */ + DIAG_SEVERITY_INFO = DIAG_SEVERITY_VERBOSE + 1, /* 1 */ + DIAG_SEVERITY_WARNING = DIAG_SEVERITY_INFO + 1, /* 2 */ + DIAG_SEVERITY_ERR = DIAG_SEVERITY_WARNING + 1, /* 3 */ + DIAG_SEVERITY_PRINT = DIAG_SEVERITY_ERR + 1, /* 4 */ + DIAG_SEVERITY_SHUTOFF = DIAG_SEVERITY_PRINT + 1, /* 5 */ + DIAG_SEVERITY_ENUM_END = DIAG_SEVERITY_SHUTOFF, /* 5 */ + DIAG_SEVERITY_NONFATAL_ERR = DIAG_SEVERITY_ERR, + DIAG_SEVERITY_FATAL_ERR = DIAG_SEVERITY_PRINT +} DIAG_SEVERITY; + +/* Event Cause enums +* +* Levels of cause for diagnostic events, in order from least to greatest cause +* Internal errors are most urgent since ideally they should never exist +* Invalid requests are preventable by avoiding invalid inputs +* Operations errors depend on environmental factors which may impact which +* requests are possible +* Manifest provides intermediate value to capture firmware and configuration +* version information +* Trace provides suplimental debug information in release firmware +* Unknown Log captures unclasified LogEvent calls. +* Debug is the least urgent since it provides suplimental debug information only +* in debug firmware +* Unknown Debug captures unclassified DebugEvent calls. +* This enum is also defined in +* DotNet\sParFramework\ControlFramework\ControlFramework.cs. +* If a change is made to this enum, they should also be reflected in that +* file. */ + + + +/* A cause value "DIAG_CAUSE_FILE_XFER" together with a severity value of +* "DIAG_SEVERITY_PRINT" (=4), is used for transferring text or binary file to +* the Diag partition. This cause-severity combination will be used by Logger +* DiagSwitch to segregate events into block types. The files are transferred in +* 256 byte chunks maximum, in the AdditionalInfo field of the DIAG_CHANNEL_EVENT +* structure. In the file transfer mode, some event fields will have different +* meaning: EventId specifies the file offset, severity specifies the block type, +* ModuleName specifies the filename, LineNumber specifies the number of valid +* data bytes in an event and AdditionalInfo contains up to 256 bytes of data. */ + +/* The Diag DiagWriter appends event blocks to events.raw as today, and for data + * blocks uses DIAG_CHANNEL_EVENT + * PartitionNumber to extract and append 'AdditionalInfo' to filename (specified + * by ModuleName). */ + +/* The Dell PDiag uses this new mechanism to stash DSET .zip onto the + * 'diagnostic' virtual disk. */ +typedef enum { + DIAG_CAUSE_UNKNOWN = 0, + DIAG_CAUSE_UNKNOWN_DEBUG = DIAG_CAUSE_UNKNOWN + 1, /* 1 */ + DIAG_CAUSE_DEBUG = DIAG_CAUSE_UNKNOWN_DEBUG + 1, /* 2 */ + DIAG_CAUSE_UNKNOWN_LOG = DIAG_CAUSE_DEBUG + 1, /* 3 */ + DIAG_CAUSE_TRACE = DIAG_CAUSE_UNKNOWN_LOG + 1, /* 4 */ + DIAG_CAUSE_MANIFEST = DIAG_CAUSE_TRACE + 1, /* 5 */ + DIAG_CAUSE_OPERATIONS_ERROR = DIAG_CAUSE_MANIFEST + 1, /* 6 */ + DIAG_CAUSE_INVALID_REQUEST = DIAG_CAUSE_OPERATIONS_ERROR + 1, /* 7 */ + DIAG_CAUSE_INTERNAL_ERROR = DIAG_CAUSE_INVALID_REQUEST + 1, /* 8 */ + DIAG_CAUSE_FILE_XFER = DIAG_CAUSE_INTERNAL_ERROR + 1, /* 9 */ + DIAG_CAUSE_ENUM_END = DIAG_CAUSE_FILE_XFER /* 9 */ +} DIAG_CAUSE; + +/* Event Cause category defined into the byte 2 of Severity */ +#define CAUSE_DEBUG (DIAG_CAUSE_DEBUG << CAUSE_SHIFT_AMT) +#define CAUSE_TRACE (DIAG_CAUSE_TRACE << CAUSE_SHIFT_AMT) +#define CAUSE_MANIFEST (DIAG_CAUSE_MANIFEST << CAUSE_SHIFT_AMT) +#define CAUSE_OPERATIONS_ERROR (DIAG_CAUSE_OPERATIONS_ERROR << CAUSE_SHIFT_AMT) +#define CAUSE_INVALID_REQUEST (DIAG_CAUSE_INVALID_REQUEST << CAUSE_SHIFT_AMT) +#define CAUSE_INTERNAL_ERROR (DIAG_CAUSE_INTERNAL_ERROR << CAUSE_SHIFT_AMT) +#define CAUSE_FILE_XFER (DIAG_CAUSE_FILE_XFER << CAUSE_SHIFT_AMT) +#define CAUSE_ENUM_END CAUSE_FILE_XFER + +/* Combine Cause and Severity categories into one */ +#define CAUSE_DEBUG_SEVERITY_VERBOSE \ + (CAUSE_DEBUG | DIAG_SEVERITY_VERBOSE) +#define CAUSE_TRACE_SEVERITY_VERBOSE \ + (CAUSE_TRACE | DIAG_SEVERITY_VERBOSE) +#define CAUSE_MANIFEST_SEVERITY_VERBOSE\ + (CAUSE_MANIFEST | DIAG_SEVERITY_VERBOSE) +#define CAUSE_OPERATIONS_SEVERITY_VERBOSE \ + (CAUSE_OPERATIONS_ERROR | DIAG_SEVERITY_VERBOSE) +#define CAUSE_INVALID_SEVERITY_VERBOSE \ + (CAUSE_INVALID_REQUEST | DIAG_SEVERITY_VERBOSE) +#define CAUSE_INTERNAL_SEVERITY_VERBOSE \ + (CAUSE_INTERNAL_ERROR | DIAG_SEVERITY_VERBOSE) + +#define CAUSE_DEBUG_SEVERITY_INFO \ + (CAUSE_DEBUG | DIAG_SEVERITY_INFO) +#define CAUSE_TRACE_SEVERITY_INFO \ + (CAUSE_TRACE | DIAG_SEVERITY_INFO) +#define CAUSE_MANIFEST_SEVERITY_INFO \ + (CAUSE_MANIFEST | DIAG_SEVERITY_INFO) +#define CAUSE_OPERATIONS_SEVERITY_INFO \ + (CAUSE_OPERATIONS_ERROR | DIAG_SEVERITY_INFO) +#define CAUSE_INVALID_SEVERITY_INFO \ + (CAUSE_INVALID_REQUEST | DIAG_SEVERITY_INFO) +#define CAUSE_INTERNAL_SEVERITY_INFO \ + (CAUSE_INTERNAL_ERROR | DIAG_SEVERITY_INFO) + +#define CAUSE_DEBUG_SEVERITY_WARN \ + (CAUSE_DEBUG | DIAG_SEVERITY_WARNING) +#define CAUSE_TRACE_SEVERITY_WARN \ + (CAUSE_TRACE | DIAG_SEVERITY_WARNING) +#define CAUSE_MANIFEST_SEVERITY_WARN \ + (CAUSE_MANIFEST | DIAG_SEVERITY_WARNING) +#define CAUSE_OPERATIONS_SEVERITY_WARN \ + (CAUSE_OPERATIONS_ERROR | DIAG_SEVERITY_WARNING) +#define CAUSE_INVALID_SEVERITY_WARN \ + (CAUSE_INVALID_REQUEST | DIAG_SEVERITY_WARNING) +#define CAUSE_INTERNAL_SEVERITY_WARN \ + (CAUSE_INTERNAL_ERROR | DIAG_SEVERITY_WARNING) + +#define CAUSE_DEBUG_SEVERITY_ERR \ + (CAUSE_DEBUG | DIAG_SEVERITY_ERR) +#define CAUSE_TRACE_SEVERITY_ERR \ + (CAUSE_TRACE | DIAG_SEVERITY_ERR) +#define CAUSE_MANIFEST_SEVERITY_ERR \ + (CAUSE_MANIFEST | DIAG_SEVERITY_ERR) +#define CAUSE_OPERATIONS_SEVERITY_ERR \ + (CAUSE_OPERATIONS_ERROR | DIAG_SEVERITY_ERR) +#define CAUSE_INVALID_SEVERITY_ERR \ + (CAUSE_INVALID_REQUEST | DIAG_SEVERITY_ERR) +#define CAUSE_INTERNAL_SEVERITY_ERR \ + (CAUSE_INTERNAL_ERROR | DIAG_SEVERITY_ERR) + +#define CAUSE_DEBUG_SEVERITY_PRINT \ + (CAUSE_DEBUG | DIAG_SEVERITY_PRINT) +#define CAUSE_TRACE_SEVERITY_PRINT \ + (CAUSE_TRACE | DIAG_SEVERITY_PRINT) +#define CAUSE_MANIFEST_SEVERITY_PRINT \ + (CAUSE_MANIFEST | DIAG_SEVERITY_PRINT) +#define CAUSE_OPERATIONS_SEVERITY_PRINT \ + (CAUSE_OPERATIONS_ERROR | DIAG_SEVERITY_PRINT) +#define CAUSE_INVALID_SEVERITY_PRINT \ + (CAUSE_INVALID_REQUEST | DIAG_SEVERITY_PRINT) +#define CAUSE_INTERNAL_SEVERITY_PRINT \ + (CAUSE_INTERNAL_ERROR | DIAG_SEVERITY_PRINT) +#define CAUSE_FILE_XFER_SEVERITY_PRINT \ + (CAUSE_FILE_XFER | DIAG_SEVERITY_PRINT) + +/* Structure: DIAG_CHANNEL_PROTOCOL_HEADER + * + * Purpose: Contains attributes that make up the header specific to the + * DIAG_CHANNEL area. + * + * Attributes: + * + * DiagLock: Diag Channel spinlock. + * + *IsChannelInitialized: 1 iff SignalInit was called for this channel; otherwise + * 0, and assume the channel is not ready for use yet. + * + * Reserved: Padding to allign the fields in this structure. + * + *SubsystemSeverityFilter: Level of severity on a subsystem basis that controls + * whether events are logged. Any event's severity for a + * particular subsystem below this level will be discarded. + */ +typedef struct _DIAG_CHANNEL_PROTOCOL_HEADER { + volatile U32 DiagLock; + U8 IsChannelInitialized; + U8 Reserved[3]; + U8 SubsystemSeverityFilter[64]; +} DIAG_CHANNEL_PROTOCOL_HEADER; + +/* The Diagram for the Diagnostic Channel: */ +/* ----------------------- */ +/* | Channel Header | Defined by ULTRA_CHANNEL_PROTOCOL */ +/* ----------------------- */ +/* | Signal Queue Header | Defined by SIGNAL_QUEUE_HEADER */ +/* ----------------------- */ +/* | DiagChannel Header | Defined by DIAG_CHANNEL_PROTOCOL_HEADER */ +/* ----------------------- */ +/* | Channel Event Info | Defined by (DIAG_CHANNEL_EVENT * MAX_EVENTS) */ +/* ----------------------- */ +/* | Reserved | Reserved (pad out to 4MB) */ +/* ----------------------- */ + +/* Offsets/sizes for diagnostic channel attributes... */ +#define DIAG_CH_QUEUE_HEADER_OFFSET (sizeof(ULTRA_CHANNEL_PROTOCOL)) +#define DIAG_CH_QUEUE_HEADER_SIZE (sizeof(SIGNAL_QUEUE_HEADER)) +#define DIAG_CH_PROTOCOL_HEADER_OFFSET \ + (DIAG_CH_QUEUE_HEADER_OFFSET + DIAG_CH_QUEUE_HEADER_SIZE) +#define DIAG_CH_PROTOCOL_HEADER_SIZE (sizeof(DIAG_CHANNEL_PROTOCOL_HEADER)) +#define DIAG_CH_EVENT_OFFSET \ + (DIAG_CH_PROTOCOL_HEADER_OFFSET + DIAG_CH_PROTOCOL_HEADER_SIZE) +#define DIAG_CH_SIZE (4096 * 1024) + +/* For Control and Idle Partitions with larger (8 MB) diagnostic(root) + * channels */ +#define DIAG_CH_LRG_SIZE (2 * DIAG_CH_SIZE) /* 8 MB */ + +/* + * Structure: ULTRA_DIAG_CHANNEL_PROTOCOL + * + * Purpose: Contains attributes that make up the DIAG_CHANNEL memory. + * + * Attributes: + * + * CommonChannelHeader: Header info common to all channels. + * + * QueueHeader: Queue header common to all channels - used to determine where to + * store event. + * + * DiagChannelHeader: Diagnostic channel header info (see + * DIAG_CHANNEL_PROTOCOL_HEADER comments). + * + * Events: Area where diagnostic events (up to MAX_EVENTS) are written. + * + *Reserved: Reserved area to allow for correct channel size padding. +*/ +typedef struct _ULTRA_DIAG_CHANNEL_PROTOCOL { + ULTRA_CHANNEL_PROTOCOL CommonChannelHeader; + SIGNAL_QUEUE_HEADER QueueHeader; + DIAG_CHANNEL_PROTOCOL_HEADER DiagChannelHeader; + DIAG_CHANNEL_EVENT Events[(DIAG_CH_SIZE - DIAG_CH_EVENT_OFFSET) / + sizeof(DIAG_CHANNEL_EVENT)]; +} +ULTRA_DIAG_CHANNEL_PROTOCOL; + +#endif diff --git a/drivers/staging/unisys/common-spar/include/channels/iochannel.h b/drivers/staging/unisys/common-spar/include/channels/iochannel.h new file mode 100644 index 00000000000..94e4b2afd55 --- /dev/null +++ b/drivers/staging/unisys/common-spar/include/channels/iochannel.h @@ -0,0 +1,938 @@ +/* Copyright © 2010 - 2013 UNISYS CORPORATION */ +/* All rights reserved. */ +#ifndef __IOCHANNEL_H__ +#define __IOCHANNEL_H__ + +/* +* Everything needed for IOPart-GuestPart communication is define in +* this file. Note: Everything is OS-independent because this file is +* used by Windows, Linux and possible EFI drivers. */ + + +/* +* Communication flow between the IOPart and GuestPart uses the channel headers +* channel state. The following states are currently being used: +* UNINIT(All Zeroes), CHANNEL_ATTACHING, CHANNEL_ATTACHED, CHANNEL_OPENED +* +* additional states will be used later. No locking is needed to switch between +* states due to the following rules: +* +* 1. IOPart is only the only partition allowed to change from UNIT +* 2. IOPart is only the only partition allowed to change from +* CHANNEL_ATTACHING +* 3. GuestPart is only the only partition allowed to change from +* CHANNEL_ATTACHED +* +* The state changes are the following: IOPart sees the channel is in UNINIT, +* UNINIT -> CHANNEL_ATTACHING (performed only by IOPart) +* CHANNEL_ATTACHING -> CHANNEL_ATTACHED (performed only by IOPart) +* CHANNEL_ATTACHED -> CHANNEL_OPENED (performed only by GuestPart) +*/ + +#include "commontypes.h" +#include "vmcallinterface.h" + +#define _ULTRA_CONTROLVM_CHANNEL_INLINE_ +#include "controlvmchannel.h" +#include "vbuschannel.h" +#undef _ULTRA_CONTROLVM_CHANNEL_INLINE_ +#include "channel.h" + +/* + * CHANNEL Guids + */ + +#include "channel_guid.h" + +#define ULTRA_VHBA_CHANNEL_PROTOCOL_SIGNATURE ULTRA_CHANNEL_PROTOCOL_SIGNATURE +#define ULTRA_VNIC_CHANNEL_PROTOCOL_SIGNATURE ULTRA_CHANNEL_PROTOCOL_SIGNATURE +#define ULTRA_VSWITCH_CHANNEL_PROTOCOL_SIGNATURE \ + ULTRA_CHANNEL_PROTOCOL_SIGNATURE + +/* Must increment these whenever you insert or delete fields within this channel +* struct. Also increment whenever you change the meaning of fields within this +* channel struct so as to break pre-existing software. Note that you can +* usually add fields to the END of the channel struct withOUT needing to +* increment this. */ +#define ULTRA_VHBA_CHANNEL_PROTOCOL_VERSIONID 2 +#define ULTRA_VNIC_CHANNEL_PROTOCOL_VERSIONID 2 +#define ULTRA_VSWITCH_CHANNEL_PROTOCOL_VERSIONID 1 + +#define ULTRA_VHBA_CHANNEL_OK_CLIENT(pChannel, logCtx) \ + (ULTRA_check_channel_client(pChannel, UltraVhbaChannelProtocolGuid, \ + "vhba", MIN_IO_CHANNEL_SIZE, \ + ULTRA_VHBA_CHANNEL_PROTOCOL_VERSIONID, \ + ULTRA_VHBA_CHANNEL_PROTOCOL_SIGNATURE, \ + __FILE__, __LINE__, logCtx)) +#define ULTRA_VHBA_CHANNEL_OK_SERVER(actualBytes, logCtx) \ + (ULTRA_check_channel_server(UltraVhbaChannelProtocolGuid, \ + "vhba", MIN_IO_CHANNEL_SIZE, actualBytes, \ + __FILE__, __LINE__, logCtx)) +#define ULTRA_VNIC_CHANNEL_OK_CLIENT(pChannel, logCtx) \ + (ULTRA_check_channel_client(pChannel, UltraVnicChannelProtocolGuid, \ + "vnic", MIN_IO_CHANNEL_SIZE, \ + ULTRA_VNIC_CHANNEL_PROTOCOL_VERSIONID, \ + ULTRA_VNIC_CHANNEL_PROTOCOL_SIGNATURE, \ + __FILE__, __LINE__, logCtx)) +#define ULTRA_VNIC_CHANNEL_OK_SERVER(actualBytes, logCtx) \ + (ULTRA_check_channel_server(UltraVnicChannelProtocolGuid, \ + "vnic", MIN_IO_CHANNEL_SIZE, actualBytes, \ + __FILE__, __LINE__, logCtx)) +#define ULTRA_VSWITCH_CHANNEL_OK_CLIENT(pChannel, logCtx) \ + (ULTRA_check_channel_client(pChannel, UltraVswitchChannelProtocolGuid, \ + "vswitch", MIN_IO_CHANNEL_SIZE, \ + ULTRA_VSWITCH_CHANNEL_PROTOCOL_VERSIONID, \ + ULTRA_VSWITCH_CHANNEL_PROTOCOL_SIGNATURE, \ + __FILE__, __LINE__, logCtx)) +#define ULTRA_VSWITCH_CHANNEL_OK_SERVER(actualBytes, logCtx) \ + (ULTRA_check_channel_server(UltraVswitchChannelProtocolGuid, \ + "vswitch", MIN_IO_CHANNEL_SIZE, \ + actualBytes, \ + __FILE__, __LINE__, logCtx)) +/* +* Everything necessary to handle SCSI & NIC traffic between Guest Partition and +* IO Partition is defined below. */ + + +/* +* Defines and enums. +*/ + +#define MINNUM(a, b) (((a) < (b)) ? (a) : (b)) +#define MAXNUM(a, b) (((a) > (b)) ? (a) : (b)) + +/* these define the two queues per data channel between iopart and + * ioguestparts */ +#define IOCHAN_TO_IOPART 0 /* used by ioguestpart to 'insert' signals to + * iopart */ +#define IOCHAN_FROM_GUESTPART 0 /* used by iopart to 'remove' signals from + * ioguestpart - same queue as previous queue */ + +#define IOCHAN_TO_GUESTPART 1 /* used by iopart to 'insert' signals to + * ioguestpart */ +#define IOCHAN_FROM_IOPART 1 /* used by ioguestpart to 'remove' signals from + * iopart - same queue as previous queue */ + +/* these define the two queues per control channel between controlpart and "its" + * guests, which includes the iopart */ +#define CTRLCHAN_TO_CTRLGUESTPART 0 /* used by ctrlguestpart to 'insert' signals + * to ctrlpart */ +#define CTLRCHAN_FROM_CTRLPART 0 /* used by ctrlpart to 'remove' signals from + * ctrlquestpart - same queue as previous + * queue */ + +#define CTRLCHAN_TO_CTRLPART 1 /* used by ctrlpart to 'insert' signals to + * ctrlguestpart */ +#define CTRLCHAN_FROM_CTRLGUESTPART 1 /* used by ctrguestpart to 'remove' + * signals from ctrlpart - same queue as + * previous queue */ + +/* these define the Event & Ack queues per control channel Events are generated +* by CTRLGUESTPART and sent to CTRLPART; Acks are generated by CTRLPART and sent +* to CTRLGUESTPART. */ +#define CTRLCHAN_EVENT_TO_CTRLPART 2 /* used by ctrlguestpart to 'insert' Events + * to ctrlpart */ +#define CTRLCHAN_EVENT_FROM_CTRLGUESTPART 2 /* used by ctrlpart to 'remove' + * Events from ctrlguestpart */ + +#define CTRLCHAN_ACK_TO_CTRLGUESTPART 3 /* used by ctrlpart to 'insert' Acks to + * ctrlguestpart */ +#define CTRLCHAN_ACK_FROM_CTRLPART 3 /* used by ctrlguestpart to 'remove' Events + * from ctrlpart */ + +/* size of cdb - i.e., scsi cmnd */ +#define MAX_CMND_SIZE 16 +enum dma_data_dir { + DMA_DIR_BIDIR = 0, + DMA_DIR_TO_DEV, + DMA_DIR_FROM_DEV, + DMA_DIR_NONE +}; + +#define MAX_SENSE_SIZE 64 + +#define MAX_PHYS_INFO 64 + +/* Because GuestToGuestCopy is limited to 4KiB segments, and we have limited the +* Emulex Driver to 256 scatter list segments via the lpfc_sg_seg_cnt parameter +* to 256, the maximum I/O size is limited to 256 * 4 KiB = 1 MB */ +#define MAX_IO_SIZE (1024*1024) /* 1 MB */ + +/* NOTE 1: lpfc defines its support for segments in +* #define LPFC_SG_SEG_CNT 64 +* +* NOTE 2: In Linux, frags array in skb is currently allocated to be +* MAX_SKB_FRAGS size, which is 18 which is smaller than MAX_PHYS_INFO for +* now. */ + +#ifndef MAX_SERIAL_NUM +#define MAX_SERIAL_NUM 32 +#endif /* MAX_SERIAL_NUM */ + +#define MAX_SCSI_BUSES 1 +#define MAX_SCSI_TARGETS 8 +#define MAX_SCSI_LUNS 16 +#define MAX_SCSI_FROM_HOST 0xFFFFFFFF /* Indicator to use Physical HBA + * SCSI Host value */ + +/* various types of network packets that can be sent in cmdrsp */ +typedef enum { NET_RCV_POST = 0, /* submit buffer to hold receiving + * incoming packet */ + /* virtnic -> uisnic */ + NET_RCV, /* incoming packet received */ + /* uisnic -> virtpci */ + NET_XMIT, /* for outgoing net packets */ + /* virtnic -> uisnic */ + NET_XMIT_DONE, /* outgoing packet xmitted */ + /* uisnic -> virtpci */ + NET_RCV_ENBDIS, /* enable/disable packet reception */ + /* virtnic -> uisnic */ + NET_RCV_ENBDIS_ACK, /* acknowledge enable/disable packet + * reception */ + /* uisnic -> virtnic */ + NET_RCV_PROMISC, /* enable/disable promiscuous mode */ + /* virtnic -> uisnic */ + NET_CONNECT_STATUS, /* indicate the loss or restoration of a network + * connection */ + /* uisnic -> virtnic */ + NET_MACADDR, /* indicates the client has requested to update + * its MAC addr */ + NET_MACADDR_ACK, /* Mac addres */ + +} NET_TYPES; + +#define ETH_HEADER_SIZE 14 /* size of ethernet header */ + +#define ETH_MIN_DATA_SIZE 46 /* minimum eth data size */ +#define ETH_MIN_PACKET_SIZE (ETH_HEADER_SIZE + ETH_MIN_DATA_SIZE) + +#define ETH_DEF_DATA_SIZE 1500 /* default data size */ +#define ETH_DEF_PACKET_SIZE (ETH_HEADER_SIZE + ETH_DEF_DATA_SIZE) + +#define ETH_MAX_MTU 16384 /* maximum data size */ + +#ifndef MAX_MACADDR_LEN +#define MAX_MACADDR_LEN 6 /* number of bytes in MAC address */ +#endif /* MAX_MACADDR_LEN */ + +#define ETH_IS_LOCALLY_ADMINISTERED(Address) \ + (((U8 *) (Address))[0] & ((U8) 0x02)) +#define NIC_VENDOR_ID 0x0008000B + +/* various types of scsi task mgmt commands */ +typedef enum { TASK_MGMT_ABORT_TASK = + 1, TASK_MGMT_BUS_RESET, TASK_MGMT_LUN_RESET, + TASK_MGMT_TARGET_RESET, +} TASK_MGMT_TYPES; + +/* various types of vdisk mgmt commands */ +typedef enum { VDISK_MGMT_ACQUIRE = 1, VDISK_MGMT_RELEASE, +} VDISK_MGMT_TYPES; + +/* this is used in the vdest field */ +#define VDEST_ALL 0xFFFF + +#define MIN_NUMSIGNALS 64 +#define MAX_NUMSIGNALS 4096 + +/* MAX_NET_RCV_BUF specifies the number of rcv buffers that are created by each +* guest's virtnic and posted to uisnic. Uisnic, for each channel, keeps the rcv +* buffers posted and uses them to receive data on behalf of the guest's virtnic. +* NOTE: the num_rcv_bufs is configurable for each VNIC. So the following is +* simply an upperlimit on what each VNIC can provide. Setting it to half of the +* NUMSIGNALS to prevent queue full deadlocks */ +#define MAX_NET_RCV_BUFS (MIN_NUMSIGNALS / 2) + +/* + * structs with pragma pack */ + + +/* ///////////// BEGIN PRAGMA PACK PUSH 1 ///////////////////////// */ +/* ///////////// ONLY STRUCT TYPE SHOULD BE BELOW */ + +#pragma pack(push, 1) + +struct guest_phys_info { + U64 address; + U64 length; +}; + +#define GPI_ENTRIES_PER_PAGE (PAGE_SIZE / sizeof(struct guest_phys_info)) + +struct uisscsi_dest { + U32 channel; /* channel == bus number */ + U32 id; /* id == target number */ + U32 lun; /* lun == logical unit number */ +}; + +struct vhba_wwnn { + U32 wwnn1; + U32 wwnn2; +}; + +/* WARNING: Values stired in this structure must contain maximum counts (not + * maximum values). */ +struct vhba_config_max { /* 20 bytes */ + U32 max_channel; /* maximum channel for devices attached to this + * bus */ + U32 max_id; /* maximum SCSI ID for devices attached to this + * bus */ + U32 max_lun; /* maximum SCSI LUN for devices attached to this + * bus */ + U32 cmd_per_lun; /* maximum number of outstanding commands per + * lun that are allowed at one time */ + U32 max_io_size; /* maximum io size for devices attached to this + * bus */ + /* max io size is often determined by the resource of the hba. e.g */ + /* max scatter gather list length * page size / sector size */ +}; + +struct uiscmdrsp_scsi { + void *scsicmd; /* the handle to the cmd that was received - + * send it back as is in the rsp packet. */ + U8 cmnd[MAX_CMND_SIZE]; /* the cdb for the command */ + U32 bufflen; /* length of data to be transferred out or in */ + U16 guest_phys_entries; /* Number of entries in scatter-gather (sg) + * list */ + struct guest_phys_info gpi_list[MAX_PHYS_INFO]; /* physical address + * information for each + * fragment */ + enum dma_data_dir data_dir; /* direction of the data, if any */ + struct uisscsi_dest vdest; /* identifies the virtual hba, id, + * channel, lun to which cmd was sent */ + + /* the following fields are needed to queue the rsp back to cmd + * originator */ + int linuxstat; /* the original Linux status - for use by linux + * vdisk code */ + U8 scsistat; /* the scsi status */ + U8 addlstat; /* non-scsi status - covers cases like timeout + * needed by windows guests */ +#define ADDL_RESET 1 +#define ADDL_TIMEOUT 2 +#define ADDL_INTERNAL_ERROR 3 +#define ADDL_SEL_TIMEOUT 4 +#define ADDL_CMD_TIMEOUT 5 +#define ADDL_BAD_TARGET 6 +#define ADDL_RETRY 7 + + /* the following fields are need to determine the result of command */ + U8 sensebuf[MAX_SENSE_SIZE]; /* sense info in case cmd failed; */ + /* it holds the sense_data struct; */ + /* see that struct for details. */ + void *vdisk; /* contains pointer to the vdisk so that we can clean up + * when the IO completes. */ + int no_disk_result; /* used to return no disk inquiry result */ + /* when no_disk_result is set to 1, */ + /* scsi.scsistat is SAM_STAT_GOOD */ + /* scsi.addlstat is 0 */ + /* scsi.linuxstat is SAM_STAT_GOOD */ + /* That is, there is NO error. */ +}; + +/* +* Defines to support sending correct inquiry result when no disk is +* configured. */ + +/* From SCSI SPC2 - + * + * If the target is not capable of supporting a device on this logical unit, the + * device server shall set this field to 7Fh (PERIPHERAL QUALIFIER set to 011b + * and PERIPHERAL DEVICE TYPE set to 1Fh). + * + *The device server is capable of supporting the specified peripheral device + *type on this logical unit. However, the physical device is not currently + *connected to this logical unit. + */ + +#define DEV_NOT_PRESENT 0x7f /* old name - compatibility */ +#define DEV_NOT_CAPABLE 0x7f /* peripheral qualifier of 0x3 */ + /* peripheral type of 0x1f */ + /* specifies no device but target present */ + +#define DEV_DISK_CAPABLE_NOT_PRESENT 0x20 /* peripheral qualifier of 0x1 */ + /* peripheral type of 0 - disk */ + /* specifies device capable, but not present */ + +#define DEV_PROC_CAPABLE_NOT_PRESENT 0x23 /* peripheral qualifier of 0x1 */ + /* peripheral type of 3 - processor */ + /* specifies device capable, but not present */ + +#define DEV_HISUPPORT 0x10; /* HiSup = 1; shows support for report luns */ + /* must be returned for lun 0. */ + +/* NOTE: Linux code assumes inquiry contains 36 bytes. Without checking length +* in buf[4] some linux code accesses bytes beyond 5 to retrieve vendor, product +* & revision. Yikes! So let us always send back 36 bytes, the minimum for +* inquiry result. */ +#define NO_DISK_INQUIRY_RESULT_LEN 36 + +#define MIN_INQUIRY_RESULT_LEN 5 /* we need at least 5 bytes minimum for inquiry + * result */ + +/* SCSI device version for no disk inquiry result */ +#define SCSI_SPC2_VER 4 /* indicates SCSI SPC2 (SPC3 is 5) */ + +/* Windows and Linux want different things for a non-existent lun. So, we'll let + * caller pass in the peripheral qualifier and type. + * NOTE:[4] SCSI returns (n-4); so we return length-1-4 or length-5. */ + +#define SET_NO_DISK_INQUIRY_RESULT(buf, len, lun, lun0notpresent, notpresent) \ + do { \ + MEMSET(buf, 0, \ + MINNUM(len, \ + (unsigned int) NO_DISK_INQUIRY_RESULT_LEN)); \ + buf[2] = (U8) SCSI_SPC2_VER; \ + if (lun == 0) { \ + buf[0] = (U8) lun0notpresent; \ + buf[3] = (U8) DEV_HISUPPORT; \ + } else \ + buf[0] = (U8) notpresent; \ + buf[4] = (U8) ( \ + MINNUM(len, \ + (unsigned int) NO_DISK_INQUIRY_RESULT_LEN) - 5); \ + if (len >= NO_DISK_INQUIRY_RESULT_LEN) { \ + buf[8] = 'D'; \ + buf[9] = 'E'; \ + buf[10] = 'L'; \ + buf[11] = 'L'; \ + buf[16] = 'P'; \ + buf[17] = 'S'; \ + buf[18] = 'E'; \ + buf[19] = 'U'; \ + buf[20] = 'D'; \ + buf[21] = 'O'; \ + buf[22] = ' '; \ + buf[23] = 'D'; \ + buf[24] = 'E'; \ + buf[25] = 'V'; \ + buf[26] = 'I'; \ + buf[27] = 'C'; \ + buf[28] = 'E'; \ + buf[30] = ' '; \ + buf[31] = '.'; \ + } \ + } while (0) + + +/* +* Struct & Defines to support sense information. +*/ + + +/* The following struct is returned in sensebuf field in uiscmdrsp_scsi. It is +* initialized in exactly the manner that is recommended in Windows (hence the +* odd values). +* When set, these fields will have the following values: +* ErrorCode = 0x70 indicates current error +* Valid = 1 indicates sense info is valid +* SenseKey contains sense key as defined by SCSI specs. +* AdditionalSenseCode contains sense key as defined by SCSI specs. +* AdditionalSenseCodeQualifier contains qualifier to sense code as defined by +* scsi docs. +* AdditionalSenseLength contains will be sizeof(sense_data)-8=10. +*/ +struct sense_data { + U8 ErrorCode:7; + U8 Valid:1; + U8 SegmentNumber; + U8 SenseKey:4; + U8 Reserved:1; + U8 IncorrectLength:1; + U8 EndOfMedia:1; + U8 FileMark:1; + U8 Information[4]; + U8 AdditionalSenseLength; + U8 CommandSpecificInformation[4]; + U8 AdditionalSenseCode; + U8 AdditionalSenseCodeQualifier; + U8 FieldReplaceableUnitCode; + U8 SenseKeySpecific[3]; +}; + +/* some SCSI ADSENSE codes */ +#ifndef SCSI_ADSENSE_LUN_NOT_READY +#define SCSI_ADSENSE_LUN_NOT_READY 0x04 +#endif /* */ +#ifndef SCSI_ADSENSE_ILLEGAL_COMMAND +#define SCSI_ADSENSE_ILLEGAL_COMMAND 0x20 +#endif /* */ +#ifndef SCSI_ADSENSE_ILLEGAL_BLOCK +#endif /* */ +#ifndef SCSI_ADSENSE_ILLEGAL_BLOCK +#define SCSI_ADSENSE_ILLEGAL_BLOCK 0x21 +#endif /* */ +#ifndef SCSI_ADSENSE_INVALID_CDB +#define SCSI_ADSENSE_INVALID_CDB 0x24 +#endif /* */ +#ifndef SCSI_ADSENSE_INVALID_LUN +#define SCSI_ADSENSE_INVALID_LUN 0x25 +#endif /* */ +#ifndef SCSI_ADWRITE_PROTECT +#define SCSI_ADWRITE_PROTECT 0x27 +#endif /* */ +#ifndef SCSI_ADSENSE_MEDIUM_CHANGED +#define SCSI_ADSENSE_MEDIUM_CHANGED 0x28 +#endif /* */ +#ifndef SCSI_ADSENSE_BUS_RESET +#define SCSI_ADSENSE_BUS_RESET 0x29 +#endif /* */ +#ifndef SCSI_ADSENSE_NO_MEDIA_IN_DEVICE +#define SCSI_ADSENSE_NO_MEDIA_IN_DEVICE 0x3a +#endif /* */ + +struct net_pkt_xmt { + int len; /* full length of data in the packet */ + int num_frags; /* number of fragments in frags containing data */ + struct phys_info frags[MAX_PHYS_INFO]; /* physical page information for + * each fragment */ + char ethhdr[ETH_HEADER_SIZE]; /* the ethernet header */ + struct { + + /* these are needed for csum at uisnic end */ + U8 valid; /* 1 = rest of this struct is valid - else + * ignore */ + U8 hrawoffv; /* 1 = hwrafoff is valid */ + U8 nhrawoffv; /* 1 = nhwrafoff is valid */ + U16 protocol; /* specifies packet protocol */ + U32 csum; /* value used to set skb->csum at IOPart */ + U32 hrawoff; /* value used to set skb->h.raw at IOPart */ + /* hrawoff points to the start of the TRANSPORT LAYER HEADER */ + U32 nhrawoff; /* value used to set skb->nh.raw at IOPart */ + /* nhrawoff points to the start of the NETWORK LAYER HEADER */ + } lincsum; + + /* **** NOTE **** + * The full packet is described in frags but the ethernet header is + * separately kept in ethhdr so that uisnic doesn't have "MAP" the + * guest memory to get to the header. uisnic needs ethhdr to + * determine how to route the packet. + */ +}; + +struct net_pkt_xmtdone { + U32 xmt_done_result; /* result of NET_XMIT */ +#define XMIT_SUCCESS 0 +#define XMIT_FAILED 1 +}; + +/* RCVPOST_BUF_SIZe must be at most page_size(4096) - cache_line_size (64) The +* reason is because dev_skb_alloc which is used to generate RCV_POST skbs in +* virtnic requires that there is "overhead" in the buffer, and pads 16 bytes. I +* prefer to use 1 full cache line size for "overhead" so that transfers are +* better. IOVM requires that a buffer be represented by 1 phys_info structure +* which can only cover page_size. */ +#define RCVPOST_BUF_SIZE 4032 +#define MAX_NET_RCV_CHAIN \ + ((ETH_MAX_MTU+ETH_HEADER_SIZE + RCVPOST_BUF_SIZE-1) / RCVPOST_BUF_SIZE) + +struct net_pkt_rcvpost { + /* rcv buf size must be large enough to include ethernet data len + + * ethernet header len - we are choosing 2K because it is guaranteed + * to be describable */ + struct phys_info frag; /* physical page information for the + * single fragment 2K rcv buf */ + U64 UniqueNum; /* This is used to make sure that + * receive posts are returned to */ + /* the Adapter which sent them origonally. */ +}; + +struct net_pkt_rcv { + + /* the number of receive buffers that can be chained */ + /* is based on max mtu and size of each rcv buf */ + U32 rcv_done_len; /* length of received data */ + U8 numrcvbufs; /* number of receive buffers that contain the */ + /* incoming data; guest end MUST chain these together. */ + void *rcvbuf[MAX_NET_RCV_CHAIN]; /* the list of receive buffers + * that must be chained; */ + /* each entry is a receive buffer provided by NET_RCV_POST. */ + /* NOTE: first rcvbuf in the chain will also be provided in net.buf. */ + U64 UniqueNum; + U32 RcvsDroppedDelta; +}; + +struct net_pkt_enbdis { + void *context; + U16 enable; /* 1 = enable, 0 = disable */ +}; + +struct net_pkt_macaddr { + void *context; + U8 macaddr[MAX_MACADDR_LEN]; /* 6 bytes */ +}; + +/* cmd rsp packet used for VNIC network traffic */ +struct uiscmdrsp_net { + NET_TYPES type; + void *buf; + union { + struct net_pkt_xmt xmt; /* used for NET_XMIT */ + struct net_pkt_xmtdone xmtdone; /* used for NET_XMIT_DONE */ + struct net_pkt_rcvpost rcvpost; /* used for NET_RCV_POST */ + struct net_pkt_rcv rcv; /* used for NET_RCV */ + struct net_pkt_enbdis enbdis; /* used for NET_RCV_ENBDIS, */ + /* NET_RCV_ENBDIS_ACK, */ + /* NET_RCV_PROMSIC, */ + /* and NET_CONNECT_STATUS */ + struct net_pkt_macaddr macaddr; + }; +}; + +struct uiscmdrsp_scsitaskmgmt { + TASK_MGMT_TYPES tasktype; + + /* the type of task */ + struct uisscsi_dest vdest; + + /* the vdisk for which this task mgmt is generated */ + void *scsicmd; + + /* This is some handle that the guest has saved off for its own use. + * Its value is preserved by iopart & returned as is in the task mgmt + * rsp. */ + void *notify; + + /* For linux guests, this is a pointer to wait_queue_head that a + * thread is waiting on to see if the taskmgmt command has completed. + * For windows guests, this is a pointer to a location that a waiting + * thread is testing to see if the taskmgmt command has completed. + * When the rsp is received by guest, the thread receiving the + * response uses this to notify the the thread waiting for taskmgmt + * command completion. Its value is preserved by iopart & returned + * as is in the task mgmt rsp. */ + void *notifyresult; + + /* this is a handle to location in guest where the result of the + * taskmgmt command (result field) is to saved off when the response + * is handled. Its value is preserved by iopart & returned as is in + * the task mgmt rsp. */ + char result; + + /* result of taskmgmt command - set by IOPart - values are: */ +#define TASK_MGMT_FAILED 0 +#define TASK_MGMT_SUCCESS 1 +}; + +/* The following is used by uissd to send disk add/remove notifications to + * Guest */ +/* Note that the vHba pointer is not used by the Client/Guest side. */ +struct uiscmdrsp_disknotify { + U8 add; /* 0-remove, 1-add */ + void *vHba; /* Pointer to vhba_info for channel info to + * route msg */ + U32 channel, id, lun; /* SCSI Path of Disk to added or removed */ +}; + +/* The following is used by virthba/vSCSI to send the Acquire/Release commands +* to the IOVM. */ +struct uiscmdrsp_vdiskmgmt { + VDISK_MGMT_TYPES vdisktype; + + /* the type of task */ + struct uisscsi_dest vdest; + + /* the vdisk for which this task mgmt is generated */ + void *scsicmd; + + /* This is some handle that the guest has saved off for its own use. + * Its value is preserved by iopart & returned as is in the task mgmt + * rsp. */ + void *notify; + + /* For linux guests, this is a pointer to wait_queue_head that a + * thread is waiting on to see if the taskmgmt command has completed. + * For windows guests, this is a pointer to a location that a waiting + * thread is testing to see if the taskmgmt command has completed. + * When the rsp is received by guest, the thread receiving the + * response uses this to notify the the thread waiting for taskmgmt + * command completion. Its value is preserved by iopart & returned + * as is in the task mgmt rsp. */ + void *notifyresult; + + /* this is a handle to location in guest where the result of the + * taskmgmt command (result field) is to saved off when the response + * is handled. Its value is preserved by iopart & returned as is in + * the task mgmt rsp. */ + char result; + + /* result of taskmgmt command - set by IOPart - values are: */ +#define VDISK_MGMT_FAILED 0 +#define VDISK_MGMT_SUCCESS 1 +}; + +/* keeping cmd & rsp info in one structure for now cmd rsp packet for scsi */ +struct uiscmdrsp { + char cmdtype; + + /* describes what type of information is in the struct */ +#define CMD_SCSI_TYPE 1 +#define CMD_NET_TYPE 2 +#define CMD_SCSITASKMGMT_TYPE 3 +#define CMD_NOTIFYGUEST_TYPE 4 +#define CMD_VDISKMGMT_TYPE 5 + union { + struct uiscmdrsp_scsi scsi; + struct uiscmdrsp_net net; + struct uiscmdrsp_scsitaskmgmt scsitaskmgmt; + struct uiscmdrsp_disknotify disknotify; + struct uiscmdrsp_vdiskmgmt vdiskmgmt; + }; + void *private_data; /* used to send the response when the cmd is + * done (scsi & scsittaskmgmt). */ + struct uiscmdrsp *next; /* General Purpose Queue Link */ + struct uiscmdrsp *activeQ_next; /* Used to track active commands */ + struct uiscmdrsp *activeQ_prev; /* Used to track active commands */ +}; + +/* This is just the header of the IO channel. It is assumed that directly after +* this header there is a large region of memory which contains the command and +* response queues as specified in cmdQ and rspQ SIGNAL_QUEUE_HEADERS. */ +typedef struct _ULTRA_IO_CHANNEL_PROTOCOL { + CHANNEL_HEADER ChannelHeader; + SIGNAL_QUEUE_HEADER cmdQ; + SIGNAL_QUEUE_HEADER rspQ; + union { + struct { + struct vhba_wwnn wwnn; /* 8 bytes */ + struct vhba_config_max max; /* 20 bytes */ + } vhba; /* 28 */ + struct { + U8 macaddr[MAX_MACADDR_LEN]; /* 6 bytes */ + U32 num_rcv_bufs; /* 4 */ + U32 mtu; /* 4 */ + GUID zoneGuid; /* 16 */ + } vnic; /* total 30 */ + }; + +#define MAX_CLIENTSTRING_LEN 1024 + U8 clientString[MAX_CLIENTSTRING_LEN]; /* NULL terminated - so holds + * max - 1 bytes */ +} ULTRA_IO_CHANNEL_PROTOCOL; + +#pragma pack(pop) +/* ///////////// END PRAGMA PACK PUSH 1 /////////////////////////// */ + +/* define offsets to members of struct uiscmdrsp */ +#define OFFSET_CMDTYPE OFFSETOF(struct uiscmdrsp, cmdtype) +#define OFFSET_SCSI OFFSETOF(struct uiscmdrsp, scsi) +#define OFFSET_NET OFFSETOF(struct uiscmdrsp, net) +#define OFFSET_SCSITASKMGMT OFFSETOF(struct uiscmdrsp, scsitaskmgmt) +#define OFFSET_NEXT OFFSETOF(struct uiscmdrsp, next) + +/* define offsets to members of struct uiscmdrsp_net */ +#define OFFSET_TYPE OFFSETOF(struct uiscmdrsp_net, type) +#define OFFSET_BUF OFFSETOF(struct uiscmdrsp_net, buf) +#define OFFSET_XMT OFFSETOF(struct uiscmdrsp_net, xmt) +#define OFFSET_XMT_DONE_RESULT OFFSETOF(struct uiscmdrsp_net, xmtdone) +#define OFFSET_RCVPOST OFFSETOF(struct uiscmdrsp_net, rcvpost) +#define OFFSET_RCV_DONE_LEN OFFSETOF(struct uiscmdrsp_net, rcv) +#define OFFSET_ENBDIS OFFSETOF(struct uiscmdrsp_net, enbdis) + +/* define offsets to members of struct net_pkt_rcvpost */ +#define OFFSET_TOTALLEN OFFSETOF(struct net_pkt_rcvpost, totallen) +#define OFFSET_FRAG OFFSETOF(struct net_pkt_rcvpost, frag) + +/* +* INLINE functions for initializing and accessing I/O data channels +*/ + + +#define NUMSIGNALS(x, q) (((ULTRA_IO_CHANNEL_PROTOCOL *)(x))->q.MaxSignalSlots) +#define SIZEOF_PROTOCOL (COVER(sizeof(ULTRA_IO_CHANNEL_PROTOCOL), 64)) +#define SIZEOF_CMDRSP (COVER(sizeof(struct uiscmdrsp), 64)) + +#define IO_CHANNEL_SIZE(x) COVER(SIZEOF_PROTOCOL + \ + (NUMSIGNALS(x, cmdQ) + \ + NUMSIGNALS(x, rspQ)) * SIZEOF_CMDRSP, 4096) +#define MIN_IO_CHANNEL_SIZE COVER(SIZEOF_PROTOCOL + \ + 2 * MIN_NUMSIGNALS * SIZEOF_CMDRSP, 4096) +#ifdef __GNUC__ +/* These defines should only ever be used in service partitons */ +/* because they rely on the size of uiscmdrsp */ +#define QSLOTSFROMBYTES(bytes) (((bytes-SIZEOF_PROTOCOL)/2)/SIZEOF_CMDRSP) +#define QSIZEFROMBYTES(bytes) (QSLOTSFROMBYTES(bytes)*SIZEOF_CMDRSP) +#define SignalQInit(x) \ + do { \ + x->cmdQ.Size = QSIZEFROMBYTES(x->ChannelHeader.Size); \ + x->cmdQ.oSignalBase = SIZEOF_PROTOCOL - \ + OFFSETOF(ULTRA_IO_CHANNEL_PROTOCOL, cmdQ); \ + x->cmdQ.SignalSize = SIZEOF_CMDRSP; \ + x->cmdQ.MaxSignalSlots = \ + QSLOTSFROMBYTES(x->ChannelHeader.Size); \ + x->cmdQ.MaxSignals = x->cmdQ.MaxSignalSlots - 1; \ + x->rspQ.Size = QSIZEFROMBYTES(x->ChannelHeader.Size); \ + x->rspQ.oSignalBase = \ + (SIZEOF_PROTOCOL + x->cmdQ.Size) - \ + OFFSETOF(ULTRA_IO_CHANNEL_PROTOCOL, rspQ); \ + x->rspQ.SignalSize = SIZEOF_CMDRSP; \ + x->rspQ.MaxSignalSlots = \ + QSLOTSFROMBYTES(x->ChannelHeader.Size); \ + x->rspQ.MaxSignals = x->rspQ.MaxSignalSlots - 1; \ + x->ChannelHeader.oChannelSpace = \ + OFFSETOF(ULTRA_IO_CHANNEL_PROTOCOL, cmdQ); \ + } while (0) + +#define INIT_CLIENTSTRING(chan, type, clientStr, clientStrLen) \ + do { \ + if (clientStr) { \ + chan->ChannelHeader.oClientString = \ + OFFSETOF(type, clientString); \ + MEMCPY(chan->clientString, clientStr, \ + MINNUM(clientStrLen, \ + (U32) (MAX_CLIENTSTRING_LEN - 1))); \ + chan->clientString[MINNUM(clientStrLen, \ + (U32) (MAX_CLIENTSTRING_LEN \ + - 1))] \ + = '\0'; \ + } \ + else \ + if (clientStrLen > 0) \ + return 0; \ + } while (0) + + +#define ULTRA_IO_CHANNEL_SERVER_READY(x, chanId, logCtx) \ + ULTRA_CHANNEL_SERVER_TRANSITION(x, chanId, SrvState, CHANNELSRV_READY, \ + logCtx); + +#define ULTRA_IO_CHANNEL_SERVER_NOTREADY(x, chanId, logCtx) \ + ULTRA_CHANNEL_SERVER_TRANSITION(x, chanId, SrvState, \ + CHANNELSRV_UNINITIALIZED, logCtx); + +static inline int ULTRA_VHBA_init_channel(ULTRA_IO_CHANNEL_PROTOCOL *x, + struct vhba_wwnn *wwnn, + struct vhba_config_max *max, + unsigned char *clientStr, + U32 clientStrLen, U64 bytes) { + MEMSET(x, 0, sizeof(ULTRA_IO_CHANNEL_PROTOCOL)); + x->ChannelHeader.VersionId = ULTRA_VHBA_CHANNEL_PROTOCOL_VERSIONID; + x->ChannelHeader.Signature = ULTRA_VHBA_CHANNEL_PROTOCOL_SIGNATURE; + x->ChannelHeader.SrvState = CHANNELSRV_UNINITIALIZED; + x->ChannelHeader.HeaderSize = sizeof(x->ChannelHeader); + x->ChannelHeader.Size = COVER(bytes, 4096); + x->ChannelHeader.Type = UltraVhbaChannelProtocolGuid; + x->ChannelHeader.ZoneGuid = Guid0; + x->vhba.wwnn = *wwnn; + x->vhba.max = *max; + INIT_CLIENTSTRING(x, ULTRA_IO_CHANNEL_PROTOCOL, clientStr, + clientStrLen); + SignalQInit(x); + if ((x->cmdQ.MaxSignalSlots > MAX_NUMSIGNALS) || + (x->rspQ.MaxSignalSlots > MAX_NUMSIGNALS)) { + return 0; + } + if ((x->cmdQ.MaxSignalSlots < MIN_NUMSIGNALS) || + (x->rspQ.MaxSignalSlots < MIN_NUMSIGNALS)) { + return 0; + } + return 1; +} + +static inline void ULTRA_VHBA_set_max(ULTRA_IO_CHANNEL_PROTOCOL *x, + struct vhba_config_max *max) { + x->vhba.max = *max; +} + +static inline int ULTRA_VNIC_init_channel(ULTRA_IO_CHANNEL_PROTOCOL *x, + unsigned char *macaddr, + U32 num_rcv_bufs, U32 mtu, + GUID zoneGuid, + unsigned char *clientStr, + U32 clientStrLen, + U64 bytes) { + MEMSET(x, 0, sizeof(ULTRA_IO_CHANNEL_PROTOCOL)); + x->ChannelHeader.VersionId = ULTRA_VNIC_CHANNEL_PROTOCOL_VERSIONID; + x->ChannelHeader.Signature = ULTRA_VNIC_CHANNEL_PROTOCOL_SIGNATURE; + x->ChannelHeader.SrvState = CHANNELSRV_UNINITIALIZED; + x->ChannelHeader.HeaderSize = sizeof(x->ChannelHeader); + x->ChannelHeader.Size = COVER(bytes, 4096); + x->ChannelHeader.Type = UltraVnicChannelProtocolGuid; + x->ChannelHeader.ZoneGuid = Guid0; + MEMCPY(x->vnic.macaddr, macaddr, MAX_MACADDR_LEN); + x->vnic.num_rcv_bufs = num_rcv_bufs; + x->vnic.mtu = mtu; + x->vnic.zoneGuid = zoneGuid; + INIT_CLIENTSTRING(x, ULTRA_IO_CHANNEL_PROTOCOL, clientStr, + clientStrLen); + SignalQInit(x); + if ((x->cmdQ.MaxSignalSlots > MAX_NUMSIGNALS) || + (x->rspQ.MaxSignalSlots > MAX_NUMSIGNALS)) { + return 0; + } + if ((x->cmdQ.MaxSignalSlots < MIN_NUMSIGNALS) || + (x->rspQ.MaxSignalSlots < MIN_NUMSIGNALS)) { + return 0; + } + return 1; +} + +#endif /* __GNUC__ */ + +/* +* INLINE function for expanding a guest's pfn-off-size into multiple 4K page +* pfn-off-size entires. +*/ + + +/* we deal with 4K page sizes when we it comes to passing page information + * between */ +/* Guest and IOPartition. */ +#define PI_PAGE_SIZE 0x1000 +#define PI_PAGE_MASK 0x0FFF +#define PI_PAGE_SHIFT 12 + +/* returns next non-zero index on success or zero on failure (i.e. out of + * room) + */ +static INLINE U16 +add_physinfo_entries(U32 inp_pfn, /* input - specifies the pfn to be used + * to add entries */ + U16 inp_off, /* input - specifies the off to be used + * to add entries */ + U32 inp_len, /* input - specifies the len to be used + * to add entries */ + U16 index, /* input - index in array at which new + * entries are added */ + U16 max_pi_arr_entries, /* input - specifies the maximum + * entries pi_arr can hold */ + struct phys_info pi_arr[]) /* input & output - array to + * which entries are added */ +{ + U32 len; + U16 i, firstlen; + + firstlen = PI_PAGE_SIZE - inp_off; + if (inp_len <= firstlen) { + + /* the input entry spans only one page - add as is */ + if (index >= max_pi_arr_entries) + return 0; + pi_arr[index].pi_pfn = inp_pfn; + pi_arr[index].pi_off = (U16) inp_off; + pi_arr[index].pi_len = (U16) inp_len; + return index + 1; + } + + /* this entry spans multiple pages */ + for (len = inp_len, i = 0; len; + len -= pi_arr[index + i].pi_len, i++) { + if (index + i >= max_pi_arr_entries) + return 0; + pi_arr[index + i].pi_pfn = inp_pfn + i; + if (i == 0) { + pi_arr[index].pi_off = inp_off; + pi_arr[index].pi_len = firstlen; + } + + else { + pi_arr[index + i].pi_off = 0; + pi_arr[index + i].pi_len = + (U16) MINNUM(len, (U32) PI_PAGE_SIZE); + } + + } + return index + i; +} + +#endif /* __IOCHANNEL_H__ */ diff --git a/drivers/staging/unisys/common-spar/include/channels/vbuschannel.h b/drivers/staging/unisys/common-spar/include/channels/vbuschannel.h new file mode 100644 index 00000000000..ec5a8c0fd50 --- /dev/null +++ b/drivers/staging/unisys/common-spar/include/channels/vbuschannel.h @@ -0,0 +1,127 @@ +/* Copyright © 2010 - 2013 UNISYS CORPORATION + * 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. + */ + +#ifndef __VBUSCHANNEL_H__ +#define __VBUSCHANNEL_H__ + +/* The vbus channel is the channel area provided via the BUS_CREATE controlvm + * message for each virtual bus. This channel area is provided to both server + * and client ends of the bus. The channel header area is initialized by + * the server, and the remaining information is filled in by the client. + * We currently use this for the client to provide various information about + * the client devices and client drivers for the server end to see. + */ +#include "commontypes.h" +#include "vbusdeviceinfo.h" +#include "channel.h" + +/* {193b331b-c58f-11da-95a9-00e08161165f} */ +#define ULTRA_VBUS_CHANNEL_PROTOCOL_GUID \ + {0x193b331b, 0xc58f, 0x11da, \ + {0x95, 0xa9, 0x0, 0xe0, 0x81, 0x61, 0x16, 0x5f} } +static const GUID UltraVbusChannelProtocolGuid = + ULTRA_VBUS_CHANNEL_PROTOCOL_GUID; + +#define ULTRA_VBUS_CHANNEL_PROTOCOL_SIGNATURE ULTRA_CHANNEL_PROTOCOL_SIGNATURE + +/* Must increment this whenever you insert or delete fields within this channel +* struct. Also increment whenever you change the meaning of fields within this +* channel struct so as to break pre-existing software. Note that you can +* usually add fields to the END of the channel struct withOUT needing to +* increment this. */ +#define ULTRA_VBUS_CHANNEL_PROTOCOL_VERSIONID 1 + +#define ULTRA_VBUS_CHANNEL_OK_CLIENT(pChannel, logCtx) \ + (ULTRA_check_channel_client(pChannel, \ + UltraVbusChannelProtocolGuid, \ + "vbus", \ + sizeof(ULTRA_VBUS_CHANNEL_PROTOCOL), \ + ULTRA_VBUS_CHANNEL_PROTOCOL_VERSIONID, \ + ULTRA_VBUS_CHANNEL_PROTOCOL_SIGNATURE, \ + __FILE__, __LINE__, logCtx)) + +#define ULTRA_VBUS_CHANNEL_OK_SERVER(actualBytes, logCtx) \ + (ULTRA_check_channel_server(UltraVbusChannelProtocolGuid, \ + "vbus", \ + sizeof(ULTRA_VBUS_CHANNEL_PROTOCOL), \ + actualBytes, \ + __FILE__, __LINE__, logCtx)) + + +#pragma pack(push, 1) /* both GCC and VC now allow this pragma */ +typedef struct _ULTRA_VBUS_HEADERINFO { + U32 structBytes; /* size of this struct in bytes */ + U32 deviceInfoStructBytes; /* sizeof(ULTRA_VBUS_DEVICEINFO) */ + U32 devInfoCount; /* num of items in DevInfo member */ + /* (this is the allocated size) */ + U32 chpInfoByteOffset; /* byte offset from beginning of this struct */ + /* to the the ChpInfo struct (below) */ + U32 busInfoByteOffset; /* byte offset from beginning of this struct */ + /* to the the BusInfo struct (below) */ + U32 devInfoByteOffset; /* byte offset from beginning of this struct */ + /* to the the DevInfo array (below) */ + U8 reserved[104]; +} ULTRA_VBUS_HEADERINFO; + +typedef struct _ULTRA_VBUS_CHANNEL_PROTOCOL { + ULTRA_CHANNEL_PROTOCOL ChannelHeader; /* initialized by server */ + ULTRA_VBUS_HEADERINFO HdrInfo; /* initialized by server */ + /* the remainder of this channel is filled in by the client */ + ULTRA_VBUS_DEVICEINFO ChpInfo; /* describes client chipset device and + * driver */ + ULTRA_VBUS_DEVICEINFO BusInfo; /* describes client bus device and + * driver */ + ULTRA_VBUS_DEVICEINFO DevInfo[0]; /* describes client device and + * driver for */ + /* each device on the bus */ +} ULTRA_VBUS_CHANNEL_PROTOCOL; + +#define VBUS_CH_SIZE_EXACT(MAXDEVICES) \ + (sizeof(ULTRA_VBUS_CHANNEL_PROTOCOL) + ((MAXDEVICES) * \ + sizeof(ULTRA_VBUS_DEVICEINFO))) +#define VBUS_CH_SIZE(MAXDEVICES) COVER(VBUS_CH_SIZE_EXACT(MAXDEVICES), 4096) + +static INLINE void +ULTRA_VBUS_init_channel(ULTRA_VBUS_CHANNEL_PROTOCOL *x, int bytesAllocated) +{ + /* Please note that the memory at <x> does NOT necessarily have space + * for DevInfo structs allocated at the end, which is why we do NOT use + * <bytesAllocated> to clear. */ + MEMSET(x, 0, sizeof(ULTRA_VBUS_CHANNEL_PROTOCOL)); + if (bytesAllocated < (int) sizeof(ULTRA_VBUS_CHANNEL_PROTOCOL)) + return; + x->ChannelHeader.VersionId = ULTRA_VBUS_CHANNEL_PROTOCOL_VERSIONID; + x->ChannelHeader.Signature = ULTRA_VBUS_CHANNEL_PROTOCOL_SIGNATURE; + x->ChannelHeader.SrvState = CHANNELSRV_READY; + x->ChannelHeader.HeaderSize = sizeof(x->ChannelHeader); + x->ChannelHeader.Size = bytesAllocated; + x->ChannelHeader.Type = UltraVbusChannelProtocolGuid; + x->ChannelHeader.ZoneGuid = Guid0; + x->HdrInfo.structBytes = sizeof(ULTRA_VBUS_HEADERINFO); + x->HdrInfo.chpInfoByteOffset = sizeof(ULTRA_VBUS_HEADERINFO); + x->HdrInfo.busInfoByteOffset = x->HdrInfo.chpInfoByteOffset + + sizeof(ULTRA_VBUS_DEVICEINFO); + x->HdrInfo.devInfoByteOffset = x->HdrInfo.busInfoByteOffset + + sizeof(ULTRA_VBUS_DEVICEINFO); + x->HdrInfo.deviceInfoStructBytes = sizeof(ULTRA_VBUS_DEVICEINFO); + bytesAllocated -= (sizeof(ULTRA_CHANNEL_PROTOCOL) + + x->HdrInfo.devInfoByteOffset); + x->HdrInfo.devInfoCount = + bytesAllocated / x->HdrInfo.deviceInfoStructBytes; +} + +#pragma pack(pop) + +#endif diff --git a/drivers/staging/unisys/common-spar/include/controlvmcompletionstatus.h b/drivers/staging/unisys/common-spar/include/controlvmcompletionstatus.h new file mode 100644 index 00000000000..de30d321d98 --- /dev/null +++ b/drivers/staging/unisys/common-spar/include/controlvmcompletionstatus.h @@ -0,0 +1,92 @@ +/* controlvmcompletionstatus.c + * + * Copyright © 2010 - 2013 UNISYS CORPORATION + * 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. + */ + +/* Defines for all valid values returned in the response message header + * completionStatus field. See controlvmchannel.h for description of + * the header: _CONTROLVM_MESSAGE_HEADER. + */ + +#ifndef __CONTROLVMCOMPLETIONSTATUS_H__ +#define __CONTROLVMCOMPLETIONSTATUS_H__ + +/* General Errors------------------------------------------------------[0-99] */ +#define CONTROLVM_RESP_SUCCESS 0 +#define CONTROLVM_RESP_ERROR_ALREADY_DONE 1 +#define CONTROLVM_RESP_ERROR_IOREMAP_FAILED 2 +#define CONTROLVM_RESP_ERROR_KMALLOC_FAILED 3 +#define CONTROLVM_RESP_ERROR_MESSAGE_ID_UNKNOWN 4 +#define CONTROLVM_RESP_ERROR_MESSAGE_ID_INVALID_FOR_CLIENT 5 + +/* CONTROLVM_INIT_CHIPSET-------------------------------------------[100-199] */ +#define CONTROLVM_RESP_ERROR_CLIENT_SWITCHCOUNT_NONZERO 100 +#define CONTROLVM_RESP_ERROR_EXPECTED_CHIPSET_INIT 101 + +/* Maximum Limit----------------------------------------------------[200-299] */ +#define CONTROLVM_RESP_ERROR_MAX_BUSES 201 /* BUS_CREATE */ +#define CONTROLVM_RESP_ERROR_MAX_DEVICES 202 /* DEVICE_CREATE */ +/* Payload and Parameter Related------------------------------------[400-499] */ +#define CONTROLVM_RESP_ERROR_PAYLOAD_INVALID 400 /* SWITCH_ATTACHEXTPORT, + * DEVICE_CONFIGURE */ +#define CONTROLVM_RESP_ERROR_INITIATOR_PARAMETER_INVALID 401 /* Multiple */ +#define CONTROLVM_RESP_ERROR_TARGET_PARAMETER_INVALID 402 /* DEVICE_CONFIGURE */ +#define CONTROLVM_RESP_ERROR_CLIENT_PARAMETER_INVALID 403 /* DEVICE_CONFIGURE */ +/* Specified[Packet Structure] Value-------------------------------[500-599] */ +#define CONTROLVM_RESP_ERROR_BUS_INVALID 500 /* SWITCH_ATTACHINTPORT, + * BUS_CONFIGURE, + * DEVICE_CREATE, + * DEVICE_CONFIG + * DEVICE_DESTROY */ +#define CONTROLVM_RESP_ERROR_DEVICE_INVALID 501 /* SWITCH_ATTACHINTPORT */ + /* DEVICE_CREATE, + * DEVICE_CONFIGURE, + * DEVICE_DESTROY */ +#define CONTROLVM_RESP_ERROR_CHANNEL_INVALID 502 /* DEVICE_CREATE, + * DEVICE_CONFIGURE */ +/* Partition Driver Callback Interface----------------------[600-699] */ +#define CONTROLVM_RESP_ERROR_VIRTPCI_DRIVER_FAILURE 604 /* BUS_CREATE, + * BUS_DESTROY, + * DEVICE_CREATE, + * DEVICE_DESTROY */ +/* Unable to invoke VIRTPCI callback */ +#define CONTROLVM_RESP_ERROR_VIRTPCI_DRIVER_CALLBACK_ERROR 605 /* BUS_CREATE, + * BUS_DESTROY, + * DEVICE_CREATE, + * DEVICE_DESTROY */ +/* VIRTPCI Callback returned error */ +#define CONTROLVM_RESP_ERROR_GENERIC_DRIVER_CALLBACK_ERROR 606 /* SWITCH_ATTACHEXTPORT, + * SWITCH_DETACHEXTPORT + * DEVICE_CONFIGURE */ + +/* generic device callback returned error */ +/* Bus Related------------------------------------------------------[700-799] */ +#define CONTROLVM_RESP_ERROR_BUS_DEVICE_ATTACHED 700 /* BUS_DESTROY */ +/* Channel Related--------------------------------------------------[800-899] */ +#define CONTROLVM_RESP_ERROR_CHANNEL_TYPE_UNKNOWN 800 /* GET_CHANNELINFO, + * DEVICE_DESTROY */ +#define CONTROLVM_RESP_ERROR_CHANNEL_SIZE_TOO_SMALL 801 /* DEVICE_CREATE */ +/* Chipset Shutdown Related---------------------------------------[1000-1099] */ +#define CONTROLVM_RESP_ERROR_CHIPSET_SHUTDOWN_FAILED 1000 +#define CONTROLVM_RESP_ERROR_CHIPSET_SHUTDOWN_ALREADY_ACTIVE 1001 + +/* Chipset Stop Related-------------------------------------------[1100-1199] */ +#define CONTROLVM_RESP_ERROR_CHIPSET_STOP_FAILED_BUS 1100 +#define CONTROLVM_RESP_ERROR_CHIPSET_STOP_FAILED_SWITCH 1101 + +/* Device Related-------------------------------------------------[1400-1499] */ +#define CONTROLVM_RESP_ERROR_DEVICE_UDEV_TIMEOUT 1400 + +#endif /* __CONTROLVMCOMPLETIONSTATUS_H__ not defined */ diff --git a/drivers/staging/unisys/common-spar/include/diagnostics/appos_subsystems.h b/drivers/staging/unisys/common-spar/include/diagnostics/appos_subsystems.h new file mode 100644 index 00000000000..4c6294d2060 --- /dev/null +++ b/drivers/staging/unisys/common-spar/include/diagnostics/appos_subsystems.h @@ -0,0 +1,310 @@ +/* Copyright © 2010 - 2013 UNISYS CORPORATION + * 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. + */ + +/* Please note that this file is to be used ONLY for defining diagnostic + * subsystem values for the appos (sPAR Linux service partitions) component. + */ +#ifndef __APPOS_SUBSYSTEMS_H__ +#define __APPOS_SUBSYSTEMS_H__ + +#ifdef __KERNEL__ +#include <linux/kernel.h> +#include <linux/string.h> +#else +#include <stdio.h> +#include <string.h> +#endif + +static inline char * +subsys_unknown_to_s(int subsys, char *s, int n) +{ + snprintf(s, n, "SUBSYS-%-2.2d", subsys); + s[n - 1] = '\0'; + return s; +} + +#define SUBSYS_TO_MASK(subsys) (1ULL << (subsys)) + +/* The first SUBSYS_APPOS_MAX subsystems are the same for each AppOS type + * (IOVM, SMS, etc.) The rest have unique values for each AppOS type. + */ +#define SUBSYS_APPOS_MAX 16 + +#define SUBSYS_APPOS_DEFAULT 1 /* or "other" */ +#define SUBSYS_APPOS_CHIPSET 2 /* controlvm and other */ + /* low-level sPAR activity */ +#define SUBSYS_APPOS_BUS 3 /* sPAR bus */ +/* DAK #define SUBSYS_APPOS_DIAG 4 // diagnostics and dump */ +#define SUBSYS_APPOS_CHANNELACCESS 5 /* generic channel access */ +#define SUBSYS_APPOS_NICCLIENT 6 /* virtual NIC client */ +#define SUBSYS_APPOS_HBACLIENT 7 /* virtual HBA client */ +#define SUBSYS_APPOS_CONSOLESERIAL 8 /* sPAR virtual serial console */ +#define SUBSYS_APPOS_UISLIB 9 /* */ +#define SUBSYS_APPOS_VRTCUPDD 10 /* */ +#define SUBSYS_APPOS_WATCHDOG 11 /* watchdog timer and healthcheck */ +#define SUBSYS_APPOS_13 13 /* available */ +#define SUBSYS_APPOS_14 14 /* available */ +#define SUBSYS_APPOS_15 15 /* available */ +#define SUBSYS_APPOS_16 16 /* available */ +static inline char * +subsys_generic_to_s(int subsys, char *s, int n) +{ + switch (subsys) { + case SUBSYS_APPOS_DEFAULT: + strncpy(s, "APPOS_DEFAULT", n); + break; + case SUBSYS_APPOS_CHIPSET: + strncpy(s, "APPOS_CHIPSET", n); + break; + case SUBSYS_APPOS_BUS: + strncpy(s, "APPOS_BUS", n); + break; + case SUBSYS_APPOS_CHANNELACCESS: + strncpy(s, "APPOS_CHANNELACCESS", n); + break; + case SUBSYS_APPOS_NICCLIENT: + strncpy(s, "APPOS_NICCLIENT", n); + break; + case SUBSYS_APPOS_HBACLIENT: + strncpy(s, "APPOS_HBACLIENT", n); + break; + case SUBSYS_APPOS_CONSOLESERIAL: + strncpy(s, "APPOS_CONSOLESERIAL", n); + break; + case SUBSYS_APPOS_UISLIB: + strncpy(s, "APPOS_UISLIB", n); + break; + case SUBSYS_APPOS_VRTCUPDD: + strncpy(s, "APPOS_VRTCUPDD", n); + break; + case SUBSYS_APPOS_WATCHDOG: + strncpy(s, "APPOS_WATCHDOG", n); + break; + case SUBSYS_APPOS_13: + strncpy(s, "APPOS_13", n); + break; + case SUBSYS_APPOS_14: + strncpy(s, "APPOS_14", n); + break; + case SUBSYS_APPOS_15: + strncpy(s, "APPOS_15", n); + break; + case SUBSYS_APPOS_16: + strncpy(s, "APPOS_16", n); + break; + default: + subsys_unknown_to_s(subsys, s, n); + break; + } + s[n - 1] = '\0'; + return s; +} + +/* CONSOLE */ + +#define SUBSYS_CONSOLE_VIDEO (SUBSYS_APPOS_MAX + 1) /* 17 */ +#define SUBSYS_CONSOLE_KBDMOU (SUBSYS_APPOS_MAX + 2) /* 18 */ +#define SUBSYS_CONSOLE_04 (SUBSYS_APPOS_MAX + 4) +#define SUBSYS_CONSOLE_05 (SUBSYS_APPOS_MAX + 5) +#define SUBSYS_CONSOLE_06 (SUBSYS_APPOS_MAX + 6) +#define SUBSYS_CONSOLE_07 (SUBSYS_APPOS_MAX + 7) +#define SUBSYS_CONSOLE_08 (SUBSYS_APPOS_MAX + 8) +#define SUBSYS_CONSOLE_09 (SUBSYS_APPOS_MAX + 9) +#define SUBSYS_CONSOLE_10 (SUBSYS_APPOS_MAX + 10) +#define SUBSYS_CONSOLE_11 (SUBSYS_APPOS_MAX + 11) +#define SUBSYS_CONSOLE_12 (SUBSYS_APPOS_MAX + 12) +#define SUBSYS_CONSOLE_13 (SUBSYS_APPOS_MAX + 13) +#define SUBSYS_CONSOLE_14 (SUBSYS_APPOS_MAX + 14) +#define SUBSYS_CONSOLE_15 (SUBSYS_APPOS_MAX + 15) +#define SUBSYS_CONSOLE_16 (SUBSYS_APPOS_MAX + 16) +#define SUBSYS_CONSOLE_17 (SUBSYS_APPOS_MAX + 17) +#define SUBSYS_CONSOLE_18 (SUBSYS_APPOS_MAX + 18) +#define SUBSYS_CONSOLE_19 (SUBSYS_APPOS_MAX + 19) +#define SUBSYS_CONSOLE_20 (SUBSYS_APPOS_MAX + 20) +#define SUBSYS_CONSOLE_21 (SUBSYS_APPOS_MAX + 21) +#define SUBSYS_CONSOLE_22 (SUBSYS_APPOS_MAX + 22) +#define SUBSYS_CONSOLE_23 (SUBSYS_APPOS_MAX + 23) +#define SUBSYS_CONSOLE_24 (SUBSYS_APPOS_MAX + 24) +#define SUBSYS_CONSOLE_25 (SUBSYS_APPOS_MAX + 25) +#define SUBSYS_CONSOLE_26 (SUBSYS_APPOS_MAX + 26) +#define SUBSYS_CONSOLE_27 (SUBSYS_APPOS_MAX + 27) +#define SUBSYS_CONSOLE_28 (SUBSYS_APPOS_MAX + 28) +#define SUBSYS_CONSOLE_29 (SUBSYS_APPOS_MAX + 29) +#define SUBSYS_CONSOLE_30 (SUBSYS_APPOS_MAX + 30) +#define SUBSYS_CONSOLE_31 (SUBSYS_APPOS_MAX + 31) +#define SUBSYS_CONSOLE_32 (SUBSYS_APPOS_MAX + 32) +#define SUBSYS_CONSOLE_33 (SUBSYS_APPOS_MAX + 33) +#define SUBSYS_CONSOLE_34 (SUBSYS_APPOS_MAX + 34) +#define SUBSYS_CONSOLE_35 (SUBSYS_APPOS_MAX + 35) +#define SUBSYS_CONSOLE_36 (SUBSYS_APPOS_MAX + 36) +#define SUBSYS_CONSOLE_37 (SUBSYS_APPOS_MAX + 37) +#define SUBSYS_CONSOLE_38 (SUBSYS_APPOS_MAX + 38) +#define SUBSYS_CONSOLE_39 (SUBSYS_APPOS_MAX + 39) +#define SUBSYS_CONSOLE_40 (SUBSYS_APPOS_MAX + 40) +#define SUBSYS_CONSOLE_41 (SUBSYS_APPOS_MAX + 41) +#define SUBSYS_CONSOLE_42 (SUBSYS_APPOS_MAX + 42) +#define SUBSYS_CONSOLE_43 (SUBSYS_APPOS_MAX + 43) +#define SUBSYS_CONSOLE_44 (SUBSYS_APPOS_MAX + 44) +#define SUBSYS_CONSOLE_45 (SUBSYS_APPOS_MAX + 45) +#define SUBSYS_CONSOLE_46 (SUBSYS_APPOS_MAX + 46) + +static inline char * +subsys_console_to_s(int subsys, char *s, int n) +{ + switch (subsys) { + case SUBSYS_CONSOLE_VIDEO: + strncpy(s, "CONSOLE_VIDEO", n); + break; + case SUBSYS_CONSOLE_KBDMOU: + strncpy(s, "CONSOLE_KBDMOU", n); + break; + case SUBSYS_CONSOLE_04: + strncpy(s, "CONSOLE_04", n); + break; + case SUBSYS_CONSOLE_05: + strncpy(s, "CONSOLE_05", n); + break; + case SUBSYS_CONSOLE_06: + strncpy(s, "CONSOLE_06", n); + break; + case SUBSYS_CONSOLE_07: + strncpy(s, "CONSOLE_07", n); + break; + case SUBSYS_CONSOLE_08: + strncpy(s, "CONSOLE_08", n); + break; + case SUBSYS_CONSOLE_09: + strncpy(s, "CONSOLE_09", n); + break; + case SUBSYS_CONSOLE_10: + strncpy(s, "CONSOLE_10", n); + break; + case SUBSYS_CONSOLE_11: + strncpy(s, "CONSOLE_11", n); + break; + case SUBSYS_CONSOLE_12: + strncpy(s, "CONSOLE_12", n); + break; + case SUBSYS_CONSOLE_13: + strncpy(s, "CONSOLE_13", n); + break; + case SUBSYS_CONSOLE_14: + strncpy(s, "CONSOLE_14", n); + break; + case SUBSYS_CONSOLE_15: + strncpy(s, "CONSOLE_15", n); + break; + case SUBSYS_CONSOLE_16: + strncpy(s, "CONSOLE_16", n); + break; + case SUBSYS_CONSOLE_17: + strncpy(s, "CONSOLE_17", n); + break; + case SUBSYS_CONSOLE_18: + strncpy(s, "CONSOLE_18", n); + break; + case SUBSYS_CONSOLE_19: + strncpy(s, "CONSOLE_19", n); + break; + case SUBSYS_CONSOLE_20: + strncpy(s, "CONSOLE_20", n); + break; + case SUBSYS_CONSOLE_21: + strncpy(s, "CONSOLE_21", n); + break; + case SUBSYS_CONSOLE_22: + strncpy(s, "CONSOLE_22", n); + break; + case SUBSYS_CONSOLE_23: + strncpy(s, "CONSOLE_23", n); + break; + case SUBSYS_CONSOLE_24: + strncpy(s, "CONSOLE_24", n); + break; + case SUBSYS_CONSOLE_25: + strncpy(s, "CONSOLE_25", n); + break; + case SUBSYS_CONSOLE_26: + strncpy(s, "CONSOLE_26", n); + break; + case SUBSYS_CONSOLE_27: + strncpy(s, "CONSOLE_27", n); + break; + case SUBSYS_CONSOLE_28: + strncpy(s, "CONSOLE_28", n); + break; + case SUBSYS_CONSOLE_29: + strncpy(s, "CONSOLE_29", n); + break; + case SUBSYS_CONSOLE_30: + strncpy(s, "CONSOLE_30", n); + break; + case SUBSYS_CONSOLE_31: + strncpy(s, "CONSOLE_31", n); + break; + case SUBSYS_CONSOLE_32: + strncpy(s, "CONSOLE_32", n); + break; + case SUBSYS_CONSOLE_33: + strncpy(s, "CONSOLE_33", n); + break; + case SUBSYS_CONSOLE_34: + strncpy(s, "CONSOLE_34", n); + break; + case SUBSYS_CONSOLE_35: + strncpy(s, "CONSOLE_35", n); + break; + case SUBSYS_CONSOLE_36: + strncpy(s, "CONSOLE_36", n); + break; + case SUBSYS_CONSOLE_37: + strncpy(s, "CONSOLE_37", n); + break; + case SUBSYS_CONSOLE_38: + strncpy(s, "CONSOLE_38", n); + break; + case SUBSYS_CONSOLE_39: + strncpy(s, "CONSOLE_39", n); + break; + case SUBSYS_CONSOLE_40: + strncpy(s, "CONSOLE_40", n); + break; + case SUBSYS_CONSOLE_41: + strncpy(s, "CONSOLE_41", n); + break; + case SUBSYS_CONSOLE_42: + strncpy(s, "CONSOLE_42", n); + break; + case SUBSYS_CONSOLE_43: + strncpy(s, "CONSOLE_43", n); + break; + case SUBSYS_CONSOLE_44: + strncpy(s, "CONSOLE_44", n); + break; + case SUBSYS_CONSOLE_45: + strncpy(s, "CONSOLE_45", n); + break; + case SUBSYS_CONSOLE_46: + strncpy(s, "CONSOLE_46", n); + break; + default: + subsys_unknown_to_s(subsys, s, n); + break; + } + s[n - 1] = '\0'; + return s; +} + +#endif diff --git a/drivers/staging/unisys/common-spar/include/iovmcall_gnuc.h b/drivers/staging/unisys/common-spar/include/iovmcall_gnuc.h new file mode 100644 index 00000000000..7304e9a0648 --- /dev/null +++ b/drivers/staging/unisys/common-spar/include/iovmcall_gnuc.h @@ -0,0 +1,53 @@ +/* Copyright © 2010 - 2013 UNISYS CORPORATION + * 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. + */ + +/* Linux GCC Version (32-bit and 64-bit) */ +static inline unsigned long +__unisys_vmcall_gnuc(unsigned long tuple, unsigned long reg_ebx, + unsigned long reg_ecx) +{ + unsigned long result = 0; + + unsigned int cpuid_eax, cpuid_ebx, cpuid_ecx, cpuid_edx; + cpuid(0x00000001, &cpuid_eax, &cpuid_ebx, &cpuid_ecx, &cpuid_edx); + if (cpuid_ecx & 0x80000000) { + __asm__ __volatile__(".byte 0x00f, 0x001, 0x0c1" : "=a"(result) : + "a"(tuple), "b"(reg_ebx), "c"(reg_ecx) + ); + } else { + result = -1; + } + return result; +} + +static inline unsigned long +__unisys_extended_vmcall_gnuc(unsigned long long tuple, + unsigned long long reg_ebx, + unsigned long long reg_ecx, + unsigned long long reg_edx) +{ + unsigned long result = 0; + + unsigned int cpuid_eax, cpuid_ebx, cpuid_ecx, cpuid_edx; + cpuid(0x00000001, &cpuid_eax, &cpuid_ebx, &cpuid_ecx, &cpuid_edx); + if (cpuid_ecx & 0x80000000) { + __asm__ __volatile__(".byte 0x00f, 0x001, 0x0c1" : "=a"(result) : + "a"(tuple), "b"(reg_ebx), "c"(reg_ecx), + "d"(reg_edx)); + } else { + result = -1; + } + return result; + } diff --git a/drivers/staging/unisys/common-spar/include/vbusdeviceinfo.h b/drivers/staging/unisys/common-spar/include/vbusdeviceinfo.h new file mode 100644 index 00000000000..37367790891 --- /dev/null +++ b/drivers/staging/unisys/common-spar/include/vbusdeviceinfo.h @@ -0,0 +1,209 @@ +/* Copyright © 2010 - 2013 UNISYS CORPORATION + * 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. + */ + +#ifndef __VBUSDEVICEINFO_H__ +#define __VBUSDEVICEINFO_H__ + +#include "commontypes.h" + +#pragma pack(push, 1) /* both GCC and VC now allow this pragma */ + +/* An array of this struct is present in the channel area for each vbus. + * (See vbuschannel.h.) + * It is filled in by the client side to provide info about the device + * and driver from the client's perspective. + */ +typedef struct _ULTRA_VBUS_DEVICEINFO { + U8 devType[16]; /* short string identifying the device type */ + U8 drvName[16]; /* driver .sys file name */ + U8 infoStrings[96]; /* sequence of tab-delimited id strings: */ + /* <DRIVER_REV> <DRIVER_VERTAG> <DRIVER_COMPILETIME> */ + U8 reserved[128]; /* pad size to 256 bytes */ +} ULTRA_VBUS_DEVICEINFO; + +#pragma pack(pop) + +/* Reads chars from the buffer at <src> for <srcmax> bytes, and writes to + * the buffer at <p>, which is <remain> bytes long, ensuring never to + * overflow the buffer at <p>, using the following rules: + * - printable characters are simply copied from the buffer at <src> to the + * buffer at <p> + * - intervening streaks of non-printable characters in the buffer at <src> + * are replaced with a single space in the buffer at <p> + * Note that we pay no attention to '\0'-termination. + * Returns the number of bytes written to <p>. + * + * Pass <p> == NULL and <remain> == 0 for this special behavior. In this + * case, we simply return the number of bytes that WOULD HAVE been written + * to a buffer at <p>, had it been infinitely big. + */ +static inline int +VBUSCHANNEL_sanitize_buffer(char *p, int remain, char *src, int srcmax) +{ + int chars = 0; + int nonprintable_streak = 0; + while (srcmax > 0) { + if ((*src >= ' ') && (*src < 0x7f)) { + if (nonprintable_streak) { + if (remain > 0) { + *p = ' '; + p++; + remain--; + chars++; + } else if (p == NULL) + chars++; + nonprintable_streak = 0; + } + if (remain > 0) { + *p = *src; + p++; + remain--; + chars++; + } else if (p == NULL) + chars++; + } else + nonprintable_streak = 1; + src++; + srcmax--; + } + return chars; +} + +#define VBUSCHANNEL_ADDACHAR(ch, p, remain, chars) \ + do { \ + if (remain <= 0) \ + break; \ + *p = ch; \ + p++; chars++; remain--; \ + } while (0) + +/* Converts the non-negative value at <num> to an ascii decimal string + * at <p>, writing at most <remain> bytes. Note there is NO '\0' termination + * written to <p>. + * + * Returns the number of bytes written to <p>. + * + * Note that we create this function because we need to do this operation in + * an environment-independent way (since we are in a common header file). + */ +static inline int +VBUSCHANNEL_itoa(char *p, int remain, int num) +{ + int digits = 0; + char s[32]; + int i; + + if (num == 0) { + /* '0' is a special case */ + if (remain <= 0) + return 0; + *p = '0'; + return 1; + } + /* form a backwards decimal ascii string in <s> */ + while (num > 0) { + if (digits >= (int) sizeof(s)) + return 0; + s[digits++] = (num % 10) + '0'; + num = num / 10; + } + if (remain < digits) { + /* not enough room left at <p> to hold number, so fill with + * '?' */ + for (i = 0; i < remain; i++, p++) + *p = '?'; + return remain; + } + /* plug in the decimal ascii string representing the number, by */ + /* reversing the string we just built in <s> */ + i = digits; + while (i > 0) { + i--; + *p = s[i]; + p++; + } + return digits; +} + +/* Reads <devInfo>, and converts its contents to a printable string at <p>, + * writing at most <remain> bytes. Note there is NO '\0' termination + * written to <p>. + * + * Pass <devix> >= 0 if you want a device index presented. + * + * Returns the number of bytes written to <p>. + */ +static inline int +VBUSCHANNEL_devInfoToStringBuffer(ULTRA_VBUS_DEVICEINFO devInfo, + char *p, int remain, int devix) +{ + char *psrc; + int nsrc, x, i, pad; + int chars = 0; + + psrc = &(devInfo.devType[0]); + nsrc = sizeof(devInfo.devType); + if (VBUSCHANNEL_sanitize_buffer(NULL, 0, psrc, nsrc) <= 0) + return 0; + + /* emit device index */ + if (devix >= 0) { + VBUSCHANNEL_ADDACHAR('[', p, remain, chars); + x = VBUSCHANNEL_itoa(p, remain, devix); + p += x; + remain -= x; + chars += x; + VBUSCHANNEL_ADDACHAR(']', p, remain, chars); + } else { + VBUSCHANNEL_ADDACHAR(' ', p, remain, chars); + VBUSCHANNEL_ADDACHAR(' ', p, remain, chars); + VBUSCHANNEL_ADDACHAR(' ', p, remain, chars); + } + + /* emit device type */ + x = VBUSCHANNEL_sanitize_buffer(p, remain, psrc, nsrc); + p += x; + remain -= x; + chars += x; + pad = 15 - x; /* pad device type to be exactly 15 chars */ + for (i = 0; i < pad; i++) + VBUSCHANNEL_ADDACHAR(' ', p, remain, chars); + VBUSCHANNEL_ADDACHAR(' ', p, remain, chars); + + /* emit driver name */ + psrc = &(devInfo.drvName[0]); + nsrc = sizeof(devInfo.drvName); + x = VBUSCHANNEL_sanitize_buffer(p, remain, psrc, nsrc); + p += x; + remain -= x; + chars += x; + pad = 15 - x; /* pad driver name to be exactly 15 chars */ + for (i = 0; i < pad; i++) + VBUSCHANNEL_ADDACHAR(' ', p, remain, chars); + VBUSCHANNEL_ADDACHAR(' ', p, remain, chars); + + /* emit strings */ + psrc = &(devInfo.infoStrings[0]); + nsrc = sizeof(devInfo.infoStrings); + x = VBUSCHANNEL_sanitize_buffer(p, remain, psrc, nsrc); + p += x; + remain -= x; + chars += x; + VBUSCHANNEL_ADDACHAR('\n', p, remain, chars); + + return chars; +} + +#endif diff --git a/drivers/staging/unisys/common-spar/include/version.h b/drivers/staging/unisys/common-spar/include/version.h new file mode 100644 index 00000000000..00b0ebb09ea --- /dev/null +++ b/drivers/staging/unisys/common-spar/include/version.h @@ -0,0 +1,46 @@ +/* Copyright © 2010 - 2013 UNISYS CORPORATION + * 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. + */ + +/* version.h */ + +/* Common version/release info needed by all components goes here. + * (This file must compile cleanly in all environments.) + * Ultimately, this will be combined with defines generated dynamically as + * part of the sysgen, and some of the defines below may in fact end up + * being replaced with dynamically generated ones. + */ +#ifndef __VERSION_H__ +#define __VERSION_H__ + +#define SPARVER1 "1" +#define SPARVER2 "0" +#define SPARVER3 "0" +#define SPARVER4 "0" + +#define VERSION SPARVER1 "." SPARVER2 "." SPARVER3 "." SPARVER4 +#define VERSIONDATE __DATE__ + +/* Here are various version forms needed in Windows environments. + */ +#define VISOR_PRODUCTVERSION SPARVERCOMMA +#define VISOR_PRODUCTVERSION_STR SPARVER1 "." SPARVER2 "." SPARVER3 "." \ + SPARVER4 +#define VISOR_OBJECTVERSION_STR SPARVER1 "," SPARVER2 "," SPARVER3 "," \ + SPARVER4 + +#define COPYRIGHT "Unisys Corporation" +#define COPYRIGHTDATE "2010 - 2013" + +#endif diff --git a/drivers/staging/unisys/common-spar/include/vmcallinterface.h b/drivers/staging/unisys/common-spar/include/vmcallinterface.h new file mode 100644 index 00000000000..bd8944abd09 --- /dev/null +++ b/drivers/staging/unisys/common-spar/include/vmcallinterface.h @@ -0,0 +1,167 @@ +/* Copyright © 2010 - 2013 UNISYS CORPORATION + * 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. + */ + +#ifndef __IOMONINTF_H__ +#define __IOMONINTF_H__ + +/* +* This file contains all structures needed to support the VMCALLs for IO +* Virtualization. The VMCALLs are provided by Monitor and used by IO code +* running on IO Partitions. +*/ + +#ifdef __GNUC__ +#include "iovmcall_gnuc.h" +#endif /* */ +#include "diagchannel.h" + +#ifdef VMCALL_IO_CONTROLVM_ADDR +#undef VMCALL_IO_CONTROLVM_ADDR +#endif /* */ + +/* define subsystem number for AppOS, used in uislib driver */ +#define MDS_APPOS 0x4000000000000000 /* subsystem = 62 - AppOS */ +typedef enum { /* VMCALL identification tuples */ + /* Note: when a new VMCALL is added: + * - the 1st 2 hex digits correspond to one of the + * VMCALL_MONITOR_INTERFACE types and + * - the next 2 hex digits are the nth relative instance of within a + * type + * E.G. for VMCALL_VIRTPART_RECYCLE_PART, + * - the 0x02 identifies it as a VMCALL_VIRTPART type and + * - the 0x01 identifies it as the 1st instance of a VMCALL_VIRTPART + * type of VMCALL + */ + + VMCALL_IO_CONTROLVM_ADDR = 0x0501, /* used by all Guests, not just + * IO */ + VMCALL_IO_DIAG_ADDR = 0x0508, + VMCALL_IO_VISORSERIAL_ADDR = 0x0509, + VMCALL_QUERY_GUEST_VIRTUAL_TIME_OFFSET = 0x0708, /* Allow caller to + * query virtual time + * offset */ + VMCALL_CHANNEL_VERSION_MISMATCH = 0x0709, + VMCALL_POST_CODE_LOGEVENT = 0x070B, /* LOGEVENT Post Code (RDX) with + * specified subsystem mask (RCX + * - monitor_subsystems.h) and + * severity (RDX) */ + VMCALL_GENERIC_SURRENDER_QUANTUM_FOREVER = 0x0802, /* Yield the + * remainder & all + * future quantums of + * the caller */ + VMCALL_MEASUREMENT_DO_NOTHING = 0x0901, + VMCALL_UPDATE_PHYSICAL_TIME = 0x0a02 /* Allow + * ULTRA_SERVICE_CAPABILITY_TIME + * capable guest to make + * VMCALL */ +} VMCALL_MONITOR_INTERFACE_METHOD_TUPLE; + +#define VMCALL_SUCCESS 0 +#define VMCALL_SUCCESSFUL(result) (result == 0) + +#ifdef __GNUC__ +#define unisys_vmcall(tuple, reg_ebx, reg_ecx) \ + __unisys_vmcall_gnuc(tuple, reg_ebx, reg_ecx) +#define unisys_extended_vmcall(tuple, reg_ebx, reg_ecx, reg_edx) \ + __unisys_extended_vmcall_gnuc(tuple, reg_ebx, reg_ecx, reg_edx) +#define ISSUE_IO_VMCALL(InterfaceMethod, param, result) \ + (result = unisys_vmcall(InterfaceMethod, (param) & 0xFFFFFFFF, \ + (param) >> 32)) +#define ISSUE_IO_EXTENDED_VMCALL(InterfaceMethod, param1, param2, \ + param3, result) \ + (result = unisys_extended_vmcall(InterfaceMethod, param1, \ + param2, param3)) + + /* The following uses VMCALL_POST_CODE_LOGEVENT interface but is currently + * not used much */ +#define ISSUE_IO_VMCALL_POSTCODE_SEVERITY(postcode, severity) \ +do { \ + U32 _tempresult = VMCALL_SUCCESS; \ + ISSUE_IO_EXTENDED_VMCALL(VMCALL_POST_CODE_LOGEVENT, severity, \ + MDS_APPOS, postcode, _tempresult); \ +} while (0) +#endif + +/* Structures for IO VMCALLs */ + +/* ///////////// BEGIN PRAGMA PACK PUSH 1 ///////////////////////// */ +/* ///////////// ONLY STRUCT TYPE SHOULD BE BELOW */ +#pragma pack(push, 1) +struct phys_info { + U64 pi_pfn; + U16 pi_off; + U16 pi_len; +}; + +#pragma pack(pop) +/* ///////////// END PRAGMA PACK PUSH 1 /////////////////////////// */ +typedef struct phys_info IO_DATA_STRUCTURE; + +/* ///////////// BEGIN PRAGMA PACK PUSH 1 ///////////////////////// */ +/* ///////////// ONLY STRUCT TYPE SHOULD BE BELOW */ +#pragma pack(push, 1) +/* Parameters to VMCALL_IO_CONTROLVM_ADDR interface */ +typedef struct _VMCALL_IO_CONTROLVM_ADDR_PARAMS { + /* The Guest-relative physical address of the ControlVm channel. + * This VMCall fills this in with the appropriate address. */ + U64 ChannelAddress; /* contents provided by this VMCALL (OUT) */ + /* the size of the ControlVm channel in bytes This VMCall fills this + * in with the appropriate address. */ + U32 ChannelBytes; /* contents provided by this VMCALL (OUT) */ + U8 Unused[4]; /* Unused Bytes in the 64-Bit Aligned Struct */ +} VMCALL_IO_CONTROLVM_ADDR_PARAMS; + +#pragma pack(pop) +/* ///////////// END PRAGMA PACK PUSH 1 /////////////////////////// */ + +/* ///////////// BEGIN PRAGMA PACK PUSH 1 ///////////////////////// */ +/* ///////////// ONLY STRUCT TYPE SHOULD BE BELOW */ +#pragma pack(push, 1) +/* Parameters to VMCALL_IO_DIAG_ADDR interface */ +typedef struct _VMCALL_IO_DIAG_ADDR_PARAMS { + /* The Guest-relative physical address of the diagnostic channel. + * This VMCall fills this in with the appropriate address. */ + U64 ChannelAddress; /* contents provided by this VMCALL (OUT) */ +} VMCALL_IO_DIAG_ADDR_PARAMS; + +#pragma pack(pop) +/* ///////////// END PRAGMA PACK PUSH 1 /////////////////////////// */ + +/* ///////////// BEGIN PRAGMA PACK PUSH 1 ///////////////////////// */ +/* ///////////// ONLY STRUCT TYPE SHOULD BE BELOW */ +#pragma pack(push, 1) +/* Parameters to VMCALL_IO_VISORSERIAL_ADDR interface */ +typedef struct _VMCALL_IO_VISORSERIAL_ADDR_PARAMS { + /* The Guest-relative physical address of the serial console + * channel. This VMCall fills this in with the appropriate + * address. */ + U64 ChannelAddress; /* contents provided by this VMCALL (OUT) */ +} VMCALL_IO_VISORSERIAL_ADDR_PARAMS; + +#pragma pack(pop) +/* ///////////// END PRAGMA PACK PUSH 1 /////////////////////////// */ + +/* Parameters to VMCALL_CHANNEL_MISMATCH interface */ +typedef struct _VMCALL_CHANNEL_VERSION_MISMATCH_PARAMS { + U8 ChannelName[32]; /* Null terminated string giving name of channel + * (IN) */ + U8 ItemName[32]; /* Null terminated string giving name of + * mismatched item (IN) */ + U32 SourceLineNumber; /* line# where invoked. (IN) */ + U8 SourceFileName[36]; /* source code where invoked - Null terminated + * string (IN) */ +} VMCALL_CHANNEL_VERSION_MISMATCH_PARAMS; + +#endif /* __IOMONINTF_H__ */ diff --git a/drivers/staging/unisys/include/commontypes.h b/drivers/staging/unisys/include/commontypes.h new file mode 100644 index 00000000000..ae46bed7143 --- /dev/null +++ b/drivers/staging/unisys/include/commontypes.h @@ -0,0 +1,166 @@ +/* Copyright © 2010 - 2013 UNISYS CORPORATION + * 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. + */ + +#ifndef _COMMONTYPES_H_ +#define _COMMONTYPES_H_ + +/* define the following to prevent include nesting in kernel header files of + * similar abreviated content */ +#define _SUPERVISOR_COMMONTYPES_H_ + +#ifdef __KERNEL__ +#include <linux/types.h> +#include <linux/version.h> +#else +#include <stdint.h> +#include <syslog.h> +#endif + +#define U8 uint8_t +#define U16 uint16_t +#define U32 uint32_t +#define U64 uint64_t +#define S8 int8_t +#define S16 int16_t +#define S32 int32_t +#define S64 int64_t + +#ifdef __KERNEL__ + +#ifdef CONFIG_X86_32 +#define UINTN U32 +#else +#define UINTN U64 +#endif + +#else + +#include <stdint.h> +#if __WORDSIZE == 32 +#define UINTN U32 +#elif __WORDSIZE == 64 +#define UINTN U64 +#else +#error Unsupported __WORDSIZE +#endif + +#endif + +typedef struct { + U32 data1; + U16 data2; + U16 data3; + U8 data4[8]; +} __attribute__ ((__packed__)) GUID; + +#ifndef GUID0 +#define GUID0 {0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0} } +#endif +typedef U64 GUEST_PHYSICAL_ADDRESS; + +#define MEMSET(ptr, val, len) memset(ptr, val, len) +#define MEMCMP(m1, m2, len) memcmp(m1, m2, len) +#define STRLEN(s) ((UINTN)strlen((const char *)s)) +#define STRCPY(d, s) (strcpy((char *)d, (const char *)s)) + +#define INLINE inline +#define OFFSETOF offsetof + +#ifdef __KERNEL__ +#define MEMORYBARRIER mb() +#define MEMCPY(dest, src, len) memcpy(dest, src, len) + +#define CHANNEL_GUID_MISMATCH(chType, chName, field, expected, actual, fil, \ + lin, logCtx) \ + do { \ + char s1[50], s2[50], s3[50]; \ + pr_err("Channel mismatch on channel=%s(%s) field=%s expected=%s actual=%s @%s:%d\n", \ + chName, GUID_format2(&chType, s1), field, \ + GUID_format2(&expected, s2), GUID_format2(&actual, s3), \ + fil, lin); \ + } while (0) +#define CHANNEL_U32_MISMATCH(chType, chName, field, expected, actual, fil, \ + lin, logCtx) \ + do { \ + char s1[50]; \ + pr_err("Channel mismatch on channel=%s(%s) field=%s expected=0x%-8.8lx actual=0x%-8.8lx @%s:%d\n", \ + chName, GUID_format2(&chType, s1), field, \ + (unsigned long)expected, (unsigned long)actual, \ + fil, lin); \ + } while (0) + +#define CHANNEL_U64_MISMATCH(chType, chName, field, expected, actual, fil, \ + lin, logCtx) \ + do { \ + char s1[50]; \ + pr_err("Channel mismatch on channel=%s(%s) field=%s expected=0x%-8.8Lx actual=0x%-8.8Lx @%s:%d\n", \ + chName, GUID_format2(&chType, s1), field, \ + (unsigned long long)expected, \ + (unsigned long long)actual, \ + fil, lin); \ + } while (0) + +#define UltraLogEvent(logCtx, EventId, Severity, SubsystemMask, pFunctionName, \ + LineNumber, Str, args...) \ + pr_info(Str, ## args) + +#else +#define MEMCPY(dest, src, len) memcpy(dest, src, len) + +#define MEMORYBARRIER mb() + +#define CHANNEL_GUID_MISMATCH(chType, chName, field, expected, actual, fil, \ + lin, logCtx) \ + do { \ + char s1[50], s2[50], s3[50]; \ + syslog(LOG_USER | LOG_ERR, \ + "Channel mismatch on channel=%s(%s) field=%s expected=%s actual=%s @%s:%d", \ + chName, GUID_format2(&chType, s1), field, \ + GUID_format2(&expected, s2), GUID_format2(&actual, s3), \ + fil, lin); \ + } while (0) + +#define CHANNEL_U32_MISMATCH(chType, chName, field, expected, actual, fil, \ + lin, logCtx) \ + do { \ + char s1[50]; \ + syslog(LOG_USER | LOG_ERR, \ + "Channel mismatch on channel=%s(%s) field=%s expected=0x%-8.8lx actual=0x%-8.8lx @%s:%d", \ + chName, GUID_format2(&chType, s1), field, \ + (unsigned long)expected, (unsigned long)actual, \ + fil, lin); \ + } while (0) + +#define CHANNEL_U64_MISMATCH(chType, chName, field, expected, actual, fil, \ + lin, logCtx) \ + do { \ + char s1[50]; \ + syslog(LOG_USER | LOG_ERR, \ + "Channel mismatch on channel=%s(%s) field=%s expected=0x%-8.8Lx actual=0x%-8.8Lx @%s:%d", \ + chName, GUID_format2(&chType, s1), field, \ + (unsigned long long)expected, \ + (unsigned long long)actual, \ + fil, lin); \ + } while (0) + +#define UltraLogEvent(logCtx, EventId, Severity, SubsystemMask, pFunctionName, \ + LineNumber, Str, args...) \ + syslog(LOG_USER | LOG_INFO, Str, ## args) +#endif + +#define VolatileBarrier() MEMORYBARRIER + +#endif +#include "guidutils.h" diff --git a/drivers/staging/unisys/include/guestlinuxdebug.h b/drivers/staging/unisys/include/guestlinuxdebug.h new file mode 100644 index 00000000000..c3de8496e5d --- /dev/null +++ b/drivers/staging/unisys/include/guestlinuxdebug.h @@ -0,0 +1,182 @@ +/* Copyright © 2010 - 2013 UNISYS CORPORATION + * 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. + */ + +#ifndef __GUESTLINUXDEBUG_H__ +#define __GUESTLINUXDEBUG_H__ + +/* +* This file contains supporting interface for "vmcallinterface.h", particuarly +* regarding adding additional structure and functionality to linux +* ISSUE_IO_VMCALL_POSTCODE_SEVERITY */ + + +/******* INFO ON ISSUE_POSTCODE_LINUX() BELOW *******/ +#include "vmcallinterface.h" +typedef enum { /* POSTCODE driver identifier tuples */ + /* visorchipset driver files */ + VISOR_CHIPSET_PC = 0xA0, + VISOR_CHIPSET_PC_controlvm_c = 0xA1, + VISOR_CHIPSET_PC_controlvm_cm2 = 0xA2, + VISOR_CHIPSET_PC_controlvm_direct_c = 0xA3, + VISOR_CHIPSET_PC_file_c = 0xA4, + VISOR_CHIPSET_PC_parser_c = 0xA5, + VISOR_CHIPSET_PC_testing_c = 0xA6, + VISOR_CHIPSET_PC_visorchipset_main_c = 0xA7, + VISOR_CHIPSET_PC_visorswitchbus_c = 0xA8, + /* visorbus driver files */ + VISOR_BUS_PC = 0xB0, + VISOR_BUS_PC_businst_attr_c = 0xB1, + VISOR_BUS_PC_channel_attr_c = 0xB2, + VISOR_BUS_PC_devmajorminor_attr_c = 0xB3, + VISOR_BUS_PC_visorbus_main_c = 0xB4, + /* visorclientbus driver files */ + VISOR_CLIENT_BUS_PC = 0xC0, + VISOR_CLIENT_BUS_PC_visorclientbus_main_c = 0xC1, + /* virt hba driver files */ + VIRT_HBA_PC = 0xC2, + VIRT_HBA_PC_virthba_c = 0xC3, + /* virtpci driver files */ + VIRT_PCI_PC = 0xC4, + VIRT_PCI_PC_virtpci_c = 0xC5, + /* virtnic driver files */ + VIRT_NIC_PC = 0xC6, + VIRT_NIC_P_virtnic_c = 0xC7, + /* uislib driver files */ + UISLIB_PC = 0xD0, + UISLIB_PC_uislib_c = 0xD1, + UISLIB_PC_uisqueue_c = 0xD2, + UISLIB_PC_uisthread_c = 0xD3, + UISLIB_PC_uisutils_c = 0xD4, +} DRIVER_PC; + +typedef enum { /* POSTCODE event identifier tuples */ + ATTACH_PORT_ENTRY_PC = 0x001, + ATTACH_PORT_FAILURE_PC = 0x002, + ATTACH_PORT_SUCCESS_PC = 0x003, + BUS_FAILURE_PC = 0x004, + BUS_CREATE_ENTRY_PC = 0x005, + BUS_CREATE_FAILURE_PC = 0x006, + BUS_CREATE_EXIT_PC = 0x007, + BUS_CONFIGURE_ENTRY_PC = 0x008, + BUS_CONFIGURE_FAILURE_PC = 0x009, + BUS_CONFIGURE_EXIT_PC = 0x00A, + CHIPSET_INIT_ENTRY_PC = 0x00B, + CHIPSET_INIT_SUCCESS_PC = 0x00C, + CHIPSET_INIT_FAILURE_PC = 0x00D, + CHIPSET_INIT_EXIT_PC = 0x00E, + CREATE_WORKQUEUE_PC = 0x00F, + CREATE_WORKQUEUE_FAILED_PC = 0x0A0, + CONTROLVM_INIT_FAILURE_PC = 0x0A1, + DEVICE_CREATE_ENTRY_PC = 0x0A2, + DEVICE_CREATE_FAILURE_PC = 0x0A3, + DEVICE_CREATE_SUCCESS_PC = 0x0A4, + DEVICE_CREATE_EXIT_PC = 0x0A5, + DEVICE_ADD_PC = 0x0A6, + DEVICE_REGISTER_FAILURE_PC = 0x0A7, + DEVICE_CHANGESTATE_ENTRY_PC = 0x0A8, + DEVICE_CHANGESTATE_FAILURE_PC = 0x0A9, + DEVICE_CHANGESTATE_EXIT_PC = 0x0AA, + DRIVER_ENTRY_PC = 0x0AB, + DRIVER_EXIT_PC = 0x0AC, + MALLOC_FAILURE_PC = 0x0AD, + QUEUE_DELAYED_WORK_PC = 0x0AE, + UISLIB_THREAD_FAILURE_PC = 0x0B7, + VBUS_CHANNEL_ENTRY_PC = 0x0B8, + VBUS_CHANNEL_FAILURE_PC = 0x0B9, + VBUS_CHANNEL_EXIT_PC = 0x0BA, + VHBA_CREATE_ENTRY_PC = 0x0BB, + VHBA_CREATE_FAILURE_PC = 0x0BC, + VHBA_CREATE_EXIT_PC = 0x0BD, + VHBA_CREATE_SUCCESS_PC = 0x0BE, + VHBA_COMMAND_HANDLER_PC = 0x0BF, + VHBA_PROBE_ENTRY_PC = 0x0C0, + VHBA_PROBE_FAILURE_PC = 0x0C1, + VHBA_PROBE_EXIT_PC = 0x0C2, + VNIC_CREATE_ENTRY_PC = 0x0C3, + VNIC_CREATE_FAILURE_PC = 0x0C4, + VNIC_CREATE_SUCCESS_PC = 0x0C5, + VNIC_PROBE_ENTRY_PC = 0x0C6, + VNIC_PROBE_FAILURE_PC = 0x0C7, + VNIC_PROBE_EXIT_PC = 0x0C8, + VPCI_CREATE_ENTRY_PC = 0x0C9, + VPCI_CREATE_FAILURE_PC = 0x0CA, + VPCI_CREATE_EXIT_PC = 0x0CB, + VPCI_PROBE_ENTRY_PC = 0x0CC, + VPCI_PROBE_FAILURE_PC = 0x0CD, + VPCI_PROBE_EXIT_PC = 0x0CE, + CRASH_DEV_ENTRY_PC = 0x0CF, + CRASH_DEV_EXIT_PC = 0x0D0, + CRASH_DEV_HADDR_NULL = 0x0D1, + CRASH_DEV_CONTROLVM_NULL = 0x0D2, + CRASH_DEV_RD_BUS_FAIULRE_PC = 0x0D3, + CRASH_DEV_RD_DEV_FAIULRE_PC = 0x0D4, + CRASH_DEV_BUS_NULL_FAILURE_PC = 0x0D5, + CRASH_DEV_DEV_NULL_FAILURE_PC = 0x0D6, + CRASH_DEV_CTRL_RD_FAILURE_PC = 0x0D7, + CRASH_DEV_COUNT_FAILURE_PC = 0x0D8, + SAVE_MSG_BUS_FAILURE_PC = 0x0D9, + SAVE_MSG_DEV_FAILURE_PC = 0x0DA, + CALLHOME_INIT_FAILURE_PC = 0x0DB +} EVENT_PC; + +#ifdef __GNUC__ + +#define POSTCODE_SEVERITY_ERR DIAG_SEVERITY_ERR +#define POSTCODE_SEVERITY_WARNING DIAG_SEVERITY_WARNING +#define POSTCODE_SEVERITY_INFO DIAG_SEVERITY_PRINT /* TODO-> Info currently + * doesnt show, so we + * set info=warning */ +/* example call of POSTCODE_LINUX_2(VISOR_CHIPSET_PC, POSTCODE_SEVERITY_ERR); + * Please also note that the resulting postcode is in hex, so if you are + * searching for the __LINE__ number, convert it first to decimal. The line + * number combined with driver and type of call, will allow you to track down + * exactly what line an error occured on, or where the last driver + * entered/exited from. + */ + +/* BASE FUNCTIONS */ +#define POSTCODE_LINUX_A(DRIVER_PC, EVENT_PC, pc32bit, severity) \ +do { \ + unsigned long long post_code_temp; \ + post_code_temp = (((U64)DRIVER_PC) << 56) | (((U64)EVENT_PC) << 44) | \ + ((((U64)__LINE__) & 0xFFF) << 32) | \ + (((U64)pc32bit) & 0xFFFFFFFF); \ + ISSUE_IO_VMCALL_POSTCODE_SEVERITY(post_code_temp, severity); \ +} while (0) + +#define POSTCODE_LINUX_B(DRIVER_PC, EVENT_PC, pc16bit1, pc16bit2, severity) \ +do { \ + unsigned long long post_code_temp; \ + post_code_temp = (((U64)DRIVER_PC) << 56) | (((U64)EVENT_PC) << 44) | \ + ((((U64)__LINE__) & 0xFFF) << 32) | \ + ((((U64)pc16bit1) & 0xFFFF) << 16) | \ + (((U64)pc16bit2) & 0xFFFF); \ + ISSUE_IO_VMCALL_POSTCODE_SEVERITY(post_code_temp, severity); \ +} while (0) + +/* MOST COMMON */ +#define POSTCODE_LINUX_2(EVENT_PC, severity) \ + POSTCODE_LINUX_A(CURRENT_FILE_PC, EVENT_PC, 0x0000, severity); + +#define POSTCODE_LINUX_3(EVENT_PC, pc32bit, severity) \ + POSTCODE_LINUX_A(CURRENT_FILE_PC, EVENT_PC, pc32bit, severity); + + +#define POSTCODE_LINUX_4(EVENT_PC, pc16bit1, pc16bit2, severity) \ + POSTCODE_LINUX_B(CURRENT_FILE_PC, EVENT_PC, pc16bit1, \ + pc16bit2, severity); + +#endif +#endif diff --git a/drivers/staging/unisys/include/guidutils.h b/drivers/staging/unisys/include/guidutils.h new file mode 100644 index 00000000000..75caf929cd6 --- /dev/null +++ b/drivers/staging/unisys/include/guidutils.h @@ -0,0 +1,203 @@ +/* Copyright © 2010 - 2013 UNISYS CORPORATION + * 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. + */ + +/* guidutils.h + * + * These are GUID manipulation inlines that can be used from either + * kernel-mode or user-mode. + * + */ +#ifndef __GUIDUTILS_H__ +#define __GUIDUTILS_H__ + +#ifdef __KERNEL__ +#include <linux/kernel.h> +#include <linux/string.h> +#include <linux/ctype.h> +#define GUID_STRTOUL kstrtoul +#else +#include <stdio.h> +#include <ctype.h> +#include <string.h> +#include <stdlib.h> + +#define GUID_STRTOUL strtoul +#endif + +static inline char * +GUID_format1(const GUID *guid, char *s) +{ + sprintf(s, "{%-8.8lx-%-4.4x-%-4.4x-%-2.2x%-2.2x%-2.2x%-2.2x%-2.2x%-2.2x%-2.2x%-2.2x}", + (ulong) guid->data1, + guid->data2, + guid->data3, + guid->data4[0], + guid->data4[1], + guid->data4[2], + guid->data4[3], + guid->data4[4], guid->data4[5], guid->data4[6], guid->data4[7]); + return s; +} + +/** Format a GUID in Microsoft's 'what in the world were they thinking' + * format. + */ +static inline char * +GUID_format2(const GUID *guid, char *s) +{ + sprintf(s, "{%-8.8lx-%-4.4x-%-4.4x-%-2.2x%-2.2x-%-2.2x%-2.2x%-2.2x%-2.2x%-2.2x%-2.2x}", + (ulong) guid->data1, + guid->data2, + guid->data3, + guid->data4[0], + guid->data4[1], + guid->data4[2], + guid->data4[3], + guid->data4[4], guid->data4[5], guid->data4[6], guid->data4[7]); + return s; +} + +/** + * Like GUID_format2 but without the curly braces and the + * hex digits in upper case + */ +static inline char * +GUID_format3(const GUID *guid, char *s) +{ + sprintf(s, "%-8.8lX-%-4.4X-%-4.4X-%-2.2X%-2.2X-%-2.2X%-2.2X%-2.2X%-2.2X%-2.2X%-2.2X", + (ulong) guid->data1, + guid->data2, + guid->data3, + guid->data4[0], + guid->data4[1], + guid->data4[2], + guid->data4[3], + guid->data4[4], guid->data4[5], guid->data4[6], guid->data4[7]); + return s; +} + +/** Parse a guid string in any of these forms: + * {11111111-2222-3333-4455-66778899aabb} + * {11111111-2222-3333-445566778899aabb} + * 11111111-2222-3333-4455-66778899aabb + * 11111111-2222-3333-445566778899aabb + */ +static inline GUID +GUID_scan(U8 *p) +{ + GUID guid = GUID0; + U8 x[33]; + int count = 0; + int c, i = 0; + U8 cdata1[9]; + U8 cdata2[5]; + U8 cdata3[5]; + U8 cdata4[3]; + int dashcount = 0; + int brace = 0; + unsigned long uldata; + + if (!p) + return guid; + if (*p == '{') { + p++; + brace = 1; + } + while (count < 32) { + if (*p == '}') + return guid; + if (*p == '\0') + return guid; + c = toupper(*p); + p++; + if (c == '-') { + switch (dashcount) { + case 0: + if (i != 8) + return guid; + break; + case 1: + if (i != 4) + return guid; + break; + case 2: + if (i != 4) + return guid; + break; + case 3: + if (i != 4) + return guid; + break; + default: + return guid; + } + dashcount++; + i = 0; + continue; + } + if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F')) + i++; + else + return guid; + x[count++] = c; + } + x[count] = '\0'; + if (brace) { + if (*p == '}') + p++; + else + return guid; + } + if (dashcount == 3 || dashcount == 4) + ; + else + return guid; + memset(cdata1, 0, sizeof(cdata1)); + memset(cdata2, 0, sizeof(cdata2)); + memset(cdata3, 0, sizeof(cdata3)); + memset(cdata4, 0, sizeof(cdata4)); + memcpy(cdata1, x + 0, 8); + memcpy(cdata2, x + 8, 4); + memcpy(cdata3, x + 12, 4); + + if (GUID_STRTOUL((char *) cdata1, 16, &uldata) == 0) + guid.data1 = (U32)uldata; + if (GUID_STRTOUL((char *) cdata2, 16, &uldata) == 0) + guid.data2 = (U16)uldata; + if (GUID_STRTOUL((char *) cdata3, 16, &uldata) == 0) + guid.data3 = (U16)uldata; + + for (i = 0; i < 8; i++) { + memcpy(cdata4, x + 16 + (i * 2), 2); + if (GUID_STRTOUL((char *) cdata4, 16, &uldata) == 0) + guid.data4[i] = (U8) uldata; + } + + return guid; +} + +static inline char * +GUID_sanitize(char *inputGuidStr, char *outputGuidStr) +{ + GUID g; + GUID guid0 = GUID0; + *outputGuidStr = '\0'; + g = GUID_scan((U8 *) inputGuidStr); + if (memcmp(&g, &guid0, sizeof(GUID)) == 0) + return outputGuidStr; /* bad GUID format */ + return GUID_format1(&g, outputGuidStr); +} + +#endif diff --git a/drivers/staging/unisys/include/periodic_work.h b/drivers/staging/unisys/include/periodic_work.h new file mode 100644 index 00000000000..6e725dfb3ff --- /dev/null +++ b/drivers/staging/unisys/include/periodic_work.h @@ -0,0 +1,40 @@ +/* periodic_work.h + * + * Copyright © 2010 - 2013 UNISYS CORPORATION + * 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. + */ + +#ifndef __PERIODIC_WORK_H__ +#define __PERIODIC_WORK_H__ + +#include "timskmod.h" + + + +/* PERIODIC_WORK an opaque structure to users. + * Fields are declared only in the implementation .c files. + */ +typedef struct PERIODIC_WORK_Tag PERIODIC_WORK; + +PERIODIC_WORK *periodic_work_create(ulong jiffy_interval, + struct workqueue_struct *workqueue, + void (*workfunc)(void *), + void *workfuncarg, + const char *devnam); +void periodic_work_destroy(PERIODIC_WORK *periodic_work); +BOOL periodic_work_nextperiod(PERIODIC_WORK *periodic_work); +BOOL periodic_work_start(PERIODIC_WORK *periodic_work); +BOOL periodic_work_stop(PERIODIC_WORK *periodic_work); + +#endif diff --git a/drivers/staging/unisys/include/procobjecttree.h b/drivers/staging/unisys/include/procobjecttree.h new file mode 100644 index 00000000000..d3b69f47a8e --- /dev/null +++ b/drivers/staging/unisys/include/procobjecttree.h @@ -0,0 +1,48 @@ +/* procobjecttree.h + * + * Copyright © 2010 - 2013 UNISYS CORPORATION + * 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. + */ + +/** @file ********************************************************************* + * + * This describes the interfaces necessary for creating a tree of types, + * objects, and properties in /proc. + * + ****************************************************************************** + */ + +#ifndef __PROCOBJECTTREE_H__ +#define __PROCOBJECTTREE_H__ + +#include "uniklog.h" +#include "timskmod.h" + +/* These are opaque structures to users. + * Fields are declared only in the implementation .c files. + */ +typedef struct MYPROCOBJECT_Tag MYPROCOBJECT; +typedef struct MYPROCTYPE_Tag MYPROCTYPE; + +MYPROCOBJECT *proc_CreateObject(MYPROCTYPE *type, const char *name, + void *context); +void proc_DestroyObject(MYPROCOBJECT *obj); +MYPROCTYPE *proc_CreateType(struct proc_dir_entry *procRootDir, + const char **name, + const char **propertyNames, + void (*show_property)(struct seq_file *, + void *, int)); +void proc_DestroyType(MYPROCTYPE *type); + +#endif diff --git a/drivers/staging/unisys/include/sparstop.h b/drivers/staging/unisys/include/sparstop.h new file mode 100644 index 00000000000..3603ac60764 --- /dev/null +++ b/drivers/staging/unisys/include/sparstop.h @@ -0,0 +1,30 @@ +/* sparstop.h + * + * Copyright © 2010 - 2013 UNISYS CORPORATION + * 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. + */ + +#ifndef __SPARSTOP_H__ +#define __SPARSTOP_H__ + +#include "timskmod.h" +#include "version.h" +#include <linux/ctype.h> + +typedef void (*SPARSTOP_COMPLETE_FUNC) (void *context, int status); + +int sp_stop(void *context, SPARSTOP_COMPLETE_FUNC get_complete_func); +void test_remove_stop_device(void); + +#endif diff --git a/drivers/staging/unisys/include/timskmod.h b/drivers/staging/unisys/include/timskmod.h new file mode 100644 index 00000000000..0d0b29c9c4b --- /dev/null +++ b/drivers/staging/unisys/include/timskmod.h @@ -0,0 +1,558 @@ +/* timskmod.h + * + * Copyright � 2010 - 2013 UNISYS CORPORATION + * 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. + */ + +#ifndef __TIMSKMOD_H__ +#define __TIMSKMOD_H__ + +#include <linux/version.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/device.h> +#include <linux/kobject.h> +#include <linux/sysfs.h> +#include <linux/fs.h> +#include <linux/string.h> +#include <linux/sched.h> +#include <linux/spinlock.h> +#include <linux/slab.h> +#include <linux/errno.h> +#include <linux/interrupt.h> +#include <linux/sched.h> +#include <linux/wait.h> +#include <linux/vmalloc.h> +#include <linux/proc_fs.h> +#include <linux/cdev.h> +#include <linux/types.h> +#include <asm/irq.h> +#include <linux/io.h> +#include <asm/dma.h> +#include <linux/uaccess.h> +#include <linux/list.h> +#include <linux/poll.h> +/* #define EXPORT_SYMTAB */ +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/fcntl.h> +#include <linux/aio.h> +#include <linux/workqueue.h> +#include <linux/kthread.h> +#include <linux/seq_file.h> +#include <linux/mm.h> + +/* #define DEBUG */ +#ifndef BOOL +#define BOOL int +#endif +#define FALSE 0 +#define TRUE 1 +#if !defined SUCCESS +#define SUCCESS 0 +#endif +#define FAILURE (-1) +#define DRIVERNAMEMAX 50 +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) +#define STRUCTSEQUAL(x, y) (memcmp(&x, &y, sizeof(x)) == 0) +#ifndef HOSTADDRESS +#define HOSTADDRESS unsigned long long +#endif + +typedef long VMMIO; /**< Virtual MMIO address (returned from ioremap), which + * is a virtual address pointer to a memory-mapped region. + * These are declared as "long" instead of u32* to force you to + * use readb()/writeb()/memcpy_fromio()/etc to access them. + * (On x86 we could probably get away with treating them as + * pointers.) + */ +typedef long VMMIO8; /**< #VMMIO pointing to 8-bit data */ +typedef long VMMIO16;/**< #VMMIO pointing to 16-bit data */ +typedef long VMMIO32;/**< #VMMIO pointing to 32-bit data */ + +#define LOCKSEM(sem) down_interruptible(sem) +#define LOCKSEM_UNINTERRUPTIBLE(sem) down(sem) +#define UNLOCKSEM(sem) up(sem) + +/** lock read/write semaphore for reading. + Note that all read/write semaphores are of the "uninterruptible" variety. + @param sem (rw_semaphore *) points to semaphore to lock + */ +#define LOCKREADSEM(sem) down_read(sem) + +/** unlock read/write semaphore for reading. + Note that all read/write semaphores are of the "uninterruptible" variety. + @param sem (rw_semaphore *) points to semaphore to unlock + */ +#define UNLOCKREADSEM(sem) up_read(sem) + +/** lock read/write semaphore for writing. + Note that all read/write semaphores are of the "uninterruptible" variety. + @param sem (rw_semaphore *) points to semaphore to lock + */ +#define LOCKWRITESEM(sem) down_write(sem) + +/** unlock read/write semaphore for writing. + Note that all read/write semaphores are of the "uninterruptible" variety. + @param sem (rw_semaphore *) points to semaphore to unlock + */ +#define UNLOCKWRITESEM(sem) up_write(sem) + +#ifdef ENABLE_RETURN_TRACE +#define RETTRACE(x) \ + do { \ + if (1) { \ + INFODRV("RET 0x%lx in %s", \ + (ulong)(x), __func__); \ + } \ + } while (0) +#else +#define RETTRACE(x) +#endif + +/** return from a void function, using a common exit point "Away" */ +#define RETVOID do { RETTRACE(0); goto Away; } while (0) +/** return from an int function, using a common exit point "Away" + * @param x the value to return + */ +#define RETINT(x) do { rc = (x); RETTRACE(x); goto Away; } while (0) +/** return from a void* function, using a common exit point "Away" + * @param x the value to return + */ +#define RETPTR(x) do { rc = (x); RETTRACE(x); goto Away; } while (0) +/** return from a BOOL function, using a common exit point "Away" + * @param x the value to return + */ +#define RETBOOL(x) do { rc = (x); RETTRACE(x); goto Away; } while (0) +/** Given a typedef/struct/union and a member field name, + * return the number of bytes occupied by that field. + * @param TYPE the typedef name, or "struct xx" or "union xx" + * @param MEMBER the name of the member field whose size is to be determined + * @return the size of the field in bytes + */ +#define FAIL(msg, status) do { \ + ERRDRV("'%s'" \ + ": error (status=%d)\n", \ + msg, status); \ + RETINT(status); \ + } while (0) +#define FAIL_WPOSTCODE_1(msg, status, EVENT_PC) do { \ + ERRDRV("'%s'" \ + ": error (status=%d)\n", \ + msg, status); \ + POSTCODE_LINUX_2(EVENT_PC, DIAG_SEVERITY_ERR); \ + RETINT(status); \ + } while (0) +#define FAIL_WPOSTCODE_2(msg, status, EVENT_PC, pcval32bit) do { \ + ERRDRV("'%s'" \ + ": error (status=%d)\n", \ + msg, status); \ + POSTCODE_LINUX_3(EVENT_PC, pcval32bit, DIAG_SEVERITY_ERR); \ + RETINT(status); \ + } while (0) +#define FAIL_WPOSTCODE_3(msg, status, EVENT_PC, pcval16bit1, pcval16bit2) \ + do { \ + ERRDRV("'%s'" \ + ": error (status=%d)\n", \ + msg, status); \ + POSTCODE_LINUX_4(EVENT_PC, pcval16bit1, pcval16bit2, \ + DIAG_SEVERITY_ERR); \ + RETINT(status); \ + } while (0) +/** Try to evaulate the provided expression, and do a RETINT(x) iff + * the expression evaluates to < 0. + * @param x the expression to try + */ +#define TRY(x) do { int status = (x); \ + if (status < 0) \ + FAIL(__stringify(x), status); \ + } while (0) + +#define TRY_WPOSTCODE_1(x, EVENT_PC) do { \ + int status = (x); \ + if (status < 0) \ + FAIL_WPOSTCODE_1(__stringify(x), status, EVENT_PC); \ + } while (0) + +#define TRY_WPOSTCODE_2(x, EVENT_PC, pcval32bit) do { \ + int status = (x); \ + if (status < 0) \ + FAIL_WPOSTCODE_2(__stringify(x), status, EVENT_PC, \ + pcval32bit); \ + } while (0) + +#define TRY_WPOSTCODE_3(x, EVENT_PC, pcval16bit1, pcval16bit2) do { \ + int status = (x); \ + if (status < 0) \ + FAIL_WPOSTCODE_3(__stringify(x), status, EVENT_PC, \ + pcval16bit1, pcval16bit2); \ + } while (0) + +#define ASSERT(cond) \ + do { if (!(cond)) \ + HUHDRV("ASSERT failed - %s", \ + __stringify(cond)); \ + } while (0) + +#define sizeofmember(TYPE, MEMBER) (sizeof(((TYPE *)0)->MEMBER)) +/** "Covered quotient" function */ +#define COVQ(v, d) (((v) + (d) - 1) / (d)) +#define SWAPPOINTERS(p1, p2) \ + do { \ + void *SWAPPOINTERS_TEMP = (void *)p1; \ + (void *)(p1) = (void *)(p2); \ + (void *)(p2) = SWAPPOINTERS_TEMP; \ + } while (0) + +/** + * @addtogroup driverlogging + * @{ + */ + +#define PRINTKDRV(fmt, args...) LOGINF(fmt, ## args) +#define TBDDRV(fmt, args...) LOGERR(fmt, ## args) +#define HUHDRV(fmt, args...) LOGERR(fmt, ## args) +#define ERRDRV(fmt, args...) LOGERR(fmt, ## args) +#define WARNDRV(fmt, args...) LOGWRN(fmt, ## args) +#define SECUREDRV(fmt, args...) LOGWRN(fmt, ## args) +#define INFODRV(fmt, args...) LOGINF(fmt, ## args) +#define DEBUGDRV(fmt, args...) DBGINF(fmt, ## args) + +#define PRINTKDEV(devname, fmt, args...) LOGINFDEV(devname, fmt, ## args) +#define TBDDEV(devname, fmt, args...) LOGERRDEV(devname, fmt, ## args) +#define HUHDEV(devname, fmt, args...) LOGERRDEV(devname, fmt, ## args) +#define ERRDEV(devname, fmt, args...) LOGERRDEV(devname, fmt, ## args) +#define ERRDEVX(devno, fmt, args...) LOGERRDEVX(devno, fmt, ## args) +#define WARNDEV(devname, fmt, args...) LOGWRNDEV(devname, fmt, ## args) +#define SECUREDEV(devname, fmt, args...) LOGWRNDEV(devname, fmt, ## args) +#define INFODEV(devname, fmt, args...) LOGINFDEV(devname, fmt, ## args) +#define INFODEVX(devno, fmt, args...) LOGINFDEVX(devno, fmt, ## args) +#define DEBUGDEV(devname, fmt, args...) DBGINFDEV(devname, fmt, ## args) + + +/* @} */ + +/** Used to add a single line to the /proc filesystem buffer */ +#define ADDPROCLINE(buf, bufsize, line, linelen, totallen) \ + { \ + if ((totallen) + (linelen) >= bufsize) \ + RETINT(totallen); \ + if (linelen > 0) { \ + strcat(buf, line); \ + totallen += linelen; \ + } \ + } + + + +/** Verifies the consistency of your PRIVATEDEVICEDATA structure using + * conventional "signature" fields: + * <p> + * - sig1 should contain the size of the structure + * - sig2 should contain a pointer to the beginning of the structure + */ +#define DDLOOKSVALID(dd) \ + ((dd != NULL) && \ + ((dd)->sig1 == sizeof(PRIVATEDEVICEDATA)) && \ + ((dd)->sig2 == dd)) + +/** Verifies the consistency of your PRIVATEFILEDATA structure using + * conventional "signature" fields: + * <p> + * - sig1 should contain the size of the structure + * - sig2 should contain a pointer to the beginning of the structure + */ +#define FDLOOKSVALID(fd) \ + ((fd != NULL) && \ + ((fd)->sig1 == sizeof(PRIVATEFILEDATA)) && \ + ((fd)->sig2 == fd)) + +/** Verifies the consistency of a PRIVATEDEVICEDATA structure and reacts + * if necessary + */ +#define CHKDDX(dd, x) ( \ + if (!DDLOOKSVALID((dd))) { \ + PRINTKDRV("bad device structure"); \ + RETINT(x); \ + }) + +/** Verifies the consistency of a PRIVATEDEVICEDATA structure and reacts + * if necessary + */ +#define CHKDD(dd) ( \ + if (!DDLOOKSVALID(dd)) { \ + PRINTKDRV("bad device structure"); \ + RETVOID; \ + }) + +/** Verifies the consistency of a PRIVATEFILEDATA structure and reacts + * if necessary + */ +#define CHKFDX(fd, x) ( \ + if (!FDLOOKSVALID(fd)) { \ + PRINTKDRV("bad file structure"); \ + RETINT(x); \ + }) + +/** Verifies the consistency of a PRIVATEFILEDATA structure and reacts + * if necessary + */ +#define CHKFD(fd) ( \ + if (!FDLOOKSVALID(fd)) { \ + PRINTKDRV("bad file structure"); \ + RETVOID; \ + }) + +/** Converts a device index #devix into #devData, after checking for validity. + * Can only be called from functions returning void. + * @param devix your device index within the #DevData array. + * @param devData the #PRIVATEDEVICEDATA pointer that will be set on return. + * @param where string identifying the calling function, to be printed in + * debug message + * @param dbg 1 iff debug messages are enabled + */ +#define DEVFROMID(devix, devData, where, dbg) \ + { \ + if (devix >= MAXDEVICES) { \ + PRINTKDRV("bad devix passed to %s()", where); \ + RETVOID; \ + } \ + if (dbg) \ + DEBUGDEV(devix, "%s", where); \ + if (devix >= MAXDEVICES) { \ + DEBUGDEV(devix, "%s - bad devix %d", \ + where, devix); \ + RETVOID; \ + } \ + devData = DevData[devix]; \ + CHKDD(devData); \ + } + +/** Converts a device index #devix into #devData, after checking for validity. + * Can only be called from functions returning int. + * @param devix your device index within the #DevData array. + * @param devData the #PRIVATEDEVICEDATA pointer that will be set on return. + * @param errcode error code that your function will return on error. + * @param where string identifying the calling function, to be printed in + * debug message + * @param dbg 1 iff debug messages are enabled + */ +#define DEVFROMIDX(devix, devData, errcode, where, dbg) \ + { \ + if (devix >= MAXDEVICES) { \ + PRINTKDRV("bad devix passed to %s()", where); \ + RETINT(errcode); \ + } \ + if (dbg) \ + DEBUGDEV(devix, "%s", where); \ + if (devix >= MAXDEVICES) { \ + DEBUGDEV(devix, "%s - bad devix %d", \ + where, devix); \ + RETINT(-ENODEV); \ + } \ + devData = DevData[devix]; \ + CHKDDX(devData, -EIO); \ + } + +/** Converts an inode pointer #inode into a #devix and #devData, after + * checking for validity. + * Can only be called from functions returning int. + * @param devix your device index within the #DevData array. + * @param devData the #PRIVATEDEVICEDATA pointer that will be set on return. + * @param inode input inode pointer + * @param errcode error code that your function will return on error. + * @param where string identifying the calling function, to be printed in + * debug message + * @param dbg 1 iff debug messages are enabled + */ +#define DEVFROMINODE(devix, devData, inode, errcode, where, dbg) \ + { \ + if (inode == NULL) { \ + PRINTKDRV("bad inode passed to %s()", where); \ + RETINT(errcode); \ + } \ + devix = MINOR(inode->i_rdev); \ + if (dbg) \ + DEBUGDEV(devix, "%s", where); \ + if (devix >= MAXDEVICES) { \ + DEBUGDEV(devix, "%s - bad devix %d", \ + where, devix); \ + RETINT(-ENODEV); \ + } \ + devData = DevData[devix]; \ + CHKDDX(devData, -EIO); \ + } + +/** Converts a file pointer #file into a #devix and #devData, after checking + * for validity. + * Can only be called from functions returning int. + * @param devix your device index within the #DevData array. + * @param devData the #PRIVATEDEVICEDATA pointer that will be set on return. + * @param file input file pointer + * @param errcode error code that your function will return on error. + * @param where string identifying the calling function, to be printed in + * debug message + * @param dbg 1 iff debug messages are enabled + */ +#define DEVFROMFILE(devix, devData, fileData, file, errcode, where, dbg) \ + { \ + if (file == NULL) { \ + PRINTKDRV("bad file passed to %s()", where); \ + RETINT(errcode); \ + } \ + CHKFDX((PRIVATEFILEDATA *)(file->private_data), -EIO); \ + fileData = file->private_data; \ + devix = fileData->devix; \ + if (dbg) \ + DEBUGDEV(devix, "%s %p", where, file); \ + if (devix >= MAXDEVICES) { \ + DEBUGDEV(devix, "%s - bad devix %d", \ + where, devix); \ + RETINT(-ENODEV); \ + } \ + devData = DevData[devix]; \ + CHKDDX(devData, -EIO); \ + } + +/** Locks dd->lockDev if you havn't already locked it */ +#define LOCKDEV(dd) \ + { \ + if (!lockedDev) { \ + spin_lock(&dd->lockDev); \ + lockedDev = TRUE; \ + } \ + } + +/** Unlocks dd->lockDev if you previously locked it */ +#define UNLOCKDEV(dd) \ + { \ + if (lockedDev) { \ + spin_unlock(&dd->lockDev); \ + lockedDev = FALSE; \ + } \ + } + +/** Locks dd->lockDevISR if you havn't already locked it */ +#define LOCKDEVISR(dd) \ + { \ + if (!lockedDevISR) { \ + spin_lock_irqsave(&dd->lockDevISR, flags); \ + lockedDevISR = TRUE; \ + } \ + } + +/** Unlocks dd->lockDevISR if you previously locked it */ +#define UNLOCKDEVISR(dd) \ + { \ + if (lockedDevISR) { \ + spin_unlock_irqrestore(&dd->lockDevISR, flags); \ + lockedDevISR = FALSE; \ + } \ + } + +/** Locks LockGlobalISR if you havn't already locked it */ +#define LOCKGLOBALISR \ + { \ + if (!lockedGlobalISR) { \ + spin_lock_irqsave(&LockGlobalISR, flags); \ + lockedGlobalISR = TRUE; \ + } \ + } + +/** Unlocks LockGlobalISR if you previously locked it */ +#define UNLOCKGLOBALISR \ + { \ + if (lockedGlobalISR) { \ + spin_unlock_irqrestore(&LockGlobalISR, flags); \ + lockedGlobalISR = FALSE; \ + } \ + } + +/** Locks LockGlobal if you havn't already locked it */ +#define LOCKGLOBAL \ + { \ + if (!lockedGlobal) { \ + spin_lock(&LockGlobal); \ + lockedGlobal = TRUE; \ + } \ + } + +/** Unlocks LockGlobal if you previously locked it */ +#define UNLOCKGLOBAL \ + { \ + if (lockedGlobal) { \ + spin_unlock(&LockGlobal); \ + lockedGlobal = FALSE; \ + } \ + } + +/** Use this at the beginning of functions where you intend to + * use #LOCKDEV/#UNLOCKDEV, #LOCKDEVISR/#UNLOCKDEVISR, + * #LOCKGLOBAL/#UNLOCKGLOBAL, #LOCKGLOBALISR/#UNLOCKGLOBALISR. + * + * Note that __attribute__((unused)) is how you tell GNU C to suppress + * any warning messages about the variable being unused. + */ +#define LOCKPREAMBLE \ + ulong flags __attribute__((unused)) = 0; \ + BOOL lockedDev __attribute__((unused)) = FALSE; \ + BOOL lockedDevISR __attribute__((unused)) = FALSE; \ + BOOL lockedGlobal __attribute__((unused)) = FALSE; \ + BOOL lockedGlobalISR __attribute__((unused)) = FALSE + + + +/** Sleep for an indicated number of seconds (for use in kernel mode). + * @param x the number of seconds to sleep. + */ +#define SLEEP(x) \ + do { current->state = TASK_INTERRUPTIBLE; \ + schedule_timeout((x)*HZ); \ + } while (0) + +/** Sleep for an indicated number of jiffies (for use in kernel mode). + * @param x the number of jiffies to sleep. + */ +#define SLEEPJIFFIES(x) \ + do { current->state = TASK_INTERRUPTIBLE; \ + schedule_timeout(x); \ + } while (0) + +#ifndef max +#define max(a, b) (((a) > (b)) ? (a):(b)) +#endif + +static inline struct cdev *cdev_alloc_init(struct module *owner, + const struct file_operations *fops) +{ + struct cdev *cdev = NULL; + cdev = cdev_alloc(); + if (!cdev) + return NULL; + cdev->ops = fops; + cdev->owner = owner; + + /* Note that the memory allocated for cdev will be deallocated + * when the usage count drops to 0, because it is controlled + * by a kobject of type ktype_cdev_dynamic. (This + * deallocation could very well happen outside of our kernel + * module, like via the cdev_put in __fput() for example.) + */ + return cdev; +} + +#include "timskmodutils.h" + +#endif diff --git a/drivers/staging/unisys/include/timskmodutils.h b/drivers/staging/unisys/include/timskmodutils.h new file mode 100644 index 00000000000..ad4175e83ab --- /dev/null +++ b/drivers/staging/unisys/include/timskmodutils.h @@ -0,0 +1,194 @@ +/* timskmodutils.h + * + * Copyright © 2010 - 2013 UNISYS CORPORATION + * 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. + */ + +#ifndef __TIMSKMODUTILS_H__ +#define __TIMSKMODUTILS_H__ + +#include "timskmod.h" + +void *kmalloc_kernel(size_t siz); +void *kmalloc_kernel_dma(size_t siz); +void kfree_kernel(const void *p, size_t siz); +void *vmalloc_kernel(size_t siz); +void vfree_kernel(const void *p, size_t siz); +void *pgalloc_kernel(size_t siz); +void pgfree_kernel(const void *p, size_t siz); +void myprintk(const char *myDrvName, const char *devname, + const char *template, ...); +void myprintkx(const char *myDrvName, int devno, const char *template, ...); + +/** Print the hexadecimal contents of a data buffer to a supplied print buffer. + * @param dest the print buffer where text characters will be + * written + * @param destSize the maximum number of bytes that can be written + * to #dest + * @param src the buffer that contains the data that is to be + * hex-dumped + * @param srcLen the number of bytes at #src to be hex-dumped + * @param bytesToDumpPerLine output will be formatted such that at most this + * many of the input data bytes will be represented + * on each line of output + * @return the number of text characters written to #dest + * (not including the trailing '\0' byte) + * @ingroup internal + */ +int hexDumpToBuffer(char *dest, + int destSize, + char *prefix, + char *src, + int srcLen, + int bytesToDumpPerLine); + +/** Print the hexadecimal contents of a data buffer to a supplied print buffer. + * Assume the data buffer contains 32-bit words in little-endian format, + * and dump the words with MSB first and LSB last. + * @param dest the print buffer where text characters will be + * written + * @param destSize the maximum number of bytes that can be written + * to #dest + * @param src the buffer that contains the data that is to be + * hex-dumped + * @param srcWords the number of 32-bit words at #src to be + & hex-dumped + * @param wordsToDumpPerLine output will be formatted such that at most this + * many of the input data words will be represented + * on each line of output + * @return the number of text characters written to #dest + * (not including the trailing '\0' byte) + * @ingroup internal + */ +int hexDumpWordsToBuffer(char *dest, + int destSize, + char *prefix, + uint32_t *src, + int srcWords, + int wordsToDumpPerLine); + + +/** Use printk to print the hexadecimal contents of a data buffer. + * See #INFOHEXDRV and #INFOHEXDEV for info. + * @ingroup internal + */ +int myPrintkHexDump(char *myDrvName, + char *devname, + char *prefix, + char *src, + int srcLen, + int bytesToDumpPerLine); + +/** Given as input a number of seconds in #seconds, creates text describing + * the time within #s. Also breaks down the number of seconds into component + * days, hours, minutes, and seconds, and stores to *#days, *#hours, + * *#minutes, and *#secondsx. + * @param seconds input number of seconds + * @param days points to a long value where the days component for the + * days+hours+minutes+seconds representation of #seconds will + * be stored + * @param hours points to a long value where the hours component for the + * days+hours+minutes+seconds representation of #seconds will + * be stored + * @param minutes points to a long value where the minutes component for the + * days+hours+minutes+seconds representation of #seconds will + * be stored + * @param secondsx points to a long value where the seconds component for the + * days+hours+minutes+seconds representation of #seconds will + * be stored + * @param s points to a character buffer where a text representation of + * the #seconds value will be stored. This buffer MUST be + * large enough to hold the resulting string; to be safe it + * should be at least 100 bytes long. + */ +void expandSeconds(time_t seconds, + long *days, long *hours, + long *minutes, + long *secondsx, + char *s); + +/*--------------------------------* + *--- GENERAL MESSAGEQ STUFF ---* + *--------------------------------*/ + +struct MessageQEntry; + +/** the data structure used to hold an arbitrary data item that you want + * to place on a #MESSAGEQ. Declare and initialize as follows: + * @code + * MESSAGEQENTRY myEntry; + * initMessageQEntry (&myEntry, pointerToMyDataItem); + * @endcode + * This structure should be considered opaque; the client using it should + * never access the fields directly. + * Refer to these functions for more info: + * - initMessageQ() + * - initMessageQEntry() + * - enqueueMessage() + * - dequeueMessage() + * - dequeueMessageNoBlock() + * - getQueueCount() + * + * @ingroup messageq + */ +typedef struct MessageQEntry { + void *data; + struct MessageQEntry *qNext; + struct MessageQEntry *qPrev; +} MESSAGEQENTRY; + +/** the data structure used to hold a FIFO queue of #MESSAGEQENTRY<b></b>s. + * Declare and initialize as follows: + * @code + * MESSAGEQ myQueue; + * initMessageQ (&myQueue); + * @endcode + * This structure should be considered opaque; the client using it should + * never access the fields directly. + * Refer to these functions for more info: + * - initMessageQ() + * - initMessageQEntry() + * - enqueueMessage() + * - dequeueMessage() + * - dequeueMessageNoBlock() + * - getQueueCount() + * + * @ingroup messageq + */ +typedef struct MessageQ { + MESSAGEQENTRY *qHead; + MESSAGEQENTRY *qTail; + struct semaphore nQEntries; + spinlock_t queueLock; +} MESSAGEQ; + +char *cyclesToSeconds(u64 cycles, u64 cyclesPerSecond, + char *buf, size_t bufsize); +char *cyclesToIterationSeconds(u64 cycles, u64 cyclesPerSecond, + u64 iterations, char *buf, size_t bufsize); +char *cyclesToSomethingsPerSecond(u64 cycles, u64 cyclesPerSecond, + u64 somethings, char *buf, size_t bufsize); +void initMessageQ(MESSAGEQ *q); +void initMessageQEntry(MESSAGEQENTRY *p, void *data); +MESSAGEQENTRY *dequeueMessage(MESSAGEQ *q); +MESSAGEQENTRY *dequeueMessageNoBlock(MESSAGEQ *q); +void enqueueMessage(MESSAGEQ *q, MESSAGEQENTRY *pEntry); +size_t getQueueCount(MESSAGEQ *q); +int waitQueueLen(wait_queue_head_t *q); +void debugWaitQ(wait_queue_head_t *q); +struct seq_file *seq_file_new_buffer(void *buf, size_t buf_size); +void seq_file_done_buffer(struct seq_file *m); +void seq_hexdump(struct seq_file *seq, u8 *pfx, void *buf, ulong nbytes); + +#endif diff --git a/drivers/staging/unisys/include/uisqueue.h b/drivers/staging/unisys/include/uisqueue.h new file mode 100644 index 00000000000..a9d95d30091 --- /dev/null +++ b/drivers/staging/unisys/include/uisqueue.h @@ -0,0 +1,472 @@ +/* uisqueue.h + * + * Copyright © 2010 - 2013 UNISYS CORPORATION + * 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. + */ + +/* + * Unisys IO Virtualization header NOTE: This file contains only Linux + * specific structs. All OS-independent structs are in iochannel.h.xx + */ + +#ifndef __UISQUEUE_H__ +#define __UISQUEUE_H__ + +#include "linux/version.h" +#include "iochannel.h" +#include "uniklog.h" +#include <linux/atomic.h> +#include <linux/semaphore.h> + +#include "controlvmchannel.h" +#include "controlvmcompletionstatus.h" + +struct uisqueue_info { + + pCHANNEL_HEADER chan; + /* channel containing queues in which scsi commands & + * responses are queued + */ + U64 packets_sent; + U64 packets_received; + U64 interrupts_sent; + U64 interrupts_received; + U64 max_not_empty_cnt; + U64 total_wakeup_cnt; + U64 non_empty_wakeup_cnt; + + struct { + SIGNAL_QUEUE_HEADER Reserved1; /* */ + SIGNAL_QUEUE_HEADER Reserved2; /* */ + } safe_uis_queue; + unsigned int (*send_int_if_needed)(struct uisqueue_info *info, + unsigned int whichcqueue, + unsigned char issueInterruptIfEmpty, + U64 interruptHandle, + unsigned char io_termination); +}; + +/* uisqueue_put_cmdrsp_with_lock_client queues a commmand or response + * to the specified queue, at the tail if the queue is full but + * oktowait == 0, then it return 0 indicating failure. otherwise it + * wait for the queue to become non-full. If command is queued, return + * 1 for success. + */ +#define DONT_ISSUE_INTERRUPT 0 +#define ISSUE_INTERRUPT 1 + +#define DONT_WAIT 0 +#define OK_TO_WAIT 1 +#define UISLIB_LOCK_PREFIX \ + ".section .smp_locks,\"a\"\n" \ + _ASM_ALIGN "\n" \ + _ASM_PTR "661f\n" /* address */ \ + ".previous\n" \ + "661:\n\tlock; " + +unsigned long long uisqueue_InterlockedOr(volatile unsigned long long *Target, + unsigned long long Set); +unsigned long long uisqueue_InterlockedAnd(volatile unsigned long long *Target, + unsigned long long Set); + +unsigned int uisqueue_send_int_if_needed(struct uisqueue_info *pqueueinfo, + unsigned int whichqueue, + unsigned char issueInterruptIfEmpty, + U64 interruptHandle, + unsigned char io_termination); + +int uisqueue_put_cmdrsp_with_lock_client(struct uisqueue_info *queueinfo, + struct uiscmdrsp *cmdrsp, + unsigned int queue, + void *insertlock, + unsigned char issueInterruptIfEmpty, + U64 interruptHandle, + char oktowait, + U8 *channelId); + +/* uisqueue_get_cmdrsp gets the cmdrsp entry at the head of the queue + * and copies it to the area pointed by cmdrsp param. + * returns 0 if queue is empty, 1 otherwise + */ +int + +uisqueue_get_cmdrsp(struct uisqueue_info *queueinfo, void *cmdrsp, + unsigned int queue); + +#define MAX_NAME_SIZE_UISQUEUE 64 + +struct extport_info { + U8 valid:1; + /* if 1, indicates this extport slot is occupied + * if 0, indicates that extport slot is unoccupied */ + + U32 num_devs_using; + /* When extport is added, this is set to 0. For exports + * located in NETWORK switches: + * Each time a VNIC, i.e., intport, is added to the switch this + * is used to assign a pref_pnic for the VNIC and when assigned + * to a VNIC this counter is incremented. When a VNIC is + * deleted, the extport corresponding to the VNIC's pref_pnic + * is located and its num_devs_using is decremented. For VNICs, + * num_devs_using is basically used to load-balance transmit + * traffic from VNICs. + */ + + struct switch_info *swtch; + struct PciId pci_id; + char name[MAX_NAME_SIZE_UISQUEUE]; + union { + struct vhba_wwnn wwnn; + unsigned char macaddr[MAX_MACADDR_LEN]; + }; +}; + +struct device_info { + void *chanptr; + U64 channelAddr; + U64 channelBytes; + GUID channelTypeGuid; + GUID devInstGuid; + struct InterruptInfo intr; + struct switch_info *swtch; + char devid[30]; /* "vbus<busno>:dev<devno>" */ + U16 polling; + struct semaphore interrupt_callback_lock; + U32 busNo; + U32 devNo; + int (*interrupt)(void *); + void *interrupt_context; + void *private_data; + struct list_head list_polling_device_channels; + unsigned long long moved_to_tail_cnt; + unsigned long long first_busy_cnt; + unsigned long long last_on_list_cnt; +}; + +typedef enum { + RECOVERY_LAN = 1, + IB_LAN = 2 +} SWITCH_TYPE; + +struct bus_info { + U32 busNo, deviceCount; + struct device_info **device; + U64 guestHandle, recvBusInterruptHandle; + GUID busInstGuid; + ULTRA_VBUS_CHANNEL_PROTOCOL *pBusChannel; + int busChannelBytes; + struct proc_dir_entry *proc_dir; /* proc/uislib/vbus/<x> */ + struct proc_dir_entry *proc_info; /* proc/uislib/vbus/<x>/info */ + char name[25]; + char partitionName[99]; + struct bus_info *next; + U8 localVnic; /* 1 if local vnic created internally + * by IOVM; 0 otherwise... */ +}; + +#define DEDICATED_SWITCH(pSwitch) ((pSwitch->extPortCount == 1) && \ + (pSwitch->intPortCount == 1)) + +struct sn_list_entry { + struct uisscsi_dest pdest; /* scsi bus, target, lun for + * phys disk */ + U8 sernum[MAX_SERIAL_NUM]; /* serial num of physical + * disk.. The length is always + * MAX_SERIAL_NUM, padded with + * spaces */ + struct sn_list_entry *next; +}; + +struct networkPolicy { + U32 promiscuous:1; + U32 macassign:1; + U32 peerforwarding:1; + U32 nonotify:1; + U32 standby:1; + U32 callhome:2; + char ip_addr[30]; +}; + +/* + * IO messages sent to UisnicControlChanFunc & UissdControlChanFunc by + * code that processes the ControlVm channel messages. + */ + + +typedef enum { + IOPART_ADD_VNIC, + IOPART_DEL_VNIC, + IOPART_DEL_ALL_VNICS, + IOPART_ADD_VHBA, + IOPART_ADD_VDISK, + IOPART_DEL_VHBA, + IOPART_DEL_VDISK, + IOPART_DEL_ALL_VDISKS_FOR_VHBA, + IOPART_DEL_ALL_VHBAS, + IOPART_ATTACH_PHBA, + IOPART_DETACH_PHBA, /* 10 */ + IOPART_ATTACH_PNIC, + IOPART_DETACH_PNIC, + IOPART_DETACH_VHBA, + IOPART_DETACH_VNIC, + IOPART_PAUSE_VDISK, + IOPART_RESUME_VDISK, + IOPART_ADD_DEVICE, /* add generic device */ + IOPART_DEL_DEVICE, /* del generic device */ +} IOPART_MSG_TYPE; + +struct add_virt_iopart { + void *chanptr; /* pointer to data channel */ + U64 guestHandle; /* used to convert guest physical + * address to real physical address + * for DMA, for ex. */ + U64 recvBusInterruptHandle; /* used to register to receive + * bus level interrupts. */ + struct InterruptInfo intr; /* contains recv & send + * interrupt info */ + /* recvInterruptHandle is used to register to receive + * interrupts on the data channel. Used by GuestLinux/Windows + * IO drivers to connect to interrupt. sendInterruptHandle is + * used by IOPart drivers as parameter to + * Issue_VMCALL_IO_QUEUE_TRANSITION to interrupt thread in + * guest linux/windows IO drivers when data channel queue for + * vhba/vnic goes from EMPTY to NON-EMPTY. */ + struct switch_info *swtch; /* pointer to the virtual + * switch to which the vnic is + * connected */ + + U8 useG2GCopy; /* Used to determine if a virtual HBA + * needs to use G2G copy. */ + U8 Filler[7]; + + U32 busNo; + U32 devNo; + char *params; + ulong params_bytes; + +}; + +struct add_vdisk_iopart { + void *chanptr; /* pointer to data channel */ + int implicit; + struct uisscsi_dest vdest; /* scsi bus, target, lun for virt disk */ + struct uisscsi_dest pdest; /* scsi bus, target, lun for phys disk */ + U8 sernum[MAX_SERIAL_NUM]; /* serial num of physical disk */ + U32 serlen; /* length of serial num */ + U32 busNo; + U32 devNo; +}; + +struct del_vdisk_iopart { + void *chanptr; /* pointer to data channel */ + struct uisscsi_dest vdest; /* scsi bus, target, lun for virt disk */ + U32 busNo; + U32 devNo; +}; + +struct del_virt_iopart { + void *chanptr; /* pointer to data channel */ + U32 busNo; + U32 devNo; +}; + +struct det_virt_iopart { /* detach internal port */ + void *chanptr; /* pointer to data channel */ + struct switch_info *swtch; +}; + +struct paures_vdisk_iopart { + void *chanptr; /* pointer to data channel */ + struct uisscsi_dest vdest; /* scsi bus, target, lun for virt disk */ +}; + +struct add_switch_iopart { /* add switch */ + struct switch_info *swtch; + char *params; + ulong params_bytes; +}; + +struct del_switch_iopart { /* destroy switch */ + struct switch_info *swtch; +}; + +struct io_msgs { + + IOPART_MSG_TYPE msgtype; + + /* additional params needed by some messages */ + union { + struct add_virt_iopart add_vhba; + struct add_virt_iopart add_vnic; + struct add_vdisk_iopart add_vdisk; + struct del_virt_iopart del_vhba; + struct del_virt_iopart del_vnic; + struct det_virt_iopart det_vhba; + struct det_virt_iopart det_vnic; + struct del_vdisk_iopart del_vdisk; + struct del_virt_iopart del_all_vdisks_for_vhba; + struct add_virt_iopart add_device; + struct del_virt_iopart del_device; + struct det_virt_iopart det_intport; + struct add_switch_iopart add_switch; + struct del_switch_iopart del_switch; + struct extport_info *extPort; /* for attach or detach + * pnic/generic delete all + * vhbas/allvnics need no + * parameters */ + struct paures_vdisk_iopart paures_vdisk; + }; +}; + +/* +* Guest messages sent to VirtControlChanFunc by code that processes +* the ControlVm channel messages. +*/ + +typedef enum { + GUEST_ADD_VBUS, + GUEST_ADD_VHBA, + GUEST_ADD_VNIC, + GUEST_DEL_VBUS, + GUEST_DEL_VHBA, + GUEST_DEL_VNIC, + GUEST_DEL_ALL_VHBAS, + GUEST_DEL_ALL_VNICS, + GUEST_DEL_ALL_VBUSES, /* deletes all vhbas & vnics on all + * buses and deletes all buses */ + GUEST_PAUSE_VHBA, + GUEST_PAUSE_VNIC, + GUEST_RESUME_VHBA, + GUEST_RESUME_VNIC +} GUESTPART_MSG_TYPE; + +struct add_vbus_guestpart { + void *chanptr; /* pointer to data channel for bus - + * NOT YET USED */ + U32 busNo; /* bus number to be created/deleted */ + U32 deviceCount; /* max num of devices on bus */ + GUID busTypeGuid; /* indicates type of bus */ + GUID busInstGuid; /* instance guid for device */ +}; + +struct del_vbus_guestpart { + U32 busNo; /* bus number to be deleted */ + /* once we start using the bus's channel, add can dump busNo + * into the channel header and then delete will need only one + * parameter, chanptr. */ +}; + +struct add_virt_guestpart { + void *chanptr; /* pointer to data channel */ + U32 busNo; /* bus number for the operation */ + U32 deviceNo; /* number of device on the bus */ + GUID devInstGuid; /* instance guid for device */ + struct InterruptInfo intr; /* recv/send interrupt info */ + /* recvInterruptHandle contains info needed in order to + * register to receive interrupts on the data channel. + * sendInterruptHandle contains handle which is provided to + * monitor VMCALL that will cause an interrupt to be generated + * for the other end. + */ +}; + +struct pause_virt_guestpart { + void *chanptr; /* pointer to data channel */ +}; + +struct resume_virt_guestpart { + void *chanptr; /* pointer to data channel */ +}; + +struct del_virt_guestpart { + void *chanptr; /* pointer to data channel */ +}; + +struct init_chipset_guestpart { + U32 busCount; /* indicates the max number of busses */ + U32 switchCount; /* indicates the max number of switches */ +}; + +struct guest_msgs { + + GUESTPART_MSG_TYPE msgtype; + + /* additional params needed by messages */ + union { + struct add_vbus_guestpart add_vbus; + struct add_virt_guestpart add_vhba; + struct add_virt_guestpart add_vnic; + struct pause_virt_guestpart pause_vhba; + struct pause_virt_guestpart pause_vnic; + struct resume_virt_guestpart resume_vhba; + struct resume_virt_guestpart resume_vnic; + struct del_vbus_guestpart del_vbus; + struct del_virt_guestpart del_vhba; + struct del_virt_guestpart del_vnic; + struct del_vbus_guestpart del_all_vhbas; + struct del_vbus_guestpart del_all_vnics; + /* del_all_vbuses needs no parameters */ + }; + struct init_chipset_guestpart init_chipset; + +}; + +#ifndef __xg +#define __xg(x) ((volatile long *)(x)) +#endif + +/* +* Below code is a copy of Linux kernel's cmpxchg function located at +* this place +* http://tcsxeon:8080/source/xref/00trunk-AppOS-linux/include/asm-x86/cmpxchg_64.h#84 +* Reason for creating our own version of cmpxchg along with +* UISLIB_LOCK_PREFIX is to make the operation atomic even for non SMP +* guests. +*/ + +static inline unsigned long +uislibcmpxchg64(volatile void *ptr, unsigned long old, unsigned long new, + int size) +{ + unsigned long prev; + switch (size) { + case 1: + __asm__ __volatile__(UISLIB_LOCK_PREFIX "cmpxchgb %b1,%2":"=a"(prev) + : "q"(new), "m"(*__xg(ptr)), + "0"(old) + : "memory"); + return prev; + case 2: + __asm__ __volatile__(UISLIB_LOCK_PREFIX "cmpxchgw %w1,%2":"=a"(prev) + : "r"(new), "m"(*__xg(ptr)), + "0"(old) + : "memory"); + return prev; + case 4: + __asm__ __volatile__(UISLIB_LOCK_PREFIX "cmpxchgl %k1,%2":"=a"(prev) + : "r"(new), "m"(*__xg(ptr)), + "0"(old) + : "memory"); + return prev; + case 8: + __asm__ __volatile__(UISLIB_LOCK_PREFIX "cmpxchgq %1,%2":"=a"(prev) + : "r"(new), "m"(*__xg(ptr)), + "0"(old) + : "memory"); + return prev; + } + return old; +} + +#endif /* __UISQUEUE_H__ */ diff --git a/drivers/staging/unisys/include/uisthread.h b/drivers/staging/unisys/include/uisthread.h new file mode 100644 index 00000000000..2b1fba75909 --- /dev/null +++ b/drivers/staging/unisys/include/uisthread.h @@ -0,0 +1,46 @@ +/* uisthread.h + * + * Copyright © 2010 - 2013 UNISYS CORPORATION + * 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. + */ + +/*****************************************************************************/ +/* Unisys thread utilities header */ +/*****************************************************************************/ + + +#ifndef __UISTHREAD_H__ +#define __UISTHREAD_H__ + + +#include "linux/completion.h" + +struct uisthread_info { + struct task_struct *task; + int id; + int should_stop; + struct completion has_stopped; +}; + + +/* returns 0 for failure, 1 for success */ +int uisthread_start( + struct uisthread_info *thrinfo, + int (*threadfn)(void *), + void *thrcontext, + char *name); + +void uisthread_stop(struct uisthread_info *thrinfo); + +#endif /* __UISTHREAD_H__ */ diff --git a/drivers/staging/unisys/include/uisutils.h b/drivers/staging/unisys/include/uisutils.h new file mode 100644 index 00000000000..9fee353686c --- /dev/null +++ b/drivers/staging/unisys/include/uisutils.h @@ -0,0 +1,359 @@ +/* uisutils.h + * + * Copyright © 2010 - 2013 UNISYS CORPORATION + * 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. + */ + +/* + * Unisys Virtual HBA utilities header + */ + +#ifndef __UISUTILS__H__ +#define __UISUTILS__H__ +#include <linux/string.h> +#include <linux/io.h> +#include <linux/sched.h> +#include <linux/gfp.h> + +#include "vmcallinterface.h" +#include "channel.h" +#include "uisthread.h" +#include "uisqueue.h" +#include "diagnostics/appos_subsystems.h" +#include "vbusdeviceinfo.h" +#include <linux/atomic.h> + +/* This is the MAGIC number stuffed by virthba in host->this_id. Used to + * identify virtual hbas. + */ +#define UIS_MAGIC_VHBA 707 + +/* global function pointers that act as callback functions into + * uisnicmod, uissdmod, and virtpcimod + */ +extern int (*UisnicControlChanFunc)(struct io_msgs *); +extern int (*UissdControlChanFunc)(struct io_msgs *); +extern int (*VirtControlChanFunc)(struct guest_msgs *); + +/* Return values of above callback functions: */ +#define CCF_ERROR 0 /* completed and failed */ +#define CCF_OK 1 /* completed successfully */ +#define CCF_PENDING 2 /* operation still pending */ +extern atomic_t UisUtils_Registered_Services; + +typedef unsigned int MACARRAY[MAX_MACADDR_LEN]; +typedef struct ReqHandlerInfo_struct { + GUID switchTypeGuid; + int (*controlfunc)(struct io_msgs *); + unsigned long min_channel_bytes; + int (*Server_Channel_Ok)(unsigned long channelBytes); + int (*Server_Channel_Init) + (void *x, unsigned char *clientStr, U32 clientStrLen, U64 bytes); + char switch_type_name[99]; + struct list_head list_link; /* links into ReqHandlerInfo_list */ +} ReqHandlerInfo_t; + +ReqHandlerInfo_t *ReqHandlerAdd(GUID switchTypeGuid, + const char *switch_type_name, + int (*controlfunc)(struct io_msgs *), + unsigned long min_channel_bytes, + int (*Server_Channel_Ok)(unsigned long + channelBytes), + int (*Server_Channel_Init) + (void *x, unsigned char *clientStr, + U32 clientStrLen, U64 bytes)); +ReqHandlerInfo_t *ReqHandlerFind(GUID switchTypeGuid); +int ReqHandlerDel(GUID switchTypeGuid); + +#define uislib_ioremap_cache(addr, size) \ + dbg_ioremap_cache(addr, size, __FILE__, __LINE__) + +static inline void * +dbg_ioremap_cache(U64 addr, unsigned long size, char *file, int line) +{ + void *new; + new = ioremap_cache(addr, size); + return new; +} + +#define uislib_ioremap(addr, size) dbg_ioremap(addr, size, __FILE__, __LINE__) + +static inline void * +dbg_ioremap(U64 addr, unsigned long size, char *file, int line) +{ + void *new; + new = ioremap(addr, size); + return new; +} + +#define uislib_iounmap(addr) dbg_iounmap(addr, __FILE__, __LINE__) + +static inline void +dbg_iounmap(void *addr, char *file, int line) +{ + iounmap(addr); +} + +#define PROC_READ_BUFFER_SIZE 131072 /* size of the buffer to allocate to + * hold all of /proc/XXX/info */ +int util_add_proc_line_ex(int *total, char **buffer, int *buffer_remaining, + char *format, ...); + +int uisctrl_register_req_handler(int type, void *fptr, + ULTRA_VBUS_DEVICEINFO *chipset_DriverInfo); +int uisctrl_register_req_handler_ex(GUID switchTypeGuid, + const char *switch_type_name, + int (*fptr)(struct io_msgs *), + unsigned long min_channel_bytes, + int (*Server_Channel_Ok)(unsigned long + channelBytes), + int (*Server_Channel_Init) + (void *x, unsigned char *clientStr, + U32 clientStrLen, U64 bytes), + ULTRA_VBUS_DEVICEINFO *chipset_DriverInfo); + +int uisctrl_unregister_req_handler_ex(GUID switchTypeGuid); +unsigned char *util_map_virt(struct phys_info *sg); +void util_unmap_virt(struct phys_info *sg); +unsigned char *util_map_virt_atomic(struct phys_info *sg); +void util_unmap_virt_atomic(void *buf); +int uislib_server_inject_add_vnic(U32 switchNo, U32 BusNo, U32 numIntPorts, + U32 numExtPorts, MACARRAY pmac[], + pCHANNEL_HEADER **chan); +void uislib_server_inject_del_vnic(U32 switchNo, U32 busNo, U32 numIntPorts, + U32 numExtPorts); +int uislib_client_inject_add_bus(U32 busNo, GUID instGuid, + U64 channelAddr, ulong nChannelBytes); +int uislib_client_inject_del_bus(U32 busNo); + +int uislib_client_inject_add_vhba(U32 busNo, U32 devNo, + U64 phys_chan_addr, U32 chan_bytes, + int is_test_addr, GUID instGuid, + struct InterruptInfo *intr); +int uislib_client_inject_pause_vhba(U32 busNo, U32 devNo); +int uislib_client_inject_resume_vhba(U32 busNo, U32 devNo); +int uislib_client_inject_del_vhba(U32 busNo, U32 devNo); +int uislib_client_inject_add_vnic(U32 busNo, U32 devNo, + U64 phys_chan_addr, U32 chan_bytes, + int is_test_addr, GUID instGuid, + struct InterruptInfo *intr); +int uislib_client_inject_pause_vnic(U32 busNo, U32 devNo); +int uislib_client_inject_resume_vnic(U32 busNo, U32 devNo); +int uislib_client_inject_del_vnic(U32 busNo, U32 devNo); +#ifdef STORAGE_CHANNEL +U64 uislib_storage_channel(int client_id); +#endif +int uislib_get_owned_pdest(struct uisscsi_dest *pdest); + +int uislib_send_event(CONTROLVM_ID id, CONTROLVM_MESSAGE_PACKET *event); + +/* structure used by vhba & vnic to keep track of queue & thread info */ +struct chaninfo { + struct uisqueue_info *queueinfo; + /* this specifies the queue structures for a channel */ + /* ALLOCATED BY THE OTHER END - WE JUST GET A POINTER TO THE MEMORY */ + spinlock_t insertlock; + /* currently used only in virtnic when sending data to uisnic */ + /* to synchronize the inserts into the signal queue */ + struct uisthread_info threadinfo; + /* this specifies the thread structures used by the thread that */ + /* handles this channel */ +}; + +/* this is the wait code for all the threads - it is used to get +* something from a queue choices: wait_for_completion_interruptible, +* _timeout, interruptible_timeout +*/ +#define UIS_THREAD_WAIT_MSEC(x) { \ + set_current_state(TASK_INTERRUPTIBLE); \ + schedule_timeout(msecs_to_jiffies(x)); \ +} +#define UIS_THREAD_WAIT_USEC(x) { \ + set_current_state(TASK_INTERRUPTIBLE); \ + schedule_timeout(usecs_to_jiffies(x)); \ +} +#define UIS_THREAD_WAIT UIS_THREAD_WAIT_MSEC(5) +#define UIS_THREAD_WAIT_SEC(x) { \ + set_current_state(TASK_INTERRUPTIBLE); \ + schedule_timeout((x)*HZ); \ +} + +#define ALLOC_CMDRSP(cmdrsp) { \ + cmdrsp = kmalloc(SIZEOF_CMDRSP, GFP_ATOMIC); \ + if (cmdrsp != NULL) { \ + memset(cmdrsp, 0, SIZEOF_CMDRSP); \ + } \ +} + +/* This is a hack until we fix IOVM to initialize the channel header + * correctly at DEVICE_CREATE time, INSTEAD OF waiting until + * DEVICE_CONFIGURE time. + */ +#define WAIT_FOR_VALID_GUID(guid) \ + do { \ + while (memcmp(&guid, &Guid0, sizeof(Guid0)) == 0) { \ + LOGERR("Waiting for non-0 GUID (why???)...\n"); \ + UIS_THREAD_WAIT_SEC(5); \ + } \ + LOGERR("OK... GUID is non-0 now\n"); \ + } while (0) + +/* CopyFragsInfoFromSkb returns the number of entries added to frags array + * Returns -1 on failure. + */ +unsigned int util_copy_fragsinfo_from_skb(unsigned char *calling_ctx, + void *skb_in, unsigned int firstfraglen, + unsigned int frags_max, struct phys_info frags[]); + +static inline unsigned int +Issue_VMCALL_IO_CONTROLVM_ADDR(U64 *ControlAddress, U32 *ControlBytes) +{ + VMCALL_IO_CONTROLVM_ADDR_PARAMS params; + int result = VMCALL_SUCCESS; + U64 physaddr; + + physaddr = virt_to_phys(¶ms); + ISSUE_IO_VMCALL(VMCALL_IO_CONTROLVM_ADDR, physaddr, result); + if (VMCALL_SUCCESSFUL(result)) { + *ControlAddress = params.ChannelAddress; + *ControlBytes = params.ChannelBytes; + } + return result; +} + +static inline unsigned int Issue_VMCALL_IO_DIAG_ADDR(U64 *DiagChannelAddress) +{ + VMCALL_IO_DIAG_ADDR_PARAMS params; + int result = VMCALL_SUCCESS; + U64 physaddr; + + physaddr = virt_to_phys(¶ms); + ISSUE_IO_VMCALL(VMCALL_IO_DIAG_ADDR, physaddr, result); + if (VMCALL_SUCCESSFUL(result)) + *DiagChannelAddress = params.ChannelAddress; + return result; +} + +static inline unsigned int +Issue_VMCALL_IO_VISORSERIAL_ADDR(U64 *DiagChannelAddress) +{ + VMCALL_IO_VISORSERIAL_ADDR_PARAMS params; + int result = VMCALL_SUCCESS; + U64 physaddr; + + physaddr = virt_to_phys(¶ms); + ISSUE_IO_VMCALL(VMCALL_IO_VISORSERIAL_ADDR, physaddr, result); + if (VMCALL_SUCCESSFUL(result)) + *DiagChannelAddress = params.ChannelAddress; + return result; +} + +static inline S64 Issue_VMCALL_QUERY_GUEST_VIRTUAL_TIME_OFFSET(void) +{ + U64 result = VMCALL_SUCCESS; + U64 physaddr = 0; + + ISSUE_IO_VMCALL(VMCALL_QUERY_GUEST_VIRTUAL_TIME_OFFSET, physaddr, + result); + return result; +} + +static inline S64 Issue_VMCALL_MEASUREMENT_DO_NOTHING(void) +{ + U64 result = VMCALL_SUCCESS; + U64 physaddr = 0; + + ISSUE_IO_VMCALL(VMCALL_MEASUREMENT_DO_NOTHING, physaddr, result); + return result; +} + +struct log_info_t { + volatile unsigned long long last_cycles; + unsigned long long delta_sum[64]; + unsigned long long delta_cnt[64]; + unsigned long long max_delta[64]; + unsigned long long min_delta[64]; +}; + +static inline int Issue_VMCALL_UPDATE_PHYSICAL_TIME(U64 adjustment) +{ + int result = VMCALL_SUCCESS; + + ISSUE_IO_VMCALL(VMCALL_UPDATE_PHYSICAL_TIME, adjustment, result); + return result; +} + +static inline unsigned int +Issue_VMCALL_CHANNEL_MISMATCH(const char *ChannelName, + const char *ItemName, + U32 SourceLineNumber, const char *path_n_fn) +{ + VMCALL_CHANNEL_VERSION_MISMATCH_PARAMS params; + int result = VMCALL_SUCCESS; + U64 physaddr; + char *last_slash = NULL; + + strncpy(params.ChannelName, ChannelName, + lengthof(VMCALL_CHANNEL_VERSION_MISMATCH_PARAMS, ChannelName)); + strncpy(params.ItemName, ItemName, + lengthof(VMCALL_CHANNEL_VERSION_MISMATCH_PARAMS, ItemName)); + params.SourceLineNumber = SourceLineNumber; + + last_slash = strrchr(path_n_fn, '/'); + if (last_slash != NULL) { + last_slash++; + strncpy(params.SourceFileName, last_slash, + lengthof(VMCALL_CHANNEL_VERSION_MISMATCH_PARAMS, + SourceFileName)); + } else + strncpy(params.SourceFileName, + "Cannot determine source filename", + lengthof(VMCALL_CHANNEL_VERSION_MISMATCH_PARAMS, + SourceFileName)); + + physaddr = virt_to_phys(¶ms); + ISSUE_IO_VMCALL(VMCALL_CHANNEL_VERSION_MISMATCH, physaddr, result); + return result; +} + +static inline unsigned int Issue_VMCALL_FATAL_BYE_BYE(void) +{ + int result = VMCALL_SUCCESS; + U64 physaddr = 0; + + ISSUE_IO_VMCALL(VMCALL_GENERIC_SURRENDER_QUANTUM_FOREVER, physaddr, + result); + return result; +} + +#define UIS_DAEMONIZE(nam) +void *uislib_malloc(size_t siz, gfp_t gfp, U8 contiguous, char *fn, int ln); +#define UISMALLOC(siz, gfp) uislib_malloc(siz, gfp, 1, __FILE__, __LINE__) +#define UISVMALLOC(siz) uislib_malloc(siz, 0, 0, __FILE__, __LINE__) +void uislib_free(void *p, size_t siz, U8 contiguous, char *fn, int ln); +#define UISFREE(p, siz) uislib_free(p, siz, 1, __FILE__, __LINE__) +#define UISVFREE(p, siz) uislib_free(p, siz, 0, __FILE__, __LINE__) +void *uislib_cache_alloc(struct kmem_cache *cur_pool, char *fn, int ln); +#define UISCACHEALLOC(cur_pool) uislib_cache_alloc(cur_pool, __FILE__, __LINE__) +void uislib_cache_free(struct kmem_cache *cur_pool, void *p, char *fn, int ln); +#define UISCACHEFREE(cur_pool, p) \ + uislib_cache_free(cur_pool, p, __FILE__, __LINE__) + +void uislib_enable_channel_interrupts(U32 busNo, U32 devNo, + int (*interrupt)(void *), + void *interrupt_context); +void uislib_disable_channel_interrupts(U32 busNo, U32 devNo); +void uislib_force_channel_interrupt(U32 busNo, U32 devNo); + +#endif /* __UISUTILS__H__ */ diff --git a/drivers/staging/unisys/include/uniklog.h b/drivers/staging/unisys/include/uniklog.h new file mode 100644 index 00000000000..4d7b87cefa6 --- /dev/null +++ b/drivers/staging/unisys/include/uniklog.h @@ -0,0 +1,193 @@ +/* uniklog.h + * + * Copyright © 2010 - 2013 UNISYS CORPORATION + * 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. + */ + +/* This module contains macros to aid developers in logging messages. + * + * This module is affected by the DEBUG compiletime option. + * + */ +#ifndef __UNIKLOG_H__ +#define __UNIKLOG_H__ + + +#include <linux/printk.h> + +/* + * # DBGINF + * + * \brief Log debug informational message - log a LOG_INFO message only + * if DEBUG compiletime option enabled + * + * \param devname the device name of the device reporting this message, or + * NULL if this message is NOT device-related. + * \param fmt printf()-style format string containing the message to log. + * \param args Optional arguments to be formatted and inserted into the + * format string. + * \return nothing + * + * Log a message at the LOG_INFO level, but only if DEBUG is enabled. If + * DEBUG is disabled, this expands to a no-op. + */ + +/* + * # DBGVER + * + * \brief Log debug verbose message - log a LOG_DEBUG message only if + * DEBUG compiletime option enabled + * + * \param devname the device name of the device reporting this message, or + * NULL if this message is NOT device-related. + * \param fmt printf()-style format string containing the message to log. + * \param args Optional arguments to be formatted and inserted into the + * format string. + * \return nothing + * + * Log a message at the LOG_DEBUG level, but only if DEBUG is enabled. If + * DEBUG is disabled, this expands to a no-op. Note also that LOG_DEBUG + * messages can be enabled/disabled at runtime as well. + */ +#define DBGINFDEV(devname, fmt, args...) do { } while (0) +#define DBGVERDEV(devname, fmt, args...) do { } while (0) +#define DBGINF(fmt, args...) do { } while (0) +#define DBGVER(fmt, args...) do { } while (0) + +/* + * # LOGINF + * + * \brief Log informational message - logs a message at the LOG_INFO level + * + * \param devname the device name of the device reporting this message, or + * NULL if this message is NOT device-related. + * \param fmt printf()-style format string containing the message to log. + * \param args Optional arguments to be formatted and inserted into the + * format string. + * \return nothing + * + * Logs the specified message at the LOG_INFO level. + */ + +#define LOGINF(fmt, args...) pr_info(fmt, ## args) +#define LOGINFDEV(devname, fmt, args...) \ + pr_info("%s " fmt, devname, ## args) +#define LOGINFDEVX(devno, fmt, args...) \ + pr_info("dev%d " fmt, devno, ## args) +#define LOGINFNAME(vnic, fmt, args...) \ + do { \ + if (vnic != NULL) { \ + pr_info("%s " fmt, vnic->name, ## args); \ + } else { \ + pr_info(fmt, ## args); \ + } \ + } while (0) + +/* + * # LOGVER + * + * \brief Log verbose message - logs a message at the LOG_DEBUG level, + * which can be disabled at runtime + * + * \param devname the device name of the device reporting this message, or + * NULL if this message is NOT device-related. + * \param fmt printf()-style format string containing the message to log. + * \param args Optional arguments to be formatted and inserted into the format + * \param string. + * \return nothing + * + * Logs the specified message at the LOG_DEBUG level. Note also that + * LOG_DEBUG messages can be enabled/disabled at runtime as well. + */ +#define LOGVER(fmt, args...) pr_debug(fmt, ## args) +#define LOGVERDEV(devname, fmt, args...) \ + pr_debug("%s " fmt, devname, ## args) +#define LOGVERNAME(vnic, fmt, args...) \ + do { \ + if (vnic != NULL) { \ + pr_debug("%s " fmt, vnic->name, ## args); \ + } else { \ + pr_debug(fmt, ## args); \ + } \ + } while (0) + + +/* + * # LOGERR + * + * \brief Log error message - logs a message at the LOG_ERR level, + * including source line number information + * + * \param devname the device name of the device reporting this message, or + * NULL if this message is NOT device-related. + * \param fmt printf()-style format string containing the message to log. + * \param args Optional arguments to be formatted and inserted into the format + * \param string. + * \return nothing + * + * Logs the specified error message at the LOG_ERR level. It will also + * include the file, line number, and function name of where the error + * originated in the log message. + */ +#define LOGERR(fmt, args...) pr_err(fmt, ## args) +#define LOGERRDEV(devname, fmt, args...) \ + pr_err("%s " fmt, devname, ## args) +#define LOGERRDEVX(devno, fmt, args...) \ + pr_err("dev%d " fmt, devno, ## args) +#define LOGERRNAME(vnic, fmt, args...) \ + do { \ + if (vnic != NULL) { \ + pr_err("%s " fmt, vnic->name, ## args); \ + } else { \ + pr_err(fmt, ## args); \ + } \ + } while (0) +#define LOGORDUMPERR(seqfile, fmt, args...) do { \ + if (seqfile) { \ + seq_printf(seqfile, fmt, ## args); \ + } else { \ + LOGERR(fmt, ## args); \ + } \ + } while (0) + +/* + * # LOGWRN + * + * \brief Log warning message - Logs a message at the LOG_WARNING level, + * including source line number information + * + * \param devname the device name of the device reporting this message, or + * NULL if this message is NOT device-related. + * \param fmt printf()-style format string containing the message to log. + * \param args Optional arguments to be formatted and inserted into the format + * \param string. + * \return nothing + * + * Logs the specified error message at the LOG_WARNING level. It will also + * include the file, line number, and function name of where the error + * originated in the log message. + */ +#define LOGWRN(fmt, args...) pr_warn(fmt, ## args) +#define LOGWRNDEV(devname, fmt, args...) \ + pr_warn("%s " fmt, devname, ## args) +#define LOGWRNNAME(vnic, fmt, args...) \ + do { \ + if (vnic != NULL) { \ + pr_warn("%s " fmt, vnic->name, ## args); \ + } else { \ + pr_warn(fmt, ## args); \ + } \ + } while (0) + +#endif /* __UNIKLOG_H__ */ diff --git a/drivers/staging/unisys/include/vbushelper.h b/drivers/staging/unisys/include/vbushelper.h new file mode 100644 index 00000000000..93e35f039de --- /dev/null +++ b/drivers/staging/unisys/include/vbushelper.h @@ -0,0 +1,47 @@ +/* vbushelper.h + * + * Copyright © 2011 - 2013 UNISYS CORPORATION + * 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. + */ + +#ifndef __VBUSHELPER_H__ +#define __VBUSHELPER_H__ + +#include "vbusdeviceinfo.h" + +/* TARGET_HOSTNAME specified as -DTARGET_HOSTNAME=\"thename\" on the + * command line */ + +#define TARGET_HOSTNAME "linuxguest" + +static inline void +BusDeviceInfo_Init(ULTRA_VBUS_DEVICEINFO *pBusDeviceInfo, + const char *deviceType, const char *driverName, + const char *ver, const char *verTag, + const char *buildDate, const char *buildTime) +{ + memset(pBusDeviceInfo, 0, sizeof(ULTRA_VBUS_DEVICEINFO)); + snprintf(pBusDeviceInfo->devType, sizeof(pBusDeviceInfo->devType), + "%s", (deviceType) ? deviceType : "unknownType"); + snprintf(pBusDeviceInfo->drvName, sizeof(pBusDeviceInfo->drvName), + "%s", (driverName) ? driverName : "unknownDriver"); + snprintf(pBusDeviceInfo->infoStrings, + sizeof(pBusDeviceInfo->infoStrings), "%s\t%s\t%s %s\t%s", + (ver) ? ver : "unknownVer", + (verTag) ? verTag : "unknownVerTag", + (buildDate) ? buildDate : "noBuildDate", + (buildTime) ? buildTime : "nobuildTime", TARGET_HOSTNAME); +} + +#endif diff --git a/drivers/staging/unisys/uislib/Kconfig b/drivers/staging/unisys/uislib/Kconfig new file mode 100644 index 00000000000..8d87d9c81c6 --- /dev/null +++ b/drivers/staging/unisys/uislib/Kconfig @@ -0,0 +1,10 @@ +# +# Unisys uislib configuration +# + +config UNISYS_UISLIB + tristate "Unisys uislib driver" + depends on UNISYSSPAR && UNISYS_VISORCHIPSET && UNISYS_CHANNELSTUB + ---help--- + If you say Y here, you will enable the Unisys uislib driver. + diff --git a/drivers/staging/unisys/uislib/Makefile b/drivers/staging/unisys/uislib/Makefile new file mode 100644 index 00000000000..6e44d49458f --- /dev/null +++ b/drivers/staging/unisys/uislib/Makefile @@ -0,0 +1,17 @@ +# +# Makefile for Unisys uislib +# + +obj-$(CONFIG_UNISYS_UISLIB) += visoruislib.o + +visoruislib-y := uislib.o uisqueue.o uisthread.o uisutils.o + +ccflags-y += -Idrivers/staging/unisys/include +ccflags-y += -Idrivers/staging/unisys/channels +ccflags-y += -Idrivers/staging/unisys/visorchipset +ccflags-y += -Idrivers/staging/unisys/sparstopdriver +ccflags-y += -Idrivers/staging/unisys/common-spar/include +ccflags-y += -Idrivers/staging/unisys/common-spar/include/channels + +ccflags-y += -DCONFIG_SPAR_GUEST -DGUESTDRIVERBUILD -DNOAUTOVERSION + diff --git a/drivers/staging/unisys/uislib/uislib.c b/drivers/staging/unisys/uislib/uislib.c new file mode 100644 index 00000000000..a004c9ddc11 --- /dev/null +++ b/drivers/staging/unisys/uislib/uislib.c @@ -0,0 +1,2536 @@ +/* uislib.c + * + * Copyright � 2010 - 2013 UNISYS CORPORATION + * 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. + */ + +/* @ALL_INSPECTED */ +#define EXPORT_SYMTAB +#include <linux/kernel.h> +#include <linux/highmem.h> +#ifdef CONFIG_MODVERSIONS +#include <config/modversions.h> +#endif +#include <linux/module.h> + +#include "commontypes.h" + +#include <linux/version.h> +#include "uniklog.h" +#include "diagnostics/appos_subsystems.h" +#include "uisutils.h" +#include "vbuschannel.h" + +#include <linux/proc_fs.h> +#include <linux/uaccess.h> /* for copy_from_user */ +#include <linux/ctype.h> /* for toupper */ +#include <linux/list.h> + +#include "sparstop.h" +#include "visorchipset.h" +#include "chanstub.h" +#include "version.h" +#include "guestlinuxdebug.h" + +#define SET_PROC_OWNER(x, y) + +#define UISLIB_TEST_PROC +#define POLLJIFFIES_NORMAL 1 +/* Choose whether or not you want to wakeup the request-polling thread + * after an IO termination: + * this is shorter than using __FILE__ (full path name) in + * debug/info/error messages + */ +#define CURRENT_FILE_PC UISLIB_PC_uislib_c +#define __MYFILE__ "uislib.c" + +/* global function pointers that act as callback functions into virtpcimod */ +int (*VirtControlChanFunc)(struct guest_msgs *); + +static int ProcReadBufferValid; +static char *ProcReadBuffer; /* Note this MUST be global, + * because the contents must */ +static unsigned int chipset_inited; +int callback_count = 0; +#define WAIT_ON_CALLBACK(handle) \ + do { \ + if (handle) \ + break; \ + UIS_THREAD_WAIT; \ + } while (1) + +static struct bus_info *BusListHead; +static rwlock_t BusListLock; +static int BusListCount; /* number of buses in the list */ +static int MaxBusCount; /* maximum number of buses expected */ +static U64 PhysicalDataChan; +static int PlatformNumber; + +/* This is a list of controlvm messages which could not complete + * immediately, but instead must be occasionally retried until they + * ultimately succeed/fail. When this happens, + * msg->hdr.Flags.responseExpected determines whether or not we will + * send a controlvm response. + */ +struct controlvm_retry_entry { + CONTROLVM_MESSAGE msg; + struct io_msgs cmd; + void *obj; + int (*controlChanFunc)(struct io_msgs *); + struct list_head list_link; +}; +LIST_HEAD(ControlVmRetryQHead); + +static struct uisthread_info Incoming_ThreadInfo; +static BOOL Incoming_Thread_Started = FALSE; +LIST_HEAD(List_Polling_Device_Channels); +unsigned long long tot_moved_to_tail_cnt = 0; +unsigned long long tot_wait_cnt = 0; +unsigned long long tot_wakeup_cnt = 0; +unsigned long long tot_schedule_cnt = 0; +int en_smart_wakeup = 1; +static DEFINE_SEMAPHORE(Lock_Polling_Device_Channels); /* unlocked */ +DECLARE_WAIT_QUEUE_HEAD(Wakeup_Polling_Device_Channels); +static int Go_Polling_Device_Channels; + +static struct proc_dir_entry *uislib_proc_dir; +static struct proc_dir_entry *uislib_proc_vbus_dir; +static struct proc_dir_entry *vnic_proc_entry; /* Used to be "datachan" */ +static struct proc_dir_entry *ctrlchan_proc_entry; +static struct proc_dir_entry *pmem_proc_entry; +static struct proc_dir_entry *info_proc_entry; +static struct proc_dir_entry *switch_proc_entry; +static struct proc_dir_entry *extport_proc_entry; +static struct proc_dir_entry *platformnumber_proc_entry; +static struct proc_dir_entry *bus_proc_entry; +static struct proc_dir_entry *dev_proc_entry; +static struct proc_dir_entry *chipset_proc_entry; +static struct proc_dir_entry *cycles_before_wait_proc_entry; +static struct proc_dir_entry *reset_counts_proc_entry; +static struct proc_dir_entry *smart_wakeup_proc_entry; +static struct proc_dir_entry *disable_proc_entry; + +#define DIR_PROC_ENTRY "uislib" +#define DIR_VBUS_PROC_ENTRY "vbus" +#define VNIC_PROC_ENTRY_FN "vnic" /* Used to be "datachan" */ +#define CTRLCHAN_PROC_ENTRY_FN "ctrlchan" +#define PMEM_PROC_ENTRY_FN "phys_to_virt" +#define INFO_PROC_ENTRY_FN "info" +#define SWITCH_PROC_ENTRY_FN "switch" +#define SWITCH_COUNT_PROC_ENTRY_FN "switch_count" +#define EXTPORT_PROC_ENTRY_FN "extport" +#define PLATFORMNUMBER_PROC_ENTRY_FN "platform" +#define BUS_PROC_ENTRY_FN "bus" +#define DEV_PROC_ENTRY_FN "device" +#define CHIPSET_PROC_ENTRY_FN "chipset" +#define CYCLES_BEFORE_WAIT_PROC_ENTRY_FN "cycles_before_wait" +#define RESET_COUNTS_PROC_ENTRY_FN "reset_counts" +#define SMART_WAKEUP_PROC_ENTRY_FN "smart_wakeup" +#define CALLHOME_PROC_ENTRY_FN "callhome" +#define CALLHOME_THROTTLED_PROC_ENTRY_FN "callhome_throttled" +#define DISABLE_PROC_ENTRY_FN "switch_state" +#ifdef UISLIB_TEST_PROC +static struct proc_dir_entry *test_proc_entry; +#define TEST_PROC_ENTRY_FN "test" +#endif +unsigned long long cycles_before_wait, wait_cycles; + +/*****************************************************/ +/* local functions */ +/*****************************************************/ + +static int proc_info_vbus_show(struct seq_file *m, void *v); +static int +proc_info_vbus_open(struct inode *inode, struct file *filp) +{ + /* proc_info_vbus_show will grab this from seq_file.private: */ + struct bus_info *bus = PDE_DATA(inode); + return single_open(filp, proc_info_vbus_show, bus); +} + +static const struct file_operations proc_info_vbus_fops = { + .open = proc_info_vbus_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static ssize_t uislib_proc_read_writeonly(struct file *file, + char __user *buffer, + size_t count, loff_t *ppos); + +static ssize_t vnic_proc_write(struct file *file, const char __user *buffer, + size_t count, loff_t *ppos); + +static const struct file_operations proc_vnic_fops = { + .read = uislib_proc_read_writeonly, + .write = vnic_proc_write, +}; + +static ssize_t chipset_proc_write(struct file *file, const char __user *buffer, + size_t count, loff_t *ppos); + +static const struct file_operations proc_chipset_fops = { + .read = uislib_proc_read_writeonly, + .write = chipset_proc_write, +}; + +static ssize_t info_proc_read(struct file *file, char __user *buf, + size_t len, loff_t *offset); +static const struct file_operations proc_info_fops = { + .read = info_proc_read, +}; + +static ssize_t platformnumber_proc_read(struct file *file, char __user *buf, + size_t len, loff_t *offset); +static const struct file_operations proc_platformnumber_fops = { + .read = platformnumber_proc_read, +}; + +static ssize_t cycles_before_wait_proc_write(struct file *file, + const char __user *buffer, + size_t count, loff_t *ppos); +static const struct file_operations proc_cycles_before_wait_fops = { + .read = uislib_proc_read_writeonly, + .write = cycles_before_wait_proc_write, +}; + +static ssize_t reset_counts_proc_write(struct file *file, + const char __user *buffer, + size_t count, loff_t *ppos); +static const struct file_operations proc_reset_counts_fops = { + .read = uislib_proc_read_writeonly, + .write = reset_counts_proc_write, +}; + +static ssize_t smart_wakeup_proc_write(struct file *file, + const char __user *buffer, + size_t count, loff_t *ppos); +static const struct file_operations proc_smart_wakeup_fops = { + .read = uislib_proc_read_writeonly, + .write = smart_wakeup_proc_write, +}; + +static ssize_t test_proc_write(struct file *file, + const char __user *buffer, + size_t count, loff_t *ppos); +static const struct file_operations proc_test_fops = { + .read = uislib_proc_read_writeonly, + .write = test_proc_write, +}; + +static ssize_t bus_proc_write(struct file *file, + const char __user *buffer, + size_t count, loff_t *ppos); +static const struct file_operations proc_bus_fops = { + .read = uislib_proc_read_writeonly, + .write = bus_proc_write, +}; + +static ssize_t dev_proc_write(struct file *file, + const char __user *buffer, + size_t count, loff_t *ppos); +static const struct file_operations proc_dev_fops = { + .read = uislib_proc_read_writeonly, + .write = dev_proc_write, +}; + +static void +init_msg_header(CONTROLVM_MESSAGE *msg, U32 id, uint rsp, uint svr) +{ + memset(msg, 0, sizeof(CONTROLVM_MESSAGE)); + msg->hdr.Id = id; + msg->hdr.Flags.responseExpected = rsp; + msg->hdr.Flags.server = svr; +} + +static void +create_bus_proc_entries(struct bus_info *bus) +{ + bus->proc_dir = proc_mkdir(bus->name, uislib_proc_vbus_dir); + if (!bus->proc_dir) { + LOGERR("failed to create /proc/uislib/vbus/%s directory", + bus->name); + return; + } + bus->proc_info = proc_create_data("info", 0, bus->proc_dir, + &proc_info_vbus_fops, bus); + if (!bus->proc_info) { + LOGERR("failed to create /proc/uislib/vbus/%s/info", bus->name); + remove_proc_entry(bus->name, uislib_proc_vbus_dir); + bus->proc_dir = NULL; + return; + } + SET_PROC_OWNER(bus->proc_info, THIS_MODULE); + +} + +static void * +init_vbus_channel(U64 channelAddr, U32 channelBytes, int isServer) +{ + void *rc = NULL; + void *pChan = uislib_ioremap_cache(channelAddr, channelBytes); + if (!pChan) { + LOGERR("CONTROLVM_BUS_CREATE error: ioremap_cache of channelAddr:%Lx for channelBytes:%llu failed", + (unsigned long long) channelAddr, + (unsigned long long) channelBytes); + RETPTR(NULL); + } + if (isServer) { + memset(pChan, 0, channelBytes); + if (!ULTRA_VBUS_CHANNEL_OK_SERVER(channelBytes, NULL)) { + ERRDRV("%s channel cannot be used", __func__); + uislib_iounmap(pChan); + RETPTR(NULL); + } + ULTRA_VBUS_init_channel(pChan, channelBytes); + } else { + if (!ULTRA_VBUS_CHANNEL_OK_CLIENT(pChan, NULL)) { + ERRDRV("%s channel cannot be used", __func__); + uislib_iounmap(pChan); + RETPTR(NULL); + } + } + RETPTR(pChan); +Away: + return rc; +} + +static int +create_bus(CONTROLVM_MESSAGE *msg, char *buf) +{ + U32 busNo, deviceCount; + struct bus_info *tmp, *bus; + size_t size; + + if (MaxBusCount == BusListCount) { + LOGERR("CONTROLVM_BUS_CREATE Failed: max buses:%d already created\n", + MaxBusCount); + POSTCODE_LINUX_3(BUS_CREATE_FAILURE_PC, MaxBusCount, + POSTCODE_SEVERITY_ERR); + return CONTROLVM_RESP_ERROR_MAX_BUSES; + } + + busNo = msg->cmd.createBus.busNo; + deviceCount = msg->cmd.createBus.deviceCount; + + POSTCODE_LINUX_4(BUS_CREATE_ENTRY_PC, busNo, deviceCount, + POSTCODE_SEVERITY_INFO); + + size = + sizeof(struct bus_info) + + (deviceCount * sizeof(struct device_info *)); + bus = UISMALLOC(size, GFP_ATOMIC); + if (!bus) { + LOGERR("CONTROLVM_BUS_CREATE Failed: kmalloc for bus failed.\n"); + POSTCODE_LINUX_3(BUS_CREATE_FAILURE_PC, busNo, + POSTCODE_SEVERITY_ERR); + return CONTROLVM_RESP_ERROR_KMALLOC_FAILED; + } + + memset(bus, 0, size); + + /* Currently by default, the bus Number is the GuestHandle. + * Configure Bus message can override this. + */ + if (msg->hdr.Flags.testMessage) { + /* This implies we're the IOVM so set guest handle to 0... */ + bus->guestHandle = 0; + bus->busNo = busNo; + bus->localVnic = 1; + } else + bus->busNo = bus->guestHandle = busNo; + sprintf(bus->name, "%d", (int) bus->busNo); + bus->deviceCount = deviceCount; + bus->device = + (struct device_info **) ((char *) bus + sizeof(struct bus_info)); + bus->busInstGuid = msg->cmd.createBus.busInstGuid; + bus->busChannelBytes = 0; + bus->pBusChannel = NULL; + + /* add bus to our bus list - but check for duplicates first */ + read_lock(&BusListLock); + for (tmp = BusListHead; tmp; tmp = tmp->next) { + if (tmp->busNo == bus->busNo) + break; + } + read_unlock(&BusListLock); + if (tmp) { + /* found a bus already in the list with same busNo - + * reject add + */ + LOGERR("CONTROLVM_BUS_CREATE Failed: bus %d already exists.\n", + bus->busNo); + POSTCODE_LINUX_3(BUS_CREATE_FAILURE_PC, bus->busNo, + POSTCODE_SEVERITY_ERR); + UISFREE(bus, size); + return CONTROLVM_RESP_ERROR_ALREADY_DONE; + } + if ((msg->cmd.createBus.channelAddr != 0) + && (msg->cmd.createBus.channelBytes != 0)) { + bus->busChannelBytes = msg->cmd.createBus.channelBytes; + bus->pBusChannel = + init_vbus_channel(msg->cmd.createBus.channelAddr, + msg->cmd.createBus.channelBytes, + msg->hdr.Flags.server); + } + /* the msg is bound for virtpci; send guest_msgs struct to callback */ + if (!msg->hdr.Flags.server) { + struct guest_msgs cmd; + cmd.msgtype = GUEST_ADD_VBUS; + cmd.add_vbus.busNo = busNo; + cmd.add_vbus.chanptr = bus->pBusChannel; + cmd.add_vbus.deviceCount = deviceCount; + cmd.add_vbus.busTypeGuid = msg->cmd.createBus.busDataTypeGuid; + cmd.add_vbus.busInstGuid = msg->cmd.createBus.busInstGuid; + if (!VirtControlChanFunc) { + UISFREE(bus, size); + LOGERR("CONTROLVM_BUS_CREATE Failed: virtpci callback not registered."); + POSTCODE_LINUX_3(BUS_CREATE_FAILURE_PC, bus->busNo, + POSTCODE_SEVERITY_ERR); + return CONTROLVM_RESP_ERROR_VIRTPCI_DRIVER_FAILURE; + } + if (!VirtControlChanFunc(&cmd)) { + UISFREE(bus, size); + LOGERR("CONTROLVM_BUS_CREATE Failed: virtpci GUEST_ADD_VBUS returned error."); + POSTCODE_LINUX_3(BUS_CREATE_FAILURE_PC, bus->busNo, + POSTCODE_SEVERITY_ERR); + return + CONTROLVM_RESP_ERROR_VIRTPCI_DRIVER_CALLBACK_ERROR; + } + } + create_bus_proc_entries(bus); + + /* add bus at the head of our list */ + write_lock(&BusListLock); + if (!BusListHead) + BusListHead = bus; + else { + bus->next = BusListHead; + BusListHead = bus; + } + BusListCount++; + write_unlock(&BusListLock); + + POSTCODE_LINUX_3(BUS_CREATE_EXIT_PC, bus->busNo, + POSTCODE_SEVERITY_INFO); + return CONTROLVM_RESP_SUCCESS; +} + +static int +destroy_bus(CONTROLVM_MESSAGE *msg, char *buf) +{ + int i; + struct bus_info *bus, *prev = NULL; + U32 busNo; + + busNo = msg->cmd.destroyBus.busNo; + + /* find and delete the bus */ + read_lock(&BusListLock); + for (bus = BusListHead; bus; prev = bus, bus = bus->next) { + if (bus->busNo == busNo) { + /* found the bus - ensure that all device + * slots are NULL + */ + for (i = 0; i < bus->deviceCount; i++) { + if (bus->device[i] != NULL) { + LOGERR("CONTROLVM_BUS_DESTROY Failed: device %i attached to bus %d.", + i, busNo); + read_unlock(&BusListLock); + return CONTROLVM_RESP_ERROR_BUS_DEVICE_ATTACHED; + } + } + read_unlock(&BusListLock); + /* the msg is bound for virtpci; send + * guest_msgs struct to callback + */ + if (!msg->hdr.Flags.server) { + struct guest_msgs cmd; + cmd.msgtype = GUEST_DEL_VBUS; + cmd.del_vbus.busNo = busNo; + if (!VirtControlChanFunc) { + LOGERR("CONTROLVM_BUS_DESTROY Failed: virtpci callback not registered."); + return CONTROLVM_RESP_ERROR_VIRTPCI_DRIVER_FAILURE; + } + if (!VirtControlChanFunc(&cmd)) { + LOGERR("CONTROLVM_BUS_DESTROY Failed: virtpci GUEST_DEL_VBUS returned error."); + return CONTROLVM_RESP_ERROR_VIRTPCI_DRIVER_CALLBACK_ERROR; + } + } + /* remove the bus from the list */ + write_lock(&BusListLock); + if (prev) /* not at head */ + prev->next = bus->next; + else + BusListHead = bus->next; + BusListCount--; + write_unlock(&BusListLock); + break; + } + } + + if (!bus) { + LOGERR("CONTROLVM_BUS_DESTROY Failed: failed to find bus %d.\n", + busNo); + read_unlock(&BusListLock); + return CONTROLVM_RESP_ERROR_ALREADY_DONE; + } + if (bus->proc_info) { + remove_proc_entry("info", bus->proc_dir); + bus->proc_info = NULL; + } + if (bus->proc_dir) { + remove_proc_entry(bus->name, uislib_proc_vbus_dir); + bus->proc_dir = NULL; + } + if (bus->pBusChannel) { + uislib_iounmap(bus->pBusChannel); + bus->pBusChannel = NULL; + } + + UISFREE(bus, + sizeof(struct bus_info) + + (bus->deviceCount * sizeof(struct device_info *))); + return CONTROLVM_RESP_SUCCESS; +} + +static int +create_device(CONTROLVM_MESSAGE *msg, char *buf) +{ + struct device_info *dev; + struct bus_info *bus; + U32 busNo, devNo; + int result = CONTROLVM_RESP_SUCCESS; + U64 minSize = MIN_IO_CHANNEL_SIZE; + ReqHandlerInfo_t *pReqHandler; + + busNo = msg->cmd.createDevice.busNo; + devNo = msg->cmd.createDevice.devNo; + + POSTCODE_LINUX_4(DEVICE_CREATE_ENTRY_PC, devNo, busNo, + POSTCODE_SEVERITY_INFO); + + dev = UISMALLOC(sizeof(struct device_info), GFP_ATOMIC); + if (!dev) { + LOGERR("CONTROLVM_DEVICE_CREATE Failed: kmalloc for dev failed.\n"); + POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC, devNo, busNo, + POSTCODE_SEVERITY_ERR); + return CONTROLVM_RESP_ERROR_KMALLOC_FAILED; + } + + memset(dev, 0, sizeof(struct device_info)); + dev->channelTypeGuid = msg->cmd.createDevice.dataTypeGuid; + dev->intr = msg->cmd.createDevice.intr; + dev->channelAddr = msg->cmd.createDevice.channelAddr; + dev->busNo = busNo; + dev->devNo = devNo; + sema_init(&dev->interrupt_callback_lock, 1); /* unlocked */ + sprintf(dev->devid, "vbus%u:dev%u", (unsigned) busNo, (unsigned) devNo); + /* map the channel memory for the device. */ + if (msg->hdr.Flags.testMessage) + dev->chanptr = __va(dev->channelAddr); + else { + pReqHandler = ReqHandlerFind(dev->channelTypeGuid); + if (pReqHandler) + /* generic service handler registered for this + * channel + */ + minSize = pReqHandler->min_channel_bytes; + if (minSize > msg->cmd.createDevice.channelBytes) { + LOGERR("CONTROLVM_DEVICE_CREATE Failed: channel size is too small, channel size:0x%lx, required size:0x%lx", + (ulong) msg->cmd.createDevice.channelBytes, + (ulong) minSize); + POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC, devNo, busNo, + POSTCODE_SEVERITY_ERR); + result = CONTROLVM_RESP_ERROR_CHANNEL_SIZE_TOO_SMALL; + goto Away; + } + dev->chanptr = + uislib_ioremap_cache(dev->channelAddr, + msg->cmd.createDevice.channelBytes); + if (!dev->chanptr) { + LOGERR("CONTROLVM_DEVICE_CREATE Failed: ioremap_cache of channelAddr:%Lx for channelBytes:%llu failed", + dev->channelAddr, + msg->cmd.createDevice.channelBytes); + result = CONTROLVM_RESP_ERROR_IOREMAP_FAILED; + POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC, devNo, busNo, + POSTCODE_SEVERITY_ERR); + goto Away; + } + } + dev->devInstGuid = msg->cmd.createDevice.devInstGuid; + dev->channelBytes = msg->cmd.createDevice.channelBytes; + + read_lock(&BusListLock); + for (bus = BusListHead; bus; bus = bus->next) { + if (bus->busNo == busNo) { + /* make sure the device number is valid */ + if (devNo >= bus->deviceCount) { + LOGERR("CONTROLVM_DEVICE_CREATE Failed: device (%d) >= deviceCount (%d).", + devNo, bus->deviceCount); + result = CONTROLVM_RESP_ERROR_MAX_DEVICES; + POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC, + devNo, busNo, + POSTCODE_SEVERITY_ERR); + read_unlock(&BusListLock); + goto Away; + } + /* make sure this device is not already set */ + if (bus->device[devNo]) { + LOGERR("CONTROLVM_DEVICE_CREATE Failed: device %d is already exists.", + devNo); + POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC, + devNo, busNo, + POSTCODE_SEVERITY_ERR); + result = CONTROLVM_RESP_ERROR_ALREADY_DONE; + read_unlock(&BusListLock); + goto Away; + } + read_unlock(&BusListLock); + /* the msg is bound for virtpci; send + * guest_msgs struct to callback + */ + if (!msg->hdr.Flags.server) { + struct guest_msgs cmd; + if (!memcmp + (&dev->channelTypeGuid, + &UltraVhbaChannelProtocolGuid, + sizeof(GUID))) { + WAIT_FOR_VALID_GUID(((CHANNEL_HEADER + *) (dev-> + chanptr))-> + Type); + if (!ULTRA_VHBA_CHANNEL_OK_CLIENT + (dev->chanptr, NULL)) { + LOGERR("CONTROLVM_DEVICE_CREATE Failed:[CLIENT]VHBA dev %d chan invalid.", + devNo); + POSTCODE_LINUX_4 + (DEVICE_CREATE_FAILURE_PC, + devNo, busNo, + POSTCODE_SEVERITY_ERR); + result = CONTROLVM_RESP_ERROR_CHANNEL_INVALID; + goto Away; + } + cmd.msgtype = GUEST_ADD_VHBA; + cmd.add_vhba.chanptr = dev->chanptr; + cmd.add_vhba.busNo = busNo; + cmd.add_vhba.deviceNo = devNo; + cmd.add_vhba.devInstGuid = + dev->devInstGuid; + cmd.add_vhba.intr = dev->intr; + } else + if (!memcmp + (&dev->channelTypeGuid, + &UltraVnicChannelProtocolGuid, + sizeof(GUID))) { + WAIT_FOR_VALID_GUID(((CHANNEL_HEADER + *) (dev-> + chanptr))-> + Type); + if (!ULTRA_VNIC_CHANNEL_OK_CLIENT + (dev->chanptr, NULL)) { + LOGERR("CONTROLVM_DEVICE_CREATE Failed: VNIC[CLIENT] dev %d chan invalid.", + devNo); + POSTCODE_LINUX_4 + (DEVICE_CREATE_FAILURE_PC, + devNo, busNo, + POSTCODE_SEVERITY_ERR); + result = CONTROLVM_RESP_ERROR_CHANNEL_INVALID; + goto Away; + } + cmd.msgtype = GUEST_ADD_VNIC; + cmd.add_vnic.chanptr = dev->chanptr; + cmd.add_vnic.busNo = busNo; + cmd.add_vnic.deviceNo = devNo; + cmd.add_vnic.devInstGuid = + dev->devInstGuid; + cmd.add_vhba.intr = dev->intr; + } else { + LOGERR("CONTROLVM_DEVICE_CREATE Failed: unknown channelTypeGuid.\n"); + POSTCODE_LINUX_4 + (DEVICE_CREATE_FAILURE_PC, devNo, + busNo, POSTCODE_SEVERITY_ERR); + result = CONTROLVM_RESP_ERROR_CHANNEL_TYPE_UNKNOWN; + goto Away; + } + + if (!VirtControlChanFunc) { + LOGERR("CONTROLVM_DEVICE_CREATE Failed: virtpci callback not registered."); + POSTCODE_LINUX_4 + (DEVICE_CREATE_FAILURE_PC, devNo, + busNo, POSTCODE_SEVERITY_ERR); + result = CONTROLVM_RESP_ERROR_VIRTPCI_DRIVER_FAILURE; + goto Away; + } + + if (!VirtControlChanFunc(&cmd)) { + LOGERR("CONTROLVM_DEVICE_CREATE Failed: virtpci GUEST_ADD_[VHBA||VNIC] returned error."); + POSTCODE_LINUX_4 + (DEVICE_CREATE_FAILURE_PC, devNo, + busNo, POSTCODE_SEVERITY_ERR); + result = CONTROLVM_RESP_ERROR_VIRTPCI_DRIVER_CALLBACK_ERROR; + goto Away; + } + } + bus->device[devNo] = dev; + POSTCODE_LINUX_4(DEVICE_CREATE_SUCCESS_PC, devNo, busNo, + POSTCODE_SEVERITY_INFO); + return CONTROLVM_RESP_SUCCESS; + } + } + read_unlock(&BusListLock); + + LOGERR("CONTROLVM_DEVICE_CREATE Failed: failed to find bus %d.", busNo); + POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC, devNo, busNo, + POSTCODE_SEVERITY_ERR); + result = CONTROLVM_RESP_ERROR_BUS_INVALID; + +Away: + if (!msg->hdr.Flags.testMessage) { + uislib_iounmap(dev->chanptr); + dev->chanptr = NULL; + } + + UISFREE(dev, sizeof(struct device_info)); + return result; +} + +static int +pause_device(CONTROLVM_MESSAGE *msg) +{ + U32 busNo, devNo; + struct bus_info *bus; + struct device_info *dev; + struct guest_msgs cmd; + + busNo = msg->cmd.deviceChangeState.busNo; + devNo = msg->cmd.deviceChangeState.devNo; + + read_lock(&BusListLock); + for (bus = BusListHead; bus; bus = bus->next) { + if (bus->busNo == busNo) { + /* make sure the device number is valid */ + if (devNo >= bus->deviceCount) { + LOGERR("CONTROLVM_DEVICE_CHANGESTATE:pause Failed: device(%d) >= deviceCount(%d).", + devNo, bus->deviceCount); + read_unlock(&BusListLock); + return CONTROLVM_RESP_ERROR_DEVICE_INVALID; + } + /* make sure this device exists */ + dev = bus->device[devNo]; + if (!dev) { + LOGERR("CONTROLVM_DEVICE_CHANGESTATE:pause Failed: device %d does not exist.", + devNo); + read_unlock(&BusListLock); + return CONTROLVM_RESP_ERROR_ALREADY_DONE; + } + read_unlock(&BusListLock); + /* the msg is bound for virtpci; send + * guest_msgs struct to callback + */ + if (!memcmp + (&dev->channelTypeGuid, + &UltraVhbaChannelProtocolGuid, sizeof(GUID))) { + cmd.msgtype = GUEST_PAUSE_VHBA; + cmd.pause_vhba.chanptr = dev->chanptr; + } else + if (!memcmp + (&dev->channelTypeGuid, + &UltraVnicChannelProtocolGuid, + sizeof(GUID))) { + cmd.msgtype = GUEST_PAUSE_VNIC; + cmd.pause_vnic.chanptr = dev->chanptr; + } else { + LOGERR("CONTROLVM_DEVICE_CHANGESTATE:pause Failed: unknown channelTypeGuid.\n"); + return + CONTROLVM_RESP_ERROR_CHANNEL_TYPE_UNKNOWN; + } + + if (!VirtControlChanFunc) { + LOGERR("CONTROLVM_DEVICE_CHANGESTATE Failed: virtpci callback not registered."); + return + CONTROLVM_RESP_ERROR_VIRTPCI_DRIVER_FAILURE; + } + + if (!VirtControlChanFunc(&cmd)) { + LOGERR("CONTROLVM_DEVICE_CHANGESTATE:pause Failed: virtpci GUEST_PAUSE_[VHBA||VNIC] returned error."); + return CONTROLVM_RESP_ERROR_VIRTPCI_DRIVER_CALLBACK_ERROR; + } + break; + } + } + + if (!bus) { + LOGERR("CONTROLVM_DEVICE_CHANGESTATE:pause Failed: bus %d does not exist", + busNo); + read_unlock(&BusListLock); + return CONTROLVM_RESP_ERROR_BUS_INVALID; + } + + return CONTROLVM_RESP_SUCCESS; +} + +static int +resume_device(CONTROLVM_MESSAGE *msg) +{ + U32 busNo, devNo; + struct bus_info *bus; + struct device_info *dev; + struct guest_msgs cmd; + + busNo = msg->cmd.deviceChangeState.busNo; + devNo = msg->cmd.deviceChangeState.devNo; + + read_lock(&BusListLock); + for (bus = BusListHead; bus; bus = bus->next) { + if (bus->busNo == busNo) { + /* make sure the device number is valid */ + if (devNo >= bus->deviceCount) { + LOGERR("CONTROLVM_DEVICE_CHANGESTATE:resume Failed: device(%d) >= deviceCount(%d).", + devNo, bus->deviceCount); + read_unlock(&BusListLock); + return CONTROLVM_RESP_ERROR_DEVICE_INVALID; + } + /* make sure this device exists */ + dev = bus->device[devNo]; + if (!dev) { + LOGERR("CONTROLVM_DEVICE_CHANGESTATE:resume Failed: device %d does not exist.", + devNo); + read_unlock(&BusListLock); + return CONTROLVM_RESP_ERROR_ALREADY_DONE; + } + read_unlock(&BusListLock); + /* the msg is bound for virtpci; send + * guest_msgs struct to callback + */ + if (!memcmp(&dev->channelTypeGuid, + &UltraVhbaChannelProtocolGuid, + sizeof(GUID))) { + cmd.msgtype = GUEST_RESUME_VHBA; + cmd.resume_vhba.chanptr = dev->chanptr; + } else + if (!memcmp(&dev->channelTypeGuid, + &UltraVnicChannelProtocolGuid, + sizeof(GUID))) { + cmd.msgtype = GUEST_RESUME_VNIC; + cmd.resume_vnic.chanptr = dev->chanptr; + } else { + LOGERR("CONTROLVM_DEVICE_CHANGESTATE:resume Failed: unknown channelTypeGuid.\n"); + return + CONTROLVM_RESP_ERROR_CHANNEL_TYPE_UNKNOWN; + } + + if (!VirtControlChanFunc) { + LOGERR("CONTROLVM_DEVICE_CHANGESTATE Failed: virtpci callback not registered."); + return + CONTROLVM_RESP_ERROR_VIRTPCI_DRIVER_FAILURE; + } + + if (!VirtControlChanFunc(&cmd)) { + LOGERR("CONTROLVM_DEVICE_CHANGESTATE:resume Failed: virtpci GUEST_RESUME_[VHBA||VNIC] returned error."); + return CONTROLVM_RESP_ERROR_VIRTPCI_DRIVER_CALLBACK_ERROR; + } + break; + } + } + + if (!bus) { + LOGERR("CONTROLVM_DEVICE_CHANGESTATE:resume Failed: bus %d does not exist", + busNo); + read_unlock(&BusListLock); + return CONTROLVM_RESP_ERROR_BUS_INVALID; + } + + return CONTROLVM_RESP_SUCCESS; +} + +static int +destroy_device(CONTROLVM_MESSAGE *msg, char *buf) +{ + U32 busNo, devNo; + struct bus_info *bus; + struct device_info *dev; + struct guest_msgs cmd; + + busNo = msg->cmd.destroyDevice.busNo; + devNo = msg->cmd.destroyDevice.devNo; + + read_lock(&BusListLock); + LOGINF("destroy_device called for busNo=%u, devNo=%u", busNo, devNo); + for (bus = BusListHead; bus; bus = bus->next) { + if (bus->busNo == busNo) { + /* make sure the device number is valid */ + if (devNo >= bus->deviceCount) { + LOGERR("CONTROLVM_DEVICE_DESTORY Failed: device(%d) >= deviceCount(%d).", + devNo, bus->deviceCount); + read_unlock(&BusListLock); + return CONTROLVM_RESP_ERROR_DEVICE_INVALID; + } + /* make sure this device exists */ + dev = bus->device[devNo]; + if (!dev) { + LOGERR("CONTROLVM_DEVICE_DESTROY Failed: device %d does not exist.", + devNo); + read_unlock(&BusListLock); + return CONTROLVM_RESP_ERROR_ALREADY_DONE; + } + read_unlock(&BusListLock); + /* the msg is bound for virtpci; send + * guest_msgs struct to callback + */ + if (!memcmp + (&dev->channelTypeGuid, + &UltraVhbaChannelProtocolGuid, sizeof(GUID))) { + cmd.msgtype = GUEST_DEL_VHBA; + cmd.del_vhba.chanptr = dev->chanptr; + } else + if (!memcmp + (&dev->channelTypeGuid, + &UltraVnicChannelProtocolGuid, + sizeof(GUID))) { + cmd.msgtype = GUEST_DEL_VNIC; + cmd.del_vnic.chanptr = dev->chanptr; + } else { + LOGERR("CONTROLVM_DEVICE_DESTROY Failed: unknown channelTypeGuid.\n"); + return + CONTROLVM_RESP_ERROR_CHANNEL_TYPE_UNKNOWN; + } + + if (!VirtControlChanFunc) { + LOGERR("CONTROLVM_DEVICE_DESTORY Failed: virtpci callback not registered."); + return + CONTROLVM_RESP_ERROR_VIRTPCI_DRIVER_FAILURE; + } + + if (!VirtControlChanFunc(&cmd)) { + LOGERR("CONTROLVM_DEVICE_DESTROY Failed: virtpci GUEST_DEL_[VHBA||VNIC] returned error."); + return CONTROLVM_RESP_ERROR_VIRTPCI_DRIVER_CALLBACK_ERROR; + } +/* you must disable channel interrupts BEFORE you unmap the channel, + * because if you unmap first, there may still be some activity going + * on which accesses the channel and you will get a "unable to handle + * kernel paging request" + */ + if (dev->polling) { + LOGINF("calling uislib_disable_channel_interrupts"); + uislib_disable_channel_interrupts(busNo, devNo); + } + /* unmap the channel memory for the device. */ + if (!msg->hdr.Flags.testMessage) { + LOGINF("destroy_device, doing iounmap"); + uislib_iounmap(dev->chanptr); + } + UISFREE(dev, sizeof(struct device_info)); + bus->device[devNo] = NULL; + break; + } + } + + if (!bus) { + LOGERR("CONTROLVM_DEVICE_DESTROY Failed: bus %d does not exist", + busNo); + read_unlock(&BusListLock); + return CONTROLVM_RESP_ERROR_BUS_INVALID; + } + + return CONTROLVM_RESP_SUCCESS; +} + +void +ULTRA_disp_channel_header(CHANNEL_HEADER *x) +{ + LOGINF("Sig=%llx, HdrSz=%lx, Sz=%llx, Feat=%llx, hPart=%llx, Hndl=%llx, ChSpace=%llx, Ver=%lx, PartIdx=%lx\n", + x->Signature, (long unsigned int) x->HeaderSize, x->Size, + x->Features, x->PartitionHandle, x->Handle, x->oChannelSpace, + (long unsigned int) x->VersionId, + (long unsigned int) x->PartitionIndex); + + LOGINF("ClientStr=%lx, CliStBoot=%lx, CmdStCli=%lx, CliStOS=%lx, ChCharistics=%lx, CmdStSrv=%lx, SrvSt=%lx\n", + (long unsigned int) x->oClientString, + (long unsigned int) x->CliStateBoot, + (long unsigned int) x->CmdStateCli, + (long unsigned int) x->CliStateOS, + (long unsigned int) x->ChannelCharacteristics, + (long unsigned int) x->CmdStateSrv, + (long unsigned int) x->SrvState); + +} + +void +ULTRA_disp_channel(ULTRA_IO_CHANNEL_PROTOCOL *x) +{ + ULTRA_disp_channel_header(&x->ChannelHeader); + LOGINF("cmdQ.Type=%lx\n", (long unsigned int) x->cmdQ.Type); + LOGINF("cmdQ.Size=%llx\n", x->cmdQ.Size); + LOGINF("cmdQ.oSignalBase=%llx\n", x->cmdQ.oSignalBase); + LOGINF("cmdQ.SignalSize=%lx\n", (long unsigned int) x->cmdQ.SignalSize); + LOGINF("cmdQ.MaxSignalSlots=%lx\n", + (long unsigned int) x->cmdQ.MaxSignalSlots); + LOGINF("cmdQ.MaxSignals=%lx\n", (long unsigned int) x->cmdQ.MaxSignals); + LOGINF("rspQ.Type=%lx\n", (long unsigned int) x->rspQ.Type); + LOGINF("rspQ.Size=%llx\n", x->rspQ.Size); + LOGINF("rspQ.oSignalBase=%llx\n", x->rspQ.oSignalBase); + LOGINF("rspQ.SignalSize=%lx\n", (long unsigned int) x->rspQ.SignalSize); + LOGINF("rspQ.MaxSignalSlots=%lx\n", + (long unsigned int) x->rspQ.MaxSignalSlots); + LOGINF("rspQ.MaxSignals=%lx\n", (long unsigned int) x->rspQ.MaxSignals); + LOGINF("SIZEOF_CMDRSP=%lx\n", SIZEOF_CMDRSP); + LOGINF("SIZEOF_PROTOCOL=%lx\n", SIZEOF_PROTOCOL); +} + +void +ULTRA_disp_vnic_channel(ULTRA_IO_CHANNEL_PROTOCOL *x) +{ + LOGINF("num_rcv_bufs=%lx\n", (long unsigned int) x->vnic.num_rcv_bufs); + LOGINF("mtu=%lx\n", (long unsigned int) x->vnic.mtu); +} + +static int +init_chipset(CONTROLVM_MESSAGE *msg, char *buf) +{ + POSTCODE_LINUX_2(CHIPSET_INIT_ENTRY_PC, POSTCODE_SEVERITY_INFO); + + MaxBusCount = msg->cmd.initChipset.busCount; + PlatformNumber = msg->cmd.initChipset.platformNumber; + PhysicalDataChan = 0; + + /* We need to make sure we have our functions registered + * before processing messages. If we are a test vehicle the + * testMessage for init_chipset will be set. We can ignore the + * waits for the callbacks, since this will be manually entered + * from a user. If no testMessage is set, we will wait for the + * functions. + */ + if (!msg->hdr.Flags.testMessage) + WAIT_ON_CALLBACK(VirtControlChanFunc); + + chipset_inited = 1; + POSTCODE_LINUX_2(CHIPSET_INIT_EXIT_PC, POSTCODE_SEVERITY_INFO); + + return CONTROLVM_RESP_SUCCESS; +} + +static int +stop_chipset(CONTROLVM_MESSAGE *msg, char *buf) +{ + /* Check that all buses and switches have been torn down and + * destroyed. + */ + if (BusListHead) { + /* Buses still exist. */ + LOGERR("CONTROLVM_CHIPSET_STOP: BusListHead is not NULL"); + return CONTROLVM_RESP_ERROR_CHIPSET_STOP_FAILED_BUS; + } + if (BusListCount) { + /* BusListHead is NULL, but BusListCount != 0 */ + LOGERR("CONTROLVM_CHIPSET_STOP: BusListCount != 0"); + return CONTROLVM_RESP_ERROR_CHIPSET_STOP_FAILED_BUS; + } + + /* Buses are shut down. */ + return visorchipset_chipset_notready(); +} + +static int +delete_bus_glue(U32 busNo) +{ + CONTROLVM_MESSAGE msg; + + init_msg_header(&msg, CONTROLVM_BUS_DESTROY, 0, 0); + msg.cmd.destroyBus.busNo = busNo; + if (destroy_bus(&msg, NULL) != CONTROLVM_RESP_SUCCESS) { + LOGERR("destroy_bus failed. busNo=0x%x\n", busNo); + return 0; + } + return 1; +} + +static int +delete_device_glue(U32 busNo, U32 devNo) +{ + CONTROLVM_MESSAGE msg; + + init_msg_header(&msg, CONTROLVM_DEVICE_DESTROY, 0, 0); + msg.cmd.destroyDevice.busNo = busNo; + msg.cmd.destroyDevice.devNo = devNo; + if (destroy_device(&msg, NULL) != CONTROLVM_RESP_SUCCESS) { + LOGERR("destroy_device failed. busNo=0x%x devNo=0x%x\n", busNo, + devNo); + return 0; + } + return 1; +} + +int +uislib_client_inject_add_bus(U32 busNo, GUID instGuid, + U64 channelAddr, ulong nChannelBytes) +{ + CONTROLVM_MESSAGE msg; + + LOGINF("enter busNo=0x%x\n", busNo); + /* step 0: init the chipset */ + POSTCODE_LINUX_3(CHIPSET_INIT_ENTRY_PC, busNo, POSTCODE_SEVERITY_INFO); + + if (!chipset_inited) { + /* step: initialize the chipset */ + init_msg_header(&msg, CONTROLVM_CHIPSET_INIT, 0, 0); + /* this change is needed so that console will come up + * OK even when the bus 0 create comes in late. If the + * bus 0 create is the first create, then the add_vnic + * will work fine, but if the bus 0 create arrives + * after number 4, then the add_vnic will fail, and the + * ultraboot will fail. + */ + msg.cmd.initChipset.busCount = 23; + msg.cmd.initChipset.switchCount = 0; + if (init_chipset(&msg, NULL) != CONTROLVM_RESP_SUCCESS) { + LOGERR("init_chipset failed.\n"); + return 0; + } + LOGINF("chipset initialized\n"); + POSTCODE_LINUX_3(CHIPSET_INIT_EXIT_PC, busNo, + POSTCODE_SEVERITY_INFO); + } + + /* step 1: create a bus */ + POSTCODE_LINUX_3(BUS_CREATE_ENTRY_PC, busNo, POSTCODE_SEVERITY_WARNING); + init_msg_header(&msg, CONTROLVM_BUS_CREATE, 0, 0); + msg.cmd.createBus.busNo = busNo; + msg.cmd.createBus.deviceCount = 23; /* devNo+1; */ + msg.cmd.createBus.channelAddr = channelAddr; + msg.cmd.createBus.channelBytes = nChannelBytes; + if (create_bus(&msg, NULL) != CONTROLVM_RESP_SUCCESS) { + LOGERR("create_bus failed.\n"); + POSTCODE_LINUX_3(BUS_CREATE_FAILURE_PC, busNo, + POSTCODE_SEVERITY_ERR); + return 0; + } + POSTCODE_LINUX_3(BUS_CREATE_EXIT_PC, busNo, POSTCODE_SEVERITY_INFO); + + return 1; +} +EXPORT_SYMBOL_GPL(uislib_client_inject_add_bus); + + +int +uislib_client_inject_del_bus(U32 busNo) +{ + return delete_bus_glue(busNo); +} +EXPORT_SYMBOL_GPL(uislib_client_inject_del_bus); + +int +uislib_client_inject_pause_vhba(U32 busNo, U32 devNo) +{ + CONTROLVM_MESSAGE msg; + int rc; + + init_msg_header(&msg, CONTROLVM_DEVICE_CHANGESTATE, 0, 0); + msg.cmd.deviceChangeState.busNo = busNo; + msg.cmd.deviceChangeState.devNo = devNo; + msg.cmd.deviceChangeState.state = SegmentStateStandby; + rc = pause_device(&msg); + if (rc != CONTROLVM_RESP_SUCCESS) { + LOGERR("VHBA pause_device failed. busNo=0x%x devNo=0x%x\n", + busNo, devNo); + return rc; + } + return 0; +} +EXPORT_SYMBOL_GPL(uislib_client_inject_pause_vhba); + +int +uislib_client_inject_resume_vhba(U32 busNo, U32 devNo) +{ + CONTROLVM_MESSAGE msg; + int rc; + + init_msg_header(&msg, CONTROLVM_DEVICE_CHANGESTATE, 0, 0); + msg.cmd.deviceChangeState.busNo = busNo; + msg.cmd.deviceChangeState.devNo = devNo; + msg.cmd.deviceChangeState.state = SegmentStateRunning; + rc = resume_device(&msg); + if (rc != CONTROLVM_RESP_SUCCESS) { + LOGERR("VHBA resume_device failed. busNo=0x%x devNo=0x%x\n", + busNo, devNo); + return rc; + } + return 0; + +} +EXPORT_SYMBOL_GPL(uislib_client_inject_resume_vhba); + +int +uislib_client_inject_add_vhba(U32 busNo, U32 devNo, + U64 phys_chan_addr, U32 chan_bytes, + int is_test_addr, GUID instGuid, + struct InterruptInfo *intr) +{ + CONTROLVM_MESSAGE msg; + + LOGINF(" enter busNo=0x%x devNo=0x%x\n", busNo, devNo); + /* chipset init'ed with bus bus has been previously created - + * Verify it still exists step 2: create the VHBA device on the + * bus + */ + POSTCODE_LINUX_4(VHBA_CREATE_ENTRY_PC, devNo, busNo, + POSTCODE_SEVERITY_INFO); + + init_msg_header(&msg, CONTROLVM_DEVICE_CREATE, 0, 0); + if (is_test_addr) + /* signify that the physical channel address does NOT + * need to be ioremap()ed + */ + msg.hdr.Flags.testMessage = 1; + msg.cmd.createDevice.busNo = busNo; + msg.cmd.createDevice.devNo = devNo; + msg.cmd.createDevice.devInstGuid = instGuid; + if (intr) + msg.cmd.createDevice.intr = *intr; + else + memset(&msg.cmd.createDevice.intr, 0, + sizeof(struct InterruptInfo)); + msg.cmd.createDevice.channelAddr = phys_chan_addr; + if (chan_bytes < MIN_IO_CHANNEL_SIZE) { + LOGERR("wrong channel size.chan_bytes = 0x%x IO_CHANNEL_SIZE= 0x%x\n", + chan_bytes, (unsigned int) MIN_IO_CHANNEL_SIZE); + POSTCODE_LINUX_4(VHBA_CREATE_FAILURE_PC, chan_bytes, + MIN_IO_CHANNEL_SIZE, POSTCODE_SEVERITY_ERR); + return 0; + } + msg.cmd.createDevice.channelBytes = chan_bytes; + msg.cmd.createDevice.dataTypeGuid = UltraVhbaChannelProtocolGuid; + if (create_device(&msg, NULL) != CONTROLVM_RESP_SUCCESS) { + LOGERR("VHBA create_device failed.\n"); + POSTCODE_LINUX_4(VHBA_CREATE_FAILURE_PC, devNo, busNo, + POSTCODE_SEVERITY_ERR); + return 0; + } + POSTCODE_LINUX_4(VHBA_CREATE_SUCCESS_PC, devNo, busNo, + POSTCODE_SEVERITY_INFO); + return 1; +} +EXPORT_SYMBOL_GPL(uislib_client_inject_add_vhba); + +int +uislib_client_inject_del_vhba(U32 busNo, U32 devNo) +{ + return delete_device_glue(busNo, devNo); +} +EXPORT_SYMBOL_GPL(uislib_client_inject_del_vhba); + +int +uislib_client_inject_add_vnic(U32 busNo, U32 devNo, + U64 phys_chan_addr, U32 chan_bytes, + int is_test_addr, GUID instGuid, + struct InterruptInfo *intr) +{ + CONTROLVM_MESSAGE msg; + + LOGINF(" enter busNo=0x%x devNo=0x%x\n", busNo, devNo); + /* chipset init'ed with bus bus has been previously created - + * Verify it still exists step 2: create the VNIC device on the + * bus + */ + POSTCODE_LINUX_4(VNIC_CREATE_ENTRY_PC, devNo, busNo, + POSTCODE_SEVERITY_INFO); + + init_msg_header(&msg, CONTROLVM_DEVICE_CREATE, 0, 0); + if (is_test_addr) + /* signify that the physical channel address does NOT + * need to be ioremap()ed + */ + msg.hdr.Flags.testMessage = 1; + msg.cmd.createDevice.busNo = busNo; + msg.cmd.createDevice.devNo = devNo; + msg.cmd.createDevice.devInstGuid = instGuid; + if (intr) + msg.cmd.createDevice.intr = *intr; + else + memset(&msg.cmd.createDevice.intr, 0, + sizeof(struct InterruptInfo)); + msg.cmd.createDevice.channelAddr = phys_chan_addr; + if (chan_bytes < MIN_IO_CHANNEL_SIZE) { + LOGERR("wrong channel size.chan_bytes = 0x%x IO_CHANNEL_SIZE= 0x%x\n", + chan_bytes, (unsigned int) MIN_IO_CHANNEL_SIZE); + POSTCODE_LINUX_4(VNIC_CREATE_FAILURE_PC, chan_bytes, + MIN_IO_CHANNEL_SIZE, POSTCODE_SEVERITY_ERR); + return 0; + } + msg.cmd.createDevice.channelBytes = chan_bytes; + msg.cmd.createDevice.dataTypeGuid = UltraVnicChannelProtocolGuid; + if (create_device(&msg, NULL) != CONTROLVM_RESP_SUCCESS) { + LOGERR("VNIC create_device failed.\n"); + POSTCODE_LINUX_4(VNIC_CREATE_FAILURE_PC, devNo, busNo, + POSTCODE_SEVERITY_ERR); + return 0; + } + + POSTCODE_LINUX_4(VNIC_CREATE_SUCCESS_PC, devNo, busNo, + POSTCODE_SEVERITY_INFO); + return 1; +} +EXPORT_SYMBOL_GPL(uislib_client_inject_add_vnic); + +int +uislib_client_inject_pause_vnic(U32 busNo, U32 devNo) +{ + CONTROLVM_MESSAGE msg; + int rc; + + init_msg_header(&msg, CONTROLVM_DEVICE_CHANGESTATE, 0, 0); + msg.cmd.deviceChangeState.busNo = busNo; + msg.cmd.deviceChangeState.devNo = devNo; + msg.cmd.deviceChangeState.state = SegmentStateStandby; + rc = pause_device(&msg); + if (rc != CONTROLVM_RESP_SUCCESS) { + LOGERR("VNIC pause_device failed. busNo=0x%x devNo=0x%x\n", + busNo, devNo); + return -1; + } + return 0; +} +EXPORT_SYMBOL_GPL(uislib_client_inject_pause_vnic); + +int +uislib_client_inject_resume_vnic(U32 busNo, U32 devNo) +{ + CONTROLVM_MESSAGE msg; + int rc; + + init_msg_header(&msg, CONTROLVM_DEVICE_CHANGESTATE, 0, 0); + msg.cmd.deviceChangeState.busNo = busNo; + msg.cmd.deviceChangeState.devNo = devNo; + msg.cmd.deviceChangeState.state = SegmentStateRunning; + rc = resume_device(&msg); + if (rc != CONTROLVM_RESP_SUCCESS) { + LOGERR("VNIC resume_device failed. busNo=0x%x devNo=0x%x\n", + busNo, devNo); + return -1; + } + return 0; + +} +EXPORT_SYMBOL_GPL(uislib_client_inject_resume_vnic); + +int +uislib_client_inject_del_vnic(U32 busNo, U32 devNo) +{ + return delete_device_glue(busNo, devNo); +} +EXPORT_SYMBOL_GPL(uislib_client_inject_del_vnic); + +int +uislib_client_add_vnic(U32 busNo) +{ + BOOL busCreated = FALSE; + int devNo = 0; /* Default to 0, since only one device + * will be created for this bus... */ + GUID dummyGuid = GUID0; + CONTROLVM_MESSAGE msg; + + init_msg_header(&msg, CONTROLVM_BUS_CREATE, 0, 0); + msg.hdr.Flags.testMessage = 1; + msg.cmd.createBus.busNo = busNo; + msg.cmd.createBus.deviceCount = 4; + msg.cmd.createBus.channelAddr = 0; + msg.cmd.createBus.channelBytes = 0; + if (create_bus(&msg, NULL) != CONTROLVM_RESP_SUCCESS) { + LOGERR("client create_bus failed"); + return 0; + } + busCreated = TRUE; + + init_msg_header(&msg, CONTROLVM_DEVICE_CREATE, 0, 0); + msg.hdr.Flags.testMessage = 1; + msg.cmd.createDevice.busNo = busNo; + msg.cmd.createDevice.devNo = devNo; + msg.cmd.createDevice.devInstGuid = dummyGuid; + memset(&msg.cmd.createDevice.intr, 0, sizeof(struct InterruptInfo)); + msg.cmd.createDevice.channelAddr = PhysicalDataChan; + msg.cmd.createDevice.channelBytes = MIN_IO_CHANNEL_SIZE; + msg.cmd.createDevice.dataTypeGuid = UltraVnicChannelProtocolGuid; + if (create_device(&msg, NULL) != CONTROLVM_RESP_SUCCESS) { + LOGERR("client create_device failed"); + goto AwayCleanup; + } + + return 1; + +AwayCleanup: + if (busCreated) { + init_msg_header(&msg, CONTROLVM_BUS_DESTROY, 0, 0); + msg.hdr.Flags.testMessage = 1; + msg.cmd.destroyBus.busNo = busNo; + if (destroy_bus(&msg, NULL) != CONTROLVM_RESP_SUCCESS) + LOGERR("client destroy_bus failed.\n"); + } + + return 0; +} /* end uislib_client_add_vnic */ +EXPORT_SYMBOL_GPL(uislib_client_add_vnic); + +int +uislib_client_delete_vnic(U32 busNo) +{ + int devNo = 0; /* Default to 0, since only one device + * will be created for this bus... */ + CONTROLVM_MESSAGE msg; + + init_msg_header(&msg, CONTROLVM_DEVICE_DESTROY, 0, 0); + msg.hdr.Flags.testMessage = 1; + msg.cmd.destroyDevice.busNo = busNo; + msg.cmd.destroyDevice.devNo = devNo; + if (destroy_device(&msg, NULL) != CONTROLVM_RESP_SUCCESS) { + /* Don't error exit - try to see if bus can be destroyed... */ + LOGERR("client destroy_device failed.\n"); + } + + init_msg_header(&msg, CONTROLVM_BUS_DESTROY, 0, 0); + msg.hdr.Flags.testMessage = 1; + msg.cmd.destroyBus.busNo = busNo; + if (destroy_bus(&msg, NULL) != CONTROLVM_RESP_SUCCESS) + LOGERR("client destroy_bus failed.\n"); + + return 1; +} +EXPORT_SYMBOL_GPL(uislib_client_delete_vnic); + + /* end client_delete_vnic */ + +static atomic_t Malloc_BytesInUse = ATOMIC_INIT(0); +static atomic_t Malloc_BuffersInUse = ATOMIC_INIT(0); +static atomic_t Malloc_FailuresAlloc = ATOMIC_INIT(0); +static atomic_t Malloc_FailuresFree = ATOMIC_INIT(0); +static atomic_t Malloc_TotalMallocs = ATOMIC_INIT(0); +static atomic_t Malloc_TotalFrees = ATOMIC_INIT(0); + +void * +uislib_malloc(size_t siz, gfp_t gfp, U8 contiguous, char *fn, int ln) +{ + void *p = NULL; + + if (contiguous == 0) { + /* Allocate non-contiguous memory, such as in the + * add_vnic and add_vhba methods where we are rebooting + * the guest, for example. Otherwise the contiguous + * memory allocation attempt results in an + * out-of-memory crash in the IOVM... + */ + p = vmalloc(siz); + } else { + /* __GFP_NORETRY means "ok to fail", meaning kmalloc() + * can return NULL. If you do NOT specify + * __GFP_NORETRY, Linux will go to extreme measures to + * get memory for you (like, invoke oom killer), which + * will probably cripple the system. + */ + p = kmalloc(siz, gfp | __GFP_NORETRY); + } + if (p == NULL) { + LOGERR("uislib_malloc failed to alloc %d bytes @%s:%d", + (int) siz, fn, ln); + atomic_inc(&Malloc_FailuresAlloc); + return NULL; + } + atomic_add((int) (siz), &Malloc_BytesInUse); + atomic_inc(&Malloc_BuffersInUse); + atomic_inc(&Malloc_TotalMallocs); /* will eventually overflow */ + return p; +} +EXPORT_SYMBOL_GPL(uislib_malloc); + +void +uislib_free(void *p, size_t siz, U8 contiguous, char *fn, int ln) +{ + if (p == NULL) { + LOGERR("uislib_free NULL pointer @%s:%d", fn, ln); + atomic_inc(&Malloc_FailuresFree); + return; + } + + if (contiguous == 0) + vfree(p); + else + kfree(p); + atomic_sub((int) (siz), &Malloc_BytesInUse); + atomic_dec(&Malloc_BuffersInUse); + atomic_inc(&Malloc_TotalFrees); /* will eventually overflow */ +} +EXPORT_SYMBOL_GPL(uislib_free); + +void * +uislib_cache_alloc(struct kmem_cache *cur_pool, char *fn, int ln) +{ + /* __GFP_NORETRY means "ok to fail", meaning kmalloc() can + * return NULL. If you do NOT specify __GFP_NORETRY, Linux + * will go to extreme measures to get memory for you (like, + * invoke oom killer), which will probably cripple the system. + */ + void *p = kmem_cache_alloc(cur_pool, GFP_ATOMIC | __GFP_NORETRY); + if (p == NULL) { + LOGERR("uislib_malloc failed to alloc uiscmdrsp @%s:%d", + fn, ln); + return NULL; + } + return p; +} +EXPORT_SYMBOL_GPL(uislib_cache_alloc); + +void +uislib_cache_free(struct kmem_cache *cur_pool, void *p, char *fn, int ln) +{ + if (p == NULL) { + LOGERR("uislib_free NULL pointer @%s:%d", fn, ln); + return; + } + kmem_cache_free(cur_pool, p); +} +EXPORT_SYMBOL_GPL(uislib_cache_free); + +/*****************************************************/ +/* proc filesystem callback functions */ +/*****************************************************/ + +static ssize_t +vnic_proc_write(struct file *file, const char __user *buffer, + size_t count, loff_t *ppos) +{ + int action = 0xffff, busNo = 0, i, result = 0; + char buf[count]; + char direction; +/* GUID guid; */ + if (copy_from_user(buf, buffer, count)) { + LOGERR("echo > /proc/uislib/vnic copy_from_user ****FAILED.\n"); + return -EFAULT; + } + + i = sscanf(buf, "%d%c", &action, &direction); + if (i != 2) { + LOGERR("unable to parse vnic proc parameters.\n"); + return -EFAULT; + } + + if ((direction != '-') && (direction != '+')) { + LOGERR("unable to determine whether to add or delete vnic\n"); + return -EFAULT; + } + + /* if (i < 1), i.e., if we didn't even read the action field, + * then action will default to 0xffff and the code below will + * fall through the switch and print usage. + */ + switch (action) { + case 0: + /* call client method... */ + busNo = 0; /* All client drivers use bus value of 0... */ + if (direction == '+') + result = uislib_client_add_vnic(busNo); + else + result = uislib_client_delete_vnic(busNo); + if (!result) { + LOGERR("echo 0%c > /proc/uislib/vnic failed (client end)", + direction); + return -EFAULT; + } + return count; + + default: + break; + } + + LOGERR("USAGE: echo <action><direction (up/down)> > /proc/uislib/vnic"); + LOGERR(" "); + LOGERR("Client Syntax"); + LOGERR("-------------"); + LOGERR("0+ ==> add vnic"); + LOGERR("0- ==> delete vnic"); + LOGERR(" "); + return count; +} /* end vnic_proc_write */ + +static ssize_t +chipset_proc_write(struct file *file, const char __user *buffer, + size_t count, loff_t *ppos) +{ + int i, action = 0xffff; + char buf[count]; + CONTROLVM_MESSAGE msg; + + memset(&msg, 0, sizeof(CONTROLVM_MESSAGE)); + + if (copy_from_user(buf, buffer, count)) { + LOGERR("copy_from_user ****FAILED.\n"); + return -EFAULT; + } + + if (chipset_inited) { + LOGINF("Chipset already initialized\n"); + return -EFAULT; + } + i = sscanf(buf, "%x", &action); + + /* if (i < 1), i.e., if we didn't even read the action field, + * then action will default to 0xffff and the code below will + * fall through the switch and print usage. + */ + switch (action) { + case 1: + /* GUEST */ + /* step: initialize the chipset */ + init_msg_header(&msg, CONTROLVM_CHIPSET_INIT, 0, 0); + msg.hdr.Flags.testMessage = 0; + msg.cmd.initChipset.busCount = 23; + msg.cmd.initChipset.switchCount = 23; + + if (init_chipset(&msg, NULL) != CONTROLVM_RESP_SUCCESS) { + LOGERR("init_chipset failed.\n"); + return 0; + } + return 1; + case 2: + /* BOTH */ + init_msg_header(&msg, CONTROLVM_CHIPSET_INIT, 0, 0); + msg.hdr.Flags.testMessage = 1; + msg.cmd.initChipset.busCount = 23; + msg.cmd.initChipset.switchCount = 23; + + if (init_chipset(&msg, NULL) != CONTROLVM_RESP_SUCCESS) { + LOGERR("init_chipset failed.\n"); + return 0; + } + return 1; + + default: + break; + } + + LOGERR("usage: 1 ==> init_chipset client\n"); + LOGERR("usage: 2 ==> init_chipset test\n"); + return -EFAULT; +} + +#define PROCLINE(...) \ + do { \ + if (util_add_proc_line_ex(&tot, buff, \ + buff_len, __VA_ARGS__) < 0) { \ + goto err_done; \ + } \ + } while (0) + +static int +info_proc_read_helper(char **buff, int *buff_len) +{ + int i, tot = 0; + struct bus_info *bus; + + PROCLINE("\nBuses:\n"); + + read_lock(&BusListLock); + for (bus = BusListHead; bus; bus = bus->next) { + + PROCLINE(" bus=0x%p, busNo=%d, deviceCount=%d\n", + bus, bus->busNo, bus->deviceCount); + + PROCLINE(" Devices:\n"); + + for (i = 0; i < bus->deviceCount; i++) { + if (bus->device[i]) { + PROCLINE(" busNo %d, device[%i]: 0x%p, chanptr=0x%p, swtch=0x%p\n", + bus->busNo, i, bus->device[i], + bus->device[i]->chanptr, + bus->device[i]->swtch); + PROCLINE(" first_busy_cnt=%llu, moved_to_tail_cnt=%llu, last_on_list_cnt=%llu\n", + bus->device[i]->first_busy_cnt, + bus->device[i]->moved_to_tail_cnt, + bus->device[i]->last_on_list_cnt); + } + } + } + read_unlock(&BusListLock); + + PROCLINE("Malloc bytes in use: %d\n", atomic_read(&Malloc_BytesInUse)); + PROCLINE("Malloc buffers in use: %d\n", + atomic_read(&Malloc_BuffersInUse)); + PROCLINE("Malloc allocation failures: %d\n", + atomic_read(&Malloc_FailuresAlloc)); + PROCLINE("Malloc free failures: %d\n", + atomic_read(&Malloc_FailuresFree)); + PROCLINE("Malloc total mallocs: %u (may overflow)\n", + (unsigned) atomic_read(&Malloc_TotalMallocs)); + PROCLINE("Malloc total frees: %u (may overflow)\n", + (unsigned) atomic_read(&Malloc_TotalFrees)); + PROCLINE("UisUtils_Registered_Services: %d\n", + atomic_read(&UisUtils_Registered_Services)); + + PROCLINE("cycles_before_wait %llu wait_cycles:%llu\n", + cycles_before_wait, wait_cycles); + PROCLINE("tot_wakeup_cnt %llu:tot_wait_cnt %llu:tot_schedule_cnt %llu\n", + tot_wakeup_cnt, tot_wait_cnt, tot_schedule_cnt); + PROCLINE("en_smart_wakeup %d\n", en_smart_wakeup); + PROCLINE("tot_moved_to_tail_cnt %llu\n", tot_moved_to_tail_cnt); + + return tot; +err_done: + + return -1; +} + +static ssize_t +info_proc_read(struct file *file, char __user *buf, size_t len, loff_t *offset) +{ + char *temp; + int totalBytes = 0; + int remaining_bytes = PROC_READ_BUFFER_SIZE; + +/* *start = buf; */ + if (ProcReadBuffer == NULL) { + DBGINF("ProcReadBuffer == NULL; allocating buffer.\n."); + ProcReadBuffer = UISVMALLOC(PROC_READ_BUFFER_SIZE); + + if (ProcReadBuffer == NULL) { + LOGERR("failed to allocate buffer to provide proc data.\n"); + return -ENOMEM; + } + } + + temp = ProcReadBuffer; + + if ((*offset == 0) || (!ProcReadBufferValid)) { + DBGINF("calling info_proc_read_helper.\n"); + /* if the read fails, then -1 will be returned */ + totalBytes = info_proc_read_helper(&temp, &remaining_bytes); + ProcReadBufferValid = 1; + } else + totalBytes = strlen(ProcReadBuffer); + + return simple_read_from_buffer(buf, len, offset, + ProcReadBuffer, totalBytes); +} + +static ssize_t +platformnumber_proc_read(struct file *file, char __user *buf, + size_t len, loff_t *offset) +{ + int length = 0; + char *vbuf; + loff_t pos = *offset; + + if (pos < 0) + return -EINVAL; + + if (pos > 0 || !len) + return 0; + + vbuf = kzalloc(len, GFP_KERNEL); + if (!vbuf) + return -ENOMEM; + + length = sprintf(vbuf, "%d\n", PlatformNumber); + + if (copy_to_user(buf, vbuf, length)) { + kfree(vbuf); + return -EFAULT; + } + + kfree(vbuf); + *offset += length; + return length; +} + +#ifdef UISLIB_TEST_PROC + +/* proc/uislib/vbus/<x>/info */ +static int +proc_info_vbus_show(struct seq_file *m, void *v) +{ + struct bus_info *bus = m->private; + int i, devInfoCount, x; + char buf[999]; + + if (bus == NULL) + return 0; + seq_printf(m, "Client device / client driver info for %s partition (vbus #%d):\n", + bus->partitionName, bus->busNo); + if ((bus->busChannelBytes == 0) || (bus->pBusChannel == NULL)) + return 0; + devInfoCount = + (bus->busChannelBytes - + sizeof(ULTRA_VBUS_CHANNEL_PROTOCOL)) / + sizeof(ULTRA_VBUS_DEVICEINFO); + x = VBUSCHANNEL_devInfoToStringBuffer(bus->pBusChannel->ChpInfo, buf, + sizeof(buf) - 1, -1); + buf[x] = '\0'; + seq_printf(m, "%s", buf); + x = VBUSCHANNEL_devInfoToStringBuffer(bus->pBusChannel->BusInfo, + buf, sizeof(buf) - 1, -1); + buf[x] = '\0'; + seq_printf(m, "%s", buf); + for (i = 0; i < devInfoCount; i++) { + x = VBUSCHANNEL_devInfoToStringBuffer(bus->pBusChannel-> + DevInfo[i], buf, + sizeof(buf) - 1, i); + if (x > 0) { + buf[x] = '\0'; + seq_printf(m, "%s", buf); + } + } + return 0; +} + +static ssize_t +bus_proc_write(struct file *file, const char __user *buffer, + size_t count, loff_t *ppos) +{ + int server_flag = 0; + int i, action = 0xffff, result; + char buf[count]; + CONTROLVM_MESSAGE msg; + U32 busNo, deviceCount; + + memset(&msg, 0, sizeof(CONTROLVM_MESSAGE)); + + if (copy_from_user(buf, buffer, count)) { + LOGERR("echo > /proc/uislib/bus: copy_from_user ****FAILED."); + return -EFAULT; + } + + i = sscanf(buf, "%x-%d-%d", &action, &busNo, &deviceCount); + + /* if (i < 1), i.e., if we didn't even read the action field, + * then action will default to 0xffff and the code below will + * fall through the switch and print usage. + */ + switch (action) { + case 0: + /* destroy a bus */ + if (i != 2) + break; + init_msg_header(&msg, CONTROLVM_BUS_DESTROY, 0, server_flag); + msg.cmd.destroyBus.busNo = busNo; + + result = destroy_bus(&msg, NULL); + + if (result != CONTROLVM_RESP_SUCCESS) { + LOGERR("echo 0-%d > /proc/uislib/bus {CONTROLVM_BUS_DESTROY Failed} Result(%d)", + busNo, result); + return -EFAULT; + } + return count; + case 1: + /* create a bus */ + if (i != 3) + break; + init_msg_header(&msg, CONTROLVM_BUS_CREATE, 0, server_flag); + msg.cmd.createBus.busNo = busNo; + msg.cmd.createBus.deviceCount = deviceCount; + + result = create_bus(&msg, NULL); + + if (result != CONTROLVM_RESP_SUCCESS) { + LOGERR("echo 1-%d-%d > /proc/uislib/bus {CONTROLVM_BUS_CREATE Failed} Result(%d)", + busNo, deviceCount, result); + return -EFAULT; + } + + return count; + default: + break; + } + + LOGERR("USAGE: echo <action>-<busNo>... > /proc/uislib/bus"); + LOGERR(" "); + LOGERR("Destruct Syntax ControlVM Message Id"); + LOGERR("--------------- ---------------------"); + LOGERR("0-<busNo> ==> CONTROLVM_BUS_DESTROY"); + LOGERR(" "); + LOGERR("Construct Syntax ControlVM Message Id"); + LOGERR("----------------------- -------------------- "); + LOGERR("1-<busNo>-<deviceCount> ==> CONTROLVM_BUS_CREATE"); + + return -EFAULT; +} + +static ssize_t +uislib_proc_read_writeonly(struct file *file, char __user *buffer, + size_t count, loff_t *ppos) +{ + return 0; +} + +static ssize_t +dev_proc_write(struct file *file, const char __user *buffer, + size_t count, loff_t *ppos) +{ + int server_flag = 0; + CONTROLVM_MESSAGE msg; + U32 busNo, devNo; + char buf[count]; + unsigned int chanptr; + int type, i, action = 0xffff, result; + + if (copy_from_user(buf, buffer, count)) { + LOGERR("echo > /proc/uislib/device: copy_from_user ****FAILED."); + return -EFAULT; + } + + i = sscanf(buf, "%x-%d-%d-%x-%d", + &action, &busNo, &devNo, &chanptr, &type); + + switch (action) { + case 0: + if (i != 3) + break; + + /* destroy a device */ + init_msg_header(&msg, CONTROLVM_DEVICE_DESTROY, 0, server_flag); + msg.cmd.destroyDevice.busNo = busNo; + msg.cmd.destroyDevice.devNo = devNo; + + result = destroy_device(&msg, NULL); + + if (result != CONTROLVM_RESP_SUCCESS) { + LOGERR("echo 0-%d-%d > /proc/uislib/device {CONTROLVM_DEVICE_DESTROY Failed} Result(%d)", + busNo, devNo, result); + return -EFAULT; + } + + return count; + + case 1: + if (i != 5) + break; + + /* create a device */ + init_msg_header(&msg, CONTROLVM_DEVICE_CREATE, 0, server_flag); + msg.cmd.createDevice.busNo = busNo; + msg.cmd.createDevice.devNo = devNo; + msg.cmd.createDevice.channelAddr = __pa(chanptr); + msg.cmd.createDevice.channelBytes = MIN_IO_CHANNEL_SIZE; + + if (type == 0) + msg.cmd.createDevice.dataTypeGuid = + UltraVhbaChannelProtocolGuid; + else if (type == 1) + msg.cmd.createDevice.dataTypeGuid = + UltraVnicChannelProtocolGuid; + else { + LOGERR("echo 1-%d-%d-%x-<type> > /proc/uislib/devce failed: invalid device type %d.", + busNo, devNo, chanptr, type); + return -EFAULT; + } + + result = create_device(&msg, NULL); + + if (result != CONTROLVM_RESP_SUCCESS) { + if (type == 0) + LOGERR("echo 1-%d-%d-%x-0 > /proc/uislib/device {CONTROLVM_DEVICE_CREATE[vHBA] Failed} Result(%d)", + busNo, devNo, chanptr, result); + else + LOGERR("echo 1-%d-%d-%x-1 > /proc/uislib/device {CONTROLVM_DEVICE_CREATE[vNIC] Failed} Result(%d)", + busNo, devNo, chanptr, result); + return -EFAULT; + } + + default: + break; + } + + LOGERR("USAGE: echo <action>-<busNo>-<devNo>... > /proc/uislib/device"); + LOGERR(" "); + LOGERR("Destruct Syntax ControlVM Message Id"); + LOGERR("----------------- ------------------------"); + LOGERR("0-<busNo>-<devNo> ==> CONTROLVM_DEVICE_DESTROY"); + LOGERR(" "); + LOGERR("Construct Syntax ControlVM Message Id"); + LOGERR + ("---------------------------------- ----------------------- "); + LOGERR + ("1-<busNo>-<devNo>-<chanptr>-<type> ==> CONTROLVM_DEVICE_CREATE"); + LOGERR(" <type = 0>: vHBA"); + LOGERR(" <type = 1>: vNIC"); + LOGERR(" "); + + return -EFAULT; +} + +static ssize_t +cycles_before_wait_proc_write(struct file *file, const char __user *buffer, + size_t count, loff_t *ppos) +{ + char buf[count]; + +#define CYCLES_BEFORE_WAIT_USE_ERROR { \ + LOGERR("Incorrect Call Home Input.\n"); \ + pr_info("Please pass Call Home Event Parameters in the form:\n"); \ + pr_info("EventID Category Type[parameter1][parameter2][parameter3][parameter4][parameter5][parameter6]\n"); \ + return -EFAULT; \ +} + + if (count == 0) + CYCLES_BEFORE_WAIT_USE_ERROR; + + if (copy_from_user(buf, buffer, count)) { + LOGERR("copy_from_user failed.\n"); + return -EFAULT; + } + buf[count - 1] = '\0'; /* Replace the LF at the end of the + * input with a NULL */ + /* Pull out the cycles_before_wait must be decimal integer */ + if (sscanf(buf, "%lld", &cycles_before_wait) != 1) + CYCLES_BEFORE_WAIT_USE_ERROR; + + return count; +} + +static ssize_t +reset_counts_proc_write(struct file *file, const char __user *buffer, + size_t count, loff_t *ppos) +{ + char buf[count]; + unsigned long long new_value; + struct bus_info *bus; + int i; + +#define RESET_COUNTS_USE_ERROR { \ + LOGERR("Incorrect reset_counts Input.\n"); \ + pr_info("Please pass the new value for the counters:\n"); \ + pr_info("e.g. echo 0 > reset_counts\n"); \ + return -EFAULT; \ + } + + if (count == 0) + RESET_COUNTS_USE_ERROR; + + if (copy_from_user(buf, buffer, count)) { + LOGERR("copy_from_user failed.\n"); + return -EFAULT; + } + buf[count - 1] = '\0'; /* Replace the LF at the end of the + * input with a NULL */ + /* Pull out the reset_counts must be decimal integer */ + if (sscanf(buf, "%llu", &new_value) != 1) + RESET_COUNTS_USE_ERROR; + read_lock(&BusListLock); + for (bus = BusListHead; bus; bus = bus->next) { + + for (i = 0; i < bus->deviceCount; i++) { + if (bus->device[i]) { + bus->device[i]->first_busy_cnt = new_value; + bus->device[i]->moved_to_tail_cnt = new_value; + bus->device[i]->last_on_list_cnt = new_value; + } + } + } + read_unlock(&BusListLock); + tot_moved_to_tail_cnt = new_value; + tot_wait_cnt = new_value; + tot_wakeup_cnt = new_value; + tot_schedule_cnt = new_value; + return count; +} + +static ssize_t +smart_wakeup_proc_write(struct file *file, const char __user *buffer, + size_t count, loff_t *ppos) +{ + char buf[count]; + int new_value; + +#define SMART_WAKEUP_USE_ERROR { \ + LOGERR("Incorrect smart_wakeup Input 0 disables smart_wakeup, and 1 enables smart_wakeup.\n"); \ + pr_info("echo 0 > smart_wakeup\n"); \ + pr_info("echo 1 > smart_wakeup\n"); \ + return -EFAULT; \ + } + + if (count == 0) + SMART_WAKEUP_USE_ERROR; + + if (copy_from_user(buf, buffer, count)) { + LOGERR("copy_from_user failed.\n"); + return -EFAULT; + } + buf[count - 1] = '\0'; /* Replace the LF at the end of the + * input with a NULL */ + /* Pull out the smart_wakeup must be decimal integer */ + if (sscanf(buf, "%d", &new_value) != 1) + SMART_WAKEUP_USE_ERROR; + en_smart_wakeup = new_value; + return count; +} + +static ssize_t +test_proc_write(struct file *file, const char __user *buffer, + size_t count, loff_t *ppos) +{ + int i, action = 0xffff; + char buf[count]; + CONTROLVM_MESSAGE msg; + S64 vrtc_offset; + + memset(&msg, 0, sizeof(CONTROLVM_MESSAGE)); + + if (copy_from_user(buf, buffer, count)) { + LOGERR("copy_from_user ****FAILED.\n"); + return -EFAULT; + } + + i = sscanf(buf, "%x", &action); + + /* if (i < 1), i.e., if we didn't even read the action field, + * then action will default to 0xffff and the code below will + * fall through the switch and print usage. */ + switch (action) { + case 6: + msg.hdr.Id = CONTROLVM_CHIPSET_STOP; + msg.hdr.Flags.responseExpected = 1; + stop_chipset(&msg, NULL); + break; + case 7: + vrtc_offset = 0; + LOGERR("about to issue QUERY vrtc_offset=%LX", vrtc_offset); + vrtc_offset = Issue_VMCALL_QUERY_GUEST_VIRTUAL_TIME_OFFSET(); + LOGERR("result is vrtc_offset=%LX", vrtc_offset); + break; + case 8: + vrtc_offset = 60; + LOGERR("about to increase physical time by 0x%LX seconds", + vrtc_offset); + vrtc_offset = Issue_VMCALL_UPDATE_PHYSICAL_TIME(vrtc_offset); + break; + case 9: + vrtc_offset = -60; + LOGERR("about to decrease physical time by 0x%LX seconds", + vrtc_offset); + vrtc_offset = Issue_VMCALL_UPDATE_PHYSICAL_TIME(vrtc_offset); + break; + default: + LOGERR("usage: 6 for CHIPSET_STOP\n"); + LOGERR(" 7 for VMCALL_QUERY_GUEST_VIRTUAL_TIME_OFFSET()\n"); + LOGERR(" 8 for VMCALL_UPDATE_PHYSICAL_TIME(60)\n"); + LOGERR(" 9 for VMCALL_UPDATE_PHYSICAL_TIME(-60)\n"); + return -EFAULT; + break; + } + return count; +} + +#endif /* UISLIB_TEST_PROC */ +static struct device_info * +find_dev(U32 busNo, U32 devNo) +{ + struct bus_info *bus; + struct device_info *dev = NULL; + + read_lock(&BusListLock); + for (bus = BusListHead; bus; bus = bus->next) { + if (bus->busNo == busNo) { + /* make sure the device number is valid */ + if (devNo >= bus->deviceCount) { + LOGERR("%s bad busNo, devNo=%d,%d", + __func__, + (int) (busNo), (int) (devNo)); + goto Away; + } + dev = bus->device[devNo]; + if (!dev) + LOGERR("%s bad busNo, devNo=%d,%d", + __func__, + (int) (busNo), (int) (devNo)); + goto Away; + } + } +Away: + read_unlock(&BusListLock); + return dev; +} + +/* This thread calls the "interrupt" function for each device that has + * enabled such using uislib_enable_channel_interrupts(). The "interrupt" + * function typically reads and processes the devices's channel input + * queue. This thread repeatedly does this, until the thread is told to stop + * (via uisthread_stop()). Sleeping rules: + * - If we have called the "interrupt" function for all devices, and all of + * them have reported "nothing processed" (returned 0), then we will go to + * sleep for a maximum of POLLJIFFIES_NORMAL jiffies. + * - If anyone calls uislib_force_channel_interrupt(), the above jiffy + * sleep will be interrupted, and we will resume calling the "interrupt" + * function for all devices. + * - The list of devices is dynamically re-ordered in order to + * attempt to preserve fairness. Whenever we spin thru the list of + * devices and call the dev->interrupt() function, if we find + * devices which report that there is still more work to do, the + * the first such device we find is moved to the end of the device + * list. This ensures that extremely busy devices don't starve out + * less-busy ones. + * + */ +static int +Process_Incoming(void *v) +{ + unsigned long long cur_cycles, old_cycles, idle_cycles, delta_cycles; + struct list_head *new_tail = NULL; + int i; + UIS_DAEMONIZE("dev_incoming"); + for (i = 0; i < 16; i++) { + old_cycles = get_cycles(); + wait_event_timeout(Wakeup_Polling_Device_Channels, + 0, POLLJIFFIES_NORMAL); + cur_cycles = get_cycles(); + if (wait_cycles == 0) { + wait_cycles = (cur_cycles - old_cycles); + } else { + if (wait_cycles < (cur_cycles - old_cycles)) + wait_cycles = (cur_cycles - old_cycles); + } + } + LOGINF("wait_cycles=%llu", wait_cycles); + cycles_before_wait = wait_cycles; + idle_cycles = 0; + Go_Polling_Device_Channels = 0; + while (1) { + struct list_head *lelt, *tmp; + struct device_info *dev = NULL; + + /* poll each channel for input */ + LOCKSEM_UNINTERRUPTIBLE(&Lock_Polling_Device_Channels); + new_tail = NULL; + list_for_each_safe(lelt, tmp, &List_Polling_Device_Channels) { + int rc = 0; + dev = list_entry(lelt, struct device_info, + list_polling_device_channels); + LOCKSEM_UNINTERRUPTIBLE(&dev->interrupt_callback_lock); + if (dev->interrupt) + rc = dev->interrupt(dev->interrupt_context); + else + continue; + UNLOCKSEM(&dev->interrupt_callback_lock); + if (rc) { + /* dev->interrupt returned, but there + * is still more work to do. + * Reschedule work to occur as soon as + * possible. */ + idle_cycles = 0; + if (new_tail == NULL) { + dev->first_busy_cnt++; + if (! + (list_is_last + (lelt, + &List_Polling_Device_Channels))) { + new_tail = lelt; + dev->moved_to_tail_cnt++; + } else + dev->last_on_list_cnt++; + } + + } + if (Incoming_ThreadInfo.should_stop) + break; + } + if (new_tail != NULL) { + tot_moved_to_tail_cnt++; + list_move_tail(new_tail, &List_Polling_Device_Channels); + } + UNLOCKSEM(&Lock_Polling_Device_Channels); + cur_cycles = get_cycles(); + delta_cycles = cur_cycles - old_cycles; + old_cycles = cur_cycles; + + /* At this point, we have scanned thru all of the + * channels, and at least one of the following is true: + * - there is no input waiting on any of the channels + * - we have received a signal to stop this thread + */ + if (Incoming_ThreadInfo.should_stop) + break; + if (en_smart_wakeup == 0xFF) { + LOGINF("en_smart_wakeup set to 0xff, to force exiting process_incoming"); + break; + } + /* wait for POLLJIFFIES_NORMAL jiffies, or until + * someone wakes up Wakeup_Polling_Device_Channels, + * whichever comes first only do a wait when we have + * been idle for cycles_before_wait cycles. + */ + if (idle_cycles > cycles_before_wait) { + Go_Polling_Device_Channels = 0; + tot_wait_cnt++; + wait_event_timeout(Wakeup_Polling_Device_Channels, + Go_Polling_Device_Channels, + POLLJIFFIES_NORMAL); + Go_Polling_Device_Channels = 1; + } else { + tot_schedule_cnt++; + schedule(); + idle_cycles = idle_cycles + delta_cycles; + } + } + DBGINF("exiting.\n"); + complete_and_exit(&Incoming_ThreadInfo.has_stopped, 0); +} + +static BOOL +Initialize_incoming_thread(void) +{ + if (Incoming_Thread_Started) + return TRUE; + if (!uisthread_start(&Incoming_ThreadInfo, + &Process_Incoming, NULL, "dev_incoming")) { + LOGERR("uisthread_start Initialize_incoming_thread ****FAILED"); + return FALSE; + } + Incoming_Thread_Started = TRUE; + return TRUE; +} + +/* Add a new device/channel to the list being processed by + * Process_Incoming(). + * <interrupt> - indicates the function to call periodically. + * <interrupt_context> - indicates the data to pass to the <interrupt> + * function. + */ +void +uislib_enable_channel_interrupts(U32 busNo, U32 devNo, + int (*interrupt)(void *), + void *interrupt_context) +{ + struct device_info *dev; + dev = find_dev(busNo, devNo); + if (!dev) { + LOGERR("%s busNo=%d, devNo=%d", __func__, (int) (busNo), + (int) (devNo)); + return; + } + LOCKSEM_UNINTERRUPTIBLE(&Lock_Polling_Device_Channels); + Initialize_incoming_thread(); + dev->interrupt = interrupt; + dev->interrupt_context = interrupt_context; + dev->polling = TRUE; + list_add_tail(&(dev->list_polling_device_channels), + &List_Polling_Device_Channels); + UNLOCKSEM(&Lock_Polling_Device_Channels); +} +EXPORT_SYMBOL_GPL(uislib_enable_channel_interrupts); + +/* Remove a device/channel from the list being processed by + * Process_Incoming(). + */ +void +uislib_disable_channel_interrupts(U32 busNo, U32 devNo) +{ + struct device_info *dev; + dev = find_dev(busNo, devNo); + if (!dev) { + LOGERR("%s busNo=%d, devNo=%d", __func__, (int) (busNo), + (int) (devNo)); + return; + } + LOCKSEM_UNINTERRUPTIBLE(&Lock_Polling_Device_Channels); + list_del(&dev->list_polling_device_channels); + dev->polling = FALSE; + dev->interrupt = NULL; + UNLOCKSEM(&Lock_Polling_Device_Channels); +} +EXPORT_SYMBOL_GPL(uislib_disable_channel_interrupts); + +static void +do_wakeup_polling_device_channels(struct work_struct *dummy) +{ + if (!Go_Polling_Device_Channels) { + Go_Polling_Device_Channels = 1; + wake_up(&Wakeup_Polling_Device_Channels); + } +} + +DECLARE_WORK(Work_wakeup_polling_device_channels, + do_wakeup_polling_device_channels); + +/* Call this function when you want to send a hint to Process_Incoming() that + * your device might have more requests. + */ +void +uislib_force_channel_interrupt(U32 busNo, U32 devNo) +{ + if (en_smart_wakeup == 0) + return; + if (Go_Polling_Device_Channels) + return; + /* The point of using schedule_work() instead of just doing + * the work inline is to force a slight delay before waking up + * the Process_Incoming() thread. + */ + tot_wakeup_cnt++; + schedule_work(&Work_wakeup_polling_device_channels); +} +EXPORT_SYMBOL_GPL(uislib_force_channel_interrupt); + +/*****************************************************/ +/* Module Init & Exit functions */ +/*****************************************************/ + +static int __init +uislib_mod_init(void) +{ + + LOGINF("MONITORAPIS"); + + LOGINF("sizeof(struct uiscmdrsp):%lu bytes\n", + (ulong) sizeof(struct uiscmdrsp)); + LOGINF("sizeof(struct phys_info):%lu\n", + (ulong) sizeof(struct phys_info)); + LOGINF("sizeof(uiscmdrsp_scsi):%lu\n", + (ulong) sizeof(struct uiscmdrsp_scsi)); + LOGINF("sizeof(uiscmdrsp_net):%lu\n", + (ulong) sizeof(struct uiscmdrsp_net)); + LOGINF("sizeof(CONTROLVM_MESSAGE):%lu bytes\n", + (ulong) sizeof(CONTROLVM_MESSAGE)); + LOGINF("sizeof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL):%lu bytes\n", + (ulong) sizeof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL)); + LOGINF("sizeof(CHANNEL_HEADER):%lu bytes\n", + (ulong) sizeof(CHANNEL_HEADER)); + LOGINF("sizeof(ULTRA_IO_CHANNEL_PROTOCOL):%lu bytes\n", + (ulong) sizeof(ULTRA_IO_CHANNEL_PROTOCOL)); + LOGINF("SIZEOF_CMDRSP:%lu bytes\n", SIZEOF_CMDRSP); + LOGINF("SIZEOF_PROTOCOL:%lu bytes\n", SIZEOF_PROTOCOL); + + /* initialize global pointers to NULL */ + BusListHead = NULL; + BusListCount = MaxBusCount = 0; + rwlock_init(&BusListLock); + VirtControlChanFunc = NULL; + + /* Issue VMCALL_GET_CONTROLVM_ADDR to get CtrlChanPhysAddr and + * then map this physical address to a virtual address. */ + POSTCODE_LINUX_2(DRIVER_ENTRY_PC, POSTCODE_SEVERITY_INFO); + + /* create the proc entries for the channels */ + uislib_proc_dir = proc_mkdir(DIR_PROC_ENTRY, NULL); + /* (e.g., for /proc/uislib/vbus/<x>/info) */ + uislib_proc_vbus_dir = proc_mkdir(DIR_VBUS_PROC_ENTRY, uislib_proc_dir); + + vnic_proc_entry = proc_create(VNIC_PROC_ENTRY_FN, 0, uislib_proc_dir, + &proc_vnic_fops); + SET_PROC_OWNER(vnic_proc_entry, THIS_MODULE); + + /* for testing purposes only, create the proc entries for + * enqueuing Control Channel messages */ + chipset_proc_entry = + proc_create(CHIPSET_PROC_ENTRY_FN, 0, uislib_proc_dir, + &proc_chipset_fops); + SET_PROC_OWNER(chipset_proc_entry, THIS_MODULE); + + info_proc_entry = proc_create(INFO_PROC_ENTRY_FN, 0, uislib_proc_dir, + &proc_info_fops); + SET_PROC_OWNER(info_proc_entry, THIS_MODULE); + + platformnumber_proc_entry = + proc_create(PLATFORMNUMBER_PROC_ENTRY_FN, 0, uislib_proc_dir, + &proc_platformnumber_fops); + SET_PROC_OWNER(platformnumberinfo_proc_entry, THIS_MODULE); + + cycles_before_wait_proc_entry = + proc_create(CYCLES_BEFORE_WAIT_PROC_ENTRY_FN, 0, uislib_proc_dir, + &proc_cycles_before_wait_fops); + SET_PROC_OWNER(cycles_before_wait_proc_entry, THIS_MODULE); + + reset_counts_proc_entry = + proc_create(RESET_COUNTS_PROC_ENTRY_FN, 0, uislib_proc_dir, + &proc_reset_counts_fops); + SET_PROC_OWNER(reset_counts_proc_entry, THIS_MODULE); + + smart_wakeup_proc_entry = + proc_create(SMART_WAKEUP_PROC_ENTRY_FN, 0, uislib_proc_dir, + &proc_smart_wakeup_fops); + SET_PROC_OWNER(smart_wakeup_proc_entry, THIS_MODULE); + +#ifdef UISLIB_TEST_PROC + test_proc_entry = proc_create(TEST_PROC_ENTRY_FN, 0, uislib_proc_dir, + &proc_test_fops); + SET_PROC_OWNER(test_proc_entry, THIS_MODULE); + + bus_proc_entry = proc_create(BUS_PROC_ENTRY_FN, 0, uislib_proc_dir, + &proc_bus_fops); + SET_PROC_OWNER(bus_proc_entry, THIS_MODULE); + + dev_proc_entry = proc_create(DEV_PROC_ENTRY_FN, 0, uislib_proc_dir, + &proc_dev_fops); + SET_PROC_OWNER(dev_proc_entry, THIS_MODULE); +#endif /* UISLIB_TEST_PROC */ + POSTCODE_LINUX_3(DRIVER_EXIT_PC, 0, POSTCODE_SEVERITY_INFO); + return 0; +} + +static void __exit +uislib_mod_exit(void) +{ + if (disable_proc_entry) + remove_proc_entry(DISABLE_PROC_ENTRY_FN, uislib_proc_dir); + if (cycles_before_wait_proc_entry) + remove_proc_entry(CYCLES_BEFORE_WAIT_PROC_ENTRY_FN, + uislib_proc_dir); + if (reset_counts_proc_entry) + remove_proc_entry(RESET_COUNTS_PROC_ENTRY_FN, uislib_proc_dir); + if (smart_wakeup_proc_entry) + remove_proc_entry(SMART_WAKEUP_PROC_ENTRY_FN, uislib_proc_dir); + if (ctrlchan_proc_entry) + remove_proc_entry(CTRLCHAN_PROC_ENTRY_FN, uislib_proc_dir); + if (pmem_proc_entry) + remove_proc_entry(PMEM_PROC_ENTRY_FN, uislib_proc_dir); + if (info_proc_entry) + remove_proc_entry(INFO_PROC_ENTRY_FN, uislib_proc_dir); + if (switch_proc_entry) + remove_proc_entry(SWITCH_PROC_ENTRY_FN, uislib_proc_dir); + if (extport_proc_entry) + remove_proc_entry(EXTPORT_PROC_ENTRY_FN, uislib_proc_dir); + if (platformnumber_proc_entry) + remove_proc_entry(PLATFORMNUMBER_PROC_ENTRY_FN, + uislib_proc_dir); + if (bus_proc_entry) + remove_proc_entry(BUS_PROC_ENTRY_FN, uislib_proc_dir); + if (dev_proc_entry) + remove_proc_entry(DEV_PROC_ENTRY_FN, uislib_proc_dir); + if (vnic_proc_entry) + remove_proc_entry(VNIC_PROC_ENTRY_FN, uislib_proc_dir); + if (chipset_proc_entry) + remove_proc_entry(CHIPSET_PROC_ENTRY_FN, uislib_proc_dir); + if (uislib_proc_vbus_dir) + remove_proc_entry(DIR_VBUS_PROC_ENTRY, uislib_proc_dir); + if (uislib_proc_dir) + remove_proc_entry(DIR_PROC_ENTRY, NULL); + + if (ProcReadBuffer) { + UISVFREE(ProcReadBuffer, PROC_READ_BUFFER_SIZE); + ProcReadBuffer = NULL; + } + + DBGINF("goodbye.\n"); + return; +} + +module_init(uislib_mod_init); +module_exit(uislib_mod_exit); + +int uis_mandatory_services = -1; + +module_param_named(mandatory_services, uis_mandatory_services, + int, S_IRUGO); +MODULE_PARM_DESC(uis_mandatory_services, + "number of server drivers we expect to register (default=-1 for legacy behavior)"); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Usha Srinivasan"); +MODULE_ALIAS("uislib"); + /* this is extracted during depmod and kept in modules.dep */ diff --git a/drivers/staging/unisys/uislib/uisqueue.c b/drivers/staging/unisys/uislib/uisqueue.c new file mode 100644 index 00000000000..67e413f748f --- /dev/null +++ b/drivers/staging/unisys/uislib/uisqueue.c @@ -0,0 +1,166 @@ +/* uisqueue.c + * + * Copyright © 2010 - 2013 UNISYS CORPORATION + * 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. + */ + +/* @ALL_INSPECTED */ +#include <linux/kernel.h> +#include <linux/module.h> + +#include "uisutils.h" + +#include "chanstub.h" + +/* this is shorter than using __FILE__ (full path name) in + * debug/info/error messages */ +#define CURRENT_FILE_PC UISLIB_PC_uisqueue_c +#define __MYFILE__ "uisqueue.c" + +#define RETVOID do { goto Away; } while (0) +#define RETINT(x) do { rc = (x); goto Away; } while (0) +#define RETPTR(x) do { rc = (x); goto Away; } while (0) +#define RETBOOL(x) do { rc = (x); goto Away; } while (0) + +#define CHECK_CACHE_ALIGN 0 + +/*****************************************************/ +/* Exported functions */ +/*****************************************************/ +unsigned long long +uisqueue_InterlockedOr(volatile unsigned long long *Target, + unsigned long long Set) +{ + unsigned long long i; + unsigned long long j; + + j = *Target; + do { + i = j; + j = uislibcmpxchg64((unsigned long long *) Target, + i, i | Set, sizeof(*(Target))); + + } while (i != j); + + return j; +} +EXPORT_SYMBOL_GPL(uisqueue_InterlockedOr); + +unsigned long long +uisqueue_InterlockedAnd(volatile unsigned long long *Target, + unsigned long long Set) +{ + unsigned long long i; + unsigned long long j; + + j = *Target; + do { + i = j; + j = uislibcmpxchg64((unsigned long long *) Target, + i, i & Set, sizeof(*(Target))); + + } while (i != j); + + return j; +} +EXPORT_SYMBOL_GPL(uisqueue_InterlockedAnd); + +static U8 +do_locked_client_insert(struct uisqueue_info *queueinfo, + unsigned int whichqueue, + void *pSignal, + spinlock_t *lock, + unsigned char issueInterruptIfEmpty, + U64 interruptHandle, U8 *channelId) +{ + unsigned long flags; + unsigned char queueWasEmpty; + unsigned int locked = 0; + unsigned int acquired = 0; + U8 rc = 0; + + spin_lock_irqsave(lock, flags); + locked = 1; + + if (!ULTRA_CHANNEL_CLIENT_ACQUIRE_OS(queueinfo->chan, channelId, NULL)) + RETINT(0); + + acquired = 1; + + queueWasEmpty = SignalQueueIsEmpty(queueinfo->chan, whichqueue); + if (!SignalInsert(queueinfo->chan, whichqueue, pSignal)) + RETINT(0); + ULTRA_CHANNEL_CLIENT_RELEASE_OS(queueinfo->chan, channelId, NULL); + acquired = 0; + spin_unlock_irqrestore(lock, flags); + locked = 0; + + queueinfo->packets_sent++; + + RETINT(1); + +Away: + if (acquired) { + ULTRA_CHANNEL_CLIENT_RELEASE_OS(queueinfo->chan, channelId, + NULL); + acquired = 0; + } + if (locked) { + spin_unlock_irqrestore((spinlock_t *) lock, flags); + locked = 0; + } + + return rc; +} + +int +uisqueue_put_cmdrsp_with_lock_client(struct uisqueue_info *queueinfo, + struct uiscmdrsp *cmdrsp, + unsigned int whichqueue, + void *insertlock, + unsigned char issueInterruptIfEmpty, + U64 interruptHandle, + char oktowait, U8 *channelId) +{ + while (!do_locked_client_insert(queueinfo, whichqueue, cmdrsp, + (spinlock_t *) insertlock, + issueInterruptIfEmpty, + interruptHandle, channelId)) { + if (oktowait != OK_TO_WAIT) { + LOGERR("****FAILED SignalInsert failed; cannot wait; insert aborted\n"); + return 0; /* failed to queue */ + } + /* try again */ + LOGERR("****FAILED SignalInsert failed; waiting to try again\n"); + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(msecs_to_jiffies(10)); + } + return 1; +} +EXPORT_SYMBOL_GPL(uisqueue_put_cmdrsp_with_lock_client); + +/* uisqueue_get_cmdrsp gets the cmdrsp entry at the head of the queue + * returns NULL if queue is empty */ +int +uisqueue_get_cmdrsp(struct uisqueue_info *queueinfo, + void *cmdrsp, unsigned int whichqueue) +{ + if (!SignalRemove(queueinfo->chan, whichqueue, cmdrsp)) + return 0; + + queueinfo->packets_received++; + + return 1; /* Success */ +} +EXPORT_SYMBOL_GPL(uisqueue_get_cmdrsp); diff --git a/drivers/staging/unisys/uislib/uisthread.c b/drivers/staging/unisys/uislib/uisthread.c new file mode 100644 index 00000000000..ecf4bfcb34a --- /dev/null +++ b/drivers/staging/unisys/uislib/uisthread.c @@ -0,0 +1,85 @@ +/* uisthread.c + * + * Copyright © 2010 - 2013 UNISYS CORPORATION + * 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. + */ + +/* @ALL_INSPECTED */ +#include <asm/processor.h> +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/kthread.h> +#include "uniklog.h" +#include "uisutils.h" +#include "uisthread.h" + +#define KILL(a, b, c) kill_pid(find_vpid(a), b, c) + +/* this is shorter than using __FILE__ (full path name) in + * debug/info/error messages + */ +#define CURRENT_FILE_PC UISLIB_PC_uisthread_c +#define __MYFILE__ "uisthread.c" + +/*****************************************************/ +/* Exported functions */ +/*****************************************************/ + +/* returns 0 for failure, 1 for success */ +int +uisthread_start(struct uisthread_info *thrinfo, + int (*threadfn)(void *), void *thrcontext, char *name) +{ + thrinfo->should_stop = 0; + /* used to stop the thread */ + init_completion(&thrinfo->has_stopped); + thrinfo->task = kthread_create(threadfn, thrcontext, name, NULL); + if (thrinfo->task == NULL) { + thrinfo->id = 0; + return 0; /* failure */ + } + thrinfo->id = thrinfo->task->pid; + wake_up_process(thrinfo->task); + LOGINF("started thread pid:%d\n", thrinfo->id); + return 1; + +} +EXPORT_SYMBOL_GPL(uisthread_start); + +void +uisthread_stop(struct uisthread_info *thrinfo) +{ + int ret; + int stopped = 0; + if (thrinfo->id == 0) + return; /* thread not running */ + + LOGINF("uisthread_stop stopping id:%d\n", thrinfo->id); + thrinfo->should_stop = 1; + ret = KILL(thrinfo->id, SIGHUP, 1); + if (ret) { + LOGERR("unable to signal thread %d\n", ret); + } else { + /* give up if the thread has NOT died in 1 minute */ + if (wait_for_completion_timeout(&thrinfo->has_stopped, 60 * HZ)) + stopped = 1; + else + LOGERR("timed out trying to signal thread\n"); + } + if (stopped) { + LOGINF("uisthread_stop stopped id:%d\n", thrinfo->id); + thrinfo->id = 0; + } +} +EXPORT_SYMBOL_GPL(uisthread_stop); diff --git a/drivers/staging/unisys/uislib/uisutils.c b/drivers/staging/unisys/uislib/uisutils.c new file mode 100644 index 00000000000..974f8bc8c68 --- /dev/null +++ b/drivers/staging/unisys/uislib/uisutils.c @@ -0,0 +1,349 @@ +/* uisutils.c + * + * Copyright © 2010 - 2013 UNISYS CORPORATION + * 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. + */ + +#include <linux/string.h> +#include <linux/slab.h> +#include <commontypes.h> +#include <linux/spinlock.h> +#include <linux/list.h> +#include "uniklog.h" +#include "uisutils.h" +#include "version.h" +#include "vbushelper.h" +#include "guidutils.h" +#include <linux/skbuff.h> +#ifdef CONFIG_HIGHMEM +#include <linux/highmem.h> +#endif + +/* this is shorter than using __FILE__ (full path name) in + * debug/info/error messages + */ +#define CURRENT_FILE_PC UISLIB_PC_uisutils_c +#define __MYFILE__ "uisutils.c" + +/* exports */ +atomic_t UisUtils_Registered_Services = ATOMIC_INIT(0); + /* num registrations via + * uisctrl_register_req_handler() or + * uisctrl_register_req_handler_ex() */ + + +/*****************************************************/ +/* Utility functions */ +/*****************************************************/ + +int +util_add_proc_line_ex(int *total, char **buffer, int *buffer_remaining, + char *format, ...) +{ + va_list args; + int len; + + DBGINF("buffer = 0x%p : *buffer = 0x%p.\n", buffer, *buffer); + va_start(args, format); + len = vsnprintf(*buffer, *buffer_remaining, format, args); + if (len >= *buffer_remaining) { + *buffer += *buffer_remaining; + *total += *buffer_remaining; + *buffer_remaining = 0; + LOGERR("bytes remaining is too small!\n"); + return -1; + } + *buffer_remaining -= len; + *buffer += len; + *total += len; + return len; +} +EXPORT_SYMBOL_GPL(util_add_proc_line_ex); + +int +uisctrl_register_req_handler(int type, void *fptr, + ULTRA_VBUS_DEVICEINFO *chipset_DriverInfo) +{ + LOGINF("type = %d, fptr = 0x%p.\n", type, fptr); + + switch (type) { + case 2: + if (fptr) { + if (!VirtControlChanFunc) + atomic_inc(&UisUtils_Registered_Services); + VirtControlChanFunc = fptr; + } else { + if (VirtControlChanFunc) + atomic_dec(&UisUtils_Registered_Services); + VirtControlChanFunc = NULL; + } + break; + + default: + LOGERR("invalid type %d.\n", type); + return 0; + } + if (chipset_DriverInfo) + BusDeviceInfo_Init(chipset_DriverInfo, + "chipset", "uislib", + VERSION, NULL, __DATE__, __TIME__); + + return 1; +} +EXPORT_SYMBOL_GPL(uisctrl_register_req_handler); + +int +uisctrl_register_req_handler_ex(GUID switchTypeGuid, + const char *switch_type_name, + int (*controlfunc)(struct io_msgs *), + unsigned long min_channel_bytes, + int (*Server_Channel_Ok)(unsigned long + channelBytes), + int (*Server_Channel_Init) + (void *x, unsigned char *clientStr, + U32 clientStrLen, U64 bytes), + ULTRA_VBUS_DEVICEINFO *chipset_DriverInfo) +{ + char s[99]; + ReqHandlerInfo_t *pReqHandlerInfo; + int rc = 0; /* assume failure */ + LOGINF("type=%s, controlfunc=0x%p.\n", + GUID_format1(&switchTypeGuid, s), controlfunc); + if (!controlfunc) { + LOGERR("%s: controlfunc must be supplied\n", + GUID_format1(&switchTypeGuid, s)); + goto Away; + } + if (!Server_Channel_Ok) { + LOGERR("%s: Server_Channel_Ok must be supplied\n", + GUID_format1(&switchTypeGuid, s)); + goto Away; + } + if (!Server_Channel_Init) { + LOGERR("%s: Server_Channel_Init must be supplied\n", + GUID_format1(&switchTypeGuid, s)); + goto Away; + } + pReqHandlerInfo = ReqHandlerAdd(switchTypeGuid, + switch_type_name, + controlfunc, + min_channel_bytes, + Server_Channel_Ok, Server_Channel_Init); + if (!pReqHandlerInfo) { + LOGERR("failed to add %s to server list\n", + GUID_format1(&switchTypeGuid, s)); + goto Away; + } + + atomic_inc(&UisUtils_Registered_Services); + rc = 1; /* success */ +Away: + if (rc) { + if (chipset_DriverInfo) + BusDeviceInfo_Init(chipset_DriverInfo, + "chipset", "uislib", + VERSION, NULL, + __DATE__, __TIME__); + } else + LOGERR("failed to register type %s.\n", + GUID_format1(&switchTypeGuid, s)); + + return rc; +} +EXPORT_SYMBOL_GPL(uisctrl_register_req_handler_ex); + +int +uisctrl_unregister_req_handler_ex(GUID switchTypeGuid) +{ + char s[99]; + int rc = 0; /* assume failure */ + LOGINF("type=%s.\n", GUID_format1(&switchTypeGuid, s)); + if (ReqHandlerDel(switchTypeGuid) < 0) { + LOGERR("failed to remove %s from server list\n", + GUID_format1(&switchTypeGuid, s)); + goto Away; + } + atomic_dec(&UisUtils_Registered_Services); + rc = 1; /* success */ +Away: + if (!rc) + LOGERR("failed to unregister type %s.\n", + GUID_format1(&switchTypeGuid, s)); + return rc; +} +EXPORT_SYMBOL_GPL(uisctrl_unregister_req_handler_ex); + +/* + * unsigned int util_copy_fragsinfo_from_skb(unsigned char *calling_ctx, + * void *skb_in, + * unsigned int firstfraglen, + * unsigned int frags_max, + * struct phys_info frags[]) + * + * calling_ctx - input - a string that is displayed to show + * who called * this func + * void *skb_in - skb whose frag info we're copying type is hidden so we + * don't need to include skbbuff in uisutils.h which is + * included in non-networking code. + * unsigned int firstfraglen - input - length of first fragment in skb + * unsigned int frags_max - input - max len of frags array + * struct phys_info frags[] - output - frags array filled in on output + * return value indicates number of + * entries filled in frags + */ +unsigned int +util_copy_fragsinfo_from_skb(unsigned char *calling_ctx, void *skb_in, + unsigned int firstfraglen, unsigned int frags_max, + struct phys_info frags[]) +{ + unsigned int count = 0, ii, size, offset = 0, numfrags; + struct sk_buff *skb = skb_in; + + numfrags = skb_shinfo(skb)->nr_frags; + + while (firstfraglen) { + if (count == frags_max) { + LOGERR("%s frags array too small: max:%d count:%d\n", + calling_ctx, frags_max, count); + return -1; /* failure */ + } + frags[count].pi_pfn = + page_to_pfn(virt_to_page(skb->data + offset)); + frags[count].pi_off = + (unsigned long) (skb->data + offset) & PI_PAGE_MASK; + size = + min(firstfraglen, + (unsigned int) (PI_PAGE_SIZE - frags[count].pi_off)); + /* can take smallest of firstfraglen(what's left) OR + * bytes left in the page + */ + frags[count].pi_len = size; + firstfraglen -= size; + offset += size; + count++; + } + if (numfrags) { + if ((count + numfrags) > frags_max) { + LOGERR("**** FAILED %s frags array too small: max:%d count+nr_frags:%d\n", + calling_ctx, frags_max, count + numfrags); + return -1; /* failure */ + } + + for (ii = 0; ii < numfrags; ii++) { + count = add_physinfo_entries(page_to_pfn(skb_frag_page(&skb_shinfo(skb)->frags[ii])), /* pfn */ + skb_shinfo(skb)->frags[ii]. + page_offset, + skb_shinfo(skb)->frags[ii]. + size, count, frags_max, + frags); + if (count == 0) { + LOGERR("**** FAILED to add physinfo entries\n"); + return -1; /* failure */ + } + } + } + if (skb_shinfo(skb)->frag_list) { + struct sk_buff *skbinlist; + int c; + for (skbinlist = skb_shinfo(skb)->frag_list; skbinlist; + skbinlist = skbinlist->next) { + + c = util_copy_fragsinfo_from_skb("recursive", skbinlist, + skbinlist->len - + skbinlist->data_len, + frags_max - count, + &frags[count]); + if (c == -1) { + LOGERR("**** FAILED recursive call failed\n"); + return -1; + } + count += c; + } + } + return count; +} +EXPORT_SYMBOL_GPL(util_copy_fragsinfo_from_skb); + +static LIST_HEAD(ReqHandlerInfo_list); /* list of ReqHandlerInfo_t */ +static DEFINE_SPINLOCK(ReqHandlerInfo_list_lock); + +ReqHandlerInfo_t * +ReqHandlerAdd(GUID switchTypeGuid, + const char *switch_type_name, + int (*controlfunc)(struct io_msgs *), + unsigned long min_channel_bytes, + int (*Server_Channel_Ok)(unsigned long channelBytes), + int (*Server_Channel_Init) + (void *x, unsigned char *clientStr, U32 clientStrLen, U64 bytes)) +{ + ReqHandlerInfo_t *rc = NULL; + + rc = UISMALLOC(sizeof(*rc), GFP_ATOMIC); + if (!rc) + return NULL; + memset(rc, 0, sizeof(*rc)); + rc->switchTypeGuid = switchTypeGuid; + rc->controlfunc = controlfunc; + rc->min_channel_bytes = min_channel_bytes; + rc->Server_Channel_Ok = Server_Channel_Ok; + rc->Server_Channel_Init = Server_Channel_Init; + if (switch_type_name) + strncpy(rc->switch_type_name, switch_type_name, + sizeof(rc->switch_type_name) - 1); + spin_lock(&ReqHandlerInfo_list_lock); + list_add_tail(&(rc->list_link), &ReqHandlerInfo_list); + spin_unlock(&ReqHandlerInfo_list_lock); + + return rc; +} + +ReqHandlerInfo_t * +ReqHandlerFind(GUID switchTypeGuid) +{ + struct list_head *lelt, *tmp; + ReqHandlerInfo_t *entry = NULL; + spin_lock(&ReqHandlerInfo_list_lock); + list_for_each_safe(lelt, tmp, &ReqHandlerInfo_list) { + entry = list_entry(lelt, ReqHandlerInfo_t, list_link); + if (memcmp + (&entry->switchTypeGuid, &switchTypeGuid, + sizeof(GUID)) == 0) { + spin_unlock(&ReqHandlerInfo_list_lock); + return entry; + } + } + spin_unlock(&ReqHandlerInfo_list_lock); + return NULL; +} + +int +ReqHandlerDel(GUID switchTypeGuid) +{ + struct list_head *lelt, *tmp; + ReqHandlerInfo_t *entry = NULL; + int rc = -1; + spin_lock(&ReqHandlerInfo_list_lock); + list_for_each_safe(lelt, tmp, &ReqHandlerInfo_list) { + entry = list_entry(lelt, ReqHandlerInfo_t, list_link); + if (memcmp + (&entry->switchTypeGuid, &switchTypeGuid, + sizeof(GUID)) == 0) { + list_del(lelt); + UISFREE(entry, sizeof(*entry)); + rc++; + } + } + spin_unlock(&ReqHandlerInfo_list_lock); + return rc; +} diff --git a/drivers/staging/unisys/virthba/Kconfig b/drivers/staging/unisys/virthba/Kconfig new file mode 100644 index 00000000000..d2ef0fc2a4f --- /dev/null +++ b/drivers/staging/unisys/virthba/Kconfig @@ -0,0 +1,10 @@ +# +# Unisys virthba configuration +# + +config UNISYS_VIRTHBA + tristate "Unisys virthba driver" + depends on UNISYSSPAR && UNISYS_VISORCHIPSET && UNISYS_CHANNELSTUB && UNISYS_UISLIB && UNISYS_VIRTPCI + ---help--- + If you say Y here, you will enable the Unisys virthba driver. + diff --git a/drivers/staging/unisys/virthba/Makefile b/drivers/staging/unisys/virthba/Makefile new file mode 100644 index 00000000000..632b1c08b97 --- /dev/null +++ b/drivers/staging/unisys/virthba/Makefile @@ -0,0 +1,16 @@ +# +# Makefile for Unisys virthba +# + +obj-$(CONFIG_UNISYS_VIRTHBA) += virthba.o + +ccflags-y += -Idrivers/staging/unisys/include +ccflags-y += -Idrivers/staging/unisys/uislib +ccflags-y += -Idrivers/staging/unisys/timskmod +ccflags-y += -Idrivers/staging/unisys/visorchipset +ccflags-y += -Idrivers/staging/unisys/virtpci +ccflags-y += -Idrivers/staging/unisys/common-spar/include +ccflags-y += -Idrivers/staging/unisys/common-spar/include/channels + +ccflags-y += -DCONFIG_SPAR_GUEST -DGUESTDRIVERBUILD -DNOAUTOVERSION + diff --git a/drivers/staging/unisys/virthba/virthba.c b/drivers/staging/unisys/virthba/virthba.c new file mode 100644 index 00000000000..dd5fe75747f --- /dev/null +++ b/drivers/staging/unisys/virthba/virthba.c @@ -0,0 +1,1813 @@ +/* virthba.c + * + * Copyright © 2010 - 2013 UNISYS CORPORATION + * 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. + */ + +#define EXPORT_SYMTAB + +/* if you want to turn on some debugging of write device data or read + * device data, define these two undefs. You will probably want to + * customize the code which is here since it was written assuming + * reading and writing a specific data file df.64M.txt which is a + * 64Megabyte file created by Art Nilson using a scritp I wrote called + * cr_test_data.pl. The data file consists of 256 byte lines of text + * which start with an 8 digit sequence number, a colon, and then + * letters after that */ + +#undef DBGINF + +#include <linux/kernel.h> +#ifdef CONFIG_MODVERSIONS +#include <config/modversions.h> +#endif + +#include "uniklog.h" +#include "diagnostics/appos_subsystems.h" +#include "uisutils.h" +#include "uisqueue.h" +#include "uisthread.h" + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/spinlock.h> +#include <linux/device.h> +#include <linux/slab.h> +#include <scsi/scsi.h> +#include <scsi/scsi_host.h> +#include <scsi/scsi_cmnd.h> +#include <scsi/scsi_device.h> +#include <asm/param.h> +#include <linux/proc_fs.h> +#include <linux/types.h> + +#include "virthba.h" +#include "virtpci.h" +#include "visorchipset.h" +#include "version.h" +#include "guestlinuxdebug.h" +/* this is shorter than using __FILE__ (full path name) in + * debug/info/error messages + */ +#define CURRENT_FILE_PC VIRT_HBA_PC_virthba_c +#define __MYFILE__ "virthba.c" + +/* NOTE: L1_CACHE_BYTES >=128 */ +#define DEVICE_ATTRIBUTE struct device_attribute + +/*****************************************************/ +/* Forward declarations */ +/*****************************************************/ +static int virthba_probe(struct virtpci_dev *dev, + const struct pci_device_id *id); +static void virthba_remove(struct virtpci_dev *dev); +static int virthba_abort_handler(struct scsi_cmnd *scsicmd); +static int virthba_bus_reset_handler(struct scsi_cmnd *scsicmd); +static int virthba_device_reset_handler(struct scsi_cmnd *scsicmd); +static int virthba_host_reset_handler(struct scsi_cmnd *scsicmd); +static const char *virthba_get_info(struct Scsi_Host *shp); +static int virthba_ioctl(struct scsi_device *dev, int cmd, void __user *arg); +static int virthba_queue_command_lck(struct scsi_cmnd *scsicmd, + void (*virthba_cmnd_done)(struct scsi_cmnd *)); +#ifdef DEF_SCSI_QCMD +DEF_SCSI_QCMD(virthba_queue_command) +#else +#define virthba_queue_command virthba_queue_command_lck +#endif +static int virthba_slave_alloc(struct scsi_device *scsidev); +static int virthba_slave_configure(struct scsi_device *scsidev); +static void virthba_slave_destroy(struct scsi_device *scsidev); +static int process_incoming_rsps(void *); +static int virthba_serverup(struct virtpci_dev *virtpcidev); +static int virthba_serverdown(struct virtpci_dev *virtpcidev, u32 state); +static void doDiskAddRemove(struct work_struct *work); +static void virthba_serverdown_complete(struct work_struct *work); + +static ssize_t info_proc_read(struct file *file, char __user *buf, + size_t len, loff_t *offset); +static ssize_t rqwu_proc_write(struct file *file, const char __user *buffer, + size_t count, loff_t *ppos); +static ssize_t enable_ints_read(struct file *file, char __user *buffer, + size_t count, loff_t *ppos); +static ssize_t enable_ints_write(struct file *file, const char __user *buffer, + size_t count, loff_t *ppos); + +/*****************************************************/ +/* Globals */ +/*****************************************************/ + +int rsltq_wait_usecs = 4000; /* Default 4ms */ +static unsigned int MaxBuffLen; + +/* Module options */ +char *virthba_options = "NONE"; + +static const struct pci_device_id virthba_id_table[] = { + {PCI_DEVICE(PCI_VENDOR_ID_UNISYS, PCI_DEVICE_ID_VIRTHBA)}, + {0}, +}; + +/* export virthba_id_table */ +MODULE_DEVICE_TABLE(pci, virthba_id_table); + +static struct workqueue_struct *virthba_serverdown_workqueue; + +static struct virtpci_driver virthba_driver = { + .name = "uisvirthba", + .version = VERSION, + .vertag = NULL, + .build_date = __DATE__, + .build_time = __TIME__, + .id_table = virthba_id_table, + .probe = virthba_probe, + .remove = virthba_remove, + .resume = virthba_serverup, + .suspend = virthba_serverdown +}; + +/* The Send and Recive Buffers of the IO Queue may both be full */ +#define MAX_PENDING_REQUESTS (MIN_NUMSIGNALS*2) +#define INTERRUPT_VECTOR_MASK 0x3F + +struct scsipending { + char cmdtype; /* Type of pointer that is being stored */ + void *sent; /* The Data being tracked */ + /* struct scsi_cmnd *type for virthba_queue_command */ + /* struct uiscmdrsp *type for management commands */ +}; + +#define VIRTHBA_ERROR_COUNT 30 +#define IOS_ERROR_THRESHOLD 1000 +struct virtdisk_info { + U32 valid; + U32 channel, id, lun; /* Disk Path */ + atomic_t ios_threshold; + atomic_t error_count; + struct virtdisk_info *next; +}; +/* Each Scsi_Host has a host_data area that contains this struct. */ +struct virthba_info { + struct Scsi_Host *scsihost; + struct virtpci_dev *virtpcidev; + struct list_head dev_info_list; + struct chaninfo chinfo; + struct InterruptInfo intr; /* use recvInterrupt info to receive + interrupts when IOs complete */ + int interrupt_vector; + struct scsipending pending[MAX_PENDING_REQUESTS]; /* Tracks the requests + that have been */ + /* forwarded to the IOVM and haven't returned yet */ + unsigned int nextinsert; /* Start search for next pending + free slot here */ + spinlock_t privlock; + bool serverdown; + bool serverchangingstate; + unsigned long long acquire_failed_cnt; + unsigned long long interrupts_rcvd; + unsigned long long interrupts_notme; + unsigned long long interrupts_disabled; + struct work_struct serverdown_completion; + U64 *flags_addr; + atomic_t interrupt_rcvd; + wait_queue_head_t rsp_queue; + struct virtdisk_info head; +}; + +/* Work Data for DARWorkQ */ +struct diskaddremove { + U8 add; /* 0-remove, 1-add */ + struct Scsi_Host *shost; /* Scsi Host for this virthba instance */ + U32 channel, id, lun; /* Disk Path */ + struct diskaddremove *next; +}; + +#define virtpci_dev_to_virthba_virthba_get_info(d) \ + container_of(d, struct virthba_info, virtpcidev) + +static DEVICE_ATTRIBUTE *virthba_shost_attrs[]; +static struct scsi_host_template virthba_driver_template = { + .name = "Unisys Virtual HBA", + .proc_name = "uisvirthba", + .info = virthba_get_info, + .ioctl = virthba_ioctl, + .queuecommand = virthba_queue_command, + .eh_abort_handler = virthba_abort_handler, + .eh_device_reset_handler = virthba_device_reset_handler, + .eh_bus_reset_handler = virthba_bus_reset_handler, + .eh_host_reset_handler = virthba_host_reset_handler, + .shost_attrs = virthba_shost_attrs, + +#define VIRTHBA_MAX_CMNDS 128 + .can_queue = VIRTHBA_MAX_CMNDS, + .sg_tablesize = 64, /* largest number of address/length pairs */ + .this_id = -1, + .slave_alloc = virthba_slave_alloc, + .slave_configure = virthba_slave_configure, + .slave_destroy = virthba_slave_destroy, + .use_clustering = ENABLE_CLUSTERING, +}; + +struct virthba_devices_open { + struct virthba_info *virthbainfo; +}; + +static const struct file_operations proc_info_fops = { + .read = info_proc_read, +}; + +static const struct file_operations proc_rqwu_fops = { + .write = rqwu_proc_write, +}; + +static const struct file_operations proc_enable_ints_fops = { + .read = enable_ints_read, + .write = enable_ints_write, +}; + + +#define VIRTHBASOPENMAX 1 +/* array of open devices maintained by open() and close(); */ +static struct virthba_devices_open VirtHbasOpen[VIRTHBASOPENMAX]; +static struct proc_dir_entry *virthba_proc_dir; +static struct proc_dir_entry *info_proc_entry; +static struct proc_dir_entry *rqwaitus_proc_entry; +static struct proc_dir_entry *enable_ints_proc_entry; +#define INFO_PROC_ENTRY_FN "info" +#define ENABLE_INTS_ENTRY_FN "enable_ints" +#define RQWU_PROC_ENTRY_FN "rqwait_usecs" +#define DIR_PROC_ENTRY "virthba" + +/*****************************************************/ +/* Local Functions */ +/*****************************************************/ +static int +add_scsipending_entry(struct virthba_info *vhbainfo, char cmdtype, void *new) +{ + unsigned long flags; + int insert_location; + + spin_lock_irqsave(&vhbainfo->privlock, flags); + insert_location = vhbainfo->nextinsert; + while (vhbainfo->pending[insert_location].sent != NULL) { + insert_location = (insert_location + 1) % MAX_PENDING_REQUESTS; + if (insert_location == (int) vhbainfo->nextinsert) { + LOGERR("Queue should be full. insert_location<<%d>> Unable to find open slot for pending commands.\n", + insert_location); + spin_unlock_irqrestore(&vhbainfo->privlock, flags); + return -1; + } + } + + vhbainfo->pending[insert_location].cmdtype = cmdtype; + vhbainfo->pending[insert_location].sent = new; + vhbainfo->nextinsert = (insert_location + 1) % MAX_PENDING_REQUESTS; + spin_unlock_irqrestore(&vhbainfo->privlock, flags); + + return insert_location; +} + +static unsigned int +add_scsipending_entry_with_wait(struct virthba_info *vhbainfo, char cmdtype, + void *new) +{ + int insert_location = add_scsipending_entry(vhbainfo, cmdtype, new); + + while (insert_location == -1) { + LOGERR("Failed to find empty queue slot. Waiting to try again\n"); + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(msecs_to_jiffies(10)); + insert_location = add_scsipending_entry(vhbainfo, cmdtype, new); + } + + return (unsigned int) insert_location; +} + +static void * +del_scsipending_entry(struct virthba_info *vhbainfo, uintptr_t del) +{ + unsigned long flags; + void *sent = NULL; + + if (del >= MAX_PENDING_REQUESTS) { + LOGERR("Invalid queue position <<%lu>> given to delete. MAX_PENDING_REQUESTS <<%d>>\n", + (unsigned long) del, MAX_PENDING_REQUESTS); + } else { + spin_lock_irqsave(&vhbainfo->privlock, flags); + + if (vhbainfo->pending[del].sent == NULL) + LOGERR("Deleting already cleared queue entry at <<%lu>>.\n", + (unsigned long) del); + + sent = vhbainfo->pending[del].sent; + + vhbainfo->pending[del].cmdtype = 0; + vhbainfo->pending[del].sent = NULL; + spin_unlock_irqrestore(&vhbainfo->privlock, flags); + } + + return sent; +} + +/* DARWorkQ (Disk Add/Remove) */ +static struct work_struct DARWorkQ; +struct diskaddremove *DARWorkQHead = NULL; +spinlock_t DARWorkQLock; +unsigned short DARWorkQSched = 0; +#define QUEUE_DISKADDREMOVE(dar) { \ + spin_lock_irqsave(&DARWorkQLock, flags); \ + if (!DARWorkQHead) { \ + DARWorkQHead = dar; \ + dar->next = NULL; \ + } \ + else { \ + dar->next = DARWorkQHead; \ + DARWorkQHead = dar; \ + } \ + if (!DARWorkQSched) { \ + schedule_work(&DARWorkQ); \ + DARWorkQSched = 1; \ + } \ + spin_unlock_irqrestore(&DARWorkQLock, flags); \ +} + +static inline void +SendDiskAddRemove(struct diskaddremove *dar) +{ + struct scsi_device *sdev; + int error; + + sdev = scsi_device_lookup(dar->shost, dar->channel, dar->id, dar->lun); + if (sdev) { + if (!(dar->add)) + scsi_remove_device(sdev); + } else if (dar->add) { + error = + scsi_add_device(dar->shost, dar->channel, dar->id, + dar->lun); + if (error) + LOGERR("Failed scsi_add_device: host_no=%d[chan=%d:id=%d:lun=%d]\n", + dar->shost->host_no, dar->channel, dar->id, + dar->lun); + } else + LOGERR("Failed scsi_device_lookup:[chan=%d:id=%d:lun=%d]\n", + dar->channel, dar->id, dar->lun); + kfree(dar); +} + +/*****************************************************/ +/* DARWorkQ Handler Thread */ +/*****************************************************/ +static void +doDiskAddRemove(struct work_struct *work) +{ + struct diskaddremove *dar; + struct diskaddremove *tmphead; + int i = 0; + unsigned long flags; + + spin_lock_irqsave(&DARWorkQLock, flags); + tmphead = DARWorkQHead; + DARWorkQHead = NULL; + DARWorkQSched = 0; + spin_unlock_irqrestore(&DARWorkQLock, flags); + while (tmphead) { + dar = tmphead; + tmphead = dar->next; + SendDiskAddRemove(dar); + i++; + } +} + +/*****************************************************/ +/* Routine to add entry to DARWorkQ */ +/*****************************************************/ +static void +process_disk_notify(struct Scsi_Host *shost, struct uiscmdrsp *cmdrsp) +{ + struct diskaddremove *dar; + unsigned long flags; + + dar = kmalloc(sizeof(struct diskaddremove), GFP_ATOMIC); + if (dar) { + memset(dar, 0, sizeof(struct diskaddremove)); + dar->add = cmdrsp->disknotify.add; + dar->shost = shost; + dar->channel = cmdrsp->disknotify.channel; + dar->id = cmdrsp->disknotify.id; + dar->lun = cmdrsp->disknotify.lun; + QUEUE_DISKADDREMOVE(dar); + } else { + LOGERR("kmalloc failed for dar. host_no=%d[chan=%d:id=%d:lun=%d]\n", + shost->host_no, cmdrsp->disknotify.channel, + cmdrsp->disknotify.id, cmdrsp->disknotify.lun); + } +} + +/*****************************************************/ +/* Probe Remove Functions */ +/*****************************************************/ +irqreturn_t +virthba_ISR(int irq, void *dev_id) +{ + struct virthba_info *virthbainfo = (struct virthba_info *) dev_id; + pCHANNEL_HEADER pChannelHeader; + pSIGNAL_QUEUE_HEADER pqhdr; + U64 mask; + unsigned long long rc1; + + if (virthbainfo == NULL) + return IRQ_NONE; + virthbainfo->interrupts_rcvd++; + pChannelHeader = virthbainfo->chinfo.queueinfo->chan; + if (((pChannelHeader->Features + & ULTRA_IO_IOVM_IS_OK_WITH_DRIVER_DISABLING_INTS) != 0) + && ((pChannelHeader->Features & ULTRA_IO_DRIVER_DISABLES_INTS) != + 0)) { + virthbainfo->interrupts_disabled++; + mask = ~ULTRA_CHANNEL_ENABLE_INTS; + rc1 = uisqueue_InterlockedAnd(virthbainfo->flags_addr, mask); + } + if (SignalQueueIsEmpty(pChannelHeader, IOCHAN_FROM_IOPART)) { + virthbainfo->interrupts_notme++; + return IRQ_NONE; + } + pqhdr = (pSIGNAL_QUEUE_HEADER) ((char *) pChannelHeader + + pChannelHeader->oChannelSpace) + + IOCHAN_FROM_IOPART; + pqhdr->NumInterruptsReceived++; + atomic_set(&virthbainfo->interrupt_rcvd, 1); + wake_up_interruptible(&virthbainfo->rsp_queue); + return IRQ_HANDLED; +} + +static int +virthba_probe(struct virtpci_dev *virtpcidev, const struct pci_device_id *id) +{ + int error; + struct Scsi_Host *scsihost; + struct virthba_info *virthbainfo; + int rsp; + int i; + irq_handler_t handler = virthba_ISR; + pCHANNEL_HEADER pChannelHeader; + pSIGNAL_QUEUE_HEADER pqhdr; + U64 mask; + + LOGVER("entering virthba_probe...\n"); + LOGVER("virtpcidev busNo<<%d>>devNo<<%d>>", virtpcidev->busNo, + virtpcidev->deviceNo); + + LOGINF("entering virthba_probe...\n"); + LOGINF("virtpcidev busNo<<%d>>devNo<<%d>>", virtpcidev->busNo, + virtpcidev->deviceNo); + POSTCODE_LINUX_2(VHBA_PROBE_ENTRY_PC, POSTCODE_SEVERITY_INFO); + /* call scsi_host_alloc to register a scsi host adapter + * instance - this virthba that has just been created is an + * instance of a scsi host adapter. This scsi_host_alloc + * function allocates a new Scsi_Host struct & performs basic + * initializatoin. The host is not published to the scsi + * midlayer until scsi_add_host is called. + */ + DBGINF("calling scsi_host_alloc.\n"); + + /* arg 2 passed in length of extra space we want allocated + * with scsi_host struct for our own use scsi_host_alloc + * assign host_no + */ + scsihost = scsi_host_alloc(&virthba_driver_template, + sizeof(struct virthba_info)); + if (scsihost == NULL) + return -ENODEV; + + DBGINF("scsihost: 0x%p, scsihost->this_id: %d, host_no: %d.\n", + scsihost, scsihost->this_id, scsihost->host_no); + + scsihost->this_id = UIS_MAGIC_VHBA; + /* linux treats max-channel differently than max-id & max-lun. + * In the latter cases, those two values result in 0 to max-1 + * (inclusive) being scanned. But in the case of channels, the + * scan is 0 to max (inclusive); so we will subtract one from + * the max-channel value. + */ + LOGINF("virtpcidev->scsi.max.max_channel=%u, max_id=%u, max_lun=%u, cmd_per_lun=%u, max_io_size=%u\n", + (unsigned) virtpcidev->scsi.max.max_channel - 1, + (unsigned) virtpcidev->scsi.max.max_id, + (unsigned) virtpcidev->scsi.max.max_lun, + (unsigned) virtpcidev->scsi.max.cmd_per_lun, + (unsigned) virtpcidev->scsi.max.max_io_size); + scsihost->max_channel = (unsigned) virtpcidev->scsi.max.max_channel; + scsihost->max_id = (unsigned) virtpcidev->scsi.max.max_id; + scsihost->max_lun = (unsigned) virtpcidev->scsi.max.max_lun; + scsihost->cmd_per_lun = (unsigned) virtpcidev->scsi.max.cmd_per_lun; + scsihost->max_sectors = + (unsigned short) (virtpcidev->scsi.max.max_io_size >> 9); + scsihost->sg_tablesize = + (unsigned short) (virtpcidev->scsi.max.max_io_size / PAGE_SIZE); + if (scsihost->sg_tablesize > MAX_PHYS_INFO) + scsihost->sg_tablesize = MAX_PHYS_INFO; + LOGINF("scsihost->max_channel=%u, max_id=%u, max_lun=%u, cmd_per_lun=%u, max_sectors=%hu, sg_tablesize=%hu\n", + scsihost->max_channel, scsihost->max_id, scsihost->max_lun, + scsihost->cmd_per_lun, scsihost->max_sectors, + scsihost->sg_tablesize); + LOGINF("scsihost->can_queue=%u, scsihost->cmd_per_lun=%u, max_sectors=%hu, sg_tablesize=%hu\n", + scsihost->can_queue, scsihost->cmd_per_lun, scsihost->max_sectors, + scsihost->sg_tablesize); + + DBGINF("calling scsi_add_host\n"); + + /* this creates "host%d" in sysfs. If 2nd argument is NULL, + * then this generic /sys/devices/platform/host? device is + * created and /sys/scsi_host/host? -> + * /sys/devices/platform/host? If 2nd argument is not NULL, + * then this generic /sys/devices/<path>/host? is created and + * host? points to that device instead. + */ + error = scsi_add_host(scsihost, &virtpcidev->generic_dev); + if (error) { + LOGERR("scsi_add_host ****FAILED 0x%x TBD - RECOVER\n", error); + POSTCODE_LINUX_2(VHBA_PROBE_FAILURE_PC, POSTCODE_SEVERITY_ERR); + /* decr refcount on scsihost which was incremented by + * scsi_add_host so the scsi_host gets deleted + */ + scsi_host_put(scsihost); + return -ENODEV; + } + + virthbainfo = (struct virthba_info *) scsihost->hostdata; + memset(virthbainfo, 0, sizeof(struct virthba_info)); + for (i = 0; i < VIRTHBASOPENMAX; i++) { + if (VirtHbasOpen[i].virthbainfo == NULL) { + VirtHbasOpen[i].virthbainfo = virthbainfo; + break; + } + } + virthbainfo->interrupt_vector = -1; + virthbainfo->chinfo.queueinfo = &virtpcidev->queueinfo; + virthbainfo->virtpcidev = virtpcidev; + spin_lock_init(&virthbainfo->chinfo.insertlock); + + DBGINF("generic_dev: 0x%p, queueinfo: 0x%p.\n", + &virtpcidev->generic_dev, &virtpcidev->queueinfo); + + init_waitqueue_head(&virthbainfo->rsp_queue); + spin_lock_init(&virthbainfo->privlock); + memset(&virthbainfo->pending, 0, sizeof(virthbainfo->pending)); + virthbainfo->serverdown = false; + virthbainfo->serverchangingstate = false; + + virthbainfo->intr = virtpcidev->intr; + /* save of host within virthba_info */ + virthbainfo->scsihost = scsihost; + + /* save of host within virtpci_dev */ + virtpcidev->scsi.scsihost = scsihost; + + /* Setup workqueue for serverdown messages */ + INIT_WORK(&virthbainfo->serverdown_completion, + virthba_serverdown_complete); + + virthbainfo->chinfo.queueinfo->chan->Features |= + ULTRA_IO_CHANNEL_IS_POLLING; + /* start thread that will receive scsicmnd responses */ + DBGINF("starting rsp thread -- queueinfo: 0x%p, threadinfo: 0x%p.\n", + virthbainfo->chinfo.queueinfo, &virthbainfo->chinfo.threadinfo); + + pChannelHeader = virthbainfo->chinfo.queueinfo->chan; + pqhdr = (pSIGNAL_QUEUE_HEADER) ((char *) pChannelHeader + + pChannelHeader->oChannelSpace) + + IOCHAN_FROM_IOPART; + virthbainfo->flags_addr = &pqhdr->FeatureFlags; + + if (!uisthread_start(&virthbainfo->chinfo.threadinfo, + process_incoming_rsps, + virthbainfo, "vhba_incoming")) { + LOGERR("uisthread_start rsp ****FAILED\n"); + /* decr refcount on scsihost which was incremented by + * scsi_add_host so the scsi_host gets deleted + */ + POSTCODE_LINUX_2(VHBA_PROBE_FAILURE_PC, POSTCODE_SEVERITY_ERR); + scsi_host_put(scsihost); + return -ENODEV; + } + LOGINF("sendInterruptHandle=0x%16llX", + virthbainfo->intr.sendInterruptHandle); + LOGINF("recvInterruptHandle=0x%16llX", + virthbainfo->intr.recvInterruptHandle); + LOGINF("recvInterruptVector=0x%8X", + virthbainfo->intr.recvInterruptVector); + LOGINF("recvInterruptShared=0x%2X", + virthbainfo->intr.recvInterruptShared); + LOGINF("scsihost.hostt->name=%s", scsihost->hostt->name); + virthbainfo->interrupt_vector = + virthbainfo->intr.recvInterruptHandle & INTERRUPT_VECTOR_MASK; + rsp = request_irq(virthbainfo->interrupt_vector, handler, IRQF_SHARED, + scsihost->hostt->name, virthbainfo); + if (rsp != 0) { + LOGERR("request_irq(%d) uislib_virthba_ISR request failed with rsp=%d\n", + virthbainfo->interrupt_vector, rsp); + virthbainfo->interrupt_vector = -1; + POSTCODE_LINUX_2(VHBA_PROBE_FAILURE_PC, POSTCODE_SEVERITY_ERR); + } else { + U64 *Features_addr = + &virthbainfo->chinfo.queueinfo->chan->Features; + LOGERR("request_irq(%d) uislib_virthba_ISR request succeeded\n", + virthbainfo->interrupt_vector); + mask = ~(ULTRA_IO_CHANNEL_IS_POLLING | + ULTRA_IO_DRIVER_DISABLES_INTS); + uisqueue_InterlockedAnd(Features_addr, mask); + mask = ULTRA_IO_DRIVER_ENABLES_INTS; + uisqueue_InterlockedOr(Features_addr, mask); + rsltq_wait_usecs = 4000000; + } + + DBGINF("calling scsi_scan_host.\n"); + scsi_scan_host(scsihost); + DBGINF("return from scsi_scan_host.\n"); + + LOGINF("virthba added scsihost:0x%p\n", scsihost); + POSTCODE_LINUX_2(VHBA_PROBE_EXIT_PC, POSTCODE_SEVERITY_INFO); + return 0; +} + +static void +virthba_remove(struct virtpci_dev *virtpcidev) +{ + struct virthba_info *virthbainfo; + struct Scsi_Host *scsihost = + (struct Scsi_Host *) virtpcidev->scsi.scsihost; + + LOGINF("virtpcidev busNo<<%d>>devNo<<%d>>", virtpcidev->busNo, + virtpcidev->deviceNo); + virthbainfo = (struct virthba_info *) scsihost->hostdata; + if (virthbainfo->interrupt_vector != -1) + free_irq(virthbainfo->interrupt_vector, virthbainfo); + LOGINF("Removing virtpcidev: 0x%p, virthbainfo: 0x%p\n", virtpcidev, + virthbainfo); + + DBGINF("removing scsihost: 0x%p, scsihost->this_id: %d\n", scsihost, + scsihost->this_id); + scsi_remove_host(scsihost); + + DBGINF("stopping thread.\n"); + uisthread_stop(&virthbainfo->chinfo.threadinfo); + + DBGINF("calling scsi_host_put\n"); + + /* decr refcount on scsihost which was incremented by + * scsi_add_host so the scsi_host gets deleted + */ + scsi_host_put(scsihost); + LOGINF("virthba removed scsi_host.\n"); +} + +static int +forward_vdiskmgmt_command(VDISK_MGMT_TYPES vdiskcmdtype, + struct Scsi_Host *scsihost, + struct uisscsi_dest *vdest) +{ + struct uiscmdrsp *cmdrsp; + struct virthba_info *virthbainfo = + (struct virthba_info *) scsihost->hostdata; + int notifyresult = 0xffff; + wait_queue_head_t notifyevent; + + LOGINF("vDiskMgmt:%d %d:%d:%d\n", vdiskcmdtype, + vdest->channel, vdest->id, vdest->lun); + + if (virthbainfo->serverdown || virthbainfo->serverchangingstate) { + DBGINF("Server is down/changing state. Returning Failure.\n"); + return FAILED; + } + + ALLOC_CMDRSP(cmdrsp); + if (cmdrsp == NULL) { + LOGERR("kmalloc of cmdrsp failed.\n"); + return FAILED; /* reject */ + } + + init_waitqueue_head(¬ifyevent); + + /* issue VDISK_MGMT_CMD + * set type to command - as opposed to task mgmt + */ + cmdrsp->cmdtype = CMD_VDISKMGMT_TYPE; + /* specify the event that has to be triggered when this cmd is + * complete + */ + cmdrsp->vdiskmgmt.notify = (void *) ¬ifyevent; + cmdrsp->vdiskmgmt.notifyresult = (void *) ¬ifyresult; + + /* save destination */ + cmdrsp->vdiskmgmt.vdisktype = vdiskcmdtype; + cmdrsp->vdiskmgmt.vdest.channel = vdest->channel; + cmdrsp->vdiskmgmt.vdest.id = vdest->id; + cmdrsp->vdiskmgmt.vdest.lun = vdest->lun; + cmdrsp->vdiskmgmt.scsicmd = + (void *) (uintptr_t) + add_scsipending_entry_with_wait(virthbainfo, CMD_VDISKMGMT_TYPE, + (void *) cmdrsp); + + uisqueue_put_cmdrsp_with_lock_client(virthbainfo->chinfo.queueinfo, + cmdrsp, IOCHAN_TO_IOPART, + &virthbainfo->chinfo.insertlock, + DONT_ISSUE_INTERRUPT, (U64) NULL, + OK_TO_WAIT, "vhba"); + LOGINF("VdiskMgmt waiting on event notifyevent=0x%p\n", + cmdrsp->scsitaskmgmt.notify); + wait_event(notifyevent, notifyresult != 0xffff); + LOGINF("VdiskMgmt complete; result:%d\n", cmdrsp->vdiskmgmt.result); + kfree(cmdrsp); + return SUCCESS; +} + +/*****************************************************/ +/* Scsi Host support functions */ +/*****************************************************/ + +static int +forward_taskmgmt_command(TASK_MGMT_TYPES tasktype, struct scsi_device *scsidev) +{ + struct uiscmdrsp *cmdrsp; + struct virthba_info *virthbainfo = + (struct virthba_info *) scsidev->host->hostdata; + int notifyresult = 0xffff; + wait_queue_head_t notifyevent; + + LOGINF("TaskMgmt:%d %d:%d:%d\n", tasktype, + scsidev->channel, scsidev->id, scsidev->lun); + + if (virthbainfo->serverdown || virthbainfo->serverchangingstate) { + DBGINF("Server is down/changing state. Returning Failure.\n"); + return FAILED; + } + + ALLOC_CMDRSP(cmdrsp); + if (cmdrsp == NULL) { + LOGERR("kmalloc of cmdrsp failed.\n"); + return FAILED; /* reject */ + } + + init_waitqueue_head(¬ifyevent); + + /* issue TASK_MGMT_ABORT_TASK */ + /* set type to command - as opposed to task mgmt */ + cmdrsp->cmdtype = CMD_SCSITASKMGMT_TYPE; + /* specify the event that has to be triggered when this */ + /* cmd is complete */ + cmdrsp->scsitaskmgmt.notify = (void *) ¬ifyevent; + cmdrsp->scsitaskmgmt.notifyresult = (void *) ¬ifyresult; + + /* save destination */ + cmdrsp->scsitaskmgmt.tasktype = tasktype; + cmdrsp->scsitaskmgmt.vdest.channel = scsidev->channel; + cmdrsp->scsitaskmgmt.vdest.id = scsidev->id; + cmdrsp->scsitaskmgmt.vdest.lun = scsidev->lun; + cmdrsp->scsitaskmgmt.scsicmd = + (void *) (uintptr_t) + add_scsipending_entry_with_wait(virthbainfo, + CMD_SCSITASKMGMT_TYPE, + (void *) cmdrsp); + + uisqueue_put_cmdrsp_with_lock_client(virthbainfo->chinfo.queueinfo, + cmdrsp, IOCHAN_TO_IOPART, + &virthbainfo->chinfo.insertlock, + DONT_ISSUE_INTERRUPT, (U64) NULL, + OK_TO_WAIT, "vhba"); + LOGINF("TaskMgmt waiting on event notifyevent=0x%p\n", + cmdrsp->scsitaskmgmt.notify); + wait_event(notifyevent, notifyresult != 0xffff); + LOGINF("TaskMgmt complete; result:%d\n", cmdrsp->scsitaskmgmt.result); + kfree(cmdrsp); + return SUCCESS; +} + +/* The abort handler returns SUCCESS if it has succeeded to make LLDD + * and all related hardware forget about the scmd. + */ +static int +virthba_abort_handler(struct scsi_cmnd *scsicmd) +{ + /* issue TASK_MGMT_ABORT_TASK */ + struct scsi_device *scsidev; + struct virtdisk_info *vdisk; + + scsidev = scsicmd->device; + for (vdisk = &((struct virthba_info *) scsidev->host->hostdata)->head; + vdisk->next; vdisk = vdisk->next) { + if ((scsidev->channel == vdisk->channel) + && (scsidev->id == vdisk->id) + && (scsidev->lun == vdisk->lun)) { + if (atomic_read(&vdisk->error_count) < + VIRTHBA_ERROR_COUNT) { + atomic_inc(&vdisk->error_count); + POSTCODE_LINUX_2(VHBA_COMMAND_HANDLER_PC, + POSTCODE_SEVERITY_INFO); + } else + atomic_set(&vdisk->ios_threshold, + IOS_ERROR_THRESHOLD); + } + } + return forward_taskmgmt_command(TASK_MGMT_ABORT_TASK, scsicmd->device); +} + +static int +virthba_bus_reset_handler(struct scsi_cmnd *scsicmd) +{ + /* issue TASK_MGMT_TARGET_RESET for each target on the bus */ + struct scsi_device *scsidev; + struct virtdisk_info *vdisk; + + scsidev = scsicmd->device; + for (vdisk = &((struct virthba_info *) scsidev->host->hostdata)->head; + vdisk->next; vdisk = vdisk->next) { + if ((scsidev->channel == vdisk->channel) + && (scsidev->id == vdisk->id) + && (scsidev->lun == vdisk->lun)) { + if (atomic_read(&vdisk->error_count) < + VIRTHBA_ERROR_COUNT) { + atomic_inc(&vdisk->error_count); + POSTCODE_LINUX_2(VHBA_COMMAND_HANDLER_PC, + POSTCODE_SEVERITY_INFO); + } else + atomic_set(&vdisk->ios_threshold, + IOS_ERROR_THRESHOLD); + } + } + return forward_taskmgmt_command(TASK_MGMT_BUS_RESET, scsicmd->device); +} + +static int +virthba_device_reset_handler(struct scsi_cmnd *scsicmd) +{ + /* issue TASK_MGMT_LUN_RESET */ + struct scsi_device *scsidev; + struct virtdisk_info *vdisk; + + scsidev = scsicmd->device; + for (vdisk = &((struct virthba_info *) scsidev->host->hostdata)->head; + vdisk->next; vdisk = vdisk->next) { + if ((scsidev->channel == vdisk->channel) + && (scsidev->id == vdisk->id) + && (scsidev->lun == vdisk->lun)) { + if (atomic_read(&vdisk->error_count) < + VIRTHBA_ERROR_COUNT) { + atomic_inc(&vdisk->error_count); + POSTCODE_LINUX_2(VHBA_COMMAND_HANDLER_PC, + POSTCODE_SEVERITY_INFO); + } else + atomic_set(&vdisk->ios_threshold, + IOS_ERROR_THRESHOLD); + } + } + return forward_taskmgmt_command(TASK_MGMT_LUN_RESET, scsicmd->device); +} + +static int +virthba_host_reset_handler(struct scsi_cmnd *scsicmd) +{ + /* issue TASK_MGMT_TARGET_RESET for each target on each bus for host */ + LOGERR("virthba_host_reset_handler Not yet implemented\n"); + return SUCCESS; +} + +static char virthba_get_info_str[256]; + +static const char * +virthba_get_info(struct Scsi_Host *shp) +{ + /* Return version string */ + sprintf(virthba_get_info_str, "virthba, version %s\n", VIRTHBA_VERSION); + return virthba_get_info_str; +} + +static int +virthba_ioctl(struct scsi_device *dev, int cmd, void __user *arg) +{ + DBGINF("In virthba_ioctl: ioctl: cmd=0x%x\n", cmd); + return -EINVAL; +} + +/* This returns SCSI_MLQUEUE_DEVICE_BUSY if the signal queue to IOpart + * is full. + */ +static int +virthba_queue_command_lck(struct scsi_cmnd *scsicmd, + void (*virthba_cmnd_done)(struct scsi_cmnd *)) +{ + struct scsi_device *scsidev = scsicmd->device; + int insert_location; + unsigned char op; + unsigned char *cdb = scsicmd->cmnd; + struct Scsi_Host *scsihost = scsidev->host; + struct uiscmdrsp *cmdrsp; + unsigned int i; + struct virthba_info *virthbainfo = + (struct virthba_info *) scsihost->hostdata; + struct scatterlist *sg = NULL; + struct scatterlist *sgl = NULL; + int sg_failed = 0; + + if (virthbainfo->serverdown || virthbainfo->serverchangingstate) { + DBGINF("Server is down/changing state. Returning SCSI_MLQUEUE_DEVICE_BUSY.\n"); + return SCSI_MLQUEUE_DEVICE_BUSY; + } + + ALLOC_CMDRSP(cmdrsp); + if (cmdrsp == NULL) { + LOGERR("kmalloc of cmdrsp failed.\n"); + return 1; /* reject the command */ + } + + /* now saving everything we need from scsi_cmd into cmdrsp + * before we queue cmdrsp set type to command - as opposed to + * task mgmt + */ + cmdrsp->cmdtype = CMD_SCSI_TYPE; + /* save the pending insertion location. Deletion from pending + * will return the scsicmd pointer for completion + */ + insert_location = + add_scsipending_entry(virthbainfo, CMD_SCSI_TYPE, (void *) scsicmd); + if (insert_location != -1) { + cmdrsp->scsi.scsicmd = (void *) (uintptr_t) insert_location; + } else { + LOGERR("Queue is full. Returning busy.\n"); + kfree(cmdrsp); + return SCSI_MLQUEUE_DEVICE_BUSY; + } + /* save done function that we have call when cmd is complete */ + scsicmd->scsi_done = virthba_cmnd_done; + /* save destination */ + cmdrsp->scsi.vdest.channel = scsidev->channel; + cmdrsp->scsi.vdest.id = scsidev->id; + cmdrsp->scsi.vdest.lun = scsidev->lun; + /* save datadir */ + cmdrsp->scsi.data_dir = scsicmd->sc_data_direction; + memcpy(cmdrsp->scsi.cmnd, cdb, MAX_CMND_SIZE); + + cmdrsp->scsi.bufflen = scsi_bufflen(scsicmd); + + /* keep track of the max buffer length so far. */ + if (cmdrsp->scsi.bufflen > MaxBuffLen) + MaxBuffLen = cmdrsp->scsi.bufflen; + + if (scsi_sg_count(scsicmd) > MAX_PHYS_INFO) { + LOGERR("scsicmd use_sg:%d greater than MAX:%d\n", + scsi_sg_count(scsicmd), MAX_PHYS_INFO); + del_scsipending_entry(virthbainfo, (uintptr_t) insert_location); + kfree(cmdrsp); + return 1; /* reject the command */ + } + + /* This is what we USED to do when we assumed we were running */ + /* uissd & virthba on the same Linux system. */ + /* cmdrsp->scsi.buffer = scsicmd->request_buffer; */ + /* The following code does NOT make that assumption. */ + /* convert buffer to phys information */ + if (scsi_sg_count(scsicmd) == 0) { + if (scsi_bufflen(scsicmd) > 0) { + LOGERR("**** FAILED No scatter list for bufflen > 0\n"); + BUG_ON(scsi_sg_count(scsicmd) == 0); + } + DBGINF("No sg; buffer:0x%p bufflen:%d\n", + scsi_sglist(scsicmd), scsi_bufflen(scsicmd)); + } else { + /* buffer is scatterlist - copy it out */ + sgl = scsi_sglist(scsicmd); + + for_each_sg(sgl, sg, scsi_sg_count(scsicmd), i) { + + cmdrsp->scsi.gpi_list[i].address = sg_phys(sg); + cmdrsp->scsi.gpi_list[i].length = sg->length; + if ((i != 0) && (sg->offset != 0)) + LOGINF("Offset on a sg_entry other than zero =<<%d>>.\n", + sg->offset); + } + + if (sg_failed) { + LOGERR("Start sg_list dump (entries %d, bufflen %d)...\n", + scsi_sg_count(scsicmd), cmdrsp->scsi.bufflen); + for_each_sg(sgl, sg, scsi_sg_count(scsicmd), i) { + LOGERR(" Entry(%d): page->[0x%p], phys->[0x%Lx], off(%d), len(%d)\n", + i, sg_page(sg), + (unsigned long long) sg_phys(sg), + sg->offset, sg->length); + } + LOGERR("Done sg_list dump.\n"); + /* BUG(); ***** For now, let it fail in uissd + * if it is a problem, as it might just + * work + */ + } + + cmdrsp->scsi.guest_phys_entries = scsi_sg_count(scsicmd); + } + + op = cdb[0]; + i = uisqueue_put_cmdrsp_with_lock_client(virthbainfo->chinfo.queueinfo, + cmdrsp, IOCHAN_TO_IOPART, + &virthbainfo->chinfo. + insertlock, + DONT_ISSUE_INTERRUPT, + (U64) NULL, DONT_WAIT, "vhba"); + if (i == 0) { + /* queue must be full - and we said don't wait - return busy */ + LOGERR("uisqueue_put_cmdrsp_with_lock ****FAILED\n"); + kfree(cmdrsp); + del_scsipending_entry(virthbainfo, (uintptr_t) insert_location); + return SCSI_MLQUEUE_DEVICE_BUSY; + } + + /* we're done with cmdrsp space - data from it has been copied + * into channel - free it now. + */ + kfree(cmdrsp); + return 0; /* non-zero implies host/device is busy */ +} + +static int +virthba_slave_alloc(struct scsi_device *scsidev) +{ + /* this called by the midlayer before scan for new devices - + * LLD can alloc any struc & do init if needed. + */ + struct virtdisk_info *vdisk; + struct virtdisk_info *tmpvdisk; + struct virthba_info *virthbainfo; + struct Scsi_Host *scsihost = (struct Scsi_Host *) scsidev->host; + + virthbainfo = (struct virthba_info *) scsihost->hostdata; + if (!virthbainfo) { + LOGERR("Could not find virthba_info for scsihost\n"); + return 0; /* even though we errored, treat as success */ + } + for (vdisk = &virthbainfo->head; vdisk->next; vdisk = vdisk->next) { + if (vdisk->next->valid && + (vdisk->next->channel == scsidev->channel) && + (vdisk->next->id == scsidev->id) && + (vdisk->next->lun == scsidev->lun)) + return 0; + } + tmpvdisk = kmalloc(sizeof(struct virtdisk_info), GFP_ATOMIC); + if (!tmpvdisk) { /* error allocating */ + LOGERR("Could not allocate memory for disk\n"); + return 0; + } + memset(tmpvdisk, 0, sizeof(struct virtdisk_info)); + tmpvdisk->channel = scsidev->channel; + tmpvdisk->id = scsidev->id; + tmpvdisk->lun = scsidev->lun; + tmpvdisk->valid = 1; + vdisk->next = tmpvdisk; + return 0; /* success */ +} + +static int +virthba_slave_configure(struct scsi_device *scsidev) +{ + return 0; /* success */ +} + +static void +virthba_slave_destroy(struct scsi_device *scsidev) +{ + /* midlevel calls this after device has been quiesced and + * before it is to be deleted. + */ + struct virtdisk_info *vdisk, *delvdisk; + struct virthba_info *virthbainfo; + struct Scsi_Host *scsihost = (struct Scsi_Host *) scsidev->host; + + virthbainfo = (struct virthba_info *) scsihost->hostdata; + if (!virthbainfo) + LOGERR("Could not find virthba_info for scsihost\n"); + for (vdisk = &virthbainfo->head; vdisk->next; vdisk = vdisk->next) { + if (vdisk->next->valid && + (vdisk->next->channel == scsidev->channel) && + (vdisk->next->id == scsidev->id) && + (vdisk->next->lun == scsidev->lun)) { + delvdisk = vdisk->next; + vdisk->next = vdisk->next->next; + kfree(delvdisk); + return; + } + } + return; +} + +/*****************************************************/ +/* Scsi Cmnd support thread */ +/*****************************************************/ + +static void +do_scsi_linuxstat(struct uiscmdrsp *cmdrsp, struct scsi_cmnd *scsicmd) +{ + struct virtdisk_info *vdisk; + struct scsi_device *scsidev; + struct sense_data *sd; + + scsidev = scsicmd->device; + memcpy(scsicmd->sense_buffer, cmdrsp->scsi.sensebuf, MAX_SENSE_SIZE); + sd = (struct sense_data *) scsicmd->sense_buffer; + + /* Do not log errors for disk-not-present inquiries */ + if ((cmdrsp->scsi.cmnd[0] == INQUIRY) && + (host_byte(cmdrsp->scsi.linuxstat) == DID_NO_CONNECT) && + (cmdrsp->scsi.addlstat == ADDL_SEL_TIMEOUT)) + return; + + /* Okay see what our error_count is here.... */ + for (vdisk = &((struct virthba_info *) scsidev->host->hostdata)->head; + vdisk->next; vdisk = vdisk->next) { + if ((scsidev->channel != vdisk->channel) + || (scsidev->id != vdisk->id) + || (scsidev->lun != vdisk->lun)) + continue; + + if (atomic_read(&vdisk->error_count) < VIRTHBA_ERROR_COUNT) { + atomic_inc(&vdisk->error_count); + LOGERR("SCSICMD ****FAILED scsicmd:0x%p op:0x%x <%d:%d:%d:%d> 0x%x-0x%x-0x%x-0x%x-0x%x.\n", + scsicmd, cmdrsp->scsi.cmnd[0], + scsidev->host->host_no, scsidev->id, + scsidev->channel, scsidev->lun, + cmdrsp->scsi.linuxstat, sd->Valid, sd->SenseKey, + sd->AdditionalSenseCode, + sd->AdditionalSenseCodeQualifier); + if (atomic_read(&vdisk->error_count) == + VIRTHBA_ERROR_COUNT) { + LOGERR("Throtling SCSICMD errors disk <%d:%d:%d:%d>\n", + scsidev->host->host_no, scsidev->id, + scsidev->channel, scsidev->lun); + } + atomic_set(&vdisk->ios_threshold, IOS_ERROR_THRESHOLD); + } + } +} + +static void +do_scsi_nolinuxstat(struct uiscmdrsp *cmdrsp, struct scsi_cmnd *scsicmd) +{ + struct scsi_device *scsidev; + unsigned char buf[36]; + struct scatterlist *sg; + unsigned int i; + char *thispage; + char *thispage_orig; + int bufind = 0; + struct virtdisk_info *vdisk; + + scsidev = scsicmd->device; + if ((cmdrsp->scsi.cmnd[0] == INQUIRY) + && (cmdrsp->scsi.bufflen >= MIN_INQUIRY_RESULT_LEN)) { + if (cmdrsp->scsi.no_disk_result == 0) + return; + + /* Linux scsi code is weird; it wants + * a device at Lun 0 to issue report + * luns, but we don't want a disk + * there so we'll present a processor + * there. */ + SET_NO_DISK_INQUIRY_RESULT(buf, cmdrsp->scsi.bufflen, + scsidev->lun, + DEV_DISK_CAPABLE_NOT_PRESENT, + DEV_NOT_CAPABLE); + + if (scsi_sg_count(scsicmd) == 0) { + if (scsi_bufflen(scsicmd) > 0) { + LOGERR("**** FAILED No scatter list for bufflen > 0\n"); + BUG_ON(scsi_sg_count(scsicmd) == + 0); + } + memcpy(scsi_sglist(scsicmd), buf, + cmdrsp->scsi.bufflen); + return; + } + + sg = scsi_sglist(scsicmd); + for (i = 0; i < scsi_sg_count(scsicmd); i++) { + DBGVER("copying OUT OF buf into 0x%p %d\n", + sg_page(sg + i), sg[i].length); + thispage_orig = kmap_atomic(sg_page(sg + i)); + thispage = (void *) ((unsigned long)thispage_orig | + sg[i].offset); + memcpy(thispage, buf + bufind, sg[i].length); + kunmap_atomic(thispage_orig); + bufind += sg[i].length; + } + } else { + + vdisk = &((struct virthba_info *)scsidev->host->hostdata)->head; + for ( ; vdisk->next; vdisk = vdisk->next) { + if ((scsidev->channel != vdisk->channel) + || (scsidev->id != vdisk->id) + || (scsidev->lun != vdisk->lun)) + continue; + + if (atomic_read(&vdisk->ios_threshold) > 0) { + atomic_dec(&vdisk->ios_threshold); + if (atomic_read(&vdisk->ios_threshold) == 0) { + LOGERR("Resetting error count for disk\n"); + atomic_set(&vdisk->error_count, 0); + } + } + } + } +} + +static void +complete_scsi_command(struct uiscmdrsp *cmdrsp, struct scsi_cmnd *scsicmd) +{ + DBGINF("cmdrsp: 0x%p, scsistat:0x%x.\n", cmdrsp, cmdrsp->scsi.scsistat); + + /* take what we need out of cmdrsp and complete the scsicmd */ + scsicmd->result = cmdrsp->scsi.linuxstat; + if (cmdrsp->scsi.linuxstat) + do_scsi_linuxstat(cmdrsp, scsicmd); + else + do_scsi_nolinuxstat(cmdrsp, scsicmd); + + if (scsicmd->scsi_done) { + DBGVER("Scsi_DONE\n"); + scsicmd->scsi_done(scsicmd); + } +} + +static inline void +complete_vdiskmgmt_command(struct uiscmdrsp *cmdrsp) +{ + /* copy the result of the taskmgmt and */ + /* wake up the error handler that is waiting for this */ + *(int *) cmdrsp->vdiskmgmt.notifyresult = cmdrsp->vdiskmgmt.result; + wake_up_all((wait_queue_head_t *) cmdrsp->vdiskmgmt.notify); + LOGINF("set notify result to %d\n", cmdrsp->vdiskmgmt.result); +} + +static inline void +complete_taskmgmt_command(struct uiscmdrsp *cmdrsp) +{ + /* copy the result of the taskmgmt and */ + /* wake up the error handler that is waiting for this */ + *(int *) cmdrsp->scsitaskmgmt.notifyresult = + cmdrsp->scsitaskmgmt.result; + wake_up_all((wait_queue_head_t *) cmdrsp->scsitaskmgmt.notify); + LOGINF("set notify result to %d\n", cmdrsp->scsitaskmgmt.result); +} + +static void +drain_queue(struct virthba_info *virthbainfo, struct chaninfo *dc, + struct uiscmdrsp *cmdrsp) +{ + unsigned long flags; + int qrslt = 0; + struct scsi_cmnd *scsicmd; + struct Scsi_Host *shost = virthbainfo->scsihost; + + while (1) { + spin_lock_irqsave(&virthbainfo->chinfo.insertlock, flags); + if (!ULTRA_CHANNEL_CLIENT_ACQUIRE_OS(dc->queueinfo->chan, + "vhba", NULL)) { + spin_unlock_irqrestore(&virthbainfo->chinfo.insertlock, + flags); + virthbainfo->acquire_failed_cnt++; + break; + } + qrslt = uisqueue_get_cmdrsp(dc->queueinfo, cmdrsp, + IOCHAN_FROM_IOPART); + ULTRA_CHANNEL_CLIENT_RELEASE_OS(dc->queueinfo->chan, + "vhba", NULL); + spin_unlock_irqrestore(&virthbainfo->chinfo.insertlock, flags); + if (qrslt == 0) + break; + if (cmdrsp->cmdtype == CMD_SCSI_TYPE) { + /* scsicmd location is returned by the + * deletion + */ + scsicmd = del_scsipending_entry(virthbainfo, + (uintptr_t) cmdrsp->scsi.scsicmd); + if (!scsicmd) + break; + /* complete the orig cmd */ + complete_scsi_command(cmdrsp, scsicmd); + } else if (cmdrsp->cmdtype == CMD_SCSITASKMGMT_TYPE) { + if (!del_scsipending_entry(virthbainfo, + (uintptr_t) cmdrsp->scsitaskmgmt.scsicmd)) + break; + complete_taskmgmt_command(cmdrsp); + } else if (cmdrsp->cmdtype == CMD_NOTIFYGUEST_TYPE) { + /* The vHba pointer has no meaning in + * a Client/Guest Partition. Let's be + * safe and set it to NULL now. Do + * not use it here! */ + cmdrsp->disknotify.vHba = NULL; + process_disk_notify(shost, cmdrsp); + } else if (cmdrsp->cmdtype == CMD_VDISKMGMT_TYPE) { + if (!del_scsipending_entry(virthbainfo, + (uintptr_t) cmdrsp->vdiskmgmt.scsicmd)) + break; + complete_vdiskmgmt_command(cmdrsp); + } else + LOGERR("Invalid cmdtype %d\n", cmdrsp->cmdtype); + /* cmdrsp is now available for reuse */ + } +} + + +/* main function for the thread that waits for scsi commands to arrive + * in a specified queue + */ +static int +process_incoming_rsps(void *v) +{ + struct virthba_info *virthbainfo = v; + struct chaninfo *dc = &virthbainfo->chinfo; + struct uiscmdrsp *cmdrsp = NULL; + const int SZ = sizeof(struct uiscmdrsp); + U64 mask; + unsigned long long rc1; + + UIS_DAEMONIZE("vhba_incoming"); + /* alloc once and reuse */ + cmdrsp = kmalloc(SZ, GFP_ATOMIC); + if (cmdrsp == NULL) { + LOGERR("process_incoming_rsps ****FAILED to malloc - thread exiting\n"); + complete_and_exit(&dc->threadinfo.has_stopped, 0); + return 0; + } + mask = ULTRA_CHANNEL_ENABLE_INTS; + while (1) { + wait_event_interruptible_timeout(virthbainfo->rsp_queue, + (atomic_read(&virthbainfo->interrupt_rcvd) == 1), + usecs_to_jiffies(rsltq_wait_usecs)); + atomic_set(&virthbainfo->interrupt_rcvd, 0); + /* drain queue */ + drain_queue(virthbainfo, dc, cmdrsp); + rc1 = uisqueue_InterlockedOr(virthbainfo->flags_addr, mask); + if (dc->threadinfo.should_stop) + break; + } + + kfree(cmdrsp); + + DBGINF("exiting processing incoming rsps.\n"); + complete_and_exit(&dc->threadinfo.has_stopped, 0); +} + +/*****************************************************/ +/* proc filesystem functions */ +/*****************************************************/ + +static ssize_t +info_proc_read(struct file *file, char __user *buf, size_t len, loff_t *offset) +{ + int length = 0; + U64 phys_flags_addr; + int i; + struct virthba_info *virthbainfo; + char *vbuf; + loff_t pos = *offset; + + if (pos < 0) + return -EINVAL; + + if (pos > 0 || !len) + return 0; + + vbuf = kzalloc(len, GFP_KERNEL); + if (!vbuf) + return -ENOMEM; + + for (i = 0; i < VIRTHBASOPENMAX; i++) { + if (VirtHbasOpen[i].virthbainfo == NULL) + continue; + + virthbainfo = VirtHbasOpen[i].virthbainfo; + length += sprintf(vbuf + length, "CHANSOCK is not defined.\n"); + + length += sprintf(vbuf + length, "MaxBuffLen:%d\n", MaxBuffLen); + + length += sprintf(vbuf + length, "\nvirthba result queue poll wait:%d usecs.\n", + rsltq_wait_usecs); + + length += sprintf(vbuf + length, + "\nModule build: Date:%s Time:%s\n", + __DATE__, __TIME__); + length += sprintf(vbuf + length, "\ninterrupts_rcvd = %llu, interrupts_disabled = %llu\n", + virthbainfo->interrupts_rcvd, + virthbainfo->interrupts_disabled); + length += sprintf(vbuf + length, "\ninterrupts_notme = %llu,\n", + virthbainfo->interrupts_notme); + phys_flags_addr = virt_to_phys(virthbainfo->flags_addr); + + length += sprintf(vbuf + length, "flags_addr = %p, phys_flags_addr=0x%016llx, FeatureFlags=%llu\n", + virthbainfo->flags_addr, phys_flags_addr, + *virthbainfo->flags_addr); + length += sprintf(vbuf + length, "acquire_failed_cnt:%llu\n", + virthbainfo->acquire_failed_cnt); + + length += sprintf(vbuf + length, "\n"); + } + if (copy_to_user(buf, vbuf, length)) { + kfree(vbuf); + return -EFAULT; + } + + kfree(vbuf); + *offset += length; + return length; +} + +static ssize_t +enable_ints_read(struct file *file, char __user *buffer, + size_t count, loff_t *ppos) +{ + return 0; +} + +static ssize_t +enable_ints_write(struct file *file, const char __user *buffer, + size_t count, loff_t *ppos) +{ + char buf[count + 1]; + int i, new_value; + struct virthba_info *virthbainfo; + U64 *Features_addr; + U64 mask; + + buf[count] = '\0'; + if (copy_from_user(buf, buffer, count)) { + LOGERR("copy_from_user failed. buf<<%.*s>> count<<%lu>>\n", + (int) count, buf, count); + return -EFAULT; + } + + i = sscanf(buf, "%d", &new_value); + + if (i < 1) { + LOGERR("Failed to scan value for enable_ints, buf<<%.*s>>", + (int) count, buf); + return -EFAULT; + } + + /* set all counts to new_value usually 0 */ + for (i = 0; i < VIRTHBASOPENMAX; i++) { + if (VirtHbasOpen[i].virthbainfo != NULL) { + virthbainfo = VirtHbasOpen[i].virthbainfo; + Features_addr = + &virthbainfo->chinfo.queueinfo->chan->Features; + if (new_value == 1) { + mask = ~(ULTRA_IO_CHANNEL_IS_POLLING | + ULTRA_IO_DRIVER_DISABLES_INTS); + uisqueue_InterlockedAnd(Features_addr, mask); + mask = ULTRA_IO_DRIVER_ENABLES_INTS; + uisqueue_InterlockedOr(Features_addr, mask); + rsltq_wait_usecs = 4000000; + } else { + mask = ~(ULTRA_IO_DRIVER_ENABLES_INTS | + ULTRA_IO_DRIVER_DISABLES_INTS); + uisqueue_InterlockedAnd(Features_addr, mask); + mask = ULTRA_IO_CHANNEL_IS_POLLING; + uisqueue_InterlockedOr(Features_addr, mask); + rsltq_wait_usecs = 4000; + } + } + } + return count; +} + +static ssize_t +rqwu_proc_write(struct file *file, const char __user *buffer, + size_t count, loff_t *ppos) +{ + char buf[count]; + int i, usecs; + + if (copy_from_user(buf, buffer, count)) { + LOGERR("copy_from_user failed. buf<<%.*s>> count<<%lu>>\n", + (int) count, buf, count); + return -EFAULT; + } + + i = sscanf(buf, "%d", &usecs); + + if (i < 1) { + LOGERR("Failed to scan value for rqwait_usecs buf<<%.*s>>", + (int) count, buf); + return -EFAULT; + } + + /* set global wait time */ + rsltq_wait_usecs = usecs; + return count; +} + +/* As per VirtpciFunc returns 1 for success and 0 for failure */ +static int +virthba_serverup(struct virtpci_dev *virtpcidev) +{ + struct virthba_info *virthbainfo = + (struct virthba_info *) ((struct Scsi_Host *) virtpcidev->scsi. + scsihost)->hostdata; + + DBGINF("virtpcidev busNo<<%d>>devNo<<%d>>", virtpcidev->busNo, + virtpcidev->deviceNo); + + if (!virthbainfo->serverdown) { + DBGINF("Server up message recieved while server is already up.\n"); + return 1; + } + if (virthbainfo->serverchangingstate) { + LOGERR("Server already processing change state message\n"); + return 0; + } + + virthbainfo->serverchangingstate = true; + /* Must transition channel to ATTACHED state BEFORE we + * can start using the device again + */ + ULTRA_CHANNEL_CLIENT_TRANSITION(virthbainfo->chinfo.queueinfo->chan, + dev_name(&virtpcidev->generic_dev), + CliStateOS, + CHANNELCLI_ATTACHED, NULL); + + /* Start Processing the IOVM Response Queue Again */ + if (!uisthread_start(&virthbainfo->chinfo.threadinfo, + process_incoming_rsps, + virthbainfo, "vhba_incoming")) { + LOGERR("uisthread_start rsp ****FAILED\n"); + return 0; + } + virthbainfo->serverdown = false; + virthbainfo->serverchangingstate = false; + + return 1; +} + +static void +virthba_serverdown_complete(struct work_struct *work) +{ + struct virthba_info *virthbainfo; + struct virtpci_dev *virtpcidev; + int i; + struct scsipending *pendingdel = NULL; + struct scsi_cmnd *scsicmd = NULL; + struct uiscmdrsp *cmdrsp; + unsigned long flags; + + virthbainfo = container_of(work, struct virthba_info, + serverdown_completion); + + /* Stop Using the IOVM Response Queue (queue should be drained + * by the end) + */ + uisthread_stop(&virthbainfo->chinfo.threadinfo); + + /* Fail Commands that weren't completed */ + spin_lock_irqsave(&virthbainfo->privlock, flags); + for (i = 0; i < MAX_PENDING_REQUESTS; i++) { + pendingdel = &(virthbainfo->pending[i]); + switch (pendingdel->cmdtype) { + case CMD_SCSI_TYPE: + scsicmd = (struct scsi_cmnd *) pendingdel->sent; + scsicmd->result = (DID_RESET << 16); + if (scsicmd->scsi_done) + scsicmd->scsi_done(scsicmd); + break; + case CMD_SCSITASKMGMT_TYPE: + cmdrsp = (struct uiscmdrsp *) pendingdel->sent; + DBGINF("cmdrsp=0x%x, notify=0x%x\n", cmdrsp, + cmdrsp->scsitaskmgmt.notify); + *(int *) cmdrsp->scsitaskmgmt.notifyresult = + TASK_MGMT_FAILED; + wake_up_all((wait_queue_head_t *) + cmdrsp->scsitaskmgmt.notify); + break; + case CMD_VDISKMGMT_TYPE: + cmdrsp = (struct uiscmdrsp *) pendingdel->sent; + *(int *) cmdrsp->vdiskmgmt.notifyresult = + VDISK_MGMT_FAILED; + wake_up_all((wait_queue_head_t *) + cmdrsp->vdiskmgmt.notify); + break; + default: + if (pendingdel->sent != NULL) + LOGERR("Unknown command type: 0x%x. Only freeing list structure.\n", + pendingdel->cmdtype); + } + pendingdel->cmdtype = 0; + pendingdel->sent = NULL; + } + spin_unlock_irqrestore(&virthbainfo->privlock, flags); + + virtpcidev = virthbainfo->virtpcidev; + + DBGINF("virtpcidev busNo<<%d>>devNo<<%d>>", virtpcidev->busNo, + virtpcidev->deviceNo); + virthbainfo->serverdown = true; + virthbainfo->serverchangingstate = false; + /* Return the ServerDown response to Command */ + device_pause_response(virtpcidev->busNo, virtpcidev->deviceNo, 0); +} + +/* As per VirtpciFunc returns 1 for success and 0 for failure */ +static int +virthba_serverdown(struct virtpci_dev *virtpcidev, u32 state) +{ + struct virthba_info *virthbainfo = + (struct virthba_info *) ((struct Scsi_Host *) virtpcidev->scsi. + scsihost)->hostdata; + + DBGINF("virthba_serverdown"); + DBGINF("virtpcidev busNo<<%d>>devNo<<%d>>", virtpcidev->busNo, + virtpcidev->deviceNo); + + if (!virthbainfo->serverdown && !virthbainfo->serverchangingstate) { + virthbainfo->serverchangingstate = true; + queue_work(virthba_serverdown_workqueue, + &virthbainfo->serverdown_completion); + } else if (virthbainfo->serverchangingstate) { + LOGERR("Server already processing change state message\n"); + return 0; + } else + LOGERR("Server already down, but another server down message received."); + + return 1; +} + +/*****************************************************/ +/* Module Init & Exit functions */ +/*****************************************************/ + +static int __init +virthba_parse_line(char *str) +{ + DBGINF("In virthba_parse_line %s\n", str); + return 1; +} + +static void __init +virthba_parse_options(char *line) +{ + char *next = line; + + POSTCODE_LINUX_2(VHBA_CREATE_ENTRY_PC, POSTCODE_SEVERITY_INFO); + if (line == NULL || !*line) + return; + while ((line = next) != NULL) { + next = strchr(line, ' '); + if (next != NULL) + *next++ = 0; + if (!virthba_parse_line(line)) + DBGINF("Unknown option '%s'\n", line); + } + + POSTCODE_LINUX_2(VHBA_CREATE_EXIT_PC, POSTCODE_SEVERITY_INFO); +} + +static int __init +virthba_mod_init(void) +{ + int error; + int i; + + LOGINF("Entering virthba_mod_init...\n"); + + POSTCODE_LINUX_2(VHBA_CREATE_ENTRY_PC, POSTCODE_SEVERITY_INFO); + virthba_parse_options(virthba_options); + + error = virtpci_register_driver(&virthba_driver); + if (error < 0) { + LOGERR("register ****FAILED 0x%x\n", error); + POSTCODE_LINUX_3(VHBA_CREATE_FAILURE_PC, error, + POSTCODE_SEVERITY_ERR); + } else { + /* create the proc directories */ + virthba_proc_dir = proc_mkdir(DIR_PROC_ENTRY, NULL); + info_proc_entry = proc_create(INFO_PROC_ENTRY_FN, 0, + virthba_proc_dir, + &proc_info_fops); + rqwaitus_proc_entry = proc_create(RQWU_PROC_ENTRY_FN, 0, + virthba_proc_dir, + &proc_rqwu_fops); + enable_ints_proc_entry = proc_create(ENABLE_INTS_ENTRY_FN, 0, + virthba_proc_dir, + &proc_enable_ints_fops); + + /* Initialize DARWorkQ */ + INIT_WORK(&DARWorkQ, doDiskAddRemove); + spin_lock_init(&DARWorkQLock); + + /* clear out array */ + for (i = 0; i < VIRTHBASOPENMAX; i++) + VirtHbasOpen[i].virthbainfo = NULL; + /* Initialize the serverdown workqueue */ + virthba_serverdown_workqueue = + create_singlethread_workqueue("virthba_serverdown"); + if (virthba_serverdown_workqueue == NULL) { + LOGERR("**** FAILED virthba_serverdown_workqueue creation\n"); + POSTCODE_LINUX_2(VHBA_CREATE_FAILURE_PC, + POSTCODE_SEVERITY_ERR); + error = -1; + } + } + + POSTCODE_LINUX_2(VHBA_CREATE_EXIT_PC, POSTCODE_SEVERITY_INFO); + LOGINF("Leaving virthba_mod_init\n"); + return error; +} + +static ssize_t +virthba_acquire_lun(struct device *cdev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct uisscsi_dest vdest; + struct Scsi_Host *shost = class_to_shost(cdev); + int i; + + i = sscanf(buf, "%d-%d-%d", &vdest.channel, &vdest.id, &vdest.lun); + if (i != 3) + return i; + + return forward_vdiskmgmt_command(VDISK_MGMT_ACQUIRE, shost, &vdest); +} + +static ssize_t +virthba_release_lun(struct device *cdev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct uisscsi_dest vdest; + struct Scsi_Host *shost = class_to_shost(cdev); + int i; + + i = sscanf(buf, "%d-%d-%d", &vdest.channel, &vdest.id, &vdest.lun); + if (i != 3) + return i; + + return forward_vdiskmgmt_command(VDISK_MGMT_RELEASE, shost, &vdest); +} + +#define CLASS_DEVICE_ATTR(_name, _mode, _show, _store) \ + struct device_attribute class_device_attr_##_name = \ + __ATTR(_name, _mode, _show, _store) + +static CLASS_DEVICE_ATTR(acquire_lun, S_IWUSR, NULL, virthba_acquire_lun); +static CLASS_DEVICE_ATTR(release_lun, S_IWUSR, NULL, virthba_release_lun); + +static DEVICE_ATTRIBUTE *virthba_shost_attrs[] = { + &class_device_attr_acquire_lun, + &class_device_attr_release_lun, + NULL +}; + +static void __exit +virthba_mod_exit(void) +{ + LOGINF("entering virthba_mod_exit...\n"); + + virtpci_unregister_driver(&virthba_driver); + /* unregister is going to call virthba_remove */ + /* destroy serverdown completion workqueue */ + if (virthba_serverdown_workqueue) { + destroy_workqueue(virthba_serverdown_workqueue); + virthba_serverdown_workqueue = NULL; + } + + if (info_proc_entry) + remove_proc_entry(INFO_PROC_ENTRY_FN, virthba_proc_dir); + + if (rqwaitus_proc_entry) + remove_proc_entry(RQWU_PROC_ENTRY_FN, NULL); + + if (enable_ints_proc_entry) + remove_proc_entry(ENABLE_INTS_ENTRY_FN, NULL); + + if (virthba_proc_dir) + remove_proc_entry(DIR_PROC_ENTRY, NULL); + + LOGINF("Leaving virthba_mod_exit\n"); + +} + +/* specify function to be run at module insertion time */ +module_init(virthba_mod_init); + +/* specify function to be run when module is removed */ +module_exit(virthba_mod_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Usha Srinivasan"); +MODULE_ALIAS("uisvirthba"); + /* this is extracted during depmod and kept in modules.dep */ +/* module parameter */ +module_param(virthba_options, charp, S_IRUGO); diff --git a/drivers/staging/unisys/virthba/virthba.h b/drivers/staging/unisys/virthba/virthba.h new file mode 100644 index 00000000000..88b797439a1 --- /dev/null +++ b/drivers/staging/unisys/virthba/virthba.h @@ -0,0 +1,31 @@ +/* virthba.h + * + * Copyright © 2010 - 2013 UNISYS CORPORATION + * 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. + */ + +/* + * Unisys Virtual HBA driver header + */ + + + +#ifndef __VIRTHBA_H__ +#define __VIRTHBA_H__ + + +#define VIRTHBA_VERSION "01.00" + + +#endif /* __VIRTHBA_H__ */ diff --git a/drivers/staging/unisys/virtpci/Kconfig b/drivers/staging/unisys/virtpci/Kconfig new file mode 100644 index 00000000000..e59efcbc4d3 --- /dev/null +++ b/drivers/staging/unisys/virtpci/Kconfig @@ -0,0 +1,10 @@ +# +# Unisys virtpci configuration +# + +config UNISYS_VIRTPCI + tristate "Unisys virtpci driver" + depends on UNISYSSPAR && UNISYS_UISLIB + ---help--- + If you say Y here, you will enable the Unisys virtpci driver. + diff --git a/drivers/staging/unisys/virtpci/Makefile b/drivers/staging/unisys/virtpci/Makefile new file mode 100644 index 00000000000..f9399aabddd --- /dev/null +++ b/drivers/staging/unisys/virtpci/Makefile @@ -0,0 +1,13 @@ +# +# Makefile for Unisys virtpci +# + +obj-$(CONFIG_UNISYS_VIRTPCI) += virtpci.o + +ccflags-y += -Idrivers/staging/unisys/include +ccflags-y += -Idrivers/staging/unisys/uislib +ccflags-y += -Idrivers/staging/unisys/common-spar/include +ccflags-y += -Idrivers/staging/unisys/common-spar/include/channels + +ccflags-y += -DCONFIG_SPAR_GUEST -DGUESTDRIVERBUILD -DNOAUTOVERSION + diff --git a/drivers/staging/unisys/virtpci/virtpci.c b/drivers/staging/unisys/virtpci/virtpci.c new file mode 100644 index 00000000000..5700e4b3686 --- /dev/null +++ b/drivers/staging/unisys/virtpci/virtpci.c @@ -0,0 +1,1755 @@ +/* virtpci.c + * + * Copyright © 2010 - 2013 UNISYS CORPORATION + * 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. + */ + +#define EXPORT_SYMTAB + +#include <linux/kernel.h> +#ifdef CONFIG_MODVERSIONS +#include <config/modversions.h> +#endif +#include "uniklog.h" +#include "diagnostics/appos_subsystems.h" +#include "uisutils.h" +#include "commontypes.h" +#include "vbuschannel.h" +#include "vbushelper.h" +#include <linux/module.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/device.h> +#include <linux/list.h> +#include <linux/slab.h> +#include <linux/mod_devicetable.h> +#include <linux/proc_fs.h> +#include <linux/if_ether.h> +#include <linux/version.h> +#include "version.h" +#include "guestlinuxdebug.h" + +struct driver_private { + struct kobject kobj; + struct klist klist_devices; + struct klist_node knode_bus; + struct module_kobject *mkobj; + struct device_driver *driver; +}; +#define to_driver(obj) container_of(obj, struct driver_private, kobj) + +/* bus_id went away in 2.6.30 - the size was 20 bytes, so we'll define + * it ourselves, and a macro to make getting the field a bit simpler. + */ +#ifndef BUS_ID_SIZE +#define BUS_ID_SIZE 20 +#endif + +#define BUS_ID(x) dev_name(x) + +#include "virtpci.h" + +/* this is shorter than using __FILE__ (full path name) in + * debug/info/error messages + */ +#define CURRENT_FILE_PC VIRT_PCI_PC_virtpci_c +#define __MYFILE__ "virtpci.c" + +#define VIRTPCI_VERSION "01.00" + +/*****************************************************/ +/* Forward declarations */ +/*****************************************************/ + +static int delete_vbus_device(struct device *vbus, void *data); +static int match_busid(struct device *dev, void *data); +static void virtpci_bus_release(struct device *dev); +static void virtpci_device_release(struct device *dev); +static int virtpci_device_add(struct device *parentbus, int devtype, + struct add_virt_guestpart *addparams, + struct scsi_adap_info *scsi, + struct net_adap_info *net); +static int virtpci_device_del(struct device *parentbus, int devtype, + struct vhba_wwnn *wwnn, unsigned char macaddr[]); +static int virtpci_device_serverdown(struct device *parentbus, int devtype, + struct vhba_wwnn *wwnn, + unsigned char macaddr[]); +static int virtpci_device_serverup(struct device *parentbus, int devtype, + struct vhba_wwnn *wwnn, + unsigned char macaddr[]); +static ssize_t virtpci_driver_attr_show(struct kobject *kobj, + struct attribute *attr, char *buf); +static ssize_t virtpci_driver_attr_store(struct kobject *kobj, + struct attribute *attr, + const char *buf, size_t count); +static int virtpci_bus_match(struct device *dev, struct device_driver *drv); +static int virtpci_uevent(struct device *dev, struct kobj_uevent_env *env); +static int virtpci_device_suspend(struct device *dev, pm_message_t state); +static int virtpci_device_resume(struct device *dev); +static int virtpci_device_probe(struct device *dev); +static int virtpci_device_remove(struct device *dev); +static ssize_t virt_proc_write(struct file *file, const char __user *buffer, + size_t count, loff_t *ppos); +static ssize_t info_proc_read(struct file *file, char __user *buf, + size_t len, loff_t *offset); + +static const struct file_operations proc_virt_fops = { + .write = virt_proc_write, +}; + +static const struct file_operations proc_info_fops = { + .read = info_proc_read, +}; + +/*****************************************************/ +/* Globals */ +/*****************************************************/ + +/* methods in bus_type struct allow the bus code to serve as an + * intermediary between the device core and individual device core and + * individual drivers + */ +static struct bus_type virtpci_bus_type = { + .name = "uisvirtpci", + .match = virtpci_bus_match, + .uevent = virtpci_uevent, + .suspend = virtpci_device_suspend, + .resume = virtpci_device_resume, +}; + +static struct device virtpci_rootbus_device = { + .init_name = "vbusroot", /* root bus */ + .release = virtpci_bus_release +}; + +/* filled in with info about parent chipset driver when we register with it */ +static ULTRA_VBUS_DEVICEINFO Chipset_DriverInfo; + +static const struct sysfs_ops virtpci_driver_sysfs_ops = { + .show = virtpci_driver_attr_show, + .store = virtpci_driver_attr_store, +}; + +static struct kobj_type virtpci_driver_kobj_type = { + .sysfs_ops = &virtpci_driver_sysfs_ops, +}; + +static struct virtpci_dev *VpcidevListHead; +static DEFINE_RWLOCK(VpcidevListLock); + +/* filled in with info about this driver, wrt it servicing client busses */ +static ULTRA_VBUS_DEVICEINFO Bus_DriverInfo; + +/* virtpci_proc_dir_entry is used to create the proc entry directory + * for virtpci + */ +static struct proc_dir_entry *virtpci_proc_dir; +/* virt_proc_entry is used to tell virtpci to add/delete vhbas/vnics/vbuses */ +static struct proc_dir_entry *virt_proc_entry; +/* info_proc_entry is used to tell virtpci to display current info + * kept in the driver + */ +static struct proc_dir_entry *info_proc_entry; +#define VIRT_PROC_ENTRY_FN "virt" +#define INFO_PROC_ENTRY_FN "info" +#define DIR_PROC_ENTRY "virtpci" + +struct virtpci_busdev { + struct device virtpci_bus_device; +}; + +/*****************************************************/ +/* Local functions */ +/*****************************************************/ + +static inline int WAIT_FOR_IO_CHANNEL(ULTRA_IO_CHANNEL_PROTOCOL *chanptr) +{ + int count = 120; + while (count > 0) { + + if (ULTRA_CHANNEL_SERVER_READY(&chanptr->ChannelHeader)) + return 1; + UIS_THREAD_WAIT_SEC(1); + count--; + } + return 0; +} + +/* Write the contents of <info> to the ULTRA_VBUS_CHANNEL_PROTOCOL.ChpInfo. */ +static int write_vbus_chpInfo(ULTRA_VBUS_CHANNEL_PROTOCOL *chan, + ULTRA_VBUS_DEVICEINFO *info) +{ + int off; + if (!chan) { + LOGERR("vbus channel not present"); + return -1; + } + off = sizeof(ULTRA_CHANNEL_PROTOCOL) + chan->HdrInfo.chpInfoByteOffset; + if (chan->HdrInfo.chpInfoByteOffset == 0) { + LOGERR("vbus channel not used, because chpInfoByteOffset == 0"); + return -1; + } + memcpy(((U8 *) (chan)) + off, info, sizeof(*info)); + return 0; +} + +/* Write the contents of <info> to the ULTRA_VBUS_CHANNEL_PROTOCOL.BusInfo. */ +static int write_vbus_busInfo(ULTRA_VBUS_CHANNEL_PROTOCOL *chan, + ULTRA_VBUS_DEVICEINFO *info) +{ + int off; + if (!chan) { + LOGERR("vbus channel not present"); + return -1; + } + off = sizeof(ULTRA_CHANNEL_PROTOCOL) + chan->HdrInfo.busInfoByteOffset; + if (chan->HdrInfo.busInfoByteOffset == 0) { + LOGERR("vbus channel not used, because busInfoByteOffset == 0"); + return -1; + } + memcpy(((U8 *) (chan)) + off, info, sizeof(*info)); + return 0; +} + +/* Write the contents of <info> to the + * ULTRA_VBUS_CHANNEL_PROTOCOL.DevInfo[<devix>]. + */ +static int +write_vbus_devInfo(ULTRA_VBUS_CHANNEL_PROTOCOL *chan, + ULTRA_VBUS_DEVICEINFO *info, int devix) +{ + int off; + if (!chan) { + LOGERR("vbus channel not present"); + return -1; + } + off = + (sizeof(ULTRA_CHANNEL_PROTOCOL) + + chan->HdrInfo.devInfoByteOffset) + + (chan->HdrInfo.deviceInfoStructBytes * devix); + if (chan->HdrInfo.devInfoByteOffset == 0) { + LOGERR("vbus channel not used, because devInfoByteOffset == 0"); + return -1; + } + memcpy(((U8 *) (chan)) + off, info, sizeof(*info)); + return 0; +} + +/* adds a vbus + * returns 0 failure, 1 success, + */ +static int add_vbus(struct add_vbus_guestpart *addparams) +{ + int ret; + struct device *vbus; + vbus = kmalloc(sizeof(struct device), GFP_ATOMIC); + + POSTCODE_LINUX_2(VPCI_CREATE_ENTRY_PC, POSTCODE_SEVERITY_INFO); + if (!vbus) + return 0; + + memset(vbus, 0, sizeof(struct device)); + dev_set_name(vbus, "vbus%d", addparams->busNo); + vbus->release = virtpci_bus_release; + vbus->parent = &virtpci_rootbus_device; /* root bus is parent */ + vbus->bus = &virtpci_bus_type; /* bus type */ + vbus->platform_data = addparams->chanptr; + + /* register a virt bus device - + * this bus shows up under /sys/devices with .name value + * "virtpci%d" any devices added to this bus then show up under + * /sys/devices/virtpci0 + */ + ret = device_register(vbus); + if (ret) { + LOGERR("device_register FAILED:%d\n", ret); + POSTCODE_LINUX_2(VPCI_CREATE_FAILURE_PC, POSTCODE_SEVERITY_ERR); + return 0; + } + write_vbus_chpInfo(vbus->platform_data /* chanptr */ , + &Chipset_DriverInfo); + write_vbus_busInfo(vbus->platform_data /* chanptr */ , &Bus_DriverInfo); + LOGINF("Added vbus %d; device %s created successfully\n", + addparams->busNo, BUS_ID(vbus)); + POSTCODE_LINUX_2(VPCI_CREATE_EXIT_PC, POSTCODE_SEVERITY_INFO); + return 1; +} + +/* for CHANSOCK wwwnn/max are AUTO-GENERATED; for normal channels, + * wwnn/max are in the channel header. + */ +#define GET_SCSIADAPINFO_FROM_CHANPTR(chanptr) { \ + scsi.wwnn = ((ULTRA_IO_CHANNEL_PROTOCOL *) chanptr)->vhba.wwnn; \ + scsi.max = ((ULTRA_IO_CHANNEL_PROTOCOL *) chanptr)->vhba.max; \ +} + +/* find bus device with the busid that matches - match_busid matches bus_id */ +#define GET_BUS_DEV(busno) { \ + sprintf(busid, "vbus%d", busno); \ + vbus = bus_find_device(&virtpci_bus_type, NULL, \ + (void *)busid, match_busid); \ + if (!vbus) { \ + LOGERR("**** FAILED to find vbus %s\n", busid); \ + return 0; \ + } \ +} + +/* adds a vhba + * returns 0 failure, 1 success, + */ +static int add_vhba(struct add_virt_guestpart *addparams) +{ + int i; + struct scsi_adap_info scsi; + struct device *vbus; + unsigned char busid[BUS_ID_SIZE]; + + POSTCODE_LINUX_2(VPCI_CREATE_ENTRY_PC, POSTCODE_SEVERITY_INFO); + if (!WAIT_FOR_IO_CHANNEL + ((ULTRA_IO_CHANNEL_PROTOCOL *) addparams->chanptr)) { + LOGERR("Timed out. Channel not ready\n"); + POSTCODE_LINUX_2(VPCI_CREATE_FAILURE_PC, POSTCODE_SEVERITY_ERR); + return 0; + } + + GET_SCSIADAPINFO_FROM_CHANPTR(addparams->chanptr); + + GET_BUS_DEV(addparams->busNo); + + LOGINF("Adding vhba wwnn:%x:%x config:%d-%d-%d-%d chanptr:%p\n", + scsi.wwnn.wwnn1, scsi.wwnn.wwnn2, + scsi.max.max_channel, scsi.max.max_id, scsi.max.max_lun, + scsi.max.cmd_per_lun, addparams->chanptr); + i = virtpci_device_add(vbus, VIRTHBA_TYPE, addparams, &scsi, NULL); + if (i) { + LOGINF("Added vhba wwnn:%x:%x chanptr:%p\n", scsi.wwnn.wwnn1, + scsi.wwnn.wwnn2, addparams->chanptr); + POSTCODE_LINUX_3(VPCI_CREATE_EXIT_PC, i, + POSTCODE_SEVERITY_INFO); + } + return i; + +} + +/* for CHANSOCK macaddr is AUTO-GENERATED; for normal channels, + * macaddr is in the channel header. + */ +#define GET_NETADAPINFO_FROM_CHANPTR(chanptr) { \ + memcpy(net.mac_addr, ((ULTRA_IO_CHANNEL_PROTOCOL *) chanptr)->vnic.macaddr, MAX_MACADDR_LEN); \ + net.num_rcv_bufs = ((ULTRA_IO_CHANNEL_PROTOCOL *) chanptr)->vnic.num_rcv_bufs; \ + net.mtu = ((ULTRA_IO_CHANNEL_PROTOCOL *) chanptr)->vnic.mtu; \ + net.zoneGuid = ((ULTRA_IO_CHANNEL_PROTOCOL *) chanptr)->vnic.zoneGuid; \ +} + +/* adds a vnic + * returns 0 failure, 1 success, + */ +static int +add_vnic(struct add_virt_guestpart *addparams) +{ + int i; + struct net_adap_info net; + struct device *vbus; + unsigned char busid[BUS_ID_SIZE]; + + POSTCODE_LINUX_2(VPCI_CREATE_ENTRY_PC, POSTCODE_SEVERITY_INFO); + if (!WAIT_FOR_IO_CHANNEL + ((ULTRA_IO_CHANNEL_PROTOCOL *) addparams->chanptr)) { + LOGERR("Timed out, channel not ready\n"); + POSTCODE_LINUX_2(VPCI_CREATE_FAILURE_PC, POSTCODE_SEVERITY_ERR); + return 0; + } + + GET_NETADAPINFO_FROM_CHANPTR(addparams->chanptr); + + GET_BUS_DEV(addparams->busNo); + + LOGINF("Adding vnic macaddr:%02x:%02x:%02x:%02x:%02x:%02x rcvbufs:%d mtu:%d chanptr:%p{%-8.8lx-%-4.4x-%-4.4x-%-2.2x%-2.2x%-2.2x%-2.2x%-2.2x%-2.2x%-2.2x%-2.2x}\n", + net.mac_addr[0], net.mac_addr[1], net.mac_addr[2], net.mac_addr[3], + net.mac_addr[4], net.mac_addr[5], net.num_rcv_bufs, net.mtu, + addparams->chanptr, (ulong) net.zoneGuid.data1, net.zoneGuid.data2, + net.zoneGuid.data3, net.zoneGuid.data4[0], net.zoneGuid.data4[1], + net.zoneGuid.data4[2], net.zoneGuid.data4[3], + net.zoneGuid.data4[4], net.zoneGuid.data4[5], + net.zoneGuid.data4[6], net.zoneGuid.data4[7]); + i = virtpci_device_add(vbus, VIRTNIC_TYPE, addparams, NULL, &net); + if (i) { + LOGINF("Added vnic macaddr:%02x:%02x:%02x:%02x:%02x:%02x\n", + net.mac_addr[0], net.mac_addr[1], net.mac_addr[2], + net.mac_addr[3], net.mac_addr[4], net.mac_addr[5]); + POSTCODE_LINUX_3(VPCI_CREATE_EXIT_PC, i, + POSTCODE_SEVERITY_INFO); + return 1; + } + return 0; +} + +/* delete vbus + * returns 0 failure, 1 success, + */ +static int +delete_vbus(struct del_vbus_guestpart *delparams) +{ + struct device *vbus; + unsigned char busid[BUS_ID_SIZE]; + + GET_BUS_DEV(delparams->busNo); + /* ensure that bus has no devices? -- TBD */ + LOGINF("Deleting %s\n", BUS_ID(vbus)); + if (delete_vbus_device(vbus, NULL)) + return 0; /* failure */ + LOGINF("Deleted vbus %d\n", delparams->busNo); + return 1; +} + +static int +delete_vbus_device(struct device *vbus, void *data) +{ + int checkforroot = (data != NULL); + struct device *pDev = &virtpci_rootbus_device; + + if ((checkforroot) && match_busid(vbus, (void *) BUS_ID(pDev))) { + /* skip it - don't delete root bus */ + LOGINF("skipping root bus\n"); + return 0; /* pretend no error */ + } + LOGINF("Calling unregister for %s\n", BUS_ID(vbus)); + device_unregister(vbus); + kfree(vbus); + LOGINF("VBus unregister and freed\n"); + return 0; /* no error */ +} + +/* pause vhba +* returns 0 failure, 1 success, +*/ +static int pause_vhba(struct pause_virt_guestpart *pauseparams) +{ + int i; + struct scsi_adap_info scsi; + + GET_SCSIADAPINFO_FROM_CHANPTR(pauseparams->chanptr); + + LOGINF("Pausing vhba wwnn:%x:%x\n", scsi.wwnn.wwnn1, scsi.wwnn.wwnn2); + i = virtpci_device_serverdown(NULL /*no parent bus */ , VIRTHBA_TYPE, + &scsi.wwnn, NULL); + if (i) + LOGINF("Paused vhba wwnn:%x:%x\n", scsi.wwnn.wwnn1, + scsi.wwnn.wwnn2); + return i; +} + +/* pause vnic + * returns 0 failure, 1 success, + */ +static int pause_vnic(struct pause_virt_guestpart *pauseparams) +{ + int i; + struct net_adap_info net; + + GET_NETADAPINFO_FROM_CHANPTR(pauseparams->chanptr); + + LOGINF("Pausing vnic macaddr:%02x:%02x:%02x:%02x:%02x:%02x\n", + net.mac_addr[0], net.mac_addr[1], net.mac_addr[2], + net.mac_addr[3], net.mac_addr[4], net.mac_addr[5]); + i = virtpci_device_serverdown(NULL /*no parent bus */ , VIRTNIC_TYPE, + NULL, net.mac_addr); + if (i) { + LOGINF(" Paused vnic macaddr:%02x:%02x:%02x:%02x:%02x:%02x\n", + net.mac_addr[0], net.mac_addr[1], net.mac_addr[2], + net.mac_addr[3], net.mac_addr[4], net.mac_addr[5]); + } + return i; +} + +/* resume vhba + * returns 0 failure, 1 success, + */ +static int resume_vhba(struct resume_virt_guestpart *resumeparams) +{ + int i; + struct scsi_adap_info scsi; + + GET_SCSIADAPINFO_FROM_CHANPTR(resumeparams->chanptr); + + LOGINF("Resuming vhba wwnn:%x:%x\n", scsi.wwnn.wwnn1, scsi.wwnn.wwnn2); + i = virtpci_device_serverup(NULL /*no parent bus */ , VIRTHBA_TYPE, + &scsi.wwnn, NULL); + if (i) + LOGINF("Resumed vhba wwnn:%x:%x\n", scsi.wwnn.wwnn1, + scsi.wwnn.wwnn2); + return i; +} + +/* resume vnic +* returns 0 failure, 1 success, +*/ +static int +resume_vnic(struct resume_virt_guestpart *resumeparams) +{ + int i; + struct net_adap_info net; + + GET_NETADAPINFO_FROM_CHANPTR(resumeparams->chanptr); + + LOGINF("Resuming vnic macaddr:%02x:%02x:%02x:%02x:%02x:%02x\n", + net.mac_addr[0], net.mac_addr[1], net.mac_addr[2], + net.mac_addr[3], net.mac_addr[4], net.mac_addr[5]); + i = virtpci_device_serverup(NULL /*no parent bus */ , VIRTNIC_TYPE, + NULL, net.mac_addr); + if (i) { + LOGINF(" Resumed vnic macaddr:%02x:%02x:%02x:%02x:%02x:%02x\n", + net.mac_addr[0], net.mac_addr[1], net.mac_addr[2], + net.mac_addr[3], net.mac_addr[4], net.mac_addr[5]); + } + return i; +} + +/* delete vhba +* returns 0 failure, 1 success, +*/ +static int delete_vhba(struct del_virt_guestpart *delparams) +{ + int i; + struct scsi_adap_info scsi; + + GET_SCSIADAPINFO_FROM_CHANPTR(delparams->chanptr); + + LOGINF("Deleting vhba wwnn:%x:%x\n", scsi.wwnn.wwnn1, scsi.wwnn.wwnn2); + i = virtpci_device_del(NULL /*no parent bus */ , VIRTHBA_TYPE, + &scsi.wwnn, NULL); + if (i) { + LOGINF("Deleted vhba wwnn:%x:%x\n", scsi.wwnn.wwnn1, + scsi.wwnn.wwnn2); + return 1; + } + return 0; +} + +/* deletes a vnic + * returns 0 failure, 1 success, + */ +static int delete_vnic(struct del_virt_guestpart *delparams) +{ + int i; + struct net_adap_info net; + + GET_NETADAPINFO_FROM_CHANPTR(delparams->chanptr); + + LOGINF("Deleting vnic macaddr:%02x:%02x:%02x:%02x:%02x:%02x\n", + net.mac_addr[0], net.mac_addr[1], net.mac_addr[2], + net.mac_addr[3], net.mac_addr[4], net.mac_addr[5]); + i = virtpci_device_del(NULL /*no parent bus */ , VIRTNIC_TYPE, NULL, + net.mac_addr); + if (i) { + LOGINF("Deleted vnic macaddr:%02x:%02x:%02x:%02x:%02x:%02x\n", + net.mac_addr[0], net.mac_addr[1], net.mac_addr[2], + net.mac_addr[3], net.mac_addr[4], net.mac_addr[5]); + } + return i; +} + +#define DELETE_ONE_VPCIDEV(vpcidev) { \ + LOGINF("calling device_unregister:%p\n", &vpcidev->generic_dev); \ + device_unregister(&vpcidev->generic_dev); \ + LOGINF("Deleted %p\n", vpcidev); \ + kfree(vpcidev); \ +} + +/* deletes all vhbas and vnics + * returns 0 failure, 1 success, + */ +static void delete_all(void) +{ + int count = 0; + unsigned long flags; + struct virtpci_dev *tmpvpcidev, *nextvpcidev; + + /* delete the entire vhba/vnic list in one shot */ + write_lock_irqsave(&VpcidevListLock, flags); + tmpvpcidev = VpcidevListHead; + VpcidevListHead = NULL; + write_unlock_irqrestore(&VpcidevListLock, flags); + + /* delete one vhba/vnic at a time */ + while (tmpvpcidev) { + nextvpcidev = tmpvpcidev->next; + /* delete the vhba/vnic at tmpvpcidev */ + DELETE_ONE_VPCIDEV(tmpvpcidev); + tmpvpcidev = nextvpcidev; + count++; + } + LOGINF("Deleted %d vhbas/vnics.\n", count); + + /* now delete each vbus */ + if (bus_for_each_dev + (&virtpci_bus_type, NULL, (void *) 1, delete_vbus_device)) + LOGERR("delete of all vbus failed\n"); +} + +/* deletes all vnics or vhbas + * returns 0 failure, 1 success, + */ +static int delete_all_virt(VIRTPCI_DEV_TYPE devtype, struct del_vbus_guestpart *delparams) +{ + int i; + unsigned char busid[BUS_ID_SIZE]; + struct device *vbus; + + GET_BUS_DEV(delparams->busNo); + + if ((devtype != VIRTHBA_TYPE) && (devtype != VIRTNIC_TYPE)) { + LOGERR("**** FAILED to delete all devices; devtype:%d not vhba:%d or vnic:%d\n", + devtype, VIRTHBA_TYPE, VIRTNIC_TYPE); + return 0; + } + + LOGINF("Deleting all %s in vbus %s\n", + devtype == VIRTHBA_TYPE ? "vhbas" : "vnics", busid); + /* delete all vhbas/vnics */ + i = virtpci_device_del(vbus, devtype, NULL, NULL); + if (i > 0) + LOGINF("Deleted %d %s\n", i, + devtype == VIRTHBA_TYPE ? "vhbas" : "vnics"); + return 1; +} + +static int virtpci_ctrlchan_func(struct guest_msgs *msg) +{ + switch (msg->msgtype) { + case GUEST_ADD_VBUS: + return add_vbus(&msg->add_vbus); + case GUEST_ADD_VHBA: + return add_vhba(&msg->add_vhba); + case GUEST_ADD_VNIC: + return add_vnic(&msg->add_vnic); + case GUEST_DEL_VBUS: + return delete_vbus(&msg->del_vbus); + case GUEST_DEL_VHBA: + return delete_vhba(&msg->del_vhba); + case GUEST_DEL_VNIC: + return delete_vnic(&msg->del_vhba); + case GUEST_DEL_ALL_VHBAS: + return delete_all_virt(VIRTHBA_TYPE, &msg->del_all_vhbas); + case GUEST_DEL_ALL_VNICS: + return delete_all_virt(VIRTNIC_TYPE, &msg->del_all_vnics); + case GUEST_DEL_ALL_VBUSES: + delete_all(); + return 1; + case GUEST_PAUSE_VHBA: + return pause_vhba(&msg->pause_vhba); + case GUEST_PAUSE_VNIC: + return pause_vnic(&msg->pause_vnic); + case GUEST_RESUME_VHBA: + return resume_vhba(&msg->resume_vhba); + case GUEST_RESUME_VNIC: + return resume_vnic(&msg->resume_vnic); + default: + LOGERR("invalid message type %d.\n", msg->msgtype); + return 0; + } +} + +/* same as driver_helper in bus.c linux */ +static int match_busid(struct device *dev, void *data) +{ + const char *name = data; + + if (strcmp(name, BUS_ID(dev)) == 0) + return 1; + return 0; +} + +/*****************************************************/ +/* Bus functions */ +/*****************************************************/ + +const struct pci_device_id * +virtpci_match_device(const struct pci_device_id *ids, + const struct virtpci_dev *dev) +{ + while (ids->vendor || ids->subvendor || ids->class_mask) { + DBGINF("ids->vendor:%x dev->vendor:%x ids->device:%x dev->device:%x\n", + ids->vendor, dev->vendor, ids->device, dev->device); + + if ((ids->vendor == dev->vendor) + && (ids->device == dev->device)) + return ids; + + ids++; + } + return NULL; +} + +/* NOTE: !!!!!! This function is called when a new device is added +* for this bus. Or, it is called for existing devices when a new +* driver is added for this bus. It returns nonzero if a given device +* can be handled by the given driver. +*/ +static int virtpci_bus_match(struct device *dev, struct device_driver *drv) +{ + struct virtpci_dev *virtpcidev = device_to_virtpci_dev(dev); + struct virtpci_driver *virtpcidrv = driver_to_virtpci_driver(drv); + int match = 0; + + DBGINF("In virtpci_bus_match dev->bus_id:%s drv->name:%s\n", + dev->bus_id, drv->name); + + /* check ids list for a match */ + if (virtpci_match_device(virtpcidrv->id_table, virtpcidev)) + match = 1; + + DBGINF("returning match:%d\n", match); + return match; /* 0 - no match; 1 - yes it matches */ +} + +static int virtpci_uevent(struct device *dev, struct kobj_uevent_env *env) +{ + DBGINF("In virtpci_hotplug\n"); + /* add variables to the environment prior to the generation of + * hotplug events to user space + */ + if (add_uevent_var(env, "VIRTPCI_VERSION=%s", VIRTPCI_VERSION)) + return -ENOMEM; + return 0; +} + +static int virtpci_device_suspend(struct device *dev, pm_message_t state) +{ + DBGINF("In virtpci_device_suspend -NYI ****\n"); + return 0; +} + +static int virtpci_device_resume(struct device *dev) +{ + DBGINF("In virtpci_device_resume -NYI ****\n"); + return 0; +} + +/* For a child device just created on a client bus, fill in + * information about the driver that is controlling this device into + * the the appropriate slot within the vbus channel of the bus + * instance. + */ +static void fix_vbus_devInfo(struct device *dev, int devNo, int devType, + struct virtpci_driver *virtpcidrv) +{ + struct device *vbus; + void *pChan; + ULTRA_VBUS_DEVICEINFO devInfo; + const char *stype; + + if (!dev) { + LOGERR("%s dev is NULL", __func__); + return; + } + if (!virtpcidrv) { + LOGERR("%s driver is NULL", __func__); + return; + } + vbus = dev->parent; + if (!vbus) { + LOGERR("%s dev has no parent bus", __func__); + return; + } + pChan = vbus->platform_data; + if (!pChan) { + LOGERR("%s dev bus has no channel", __func__); + return; + } + switch (devType) { + case PCI_DEVICE_ID_VIRTHBA: + stype = "vHBA"; + break; + case PCI_DEVICE_ID_VIRTNIC: + stype = "vNIC"; + break; + default: + stype = "unknown"; + break; + } + BusDeviceInfo_Init(&devInfo, stype, + virtpcidrv->name, + virtpcidrv->version, + virtpcidrv->vertag, + virtpcidrv->build_date, virtpcidrv->build_time); + write_vbus_devInfo(pChan, &devInfo, devNo); + + /* Re-write bus+chipset info, because it is possible that this + * was previously written by our good counterpart, visorbus. + */ + write_vbus_chpInfo(pChan, &Chipset_DriverInfo); + write_vbus_busInfo(pChan, &Bus_DriverInfo); +} + +/* This function is called to query the existence of a specific device +* and whether this driver can work with it. It should return -ENODEV +* in case of failure. +*/ +static int virtpci_device_probe(struct device *dev) +{ + struct virtpci_dev *virtpcidev = device_to_virtpci_dev(dev); + struct virtpci_driver *virtpcidrv = + driver_to_virtpci_driver(dev->driver); + const struct pci_device_id *id; + int error = 0; + + LOGINF("In virtpci_device_probe dev:%p virtpcidev:%p virtpcidrv:%p\n", + dev, virtpcidev, virtpcidrv); /* VERBOSE/DEBUG ? */ + POSTCODE_LINUX_2(VPCI_PROBE_ENTRY_PC, POSTCODE_SEVERITY_INFO); + /* static match and static probe vs dynamic match & dynamic + * probe - do we care?. + */ + if (!virtpcidrv->id_table) + return -ENODEV; + + id = virtpci_match_device(virtpcidrv->id_table, virtpcidev); + if (!id) + return -ENODEV; + + /* increment reference count */ + get_device(dev); + + /* if virtpcidev is not already claimed & probe function is + * valid, probe it + */ + if (!virtpcidev->mydriver && virtpcidrv->probe) { + /* call the probe function - virthba or virtnic probe + * is what it should be + */ + error = virtpcidrv->probe(virtpcidev, id); + if (!error) { + fix_vbus_devInfo(dev, virtpcidev->deviceNo, + virtpcidev->device, virtpcidrv); + virtpcidev->mydriver = virtpcidrv; + POSTCODE_LINUX_2(VPCI_PROBE_EXIT_PC, + POSTCODE_SEVERITY_INFO); + } else + put_device(dev); + } + POSTCODE_LINUX_2(VPCI_PROBE_FAILURE_PC, POSTCODE_SEVERITY_ERR); + return error; /* -ENODEV for probe failure */ +} + +static int virtpci_device_remove(struct device *dev_) +{ + /* dev_ passed in is the HBA device which we called + * generic_dev in our virtpcidev struct + */ + struct virtpci_dev *virtpcidev = device_to_virtpci_dev(dev_); + struct virtpci_driver *virtpcidrv = virtpcidev->mydriver; + LOGINF("In virtpci_device_remove bus_id:%s dev_:%p virtpcidev:%p dev->driver:%p drivername:%s\n", + BUS_ID(dev_), dev_, virtpcidev, dev_->driver, + dev_->driver->name); /* VERBOSE/DEBUG */ + if (virtpcidrv) { + /* TEMP: assuming we have only one such driver for now */ + if (virtpcidrv->remove) + virtpcidrv->remove(virtpcidev); + virtpcidev->mydriver = NULL; + } + + DBGINF("calling putdevice\n"); + put_device(dev_); + + DBGINF("Leaving\n"); + return 0; +} + +/*****************************************************/ +/* Bus functions */ +/*****************************************************/ + +static void virtpci_bus_release(struct device *dev) +{ + /* this function is called when the last reference to the + * device is removed + */ + DBGINF("In virtpci_bus_release\n"); + /* what else is supposed to happen here? */ +} + +/*****************************************************/ +/* Adapter functions */ +/*****************************************************/ + +static int virtpci_device_add(struct device *parentbus, int devtype, + struct add_virt_guestpart *addparams, + struct scsi_adap_info *scsi, /* NULL for VNIC add */ + struct net_adap_info *net /* NULL for VHBA add */) +{ + struct virtpci_dev *virtpcidev = NULL; + struct virtpci_dev *tmpvpcidev = NULL, *prev; + unsigned long flags; + int ret; + ULTRA_IO_CHANNEL_PROTOCOL *pIoChan = NULL; + struct device *pDev; + + LOGINF("virtpci_device_add parentbus:%p chanptr:%p\n", parentbus, + addparams->chanptr); + + POSTCODE_LINUX_2(VPCI_CREATE_ENTRY_PC, POSTCODE_SEVERITY_INFO); + + if ((devtype != VIRTHBA_TYPE) && (devtype != VIRTNIC_TYPE)) { + LOGERR("**** FAILED to add device; devtype:%d not vhba:%d or vnic:%d\n", + devtype, VIRTHBA_TYPE, VIRTNIC_TYPE); + POSTCODE_LINUX_3(VPCI_CREATE_FAILURE_PC, devtype, + POSTCODE_SEVERITY_ERR); + return 0; + } + + /* add a Virtual Device */ + virtpcidev = kmalloc(sizeof(struct virtpci_dev), GFP_ATOMIC); + if (virtpcidev == NULL) { + LOGERR("can't add device - malloc FALLED\n"); + POSTCODE_LINUX_2(MALLOC_FAILURE_PC, POSTCODE_SEVERITY_ERR); + return 0; + } + + memset(virtpcidev, 0, sizeof(struct virtpci_dev)); + + /* initialize stuff unique to virtpci_dev struct */ + virtpcidev->devtype = devtype; + if (devtype == VIRTHBA_TYPE) { + virtpcidev->device = PCI_DEVICE_ID_VIRTHBA; + virtpcidev->scsi = *scsi; + } else { + virtpcidev->device = PCI_DEVICE_ID_VIRTNIC; + virtpcidev->net = *net; + } + virtpcidev->vendor = PCI_VENDOR_ID_UNISYS; + virtpcidev->busNo = addparams->busNo; + virtpcidev->deviceNo = addparams->deviceNo; + + virtpcidev->queueinfo.chan = addparams->chanptr; + virtpcidev->queueinfo.send_int_if_needed = NULL; + + /* Set up safe queue... */ + pIoChan = (ULTRA_IO_CHANNEL_PROTOCOL *) virtpcidev->queueinfo.chan; + + virtpcidev->intr = addparams->intr; + + /* initialize stuff in the device portion of the struct */ + virtpcidev->generic_dev.bus = &virtpci_bus_type; + virtpcidev->generic_dev.parent = parentbus; + virtpcidev->generic_dev.release = virtpci_device_release; + + dev_set_name(&virtpcidev->generic_dev, "%x:%x", + addparams->busNo, addparams->deviceNo); + + /* add the vhba/vnic to virtpci device list - but check for + * duplicate wwnn/macaddr first + */ + write_lock_irqsave(&VpcidevListLock, flags); + for (tmpvpcidev = VpcidevListHead; tmpvpcidev; + tmpvpcidev = tmpvpcidev->next) { + if (devtype == VIRTHBA_TYPE) { + if ((tmpvpcidev->scsi.wwnn.wwnn1 == scsi->wwnn.wwnn1) && + (tmpvpcidev->scsi.wwnn.wwnn2 == scsi->wwnn.wwnn2)) { + /* duplicate - already have vpcidev + with this wwnn */ + break; + } + } else + if (memcmp + (tmpvpcidev->net.mac_addr, net->mac_addr, + MAX_MACADDR_LEN) == 0) { + /* duplicate - already have vnic with this wwnn */ + break; + } + } + if (tmpvpcidev) { + /* found a vhba/vnic already in the list with same + * wwnn or macaddr - reject add + */ + write_unlock_irqrestore(&VpcidevListLock, flags); + kfree(virtpcidev); + LOGERR("**** FAILED vhba/vnic already exists in the list\n"); + POSTCODE_LINUX_2(VPCI_CREATE_FAILURE_PC, POSTCODE_SEVERITY_ERR); + return 0; + } + + /* add it at the head */ + if (!VpcidevListHead) + VpcidevListHead = virtpcidev; + else { + /* insert virtpcidev at the head of our linked list of + * vpcidevs + */ + virtpcidev->next = VpcidevListHead; + VpcidevListHead = virtpcidev; + } + + write_unlock_irqrestore(&VpcidevListLock, flags); + + /* Must transition channel to ATTACHED state BEFORE + * registering the device, because polling of the channel + * queues can begin at any time after device_register(). + */ + pDev = &virtpcidev->generic_dev; + ULTRA_CHANNEL_CLIENT_TRANSITION(addparams->chanptr, + BUS_ID(pDev), + CliStateOS, CHANNELCLI_ATTACHED, NULL); + + /* don't register until device has been added to + * list. Otherwise, a device_unregister from this function can + * cause a "scheduling while atomic". + */ + DBGINF("registering device:%p with bus_id:%s\n", + &virtpcidev->generic_dev, virtpcidev->generic_dev.bus_id); + ret = device_register(&virtpcidev->generic_dev); + /* NOTE: THIS IS CALLING HOTPLUG virtpci_hotplug!!! + * This call to device_register results in virtpci_bus_match + * being called !!!!! And, if match returns success, then + * virtpcidev->generic_dev.driver is setup to core_driver, + * i.e., virtpci and the probe function + * virtpcidev->generic_dev.driver->probe is called which + * results in virtpci_device_probe being called. And if + * virtpci_device_probe is successful + */ + if (ret) { + LOGERR("device_register returned %d\n", ret); + pDev = &virtpcidev->generic_dev; + ULTRA_CHANNEL_CLIENT_TRANSITION(addparams->chanptr, + BUS_ID(pDev), + CliStateOS, + CHANNELCLI_DETACHED, NULL); + /* remove virtpcidev, the one we just added, from the list */ + write_lock_irqsave(&VpcidevListLock, flags); + for (tmpvpcidev = VpcidevListHead, prev = NULL; + tmpvpcidev; + prev = tmpvpcidev, tmpvpcidev = tmpvpcidev->next) { + if (tmpvpcidev == virtpcidev) { + if (prev) + prev->next = tmpvpcidev->next; + else + VpcidevListHead = tmpvpcidev->next; + break; + } + } + write_unlock_irqrestore(&VpcidevListLock, flags); + kfree(virtpcidev); + return 0; + } + + LOGINF("Added %s:%d:%d &virtpcidev->generic_dev:%p\n", + (devtype == VIRTHBA_TYPE) ? "virthba" : "virtnic", + addparams->busNo, addparams->deviceNo, &virtpcidev->generic_dev); + POSTCODE_LINUX_2(VPCI_CREATE_EXIT_PC, POSTCODE_SEVERITY_INFO); + return 1; +} + +static int virtpci_device_serverdown(struct device *parentbus, + int devtype, + struct vhba_wwnn *wwnn, + unsigned char macaddr[]) +{ + int pausethisone = 0; + bool found = false; + struct virtpci_dev *tmpvpcidev, *prevvpcidev; + struct virtpci_driver *vpcidriver; + unsigned long flags; + int rc = 0; + + if ((devtype != VIRTHBA_TYPE) && (devtype != VIRTNIC_TYPE)) { + LOGERR("**** FAILED to pause device; devtype:%d not vhba:%d or vnic:%d\n", + devtype, VIRTHBA_TYPE, VIRTNIC_TYPE); + return 0; + } + + /* find the vhba or vnic in virtpci device list */ + write_lock_irqsave(&VpcidevListLock, flags); + + for (tmpvpcidev = VpcidevListHead, prevvpcidev = NULL; + (tmpvpcidev && !found); + prevvpcidev = tmpvpcidev, tmpvpcidev = tmpvpcidev->next) { + if (tmpvpcidev->devtype != devtype) + continue; + + if (devtype == VIRTHBA_TYPE) { + pausethisone = + ((tmpvpcidev->scsi.wwnn.wwnn1 == wwnn->wwnn1) && + (tmpvpcidev->scsi.wwnn.wwnn2 == wwnn->wwnn2)); + /* devtype is vhba, we're pausing vhba whose + * wwnn matches the current device's wwnn + */ + } else { /* VIRTNIC_TYPE */ + pausethisone = + memcmp(tmpvpcidev->net.mac_addr, macaddr, + MAX_MACADDR_LEN) == 0; + /* devtype is vnic, we're pausing vnic whose + * macaddr matches the current device's macaddr */ + } + + if (!pausethisone) + continue; + + found = true; + vpcidriver = tmpvpcidev->mydriver; + rc = vpcidriver->suspend(tmpvpcidev, 0); + } + write_unlock_irqrestore(&VpcidevListLock, flags); + + if (!found) { + LOGERR("**** FAILED to find vhba/vnic in the list\n"); + return 0; + } + + return rc; +} + +static int virtpci_device_serverup(struct device *parentbus, + int devtype, + struct vhba_wwnn *wwnn, + unsigned char macaddr[]) +{ + int resumethisone = 0; + bool found = false; + struct virtpci_dev *tmpvpcidev, *prevvpcidev; + struct virtpci_driver *vpcidriver; + unsigned long flags; + int rc = 0; + + if ((devtype != VIRTHBA_TYPE) && (devtype != VIRTNIC_TYPE)) { + LOGERR("**** FAILED to resume device; devtype:%d not vhba:%d or vnic:%d\n", + devtype, VIRTHBA_TYPE, VIRTNIC_TYPE); + return 0; + } + + /* find the vhba or vnic in virtpci device list */ + write_lock_irqsave(&VpcidevListLock, flags); + + for (tmpvpcidev = VpcidevListHead, prevvpcidev = NULL; + (tmpvpcidev && !found); + prevvpcidev = tmpvpcidev, tmpvpcidev = tmpvpcidev->next) { + if (tmpvpcidev->devtype != devtype) + continue; + + if (devtype == VIRTHBA_TYPE) { + resumethisone = + ((tmpvpcidev->scsi.wwnn.wwnn1 == wwnn->wwnn1) && + (tmpvpcidev->scsi.wwnn.wwnn2 == wwnn->wwnn2)); + /* devtype is vhba, we're resuming vhba whose + * wwnn matches the current device's wwnn */ + } else { /* VIRTNIC_TYPE */ + resumethisone = + memcmp(tmpvpcidev->net.mac_addr, macaddr, + MAX_MACADDR_LEN) == 0; + /* devtype is vnic, we're resuming vnic whose + * macaddr matches the current device's macaddr */ + } + + if (!resumethisone) + continue; + + found = true; + vpcidriver = tmpvpcidev->mydriver; + /* This should be done at BUS resume time, but an + * existing problem prevents us from ever getting a bus + * resume... This hack would fail to work should we + * ever have a bus that contains NO devices, since we + * would never even get here in that case. + */ + fix_vbus_devInfo(&tmpvpcidev->generic_dev, tmpvpcidev->deviceNo, + tmpvpcidev->device, vpcidriver); + rc = vpcidriver->resume(tmpvpcidev); + } + + write_unlock_irqrestore(&VpcidevListLock, flags); + + if (!found) { + LOGERR("**** FAILED to find vhba/vnic in the list\n"); + return 0; + } + + return rc; +} + +static int virtpci_device_del(struct device *parentbus, + int devtype, struct vhba_wwnn *wwnn, + unsigned char macaddr[]) +{ + int count = 0, all = 0, delthisone; + struct virtpci_dev *tmpvpcidev, *prevvpcidev, *dellist = NULL; + unsigned long flags; + +#define DEL_CONTINUE { \ + prevvpcidev = tmpvpcidev;\ + tmpvpcidev = tmpvpcidev->next;\ + continue; \ +} + + if ((devtype != VIRTHBA_TYPE) && (devtype != VIRTNIC_TYPE)) { + LOGERR("**** FAILED to delete device; devtype:%d not vhba:%d or vnic:%d\n", + devtype, VIRTHBA_TYPE, VIRTNIC_TYPE); + return 0; + } + + /* see if we are to delete all - NOTE: all implies we have a + * valid parentbus + */ + all = ((devtype == VIRTHBA_TYPE) && (wwnn == NULL)) || + ((devtype == VIRTNIC_TYPE) && (macaddr == NULL)); + + /* find all the vhba or vnic or both in virtpci device list + * keep list of ones we are deleting so we can call + * device_unregister after we release the lock; otherwise we + * encounter "schedule while atomic" + */ + write_lock_irqsave(&VpcidevListLock, flags); + for (tmpvpcidev = VpcidevListHead, prevvpcidev = NULL; tmpvpcidev;) { + if (tmpvpcidev->devtype != devtype) + DEL_CONTINUE; + + if (all) { + delthisone = + (tmpvpcidev->generic_dev.parent == parentbus); + /* we're deleting all vhbas or vnics on the + * specified parent bus + */ + } else if (devtype == VIRTHBA_TYPE) { + delthisone = + ((tmpvpcidev->scsi.wwnn.wwnn1 == wwnn->wwnn1) && + (tmpvpcidev->scsi.wwnn.wwnn2 == wwnn->wwnn2)); + /* devtype is vhba, we're deleting vhba whose + * wwnn matches the current device's wwnn + */ + } else { /* VIRTNIC_TYPE */ + delthisone = + memcmp(tmpvpcidev->net.mac_addr, macaddr, + MAX_MACADDR_LEN) == 0; + /* devtype is vnic, we're deleting vnic whose + * macaddr matches the current device's macaddr + */ + } + + if (!delthisone) + DEL_CONTINUE; + + /* take vhba/vnic out of the list */ + if (prevvpcidev) + /* not at head */ + prevvpcidev->next = tmpvpcidev->next; + else + VpcidevListHead = tmpvpcidev->next; + + /* add it to our deletelist */ + tmpvpcidev->next = dellist; + dellist = tmpvpcidev; + + count++; + if (!all) + break; /* done */ + /* going to top of loop again - set tmpvpcidev to next + * one we're to process + */ + if (prevvpcidev) + tmpvpcidev = prevvpcidev->next; + else + tmpvpcidev = VpcidevListHead; + } + write_unlock_irqrestore(&VpcidevListLock, flags); + + if (!all && (count == 0)) { + LOGERR("**** FAILED to find vhba/vnic in the list\n"); + return 0; + } + + /* now delete each one from delete list */ + while (dellist) { + /* save next */ + tmpvpcidev = dellist->next; + /* delete the vhba/vnic at dellist */ + DELETE_ONE_VPCIDEV(dellist); + /* do next */ + dellist = tmpvpcidev; + } + + return count; +} + +static void virtpci_device_release(struct device *dev_) +{ + /* this function is called when the last reference to the + * device is removed + */ + LOGINF("In virtpci_device_release:%p - NOT YET IMPLEMENTED\n", dev_); +} + +/*****************************************************/ +/* Driver functions */ +/*****************************************************/ + +#define kobj_to_device_driver(obj) container_of(obj, struct device_driver, kobj) +#define attribute_to_driver_attribute(obj) \ + container_of(obj, struct driver_attribute, attr) + +static ssize_t virtpci_driver_attr_show(struct kobject *kobj, + struct attribute *attr, + char *buf) +{ + struct driver_attribute *dattr = attribute_to_driver_attribute(attr); + ssize_t ret = 0; + + struct driver_private *dprivate = to_driver(kobj); + struct device_driver *driver; + if (dprivate != NULL) + driver = dprivate->driver; + else + driver = NULL; + + DBGINF("In virtpci_driver_attr_show driver->name:%s\n", driver->name); + if (driver) { + if (dattr->show) + ret = dattr->show(driver, buf); + } + return ret; +} + +static ssize_t virtpci_driver_attr_store(struct kobject *kobj, + struct attribute *attr, + const char *buf, size_t count) +{ + struct driver_attribute *dattr = attribute_to_driver_attribute(attr); + ssize_t ret = 0; + + struct driver_private *dprivate = to_driver(kobj); + struct device_driver *driver; + if (dprivate != NULL) + driver = dprivate->driver; + else + driver = NULL; + + DBGINF("In virtpci_driver_attr_store driver->name:%s\n", driver->name); + + if (driver) { + if (dattr->store) + ret = dattr->store(driver, buf, count); + } + return ret; +} + +/* register a new virtpci driver */ +int virtpci_register_driver(struct virtpci_driver *drv) +{ + int result = 0; + + DBGINF("In virtpci_register_driver\n"); + + if (drv->id_table == NULL) { + LOGERR("id_table missing\n"); + return 1; + } + /* initialize core driver fields needed to call driver_register */ + drv->core_driver.name = drv->name; /* name of driver in sysfs */ + drv->core_driver.bus = &virtpci_bus_type; /* type of bus this + * driver works with */ + drv->core_driver.probe = virtpci_device_probe; /* called to query the + * existence of a + * specific device and + * whether this driver + *can work with it */ + drv->core_driver.remove = virtpci_device_remove; /* called when the + * device is removed + * from the system */ + /* register with core */ + result = driver_register(&drv->core_driver); + /* calls bus_add_driver which calls driver_attach and + * module_add_driver + */ + if (result) + return result; /* failed */ + + drv->core_driver.p->kobj.ktype = &virtpci_driver_kobj_type; + + return 0; +} +EXPORT_SYMBOL_GPL(virtpci_register_driver); + +void virtpci_unregister_driver(struct virtpci_driver *drv) +{ + DBGINF("In virtpci_unregister_driver drv:%p\n", drv); + driver_unregister(&drv->core_driver); + /* driver_unregister calls bus_remove_driver + * bus_remove_driver calls device_detach + * device_detach calls device_release_driver for each of the + * driver's devices + * device_release driver calls drv->remove which is + * virtpci_device_remove + * virtpci_device_remove calls virthba_remove + */ + DBGINF("Leaving\n"); +} +EXPORT_SYMBOL_GPL(virtpci_unregister_driver); + +/*****************************************************/ +/* proc filesystem functions */ +/*****************************************************/ +struct print_vbus_info { + int *length; + char *buf; +}; + +static int print_vbus(struct device *vbus, void *data) +{ + struct print_vbus_info *p = (struct print_vbus_info *) data; + int l = *(p->length); + + *(p->length) = l + sprintf(p->buf + l, "bus_id:%s\n", dev_name(vbus)); + return 0; /* no error */ +} + +static ssize_t info_proc_read(struct file *file, char __user *buf, + size_t len, loff_t *offset) +{ + int length = 0; + struct virtpci_dev *tmpvpcidev; + unsigned long flags; + struct print_vbus_info printparam; + char *vbuf; + loff_t pos = *offset; + + if (pos < 0) + return -EINVAL; + + if (pos > 0 || !len) + return 0; + + vbuf = kzalloc(len, GFP_KERNEL); + if (!vbuf) + return -ENOMEM; + + length += sprintf(vbuf + length, "CHANSOCK is not defined.\n"); + + length += sprintf(vbuf + length, "\n Virtual PCI Bus devices\n"); + printparam.length = &length; + printparam.buf = vbuf; + if (bus_for_each_dev(&virtpci_bus_type, NULL, + (void *) &printparam, print_vbus)) + LOGERR("delete of all vbus failed\n"); + + length += sprintf(vbuf + length, "\n Virtual PCI devices\n"); + read_lock_irqsave(&VpcidevListLock, flags); + tmpvpcidev = VpcidevListHead; + while (tmpvpcidev) { + if (tmpvpcidev->devtype == VIRTHBA_TYPE) { + length += sprintf(vbuf + length, "[%d:%d] VHba:%08x:%08x max-config:%d-%d-%d-%d", + tmpvpcidev->busNo, tmpvpcidev->deviceNo, + tmpvpcidev->scsi.wwnn.wwnn1, + tmpvpcidev->scsi.wwnn.wwnn2, + tmpvpcidev->scsi.max.max_channel, + tmpvpcidev->scsi.max.max_id, + tmpvpcidev->scsi.max.max_lun, + tmpvpcidev->scsi.max.cmd_per_lun); + } else { + length += sprintf(vbuf + length, "[%d:%d] VNic:%02x:%02x:%02x:%02x:%02x:%02x num_rcv_bufs:%d mtu:%d", + tmpvpcidev->busNo, tmpvpcidev->deviceNo, + tmpvpcidev->net.mac_addr[0], + tmpvpcidev->net.mac_addr[1], + tmpvpcidev->net.mac_addr[2], + tmpvpcidev->net.mac_addr[3], + tmpvpcidev->net.mac_addr[4], + tmpvpcidev->net.mac_addr[5], + tmpvpcidev->net.num_rcv_bufs, + tmpvpcidev->net.mtu); + } + length += + sprintf(vbuf + length, " chanptr:%p\n", + tmpvpcidev->queueinfo.chan); + tmpvpcidev = tmpvpcidev->next; + } + read_unlock_irqrestore(&VpcidevListLock, flags); + + length += + sprintf(vbuf + length, "\nModule build: Date:%s Time:%s\n", __DATE__, + __TIME__); + + length += sprintf(vbuf + length, "\n"); + if (copy_to_user(buf, vbuf, length)) { + kfree(vbuf); + return -EFAULT; + } + + kfree(vbuf); + *offset += length; + return length; +} + +static ssize_t virt_proc_write(struct file *file, const char __user *buffer, + size_t count, loff_t *ppos) +{ + char buf[count]; + int type, i, action = 0xffff; + unsigned int busno, deviceno; + void *chanptr; + struct add_vbus_guestpart busaddparams; + struct add_virt_guestpart addparams; + struct del_vbus_guestpart busdelparams; + struct del_virt_guestpart delparams; + GUID dummyGuid = GUID0; +#ifdef STORAGE_CHANNEL + U64 storagechannel; +#endif + +#define PRINT_USAGE_RETURN {\ + LOGERR("usage: 0-0-<chanptr> ==> delete vhba\n"); \ + LOGERR("usage: 0-1-<chanptr>-<busNo>-<deviceNo> ==> add vhba\n"); \ + LOGERR("usage: 0-f-<busNo> ==> delete all vhbas\n"); \ + LOGERR("\n"); \ + LOGERR("usage: 1-0-<chanptr> ==> delete vnic\n"); \ + LOGERR("usage: 1-1-<chanptr>-<busNo>-<deviceNo> ==> add vnic\n"); \ + LOGERR("usage: 1-f-<busNo> ==> delete all vnics\n"); \ + LOGERR("\n"); \ + LOGERR("usage: 6-0-<busNo> ==> delete vbus\n"); \ + LOGERR("usage: 6-1-<busNo> ==> add vbus\n"); \ + LOGERR("usage: 6-f ==> delete all vbuses\n"); \ + LOGERR("usage: 98-<busNo>-<deviceNo> ==> INJECT Client delete vnic\n"); \ + LOGERR("usage: 99-<chanptr>-<busNo>-<deviceNo> ==> INJECT Client add vnic\n"); \ + return -EINVAL; \ +} + + if (copy_from_user(buf, buffer, count)) { + LOGERR("copy_from_user failed.\n"); + return -EFAULT; + } + + i = sscanf(buf, "%x-%x", &type, &action); + if (i < 2) + PRINT_USAGE_RETURN; + + if (type == 0x98) { + /* client inject delete vnic */ + i = sscanf(buf, "%x-%d-%d", &type, &busno, &deviceno); + if (i != 3) + PRINT_USAGE_RETURN; + uislib_client_inject_del_vnic(busno, deviceno); + return count; /* success */ + } else if (type == 0x99) { + /* client inject add vnic */ + i = sscanf(buf, "%x-%p-%d-%d", &type, &chanptr, &busno, + &deviceno); + if (i != 4) + PRINT_USAGE_RETURN; + if (!uislib_client_inject_add_vnic(busno, deviceno, + __pa(chanptr), + MIN_IO_CHANNEL_SIZE, + 1, /* test msg */ + dummyGuid, /* inst guid */ + NULL)) { /*interrupt info */ + LOGERR("FAILED to inject add vnic\n"); + return -EFAULT; + } + return count; /* success */ + } + + if ((type != VIRTHBA_TYPE) && (type != VIRTNIC_TYPE) + && (type != VIRTBUS_TYPE)) + PRINT_USAGE_RETURN; + + if (type == VIRTBUS_TYPE) { + i = sscanf(buf, "%x-%x-%d", &type, &action, &busno); + switch (action) { + case 0: + /* delete vbus */ + if (i != 3) + break; + busdelparams.busNo = busno; + if (delete_vbus(&busdelparams)) + return count; /* success */ + return -EFAULT; + + case 1: + /* add vbus */ + if (i != 3) + break; + busaddparams.chanptr = NULL; /* NOT YET USED */ + busaddparams.busNo = busno; + if (add_vbus(&busaddparams)) + return count; /* success */ + return -EFAULT; + + case 0xf: + /* delete all vbuses and all vhbas/vnics on the buses */ + if (i != 2) + break; + delete_all(); + return count; /* success */ + default: + break; + } + PRINT_USAGE_RETURN; + } + + /* if (type == VIRTNIC_TYPE) or if (type == VIRTHBA_TYPE) */ + switch (action) { + case 0: + /* delete vhba/vnic */ + i = sscanf(buf, "%x-%x-%p", &type, &action, &chanptr); + if (i != 3) + break; + delparams.chanptr = chanptr; + if (type == VIRTHBA_TYPE) { + if (delete_vhba(&delparams)) + return count; /* success */ + } else { + if (delete_vnic(&delparams)) + return count; /* success */ + } + return -EFAULT; + + case 1: + /* add vhba/vnic */ + i = sscanf(buf, "%x-%x-%p-%d-%d", &type, &action, &chanptr, + &busno, &deviceno); + if (i != 5) + break; + addparams.chanptr = chanptr; + addparams.busNo = busno; + addparams.deviceNo = deviceno; + if (type == VIRTHBA_TYPE) { + if (add_vhba(&addparams)) + return count; /* success */ + } else { + if (add_vnic(&addparams)) + return count; /* success */ + } + return -EFAULT; + +#ifdef STORAGE_CHANNEL + case 2: + /* add vhba */ + i = sscanf(buf, "%x-%x-%d-%d", &type, &action, &busno, + &deviceno); + if (i != 4) + break; + storagechannel = uislib_storage_channel(0); /* Get my storage channel */ + /* ioremap_cache it now */ + addparams.chanptr = + (void *) ioremap_cache(storagechannel, IO_CHANNEL_SIZE); + if (addparams.chanptr == NULL) { + LOGERR("Failure to get remap storage channel.\n"); + return -EFAULT; + } + addparams.busNo = busno; + addparams.deviceNo = deviceno; + if (type == VIRTHBA_TYPE) { + if (add_vhba(&addparams)) + return count; /* success */ + } + return -EFAULT; +#endif + case 0xf: + /* delete all vhbas/vnics */ + i = sscanf(buf, "%x-%x-%d", &type, &action, &busno); + if (i != 3) + break; + busdelparams.busNo = busno; + delete_all_virt(type, &busdelparams); + return count; /* success */ + default: + break; + } + PRINT_USAGE_RETURN; +} + +/*****************************************************/ +/* Module Init & Exit functions */ +/*****************************************************/ + +static int __init virtpci_mod_init(void) +{ + int ret; + + + LOGINF("Module build: Date:%s Time:%s...\n", __DATE__, __TIME__); + + POSTCODE_LINUX_2(VPCI_CREATE_ENTRY_PC, POSTCODE_SEVERITY_INFO); + + ret = bus_register(&virtpci_bus_type); + /* creates /sys/bus/uisvirtpci which contains devices & + * drivers directory + */ + if (ret) { + LOGERR("bus_register ****FAILED:%d\n", ret); + POSTCODE_LINUX_3(VPCI_CREATE_FAILURE_PC, ret, + POSTCODE_SEVERITY_ERR); + return ret; + } + DBGINF("bus_register successful\n"); + BusDeviceInfo_Init(&Bus_DriverInfo, + "clientbus", "virtpci", + VERSION, NULL, __DATE__, __TIME__); + + /* create a root bus used to parent all the virtpci buses. */ + ret = device_register(&virtpci_rootbus_device); + if (ret) { + LOGERR("device_register FAILED:%d\n", ret); + bus_unregister(&virtpci_bus_type); + POSTCODE_LINUX_3(VPCI_CREATE_FAILURE_PC, ret, + POSTCODE_SEVERITY_ERR); + return ret; + } + DBGINF("device_register successful ret:%x\n", ret); + + if (!uisctrl_register_req_handler(2, (void *) &virtpci_ctrlchan_func, + &Chipset_DriverInfo)) { + LOGERR("uisctrl_register_req_handler ****FAILED.\n"); + POSTCODE_LINUX_2(VPCI_CREATE_FAILURE_PC, POSTCODE_SEVERITY_ERR); + device_unregister(&virtpci_rootbus_device); + bus_unregister(&virtpci_bus_type); + return -1; + } + + LOGINF("successfully registered virtpci_ctrlchan_func (0x%p) as callback.\n", + (void *) &virtpci_ctrlchan_func); + /* create the proc directories */ + virtpci_proc_dir = proc_mkdir(DIR_PROC_ENTRY, NULL); + virt_proc_entry = proc_create(VIRT_PROC_ENTRY_FN, 0, virtpci_proc_dir, + &proc_virt_fops); + info_proc_entry = proc_create(INFO_PROC_ENTRY_FN, 0, virtpci_proc_dir, + &proc_info_fops); + LOGINF("Leaving\n"); + POSTCODE_LINUX_2(VPCI_CREATE_EXIT_PC, POSTCODE_SEVERITY_INFO); + return 0; +} + +static void __exit virtpci_mod_exit(void) +{ + LOGINF("virtpci_mod_exit...\n"); + + /* unregister the callback function */ + if (!uisctrl_register_req_handler(2, NULL, NULL)) + LOGERR("uisctrl_register_req_handler ****FAILED.\n"); + + device_unregister(&virtpci_rootbus_device); + bus_unregister(&virtpci_bus_type); + + if (virt_proc_entry) + remove_proc_entry(VIRT_PROC_ENTRY_FN, virtpci_proc_dir); + + if (info_proc_entry) + remove_proc_entry(INFO_PROC_ENTRY_FN, virtpci_proc_dir); + + if (virtpci_proc_dir) + remove_proc_entry(DIR_PROC_ENTRY, NULL); + + LOGINF("Leaving\n"); + +} + +module_init(virtpci_mod_init); +module_exit(virtpci_mod_exit); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Usha Srinivasan"); +MODULE_ALIAS("uisvirtpci"); + diff --git a/drivers/staging/unisys/virtpci/virtpci.h b/drivers/staging/unisys/virtpci/virtpci.h new file mode 100644 index 00000000000..b8fd07bc543 --- /dev/null +++ b/drivers/staging/unisys/virtpci/virtpci.h @@ -0,0 +1,104 @@ +/* virtpci.h + * + * Copyright © 2010 - 2013 UNISYS CORPORATION + * 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. + */ + +/* + * Unisys Virtual PCI driver header + */ + +#ifndef __VIRTPCI_H__ +#define __VIRTPCI_H__ + +#include "uisqueue.h" +#include <linux/version.h> + +#define PCI_DEVICE_ID_VIRTHBA 0xAA00 +#define PCI_DEVICE_ID_VIRTNIC 0xAB00 + +struct scsi_adap_info { + void *scsihost; /* scsi host if this device is a scsi hba */ + struct vhba_wwnn wwnn; /* the world wide node name of vhba */ + struct vhba_config_max max; /* various max specifications used + * to config vhba */ +}; + +struct net_adap_info { + struct net_device *netdev; /* network device if this + * device is a NIC */ + u8 mac_addr[MAX_MACADDR_LEN]; + int num_rcv_bufs; + unsigned mtu; + GUID zoneGuid; +}; + +typedef enum { + VIRTHBA_TYPE = 0, + VIRTNIC_TYPE = 1, + VIRTBUS_TYPE = 6, +} VIRTPCI_DEV_TYPE; + +struct virtpci_dev { + VIRTPCI_DEV_TYPE devtype; /* indicates type of the + * virtual pci device */ + struct virtpci_driver *mydriver; /* which driver has allocated + * this device */ + unsigned short vendor; /* vendor id for device */ + unsigned short device; /* device id for device */ + U32 busNo; /* number of bus on which device exists */ + U32 deviceNo; /* device's number on the bus */ + struct InterruptInfo intr; /* interrupt info */ + struct device generic_dev; /* generic device */ + union { + struct scsi_adap_info scsi; + struct net_adap_info net; + }; + + struct uisqueue_info queueinfo; /* holds ptr to channel where cmds & + * rsps are queued & retrieved */ + struct virtpci_dev *next; /* points to next virtpci device */ +}; + +struct virtpci_driver { + struct list_head node; + const char *name; /* the name of the driver in sysfs */ + const char *version; + const char *vertag; + const char *build_date; + const char *build_time; + const struct pci_device_id *id_table; /* must be non-NULL for probe + * to be called */ + int (*probe)(struct virtpci_dev *dev, + const struct pci_device_id *id); /* device inserted */ + void (*remove)(struct virtpci_dev *dev); /* Device removed (NULL if + * not a hot-plug capable + * driver) */ + int (*suspend)(struct virtpci_dev *dev, + u32 state); /* Device suspended */ + int (*resume)(struct virtpci_dev *dev); /* Device woken up */ + int (*enable_wake)(struct virtpci_dev *dev, + u32 state, int enable); /* Enable wake event */ + struct device_driver core_driver; /* VIRTPCI core fills this in */ +}; + +#define driver_to_virtpci_driver(in_drv) \ + container_of(in_drv, struct virtpci_driver, core_driver) +#define device_to_virtpci_dev(in_dev) \ + container_of(in_dev, struct virtpci_dev, generic_dev) + +int virtpci_register_driver(struct virtpci_driver *); +void virtpci_unregister_driver(struct virtpci_driver *); + +#endif /* __VIRTPCI_H__ */ diff --git a/drivers/staging/unisys/visorchannel/Kconfig b/drivers/staging/unisys/visorchannel/Kconfig new file mode 100644 index 00000000000..41c3b4b997e --- /dev/null +++ b/drivers/staging/unisys/visorchannel/Kconfig @@ -0,0 +1,10 @@ +# +# Unisys visorchannel configuration +# + +config UNISYS_VISORCHANNEL + tristate "Unisys visorchannel driver" + depends on UNISYSSPAR && UNISYS_VISORUTIL + ---help--- + If you say Y here, you will enable the Unisys visorchannel driver. + diff --git a/drivers/staging/unisys/visorchannel/Makefile b/drivers/staging/unisys/visorchannel/Makefile new file mode 100644 index 00000000000..f0060be55bc --- /dev/null +++ b/drivers/staging/unisys/visorchannel/Makefile @@ -0,0 +1,14 @@ +# +# Makefile for Unisys visorchannel +# + +obj-$(CONFIG_UNISYS_VISORCHANNEL) += visorchannel.o + +visorchannel-y := visorchannel_main.o visorchannel_funcs.o + +ccflags-y += -Idrivers/staging/unisys/include +ccflags-y += -Idrivers/staging/unisys/common-spar/include +ccflags-y += -Idrivers/staging/unisys/common-spar/include/channels +ccflags-y += -Idrivers/staging/unisys/visorutil +ccflags-y += -DCONFIG_SPAR_GUEST -DGUESTDRIVERBUILD -DNOAUTOVERSION + diff --git a/drivers/staging/unisys/visorchannel/globals.h b/drivers/staging/unisys/visorchannel/globals.h new file mode 100644 index 00000000000..668f832ca56 --- /dev/null +++ b/drivers/staging/unisys/visorchannel/globals.h @@ -0,0 +1,29 @@ +/* globals.h + * + * Copyright © 2010 - 2013 UNISYS CORPORATION + * 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. + */ + +#ifndef __VISORCHANNEL_GLOBALS_H__ +#define __VISORCHANNEL_GLOBALS_H__ + +#include "uniklog.h" +#include "timskmod.h" +#include "memregion.h" +#include "version.h" + +#define MYDRVNAME "visorchannel" + + +#endif diff --git a/drivers/staging/unisys/visorchannel/visorchannel.h b/drivers/staging/unisys/visorchannel/visorchannel.h new file mode 100644 index 00000000000..45466862494 --- /dev/null +++ b/drivers/staging/unisys/visorchannel/visorchannel.h @@ -0,0 +1,106 @@ +/* visorchannel.h + * + * Copyright © 2010 - 2013 UNISYS CORPORATION + * 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. + */ + +#ifndef __VISORCHANNEL_H__ +#define __VISORCHANNEL_H__ + +#include "commontypes.h" +#include "memregion.h" +#include "channel.h" +#ifndef HOSTADDRESS +#define HOSTADDRESS U64 +#endif +#ifndef BOOL +#define BOOL int +#endif + +/* VISORCHANNEL is an opaque structure to users. + * Fields are declared only in the implementation .c files. + */ +typedef struct VISORCHANNEL_Tag VISORCHANNEL; + +/* Note that for visorchannel_create() and visorchannel_create_overlapped(), + * <channelBytes> and <guid> arguments may be 0 if we are a channel CLIENT. + * In this case, the values can simply be read from the channel header. + */ +VISORCHANNEL *visorchannel_create(HOSTADDRESS physaddr, + ulong channelBytes, GUID guid); +VISORCHANNEL *visorchannel_create_overlapped(ulong channelBytes, + VISORCHANNEL *parent, ulong off, + GUID guid); +VISORCHANNEL *visorchannel_create_with_lock(HOSTADDRESS physaddr, + ulong channelBytes, GUID guid); +VISORCHANNEL *visorchannel_create_overlapped_with_lock(ulong channelBytes, + VISORCHANNEL *parent, + ulong off, GUID guid); +void visorchannel_destroy(VISORCHANNEL *channel); +int visorchannel_read(VISORCHANNEL *channel, ulong offset, + void *local, ulong nbytes); +int visorchannel_write(VISORCHANNEL *channel, ulong offset, + void *local, ulong nbytes); +int visorchannel_clear(VISORCHANNEL *channel, ulong offset, + U8 ch, ulong nbytes); +BOOL visorchannel_signalremove(VISORCHANNEL *channel, U32 queue, void *msg); +BOOL visorchannel_signalinsert(VISORCHANNEL *channel, U32 queue, void *msg); +int visorchannel_signalqueue_slots_avail(VISORCHANNEL *channel, U32 queue); +int visorchannel_signalqueue_max_slots(VISORCHANNEL *channel, U32 queue); + +HOSTADDRESS visorchannel_get_physaddr(VISORCHANNEL *channel); +ulong visorchannel_get_nbytes(VISORCHANNEL *channel); +char *visorchannel_id(VISORCHANNEL *channel, char *s); +char *visorchannel_zoneid(VISORCHANNEL *channel, char *s); +U64 visorchannel_get_clientpartition(VISORCHANNEL *channel); +GUID visorchannel_get_GUID(VISORCHANNEL *channel); +MEMREGION *visorchannel_get_memregion(VISORCHANNEL *channel); +char *visorchannel_GUID_id(GUID *guid, char *s); +void visorchannel_debug(VISORCHANNEL *channel, int nQueues, + struct seq_file *seq, U32 off); +void visorchannel_dump_section(VISORCHANNEL *chan, char *s, + int off, int len, struct seq_file *seq); +void *visorchannel_get_header(VISORCHANNEL *channel); + +#define VISORCHANNEL_CHANGE_SERVER_STATE(chan, chanId, newstate) \ + do { \ + U8 *p = (U8 *)visorchannel_get_header(chan); \ + if (p) { \ + ULTRA_CHANNEL_SERVER_TRANSITION(p, chanId, SrvState, \ + newstate, logCtx); \ + visorchannel_write \ + (chan, \ + offsetof(ULTRA_CHANNEL_PROTOCOL, SrvState), \ + p + \ + offsetof(ULTRA_CHANNEL_PROTOCOL, SrvState), \ + sizeof(U32)); \ + } \ + } while (0) + +#define VISORCHANNEL_CHANGE_CLIENT_STATE(chan, chanId, newstate) \ + do { \ + U8 *p = (U8 *)visorchannel_get_header(chan); \ + if (p) { \ + ULTRA_CHANNEL_CLIENT_TRANSITION(p, chanId, CliStateOS, \ + newstate, logCtx); \ + visorchannel_write \ + (chan, \ + offsetof(ULTRA_CHANNEL_PROTOCOL, CliStateOS), \ + p + \ + offsetof(ULTRA_CHANNEL_PROTOCOL, CliStateOS), \ + sizeof(U32)); \ + } \ + } while (0) + +#endif diff --git a/drivers/staging/unisys/visorchannel/visorchannel_funcs.c b/drivers/staging/unisys/visorchannel/visorchannel_funcs.c new file mode 100644 index 00000000000..509c77bbb3a --- /dev/null +++ b/drivers/staging/unisys/visorchannel/visorchannel_funcs.c @@ -0,0 +1,765 @@ +/* visorchannel_funcs.c + * + * Copyright © 2010 - 2013 UNISYS CORPORATION + * 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. + */ + +/* + * This provides Supervisor channel communication primitives, which are + * independent of the mechanism used to access the channel data. All channel + * data is accessed using the memregion abstraction. (memregion has both + * a CM2 implementation and a direct memory implementation.) + */ + +#include "globals.h" +#include "visorchannel.h" +#include "guidutils.h" + +#define MYDRVNAME "visorchannel" + +struct VISORCHANNEL_Tag { + MEMREGION *memregion; /* from memregion_create() */ + CHANNEL_HEADER chan_hdr; + GUID guid; + ulong size; + BOOL needs_lock; + spinlock_t insert_lock; + spinlock_t remove_lock; + + struct { + SIGNAL_QUEUE_HEADER req_queue; + SIGNAL_QUEUE_HEADER rsp_queue; + SIGNAL_QUEUE_HEADER event_queue; + SIGNAL_QUEUE_HEADER ack_queue; + } safe_uis_queue; +}; + +/* Creates the VISORCHANNEL abstraction for a data area in memory, but does + * NOT modify this data area. + */ +static VISORCHANNEL * +visorchannel_create_guts(HOSTADDRESS physaddr, ulong channelBytes, + VISORCHANNEL *parent, ulong off, GUID guid, + BOOL needs_lock) +{ + VISORCHANNEL *p = NULL; + void *rc = NULL; + + p = kmalloc(sizeof(VISORCHANNEL), GFP_KERNEL|__GFP_NORETRY); + if (p == NULL) + FAIL("allocation failed", 0); + p->memregion = NULL; + p->needs_lock = needs_lock; + spin_lock_init(&p->insert_lock); + spin_lock_init(&p->remove_lock); + + /* prepare chan_hdr (abstraction to read/write channel memory) */ + if (parent == NULL) + p->memregion = + memregion_create(physaddr, sizeof(CHANNEL_HEADER)); + else + p->memregion = + memregion_create_overlapped + (parent->memregion, off, sizeof(CHANNEL_HEADER)); + if (p->memregion == NULL) + FAIL("memregion_create failed", 0); + if (memregion_read(p->memregion, 0, &p->chan_hdr, + sizeof(CHANNEL_HEADER)) < 0) + FAIL("memregion_read failed", 0); + if (channelBytes == 0) + /* we had better be a CLIENT of this channel */ + channelBytes = (ulong) p->chan_hdr.Size; + if (STRUCTSEQUAL(guid, Guid0)) + /* we had better be a CLIENT of this channel */ + guid = p->chan_hdr.Type; + if (memregion_resize(p->memregion, channelBytes) < 0) + FAIL("memregion_resize failed", 0); + p->size = channelBytes; + p->guid = guid; + + RETPTR(p); + +Away: + + if (rc == NULL) { + if (p != NULL) { + visorchannel_destroy(p); + p = NULL; + } + } + return rc; +} + +VISORCHANNEL * +visorchannel_create(HOSTADDRESS physaddr, ulong channelBytes, GUID guid) +{ + return visorchannel_create_guts(physaddr, channelBytes, NULL, 0, guid, + FALSE); +} +EXPORT_SYMBOL_GPL(visorchannel_create); + +VISORCHANNEL * +visorchannel_create_with_lock(HOSTADDRESS physaddr, ulong channelBytes, + GUID guid) +{ + return visorchannel_create_guts(physaddr, channelBytes, NULL, 0, guid, + TRUE); +} +EXPORT_SYMBOL_GPL(visorchannel_create_with_lock); + +VISORCHANNEL * +visorchannel_create_overlapped(ulong channelBytes, + VISORCHANNEL *parent, ulong off, GUID guid) +{ + return visorchannel_create_guts(0, channelBytes, parent, off, guid, + FALSE); +} +EXPORT_SYMBOL_GPL(visorchannel_create_overlapped); + +VISORCHANNEL * +visorchannel_create_overlapped_with_lock(ulong channelBytes, + VISORCHANNEL *parent, ulong off, + GUID guid) +{ + return visorchannel_create_guts(0, channelBytes, parent, off, guid, + TRUE); +} +EXPORT_SYMBOL_GPL(visorchannel_create_overlapped_with_lock); + +void +visorchannel_destroy(VISORCHANNEL *channel) +{ + if (channel == NULL) + return; + if (channel->memregion != NULL) { + memregion_destroy(channel->memregion); + channel->memregion = NULL; + } + kfree(channel); +} +EXPORT_SYMBOL_GPL(visorchannel_destroy); + +HOSTADDRESS +visorchannel_get_physaddr(VISORCHANNEL *channel) +{ + return memregion_get_physaddr(channel->memregion); +} +EXPORT_SYMBOL_GPL(visorchannel_get_physaddr); + +ulong +visorchannel_get_nbytes(VISORCHANNEL *channel) +{ + return channel->size; +} +EXPORT_SYMBOL_GPL(visorchannel_get_nbytes); + +char * +visorchannel_GUID_id(GUID *guid, char *s) +{ + return GUID_format1(guid, s); +} +EXPORT_SYMBOL_GPL(visorchannel_GUID_id); + +char * +visorchannel_id(VISORCHANNEL *channel, char *s) +{ + return visorchannel_GUID_id(&channel->guid, s); +} +EXPORT_SYMBOL_GPL(visorchannel_id); + +char * +visorchannel_zoneid(VISORCHANNEL *channel, char *s) +{ + return visorchannel_GUID_id(&channel->chan_hdr.ZoneGuid, s); +} +EXPORT_SYMBOL_GPL(visorchannel_zoneid); + +HOSTADDRESS +visorchannel_get_clientpartition(VISORCHANNEL *channel) +{ + return channel->chan_hdr.PartitionHandle; +} +EXPORT_SYMBOL_GPL(visorchannel_get_clientpartition); + +GUID +visorchannel_get_GUID(VISORCHANNEL *channel) +{ + return channel->guid; +} +EXPORT_SYMBOL_GPL(visorchannel_get_GUID); + +MEMREGION * +visorchannel_get_memregion(VISORCHANNEL *channel) +{ + return channel->memregion; +} +EXPORT_SYMBOL_GPL(visorchannel_get_memregion); + +pSIGNAL_QUEUE_HEADER +visorchannel_get_safe_queue(VISORCHANNEL *pchannel, U32 queue) +{ + switch (queue) { + case 0: + return &pchannel->safe_uis_queue.req_queue; + case 1: + return &pchannel->safe_uis_queue.rsp_queue; + case 2: + return &pchannel->safe_uis_queue.event_queue; + case 3: + return &pchannel->safe_uis_queue.ack_queue; + default: + ERRDRV("Invalid queue value %d\n", queue); + return NULL; + } +} /* end visorchannel_get_safe_queue */ + +int +visorchannel_read(VISORCHANNEL *channel, ulong offset, + void *local, ulong nbytes) +{ + int rc = memregion_read(channel->memregion, offset, local, nbytes); + if ((rc >= 0) && (offset == 0) && (nbytes >= sizeof(CHANNEL_HEADER))) + memcpy(&channel->chan_hdr, local, sizeof(CHANNEL_HEADER)); + return rc; +} +EXPORT_SYMBOL_GPL(visorchannel_read); + +int +visorchannel_write(VISORCHANNEL *channel, ulong offset, + void *local, ulong nbytes) +{ + if (offset == 0 && nbytes >= sizeof(CHANNEL_HEADER)) + memcpy(&channel->chan_hdr, local, sizeof(CHANNEL_HEADER)); + return memregion_write(channel->memregion, offset, local, nbytes); +} +EXPORT_SYMBOL_GPL(visorchannel_write); + +int +visorchannel_clear(VISORCHANNEL *channel, ulong offset, U8 ch, ulong nbytes) +{ + int rc = -1; + int bufsize = 65536; + int written = 0; + U8 *buf = vmalloc(bufsize); + + if (buf == NULL) { + ERRDRV("%s failed memory allocation", __func__); + RETINT(-1); + } + memset(buf, ch, bufsize); + while (nbytes > 0) { + ulong thisbytes = bufsize; + int x = -1; + if (nbytes < thisbytes) + thisbytes = nbytes; + x = memregion_write(channel->memregion, offset + written, + buf, thisbytes); + if (x < 0) + RETINT(x); + written += thisbytes; + nbytes -= thisbytes; + } + RETINT(0); + +Away: + if (buf != NULL) { + vfree(buf); + buf = NULL; + } + return rc; +} +EXPORT_SYMBOL_GPL(visorchannel_clear); + +void * +visorchannel_get_header(VISORCHANNEL *channel) +{ + return (void *) &(channel->chan_hdr); +} +EXPORT_SYMBOL_GPL(visorchannel_get_header); + +/** Return offset of a specific SIGNAL_QUEUE_HEADER from the beginning of a + * channel header + */ +#define SIG_QUEUE_OFFSET(chan_hdr, q) \ + ((chan_hdr)->oChannelSpace + ((q) * sizeof(SIGNAL_QUEUE_HEADER))) + +/** Return offset of a specific queue entry (data) from the beginning of a + * channel header + */ +#define SIG_DATA_OFFSET(chan_hdr, q, sig_hdr, slot) \ + (SIG_QUEUE_OFFSET(chan_hdr, q) + (sig_hdr)->oSignalBase + \ + ((slot) * (sig_hdr)->SignalSize)) + +/** Write the contents of a specific field within a SIGNAL_QUEUE_HEADER back + * into host memory + */ +#define SIG_WRITE_FIELD(channel, queue, sig_hdr, FIELD) \ + (memregion_write(channel->memregion, \ + SIG_QUEUE_OFFSET(&channel->chan_hdr, queue)+\ + offsetof(SIGNAL_QUEUE_HEADER, FIELD), \ + &((sig_hdr)->FIELD), \ + sizeof((sig_hdr)->FIELD)) >= 0) + +static BOOL +sig_read_header(VISORCHANNEL *channel, U32 queue, + SIGNAL_QUEUE_HEADER *sig_hdr) +{ + BOOL rc = FALSE; + + if (channel->chan_hdr.oChannelSpace < sizeof(CHANNEL_HEADER)) + FAIL("oChannelSpace too small", FALSE); + + /* Read the appropriate SIGNAL_QUEUE_HEADER into local memory. */ + + if (memregion_read(channel->memregion, + SIG_QUEUE_OFFSET(&channel->chan_hdr, queue), + sig_hdr, sizeof(SIGNAL_QUEUE_HEADER)) < 0) { + ERRDRV("queue=%d SIG_QUEUE_OFFSET=%d", + queue, (int)SIG_QUEUE_OFFSET(&channel->chan_hdr, queue)); + FAIL("memregion_read of signal queue failed", FALSE); + } + RETBOOL(TRUE); +Away: + return rc; +} + +static BOOL +sig_do_data(VISORCHANNEL *channel, U32 queue, + SIGNAL_QUEUE_HEADER *sig_hdr, U32 slot, void *data, BOOL is_write) +{ + BOOL rc = FALSE; + int signal_data_offset = SIG_DATA_OFFSET(&channel->chan_hdr, queue, + sig_hdr, slot); + if (is_write) { + if (memregion_write(channel->memregion, signal_data_offset, + data, sig_hdr->SignalSize) < 0) + FAIL("memregion_write of signal data failed", FALSE); + } else { + if (memregion_read(channel->memregion, signal_data_offset, + data, sig_hdr->SignalSize) < 0) + FAIL("memregion_read of signal data failed", FALSE); + } + RETBOOL(TRUE); +Away: + return rc; +} + +static inline BOOL +sig_read_data(VISORCHANNEL *channel, U32 queue, + SIGNAL_QUEUE_HEADER *sig_hdr, U32 slot, void *data) +{ + return sig_do_data(channel, queue, sig_hdr, slot, data, FALSE); +} + +static inline BOOL +sig_write_data(VISORCHANNEL *channel, U32 queue, + SIGNAL_QUEUE_HEADER *sig_hdr, U32 slot, void *data) +{ + return sig_do_data(channel, queue, sig_hdr, slot, data, TRUE); +} + +static inline unsigned char +safe_sig_queue_validate(pSIGNAL_QUEUE_HEADER psafe_sqh, + pSIGNAL_QUEUE_HEADER punsafe_sqh, + U32 *phead, U32 *ptail) +{ + if ((*phead >= psafe_sqh->MaxSignalSlots) + || (*ptail >= psafe_sqh->MaxSignalSlots)) { + /* Choose 0 or max, maybe based on current tail value */ + *phead = 0; + *ptail = 0; + + /* Sync with client as necessary */ + punsafe_sqh->Head = *phead; + punsafe_sqh->Tail = *ptail; + + ERRDRV("safe_sig_queue_validate: head = 0x%x, tail = 0x%x, MaxSlots = 0x%x", + *phead, *ptail, psafe_sqh->MaxSignalSlots); + return 0; + } + return 1; +} /* end safe_sig_queue_validate */ + +BOOL +visorchannel_signalremove(VISORCHANNEL *channel, U32 queue, void *msg) +{ + BOOL rc = FALSE; + SIGNAL_QUEUE_HEADER sig_hdr; + + if (channel->needs_lock) + spin_lock(&channel->remove_lock); + + if (!sig_read_header(channel, queue, &sig_hdr)) + RETBOOL(FALSE); + if (sig_hdr.Head == sig_hdr.Tail) + RETBOOL(FALSE); /* no signals to remove */ + sig_hdr.Tail = (sig_hdr.Tail + 1) % sig_hdr.MaxSignalSlots; + if (!sig_read_data(channel, queue, &sig_hdr, sig_hdr.Tail, msg)) + FAIL("sig_read_data failed", FALSE); + sig_hdr.NumSignalsReceived++; + + /* For each data field in SIGNAL_QUEUE_HEADER that was modified, + * update host memory. + */ + MEMORYBARRIER; + if (!SIG_WRITE_FIELD(channel, queue, &sig_hdr, Tail)) + FAIL("memregion_write of Tail failed", FALSE); + if (!SIG_WRITE_FIELD(channel, queue, &sig_hdr, NumSignalsReceived)) + FAIL("memregion_write of NumSignalsReceived failed", FALSE); + + RETBOOL(TRUE); + +Away: + if (channel->needs_lock) + spin_unlock(&channel->remove_lock); + + return rc; +} +EXPORT_SYMBOL_GPL(visorchannel_signalremove); + +BOOL +visorchannel_safesignalremove(VISORCHANNEL *channel, U32 queue, void *msg) +{ + BOOL rc = FALSE; + SIGNAL_QUEUE_HEADER *psafe_sqh, unsafe_sqh; + int stat; + + if (channel->needs_lock) + spin_lock(&channel->remove_lock); + + if (!sig_read_header(channel, queue, &unsafe_sqh)) + RETBOOL(FALSE); + + psafe_sqh = visorchannel_get_safe_queue(channel, queue); + if (psafe_sqh == NULL) { + ERRDRV("safesignalremove: get_safe_queue failed\n"); + RETBOOL(FALSE); + } + + stat = + safe_sig_queue_validate(psafe_sqh, &unsafe_sqh, &unsafe_sqh.Head, + &unsafe_sqh.Tail); + if (stat == 0) { + ERRDRV("safe_signal_remove: safe_sig_queue_validate failed, queue = %d", + queue); + RETBOOL(FALSE); + } + + if (unsafe_sqh.Head == unsafe_sqh.Tail) + RETBOOL(FALSE); /* no signals to remove */ + unsafe_sqh.Tail = (unsafe_sqh.Tail + 1) % psafe_sqh->MaxSignalSlots; + if (!sig_read_data(channel, queue, psafe_sqh, unsafe_sqh.Tail, msg)) + FAIL("sig_read_data failed", FALSE); + unsafe_sqh.NumSignalsReceived++; + + /* For each data field in SIGNAL_QUEUE_HEADER that was modified, + * update host memory. + */ + MEMORYBARRIER; + if (!SIG_WRITE_FIELD(channel, queue, &unsafe_sqh, Tail)) + FAIL("memregion_write of Tail failed", FALSE); + if (!SIG_WRITE_FIELD(channel, queue, &unsafe_sqh, NumSignalsReceived)) + FAIL("memregion_write of NumSignalsReceived failed", FALSE); + + RETBOOL(TRUE); + +Away: + if (channel->needs_lock) + spin_unlock(&channel->remove_lock); + + return rc; +} /* end visorchannel_safesignalremove */ + +BOOL +visorchannel_signalinsert(VISORCHANNEL *channel, U32 queue, void *msg) +{ + BOOL rc = FALSE; + SIGNAL_QUEUE_HEADER sig_hdr; + + if (channel->needs_lock) + spin_lock(&channel->insert_lock); + + if (!sig_read_header(channel, queue, &sig_hdr)) + RETBOOL(FALSE); + + sig_hdr.Head = ((sig_hdr.Head + 1) % sig_hdr.MaxSignalSlots); + if (sig_hdr.Head == sig_hdr.Tail) { +#if 0 + ERRDRV("visorchannel queue #%d overflow (max slots=%d)", + queue, sig_hdr.MaxSignalSlots); +#endif + sig_hdr.NumOverflows++; + if (!SIG_WRITE_FIELD(channel, queue, &sig_hdr, NumOverflows)) + FAIL("memregion_write of NumOverflows failed", FALSE); + RETBOOL(FALSE); + } + + if (!sig_write_data(channel, queue, &sig_hdr, sig_hdr.Head, msg)) + FAIL("sig_write_data failed", FALSE); + sig_hdr.NumSignalsSent++; + + /* For each data field in SIGNAL_QUEUE_HEADER that was modified, + * update host memory. + */ + MEMORYBARRIER; + if (!SIG_WRITE_FIELD(channel, queue, &sig_hdr, Head)) + FAIL("memregion_write of Head failed", FALSE); + if (!SIG_WRITE_FIELD(channel, queue, &sig_hdr, NumSignalsSent)) + FAIL("memregion_write of NumSignalsSent failed", FALSE); + + RETBOOL(TRUE); + +Away: + if (channel->needs_lock) + spin_unlock(&channel->insert_lock); + + return rc; +} +EXPORT_SYMBOL_GPL(visorchannel_signalinsert); + + +int +visorchannel_signalqueue_slots_avail(VISORCHANNEL *channel, U32 queue) +{ + SIGNAL_QUEUE_HEADER sig_hdr; + U32 slots_avail, slots_used; + U32 head, tail; + + if (!sig_read_header(channel, queue, &sig_hdr)) + return 0; + head = sig_hdr.Head; + tail = sig_hdr.Tail; + if (head < tail) + head = head + sig_hdr.MaxSignalSlots; + slots_used = (head - tail); + slots_avail = sig_hdr.MaxSignals - slots_used; + return (int) slots_avail; +} +EXPORT_SYMBOL_GPL(visorchannel_signalqueue_slots_avail); + +int +visorchannel_signalqueue_max_slots(VISORCHANNEL *channel, U32 queue) +{ + SIGNAL_QUEUE_HEADER sig_hdr; + if (!sig_read_header(channel, queue, &sig_hdr)) + return 0; + return (int) sig_hdr.MaxSignals; +} +EXPORT_SYMBOL_GPL(visorchannel_signalqueue_max_slots); + +BOOL +visorchannel_safesignalinsert(VISORCHANNEL *channel, U32 queue, void *msg) +{ + BOOL rc = FALSE; + SIGNAL_QUEUE_HEADER *psafe_sqh, unsafe_sqh; + int stat; + + if (channel->needs_lock) + spin_lock(&channel->insert_lock); + + if (!sig_read_header(channel, queue, &unsafe_sqh)) + RETBOOL(FALSE); + + psafe_sqh = visorchannel_get_safe_queue(channel, queue); + if (psafe_sqh == NULL) { + ERRDRV("safesignalinsert: get_safe_queue failed\n"); + RETBOOL(FALSE); + } + + unsafe_sqh.Head = ((unsafe_sqh.Head + 1) % psafe_sqh->MaxSignalSlots); + + stat = + safe_sig_queue_validate(psafe_sqh, &unsafe_sqh, &unsafe_sqh.Head, + &unsafe_sqh.Tail); + if (stat == 0) { + ERRDRV("safe_signal_insert: safe_sig_queue_validate failed, queue = %d", + queue); + RETBOOL(FALSE); + } + + if (unsafe_sqh.Head == unsafe_sqh.Tail) { +#if 0 + ERRDRV("visorchannel queue #%d overflow (max slots=%d)", + queue, psafe_sqh->MaxSignalSlots); +#endif + unsafe_sqh.NumOverflows++; + if (!SIG_WRITE_FIELD(channel, queue, &unsafe_sqh, NumOverflows)) + FAIL("memregion_write of NumOverflows failed", FALSE); + RETBOOL(FALSE); + } + + if (!sig_write_data(channel, queue, psafe_sqh, unsafe_sqh.Head, msg)) + FAIL("sig_write_data failed", FALSE); + unsafe_sqh.NumSignalsSent++; + + /* For each data field in SIGNAL_QUEUE_HEADER that was modified, + * update host memory. + */ + MEMORYBARRIER; + if (!SIG_WRITE_FIELD(channel, queue, &unsafe_sqh, Head)) + FAIL("memregion_write of Head failed", FALSE); + if (!SIG_WRITE_FIELD(channel, queue, &unsafe_sqh, NumSignalsSent)) + FAIL("memregion_write of NumSignalsSent failed", FALSE); + + RETBOOL(TRUE); + +Away: + if (channel->needs_lock) + spin_unlock(&channel->insert_lock); + + return rc; +} /* end visorchannel_safesignalinsert */ + +static void +sigqueue_debug(SIGNAL_QUEUE_HEADER *q, int which, struct seq_file *seq) +{ + seq_printf(seq, "Signal Queue #%d\n", which); + seq_printf(seq, " VersionId = %lu\n", (ulong) q->VersionId); + seq_printf(seq, " Type = %lu\n", (ulong) q->Type); + seq_printf(seq, " oSignalBase = %llu\n", + (long long) q->oSignalBase); + seq_printf(seq, " SignalSize = %lu\n", (ulong) q->SignalSize); + seq_printf(seq, " MaxSignalSlots = %lu\n", + (ulong) q->MaxSignalSlots); + seq_printf(seq, " MaxSignals = %lu\n", (ulong) q->MaxSignals); + seq_printf(seq, " FeatureFlags = %-16.16Lx\n", + (long long) q->FeatureFlags); + seq_printf(seq, " NumSignalsSent = %llu\n", + (long long) q->NumSignalsSent); + seq_printf(seq, " NumSignalsReceived = %llu\n", + (long long) q->NumSignalsReceived); + seq_printf(seq, " NumOverflows = %llu\n", + (long long) q->NumOverflows); + seq_printf(seq, " Head = %lu\n", (ulong) q->Head); + seq_printf(seq, " Tail = %lu\n", (ulong) q->Tail); +} + +void +visorchannel_debug(VISORCHANNEL *channel, int nQueues, + struct seq_file *seq, U32 off) +{ + HOSTADDRESS addr = 0; + ulong nbytes = 0, nbytes_region = 0; + MEMREGION *memregion = NULL; + CHANNEL_HEADER hdr; + CHANNEL_HEADER *phdr = &hdr; + char s[99]; + int i = 0; + int errcode = 0; + + if (channel == NULL) { + ERRDRV("%s no channel", __func__); + return; + } + memregion = channel->memregion; + if (memregion == NULL) { + ERRDRV("%s no memregion", __func__); + return; + } + addr = memregion_get_physaddr(memregion); + nbytes_region = memregion_get_nbytes(memregion); + errcode = visorchannel_read(channel, off, + phdr, sizeof(CHANNEL_HEADER)); + if (errcode < 0) { + seq_printf(seq, + "Read of channel header failed with errcode=%d)\n", + errcode); + if (off == 0) { + phdr = &channel->chan_hdr; + seq_puts(seq, "(following data may be stale)\n"); + } else + return; + } + nbytes = (ulong) (phdr->Size); + seq_printf(seq, "--- Begin channel @0x%-16.16Lx for 0x%lx bytes (region=0x%lx bytes) ---\n", + addr + off, nbytes, nbytes_region); + seq_printf(seq, "Type = %s\n", GUID_format2(&phdr->Type, s)); + seq_printf(seq, "ZoneGuid = %s\n", + GUID_format2(&phdr->ZoneGuid, s)); + seq_printf(seq, "Signature = 0x%-16.16Lx\n", + (long long) phdr->Signature); + seq_printf(seq, "LegacyState = %lu\n", (ulong) phdr->LegacyState); + seq_printf(seq, "SrvState = %lu\n", (ulong) phdr->SrvState); + seq_printf(seq, "CliStateBoot = %lu\n", (ulong) phdr->CliStateBoot); + seq_printf(seq, "CliStateOS = %lu\n", (ulong) phdr->CliStateOS); + seq_printf(seq, "HeaderSize = %lu\n", (ulong) phdr->HeaderSize); + seq_printf(seq, "Size = %llu\n", (long long) phdr->Size); + seq_printf(seq, "Features = 0x%-16.16llx\n", + (long long) phdr->Features); + seq_printf(seq, "PartitionHandle = 0x%-16.16llx\n", + (long long) phdr->PartitionHandle); + seq_printf(seq, "Handle = 0x%-16.16llx\n", + (long long) phdr->Handle); + seq_printf(seq, "VersionId = %lu\n", (ulong) phdr->VersionId); + seq_printf(seq, "oChannelSpace = %llu\n", + (long long) phdr->oChannelSpace); + if ((phdr->oChannelSpace == 0) || (errcode < 0)) + ; + else + for (i = 0; i < nQueues; i++) { + SIGNAL_QUEUE_HEADER q; + errcode = visorchannel_read(channel, + off + phdr->oChannelSpace + + (i * sizeof(q)), + &q, sizeof(q)); + if (errcode < 0) { + seq_printf(seq, + "failed to read signal queue #%d from channel @0x%-16.16Lx errcode=%d\n", + i, addr, errcode); + continue; + } + sigqueue_debug(&q, i, seq); + } + seq_printf(seq, "--- End channel @0x%-16.16Lx for 0x%lx bytes ---\n", + addr + off, nbytes); +} +EXPORT_SYMBOL_GPL(visorchannel_debug); + +void +visorchannel_dump_section(VISORCHANNEL *chan, char *s, + int off, int len, struct seq_file *seq) +{ + char *buf = NULL, *fmtbuf = NULL; + int fmtbufsize = 0; + int i = 0; + int errcode = 0; + + fmtbufsize = 100 * COVQ(len, 16); + buf = kmalloc(len, GFP_KERNEL|__GFP_NORETRY); + fmtbuf = kmalloc(fmtbufsize, GFP_KERNEL|__GFP_NORETRY); + if (buf == NULL || fmtbuf == NULL) + goto Away; + + errcode = visorchannel_read(chan, off, buf, len); + if (errcode < 0) { + ERRDRV("%s failed to read %s from channel errcode=%d", + s, __func__, errcode); + goto Away; + } + seq_printf(seq, "channel %s:\n", s); + hexDumpToBuffer(fmtbuf, fmtbufsize, " ", buf, len, 16); + for (i = 0; fmtbuf[i] != '\0'; i++) + seq_printf(seq, "%c", fmtbuf[i]); + +Away: + if (buf != NULL) { + kfree(buf); + buf = NULL; + } + if (fmtbuf != NULL) { + kfree(fmtbuf); + fmtbuf = NULL; + } +} +EXPORT_SYMBOL_GPL(visorchannel_dump_section); diff --git a/drivers/staging/unisys/visorchannel/visorchannel_main.c b/drivers/staging/unisys/visorchannel/visorchannel_main.c new file mode 100644 index 00000000000..482ee0ac1c1 --- /dev/null +++ b/drivers/staging/unisys/visorchannel/visorchannel_main.c @@ -0,0 +1,49 @@ +/* visorchannel_main.c + * + * Copyright © 2010 - 2013 UNISYS CORPORATION + * 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. + */ + +/* + * This is a module "wrapper" around visorchannel_funcs. + */ + +#include "globals.h" +#include "channel.h" +#include "visorchannel.h" +#include "guidutils.h" + +#define MYDRVNAME "visorchannel" + +static int __init +visorchannel_init(void) +{ + INFODRV("driver version %s loaded", VERSION); + return 0; +} + +static void +visorchannel_exit(void) +{ + INFODRV("driver unloaded"); +} + +module_init(visorchannel_init); +module_exit(visorchannel_exit); + +MODULE_AUTHOR("Unisys"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Supervisor channel driver for service partition: ver " + VERSION); +MODULE_VERSION(VERSION); diff --git a/drivers/staging/unisys/visorchipset/Kconfig b/drivers/staging/unisys/visorchipset/Kconfig new file mode 100644 index 00000000000..7ca2fbca9d5 --- /dev/null +++ b/drivers/staging/unisys/visorchipset/Kconfig @@ -0,0 +1,10 @@ +# +# Unisys visorchipset configuration +# + +config UNISYS_VISORCHIPSET + tristate "Unisys visorchipset driver" + depends on UNISYSSPAR && UNISYS_VISORUTIL && UNISYS_VISORCHANNEL + ---help--- + If you say Y here, you will enable the Unisys visorchipset driver. + diff --git a/drivers/staging/unisys/visorchipset/Makefile b/drivers/staging/unisys/visorchipset/Makefile new file mode 100644 index 00000000000..f5e8650e1b0 --- /dev/null +++ b/drivers/staging/unisys/visorchipset/Makefile @@ -0,0 +1,18 @@ +# +# Makefile for Unisys visorchipset +# + +obj-$(CONFIG_UNISYS_VISORCHIPSET) += visorchipset.o + +visorchipset-y := visorchipset_main.o controlvm_direct.o file.o filexfer.o \ + parser.o + +ccflags-y += -Idrivers/staging/unisys/include +ccflags-y += -Idrivers/staging/unisys/uislib +ccflags-y += -Idrivers/staging/unisys/visorchannel +ccflags-y += -Idrivers/staging/unisys/common-spar/include +ccflags-y += -Idrivers/staging/unisys/common-spar/include/channels +ccflags-y += -Idrivers/staging/unisys/visorutil +ccflags-y += -Iinclude/generated +ccflags-y += -DCONFIG_SPAR_GUEST -DGUESTDRIVERBUILD -DNOAUTOVERSION + diff --git a/drivers/staging/unisys/visorchipset/controlvm.h b/drivers/staging/unisys/visorchipset/controlvm.h new file mode 100644 index 00000000000..873fa12dfe6 --- /dev/null +++ b/drivers/staging/unisys/visorchipset/controlvm.h @@ -0,0 +1,27 @@ +/* controlvm.h + * + * Copyright © 2010 - 2013 UNISYS CORPORATION + * 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. + */ + +#ifndef __CONTROLVM_H__ +#define __CONTROLVM_H__ + +#include "timskmod.h" + +int controlvm_init(void); +void controlvm_deinit(void); +HOSTADDRESS controlvm_get_channel_address(void); + +#endif diff --git a/drivers/staging/unisys/visorchipset/controlvm_direct.c b/drivers/staging/unisys/visorchipset/controlvm_direct.c new file mode 100644 index 00000000000..7fbc5892bcb --- /dev/null +++ b/drivers/staging/unisys/visorchipset/controlvm_direct.c @@ -0,0 +1,61 @@ +/* controlvm_direct.c + * + * Copyright © 2010 - 2013 UNISYS CORPORATION + * 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. + */ + +/* This is a controlvm-related code that is dependent upon firmware running + * on a virtual partition. + */ + +#include "globals.h" +#include "uisutils.h" +#define CURRENT_FILE_PC VISOR_CHIPSET_PC_controlvm_direct_c + + +/* We can fill in this code when we learn how to make vmcalls... */ + + + +int controlvm_init(void) +{ + return 0; +} + + + +void controlvm_deinit(void) +{ +} + + + +HOSTADDRESS controlvm_get_channel_address(void) +{ + static BOOL warned = FALSE; + U64 addr = 0; + + U32 size = 0; + + if (!VMCALL_SUCCESSFUL(Issue_VMCALL_IO_CONTROLVM_ADDR(&addr, &size))) { + if (!warned) { + ERRDRV("%s - vmcall to determine controlvm channel addr failed", + __func__); + warned = TRUE; + } + return 0; + } + INFODRV("controlvm addr=%Lx", addr); + return addr; +} diff --git a/drivers/staging/unisys/visorchipset/file.c b/drivers/staging/unisys/visorchipset/file.c new file mode 100644 index 00000000000..b0d28a2b523 --- /dev/null +++ b/drivers/staging/unisys/visorchipset/file.c @@ -0,0 +1,223 @@ +/* file.c + * + * Copyright © 2010 - 2013 UNISYS CORPORATION + * 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. + */ + +/* This contains the implementation that allows a usermode program to + * communicate with the visorchipset driver using a device/file interface. + */ + +#include "globals.h" +#include "visorchannel.h" +#include <linux/mm.h> +#include <linux/fs.h> +#include "uisutils.h" + +#define CURRENT_FILE_PC VISOR_CHIPSET_PC_file_c + +static struct cdev Cdev; +static VISORCHANNEL **PControlVm_channel; +static dev_t MajorDev = -1; /**< indicates major num for device */ +static BOOL Registered = FALSE; + +static int visorchipset_open(struct inode *inode, struct file *file); +static int visorchipset_release(struct inode *inode, struct file *file); +static int visorchipset_mmap(struct file *file, struct vm_area_struct *vma); +#ifdef HAVE_UNLOCKED_IOCTL +long visorchipset_ioctl(struct file *file, unsigned int cmd, unsigned long arg); +#else +int visorchipset_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg); +#endif + +static const struct file_operations visorchipset_fops = { + .owner = THIS_MODULE, + .open = visorchipset_open, + .read = NULL, + .write = NULL, +#ifdef HAVE_UNLOCKED_IOCTL + .unlocked_ioctl = visorchipset_ioctl, +#else + .ioctl = visorchipset_ioctl, +#endif + .release = visorchipset_release, + .mmap = visorchipset_mmap, +}; + +int +visorchipset_file_init(dev_t majorDev, VISORCHANNEL **pControlVm_channel) +{ + int rc = -1; + + PControlVm_channel = pControlVm_channel; + MajorDev = majorDev; + cdev_init(&Cdev, &visorchipset_fops); + Cdev.owner = THIS_MODULE; + if (MAJOR(MajorDev) == 0) { + /* dynamic major device number registration required */ + if (alloc_chrdev_region(&MajorDev, 0, 1, MYDRVNAME) < 0) { + ERRDRV("Unable to allocate+register char device %s", + MYDRVNAME); + RETINT(-1); + } + Registered = TRUE; + INFODRV("New major number %d registered\n", MAJOR(MajorDev)); + } else { + /* static major device number registration required */ + if (register_chrdev_region(MajorDev, 1, MYDRVNAME) < 0) { + ERRDRV("Unable to register char device %s", MYDRVNAME); + RETINT(-1); + } + Registered = TRUE; + INFODRV("Static major number %d registered\n", MAJOR(MajorDev)); + } + if (cdev_add(&Cdev, MKDEV(MAJOR(MajorDev), 0), 1) < 0) + FAIL("failed to create char device", -1); + INFODRV("Registered char device for %s (major=%d)", + MYDRVNAME, MAJOR(MajorDev)); + RETINT(0); +Away: + return rc; +} + +void +visorchipset_file_cleanup(void) +{ + if (Cdev.ops != NULL) + cdev_del(&Cdev); + Cdev.ops = NULL; + if (Registered) { + if (MAJOR(MajorDev) >= 0) { + unregister_chrdev_region(MajorDev, 1); + MajorDev = MKDEV(0, 0); + } + Registered = FALSE; + } +} + +static int +visorchipset_open(struct inode *inode, struct file *file) +{ + unsigned minor_number = iminor(inode); + int rc = -ENODEV; + + DEBUGDRV("%s", __func__); + if (minor_number != 0) + RETINT(-ENODEV); + file->private_data = NULL; + RETINT(0); +Away: + if (rc < 0) + ERRDRV("%s minor=%d failed", __func__, minor_number); + return rc; +} + +static int +visorchipset_release(struct inode *inode, struct file *file) +{ + int rc = -1; + DEBUGDRV("%s", __func__); + RETINT(0); +Away: + return rc; +} + +static int +visorchipset_mmap(struct file *file, struct vm_area_struct *vma) +{ + ulong physAddr = 0; + ulong offset = vma->vm_pgoff << PAGE_SHIFT; + GUEST_PHYSICAL_ADDRESS addr = 0; + + /* sv_enable_dfp(); */ + DEBUGDRV("%s", __func__); + if (offset & (PAGE_SIZE - 1)) { + ERRDRV("%s virtual address NOT page-aligned!", __func__); + return -ENXIO; /* need aligned offsets */ + } + switch (offset) { + case VISORCHIPSET_MMAP_CONTROLCHANOFFSET: + vma->vm_flags |= VM_IO; + if (*PControlVm_channel == NULL) { + ERRDRV("%s no controlvm channel yet", __func__); + return -ENXIO; + } + visorchannel_read(*PControlVm_channel, + offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL, + gpControlChannel), &addr, + sizeof(addr)); + if (addr == 0) { + ERRDRV("%s control channel address is 0", __func__); + return -ENXIO; + } + physAddr = (ulong) (addr); + DEBUGDRV("mapping physical address = 0x%lx", physAddr); + if (remap_pfn_range(vma, vma->vm_start, + physAddr >> PAGE_SHIFT, + vma->vm_end - vma->vm_start, + /*pgprot_noncached */ + (vma->vm_page_prot))) { + ERRDRV("%s remap_pfn_range failed", __func__); + return -EAGAIN; + } + break; + default: + return -ENOSYS; + } + DEBUGDRV("%s success!", __func__); + return 0; +} + +#ifdef HAVE_UNLOCKED_IOCTL +long +visorchipset_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +#else +int +visorchipset_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +#endif +{ + int rc = SUCCESS; + S64 adjustment; + S64 vrtc_offset; + DBGINF("entered visorchipset_ioctl, cmd=%d", cmd); + switch (cmd) { + case VMCALL_QUERY_GUEST_VIRTUAL_TIME_OFFSET: + /* get the physical rtc offset */ + vrtc_offset = Issue_VMCALL_QUERY_GUEST_VIRTUAL_TIME_OFFSET(); + if (copy_to_user + ((void __user *)arg, &vrtc_offset, sizeof(vrtc_offset))) + RETINT(-EFAULT); + DBGINF("insde visorchipset_ioctl, cmd=%d, vrtc_offset=%lld", + cmd, vrtc_offset); + break; + case VMCALL_UPDATE_PHYSICAL_TIME: + if (copy_from_user + (&adjustment, (void __user *)arg, sizeof(adjustment))) + RETINT(-EFAULT); + DBGINF("insde visorchipset_ioctl, cmd=%d, adjustment=%lld", cmd, + adjustment); + rc = Issue_VMCALL_UPDATE_PHYSICAL_TIME(adjustment); + break; + default: + LOGERR("visorchipset_ioctl received invalid command"); + RETINT(-EFAULT); + break; + } + RETINT(rc); +Away: + DBGINF("exiting %d!", rc); + return rc; +} diff --git a/drivers/staging/unisys/visorchipset/file.h b/drivers/staging/unisys/visorchipset/file.h new file mode 100644 index 00000000000..597282aa9a0 --- /dev/null +++ b/drivers/staging/unisys/visorchipset/file.h @@ -0,0 +1,26 @@ +/* file.h + * + * Copyright © 2010 - 2013 UNISYS CORPORATION + * 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. + */ + +#ifndef __FILE_H__ +#define __FILE_H__ + +#include "globals.h" + +int visorchipset_file_init(dev_t majorDev, VISORCHANNEL **pControlVm_channel); +void visorchipset_file_cleanup(void); + +#endif diff --git a/drivers/staging/unisys/visorchipset/filexfer.c b/drivers/staging/unisys/visorchipset/filexfer.c new file mode 100644 index 00000000000..431cff844a4 --- /dev/null +++ b/drivers/staging/unisys/visorchipset/filexfer.c @@ -0,0 +1,506 @@ +/* filexfer.c + * + * Copyright © 2013 - 2013 UNISYS CORPORATION + * 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. + */ + +/* Code here-in is the "glue" that connects controlvm messages with the + * sparfilexfer driver, which is used to transfer file contents as payload + * across the controlvm channel. + */ + +#include "globals.h" +#include "controlvm.h" +#include "visorchipset.h" +#include "filexfer.h" + +#ifdef ENABLE_SPARFILEXFER /* sparfilexfer kernel module enabled in build */ +#include "sparfilexfer.h" + +/* Driver-global memory */ +static LIST_HEAD(Request_list); /* list of struct any_request *, via + * req_list memb */ + +/* lock for above pool for allocation of any_request structs, and pool +* name; note that kmem_cache_create requires that we keep the storage +* for the pool name for the life of the pool + */ +static DEFINE_SPINLOCK(Request_list_lock); + +static struct kmem_cache *Request_memory_pool; +static const char Request_memory_pool_name[] = "filexfer_request_pool"; +size_t Caller_req_context_bytes = 0; /* passed to filexfer_constructor() */ + +/* This structure defines a single controlvm GETFILE conversation, which + * consists of a single controlvm request message and 1 or more controlvm + * response messages. + */ +struct getfile_request { + CONTROLVM_MESSAGE_HEADER controlvm_header; + atomic_t buffers_in_use; + GET_CONTIGUOUS_CONTROLVM_PAYLOAD_FUNC get_contiguous_controlvm_payload; + CONTROLVM_RESPOND_WITH_PAYLOAD_FUNC controlvm_respond_with_payload; +}; + +/* This structure defines a single controlvm PUTFILE conversation, which + * consists of a single controlvm request with a filename, and additional + * controlvm messages with file data. + */ +struct putfile_request { + GET_CONTROLVM_FILEDATA_FUNC get_controlvm_filedata; + CONTROLVM_RESPOND_FUNC controlvm_end_putFile; +}; + +/* This structure defines a single file transfer operation, which can either + * be a GETFILE or PUTFILE. + */ +struct any_request { + struct list_head req_list; + ulong2 file_request_number; + ulong2 data_sequence_number; + TRANSMITFILE_DUMP_FUNC dump_func; + BOOL is_get; + union { + struct getfile_request get; + struct putfile_request put; + }; + /* Size of caller_context_data will be + * <Caller_req_context_bytes> bytes. I aligned this because I + * am paranoid about what happens when an arbitrary data + * structure with unknown alignment requirements gets copied + * here. I want caller_context_data to be aligned to the + * coarsest possible alignment boundary that could be required + * for any user data structure. + */ + u8 caller_context_data[1] __aligned(sizeof(ulong2); +}; + +/* + * Links the any_request into the global list of allocated requests + * (<Request_list>). + */ +static void +unit_tracking_create(struct list_head *dev_list_link) +{ + unsigned long flags; + spin_lock_irqsave(&Request_list_lock, flags); + list_add(dev_list_link, &Request_list); + spin_unlock_irqrestore(&Request_list_lock, flags); +} + +/* Unlinks a any_request from the global list (<Request_list>). + */ +static void +unit_tracking_destroy(struct list_head *dev_list_link) +{ + unsigned long flags; + spin_lock_irqsave(&Request_list_lock, flags); + list_del(dev_list_link); + spin_unlock_irqrestore(&Request_list_lock, flags); +} + +/* Allocate memory for and return a new any_request struct, and + * link it to the global list of outstanding requests. + */ +static struct any_request * +alloc_request(char *fn, int ln) +{ + struct any_request *req = (struct any_request *) + (visorchipset_cache_alloc(Request_memory_pool, + FALSE, + fn, ln)); + if (!req) + return NULL; + memset(req, 0, sizeof(struct any_request) + Caller_req_context_bytes); + unit_tracking_create(&req->req_list); + return req; +} + +/* Book-end for alloc_request(). + */ +static void +free_request(struct any_request *req, char *fn, int ln) +{ + unit_tracking_destroy(&req->req_list); + visorchipset_cache_free(Request_memory_pool, req, fn, ln); +} + +/* Constructor for filexfer.o. + */ +int +filexfer_constructor(size_t req_context_bytes) +{ + int rc = -1; + + Caller_req_context_bytes = req_context_bytes; + Request_memory_pool = + kmem_cache_create(Request_memory_pool_name, + sizeof(struct any_request) + + Caller_req_context_bytes, + 0, SLAB_HWCACHE_ALIGN, NULL); + if (!Request_memory_pool) { + LOGERR("failed to alloc Request_memory_pool"); + rc = -ENOMEM; + goto Away; + } + rc = 0; +Away: + if (rc < 0) { + if (Request_memory_pool) { + kmem_cache_destroy(Request_memory_pool); + Request_memory_pool = NULL; + } + } + return rc; +} + +/* Destructor for filexfer.o. + */ +void +filexfer_destructor(void) +{ + if (Request_memory_pool) { + kmem_cache_destroy(Request_memory_pool); + Request_memory_pool = NULL; + } +} + +/* This function will obtain an available chunk from the controlvm payload area, + * store the size in bytes of the chunk in <actual_size>, and return a pointer + * to the chunk. The function is passed to the sparfilexfer driver, which calls + * it whenever payload space is required to copy file data into. + */ +static void * +get_empty_bucket_for_getfile_data(void *context, + ulong min_size, ulong max_size, + ulong *actual_size) +{ + void *bucket; + struct any_request *req = (struct any_request *) context; + + if (!req->is_get) { + LOGERR("%s - unexpected call", __func__); + return NULL; + } + bucket = (*req->get.get_contiguous_controlvm_payload) + (min_size, max_size, actual_size); + if (bucket != NULL) { + atomic_inc(&req->get.buffers_in_use); + DBGINF("%s - sent %lu-byte buffer", __func__, *actual_size); + } + return bucket; +} + +/* This function will send a controlvm response with data in the payload + * (whose space was obtained with get_empty_bucket_for_getfile_data). The + * function is passed to the sparfilexfer driver, which calls it whenever it + * wants to send file data back across the controlvm channel. + */ +static int +send_full_getfile_data_bucket(void *context, void *bucket, + ulong bucket_actual_size, ulong bucket_used_size) +{ + struct any_request *req = (struct any_request *) context; + + if (!req->is_get) { + LOGERR("%s - unexpected call", __func__); + return 0; + } + DBGINF("sending buffer for %lu/%lu", + bucket_used_size, bucket_actual_size); + if (!(*req->get.controlvm_respond_with_payload) + (&req->get.controlvm_header, + req->file_request_number, + req->data_sequence_number++, + 0, bucket, bucket_actual_size, bucket_used_size, TRUE)) + atomic_dec(&req->get.buffers_in_use); + return 0; +} + +/* This function will send a controlvm response indicating the end of a + * GETFILE transfer. The function is passed to the sparfilexfer driver. + */ +static void +send_end_of_getfile_data(void *context, int status) +{ + struct any_request *req = (struct any_request *) context; + if (!req->is_get) { + LOGERR("%s - unexpected call", __func__); + return; + } + LOGINF("status=%d", status); + (*req->get.controlvm_respond_with_payload) + (&req->get.controlvm_header, + req->file_request_number, + req->data_sequence_number++, status, NULL, 0, 0, FALSE); + free_request(req, __FILE__, __LINE__); + module_put(THIS_MODULE); +} + +/* This function supplies data for a PUTFILE transfer. + * The function is passed to the sparfilexfer driver. + */ +static int +get_putfile_data(void *context, void *pbuf, size_t bufsize, + BOOL buf_is_userspace, size_t *bytes_transferred) +{ + struct any_request *req = (struct any_request *) context; + if (req->is_get) { + LOGERR("%s - unexpected call", __func__); + return -1; + } + return (*req->put.get_controlvm_filedata) (&req->caller_context_data[0], + pbuf, bufsize, + buf_is_userspace, + bytes_transferred); +} + +/* This function is called to indicate the end of a PUTFILE transfer. + * The function is passed to the sparfilexfer driver. + */ +static void +end_putfile(void *context, int status) +{ + struct any_request *req = (struct any_request *) context; + if (req->is_get) { + LOGERR("%s - unexpected call", __func__); + return; + } + (*req->put.controlvm_end_putFile) (&req->caller_context_data[0], + status); + free_request(req, __FILE__, __LINE__); + module_put(THIS_MODULE); +} + +/* Refer to filexfer.h for description. */ +BOOL +filexfer_getFile(CONTROLVM_MESSAGE_HEADER *msgHdr, + ulong2 file_request_number, + uint uplink_index, + uint disk_index, + char *file_name, + GET_CONTIGUOUS_CONTROLVM_PAYLOAD_FUNC + get_contiguous_controlvm_payload, + CONTROLVM_RESPOND_WITH_PAYLOAD_FUNC + controlvm_respond_with_payload, + TRANSMITFILE_DUMP_FUNC dump_func) +{ + BOOL use_count_up = FALSE; + BOOL failed = TRUE; + struct any_request *req = alloc_request(__FILE__, __LINE__); + + if (!req) { + LOGERR("allocation of any_request failed"); + goto Away; + } + /* We need to increment this module's use count because we're handing + * off pointers to functions within this module to be used by + * another module. + */ + __module_get(THIS_MODULE); + use_count_up = TRUE; + req->is_get = TRUE; + req->file_request_number = file_request_number; + req->data_sequence_number = 0; + req->dump_func = dump_func; + req->get.controlvm_header = *msgHdr; + atomic_set(&req->get.buffers_in_use, 0); + req->get.get_contiguous_controlvm_payload = + get_contiguous_controlvm_payload; + req->get.controlvm_respond_with_payload = + controlvm_respond_with_payload; + if (sparfilexfer_local2remote(req, /* context, passed to + * callback funcs */ + file_name, + file_request_number, + uplink_index, + disk_index, + get_empty_bucket_for_getfile_data, + send_full_getfile_data_bucket, + send_end_of_getfile_data) < 0) { + LOGERR("sparfilexfer_local2remote failed"); + goto Away; + } + failed = FALSE; +Away: + if (failed) { + if (use_count_up) { + module_put(THIS_MODULE); + use_count_up = FALSE; + } + if (req) { + free_request(req, __FILE__, __LINE__); + req = NULL; + } + return FALSE; + } else { + return TRUE; + /* success; send callbacks will be called for responses */ + } +} + +/* Refer to filexfer.h for description. */ +void * +filexfer_putFile(CONTROLVM_MESSAGE_HEADER *msgHdr, + ulong2 file_request_number, + uint uplink_index, + uint disk_index, + char *file_name, + TRANSMITFILE_INIT_CONTEXT_FUNC init_context, + GET_CONTROLVM_FILEDATA_FUNC get_controlvm_filedata, + CONTROLVM_RESPOND_FUNC controlvm_end_putFile, + TRANSMITFILE_DUMP_FUNC dump_func) +{ + BOOL use_count_up = FALSE; + BOOL failed = TRUE; + struct any_request *req = alloc_request(__FILE__, __LINE__); + void *caller_ctx = NULL; + + if (!req) { + LOGERR("allocation of any_request failed"); + goto Away; + } + caller_ctx = (void *) (&(req->caller_context_data[0])); + /* We need to increment this module's use count because we're handing + * off pointers to functions within this module to be used by + * another module. + */ + __module_get(THIS_MODULE); + use_count_up = TRUE; + req->is_get = FALSE; + req->file_request_number = file_request_number; + req->data_sequence_number = 0; + req->dump_func = dump_func; + req->put.get_controlvm_filedata = get_controlvm_filedata; + req->put.controlvm_end_putFile = controlvm_end_putFile; + (*init_context) (caller_ctx, msgHdr, file_request_number); + if (sparfilexfer_remote2local(req, /* context, passed to + * callback funcs */ + file_name, + file_request_number, + uplink_index, + disk_index, + get_putfile_data, end_putfile) < 0) { + LOGERR("sparfilexfer_remote2local failed"); + goto Away; + } + failed = FALSE; +Away: + if (failed) { + if (use_count_up) { + module_put(THIS_MODULE); + use_count_up = FALSE; + } + if (req) { + free_request(req, __FILE__, __LINE__); + req = NULL; + } + return NULL; + } else { + return caller_ctx; + /* success; callbacks will be called for responses */ + } +} + +static void +dump_get_request(struct seq_file *f, struct getfile_request *getreq) +{ + seq_printf(f, " buffers_in_use=%d\n", + atomic_read(&getreq->buffers_in_use)); +} + +static void +dump_put_request(struct seq_file *f, struct putfile_request *putreq) +{ +} + +static void +dump_request(struct seq_file *f, struct any_request *req) +{ + seq_printf(f, "* %s id=%llu seq=%llu\n", + ((req->is_get) ? "Get" : "Put"), + req->file_request_number, req->data_sequence_number); + if (req->is_get) + dump_get_request(f, &req->get); + else + dump_put_request(f, &req->put); + if (req->dump_func) + (*req->dump_func) (f, &(req->caller_context_data[0]), " "); +} + +void +filexfer_dump(struct seq_file *f) +{ + ulong flags; + struct list_head *entry; + + seq_puts(f, "Outstanding TRANSMIT_FILE requests:\n"); + spin_lock_irqsave(&Request_list_lock, flags); + list_for_each(entry, &Request_list) { + struct any_request *req; + req = list_entry(entry, struct any_request, req_list); + dump_request(f, req); + } + spin_unlock_irqrestore(&Request_list_lock, flags); +} + +#else /* ifdef ENABLE_SPARFILEXFER */ +int +filexfer_constructor(size_t req_context_bytes) +{ + return 0; /* success */ +} + +void +filexfer_destructor(void) +{ +} + +BOOL +filexfer_getFile(CONTROLVM_MESSAGE_HEADER *msgHdr, + u64 file_request_number, + uint uplink_index, + uint disk_index, + char *file_name, + GET_CONTIGUOUS_CONTROLVM_PAYLOAD_FUNC + get_contiguous_controlvm_payload, + CONTROLVM_RESPOND_WITH_PAYLOAD_FUNC + controlvm_respond_with_payload, + TRANSMITFILE_DUMP_FUNC dump_func) +{ + /* since no sparfilexfer module exists to call, we just fail */ + return FALSE; +} + +void * +filexfer_putFile(CONTROLVM_MESSAGE_HEADER *msgHdr, + u64 file_request_number, + uint uplink_index, + uint disk_index, + char *file_name, + TRANSMITFILE_INIT_CONTEXT_FUNC init_context, + GET_CONTROLVM_FILEDATA_FUNC get_controlvm_filedata, + CONTROLVM_RESPOND_FUNC controlvm_end_putFile, + TRANSMITFILE_DUMP_FUNC dump_func) +{ + /* since no sparfilexfer module exists to call, we just fail */ + return NULL; +} + +void +filexfer_dump(struct seq_file *f) +{ +} + +#endif /* ifdef ENABLE_SPARFILEXFER */ diff --git a/drivers/staging/unisys/visorchipset/filexfer.h b/drivers/staging/unisys/visorchipset/filexfer.h new file mode 100644 index 00000000000..a1bfca69cdc --- /dev/null +++ b/drivers/staging/unisys/visorchipset/filexfer.h @@ -0,0 +1,147 @@ +/* filexfer.h + * + * Copyright © 2013 - 2013 UNISYS CORPORATION + * 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. + */ + +/* This header file defines the interface that filexfer.c provides to other + * code in the visorchipset driver. + */ + +#ifndef __FILEXFER_H__ +#define __FILEXFER_H__ + +#include "globals.h" +#include "controlvmchannel.h" +#include <linux/seq_file.h> + +typedef void *(*GET_CONTIGUOUS_CONTROLVM_PAYLOAD_FUNC) (ulong min_size, + ulong max_size, + ulong *actual_size); + +typedef BOOL +(*CONTROLVM_RESPOND_WITH_PAYLOAD_FUNC) (CONTROLVM_MESSAGE_HEADER *msgHdr, + u64 fileRequestNumber, + u64 dataSequenceNumber, + int response, + void *bucket, ulong payloadChunkSize, + ulong payloadUsedBytes, BOOL partial); + +typedef void +(*TRANSMITFILE_INIT_CONTEXT_FUNC)(void *ctx, + const CONTROLVM_MESSAGE_HEADER *hdr, + u64 file_request_number); +typedef void (*TRANSMITFILE_DUMP_FUNC) (struct seq_file *f, void *ctx, + const char *pfx); +typedef int (*GET_CONTROLVM_FILEDATA_FUNC) (void *ctx, + void *buf, size_t bufsize, + BOOL buf_is_userspace, + size_t *bytes_transferred); +typedef void (*CONTROLVM_RESPOND_FUNC) (void *ctx, int response); + +/* Call once to initialize filexfer.o. + * req_context_bytes number of bytes the caller needs to keep track of each file + * transfer conversation. The <ctx_init_value> passed to filexfer_putFile() is + * assumed to be this many bytes in size. Code within filexfer.o will copy this + * into a dynamically-allocated area, and pass back a pointer to that area in + * callback functions. + */ +int filexfer_constructor(size_t req_context_bytes); + +/* Call once to clean up filexfer.o */ +void filexfer_destructor(void); + +/* Call this to dump diagnostic info about all outstanding getFiles/putFiles */ +void filexfer_dump(struct seq_file *f); + +/* Call to transfer a file from the local filesystem (i.e., from the environment + * where this driver is running) across the controlvm channel to a remote + * environment. 1 or more controlvm responses will be sent as a result, each + * of which whose payload contains file data. Only the last controlvm message + * will have Flags.partialCompletion==0. + * + * msgHdr the controlvm message header of the GETFILE request which + * we just received + * file_request_number this is all data from the GETFILE request that + * uplink_index define which file is to be transferred + * disk_index + * file_name + * get_contiguous_controlvm_payload function to call when space is needed + * in the payload area + * controlvm_respond_with_payload function to call to send each controlvm + * response containing file data as the + * payload; returns FALSE only if the + * payload buffer was freed inline + * dump_func function to dump context data in + * human-readable format + * + * Returns TRUE iff the file transfer request has been successfully initiated, + * or FALSE to indicate failure. + */ +BOOL +filexfer_getFile(CONTROLVM_MESSAGE_HEADER *msgHdr, + u64 file_request_number, + uint uplink_index, + uint disk_index, + char *file_name, + GET_CONTIGUOUS_CONTROLVM_PAYLOAD_FUNC + get_contiguous_controlvm_payload, + CONTROLVM_RESPOND_WITH_PAYLOAD_FUNC + controlvm_respond_with_payload, + TRANSMITFILE_DUMP_FUNC dump_func); + +/* Call to create a file in the local filesystem (i.e., in the environment + * where this driver is running) from data received as payload in + * controlvm channel messages from a remote environment. 1 or more controlvm + * messages will be received for this transfer, and only the last will have + * Flags.partialCompletion==0. + * + * msgHdr the controlvm message header of the PUTFILE request which + * we just received + * file_request_number this is all data from the PUTFILE request that + * uplink_index define which file is to be created in the local + * disk_index filesystem + * file_name + * init_context function to call to initialize the + * <req_context_bytes>-sized storage area returned by + * this func; note that it would NOT be sufficient to + * allow the caller to initialize this upon return, as + * the the other user-supplied callbacks might have + * already been called by then + * get_controlvm_filedata function to call to obtain more data for the file + * being written; refer to get_controlvm_filedata() + * in visorchipset_main.c for a complete description + * of parameters + * controlvm_end_putFile function to call to indicate that creation of the + * local file has completed; set <response> to a + * negative value to indicate an error + * dump_func function to dump context data in human-readable + * format + * + * Returns a pointer to a dynamically-allocated storage area of size + * <req_context_bytes> which the caller can use, or NULL for error. The + * caller should NEVER free the returned pointer, but should expect to receive + * it as the <ctx> argument when callback functions are called. + */ +void *filexfer_putFile(CONTROLVM_MESSAGE_HEADER *msgHdr, + u64 file_request_number, + uint uplink_index, + uint disk_index, + char *file_name, + TRANSMITFILE_INIT_CONTEXT_FUNC init_context, + GET_CONTROLVM_FILEDATA_FUNC get_controlvm_filedata, + CONTROLVM_RESPOND_FUNC controlvm_end_putFile, + TRANSMITFILE_DUMP_FUNC dump_func); + +#endif diff --git a/drivers/staging/unisys/visorchipset/globals.h b/drivers/staging/unisys/visorchipset/globals.h new file mode 100644 index 00000000000..a0e6d4fc03a --- /dev/null +++ b/drivers/staging/unisys/visorchipset/globals.h @@ -0,0 +1,45 @@ +/* globals.h + * + * Copyright © 2010 - 2013 UNISYS CORPORATION + * 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. + */ + + +#ifndef __VISORCHIPSET_GLOBALS_H__ +#define __VISORCHIPSET_GLOBALS_H__ + +#include "uniklog.h" +#include "diagnostics/appos_subsystems.h" +#include "timskmod.h" +#include "visorchipset.h" +#include "visorchipset_umode.h" +#include "version.h" + +#define MYDRVNAME "visorchipset" + + +/* module parameters */ + +extern int visorchipset_testvnic; +extern int visorchipset_testvnicclient; +extern int visorchipset_testmsg; +extern int visorchipset_major; +extern int visorchipset_serverregwait; +extern int visorchipset_clientregwait; +extern int visorchipset_testteardown; +extern int visorchipset_disable_controlvm; +extern int visorchipset_crash_kernel; +extern int visorchipset_holdchipsetready; + +#endif diff --git a/drivers/staging/unisys/visorchipset/parser.c b/drivers/staging/unisys/visorchipset/parser.c new file mode 100644 index 00000000000..09b3a8485ca --- /dev/null +++ b/drivers/staging/unisys/visorchipset/parser.c @@ -0,0 +1,466 @@ +/* parser.c + * + * Copyright © 2010 - 2013 UNISYS CORPORATION + * 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. + */ + +#include "parser.h" +#include "memregion.h" +#include "controlvmchannel.h" +#include <linux/ctype.h> +#include <linux/mm.h> + +#define MYDRVNAME "visorchipset_parser" +#define CURRENT_FILE_PC VISOR_CHIPSET_PC_parser_c + +/* We will refuse to allocate more than this many bytes to copy data from + * incoming payloads. This serves as a throttling mechanism. + */ +#define MAX_CONTROLVM_PAYLOAD_BYTES (1024*128) +static ulong Controlvm_Payload_Bytes_Buffered; + +struct PARSER_CONTEXT_Tag { + ulong allocbytes; + ulong param_bytes; + u8 *curr; + ulong bytes_remaining; + BOOL byte_stream; + char data[0]; +}; + +static PARSER_CONTEXT * +parser_init_guts(U64 addr, U32 bytes, BOOL isLocal, + BOOL hasStandardPayloadHeader, BOOL *tryAgain) +{ + int allocbytes = sizeof(PARSER_CONTEXT) + bytes; + PARSER_CONTEXT *rc = NULL; + PARSER_CONTEXT *ctx = NULL; + MEMREGION *rgn = NULL; + ULTRA_CONTROLVM_PARAMETERS_HEADER *phdr = NULL; + + if (tryAgain) + *tryAgain = FALSE; + if (!hasStandardPayloadHeader) + /* alloc and 0 extra byte to ensure payload is + * '\0'-terminated + */ + allocbytes++; + if ((Controlvm_Payload_Bytes_Buffered + bytes) + > MAX_CONTROLVM_PAYLOAD_BYTES) { + ERRDRV("%s (%s:%d) - prevented allocation of %d bytes to prevent exceeding throttling max (%d)", + __func__, __FILE__, __LINE__, allocbytes, + MAX_CONTROLVM_PAYLOAD_BYTES); + if (tryAgain) + *tryAgain = TRUE; + RETPTR(NULL); + } + ctx = kmalloc(allocbytes, GFP_KERNEL|__GFP_NORETRY); + if (ctx == NULL) { + ERRDRV("%s (%s:%d) - failed to allocate %d bytes", + __func__, __FILE__, __LINE__, allocbytes); + if (tryAgain) + *tryAgain = TRUE; + RETPTR(NULL); + } + memset(ctx, 0, allocbytes); + ctx->allocbytes = allocbytes; + ctx->param_bytes = bytes; + ctx->curr = NULL; + ctx->bytes_remaining = 0; + ctx->byte_stream = FALSE; + if (isLocal) { + void *p; + if (addr > virt_to_phys(high_memory - 1)) { + ERRDRV("%s - bad local address (0x%-16.16Lx for %lu)", + __func__, + (unsigned long long) addr, (ulong) bytes); + RETPTR(NULL); + } + p = __va((ulong) (addr)); + memcpy(ctx->data, p, bytes); + } else { + rgn = memregion_create(addr, bytes); + if (!rgn) + RETPTR(NULL); + if (memregion_read(rgn, 0, ctx->data, bytes) < 0) + RETPTR(NULL); + } + if (!hasStandardPayloadHeader) { + ctx->byte_stream = TRUE; + RETPTR(ctx); + } + phdr = (ULTRA_CONTROLVM_PARAMETERS_HEADER *) (ctx->data); + if (phdr->TotalLength != bytes) { + ERRDRV("%s - bad total length %lu (should be %lu)", + __func__, + (ulong) (phdr->TotalLength), (ulong) (bytes)); + RETPTR(NULL); + } + if (phdr->TotalLength < phdr->HeaderLength) { + ERRDRV("%s - total length < header length (%lu < %lu)", + __func__, + (ulong) (phdr->TotalLength), + (ulong) (phdr->HeaderLength)); + RETPTR(NULL); + } + if (phdr->HeaderLength < sizeof(ULTRA_CONTROLVM_PARAMETERS_HEADER)) { + ERRDRV("%s - header is too small (%lu < %lu)", + __func__, + (ulong) (phdr->HeaderLength), + (ulong) (sizeof(ULTRA_CONTROLVM_PARAMETERS_HEADER))); + RETPTR(NULL); + } + + RETPTR(ctx); + +Away: + if (rgn) { + memregion_destroy(rgn); + rgn = NULL; + } + if (rc) + Controlvm_Payload_Bytes_Buffered += ctx->param_bytes; + else { + if (ctx) { + parser_done(ctx); + ctx = NULL; + } + } + return rc; +} + +PARSER_CONTEXT * +parser_init(U64 addr, U32 bytes, BOOL isLocal, BOOL *tryAgain) +{ + return parser_init_guts(addr, bytes, isLocal, TRUE, tryAgain); +} + +/* Call this instead of parser_init() if the payload area consists of just + * a sequence of bytes, rather than a ULTRA_CONTROLVM_PARAMETERS_HEADER + * structures. Afterwards, you can call parser_simpleString_get() or + * parser_byteStream_get() to obtain the data. + */ +PARSER_CONTEXT * +parser_init_byteStream(U64 addr, U32 bytes, BOOL isLocal, BOOL *tryAgain) +{ + return parser_init_guts(addr, bytes, isLocal, FALSE, tryAgain); +} + +/* Obtain '\0'-terminated copy of string in payload area. + */ +char * +parser_simpleString_get(PARSER_CONTEXT *ctx) +{ + if (!ctx->byte_stream) + return NULL; + return ctx->data; /* note this IS '\0'-terminated, because of + * the num of bytes we alloc+clear in + * parser_init_byteStream() */ +} + +/* Obtain a copy of the buffer in the payload area. + */ +void * +parser_byteStream_get(PARSER_CONTEXT *ctx, ulong *nbytes) +{ + if (!ctx->byte_stream) + return NULL; + if (nbytes) + *nbytes = ctx->param_bytes; + return (void *) ctx->data; +} + +GUID +parser_id_get(PARSER_CONTEXT *ctx) +{ + ULTRA_CONTROLVM_PARAMETERS_HEADER *phdr = NULL; + + if (ctx == NULL) { + ERRDRV("%s (%s:%d) - no context", + __func__, __FILE__, __LINE__); + return Guid0; + } + phdr = (ULTRA_CONTROLVM_PARAMETERS_HEADER *) (ctx->data); + return phdr->Id; +} + +void +parser_param_start(PARSER_CONTEXT *ctx, PARSER_WHICH_STRING which_string) +{ + ULTRA_CONTROLVM_PARAMETERS_HEADER *phdr = NULL; + + if (ctx == NULL) { + ERRDRV("%s (%s:%d) - no context", + __func__, __FILE__, __LINE__); + RETVOID; + } + phdr = (ULTRA_CONTROLVM_PARAMETERS_HEADER *) (ctx->data); + switch (which_string) { + case PARSERSTRING_INITIATOR: + ctx->curr = ctx->data + phdr->InitiatorOffset; + ctx->bytes_remaining = phdr->InitiatorLength; + break; + case PARSERSTRING_TARGET: + ctx->curr = ctx->data + phdr->TargetOffset; + ctx->bytes_remaining = phdr->TargetLength; + break; + case PARSERSTRING_CONNECTION: + ctx->curr = ctx->data + phdr->ConnectionOffset; + ctx->bytes_remaining = phdr->ConnectionLength; + break; + case PARSERSTRING_NAME: + ctx->curr = ctx->data + phdr->NameOffset; + ctx->bytes_remaining = phdr->NameLength; + break; + default: + ERRDRV("%s - bad which_string %d", __func__, which_string); + RETVOID; + break; + } + RETVOID; + +Away: + return; +} + +void +parser_done(PARSER_CONTEXT *ctx) +{ + if (!ctx) + return; + Controlvm_Payload_Bytes_Buffered -= ctx->param_bytes; + kfree(ctx); +} + +/** Return length of string not counting trailing spaces. */ +static int +string_length_no_trail(char *s, int len) +{ + int i = len - 1; + while (i >= 0) { + if (!isspace(s[i])) + return i + 1; + i--; + } + return 0; +} + +/** Grab the next name and value out of the parameter buffer. + * The entire parameter buffer looks like this: + * <name>=<value>\0 + * <name>=<value>\0 + * ... + * \0 + * If successful, the next <name> value is returned within the supplied + * <nam> buffer (the value is always upper-cased), and the corresponding + * <value> is returned within a kmalloc()ed buffer, whose pointer is + * provided as the return value of this function. + * (The total number of bytes allocated is strlen(<value>)+1.) + * + * NULL is returned to indicate failure, which can occur for several reasons: + * - all <name>=<value> pairs have already been processed + * - bad parameter + * - parameter buffer ends prematurely (couldn't find an '=' or '\0' within + * the confines of the parameter buffer) + * - the <nam> buffer is not large enough to hold the <name> of the next + * parameter + */ +void * +parser_param_get(PARSER_CONTEXT *ctx, char *nam, int namesize) +{ + u8 *pscan, *pnam = nam; + ulong nscan; + int value_length = -1, orig_value_length = -1; + void *value = NULL; + int i; + int closing_quote = 0; + + if (!ctx) + return NULL; + pscan = ctx->curr; + nscan = ctx->bytes_remaining; + if (nscan == 0) + return NULL; + if (*pscan == '\0') + /* This is the normal return point after you have processed + * all of the <name>=<value> pairs in a syntactically-valid + * parameter buffer. + */ + return NULL; + + /* skip whitespace */ + while (isspace(*pscan)) { + pscan++; + nscan--; + if (nscan == 0) + return NULL; + } + + while (*pscan != ':') { + if (namesize <= 0) { + ERRDRV("%s - name too big", __func__); + return NULL; + } + *pnam = toupper(*pscan); + pnam++; + namesize--; + pscan++; + nscan--; + if (nscan == 0) { + ERRDRV("%s - unexpected end of input parsing name", + __func__); + return NULL; + } + } + if (namesize <= 0) { + ERRDRV("%s - name too big", __func__); + return NULL; + } + *pnam = '\0'; + nam[string_length_no_trail(nam, strlen(nam))] = '\0'; + + /* point to char immediately after ":" in "<name>:<value>" */ + pscan++; + nscan--; + /* skip whitespace */ + while (isspace(*pscan)) { + pscan++; + nscan--; + if (nscan == 0) { + ERRDRV("%s - unexpected end of input looking for value", + __func__); + return NULL; + } + } + if (nscan == 0) { + ERRDRV("%s - unexpected end of input looking for value", + __func__); + return NULL; + } + if (*pscan == '\'' || *pscan == '"') { + closing_quote = *pscan; + pscan++; + nscan--; + if (nscan == 0) { + ERRDRV("%s - unexpected end of input after %c", + __func__, closing_quote); + return NULL; + } + } + + /* look for a separator character, terminator character, or + * end of data + */ + for (i = 0, value_length = -1; i < nscan; i++) { + if (closing_quote) { + if (pscan[i] == '\0') { + ERRDRV("%s - unexpected end of input parsing quoted value", __func__); + return NULL; + } + if (pscan[i] == closing_quote) { + value_length = i; + break; + } + } else + if (pscan[i] == ',' || pscan[i] == ';' + || pscan[i] == '\0') { + value_length = i; + break; + } + } + if (value_length < 0) { + if (closing_quote) { + ERRDRV("%s - unexpected end of input parsing quoted value", __func__); + return NULL; + } + value_length = nscan; + } + orig_value_length = value_length; + if (closing_quote == 0) + value_length = string_length_no_trail(pscan, orig_value_length); + value = kmalloc(value_length + 1, GFP_KERNEL|__GFP_NORETRY); + if (value == NULL) + return NULL; + memcpy(value, pscan, value_length); + ((u8 *) (value))[value_length] = '\0'; + + pscan += orig_value_length; + nscan -= orig_value_length; + + /* skip past separator or closing quote */ + if (nscan > 0) { + if (*pscan != '\0') { + pscan++; + nscan--; + } + } + + if (closing_quote && (nscan > 0)) { + /* we still need to skip around the real separator if present */ + /* first, skip whitespace */ + while (isspace(*pscan)) { + pscan++; + nscan--; + if (nscan == 0) + break; + } + if (nscan > 0) { + if (*pscan == ',' || *pscan == ';') { + pscan++; + nscan--; + } else if (*pscan != '\0') { + ERRDRV("%s - missing separator after quoted string", __func__); + kfree(value); + value = NULL; + return NULL; + } + } + } + ctx->curr = pscan; + ctx->bytes_remaining = nscan; + return value; +} + +void * +parser_string_get(PARSER_CONTEXT *ctx) +{ + u8 *pscan; + ulong nscan; + int value_length = -1; + void *value = NULL; + int i; + + if (!ctx) + return NULL; + pscan = ctx->curr; + nscan = ctx->bytes_remaining; + if (nscan == 0) + return NULL; + if (!pscan) + return NULL; + for (i = 0, value_length = -1; i < nscan; i++) + if (pscan[i] == '\0') { + value_length = i; + break; + } + if (value_length < 0) /* '\0' was not included in the length */ + value_length = nscan; + value = kmalloc(value_length + 1, GFP_KERNEL|__GFP_NORETRY); + if (value == NULL) + return NULL; + if (value_length > 0) + memcpy(value, pscan, value_length); + ((u8 *) (value))[value_length] = '\0'; + return value; +} diff --git a/drivers/staging/unisys/visorchipset/parser.h b/drivers/staging/unisys/visorchipset/parser.h new file mode 100644 index 00000000000..a0cc50a533c --- /dev/null +++ b/drivers/staging/unisys/visorchipset/parser.h @@ -0,0 +1,45 @@ +/* parser.h + * + * Copyright © 2010 - 2013 UNISYS CORPORATION + * 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. + */ + +#ifndef __PARSER_H__ +#define __PARSER_H__ + +#include "uniklog.h" +#include "timskmod.h" +#include "channel.h" + +typedef enum { + PARSERSTRING_INITIATOR, + PARSERSTRING_TARGET, + PARSERSTRING_CONNECTION, + PARSERSTRING_NAME, +} PARSER_WHICH_STRING; + +typedef struct PARSER_CONTEXT_Tag PARSER_CONTEXT; + +PARSER_CONTEXT *parser_init(U64 addr, U32 bytes, BOOL isLocal, BOOL *tryAgain); +PARSER_CONTEXT *parser_init_byteStream(U64 addr, U32 bytes, BOOL isLocal, + BOOL *tryAgain); +void parser_param_start(PARSER_CONTEXT *ctx, PARSER_WHICH_STRING which_string); +void *parser_param_get(PARSER_CONTEXT *ctx, char *nam, int namesize); +void *parser_string_get(PARSER_CONTEXT *ctx); +GUID parser_id_get(PARSER_CONTEXT *ctx); +char *parser_simpleString_get(PARSER_CONTEXT *ctx); +void *parser_byteStream_get(PARSER_CONTEXT *ctx, ulong *nbytes); +void parser_done(PARSER_CONTEXT *ctx); + +#endif diff --git a/drivers/staging/unisys/visorchipset/testing.h b/drivers/staging/unisys/visorchipset/testing.h new file mode 100644 index 00000000000..a44f5556cb2 --- /dev/null +++ b/drivers/staging/unisys/visorchipset/testing.h @@ -0,0 +1,41 @@ +/* testing.h + * + * Copyright © 2010 - 2013 UNISYS CORPORATION + * 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. + */ + +#ifndef __VISORCHIPSET_TESTING_H__ +#define __VISORCHIPSET_TESTING_H__ + +#define VISORCHIPSET_TEST_PROC +#include "globals.h" +#include "controlvmchannel.h" + +void test_produce_test_message(CONTROLVM_MESSAGE *msg, int isLocalTestAddr); +BOOL test_consume_test_message(CONTROLVM_MESSAGE *msg); +void test_manufacture_vnic_client_add(void *p); +void test_manufacture_vnic_client_add_phys(HOSTADDRESS addr); +void test_manufacture_preamble_messages(void); +void test_manufacture_device_attach(ulong busNo, ulong devNo); +void test_manufacture_device_add(ulong busNo, ulong devNo, GUID dataTypeGuid, + void *pChannel); +void test_manufacture_add_bus(ulong busNo, ulong maxDevices, + GUID id, u8 *name, BOOL isServer); +void test_manufacture_device_destroy(ulong busNo, ulong devNo); +void test_manufacture_bus_destroy(ulong busNo); +void test_manufacture_detach_externalPort(ulong switchNo, ulong externalPortNo); +void test_manufacture_detach_internalPort(ulong switchNo, ulong internalPortNo); +void test_cleanup(void); + +#endif diff --git a/drivers/staging/unisys/visorchipset/visorchipset.h b/drivers/staging/unisys/visorchipset/visorchipset.h new file mode 100644 index 00000000000..8e62a89a7d2 --- /dev/null +++ b/drivers/staging/unisys/visorchipset/visorchipset.h @@ -0,0 +1,307 @@ +/* visorchipset.h + * + * Copyright © 2010 - 2013 UNISYS CORPORATION + * 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. + */ + +#ifndef __VISORCHIPSET_H__ +#define __VISORCHIPSET_H__ + +#include "timskmod.h" +#include "channel.h" +#include "controlvmchannel.h" +#include "parser.h" +#include "procobjecttree.h" +#include "vbusdeviceinfo.h" +#include "vbushelper.h" + +/** Describes the state from the perspective of which controlvm messages have + * been received for a bus or device. + */ +typedef struct { + U32 created:1; + U32 attached:1; + U32 configured:1; + U32 running:1; + /* Add new fields above. */ + /* Remaining bits in this 32-bit word are unused. */ +} VISORCHIPSET_STATE; + +typedef enum { + /** address is guest physical, but outside of the physical memory + * region that is controlled by the running OS (this is the normal + * address type for Supervisor channels) + */ + ADDRTYPE_localPhysical, + + /** address is guest physical, and withIN the confines of the + * physical memory controlled by the running OS. + */ + ADDRTYPE_localTest, +} VISORCHIPSET_ADDRESSTYPE; + +typedef enum { + CRASH_dev, + CRASH_bus, +} CRASH_OBJ_TYPE; + +/** Attributes for a particular Supervisor channel. + */ +typedef struct { + VISORCHIPSET_ADDRESSTYPE addrType; + HOSTADDRESS channelAddr; + struct InterruptInfo intr; + U64 nChannelBytes; + GUID channelTypeGuid; + GUID channelInstGuid; + +} VISORCHIPSET_CHANNEL_INFO; + +/** Attributes for a particular Supervisor device. + * Any visorchipset client can query these attributes using + * visorchipset_get_client_device_info() or + * visorchipset_get_server_device_info(). + */ +typedef struct { + struct list_head entry; + U32 busNo; + U32 devNo; + GUID devInstGuid; + VISORCHIPSET_STATE state; + VISORCHIPSET_CHANNEL_INFO chanInfo; + U32 Reserved1; /* CONTROLVM_ID */ + U64 Reserved2; + U32 switchNo; /* when devState.attached==1 */ + U32 internalPortNo; /* when devState.attached==1 */ + CONTROLVM_MESSAGE_HEADER pendingMsgHdr; /* CONTROLVM_MESSAGE */ + /** For private use by the bus driver */ + void *bus_driver_context; + +} VISORCHIPSET_DEVICE_INFO; + +static inline VISORCHIPSET_DEVICE_INFO * +finddevice(struct list_head *list, U32 busNo, U32 devNo) +{ + VISORCHIPSET_DEVICE_INFO *p; + + list_for_each_entry(p, list, entry) { + if (p->busNo == busNo && p->devNo == devNo) + return p; + } + return NULL; +} + +static inline void delbusdevices(struct list_head *list, U32 busNo) +{ + VISORCHIPSET_DEVICE_INFO *p; + + list_for_each_entry(p, list, entry) { + if (p->busNo == busNo) { + list_del(&p->entry); + kfree(p); + } + } +} + +/** Attributes for a particular Supervisor bus. + * (For a service partition acting as the server for buses/devices, there + * is a 1-to-1 relationship between busses and guest partitions.) + * Any visorchipset client can query these attributes using + * visorchipset_get_client_bus_info() or visorchipset_get_bus_info(). + */ +typedef struct { + struct list_head entry; + U32 busNo; + VISORCHIPSET_STATE state; + VISORCHIPSET_CHANNEL_INFO chanInfo; + GUID partitionGuid; + U64 partitionHandle; + U8 *name; /* UTF8 */ + U8 *description; /* UTF8 */ + U64 Reserved1; + U32 Reserved2; + MYPROCOBJECT *procObject; + struct { + U32 server:1; + /* Add new fields above. */ + /* Remaining bits in this 32-bit word are unused. */ + } flags; + CONTROLVM_MESSAGE_HEADER pendingMsgHdr; /* CONTROLVM MsgHdr */ + /** For private use by the bus driver */ + void *bus_driver_context; + U64 devNo; + +} VISORCHIPSET_BUS_INFO; + +static inline VISORCHIPSET_BUS_INFO * +findbus(struct list_head *list, U32 busNo) +{ + VISORCHIPSET_BUS_INFO *p; + + list_for_each_entry(p, list, entry) { + if (p->busNo == busNo) + return p; + } + return NULL; +} + +/** Attributes for a particular Supervisor switch. + */ +typedef struct { + U32 switchNo; + VISORCHIPSET_STATE state; + GUID switchTypeGuid; + U8 *authService1; + U8 *authService2; + U8 *authService3; + U8 *securityContext; + U64 Reserved; + U32 Reserved2; /* CONTROLVM_ID */ + struct device dev; + BOOL dev_exists; + CONTROLVM_MESSAGE_HEADER pendingMsgHdr; + +} VISORCHIPSET_SWITCH_INFO; + +/** Attributes for a particular Supervisor external port, which is connected + * to a specific switch. + */ +typedef struct { + U32 switchNo; + U32 externalPortNo; + VISORCHIPSET_STATE state; + GUID networkZoneGuid; + int pdPort; + U8 *ip; + U8 *ipNetmask; + U8 *ipBroadcast; + U8 *ipNetwork; + U8 *ipGateway; + U8 *ipDNS; + U64 Reserved1; + U32 Reserved2; /* CONTROLVM_ID */ + struct device dev; + BOOL dev_exists; + CONTROLVM_MESSAGE_HEADER pendingMsgHdr; + +} VISORCHIPSET_EXTERNALPORT_INFO; + +/** Attributes for a particular Supervisor internal port, which is how a + * device connects to a particular switch. + */ +typedef struct { + U32 switchNo; + U32 internalPortNo; + VISORCHIPSET_STATE state; + U32 busNo; /* valid only when state.attached == 1 */ + U32 devNo; /* valid only when state.attached == 1 */ + U64 Reserved1; + U32 Reserved2; /* CONTROLVM_ID */ + CONTROLVM_MESSAGE_HEADER pendingMsgHdr; + MYPROCOBJECT *procObject; + +} VISORCHIPSET_INTERNALPORT_INFO; + +/* These functions will be called from within visorchipset when certain + * events happen. (The implementation of these functions is outside of + * visorchipset.) + */ +typedef struct { + void (*bus_create)(ulong busNo); + void (*bus_destroy)(ulong busNo); + void (*device_create)(ulong busNo, ulong devNo); + void (*device_destroy)(ulong busNo, ulong devNo); + void (*device_pause)(ulong busNo, ulong devNo); + void (*device_resume)(ulong busNo, ulong devNo); + int (*get_channel_info)(GUID typeGuid, ulong *minSize, + ulong *maxSize); +} VISORCHIPSET_BUSDEV_NOTIFIERS; + +/* These functions live inside visorchipset, and will be called to indicate + * responses to specific events (by code outside of visorchipset). + * For now, the value for each response is simply either: + * 0 = it worked + * -1 = it failed + */ +typedef struct { + void (*bus_create)(ulong busNo, int response); + void (*bus_destroy)(ulong busNo, int response); + void (*device_create)(ulong busNo, ulong devNo, int response); + void (*device_destroy)(ulong busNo, ulong devNo, int response); + void (*device_pause)(ulong busNo, ulong devNo, int response); + void (*device_resume)(ulong busNo, ulong devNo, int response); +} VISORCHIPSET_BUSDEV_RESPONDERS; + +/** Register functions (in the bus driver) to get called by visorchipset + * whenever a bus or device appears for which this service partition is + * to be the server for. visorchipset will fill in <responders>, to + * indicate functions the bus driver should call to indicate message + * responses. + */ +void +visorchipset_register_busdev_client(VISORCHIPSET_BUSDEV_NOTIFIERS *notifiers, + VISORCHIPSET_BUSDEV_RESPONDERS *responders, + ULTRA_VBUS_DEVICEINFO *driverInfo); + +/** Register functions (in the bus driver) to get called by visorchipset + * whenever a bus or device appears for which this service partition is + * to be the client for. visorchipset will fill in <responders>, to + * indicate functions the bus driver should call to indicate message + * responses. + */ +void +visorchipset_register_busdev_server(VISORCHIPSET_BUSDEV_NOTIFIERS *notifiers, + VISORCHIPSET_BUSDEV_RESPONDERS *responders, + ULTRA_VBUS_DEVICEINFO *driverInfo); + +typedef void (*SPARREPORTEVENT_COMPLETE_FUNC) (CONTROLVM_MESSAGE *msg, + int status); + +void device_pause_response(ulong busNo, ulong devNo, int response); + +BOOL visorchipset_get_bus_info(ulong busNo, VISORCHIPSET_BUS_INFO *busInfo); +BOOL visorchipset_get_device_info(ulong busNo, ulong devNo, + VISORCHIPSET_DEVICE_INFO *devInfo); +BOOL visorchipset_get_switch_info(ulong switchNo, + VISORCHIPSET_SWITCH_INFO *switchInfo); +BOOL visorchipset_get_externalport_info(ulong switchNo, ulong externalPortNo, + VISORCHIPSET_EXTERNALPORT_INFO + *externalPortInfo); +BOOL visorchipset_set_bus_context(ulong busNo, void *context); +BOOL visorchipset_set_device_context(ulong busNo, ulong devNo, void *context); +int visorchipset_chipset_ready(void); +int visorchipset_chipset_selftest(void); +int visorchipset_chipset_notready(void); +void visorchipset_controlvm_respond_reportEvent(CONTROLVM_MESSAGE *msg, + void *payload); +void visorchipset_save_message(CONTROLVM_MESSAGE *msg, CRASH_OBJ_TYPE type); +void *visorchipset_cache_alloc(struct kmem_cache *pool, + BOOL ok_to_block, char *fn, int ln); +void visorchipset_cache_free(struct kmem_cache *pool, void *p, + char *fn, int ln); + +#if defined(TRANSMITFILE_DEBUG) || defined(DEBUG) +#define DBG_GETFILE_PAYLOAD(msg, controlvm_header) \ + LOGINF(msg, \ + (ulong)controlvm_header.PayloadVmOffset, \ + (ulong)controlvm_header.PayloadMaxBytes) +#define DBG_GETFILE(fmt, ...) LOGINF(fmt, ##__VA_ARGS__) +#define DBG_PUTFILE(fmt, ...) LOGINF(fmt, ##__VA_ARGS__) +#else +#define DBG_GETFILE_PAYLOAD(msg, controlvm_header) +#define DBG_GETFILE(fmt, ...) +#define DBG_PUTFILE(fmt, ...) +#endif + +#endif diff --git a/drivers/staging/unisys/visorchipset/visorchipset_main.c b/drivers/staging/unisys/visorchipset/visorchipset_main.c new file mode 100644 index 00000000000..e0ec3a4fa3a --- /dev/null +++ b/drivers/staging/unisys/visorchipset/visorchipset_main.c @@ -0,0 +1,2912 @@ +/* visorchipset_main.c + * + * Copyright � 2010 - 2013 UNISYS CORPORATION + * 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. + */ + +#include "globals.h" +#include "controlvm.h" +#include "visorchipset.h" +#include "procobjecttree.h" +#include "visorchannel.h" +#include "periodic_work.h" +#include "testing.h" +#include "file.h" +#include "parser.h" +#include "uniklog.h" +#include "uisutils.h" +#include "guidutils.h" +#include "controlvmcompletionstatus.h" +#include "guestlinuxdebug.h" +#include "filexfer.h" + +#include <linux/nls.h> +#include <linux/netdevice.h> +#include <linux/platform_device.h> + +#define CURRENT_FILE_PC VISOR_CHIPSET_PC_visorchipset_main_c +#define TEST_VNIC_PHYSITF "eth0" /* physical network itf for + * vnic loopback test */ +#define TEST_VNIC_SWITCHNO 1 +#define TEST_VNIC_BUSNO 9 + +#define MAX_NAME_SIZE 128 +#define MAX_IP_SIZE 50 +#define MAXOUTSTANDINGCHANNELCOMMAND 256 +#define POLLJIFFIES_CONTROLVMCHANNEL_FAST 1 +#define POLLJIFFIES_CONTROLVMCHANNEL_SLOW 100 + +/* When the controlvm channel is idle for at least MIN_IDLE_SECONDS, +* we switch to slow polling mode. As soon as we get a controlvm +* message, we switch back to fast polling mode. +*/ +#define MIN_IDLE_SECONDS 10 +ulong Poll_jiffies = POLLJIFFIES_CONTROLVMCHANNEL_FAST; +ulong Most_recent_message_jiffies; /* when we got our last + * controlvm message */ +static inline char * +NONULLSTR(char *s) +{ + if (s) + return s; + else + return ""; +} + +static int serverregistered; +static int clientregistered; + +#define MAX_CHIPSET_EVENTS 2 +static U8 chipset_events[MAX_CHIPSET_EVENTS] = { 0, 0 }; + +static struct delayed_work Periodic_controlvm_work; +static struct workqueue_struct *Periodic_controlvm_workqueue; +DEFINE_SEMAPHORE(NotifierLock); + +typedef struct { + CONTROLVM_MESSAGE message; + unsigned int crc; +} MESSAGE_ENVELOPE; + +static CONTROLVM_MESSAGE_HEADER g_DiagMsgHdr; +static CONTROLVM_MESSAGE_HEADER g_ChipSetMsgHdr; +static CONTROLVM_MESSAGE_HEADER g_DelDumpMsgHdr; +static const GUID UltraDiagPoolChannelProtocolGuid = + ULTRA_DIAG_POOL_CHANNEL_PROTOCOL_GUID; +/* 0xffffff is an invalid Bus/Device number */ +static ulong g_diagpoolBusNo = 0xffffff; +static ulong g_diagpoolDevNo = 0xffffff; +static CONTROLVM_MESSAGE_PACKET g_DeviceChangeStatePacket; + +/* Only VNIC and VHBA channels are sent to visorclientbus (aka + * "visorhackbus") + */ +#define FOR_VISORHACKBUS(channel_type_guid) \ + ((memcmp(&channel_type_guid, &UltraVnicChannelProtocolGuid, \ + sizeof(GUID)) == 0) || \ + (memcmp(&channel_type_guid, &UltraVhbaChannelProtocolGuid, \ + sizeof(GUID)) == 0)) +#define FOR_VISORBUS(channel_type_guid) (!(FOR_VISORHACKBUS(channel_type_guid))) + +#define is_diagpool_channel(channel_type_guid) \ + (memcmp(&channel_type_guid, \ + &UltraDiagPoolChannelProtocolGuid, sizeof(GUID)) == 0) + +typedef enum { + PARTPROP_invalid, + PARTPROP_name, + PARTPROP_description, + PARTPROP_handle, + PARTPROP_busNumber, + /* add new properties above, but don't forget to change + * InitPartitionProperties() and show_partition_property() also... + */ + PARTPROP_last +} PARTITION_property; +static const char *PartitionTypeNames[] = { "partition", NULL }; + +static char *PartitionPropertyNames[PARTPROP_last + 1]; +static void +InitPartitionProperties(void) +{ + char **p = PartitionPropertyNames; + p[PARTPROP_invalid] = ""; + p[PARTPROP_name] = "name"; + p[PARTPROP_description] = "description"; + p[PARTPROP_handle] = "handle"; + p[PARTPROP_busNumber] = "busNumber"; + p[PARTPROP_last] = NULL; +} + +typedef enum { + CTLVMPROP_invalid, + CTLVMPROP_physAddr, + CTLVMPROP_controlChannelAddr, + CTLVMPROP_controlChannelBytes, + CTLVMPROP_sparBootPart, + CTLVMPROP_sparStoragePart, + CTLVMPROP_livedumpLength, + CTLVMPROP_livedumpCrc32, + /* add new properties above, but don't forget to change + * InitControlVmProperties() show_controlvm_property() also... + */ + CTLVMPROP_last +} CONTROLVM_property; + +static const char *ControlVmTypeNames[] = { "controlvm", NULL }; + +static char *ControlVmPropertyNames[CTLVMPROP_last + 1]; +static void +InitControlVmProperties(void) +{ + char **p = ControlVmPropertyNames; + p[CTLVMPROP_invalid] = ""; + p[CTLVMPROP_physAddr] = "physAddr"; + p[CTLVMPROP_controlChannelAddr] = "controlChannelAddr"; + p[CTLVMPROP_controlChannelBytes] = "controlChannelBytes"; + p[CTLVMPROP_sparBootPart] = "spar_boot_part"; + p[CTLVMPROP_sparStoragePart] = "spar_storage_part"; + p[CTLVMPROP_livedumpLength] = "livedumpLength"; + p[CTLVMPROP_livedumpCrc32] = "livedumpCrc32"; + p[CTLVMPROP_last] = NULL; +} + +static MYPROCOBJECT *ControlVmObject; +static MYPROCTYPE *PartitionType; +static MYPROCTYPE *ControlVmType; + +#define VISORCHIPSET_DIAG_PROC_ENTRY_FN "diagdump" +static struct proc_dir_entry *diag_proc_dir; + +#define VISORCHIPSET_CHIPSET_PROC_ENTRY_FN "chipsetready" +static struct proc_dir_entry *chipset_proc_dir; + +#define VISORCHIPSET_PARAHOTPLUG_PROC_ENTRY_FN "parahotplug" +static struct proc_dir_entry *parahotplug_proc_dir; + +static LIST_HEAD(BusInfoList); +static LIST_HEAD(DevInfoList); + +static struct proc_dir_entry *ProcDir; +static VISORCHANNEL *ControlVm_channel; + +static ssize_t visorchipset_proc_read_writeonly(struct file *file, + char __user *buf, + size_t len, loff_t *offset); +static ssize_t proc_read_installer(struct file *file, char __user *buf, + size_t len, loff_t *offset); +static ssize_t proc_write_installer(struct file *file, + const char __user *buffer, + size_t count, loff_t *ppos); +static ssize_t proc_read_toolaction(struct file *file, char __user *buf, + size_t len, loff_t *offset); +static ssize_t proc_write_toolaction(struct file *file, + const char __user *buffer, + size_t count, loff_t *ppos); +static ssize_t proc_read_bootToTool(struct file *file, char __user *buf, + size_t len, loff_t *offset); +static ssize_t proc_write_bootToTool(struct file *file, + const char __user *buffer, + size_t count, loff_t *ppos); +static const struct file_operations proc_installer_fops = { + .read = proc_read_installer, + .write = proc_write_installer, +}; + +static const struct file_operations proc_toolaction_fops = { + .read = proc_read_toolaction, + .write = proc_write_toolaction, +}; + +static const struct file_operations proc_bootToTool_fops = { + .read = proc_read_bootToTool, + .write = proc_write_bootToTool, +}; + +typedef struct { + U8 *ptr; /* pointer to base address of payload pool */ + U64 offset; /* offset from beginning of controlvm + * channel to beginning of payload * pool */ + U32 bytes; /* number of bytes in payload pool */ +} CONTROLVM_PAYLOAD_INFO; + +/* Manages the request payload in the controlvm channel */ +static CONTROLVM_PAYLOAD_INFO ControlVm_payload_info; + +static pCHANNEL_HEADER Test_Vnic_channel; + +typedef struct { + CONTROLVM_MESSAGE_HEADER Dumpcapture_header; + CONTROLVM_MESSAGE_HEADER Gettextdump_header; + CONTROLVM_MESSAGE_HEADER Dumpcomplete_header; + BOOL Gettextdump_outstanding; + u32 crc32; + ulong length; + atomic_t buffers_in_use; + ulong destination; +} LIVEDUMP_INFO; +/* Manages the info for a CONTROLVM_DUMP_CAPTURESTATE / + * CONTROLVM_DUMP_GETTEXTDUMP / CONTROLVM_DUMP_COMPLETE conversation. + */ +static LIVEDUMP_INFO LiveDump_info; + +/* The following globals are used to handle the scenario where we are unable to + * offload the payload from a controlvm message due to memory requirements. In + * this scenario, we simply stash the controlvm message, then attempt to + * process it again the next time controlvm_periodic_work() runs. + */ +static CONTROLVM_MESSAGE ControlVm_Pending_Msg; +static BOOL ControlVm_Pending_Msg_Valid = FALSE; + +/* Pool of struct putfile_buffer_entry, for keeping track of pending (incoming) + * TRANSMIT_FILE PutFile payloads. + */ +static struct kmem_cache *Putfile_buffer_list_pool; +static const char Putfile_buffer_list_pool_name[] = + "controlvm_putfile_buffer_list_pool"; + +/* This identifies a data buffer that has been received via a controlvm messages + * in a remote --> local CONTROLVM_TRANSMIT_FILE conversation. + */ +struct putfile_buffer_entry { + struct list_head next; /* putfile_buffer_entry list */ + PARSER_CONTEXT *parser_ctx; /* points to buffer containing input data */ +}; + +/* List of struct putfile_request *, via next_putfile_request member. + * Each entry in this list identifies an outstanding TRANSMIT_FILE + * conversation. + */ +static LIST_HEAD(Putfile_request_list); + +/* This describes a buffer and its current state of transfer (e.g., how many + * bytes have already been supplied as putfile data, and how many bytes are + * remaining) for a putfile_request. + */ +struct putfile_active_buffer { + /* a payload from a controlvm message, containing a file data buffer */ + PARSER_CONTEXT *parser_ctx; + /* points within data area of parser_ctx to next byte of data */ + u8 *pnext; + /* # bytes left from <pnext> to the end of this data buffer */ + size_t bytes_remaining; +}; + +#define PUTFILE_REQUEST_SIG 0x0906101302281211 +/* This identifies a single remote --> local CONTROLVM_TRANSMIT_FILE + * conversation. Structs of this type are dynamically linked into + * <Putfile_request_list>. + */ +struct putfile_request { + u64 sig; /* PUTFILE_REQUEST_SIG */ + + /* header from original TransmitFile request */ + CONTROLVM_MESSAGE_HEADER controlvm_header; + u64 file_request_number; /* from original TransmitFile request */ + + /* link to next struct putfile_request */ + struct list_head next_putfile_request; + + /* most-recent sequence number supplied via a controlvm message */ + u64 data_sequence_number; + + /* head of putfile_buffer_entry list, which describes the data to be + * supplied as putfile data; + * - this list is added to when controlvm messages come in that supply + * file data + * - this list is removed from via the hotplug program that is actually + * consuming these buffers to write as file data */ + struct list_head input_buffer_list; + spinlock_t req_list_lock; /* lock for input_buffer_list */ + + /* waiters for input_buffer_list to go non-empty */ + wait_queue_head_t input_buffer_wq; + + /* data not yet read within current putfile_buffer_entry */ + struct putfile_active_buffer active_buf; + + /* <0 = failed, 0 = in-progress, >0 = successful; */ + /* note that this must be set with req_list_lock, and if you set <0, */ + /* it is your responsibility to also free up all of the other objects */ + /* in this struct (like input_buffer_list, active_buf.parser_ctx) */ + /* before releasing the lock */ + int completion_status; +}; + +atomic_t Visorchipset_cache_buffers_in_use = ATOMIC_INIT(0); + +struct parahotplug_request { + struct list_head list; + int id; + unsigned long expiration; + CONTROLVM_MESSAGE msg; +}; + +static LIST_HEAD(Parahotplug_request_list); +static DEFINE_SPINLOCK(Parahotplug_request_list_lock); /* lock for above */ +static void parahotplug_process_list(void); + +/* Manages the info for a CONTROLVM_DUMP_CAPTURESTATE / + * CONTROLVM_REPORTEVENT. + */ +static VISORCHIPSET_BUSDEV_NOTIFIERS BusDev_Server_Notifiers; +static VISORCHIPSET_BUSDEV_NOTIFIERS BusDev_Client_Notifiers; + +static void bus_create_response(ulong busNo, int response); +static void bus_destroy_response(ulong busNo, int response); +static void device_create_response(ulong busNo, ulong devNo, int response); +static void device_destroy_response(ulong busNo, ulong devNo, int response); +static void device_resume_response(ulong busNo, ulong devNo, int response); + +static VISORCHIPSET_BUSDEV_RESPONDERS BusDev_Responders = { + .bus_create = bus_create_response, + .bus_destroy = bus_destroy_response, + .device_create = device_create_response, + .device_destroy = device_destroy_response, + .device_pause = device_pause_response, + .device_resume = device_resume_response, +}; + +/* info for /dev/visorchipset */ +static dev_t MajorDev = -1; /**< indicates major num for device */ + +/* /sys/devices/platform/visorchipset */ +static struct platform_device Visorchipset_platform_device = { + .name = "visorchipset", + .id = -1, +}; + +/* Function prototypes */ +static void controlvm_respond(CONTROLVM_MESSAGE_HEADER *msgHdr, int response); +static void controlvm_respond_chipset_init(CONTROLVM_MESSAGE_HEADER *msgHdr, + int response, + ULTRA_CHIPSET_FEATURE features); +static void controlvm_respond_physdev_changestate(CONTROLVM_MESSAGE_HEADER * + msgHdr, int response, + ULTRA_SEGMENT_STATE state); + +static void +show_partition_property(struct seq_file *f, void *ctx, int property) +{ + VISORCHIPSET_BUS_INFO *info = (VISORCHIPSET_BUS_INFO *) (ctx); + + switch (property) { + case PARTPROP_name: + seq_printf(f, "%s\n", NONULLSTR(info->name)); + break; + case PARTPROP_description: + seq_printf(f, "%s\n", NONULLSTR(info->description)); + break; + case PARTPROP_handle: + seq_printf(f, "0x%-16.16Lx\n", info->partitionHandle); + break; + case PARTPROP_busNumber: + seq_printf(f, "%d\n", info->busNo); + break; + default: + seq_printf(f, "(%d??)\n", property); + break; + } +} + +static void +show_controlvm_property(struct seq_file *f, void *ctx, int property) +{ + /* Note: ctx is not needed since we only have 1 controlvm channel */ + switch (property) { + case CTLVMPROP_physAddr: + if (ControlVm_channel == NULL) + seq_puts(f, "0x0\n"); + else + seq_printf(f, "0x%-16.16Lx\n", + visorchannel_get_physaddr + (ControlVm_channel)); + break; + case CTLVMPROP_controlChannelAddr: + if (ControlVm_channel == NULL) + seq_puts(f, "0x0\n"); + else { + GUEST_PHYSICAL_ADDRESS addr = 0; + visorchannel_read(ControlVm_channel, + offsetof + (ULTRA_CONTROLVM_CHANNEL_PROTOCOL, + gpControlChannel), &addr, + sizeof(addr)); + seq_printf(f, "0x%-16.16Lx\n", (u64) (addr)); + } + break; + case CTLVMPROP_controlChannelBytes: + if (ControlVm_channel == NULL) + seq_puts(f, "0x0\n"); + else { + U32 bytes = 0; + visorchannel_read(ControlVm_channel, + offsetof + (ULTRA_CONTROLVM_CHANNEL_PROTOCOL, + ControlChannelBytes), &bytes, + sizeof(bytes)); + seq_printf(f, "%lu\n", (ulong) (bytes)); + } + break; + case CTLVMPROP_sparBootPart: + seq_puts(f, "0:0:0:0/1\n"); + break; + case CTLVMPROP_sparStoragePart: + seq_puts(f, "0:0:0:0/2\n"); + break; + case CTLVMPROP_livedumpLength: + seq_printf(f, "%lu\n", LiveDump_info.length); + break; + case CTLVMPROP_livedumpCrc32: + seq_printf(f, "%lu\n", (ulong) LiveDump_info.crc32); + break; + default: + seq_printf(f, "(%d??)\n", property); + break; + } +} + +static void +proc_Init(void) +{ + if (ProcDir == NULL) { + ProcDir = proc_mkdir(MYDRVNAME, NULL); + if (ProcDir == NULL) { + LOGERR("failed to create /proc directory %s", + MYDRVNAME); + POSTCODE_LINUX_2(CHIPSET_INIT_FAILURE_PC, + POSTCODE_SEVERITY_ERR); + } + } +} + +static void +proc_DeInit(void) +{ + if (ProcDir != NULL) + remove_proc_entry(MYDRVNAME, NULL); + ProcDir = NULL; +} + +#if 0 +static void +testUnicode(void) +{ + wchar_t unicodeString[] = { 'a', 'b', 'c', 0 }; + char s[sizeof(unicodeString) * NLS_MAX_CHARSET_SIZE]; + wchar_t unicode2[99]; + + /* NOTE: Either due to a bug, or feature I don't understand, the + * kernel utf8_mbstowcs() and utf_wcstombs() do NOT copy the + * trailed NUL byte!! REALLY!!!!! Arrrrgggghhhhh + */ + + LOGINF("sizeof(wchar_t) = %d", sizeof(wchar_t)); + LOGINF("utf8_wcstombs=%d", + chrs = utf8_wcstombs(s, unicodeString, sizeof(s))); + if (chrs >= 0) + s[chrs] = '\0'; /* GRRRRRRRR */ + LOGINF("s='%s'", s); + LOGINF("utf8_mbstowcs=%d", chrs = utf8_mbstowcs(unicode2, s, 100)); + if (chrs >= 0) + unicode2[chrs] = 0; /* GRRRRRRRR */ + if (memcmp(unicodeString, unicode2, sizeof(unicodeString)) == 0) + LOGINF("strings match... good"); + else + LOGINF("strings did not match!!"); +} +#endif + +static void +busInfo_clear(void *v) +{ + VISORCHIPSET_BUS_INFO *p = (VISORCHIPSET_BUS_INFO *) (v); + + if (p->procObject) { + proc_DestroyObject(p->procObject); + p->procObject = NULL; + } + kfree(p->name); + p->name = NULL; + + kfree(p->description); + p->description = NULL; + + p->state.created = 0; + memset(p, 0, sizeof(VISORCHIPSET_BUS_INFO)); +} + +static void +devInfo_clear(void *v) +{ + VISORCHIPSET_DEVICE_INFO *p = (VISORCHIPSET_DEVICE_INFO *) (v); + p->state.created = 0; + memset(p, 0, sizeof(VISORCHIPSET_DEVICE_INFO)); +} + +static U8 +check_chipset_events(void) +{ + int i; + U8 send_msg = 1; + /* Check events to determine if response should be sent */ + for (i = 0; i < MAX_CHIPSET_EVENTS; i++) + send_msg &= chipset_events[i]; + return send_msg; +} + +static void +clear_chipset_events(void) +{ + int i; + /* Clear chipset_events */ + for (i = 0; i < MAX_CHIPSET_EVENTS; i++) + chipset_events[i] = 0; +} + +void +visorchipset_register_busdev_server(VISORCHIPSET_BUSDEV_NOTIFIERS *notifiers, + VISORCHIPSET_BUSDEV_RESPONDERS *responders, + ULTRA_VBUS_DEVICEINFO *driverInfo) +{ + LOCKSEM_UNINTERRUPTIBLE(&NotifierLock); + if (notifiers == NULL) { + memset(&BusDev_Server_Notifiers, 0, + sizeof(BusDev_Server_Notifiers)); + serverregistered = 0; /* clear flag */ + } else { + BusDev_Server_Notifiers = *notifiers; + serverregistered = 1; /* set flag */ + } + if (responders) + *responders = BusDev_Responders; + if (driverInfo) + BusDeviceInfo_Init(driverInfo, "chipset", "visorchipset", + VERSION, NULL, __DATE__, __TIME__); + + UNLOCKSEM(&NotifierLock); +} +EXPORT_SYMBOL_GPL(visorchipset_register_busdev_server); + +void +visorchipset_register_busdev_client(VISORCHIPSET_BUSDEV_NOTIFIERS *notifiers, + VISORCHIPSET_BUSDEV_RESPONDERS *responders, + ULTRA_VBUS_DEVICEINFO *driverInfo) +{ + LOCKSEM_UNINTERRUPTIBLE(&NotifierLock); + if (notifiers == NULL) { + memset(&BusDev_Client_Notifiers, 0, + sizeof(BusDev_Client_Notifiers)); + clientregistered = 0; /* clear flag */ + } else { + BusDev_Client_Notifiers = *notifiers; + clientregistered = 1; /* set flag */ + } + if (responders) + *responders = BusDev_Responders; + if (driverInfo) + BusDeviceInfo_Init(driverInfo, "chipset(bolts)", "visorchipset", + VERSION, NULL, __DATE__, __TIME__); + UNLOCKSEM(&NotifierLock); +} +EXPORT_SYMBOL_GPL(visorchipset_register_busdev_client); + +static void +cleanup_controlvm_structures(void) +{ + VISORCHIPSET_BUS_INFO *bi; + VISORCHIPSET_DEVICE_INFO *di; + + list_for_each_entry(bi, &BusInfoList, entry) { + busInfo_clear(bi); + list_del(&bi->entry); + kfree(bi); + } + + list_for_each_entry(di, &DevInfoList, entry) { + devInfo_clear(di); + list_del(&di->entry); + kfree(di); + } +} + +static void +chipset_init(CONTROLVM_MESSAGE *inmsg) +{ + static int chipset_inited; + ULTRA_CHIPSET_FEATURE features = 0; + int rc = CONTROLVM_RESP_SUCCESS; + + POSTCODE_LINUX_2(CHIPSET_INIT_ENTRY_PC, POSTCODE_SEVERITY_INFO); + if (chipset_inited) { + LOGERR("CONTROLVM_CHIPSET_INIT Failed: Already Done."); + RETINT(-CONTROLVM_RESP_ERROR_ALREADY_DONE); + } + chipset_inited = 1; + POSTCODE_LINUX_2(CHIPSET_INIT_EXIT_PC, POSTCODE_SEVERITY_INFO); + + /* Set features to indicate we support parahotplug (if Command + * also supports it). */ + features = + inmsg->cmd.initChipset. + features & ULTRA_CHIPSET_FEATURE_PARA_HOTPLUG; + + /* Set the "reply" bit so Command knows this is a + * features-aware driver. */ + features |= ULTRA_CHIPSET_FEATURE_REPLY; + +Away: + if (rc < 0) + cleanup_controlvm_structures(); + if (inmsg->hdr.Flags.responseExpected) + controlvm_respond_chipset_init(&inmsg->hdr, rc, features); +} + +static void +controlvm_init_response(CONTROLVM_MESSAGE *msg, + CONTROLVM_MESSAGE_HEADER *msgHdr, int response) +{ + memset(msg, 0, sizeof(CONTROLVM_MESSAGE)); + memcpy(&msg->hdr, msgHdr, sizeof(CONTROLVM_MESSAGE_HEADER)); + msg->hdr.PayloadBytes = 0; + msg->hdr.PayloadVmOffset = 0; + msg->hdr.PayloadMaxBytes = 0; + if (response < 0) { + msg->hdr.Flags.failed = 1; + msg->hdr.CompletionStatus = (U32) (-response); + } +} + +static void +controlvm_respond(CONTROLVM_MESSAGE_HEADER *msgHdr, int response) +{ + CONTROLVM_MESSAGE outmsg; + if (!ControlVm_channel) + return; + controlvm_init_response(&outmsg, msgHdr, response); + /* For DiagPool channel DEVICE_CHANGESTATE, we need to send + * back the deviceChangeState structure in the packet. */ + if (msgHdr->Id == CONTROLVM_DEVICE_CHANGESTATE + && g_DeviceChangeStatePacket.deviceChangeState.busNo == + g_diagpoolBusNo + && g_DeviceChangeStatePacket.deviceChangeState.devNo == + g_diagpoolDevNo) + outmsg.cmd = g_DeviceChangeStatePacket; + if (outmsg.hdr.Flags.testMessage == 1) { + LOGINF("%s controlvm_msg=0x%x response=%d for test message", + __func__, outmsg.hdr.Id, response); + return; + } + if (!visorchannel_signalinsert(ControlVm_channel, + CONTROLVM_QUEUE_REQUEST, &outmsg)) { + LOGERR("signalinsert failed!"); + return; + } +} + +static void +controlvm_respond_chipset_init(CONTROLVM_MESSAGE_HEADER *msgHdr, int response, + ULTRA_CHIPSET_FEATURE features) +{ + CONTROLVM_MESSAGE outmsg; + if (!ControlVm_channel) + return; + controlvm_init_response(&outmsg, msgHdr, response); + outmsg.cmd.initChipset.features = features; + if (!visorchannel_signalinsert(ControlVm_channel, + CONTROLVM_QUEUE_REQUEST, &outmsg)) { + LOGERR("signalinsert failed!"); + return; + } +} + +static void +controlvm_respond_physdev_changestate(CONTROLVM_MESSAGE_HEADER *msgHdr, + int response, ULTRA_SEGMENT_STATE state) +{ + CONTROLVM_MESSAGE outmsg; + if (!ControlVm_channel) + return; + controlvm_init_response(&outmsg, msgHdr, response); + outmsg.cmd.deviceChangeState.state = state; + outmsg.cmd.deviceChangeState.flags.physicalDevice = 1; + if (!visorchannel_signalinsert(ControlVm_channel, + CONTROLVM_QUEUE_REQUEST, &outmsg)) { + LOGERR("signalinsert failed!"); + return; + } +} + +void +visorchipset_save_message(CONTROLVM_MESSAGE *msg, CRASH_OBJ_TYPE type) +{ + U32 localSavedCrashMsgOffset; + U16 localSavedCrashMsgCount; + + /* get saved message count */ + if (visorchannel_read(ControlVm_channel, + offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL, + SavedCrashMsgCount), + &localSavedCrashMsgCount, sizeof(U16)) < 0) { + LOGERR("failed to get Saved Message Count"); + POSTCODE_LINUX_2(CRASH_DEV_CTRL_RD_FAILURE_PC, + POSTCODE_SEVERITY_ERR); + return; + } + + if (localSavedCrashMsgCount != CONTROLVM_CRASHMSG_MAX) { + LOGERR("Saved Message Count incorrect %d", + localSavedCrashMsgCount); + POSTCODE_LINUX_3(CRASH_DEV_COUNT_FAILURE_PC, + localSavedCrashMsgCount, + POSTCODE_SEVERITY_ERR); + return; + } + + /* get saved crash message offset */ + if (visorchannel_read(ControlVm_channel, + offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL, + SavedCrashMsgOffset), + &localSavedCrashMsgOffset, sizeof(U32)) < 0) { + LOGERR("failed to get Saved Message Offset"); + POSTCODE_LINUX_2(CRASH_DEV_CTRL_RD_FAILURE_PC, + POSTCODE_SEVERITY_ERR); + return; + } + + if (type == CRASH_bus) { + if (visorchannel_write(ControlVm_channel, + localSavedCrashMsgOffset, + msg, sizeof(CONTROLVM_MESSAGE)) < 0) { + LOGERR("SAVE_MSG_BUS_FAILURE: Failed to write CrashCreateBusMsg!"); + POSTCODE_LINUX_2(SAVE_MSG_BUS_FAILURE_PC, + POSTCODE_SEVERITY_ERR); + return; + } + } else { + if (visorchannel_write(ControlVm_channel, + localSavedCrashMsgOffset + + sizeof(CONTROLVM_MESSAGE), msg, + sizeof(CONTROLVM_MESSAGE)) < 0) { + LOGERR("SAVE_MSG_DEV_FAILURE: Failed to write CrashCreateDevMsg!"); + POSTCODE_LINUX_2(SAVE_MSG_DEV_FAILURE_PC, + POSTCODE_SEVERITY_ERR); + return; + } + } +} +EXPORT_SYMBOL_GPL(visorchipset_save_message); + +static void +bus_responder(CONTROLVM_ID cmdId, ulong busNo, int response) +{ + VISORCHIPSET_BUS_INFO *p = NULL; + BOOL need_clear = FALSE; + + p = findbus(&BusInfoList, busNo); + if (!p) { + LOGERR("internal error busNo=%lu", busNo); + return; + } + if (response < 0) { + if ((cmdId == CONTROLVM_BUS_CREATE) && + (response != (-CONTROLVM_RESP_ERROR_ALREADY_DONE))) + /* undo the row we just created... */ + delbusdevices(&DevInfoList, busNo); + } else { + if (cmdId == CONTROLVM_BUS_CREATE) + p->state.created = 1; + if (cmdId == CONTROLVM_BUS_DESTROY) + need_clear = TRUE; + } + + if (p->pendingMsgHdr.Id == CONTROLVM_INVALID) { + LOGERR("bus_responder no pending msg"); + return; /* no controlvm response needed */ + } + if (p->pendingMsgHdr.Id != (U32) cmdId) { + LOGERR("expected=%d, found=%d", cmdId, p->pendingMsgHdr.Id); + return; + } + controlvm_respond(&p->pendingMsgHdr, response); + p->pendingMsgHdr.Id = CONTROLVM_INVALID; + if (need_clear) { + busInfo_clear(p); + delbusdevices(&DevInfoList, busNo); + } +} + +static void +device_changestate_responder(CONTROLVM_ID cmdId, + ulong busNo, ulong devNo, int response, + ULTRA_SEGMENT_STATE responseState) +{ + VISORCHIPSET_DEVICE_INFO *p = NULL; + CONTROLVM_MESSAGE outmsg; + + if (!ControlVm_channel) + return; + + p = finddevice(&DevInfoList, busNo, devNo); + if (!p) { + LOGERR("internal error; busNo=%lu, devNo=%lu", busNo, devNo); + return; + } + if (p->pendingMsgHdr.Id == CONTROLVM_INVALID) { + LOGERR("device_responder no pending msg"); + return; /* no controlvm response needed */ + } + if (p->pendingMsgHdr.Id != cmdId) { + LOGERR("expected=%d, found=%d", cmdId, p->pendingMsgHdr.Id); + return; + } + + controlvm_init_response(&outmsg, &p->pendingMsgHdr, response); + + outmsg.cmd.deviceChangeState.busNo = busNo; + outmsg.cmd.deviceChangeState.devNo = devNo; + outmsg.cmd.deviceChangeState.state = responseState; + + if (!visorchannel_signalinsert(ControlVm_channel, + CONTROLVM_QUEUE_REQUEST, &outmsg)) { + LOGERR("signalinsert failed!"); + return; + } + + p->pendingMsgHdr.Id = CONTROLVM_INVALID; +} + +static void +device_responder(CONTROLVM_ID cmdId, ulong busNo, ulong devNo, int response) +{ + VISORCHIPSET_DEVICE_INFO *p = NULL; + BOOL need_clear = FALSE; + + p = finddevice(&DevInfoList, busNo, devNo); + if (!p) { + LOGERR("internal error; busNo=%lu, devNo=%lu", busNo, devNo); + return; + } + if (response >= 0) { + if (cmdId == CONTROLVM_DEVICE_CREATE) + p->state.created = 1; + if (cmdId == CONTROLVM_DEVICE_DESTROY) + need_clear = TRUE; + } + + if (p->pendingMsgHdr.Id == CONTROLVM_INVALID) { + LOGERR("device_responder no pending msg"); + return; /* no controlvm response needed */ + } + if (p->pendingMsgHdr.Id != (U32) cmdId) { + LOGERR("expected=%d, found=%d", cmdId, p->pendingMsgHdr.Id); + return; + } + controlvm_respond(&p->pendingMsgHdr, response); + p->pendingMsgHdr.Id = CONTROLVM_INVALID; + if (need_clear) + devInfo_clear(p); +} + +static void +bus_epilog(U32 busNo, + U32 cmd, CONTROLVM_MESSAGE_HEADER *msgHdr, + int response, BOOL needResponse) +{ + BOOL notified = FALSE; + + VISORCHIPSET_BUS_INFO *pBusInfo = findbus(&BusInfoList, busNo); + + if (!pBusInfo) { + LOGERR("HUH? bad busNo=%d", busNo); + return; + } + if (needResponse) { + memcpy(&pBusInfo->pendingMsgHdr, msgHdr, + sizeof(CONTROLVM_MESSAGE_HEADER)); + } else + pBusInfo->pendingMsgHdr.Id = CONTROLVM_INVALID; + + LOCKSEM_UNINTERRUPTIBLE(&NotifierLock); + if (response == CONTROLVM_RESP_SUCCESS) { + switch (cmd) { + case CONTROLVM_BUS_CREATE: + /* We can't tell from the bus_create + * information which of our 2 bus flavors the + * devices on this bus will ultimately end up. + * FORTUNATELY, it turns out it is harmless to + * send the bus_create to both of them. We can + * narrow things down a little bit, though, + * because we know: - BusDev_Server can handle + * either server or client devices + * - BusDev_Client can handle ONLY client + * devices */ + if (BusDev_Server_Notifiers.bus_create) { + (*BusDev_Server_Notifiers.bus_create) (busNo); + notified = TRUE; + } + if ((!pBusInfo->flags.server) /*client */ && + BusDev_Client_Notifiers.bus_create) { + (*BusDev_Client_Notifiers.bus_create) (busNo); + notified = TRUE; + } + break; + case CONTROLVM_BUS_DESTROY: + if (BusDev_Server_Notifiers.bus_destroy) { + (*BusDev_Server_Notifiers.bus_destroy) (busNo); + notified = TRUE; + } + if ((!pBusInfo->flags.server) /*client */ && + BusDev_Client_Notifiers.bus_destroy) { + (*BusDev_Client_Notifiers.bus_destroy) (busNo); + notified = TRUE; + } + break; + } + } + if (notified) + /* The callback function just called above is responsible + * for calling the appropriate VISORCHIPSET_BUSDEV_RESPONDERS + * function, which will call bus_responder() + */ + ; + else + bus_responder(cmd, busNo, response); + UNLOCKSEM(&NotifierLock); +} + +static void +device_epilog(U32 busNo, U32 devNo, ULTRA_SEGMENT_STATE state, U32 cmd, + CONTROLVM_MESSAGE_HEADER *msgHdr, int response, + BOOL needResponse, BOOL for_visorbus) +{ + VISORCHIPSET_BUSDEV_NOTIFIERS *notifiers = NULL; + BOOL notified = FALSE; + + VISORCHIPSET_DEVICE_INFO *pDevInfo = + finddevice(&DevInfoList, busNo, devNo); + char *envp[] = { + "SPARSP_DIAGPOOL_PAUSED_STATE = 1", + NULL + }; + + if (!pDevInfo) { + LOGERR("HUH? bad busNo=%d, devNo=%d", busNo, devNo); + return; + } + if (for_visorbus) + notifiers = &BusDev_Server_Notifiers; + else + notifiers = &BusDev_Client_Notifiers; + if (needResponse) { + memcpy(&pDevInfo->pendingMsgHdr, msgHdr, + sizeof(CONTROLVM_MESSAGE_HEADER)); + } else + pDevInfo->pendingMsgHdr.Id = CONTROLVM_INVALID; + + LOCKSEM_UNINTERRUPTIBLE(&NotifierLock); + if (response >= 0) { + switch (cmd) { + case CONTROLVM_DEVICE_CREATE: + if (notifiers->device_create) { + (*notifiers->device_create) (busNo, devNo); + notified = TRUE; + } + break; + case CONTROLVM_DEVICE_CHANGESTATE: + /* ServerReady / ServerRunning / SegmentStateRunning */ + if (state.Alive == SegmentStateRunning.Alive && + state.Operating == SegmentStateRunning.Operating) { + if (notifiers->device_resume) { + (*notifiers->device_resume) (busNo, + devNo); + notified = TRUE; + } + } + /* ServerNotReady / ServerLost / SegmentStateStandby */ + else if (state.Alive == SegmentStateStandby.Alive && + state.Operating == + SegmentStateStandby.Operating) { + /* technically this is standby case + * where server is lost + */ + if (notifiers->device_pause) { + (*notifiers->device_pause) (busNo, + devNo); + notified = TRUE; + } + } else if (state.Alive == SegmentStatePaused.Alive && + state.Operating == + SegmentStatePaused.Operating) { + /* this is lite pause where channel is + * still valid just 'pause' of it + */ + if (busNo == g_diagpoolBusNo + && devNo == g_diagpoolDevNo) { + LOGINF("DEVICE_CHANGESTATE(DiagpoolChannel busNo=%d devNo=%d is pausing...)", + busNo, devNo); + /* this will trigger the + * diag_shutdown.sh script in + * the visorchipset hotplug */ + kobject_uevent_env + (&Visorchipset_platform_device.dev. + kobj, KOBJ_ONLINE, envp); + } + } + break; + case CONTROLVM_DEVICE_DESTROY: + if (notifiers->device_destroy) { + (*notifiers->device_destroy) (busNo, devNo); + notified = TRUE; + } + break; + } + } + if (notified) + /* The callback function just called above is responsible + * for calling the appropriate VISORCHIPSET_BUSDEV_RESPONDERS + * function, which will call device_responder() + */ + ; + else + device_responder(cmd, busNo, devNo, response); + UNLOCKSEM(&NotifierLock); +} + +static void +bus_create(CONTROLVM_MESSAGE *inmsg) +{ + CONTROLVM_MESSAGE_PACKET *cmd = &inmsg->cmd; + ulong busNo = cmd->createBus.busNo; + int rc = CONTROLVM_RESP_SUCCESS; + VISORCHIPSET_BUS_INFO *pBusInfo = NULL; + + + pBusInfo = findbus(&BusInfoList, busNo); + if (pBusInfo && (pBusInfo->state.created == 1)) { + LOGERR("CONTROLVM_BUS_CREATE Failed: bus %lu already exists", + busNo); + POSTCODE_LINUX_3(BUS_CREATE_FAILURE_PC, busNo, + POSTCODE_SEVERITY_ERR); + RETINT(-CONTROLVM_RESP_ERROR_ALREADY_DONE); + } + pBusInfo = kmalloc(sizeof(VISORCHIPSET_BUS_INFO), GFP_KERNEL); + if (pBusInfo == NULL) { + LOGERR("CONTROLVM_BUS_CREATE Failed: bus %lu kmalloc failed", + busNo); + POSTCODE_LINUX_3(BUS_CREATE_FAILURE_PC, busNo, + POSTCODE_SEVERITY_ERR); + RETINT(-CONTROLVM_RESP_ERROR_KMALLOC_FAILED); + } + + memset(pBusInfo, 0, sizeof(VISORCHIPSET_BUS_INFO)); + INIT_LIST_HEAD(&pBusInfo->entry); + pBusInfo->busNo = busNo; + pBusInfo->devNo = cmd->createBus.deviceCount; + + POSTCODE_LINUX_3(BUS_CREATE_ENTRY_PC, busNo, POSTCODE_SEVERITY_INFO); + + if (inmsg->hdr.Flags.testMessage == 1) + pBusInfo->chanInfo.addrType = ADDRTYPE_localTest; + else + pBusInfo->chanInfo.addrType = ADDRTYPE_localPhysical; + + pBusInfo->flags.server = inmsg->hdr.Flags.server; + pBusInfo->chanInfo.channelAddr = cmd->createBus.channelAddr; + pBusInfo->chanInfo.nChannelBytes = cmd->createBus.channelBytes; + pBusInfo->chanInfo.channelTypeGuid = cmd->createBus.busDataTypeGuid; + pBusInfo->chanInfo.channelInstGuid = cmd->createBus.busInstGuid; + + list_add(&pBusInfo->entry, &BusInfoList); + + POSTCODE_LINUX_3(BUS_CREATE_EXIT_PC, busNo, POSTCODE_SEVERITY_INFO); + +Away: + bus_epilog(busNo, CONTROLVM_BUS_CREATE, &inmsg->hdr, + rc, inmsg->hdr.Flags.responseExpected == 1); +} + +static void +bus_destroy(CONTROLVM_MESSAGE *inmsg) +{ + CONTROLVM_MESSAGE_PACKET *cmd = &inmsg->cmd; + ulong busNo = cmd->destroyBus.busNo; + VISORCHIPSET_BUS_INFO *pBusInfo; + int rc = CONTROLVM_RESP_SUCCESS; + + pBusInfo = findbus(&BusInfoList, busNo); + if (!pBusInfo) { + LOGERR("CONTROLVM_BUS_DESTROY Failed: bus %lu invalid", busNo); + RETINT(-CONTROLVM_RESP_ERROR_BUS_INVALID); + } + if (pBusInfo->state.created == 0) { + LOGERR("CONTROLVM_BUS_DESTROY Failed: bus %lu already destroyed", + busNo); + RETINT(-CONTROLVM_RESP_ERROR_ALREADY_DONE); + } + +Away: + bus_epilog(busNo, CONTROLVM_BUS_DESTROY, &inmsg->hdr, + rc, inmsg->hdr.Flags.responseExpected == 1); +} + +static void +bus_configure(CONTROLVM_MESSAGE *inmsg, PARSER_CONTEXT *parser_ctx) +{ + CONTROLVM_MESSAGE_PACKET *cmd = &inmsg->cmd; + ulong busNo = cmd->configureBus.busNo; + VISORCHIPSET_BUS_INFO *pBusInfo = NULL; + int rc = CONTROLVM_RESP_SUCCESS; + char s[99]; + + busNo = cmd->configureBus.busNo; + POSTCODE_LINUX_3(BUS_CONFIGURE_ENTRY_PC, busNo, POSTCODE_SEVERITY_INFO); + + pBusInfo = findbus(&BusInfoList, busNo); + if (!pBusInfo) { + LOGERR("CONTROLVM_BUS_CONFIGURE Failed: bus %lu invalid", + busNo); + POSTCODE_LINUX_3(BUS_CONFIGURE_FAILURE_PC, busNo, + POSTCODE_SEVERITY_ERR); + RETINT(-CONTROLVM_RESP_ERROR_BUS_INVALID); + } + if (pBusInfo->state.created == 0) { + LOGERR("CONTROLVM_BUS_CONFIGURE Failed: Invalid bus %lu - not created yet", + busNo); + POSTCODE_LINUX_3(BUS_CONFIGURE_FAILURE_PC, busNo, + POSTCODE_SEVERITY_ERR); + RETINT(-CONTROLVM_RESP_ERROR_BUS_INVALID); + } + /* TBD - add this check to other commands also... */ + if (pBusInfo->pendingMsgHdr.Id != CONTROLVM_INVALID) { + LOGERR("CONTROLVM_BUS_CONFIGURE Failed: bus %lu MsgId=%u outstanding", + busNo, (uint) pBusInfo->pendingMsgHdr.Id); + POSTCODE_LINUX_3(BUS_CONFIGURE_FAILURE_PC, busNo, + POSTCODE_SEVERITY_ERR); + RETINT(-CONTROLVM_RESP_ERROR_MESSAGE_ID_INVALID_FOR_CLIENT); + } + + pBusInfo->partitionHandle = cmd->configureBus.guestHandle; + pBusInfo->partitionGuid = parser_id_get(parser_ctx); + parser_param_start(parser_ctx, PARSERSTRING_NAME); + pBusInfo->name = parser_string_get(parser_ctx); + + visorchannel_GUID_id(&pBusInfo->partitionGuid, s); + pBusInfo->procObject = + proc_CreateObject(PartitionType, s, (void *) (pBusInfo)); + if (pBusInfo->procObject == NULL) { + LOGERR("CONTROLVM_BUS_CONFIGURE Failed: busNo=%lu failed to create /proc entry", + busNo); + POSTCODE_LINUX_3(BUS_CONFIGURE_FAILURE_PC, busNo, + POSTCODE_SEVERITY_ERR); + RETINT(-CONTROLVM_RESP_ERROR_KMALLOC_FAILED); + } + POSTCODE_LINUX_3(BUS_CONFIGURE_EXIT_PC, busNo, POSTCODE_SEVERITY_INFO); +Away: + bus_epilog(busNo, CONTROLVM_BUS_CONFIGURE, &inmsg->hdr, + rc, inmsg->hdr.Flags.responseExpected == 1); +} + +static void +my_device_create(CONTROLVM_MESSAGE *inmsg) +{ + CONTROLVM_MESSAGE_PACKET *cmd = &inmsg->cmd; + ulong busNo = cmd->createDevice.busNo; + ulong devNo = cmd->createDevice.devNo; + VISORCHIPSET_DEVICE_INFO *pDevInfo = NULL; + VISORCHIPSET_BUS_INFO *pBusInfo = NULL; + int rc = CONTROLVM_RESP_SUCCESS; + + pDevInfo = finddevice(&DevInfoList, busNo, devNo); + if (pDevInfo && (pDevInfo->state.created == 1)) { + LOGERR("CONTROLVM_DEVICE_CREATE Failed: busNo=%lu, devNo=%lu already exists", + busNo, devNo); + POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC, devNo, busNo, + POSTCODE_SEVERITY_ERR); + RETINT(-CONTROLVM_RESP_ERROR_ALREADY_DONE); + } + pBusInfo = findbus(&BusInfoList, busNo); + if (!pBusInfo) { + LOGERR("CONTROLVM_DEVICE_CREATE Failed: Invalid bus %lu - out of range", + busNo); + POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC, devNo, busNo, + POSTCODE_SEVERITY_ERR); + RETINT(-CONTROLVM_RESP_ERROR_BUS_INVALID); + } + if (pBusInfo->state.created == 0) { + LOGERR("CONTROLVM_DEVICE_CREATE Failed: Invalid bus %lu - not created yet", + busNo); + POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC, devNo, busNo, + POSTCODE_SEVERITY_ERR); + RETINT(-CONTROLVM_RESP_ERROR_BUS_INVALID); + } + pDevInfo = kmalloc(sizeof(VISORCHIPSET_DEVICE_INFO), GFP_KERNEL); + if (pDevInfo == NULL) { + LOGERR("CONTROLVM_DEVICE_CREATE Failed: busNo=%lu, devNo=%lu kmaloc failed", + busNo, devNo); + POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC, devNo, busNo, + POSTCODE_SEVERITY_ERR); + RETINT(-CONTROLVM_RESP_ERROR_KMALLOC_FAILED); + } + memset(pDevInfo, 0, sizeof(VISORCHIPSET_DEVICE_INFO)); + INIT_LIST_HEAD(&pDevInfo->entry); + pDevInfo->busNo = busNo; + pDevInfo->devNo = devNo; + pDevInfo->devInstGuid = cmd->createDevice.devInstGuid; + POSTCODE_LINUX_4(DEVICE_CREATE_ENTRY_PC, devNo, busNo, + POSTCODE_SEVERITY_INFO); + + if (inmsg->hdr.Flags.testMessage == 1) + pDevInfo->chanInfo.addrType = ADDRTYPE_localTest; + else + pDevInfo->chanInfo.addrType = ADDRTYPE_localPhysical; + pDevInfo->chanInfo.channelAddr = cmd->createDevice.channelAddr; + pDevInfo->chanInfo.nChannelBytes = cmd->createDevice.channelBytes; + pDevInfo->chanInfo.channelTypeGuid = cmd->createDevice.dataTypeGuid; + pDevInfo->chanInfo.intr = cmd->createDevice.intr; + list_add(&pDevInfo->entry, &DevInfoList); + POSTCODE_LINUX_4(DEVICE_CREATE_EXIT_PC, devNo, busNo, + POSTCODE_SEVERITY_INFO); +Away: + /* get the bus and devNo for DiagPool channel */ + if (is_diagpool_channel(pDevInfo->chanInfo.channelTypeGuid)) { + g_diagpoolBusNo = busNo; + g_diagpoolDevNo = devNo; + LOGINF("CONTROLVM_DEVICE_CREATE for DiagPool channel: busNo=%lu, devNo=%lu", + g_diagpoolBusNo, g_diagpoolDevNo); + } + device_epilog(busNo, devNo, SegmentStateRunning, + CONTROLVM_DEVICE_CREATE, &inmsg->hdr, rc, + inmsg->hdr.Flags.responseExpected == 1, + FOR_VISORBUS(pDevInfo->chanInfo.channelTypeGuid)); +} + +static void +my_device_changestate(CONTROLVM_MESSAGE *inmsg) +{ + CONTROLVM_MESSAGE_PACKET *cmd = &inmsg->cmd; + ulong busNo = cmd->deviceChangeState.busNo; + ulong devNo = cmd->deviceChangeState.devNo; + ULTRA_SEGMENT_STATE state = cmd->deviceChangeState.state; + VISORCHIPSET_DEVICE_INFO *pDevInfo = NULL; + int rc = CONTROLVM_RESP_SUCCESS; + + pDevInfo = finddevice(&DevInfoList, busNo, devNo); + if (!pDevInfo) { + LOGERR("CONTROLVM_DEVICE_CHANGESTATE Failed: busNo=%lu, devNo=%lu invalid (doesn't exist)", + busNo, devNo); + POSTCODE_LINUX_4(DEVICE_CHANGESTATE_FAILURE_PC, devNo, busNo, + POSTCODE_SEVERITY_ERR); + RETINT(-CONTROLVM_RESP_ERROR_DEVICE_INVALID); + } + if (pDevInfo->state.created == 0) { + LOGERR("CONTROLVM_DEVICE_CHANGESTATE Failed: busNo=%lu, devNo=%lu invalid (not created)", + busNo, devNo); + POSTCODE_LINUX_4(DEVICE_CHANGESTATE_FAILURE_PC, devNo, busNo, + POSTCODE_SEVERITY_ERR); + RETINT(-CONTROLVM_RESP_ERROR_DEVICE_INVALID); + } +Away: + if ((rc >= CONTROLVM_RESP_SUCCESS) && pDevInfo) + device_epilog(busNo, devNo, state, CONTROLVM_DEVICE_CHANGESTATE, + &inmsg->hdr, rc, + inmsg->hdr.Flags.responseExpected == 1, + FOR_VISORBUS(pDevInfo->chanInfo.channelTypeGuid)); +} + +static void +my_device_destroy(CONTROLVM_MESSAGE *inmsg) +{ + CONTROLVM_MESSAGE_PACKET *cmd = &inmsg->cmd; + ulong busNo = cmd->destroyDevice.busNo; + ulong devNo = cmd->destroyDevice.devNo; + VISORCHIPSET_DEVICE_INFO *pDevInfo = NULL; + int rc = CONTROLVM_RESP_SUCCESS; + + pDevInfo = finddevice(&DevInfoList, busNo, devNo); + if (!pDevInfo) { + LOGERR("CONTROLVM_DEVICE_DESTROY Failed: busNo=%lu, devNo=%lu invalid", + busNo, devNo); + RETINT(-CONTROLVM_RESP_ERROR_DEVICE_INVALID); + } + if (pDevInfo->state.created == 0) { + LOGERR("CONTROLVM_DEVICE_DESTROY Failed: busNo=%lu, devNo=%lu already destroyed", + busNo, devNo); + RETINT(-CONTROLVM_RESP_ERROR_ALREADY_DONE); + } + +Away: + if ((rc >= CONTROLVM_RESP_SUCCESS) && pDevInfo) + device_epilog(busNo, devNo, SegmentStateRunning, + CONTROLVM_DEVICE_DESTROY, &inmsg->hdr, rc, + inmsg->hdr.Flags.responseExpected == 1, + FOR_VISORBUS(pDevInfo->chanInfo.channelTypeGuid)); +} + +/* When provided with the physical address of the controlvm channel + * (phys_addr), the offset to the payload area we need to manage + * (offset), and the size of this payload area (bytes), fills in the + * CONTROLVM_PAYLOAD_INFO struct. Returns TRUE for success or FALSE + * for failure. + */ +static int +initialize_controlvm_payload_info(HOSTADDRESS phys_addr, U64 offset, U32 bytes, + CONTROLVM_PAYLOAD_INFO *info) +{ + U8 *payload = NULL; + int rc = CONTROLVM_RESP_SUCCESS; + + if (info == NULL) { + LOGERR("HUH ? CONTROLVM_PAYLOAD_INIT Failed : Programmer check at %s:%d", + __FILE__, __LINE__); + RETINT(-CONTROLVM_RESP_ERROR_PAYLOAD_INVALID); + } + memset(info, 0, sizeof(CONTROLVM_PAYLOAD_INFO)); + if ((offset == 0) || (bytes == 0)) { + LOGERR("CONTROLVM_PAYLOAD_INIT Failed: RequestPayloadOffset=%llu RequestPayloadBytes=%llu!", + (u64) offset, (u64) bytes); + RETINT(-CONTROLVM_RESP_ERROR_PAYLOAD_INVALID); + } + payload = ioremap_cache(phys_addr + offset, bytes); + if (payload == NULL) { + LOGERR("CONTROLVM_PAYLOAD_INIT Failed: ioremap_cache %llu for %llu bytes failed", + (u64) offset, (u64) bytes); + RETINT(-CONTROLVM_RESP_ERROR_IOREMAP_FAILED); + } + + info->offset = offset; + info->bytes = bytes; + info->ptr = payload; + LOGINF("offset=%llu, bytes=%lu, ptr=%p", + (u64) (info->offset), (ulong) (info->bytes), info->ptr); + +Away: + if (rc < 0) { + if (payload != NULL) { + iounmap(payload); + payload = NULL; + } + } + return rc; +} + +static void +destroy_controlvm_payload_info(CONTROLVM_PAYLOAD_INFO *info) +{ + if (info->ptr != NULL) { + iounmap(info->ptr); + info->ptr = NULL; + } + memset(info, 0, sizeof(CONTROLVM_PAYLOAD_INFO)); +} + +static void +initialize_controlvm_payload(void) +{ + HOSTADDRESS phys_addr = visorchannel_get_physaddr(ControlVm_channel); + U64 payloadOffset = 0; + U32 payloadBytes = 0; + if (visorchannel_read(ControlVm_channel, + offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL, + RequestPayloadOffset), + &payloadOffset, sizeof(payloadOffset)) < 0) { + LOGERR("CONTROLVM_PAYLOAD_INIT Failed to read controlvm channel!"); + POSTCODE_LINUX_2(CONTROLVM_INIT_FAILURE_PC, + POSTCODE_SEVERITY_ERR); + return; + } + if (visorchannel_read(ControlVm_channel, + offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL, + RequestPayloadBytes), + &payloadBytes, sizeof(payloadBytes)) < 0) { + LOGERR("CONTROLVM_PAYLOAD_INIT Failed to read controlvm channel!"); + POSTCODE_LINUX_2(CONTROLVM_INIT_FAILURE_PC, + POSTCODE_SEVERITY_ERR); + return; + } + initialize_controlvm_payload_info(phys_addr, + payloadOffset, payloadBytes, + &ControlVm_payload_info); +} + +/* Send ACTION=online for DEVPATH=/sys/devices/platform/visorchipset. + * Returns CONTROLVM_RESP_xxx code. + */ +int +visorchipset_chipset_ready(void) +{ + kobject_uevent(&Visorchipset_platform_device.dev.kobj, KOBJ_ONLINE); + return CONTROLVM_RESP_SUCCESS; +} +EXPORT_SYMBOL_GPL(visorchipset_chipset_ready); + +int +visorchipset_chipset_selftest(void) +{ + char env_selftest[20]; + char *envp[] = { env_selftest, NULL }; + sprintf(env_selftest, "SPARSP_SELFTEST=%d", 1); + kobject_uevent_env(&Visorchipset_platform_device.dev.kobj, KOBJ_CHANGE, + envp); + return CONTROLVM_RESP_SUCCESS; +} +EXPORT_SYMBOL_GPL(visorchipset_chipset_selftest); + +/* Send ACTION=offline for DEVPATH=/sys/devices/platform/visorchipset. + * Returns CONTROLVM_RESP_xxx code. + */ +int +visorchipset_chipset_notready(void) +{ + kobject_uevent(&Visorchipset_platform_device.dev.kobj, KOBJ_OFFLINE); + return CONTROLVM_RESP_SUCCESS; +} +EXPORT_SYMBOL_GPL(visorchipset_chipset_notready); + +static void +chipset_ready(CONTROLVM_MESSAGE_HEADER *msgHdr) +{ + int rc = visorchipset_chipset_ready(); + if (rc != CONTROLVM_RESP_SUCCESS) + rc = -rc; + if (msgHdr->Flags.responseExpected && !visorchipset_holdchipsetready) + controlvm_respond(msgHdr, rc); + if (msgHdr->Flags.responseExpected && visorchipset_holdchipsetready) { + /* Send CHIPSET_READY response when all modules have been loaded + * and disks mounted for the partition + */ + g_ChipSetMsgHdr = *msgHdr; + LOGINF("Holding CHIPSET_READY response"); + } +} + +static void +chipset_selftest(CONTROLVM_MESSAGE_HEADER *msgHdr) +{ + int rc = visorchipset_chipset_selftest(); + if (rc != CONTROLVM_RESP_SUCCESS) + rc = -rc; + if (msgHdr->Flags.responseExpected) + controlvm_respond(msgHdr, rc); +} + +static void +chipset_notready(CONTROLVM_MESSAGE_HEADER *msgHdr) +{ + int rc = visorchipset_chipset_notready(); + if (rc != CONTROLVM_RESP_SUCCESS) + rc = -rc; + if (msgHdr->Flags.responseExpected) + controlvm_respond(msgHdr, rc); +} + +/* This is your "one-stop" shop for grabbing the next message from the + * CONTROLVM_QUEUE_EVENT queue in the controlvm channel. + */ +static BOOL +read_controlvm_event(CONTROLVM_MESSAGE *msg) +{ + if (visorchannel_signalremove(ControlVm_channel, + CONTROLVM_QUEUE_EVENT, msg)) { + /* got a message */ + if (msg->hdr.Flags.testMessage == 1) { + LOGERR("ignoring bad CONTROLVM_QUEUE_EVENT msg with controlvm_msg_id=0x%x because Flags.testMessage is nonsensical (=1)", msg->hdr.Id); + return FALSE; + } else + return TRUE; + } + return FALSE; +} + +/* + * The general parahotplug flow works as follows. The visorchipset + * driver receives a DEVICE_CHANGESTATE message from Command + * specifying a physical device to enable or disable. The CONTROLVM + * message handler calls parahotplug_process_message, which then adds + * the message to a global list and kicks off a udev event which + * causes a user level script to enable or disable the specified + * device. The udev script then writes to + * /proc/visorchipset/parahotplug, which causes parahotplug_proc_write + * to get called, at which point the appropriate CONTROLVM message is + * retrieved from the list and responded to. + */ + +#define PARAHOTPLUG_TIMEOUT_MS 2000 + +/* + * Generate unique int to match an outstanding CONTROLVM message with a + * udev script /proc response + */ +static int +parahotplug_next_id(void) +{ + static atomic_t id = ATOMIC_INIT(0); + return atomic_inc_return(&id); +} + +/* + * Returns the time (in jiffies) when a CONTROLVM message on the list + * should expire -- PARAHOTPLUG_TIMEOUT_MS in the future + */ +static unsigned long +parahotplug_next_expiration(void) +{ + return jiffies + PARAHOTPLUG_TIMEOUT_MS * HZ / 1000; +} + +/* + * Create a parahotplug_request, which is basically a wrapper for a + * CONTROLVM_MESSAGE that we can stick on a list + */ +static struct parahotplug_request * +parahotplug_request_create(CONTROLVM_MESSAGE *msg) +{ + struct parahotplug_request *req = + kmalloc(sizeof(struct parahotplug_request), + GFP_KERNEL|__GFP_NORETRY); + if (req == NULL) + return NULL; + + req->id = parahotplug_next_id(); + req->expiration = parahotplug_next_expiration(); + req->msg = *msg; + + return req; +} + +/* + * Free a parahotplug_request. + */ +static void +parahotplug_request_destroy(struct parahotplug_request *req) +{ + kfree(req); +} + +/* + * Cause uevent to run the user level script to do the disable/enable + * specified in (the CONTROLVM message in) the specified + * parahotplug_request + */ +static void +parahotplug_request_kickoff(struct parahotplug_request *req) +{ + CONTROLVM_MESSAGE_PACKET *cmd = &req->msg.cmd; + char env_cmd[40], env_id[40], env_state[40], env_bus[40], env_dev[40], + env_func[40]; + char *envp[] = { + env_cmd, env_id, env_state, env_bus, env_dev, env_func, NULL + }; + + sprintf(env_cmd, "SPAR_PARAHOTPLUG=1"); + sprintf(env_id, "SPAR_PARAHOTPLUG_ID=%d", req->id); + sprintf(env_state, "SPAR_PARAHOTPLUG_STATE=%d", + cmd->deviceChangeState.state.Active); + sprintf(env_bus, "SPAR_PARAHOTPLUG_BUS=%d", + cmd->deviceChangeState.busNo); + sprintf(env_dev, "SPAR_PARAHOTPLUG_DEVICE=%d", + cmd->deviceChangeState.devNo >> 3); + sprintf(env_func, "SPAR_PARAHOTPLUG_FUNCTION=%d", + cmd->deviceChangeState.devNo & 0x7); + + LOGINF("parahotplug_request_kickoff: state=%d, bdf=%d/%d/%d, id=%u\n", + cmd->deviceChangeState.state.Active, + cmd->deviceChangeState.busNo, cmd->deviceChangeState.devNo >> 3, + cmd->deviceChangeState.devNo & 7, req->id); + + kobject_uevent_env(&Visorchipset_platform_device.dev.kobj, KOBJ_CHANGE, + envp); +} + +/* + * Remove any request from the list that's been on there too long and + * respond with an error. + */ +static void +parahotplug_process_list(void) +{ + struct list_head *pos = NULL; + struct list_head *tmp = NULL; + + spin_lock(&Parahotplug_request_list_lock); + + list_for_each_safe(pos, tmp, &Parahotplug_request_list) { + struct parahotplug_request *req = + list_entry(pos, struct parahotplug_request, list); + if (time_after_eq(jiffies, req->expiration)) { + list_del(pos); + if (req->msg.hdr.Flags.responseExpected) + controlvm_respond_physdev_changestate( + &req->msg.hdr, + CONTROLVM_RESP_ERROR_DEVICE_UDEV_TIMEOUT, + req->msg.cmd.deviceChangeState.state); + parahotplug_request_destroy(req); + } + } + + spin_unlock(&Parahotplug_request_list_lock); +} + +/* + * Called from the /proc handler, which means the user script has + * finished the enable/disable. Find the matching identifier, and + * respond to the CONTROLVM message with success. + */ +static int +parahotplug_request_complete(int id, U16 active) +{ + struct list_head *pos = NULL; + struct list_head *tmp = NULL; + + spin_lock(&Parahotplug_request_list_lock); + + /* Look for a request matching "id". */ + list_for_each_safe(pos, tmp, &Parahotplug_request_list) { + struct parahotplug_request *req = + list_entry(pos, struct parahotplug_request, list); + if (req->id == id) { + /* Found a match. Remove it from the list and + * respond. + */ + list_del(pos); + spin_unlock(&Parahotplug_request_list_lock); + req->msg.cmd.deviceChangeState.state.Active = active; + if (req->msg.hdr.Flags.responseExpected) + controlvm_respond_physdev_changestate( + &req->msg.hdr, CONTROLVM_RESP_SUCCESS, + req->msg.cmd.deviceChangeState.state); + parahotplug_request_destroy(req); + return 0; + } + } + + spin_unlock(&Parahotplug_request_list_lock); + return -1; +} + +/* + * Enables or disables a PCI device by kicking off a udev script + */ +void +parahotplug_process_message(CONTROLVM_MESSAGE *inmsg) +{ + struct parahotplug_request *req; + + req = parahotplug_request_create(inmsg); + + if (req == NULL) { + LOGERR("parahotplug_process_message: couldn't allocate request"); + return; + } + + if (inmsg->cmd.deviceChangeState.state.Active) { + /* For enable messages, just respond with success + * right away. This is a bit of a hack, but there are + * issues with the early enable messages we get (with + * either the udev script not detecting that the device + * is up, or not getting called at all). Fortunately + * the messages that get lost don't matter anyway, as + * devices are automatically enabled at + * initialization. + */ + parahotplug_request_kickoff(req); + controlvm_respond_physdev_changestate(&inmsg->hdr, + CONTROLVM_RESP_SUCCESS, + inmsg->cmd. + deviceChangeState.state); + parahotplug_request_destroy(req); + } else { + /* For disable messages, add the request to the + * request list before kicking off the udev script. It + * won't get responded to until the script has + * indicated it's done. + */ + spin_lock(&Parahotplug_request_list_lock); + list_add_tail(&(req->list), &Parahotplug_request_list); + spin_unlock(&Parahotplug_request_list_lock); + + parahotplug_request_kickoff(req); + } +} + +/* + * Gets called when the udev script writes to + * /proc/visorchipset/parahotplug. Expects input in the form of "<id> + * <active>" where <id> is the identifier passed to the script that + * matches a request on the request list, and <active> is 0 or 1 + * indicating whether the device is now enabled or not. + */ +static ssize_t +parahotplug_proc_write(struct file *file, const char __user *buffer, + size_t count, loff_t *ppos) +{ + char buf[64]; + uint id; + ushort active; + + if (count > sizeof(buf) - 1) { + LOGERR("parahotplug_proc_write: count (%d) exceeds size of buffer (%d)", + (int) count, (int) sizeof(buf)); + return -EINVAL; + } + if (copy_from_user(buf, buffer, count)) { + LOGERR("parahotplug_proc_write: copy_from_user failed"); + return -EFAULT; + } + buf[count] = '\0'; + + if (sscanf(buf, "%u %hu", &id, &active) != 2) { + id = 0; + active = 0; + } + + if (active != 1 && active != 0) { + LOGERR("parahotplug_proc_write: invalid active field"); + return -EINVAL; + } + + parahotplug_request_complete((int) id, (U16) active); + + return count; +} + +static const struct file_operations parahotplug_proc_fops = { + .owner = THIS_MODULE, + .read = visorchipset_proc_read_writeonly, + .write = parahotplug_proc_write, +}; + +/* Process a controlvm message. + * Return result: + * FALSE - this function will return FALSE only in the case where the + * controlvm message was NOT processed, but processing must be + * retried before reading the next controlvm message; a + * scenario where this can occur is when we need to throttle + * the allocation of memory in which to copy out controlvm + * payload data + * TRUE - processing of the controlvm message completed, + * either successfully or with an error. + */ +static BOOL +handle_command(CONTROLVM_MESSAGE inmsg, HOSTADDRESS channel_addr) +{ + CONTROLVM_MESSAGE_PACKET *cmd = &inmsg.cmd; + U64 parametersAddr = 0; + U32 parametersBytes = 0; + PARSER_CONTEXT *parser_ctx = NULL; + BOOL isLocalAddr = FALSE; + CONTROLVM_MESSAGE ackmsg; + + /* create parsing context if necessary */ + isLocalAddr = (inmsg.hdr.Flags.testMessage == 1); + if (channel_addr == 0) { + LOGERR("HUH? channel_addr is 0!"); + return TRUE; + } + parametersAddr = channel_addr + inmsg.hdr.PayloadVmOffset; + parametersBytes = inmsg.hdr.PayloadBytes; + + /* Parameter and channel addresses within test messages actually lie + * within our OS-controlled memory. We need to know that, because it + * makes a difference in how we compute the virtual address. + */ + if (parametersAddr != 0 && parametersBytes != 0) { + BOOL retry = FALSE; + parser_ctx = + parser_init_byteStream(parametersAddr, parametersBytes, + isLocalAddr, &retry); + if (!parser_ctx) { + if (retry) { + LOGWRN("throttling to copy payload"); + return FALSE; + } + LOGWRN("parsing failed"); + LOGWRN("inmsg.hdr.Id=0x%lx", (ulong) inmsg.hdr.Id); + LOGWRN("parametersAddr=0x%llx", (u64) parametersAddr); + LOGWRN("parametersBytes=%lu", (ulong) parametersBytes); + LOGWRN("isLocalAddr=%d", isLocalAddr); + } + } + + if (!isLocalAddr) { + controlvm_init_response(&ackmsg, &inmsg.hdr, + CONTROLVM_RESP_SUCCESS); + if ((ControlVm_channel) + && + (!visorchannel_signalinsert + (ControlVm_channel, CONTROLVM_QUEUE_ACK, &ackmsg))) + LOGWRN("failed to send ACK failed"); + } + switch (inmsg.hdr.Id) { + case CONTROLVM_CHIPSET_INIT: + LOGINF("CHIPSET_INIT(#busses=%lu,#switches=%lu)", + (ulong) inmsg.cmd.initChipset.busCount, + (ulong) inmsg.cmd.initChipset.switchCount); + chipset_init(&inmsg); + break; + case CONTROLVM_BUS_CREATE: + LOGINF("BUS_CREATE(%lu,#devs=%lu)", + (ulong) cmd->createBus.busNo, + (ulong) cmd->createBus.deviceCount); + bus_create(&inmsg); + break; + case CONTROLVM_BUS_DESTROY: + LOGINF("BUS_DESTROY(%lu)", (ulong) cmd->destroyBus.busNo); + bus_destroy(&inmsg); + break; + case CONTROLVM_BUS_CONFIGURE: + LOGINF("BUS_CONFIGURE(%lu)", (ulong) cmd->configureBus.busNo); + bus_configure(&inmsg, parser_ctx); + break; + case CONTROLVM_DEVICE_CREATE: + LOGINF("DEVICE_CREATE(%lu,%lu)", + (ulong) cmd->createDevice.busNo, + (ulong) cmd->createDevice.devNo); + my_device_create(&inmsg); + break; + case CONTROLVM_DEVICE_CHANGESTATE: + if (cmd->deviceChangeState.flags.physicalDevice) { + LOGINF("DEVICE_CHANGESTATE for physical device (%lu,%lu, active=%lu)", + (ulong) cmd->deviceChangeState.busNo, + (ulong) cmd->deviceChangeState.devNo, + (ulong) cmd->deviceChangeState.state.Active); + parahotplug_process_message(&inmsg); + } else { + LOGINF("DEVICE_CHANGESTATE for virtual device (%lu,%lu, state.Alive=0x%lx)", + (ulong) cmd->deviceChangeState.busNo, + (ulong) cmd->deviceChangeState.devNo, + (ulong) cmd->deviceChangeState.state.Alive); + /* save the hdr and cmd structures for later use */ + /* when sending back the response to Command */ + my_device_changestate(&inmsg); + g_DiagMsgHdr = inmsg.hdr; + g_DeviceChangeStatePacket = inmsg.cmd; + break; + } + break; + case CONTROLVM_DEVICE_DESTROY: + LOGINF("DEVICE_DESTROY(%lu,%lu)", + (ulong) cmd->destroyDevice.busNo, + (ulong) cmd->destroyDevice.devNo); + my_device_destroy(&inmsg); + break; + case CONTROLVM_DEVICE_CONFIGURE: + LOGINF("DEVICE_CONFIGURE(%lu,%lu)", + (ulong) cmd->configureDevice.busNo, + (ulong) cmd->configureDevice.devNo); + /* no op for now, just send a respond that we passed */ + if (inmsg.hdr.Flags.responseExpected) + controlvm_respond(&inmsg.hdr, CONTROLVM_RESP_SUCCESS); + break; + case CONTROLVM_CHIPSET_READY: + LOGINF("CHIPSET_READY"); + chipset_ready(&inmsg.hdr); + break; + case CONTROLVM_CHIPSET_SELFTEST: + LOGINF("CHIPSET_SELFTEST"); + chipset_selftest(&inmsg.hdr); + break; + case CONTROLVM_CHIPSET_STOP: + LOGINF("CHIPSET_STOP"); + chipset_notready(&inmsg.hdr); + break; + default: + LOGERR("unrecognized controlvm cmd=%d", (int) inmsg.hdr.Id); + if (inmsg.hdr.Flags.responseExpected) + controlvm_respond(&inmsg.hdr, + -CONTROLVM_RESP_ERROR_MESSAGE_ID_UNKNOWN); + break; + } + + if (parser_ctx != NULL) { + parser_done(parser_ctx); + parser_ctx = NULL; + } + return TRUE; +} + +static void +controlvm_periodic_work(struct work_struct *work) +{ + VISORCHIPSET_CHANNEL_INFO chanInfo; + CONTROLVM_MESSAGE inmsg; + char s[99]; + BOOL gotACommand = FALSE; + BOOL handle_command_failed = FALSE; + static U64 Poll_Count; + + /* make sure visorbus server is registered for controlvm callbacks */ + if (visorchipset_serverregwait && !serverregistered) + RETVOID; + /* make sure visorclientbus server is regsitered for controlvm + * callbacks + */ + if (visorchipset_clientregwait && !clientregistered) + RETVOID; + + memset(&chanInfo, 0, sizeof(VISORCHIPSET_CHANNEL_INFO)); + if (!ControlVm_channel) { + HOSTADDRESS addr = controlvm_get_channel_address(); + if (addr != 0) { + ControlVm_channel = + visorchannel_create_with_lock + (addr, + sizeof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL), + UltraControlvmChannelProtocolGuid); + if (ControlVm_channel == NULL) + LOGERR("failed to create controlvm channel"); + else if (ULTRA_CONTROLVM_CHANNEL_OK_CLIENT + (visorchannel_get_header(ControlVm_channel), + NULL)) { + LOGINF("Channel %s (ControlVm) discovered", + visorchannel_id(ControlVm_channel, s)); + initialize_controlvm_payload(); + } else { + LOGERR("controlvm channel is invalid"); + visorchannel_destroy(ControlVm_channel); + ControlVm_channel = NULL; + } + } + } + + Poll_Count++; + if ((ControlVm_channel != NULL) || (Poll_Count >= 250)) + ; /* keep going */ + else + RETVOID; + + /* Check events to determine if response to CHIPSET_READY + * should be sent + */ + if (visorchipset_holdchipsetready + && (g_ChipSetMsgHdr.Id != CONTROLVM_INVALID)) { + if (check_chipset_events() == 1) { + LOGINF("Sending CHIPSET_READY response"); + controlvm_respond(&g_ChipSetMsgHdr, 0); + clear_chipset_events(); + memset(&g_ChipSetMsgHdr, 0, + sizeof(CONTROLVM_MESSAGE_HEADER)); + } + } + + if (ControlVm_channel) { + while (visorchannel_signalremove(ControlVm_channel, + CONTROLVM_QUEUE_RESPONSE, + &inmsg)) { + if (inmsg.hdr.PayloadMaxBytes != 0) { + LOGERR("Payload of size %lu returned @%lu with unexpected message id %d.", + (ulong) inmsg.hdr.PayloadMaxBytes, + (ulong) inmsg.hdr.PayloadVmOffset, + inmsg.hdr.Id); + } + } + if (!gotACommand) { + if (ControlVm_Pending_Msg_Valid) { + /* we throttled processing of a prior + * msg, so try to process it again + * rather than reading a new one + */ + inmsg = ControlVm_Pending_Msg; + ControlVm_Pending_Msg_Valid = FALSE; + gotACommand = TRUE; + } else + gotACommand = read_controlvm_event(&inmsg); + } + } + + handle_command_failed = FALSE; + while (gotACommand && (!handle_command_failed)) { + Most_recent_message_jiffies = jiffies; + if (ControlVm_channel) { + if (handle_command(inmsg, + visorchannel_get_physaddr + (ControlVm_channel))) + gotACommand = read_controlvm_event(&inmsg); + else { + /* this is a scenario where throttling + * is required, but probably NOT an + * error...; we stash the current + * controlvm msg so we will attempt to + * reprocess it on our next loop + */ + handle_command_failed = TRUE; + ControlVm_Pending_Msg = inmsg; + ControlVm_Pending_Msg_Valid = TRUE; + } + + } else { + handle_command(inmsg, 0); + gotACommand = FALSE; + } + } + + /* parahotplug_worker */ + parahotplug_process_list(); + + RETVOID; + +Away: + + if (time_after(jiffies, + Most_recent_message_jiffies + (HZ * MIN_IDLE_SECONDS))) { + /* it's been longer than MIN_IDLE_SECONDS since we + * processed our last controlvm message; slow down the + * polling + */ + if (Poll_jiffies != POLLJIFFIES_CONTROLVMCHANNEL_SLOW) { + LOGINF("switched to slow controlvm polling"); + Poll_jiffies = POLLJIFFIES_CONTROLVMCHANNEL_SLOW; + } + } else { + if (Poll_jiffies != POLLJIFFIES_CONTROLVMCHANNEL_FAST) { + Poll_jiffies = POLLJIFFIES_CONTROLVMCHANNEL_FAST; + LOGINF("switched to fast controlvm polling"); + } + } + + if (queue_delayed_work(Periodic_controlvm_workqueue, + &Periodic_controlvm_work, Poll_jiffies) < 0) { + LOGERR("queue_delayed_work failed!"); + POSTCODE_LINUX_2(QUEUE_DELAYED_WORK_PC, POSTCODE_SEVERITY_ERR); + } +} + +static void +setup_crash_devices_work_queue(struct work_struct *work) +{ + + CONTROLVM_MESSAGE localCrashCreateBusMsg; + CONTROLVM_MESSAGE localCrashCreateDevMsg; + CONTROLVM_MESSAGE msg; + HOSTADDRESS host_addr; + U32 localSavedCrashMsgOffset; + U16 localSavedCrashMsgCount; + + /* make sure visorbus server is registered for controlvm callbacks */ + if (visorchipset_serverregwait && !serverregistered) + RETVOID; + + /* make sure visorclientbus server is regsitered for controlvm + * callbacks + */ + if (visorchipset_clientregwait && !clientregistered) + RETVOID; + + POSTCODE_LINUX_2(CRASH_DEV_ENTRY_PC, POSTCODE_SEVERITY_INFO); + + /* send init chipset msg */ + msg.hdr.Id = CONTROLVM_CHIPSET_INIT; + msg.cmd.initChipset.busCount = 23; + msg.cmd.initChipset.switchCount = 0; + + chipset_init(&msg); + + host_addr = controlvm_get_channel_address(); + if (!host_addr) { + LOGERR("Huh? Host address is NULL"); + POSTCODE_LINUX_2(CRASH_DEV_HADDR_NULL, POSTCODE_SEVERITY_ERR); + return; + } + + ControlVm_channel = + visorchannel_create_with_lock + (host_addr, + sizeof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL), + UltraControlvmChannelProtocolGuid); + + if (ControlVm_channel == NULL) { + LOGERR("failed to create controlvm channel"); + POSTCODE_LINUX_2(CRASH_DEV_CONTROLVM_NULL, + POSTCODE_SEVERITY_ERR); + return; + } + + /* get saved message count */ + if (visorchannel_read(ControlVm_channel, + offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL, + SavedCrashMsgCount), + &localSavedCrashMsgCount, sizeof(U16)) < 0) { + LOGERR("failed to get Saved Message Count"); + POSTCODE_LINUX_2(CRASH_DEV_CTRL_RD_FAILURE_PC, + POSTCODE_SEVERITY_ERR); + return; + } + + if (localSavedCrashMsgCount != CONTROLVM_CRASHMSG_MAX) { + LOGERR("Saved Message Count incorrect %d", + localSavedCrashMsgCount); + POSTCODE_LINUX_3(CRASH_DEV_COUNT_FAILURE_PC, + localSavedCrashMsgCount, + POSTCODE_SEVERITY_ERR); + return; + } + + /* get saved crash message offset */ + if (visorchannel_read(ControlVm_channel, + offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL, + SavedCrashMsgOffset), + &localSavedCrashMsgOffset, sizeof(U32)) < 0) { + LOGERR("failed to get Saved Message Offset"); + POSTCODE_LINUX_2(CRASH_DEV_CTRL_RD_FAILURE_PC, + POSTCODE_SEVERITY_ERR); + return; + } + + /* read create device message for storage bus offset */ + if (visorchannel_read(ControlVm_channel, + localSavedCrashMsgOffset, + &localCrashCreateBusMsg, + sizeof(CONTROLVM_MESSAGE)) < 0) { + LOGERR("CRASH_DEV_RD_BUS_FAIULRE: Failed to read CrashCreateBusMsg!"); + POSTCODE_LINUX_2(CRASH_DEV_RD_BUS_FAIULRE_PC, + POSTCODE_SEVERITY_ERR); + return; + } + + /* read create device message for storage device */ + if (visorchannel_read(ControlVm_channel, + localSavedCrashMsgOffset + + sizeof(CONTROLVM_MESSAGE), + &localCrashCreateDevMsg, + sizeof(CONTROLVM_MESSAGE)) < 0) { + LOGERR("CRASH_DEV_RD_DEV_FAIULRE: Failed to read CrashCreateDevMsg!"); + POSTCODE_LINUX_2(CRASH_DEV_RD_DEV_FAIULRE_PC, + POSTCODE_SEVERITY_ERR); + return; + } + + /* reuse IOVM create bus message */ + if (localCrashCreateBusMsg.cmd.createBus.channelAddr != 0) + bus_create(&localCrashCreateBusMsg); + else { + LOGERR("CrashCreateBusMsg is null, no dump will be taken"); + POSTCODE_LINUX_2(CRASH_DEV_BUS_NULL_FAILURE_PC, + POSTCODE_SEVERITY_ERR); + return; + } + + /* reuse create device message for storage device */ + if (localCrashCreateDevMsg.cmd.createDevice.channelAddr != 0) + my_device_create(&localCrashCreateDevMsg); + else { + LOGERR("CrashCreateDevMsg is null, no dump will be taken"); + POSTCODE_LINUX_2(CRASH_DEV_DEV_NULL_FAILURE_PC, + POSTCODE_SEVERITY_ERR); + return; + } + LOGINF("Bus and device ready for dumping"); + POSTCODE_LINUX_2(CRASH_DEV_EXIT_PC, POSTCODE_SEVERITY_INFO); + return; + +Away: + + Poll_jiffies = POLLJIFFIES_CONTROLVMCHANNEL_SLOW; + + if (queue_delayed_work(Periodic_controlvm_workqueue, + &Periodic_controlvm_work, Poll_jiffies) < 0) { + LOGERR("queue_delayed_work failed!"); + POSTCODE_LINUX_2(QUEUE_DELAYED_WORK_PC, POSTCODE_SEVERITY_ERR); + } +} + +static void +bus_create_response(ulong busNo, int response) +{ + bus_responder(CONTROLVM_BUS_CREATE, busNo, response); +} + +static void +bus_destroy_response(ulong busNo, int response) +{ + bus_responder(CONTROLVM_BUS_DESTROY, busNo, response); +} + +static void +device_create_response(ulong busNo, ulong devNo, int response) +{ + device_responder(CONTROLVM_DEVICE_CREATE, busNo, devNo, response); +} + +static void +device_destroy_response(ulong busNo, ulong devNo, int response) +{ + device_responder(CONTROLVM_DEVICE_DESTROY, busNo, devNo, response); +} + +void +device_pause_response(ulong busNo, ulong devNo, int response) +{ + + device_changestate_responder(CONTROLVM_DEVICE_CHANGESTATE, + busNo, devNo, response, + SegmentStateStandby); +} +EXPORT_SYMBOL_GPL(device_pause_response); + +static void +device_resume_response(ulong busNo, ulong devNo, int response) +{ + device_changestate_responder(CONTROLVM_DEVICE_CHANGESTATE, + busNo, devNo, response, + SegmentStateRunning); +} + +BOOL +visorchipset_get_bus_info(ulong busNo, VISORCHIPSET_BUS_INFO *busInfo) +{ + void *p = findbus(&BusInfoList, busNo); + if (!p) { + LOGERR("(%lu) failed", busNo); + return FALSE; + } + memcpy(busInfo, p, sizeof(VISORCHIPSET_BUS_INFO)); + return TRUE; +} +EXPORT_SYMBOL_GPL(visorchipset_get_bus_info); + +BOOL +visorchipset_set_bus_context(ulong busNo, void *context) +{ + VISORCHIPSET_BUS_INFO *p = findbus(&BusInfoList, busNo); + if (!p) { + LOGERR("(%lu) failed", busNo); + return FALSE; + } + p->bus_driver_context = context; + return TRUE; +} +EXPORT_SYMBOL_GPL(visorchipset_set_bus_context); + +BOOL +visorchipset_get_device_info(ulong busNo, ulong devNo, + VISORCHIPSET_DEVICE_INFO *devInfo) +{ + void *p = finddevice(&DevInfoList, busNo, devNo); + if (!p) { + LOGERR("(%lu,%lu) failed", busNo, devNo); + return FALSE; + } + memcpy(devInfo, p, sizeof(VISORCHIPSET_DEVICE_INFO)); + return TRUE; +} +EXPORT_SYMBOL_GPL(visorchipset_get_device_info); + +BOOL +visorchipset_set_device_context(ulong busNo, ulong devNo, void *context) +{ + VISORCHIPSET_DEVICE_INFO *p = finddevice(&DevInfoList, busNo, devNo); + if (!p) { + LOGERR("(%lu,%lu) failed", busNo, devNo); + return FALSE; + } + p->bus_driver_context = context; + return TRUE; +} +EXPORT_SYMBOL_GPL(visorchipset_set_device_context); + +/* Generic wrapper function for allocating memory from a kmem_cache pool. + */ +void * +visorchipset_cache_alloc(struct kmem_cache *pool, BOOL ok_to_block, + char *fn, int ln) +{ + gfp_t gfp; + void *p; + + if (ok_to_block) + gfp = GFP_KERNEL; + else + gfp = GFP_ATOMIC; + /* __GFP_NORETRY means "ok to fail", meaning + * kmem_cache_alloc() can return NULL, implying the caller CAN + * cope with failure. If you do NOT specify __GFP_NORETRY, + * Linux will go to extreme measures to get memory for you + * (like, invoke oom killer), which will probably cripple the + * system. + */ + gfp |= __GFP_NORETRY; + p = kmem_cache_alloc(pool, gfp); + if (!p) { + LOGERR("kmem_cache_alloc failed early @%s:%d\n", fn, ln); + return NULL; + } + atomic_inc(&Visorchipset_cache_buffers_in_use); + return p; +} + +/* Generic wrapper function for freeing memory from a kmem_cache pool. + */ +void +visorchipset_cache_free(struct kmem_cache *pool, void *p, char *fn, int ln) +{ + if (!p) { + LOGERR("NULL pointer @%s:%d\n", fn, ln); + return; + } + atomic_dec(&Visorchipset_cache_buffers_in_use); + kmem_cache_free(pool, p); +} + +#define gettoken(bufp) strsep(bufp, " -\t\n") + +static ssize_t +chipset_proc_write(struct file *file, const char __user *buffer, + size_t count, loff_t *ppos) +{ + char buf[512]; + char *token, *p; + + if (count > sizeof(buf) - 1) { + LOGERR("chipset_proc_write: count (%d) exceeds size of buffer (%d)", + (int) count, (int) sizeof(buffer)); + return -EINVAL; + } + if (copy_from_user(buf, buffer, count)) { + LOGERR("chipset_proc_write: copy_from_user failed"); + return -EFAULT; + } + buf[count] = '\0'; + + p = buf; + token = gettoken(&p); + + if (strcmp(token, "CALLHOMEDISK_MOUNTED") == 0) { + token = gettoken(&p); + /* The Call Home Disk has been mounted */ + if (strcmp(token, "0") == 0) + chipset_events[0] = 1; + } else if (strcmp(token, "MODULES_LOADED") == 0) { + token = gettoken(&p); + /* All modules for the partition have been loaded */ + if (strcmp(token, "0") == 0) + chipset_events[1] = 1; + } else if (token == NULL) { + /* No event specified */ + LOGERR("No event was specified to send CHIPSET_READY response"); + return -1; + } else { + /* Unsupported event specified */ + LOGERR("%s is an invalid event for sending CHIPSET_READY response", token); + return -1; + } + + return count; +} + +static ssize_t +visorchipset_proc_read_writeonly(struct file *file, char __user *buf, + size_t len, loff_t *offset) +{ + return 0; +} + +/** + * Reads the InstallationError, InstallationTextId, + * InstallationRemainingSteps fields of ControlVMChannel. + */ +static ssize_t +proc_read_installer(struct file *file, char __user *buf, + size_t len, loff_t *offset) +{ + int length = 0; + U16 remainingSteps; + U32 error, textId; + char *vbuf; + loff_t pos = *offset; + + if (pos < 0) + return -EINVAL; + + if (pos > 0 || !len) + return 0; + + vbuf = kzalloc(len, GFP_KERNEL); + if (!vbuf) + return -ENOMEM; + + visorchannel_read(ControlVm_channel, + offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL, + InstallationRemainingSteps), &remainingSteps, + sizeof(U16)); + visorchannel_read(ControlVm_channel, + offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL, + InstallationError), &error, sizeof(U32)); + visorchannel_read(ControlVm_channel, + offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL, + InstallationTextId), &textId, sizeof(U32)); + + length = sprintf(vbuf, "%u %u %u\n", remainingSteps, error, textId); + if (copy_to_user(buf, vbuf, length)) { + kfree(vbuf); + return -EFAULT; + } + + kfree(vbuf); + *offset += length; + return length; +} + +/** + * Writes to the InstallationError, InstallationTextId, + * InstallationRemainingSteps fields of + * ControlVMChannel. + * Input: RemainingSteps Error TextId + * Limit 32 characters input + */ +#define UINT16_MAX (65535U) +#define UINT32_MAX (4294967295U) +static ssize_t +proc_write_installer(struct file *file, + const char __user *buffer, size_t count, loff_t *ppos) +{ + char buf[32]; + U16 remainingSteps; + U32 error, textId; + + /* Check to make sure there is no buffer overflow */ + if (count > (sizeof(buf) - 1)) + return -EINVAL; + + if (copy_from_user(buf, buffer, count)) { + WARN(1, "Error copying from user space\n"); + return -EFAULT; + } + + if (sscanf(buf, "%hu %i %i", &remainingSteps, &error, &textId) != 3) { + remainingSteps = UINT16_MAX; + error = UINT32_MAX; + textId = UINT32_MAX; + } + + if (remainingSteps != UINT16_MAX) { + if (visorchannel_write + (ControlVm_channel, + offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL, + InstallationRemainingSteps), &remainingSteps, + sizeof(U16)) < 0) + WARN(1, "Installation Status Write Failed - Write function error - RemainingSteps = %d\n", + remainingSteps); + } + + if (error != UINT32_MAX) { + if (visorchannel_write + (ControlVm_channel, + offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL, + InstallationError), &error, sizeof(U32)) < 0) + WARN(1, "Installation Status Write Failed - Write function error - Error = %d\n", + error); + } + + if (textId != UINT32_MAX) { + if (visorchannel_write + (ControlVm_channel, + offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL, + InstallationTextId), &textId, sizeof(U32)) < 0) + WARN(1, "Installation Status Write Failed - Write function error - TextId = %d\n", + textId); + } + + /* So this function isn't called multiple times, must return + * size of buffer + */ + return count; +} + +/** + * Reads the ToolAction field of ControlVMChannel. + */ +static ssize_t +proc_read_toolaction(struct file *file, char __user *buf, + size_t len, loff_t *offset) +{ + int length = 0; + U8 toolAction; + char *vbuf; + loff_t pos = *offset; + + if (pos < 0) + return -EINVAL; + + if (pos > 0 || !len) + return 0; + + vbuf = kzalloc(len, GFP_KERNEL); + if (!vbuf) + return -ENOMEM; + + visorchannel_read(ControlVm_channel, + offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL, + ToolAction), &toolAction, sizeof(U8)); + + length = sprintf(vbuf, "%u\n", toolAction); + if (copy_to_user(buf, vbuf, length)) { + kfree(vbuf); + return -EFAULT; + } + + kfree(vbuf); + *offset += length; + return length; +} + +/** + * Writes to the ToolAction field of ControlVMChannel. + * Input: ToolAction + * Limit 3 characters input + */ +#define UINT8_MAX (255U) +static ssize_t +proc_write_toolaction(struct file *file, + const char __user *buffer, size_t count, loff_t *ppos) +{ + char buf[3]; + U8 toolAction; + + /* Check to make sure there is no buffer overflow */ + if (count > (sizeof(buf) - 1)) + return -EINVAL; + + if (copy_from_user(buf, buffer, count)) { + WARN(1, "Error copying from user space\n"); + return -EFAULT; + } + + if (sscanf(buf, "%hhd", &toolAction) != 1) + toolAction = UINT8_MAX; + + if (toolAction != UINT8_MAX) { + if (visorchannel_write + (ControlVm_channel, + offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL, ToolAction), + &toolAction, sizeof(U8)) < 0) + WARN(1, "Installation ToolAction Write Failed - ToolAction = %d\n", + toolAction); + } + + /* So this function isn't called multiple times, must return + * size of buffer + */ + return count; +} + +/** + * Reads the EfiSparIndication.BootToTool field of ControlVMChannel. + */ +static ssize_t +proc_read_bootToTool(struct file *file, char __user *buf, + size_t len, loff_t *offset) +{ + int length = 0; + ULTRA_EFI_SPAR_INDICATION efiSparIndication; + char *vbuf; + loff_t pos = *offset; + + if (pos < 0) + return -EINVAL; + + if (pos > 0 || !len) + return 0; + + vbuf = kzalloc(len, GFP_KERNEL); + if (!vbuf) + return -ENOMEM; + + visorchannel_read(ControlVm_channel, + offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL, + EfiSparIndication), &efiSparIndication, + sizeof(ULTRA_EFI_SPAR_INDICATION)); + + length = sprintf(vbuf, "%d\n", (int) efiSparIndication.BootToTool); + if (copy_to_user(buf, vbuf, length)) { + kfree(vbuf); + return -EFAULT; + } + + kfree(vbuf); + *offset += length; + return length; +} + +/** + * Writes to the EfiSparIndication.BootToTool field of ControlVMChannel. + * Input: 1 or 0 (1 being on, 0 being off) + */ +static ssize_t +proc_write_bootToTool(struct file *file, + const char __user *buffer, size_t count, loff_t *ppos) +{ + char buf[3]; + int inputVal; + ULTRA_EFI_SPAR_INDICATION efiSparIndication; + + /* Check to make sure there is no buffer overflow */ + if (count > (sizeof(buf) - 1)) + return -EINVAL; + + if (copy_from_user(buf, buffer, count)) { + WARN(1, "Error copying from user space\n"); + return -EFAULT; + } + + if (sscanf(buf, "%i", &inputVal) != 1) + inputVal = 0; + + efiSparIndication.BootToTool = (inputVal == 1 ? 1 : 0); + + if (visorchannel_write + (ControlVm_channel, + offsetof(ULTRA_CONTROLVM_CHANNEL_PROTOCOL, EfiSparIndication), + &efiSparIndication, sizeof(ULTRA_EFI_SPAR_INDICATION)) < 0) + printk + ("Installation BootToTool Write Failed - BootToTool = %d\n", + (int) efiSparIndication.BootToTool); + + /* So this function isn't called multiple times, must return + * size of buffer + */ + return count; +} + +static const struct file_operations chipset_proc_fops = { + .owner = THIS_MODULE, + .read = visorchipset_proc_read_writeonly, + .write = chipset_proc_write, +}; + +static int __init +visorchipset_init(void) +{ + int rc = 0, x = 0; + struct proc_dir_entry *installer_file; + struct proc_dir_entry *toolaction_file; + struct proc_dir_entry *bootToTool_file; + + LOGINF("chipset driver version %s loaded", VERSION); + /* process module options */ + POSTCODE_LINUX_2(DRIVER_ENTRY_PC, POSTCODE_SEVERITY_INFO); + + LOGINF("option - testvnic=%d", visorchipset_testvnic); + LOGINF("option - testvnicclient=%d", visorchipset_testvnicclient); + LOGINF("option - testmsg=%d", visorchipset_testmsg); + LOGINF("option - testteardown=%d", visorchipset_testteardown); + LOGINF("option - major=%d", visorchipset_major); + LOGINF("option - serverregwait=%d", visorchipset_serverregwait); + LOGINF("option - clientregwait=%d", visorchipset_clientregwait); + LOGINF("option - holdchipsetready=%d", visorchipset_holdchipsetready); + + memset(&BusDev_Server_Notifiers, 0, sizeof(BusDev_Server_Notifiers)); + memset(&BusDev_Client_Notifiers, 0, sizeof(BusDev_Client_Notifiers)); + memset(&ControlVm_payload_info, 0, sizeof(ControlVm_payload_info)); + memset(&LiveDump_info, 0, sizeof(LiveDump_info)); + atomic_set(&LiveDump_info.buffers_in_use, 0); + + if (visorchipset_testvnic) + FAIL_WPOSTCODE_2("testvnic option no longer supported", x, + CHIPSET_INIT_FAILURE_PC, x); + + controlvm_init(); + MajorDev = MKDEV(visorchipset_major, 0); + TRY_WPOSTCODE_1(visorchipset_file_init(MajorDev, &ControlVm_channel), + CHIPSET_INIT_FAILURE_PC); + proc_Init(); + memset(PartitionPropertyNames, 0, sizeof(PartitionPropertyNames)); + memset(ControlVmPropertyNames, 0, sizeof(ControlVmPropertyNames)); + InitPartitionProperties(); + InitControlVmProperties(); + + PartitionType = proc_CreateType(ProcDir, PartitionTypeNames, + (const char **) PartitionPropertyNames, + &show_partition_property); + ControlVmType = + proc_CreateType(ProcDir, ControlVmTypeNames, + (const char **) ControlVmPropertyNames, + &show_controlvm_property); + + ControlVmObject = proc_CreateObject(ControlVmType, NULL, NULL); + + /* Setup Installation fields */ + installer_file = proc_create("installer", 0644, ProcDir, + &proc_installer_fops); + /* Setup the ToolAction field */ + toolaction_file = proc_create("toolaction", 0644, ProcDir, + &proc_toolaction_fops); + /* Setup the BootToTool field */ + bootToTool_file = proc_create("boottotool", 0644, ProcDir, + &proc_bootToTool_fops); + + memset(&g_DiagMsgHdr, 0, sizeof(CONTROLVM_MESSAGE_HEADER)); + + chipset_proc_dir = proc_create(VISORCHIPSET_CHIPSET_PROC_ENTRY_FN, + 0644, ProcDir, &chipset_proc_fops); + memset(&g_ChipSetMsgHdr, 0, sizeof(CONTROLVM_MESSAGE_HEADER)); + + parahotplug_proc_dir = + proc_create(VISORCHIPSET_PARAHOTPLUG_PROC_ENTRY_FN, 0200, + ProcDir, ¶hotplug_proc_fops); + memset(&g_DelDumpMsgHdr, 0, sizeof(CONTROLVM_MESSAGE_HEADER)); + + if (filexfer_constructor(sizeof(struct putfile_request)) < 0) { + FAIL_WPOSTCODE_1("filexfer_constructor failed", -1, + CHIPSET_INIT_FAILURE_PC); + } + Putfile_buffer_list_pool = + kmem_cache_create(Putfile_buffer_list_pool_name, + sizeof(struct putfile_buffer_entry), + 0, SLAB_HWCACHE_ALIGN, NULL); + if (!Putfile_buffer_list_pool) { + FAIL_WPOSTCODE_1("failed to alloc Putfile_buffer_list_pool", -1, + CHIPSET_INIT_FAILURE_PC); + } + if (visorchipset_disable_controlvm) { + LOGINF("visorchipset_init:controlvm disabled"); + } else { + /* if booting in a crash kernel */ + if (visorchipset_crash_kernel) + INIT_DELAYED_WORK(&Periodic_controlvm_work, + setup_crash_devices_work_queue); + else + INIT_DELAYED_WORK(&Periodic_controlvm_work, + controlvm_periodic_work); + Periodic_controlvm_workqueue = + create_singlethread_workqueue("visorchipset_controlvm"); + + if (Periodic_controlvm_workqueue == NULL) + FAIL_WPOSTCODE_1("cannot create controlvm workqueue", + -ENOMEM, CREATE_WORKQUEUE_FAILED_PC); + Most_recent_message_jiffies = jiffies; + Poll_jiffies = POLLJIFFIES_CONTROLVMCHANNEL_FAST; + TRY_WPOSTCODE_1(queue_delayed_work + (Periodic_controlvm_workqueue, + &Periodic_controlvm_work, Poll_jiffies), + QUEUE_DELAYED_WORK_PC); + } + + Visorchipset_platform_device.dev.devt = MajorDev; + if (platform_device_register(&Visorchipset_platform_device) < 0) + FAIL_WPOSTCODE_1 + ("platform_device_register(visorchipset) failed", -1, + DEVICE_REGISTER_FAILURE_PC); + LOGINF("visorchipset device created"); + POSTCODE_LINUX_2(CHIPSET_INIT_SUCCESS_PC, POSTCODE_SEVERITY_INFO); + RETINT(0); + +Away: + + if (rc) { + LOGERR("visorchipset_init failed"); + POSTCODE_LINUX_3(CHIPSET_INIT_FAILURE_PC, rc, + POSTCODE_SEVERITY_ERR); + } + return rc; +} + +static void +visorchipset_exit(void) +{ + char s[99]; + POSTCODE_LINUX_2(DRIVER_EXIT_PC, POSTCODE_SEVERITY_INFO); + + if (visorchipset_disable_controlvm) { + ; + } else { + cancel_delayed_work(&Periodic_controlvm_work); + flush_workqueue(Periodic_controlvm_workqueue); + destroy_workqueue(Periodic_controlvm_workqueue); + Periodic_controlvm_workqueue = NULL; + destroy_controlvm_payload_info(&ControlVm_payload_info); + } + Test_Vnic_channel = NULL; + if (Putfile_buffer_list_pool) { + kmem_cache_destroy(Putfile_buffer_list_pool); + Putfile_buffer_list_pool = NULL; + } + filexfer_destructor(); + if (ControlVmObject) { + proc_DestroyObject(ControlVmObject); + ControlVmObject = NULL; + } + cleanup_controlvm_structures(); + + if (ControlVmType) { + proc_DestroyType(ControlVmType); + ControlVmType = NULL; + } + if (PartitionType) { + proc_DestroyType(PartitionType); + PartitionType = NULL; + } + if (diag_proc_dir) { + remove_proc_entry(VISORCHIPSET_DIAG_PROC_ENTRY_FN, ProcDir); + diag_proc_dir = NULL; + } + memset(&g_DiagMsgHdr, 0, sizeof(CONTROLVM_MESSAGE_HEADER)); + + if (chipset_proc_dir) { + remove_proc_entry(VISORCHIPSET_CHIPSET_PROC_ENTRY_FN, ProcDir); + chipset_proc_dir = NULL; + } + memset(&g_ChipSetMsgHdr, 0, sizeof(CONTROLVM_MESSAGE_HEADER)); + + if (parahotplug_proc_dir) { + remove_proc_entry(VISORCHIPSET_PARAHOTPLUG_PROC_ENTRY_FN, + ProcDir); + parahotplug_proc_dir = NULL; + } + + memset(&g_DelDumpMsgHdr, 0, sizeof(CONTROLVM_MESSAGE_HEADER)); + + proc_DeInit(); + if (ControlVm_channel != NULL) { + LOGINF("Channel %s (ControlVm) disconnected", + visorchannel_id(ControlVm_channel, s)); + visorchannel_destroy(ControlVm_channel); + ControlVm_channel = NULL; + } + controlvm_deinit(); + visorchipset_file_cleanup(); + POSTCODE_LINUX_2(DRIVER_EXIT_PC, POSTCODE_SEVERITY_INFO); + LOGINF("chipset driver unloaded"); +} + +module_param_named(testvnic, visorchipset_testvnic, int, S_IRUGO); +MODULE_PARM_DESC(visorchipset_testvnic, "1 to test vnic, using dummy VNIC connected via a loopback to a physical ethernet"); +int visorchipset_testvnic = 0; + +module_param_named(testvnicclient, visorchipset_testvnicclient, int, S_IRUGO); +MODULE_PARM_DESC(visorchipset_testvnicclient, "1 to test vnic, using real VNIC channel attached to a separate IOVM guest"); +int visorchipset_testvnicclient = 0; + +module_param_named(testmsg, visorchipset_testmsg, int, S_IRUGO); +MODULE_PARM_DESC(visorchipset_testmsg, + "1 to manufacture the chipset, bus, and switch messages"); +int visorchipset_testmsg = 0; + +module_param_named(major, visorchipset_major, int, S_IRUGO); +MODULE_PARM_DESC(visorchipset_major, "major device number to use for the device node"); +int visorchipset_major = 0; + +module_param_named(serverregwait, visorchipset_serverregwait, int, S_IRUGO); +MODULE_PARM_DESC(visorchipset_serverreqwait, + "1 to have the module wait for the visor bus to register"); +int visorchipset_serverregwait = 0; /* default is off */ +module_param_named(clientregwait, visorchipset_clientregwait, int, S_IRUGO); +MODULE_PARM_DESC(visorchipset_clientregwait, "1 to have the module wait for the visorclientbus to register"); +int visorchipset_clientregwait = 1; /* default is on */ +module_param_named(testteardown, visorchipset_testteardown, int, S_IRUGO); +MODULE_PARM_DESC(visorchipset_testteardown, + "1 to test teardown of the chipset, bus, and switch"); +int visorchipset_testteardown = 0; /* default is off */ +module_param_named(disable_controlvm, visorchipset_disable_controlvm, int, + S_IRUGO); +MODULE_PARM_DESC(visorchipset_disable_controlvm, + "1 to disable polling of controlVm channel"); +int visorchipset_disable_controlvm = 0; /* default is off */ +module_param_named(crash_kernel, visorchipset_crash_kernel, int, S_IRUGO); +MODULE_PARM_DESC(visorchipset_crash_kernel, + "1 means we are running in crash kernel"); +int visorchipset_crash_kernel = 0; /* default is running in non-crash kernel */ +module_param_named(holdchipsetready, visorchipset_holdchipsetready, + int, S_IRUGO); +MODULE_PARM_DESC(visorchipset_holdchipsetready, + "1 to hold response to CHIPSET_READY"); +int visorchipset_holdchipsetready = 0; /* default is to send CHIPSET_READY + * response immediately */ +module_init(visorchipset_init); +module_exit(visorchipset_exit); + +MODULE_AUTHOR("Unisys"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Supervisor chipset driver for service partition: ver " + VERSION); +MODULE_VERSION(VERSION); diff --git a/drivers/staging/unisys/visorchipset/visorchipset_umode.h b/drivers/staging/unisys/visorchipset/visorchipset_umode.h new file mode 100644 index 00000000000..259e840376a --- /dev/null +++ b/drivers/staging/unisys/visorchipset/visorchipset_umode.h @@ -0,0 +1,37 @@ +/* visorchipset_umode.h + * + * Copyright © 2010 - 2013 UNISYS CORPORATION + * 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. + */ + +/** @file ********************************************************************* + * + * This describes structures needed for the interface between the + * visorchipset driver and a user-mode component that opens the device. + * + ****************************************************************************** + */ + +#ifndef __VISORCHIPSET_UMODE_H +#define __VISORCHIPSET_UMODE_H + + + +/** The user-mode program can access the control channel buffer directly + * via this memory map. + */ +#define VISORCHIPSET_MMAP_CONTROLCHANOFFSET (0x00000000) +#define VISORCHIPSET_MMAP_CONTROLCHANSIZE (0x00400000) /* 4MB */ + +#endif /* __VISORCHIPSET_UMODE_H */ diff --git a/drivers/staging/unisys/visorutil/Kconfig b/drivers/staging/unisys/visorutil/Kconfig new file mode 100644 index 00000000000..4ff61a7c506 --- /dev/null +++ b/drivers/staging/unisys/visorutil/Kconfig @@ -0,0 +1,10 @@ +# +# Unisys timskmod configuration +# + +config UNISYS_VISORUTIL + tristate "Unisys visorutil driver" + depends on UNISYSSPAR + ---help--- + If you say Y here, you will enable the Unisys visorutil driver. + diff --git a/drivers/staging/unisys/visorutil/Makefile b/drivers/staging/unisys/visorutil/Makefile new file mode 100644 index 00000000000..3f463888dce --- /dev/null +++ b/drivers/staging/unisys/visorutil/Makefile @@ -0,0 +1,11 @@ +# +# Makefile for Unisys timskmod +# + +obj-$(CONFIG_UNISYS_VISORUTIL) += visorutil.o + +visorutil-y := charqueue.o easyproc.o periodic_work.o procobjecttree.o \ + memregion_direct.o visorkmodutils.o + +ccflags-y += -Idrivers/staging/unisys/include +ccflags-y += -DCONFIG_SPAR_GUEST -DGUESTDRIVERBUILD -DNOAUTOVERSION diff --git a/drivers/staging/unisys/visorutil/charqueue.c b/drivers/staging/unisys/visorutil/charqueue.c new file mode 100644 index 00000000000..2bce94e7009 --- /dev/null +++ b/drivers/staging/unisys/visorutil/charqueue.c @@ -0,0 +1,144 @@ +/* charqueue.c + * + * Copyright © 2010 - 2013 UNISYS CORPORATION + * 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. + */ + +/* + * Simple character queue implementation for Linux kernel mode. + */ + +#include "charqueue.h" + +#define MYDRVNAME "charqueue" + +#define IS_EMPTY(charqueue) (charqueue->head == charqueue->tail) + + + +struct CHARQUEUE_Tag { + int alloc_size; + int nslots; + spinlock_t lock; + int head, tail; + unsigned char buf[0]; +}; + + + +CHARQUEUE *charqueue_create(ulong nslots) +{ + int alloc_size = sizeof(CHARQUEUE) + nslots + 1; + CHARQUEUE *cq = kmalloc(alloc_size, GFP_KERNEL|__GFP_NORETRY); + if (cq == NULL) { + ERRDRV("charqueue_create allocation failed (alloc_size=%d)", + alloc_size); + return NULL; + } + cq->alloc_size = alloc_size; + cq->nslots = nslots; + cq->head = cq->tail = 0; + spin_lock_init(&cq->lock); + return cq; +} +EXPORT_SYMBOL_GPL(charqueue_create); + + + +void charqueue_enqueue(CHARQUEUE *charqueue, unsigned char c) +{ + int alloc_slots = charqueue->nslots+1; /* 1 slot is always empty */ + + spin_lock(&charqueue->lock); + charqueue->head = (charqueue->head+1) % alloc_slots; + if (charqueue->head == charqueue->tail) + /* overflow; overwrite the oldest entry */ + charqueue->tail = (charqueue->tail+1) % alloc_slots; + charqueue->buf[charqueue->head] = c; + spin_unlock(&charqueue->lock); +} +EXPORT_SYMBOL_GPL(charqueue_enqueue); + + + +BOOL charqueue_is_empty(CHARQUEUE *charqueue) +{ + BOOL b; + spin_lock(&charqueue->lock); + b = IS_EMPTY(charqueue); + spin_unlock(&charqueue->lock); + return b; +} +EXPORT_SYMBOL_GPL(charqueue_is_empty); + + + +static int charqueue_dequeue_1(CHARQUEUE *charqueue) +{ + int alloc_slots = charqueue->nslots + 1; /* 1 slot is always empty */ + + if (IS_EMPTY(charqueue)) + return -1; + charqueue->tail = (charqueue->tail+1) % alloc_slots; + return charqueue->buf[charqueue->tail]; +} + + + +int charqueue_dequeue(CHARQUEUE *charqueue) +{ + int rc = -1; + + spin_lock(&charqueue->lock); + RETINT(charqueue_dequeue_1(charqueue)); +Away: + spin_unlock(&charqueue->lock); + return rc; +} + + + +int charqueue_dequeue_n(CHARQUEUE *charqueue, unsigned char *buf, int n) +{ + int rc = -1, counter = 0, c; + + spin_lock(&charqueue->lock); + for (;;) { + if (n <= 0) + break; /* no more buffer space */ + c = charqueue_dequeue_1(charqueue); + if (c < 0) + break; /* no more input */ + *buf = (unsigned char)(c); + buf++; + n--; + counter++; + } + RETINT(counter); + +Away: + spin_unlock(&charqueue->lock); + return rc; +} +EXPORT_SYMBOL_GPL(charqueue_dequeue_n); + + + +void charqueue_destroy(CHARQUEUE *charqueue) +{ + if (charqueue == NULL) + return; + kfree(charqueue); +} +EXPORT_SYMBOL_GPL(charqueue_destroy); diff --git a/drivers/staging/unisys/visorutil/charqueue.h b/drivers/staging/unisys/visorutil/charqueue.h new file mode 100644 index 00000000000..e9ce0a90d86 --- /dev/null +++ b/drivers/staging/unisys/visorutil/charqueue.h @@ -0,0 +1,37 @@ +/* charqueue.h + * + * Copyright © 2010 - 2013 UNISYS CORPORATION + * 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. + */ + +#ifndef __CHARQUEUE_H__ +#define __CHARQUEUE_H__ + +#include "uniklog.h" +#include "timskmod.h" + +/* CHARQUEUE is an opaque structure to users. + * Fields are declared only in the implementation .c files. + */ +typedef struct CHARQUEUE_Tag CHARQUEUE; + +CHARQUEUE *charqueue_create(ulong nslots); +void charqueue_enqueue(CHARQUEUE *charqueue, unsigned char c); +int charqueue_dequeue(CHARQUEUE *charqueue); +int charqueue_dequeue_n(CHARQUEUE *charqueue, unsigned char *buf, int n); +BOOL charqueue_is_empty(CHARQUEUE *charqueue); +void charqueue_destroy(CHARQUEUE *charqueue); + +#endif + diff --git a/drivers/staging/unisys/visorutil/easyproc.c b/drivers/staging/unisys/visorutil/easyproc.c new file mode 100644 index 00000000000..2b750eef9f0 --- /dev/null +++ b/drivers/staging/unisys/visorutil/easyproc.c @@ -0,0 +1,365 @@ +/* Copyright © 2010 - 2013 UNISYS CORPORATION + * 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. + */ + +/** @file ********************************************************************* + * + * Handle procfs-specific tasks. + * Note that this file does not know about any module-specific things, nor + * does it know anything about what information to reveal as part of the proc + * entries. The 2 functions that take care of displaying device and + * driver specific information are passed as parameters to + * easyproc_InitDriver(). + * + * void show_device_info(struct seq_file *seq, void *p); + * void show_driver_info(struct seq_file *seq); + * + * The second parameter to show_device_info is actually a pointer to the + * device-specific info to show. It is the context that was originally + * passed to easyproc_InitDevice(). + * + ****************************************************************************** + */ + +#include <linux/proc_fs.h> + +#include "uniklog.h" +#include "timskmod.h" +#include "easyproc.h" + +#define MYDRVNAME "easyproc" + + + +/* + * /proc/<ProcId> ProcDir + * /proc/<ProcId>/driver ProcDriverDir + * /proc/<ProcId>/driver/diag ProcDriverDiagFile + * /proc/<ProcId>/device ProcDeviceDir + * /proc/<ProcId>/device/0 procDevicexDir + * /proc/<ProcId>/device/0/diag procDevicexDiagFile + */ + + +static ssize_t proc_write_device(struct file *file, const char __user *buffer, + size_t count, loff_t *ppos); +static ssize_t proc_write_driver(struct file *file, const char __user *buffer, + size_t count, loff_t *ppos); + +static struct proc_dir_entry * + createProcDir(char *name, struct proc_dir_entry *parent) +{ + struct proc_dir_entry *p = proc_mkdir_mode(name, S_IFDIR, parent); + if (p == NULL) + ERRDRV("failed to create /proc directory %s", name); + return p; +} + +static int seq_show_driver(struct seq_file *seq, void *offset); +static int proc_open_driver(struct inode *inode, struct file *file) +{ + return single_open(file, seq_show_driver, PDE_DATA(inode)); +} +static const struct file_operations proc_fops_driver = { + .open = proc_open_driver, + .read = seq_read, + .write = proc_write_driver, + .llseek = seq_lseek, + .release = single_release, +}; + +static int seq_show_device(struct seq_file *seq, void *offset); +static int seq_show_device_property(struct seq_file *seq, void *offset); +static int proc_open_device(struct inode *inode, struct file *file) +{ + return single_open(file, seq_show_device, PDE_DATA(inode)); +} +static const struct file_operations proc_fops_device = { + .open = proc_open_device, + .read = seq_read, + .write = proc_write_device, + .llseek = seq_lseek, + .release = single_release, +}; +static int proc_open_device_property(struct inode *inode, struct file *file) +{ + return single_open(file, seq_show_device_property, PDE_DATA(inode)); +} +static const struct file_operations proc_fops_device_property = { + .open = proc_open_device_property, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + + + +void easyproc_InitDriver(struct easyproc_driver_info *pdriver, + char *procId, + void (*show_driver_info)(struct seq_file *), + void (*show_device_info)(struct seq_file *, void *)) +{ + memset(pdriver, 0, sizeof(struct easyproc_driver_info)); + pdriver->ProcId = procId; + if (pdriver->ProcId == NULL) + ERRDRV("ProcId cannot be NULL (trouble ahead)!"); + pdriver->Show_driver_info = show_driver_info; + pdriver->Show_device_info = show_device_info; + if (pdriver->ProcDir == NULL) + pdriver->ProcDir = createProcDir(pdriver->ProcId, NULL); + if ((pdriver->ProcDir != NULL) && (pdriver->ProcDriverDir == NULL)) + pdriver->ProcDriverDir = createProcDir("driver", + pdriver->ProcDir); + if ((pdriver->ProcDir != NULL) && (pdriver->ProcDeviceDir == NULL)) + pdriver->ProcDeviceDir = createProcDir("device", + pdriver->ProcDir); + if ((pdriver->ProcDriverDir != NULL) && + (pdriver->ProcDriverDiagFile == NULL)) { + pdriver->ProcDriverDiagFile = + proc_create_data("diag", 0, + pdriver->ProcDriverDir, + &proc_fops_driver, pdriver); + if (pdriver->ProcDriverDiagFile == NULL) + ERRDRV("failed to register /proc/%s/driver/diag entry", + pdriver->ProcId); + } +} +EXPORT_SYMBOL_GPL(easyproc_InitDriver); + + + +void easyproc_InitDriverEx(struct easyproc_driver_info *pdriver, + char *procId, + void (*show_driver_info)(struct seq_file *), + void (*show_device_info)(struct seq_file *, void *), + void (*write_driver_info)(char *buf, size_t count, + loff_t *ppos), + void (*write_device_info)(char *buf, size_t count, + loff_t *ppos, void *p)) +{ + easyproc_InitDriver(pdriver, procId, + show_driver_info, show_device_info); + pdriver->Write_driver_info = write_driver_info; + pdriver->Write_device_info = write_device_info; +} +EXPORT_SYMBOL_GPL(easyproc_InitDriverEx); + + + +void easyproc_DeInitDriver(struct easyproc_driver_info *pdriver) +{ + if (pdriver->ProcDriverDiagFile != NULL) { + remove_proc_entry("diag", pdriver->ProcDriverDir); + pdriver->ProcDriverDiagFile = NULL; + } + if (pdriver->ProcDriverDir != NULL) { + remove_proc_entry("driver", pdriver->ProcDir); + pdriver->ProcDriverDir = NULL; + } + if (pdriver->ProcDeviceDir != NULL) { + remove_proc_entry("device", pdriver->ProcDir); + pdriver->ProcDeviceDir = NULL; + } + if (pdriver->ProcDir != NULL) { + remove_proc_entry(pdriver->ProcId, NULL); + pdriver->ProcDir = NULL; + } + pdriver->ProcId = NULL; + pdriver->Show_driver_info = NULL; + pdriver->Show_device_info = NULL; + pdriver->Write_driver_info = NULL; + pdriver->Write_device_info = NULL; +} +EXPORT_SYMBOL_GPL(easyproc_DeInitDriver); + + + +void easyproc_InitDevice(struct easyproc_driver_info *pdriver, + struct easyproc_device_info *p, int devno, + void *devdata) +{ + if ((pdriver->ProcDeviceDir != NULL) && (p->procDevicexDir == NULL)) { + char s[29]; + sprintf(s, "%d", devno); + p->procDevicexDir = createProcDir(s, pdriver->ProcDeviceDir); + p->devno = devno; + } + p->devdata = devdata; + p->pdriver = pdriver; + p->devno = devno; + if ((p->procDevicexDir != NULL) && (p->procDevicexDiagFile == NULL)) { + p->procDevicexDiagFile = + proc_create_data("diag", 0, p->procDevicexDir, + &proc_fops_device, p); + if (p->procDevicexDiagFile == NULL) + ERRDEVX(devno, "failed to register /proc/%s/device/%d/diag entry", + pdriver->ProcId, devno + ); + } + memset(&(p->device_property_info[0]), 0, + sizeof(p->device_property_info)); +} +EXPORT_SYMBOL_GPL(easyproc_InitDevice); + + + +void easyproc_CreateDeviceProperty(struct easyproc_device_info *p, + void (*show_property_info)(struct seq_file *, void *), + char *property_name) +{ + size_t i; + struct easyproc_device_property_info *px = NULL; + + if (p->procDevicexDir == NULL) { + ERRDRV("state error"); + return; + } + for (i = 0; i < ARRAY_SIZE(p->device_property_info); i++) { + if (p->device_property_info[i].procEntry == NULL) { + px = &(p->device_property_info[i]); + break; + } + } + if (!px) { + ERRDEVX(p->devno, "too many device properties"); + return; + } + px->devdata = p->devdata; + px->pdriver = p->pdriver; + px->procEntry = proc_create_data(property_name, 0, p->procDevicexDir, + &proc_fops_device_property, px); + if (strlen(property_name)+1 > sizeof(px->property_name)) { + ERRDEVX(p->devno, "device property name %s too long", + property_name); + return; + } + strcpy(px->property_name, property_name); + if (px->procEntry == NULL) { + ERRDEVX(p->devno, "failed to register /proc/%s/device/%d/%s entry", + p->pdriver->ProcId, p->devno, property_name + ); + return; + } + px->show_device_property_info = show_property_info; +} +EXPORT_SYMBOL_GPL(easyproc_CreateDeviceProperty); + + + +void easyproc_DeInitDevice(struct easyproc_driver_info *pdriver, + struct easyproc_device_info *p, int devno) +{ + size_t i; + for (i = 0; i < ARRAY_SIZE(p->device_property_info); i++) { + if (p->device_property_info[i].procEntry != NULL) { + struct easyproc_device_property_info *px = + &(p->device_property_info[i]); + remove_proc_entry(px->property_name, p->procDevicexDir); + px->procEntry = NULL; + } + } + if (p->procDevicexDiagFile != NULL) { + remove_proc_entry("diag", p->procDevicexDir); + p->procDevicexDiagFile = NULL; + } + if (p->procDevicexDir != NULL) { + char s[29]; + sprintf(s, "%d", devno); + remove_proc_entry(s, pdriver->ProcDeviceDir); + p->procDevicexDir = NULL; + } + p->devdata = NULL; + p->pdriver = NULL; +} +EXPORT_SYMBOL_GPL(easyproc_DeInitDevice); + + + +static int seq_show_driver(struct seq_file *seq, void *offset) +{ + struct easyproc_driver_info *p = + (struct easyproc_driver_info *)(seq->private); + if (!p) + return 0; + (*(p->Show_driver_info))(seq); + return 0; +} + + + +static int seq_show_device(struct seq_file *seq, void *offset) +{ + struct easyproc_device_info *p = + (struct easyproc_device_info *)(seq->private); + if ((!p) || (!(p->pdriver))) + return 0; + (*(p->pdriver->Show_device_info))(seq, p->devdata); + return 0; +} + + + +static int seq_show_device_property(struct seq_file *seq, void *offset) +{ + struct easyproc_device_property_info *p = + (struct easyproc_device_property_info *)(seq->private); + if ((!p) || (!(p->show_device_property_info))) + return 0; + (*(p->show_device_property_info))(seq, p->devdata); + return 0; +} + + + +static ssize_t proc_write_driver(struct file *file, const char __user *buffer, + size_t count, loff_t *ppos) +{ + struct seq_file *seq = (struct seq_file *)file->private_data; + struct easyproc_driver_info *p = NULL; + char local_buf[256]; + if (seq == NULL) + return 0; + p = (struct easyproc_driver_info *)(seq->private); + if ((!p) || (!(p->Write_driver_info))) + return 0; + if (count >= sizeof(local_buf)) + return -ENOMEM; + if (copy_from_user(local_buf, buffer, count)) + return -EFAULT; + local_buf[count] = '\0'; /* be friendly */ + (*(p->Write_driver_info))(local_buf, count, ppos); + return count; +} + + + +static ssize_t proc_write_device(struct file *file, const char __user *buffer, + size_t count, loff_t *ppos) +{ + struct seq_file *seq = (struct seq_file *)file->private_data; + struct easyproc_device_info *p = NULL; + char local_buf[256]; + if (seq == NULL) + return 0; + p = (struct easyproc_device_info *)(seq->private); + if ((!p) || (!(p->pdriver)) || (!(p->pdriver->Write_device_info))) + return 0; + if (count >= sizeof(local_buf)) + return -ENOMEM; + if (copy_from_user(local_buf, buffer, count)) + return -EFAULT; + local_buf[count] = '\0'; /* be friendly */ + (*(p->pdriver->Write_device_info))(local_buf, count, ppos, p->devdata); + return count; +} diff --git a/drivers/staging/unisys/visorutil/easyproc.h b/drivers/staging/unisys/visorutil/easyproc.h new file mode 100644 index 00000000000..a1b4df75f3e --- /dev/null +++ b/drivers/staging/unisys/visorutil/easyproc.h @@ -0,0 +1,86 @@ +/* easyproc.h + * + * Copyright © 2010 - 2013 UNISYS CORPORATION + * 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. + */ + +/** @file ********************************************************************* + * + * This describes the interfaces necessary for a simple /proc file + * implementation for a driver. + * + ****************************************************************************** + */ + +#ifndef __EASYPROC_H__ +#define __EASYPROC_H__ + +#include "timskmod.h" + + +struct easyproc_driver_info { + struct proc_dir_entry *ProcDir; + struct proc_dir_entry *ProcDriverDir; + struct proc_dir_entry *ProcDriverDiagFile; + struct proc_dir_entry *ProcDeviceDir; + char *ProcId; + void (*Show_device_info)(struct seq_file *seq, void *p); + void (*Show_driver_info)(struct seq_file *seq); + void (*Write_device_info)(char *buf, size_t count, + loff_t *ppos, void *p); + void (*Write_driver_info)(char *buf, size_t count, loff_t *ppos); +}; + +/* property is a file under /proc/<x>/device/<x>/<property_name> */ +struct easyproc_device_property_info { + char property_name[25]; + struct proc_dir_entry *procEntry; + struct easyproc_driver_info *pdriver; + void *devdata; + void (*show_device_property_info)(struct seq_file *seq, void *p); +}; + +struct easyproc_device_info { + struct proc_dir_entry *procDevicexDir; + struct proc_dir_entry *procDevicexDiagFile; + struct easyproc_driver_info *pdriver; + void *devdata; + int devno; + /* allow for a number of custom properties for each device: */ + struct easyproc_device_property_info device_property_info[10]; +}; + +void easyproc_InitDevice(struct easyproc_driver_info *pdriver, + struct easyproc_device_info *p, int devno, + void *devdata); +void easyproc_DeInitDevice(struct easyproc_driver_info *pdriver, + struct easyproc_device_info *p, int devno); +void easyproc_InitDriver(struct easyproc_driver_info *pdriver, + char *procId, + void (*show_driver_info)(struct seq_file *), + void (*show_device_info)(struct seq_file *, void *)); +void easyproc_InitDriverEx(struct easyproc_driver_info *pdriver, + char *procId, + void (*show_driver_info)(struct seq_file *), + void (*show_device_info)(struct seq_file *, void *), + void (*Write_driver_info)(char *buf, size_t count, + loff_t *ppos), + void (*Write_device_info)(char *buf, size_t count, + loff_t *ppos, void *p)); +void easyproc_DeInitDriver(struct easyproc_driver_info *pdriver); +void easyproc_CreateDeviceProperty(struct easyproc_device_info *p, + void (*show_property_info)(struct seq_file *, void *), + char *property_name); + +#endif diff --git a/drivers/staging/unisys/visorutil/memregion.h b/drivers/staging/unisys/visorutil/memregion.h new file mode 100644 index 00000000000..a1fce7bb1e8 --- /dev/null +++ b/drivers/staging/unisys/visorutil/memregion.h @@ -0,0 +1,43 @@ +/* memregion.h + * + * Copyright © 2010 - 2013 UNISYS CORPORATION + * 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. + */ + +#ifndef __MEMREGION_H__ +#define __MEMREGION_H__ + +#include "timskmod.h" + +/* MEMREGION is an opaque structure to users. + * Fields are declared only in the implementation .c files. + */ +typedef struct MEMREGION_Tag MEMREGION; + +MEMREGION *memregion_create(HOSTADDRESS physaddr, ulong nbytes); +MEMREGION *memregion_create_overlapped(MEMREGION *parent, + ulong offset, ulong nbytes); +int memregion_resize(MEMREGION *memregion, ulong newsize); +int memregion_read(MEMREGION *memregion, + ulong offset, void *dest, ulong nbytes); +int memregion_write(MEMREGION *memregion, + ulong offset, void *src, ulong nbytes); +void memregion_destroy(MEMREGION *memregion); +HOSTADDRESS memregion_get_physaddr(MEMREGION *memregion); +ulong memregion_get_nbytes(MEMREGION *memregion); +void memregion_dump(MEMREGION *memregion, char *s, + ulong off, ulong len, struct seq_file *seq); +void *memregion_get_pointer(MEMREGION *memregion); + +#endif diff --git a/drivers/staging/unisys/visorutil/memregion_direct.c b/drivers/staging/unisys/visorutil/memregion_direct.c new file mode 100644 index 00000000000..fbb460f69bd --- /dev/null +++ b/drivers/staging/unisys/visorutil/memregion_direct.c @@ -0,0 +1,221 @@ +/* memregion_direct.c + * + * Copyright © 2010 - 2013 UNISYS CORPORATION + * 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. + */ + +/* + * This is an implementation of memory regions that can be used to read/write + * channel memory (in main memory of the host system) from code running in + * a virtual partition. + */ +#include "uniklog.h" +#include "timskmod.h" +#include "memregion.h" + +#define MYDRVNAME "memregion" + +struct MEMREGION_Tag { + HOSTADDRESS physaddr; + ulong nbytes; + void *mapped; + BOOL requested; + BOOL overlapped; +}; + +static BOOL mapit(MEMREGION *memregion); +static void unmapit(MEMREGION *memregion); + +MEMREGION * +memregion_create(HOSTADDRESS physaddr, ulong nbytes) +{ + MEMREGION *rc = NULL; + MEMREGION *memregion = kmalloc(sizeof(MEMREGION), + GFP_KERNEL|__GFP_NORETRY); + if (memregion == NULL) { + ERRDRV("memregion_create allocation failed"); + return NULL; + } + memset(memregion, 0, sizeof(MEMREGION)); + memregion->physaddr = physaddr; + memregion->nbytes = nbytes; + memregion->overlapped = FALSE; + if (!mapit(memregion)) + RETPTR(NULL); + RETPTR(memregion); + +Away: + if (rc == NULL) { + if (memregion != NULL) { + memregion_destroy(memregion); + memregion = NULL; + } + } + return rc; +} +EXPORT_SYMBOL_GPL(memregion_create); + +MEMREGION * +memregion_create_overlapped(MEMREGION *parent, ulong offset, ulong nbytes) +{ + MEMREGION *memregion = NULL; + + if (parent == NULL) { + ERRDRV("%s parent is NULL", __func__); + return NULL; + } + if (parent->mapped == NULL) { + ERRDRV("%s parent is not mapped!", __func__); + return NULL; + } + if ((offset >= parent->nbytes) || + ((offset + nbytes) >= parent->nbytes)) { + ERRDRV("%s range (%lu,%lu) out of parent range", + __func__, offset, nbytes); + return NULL; + } + memregion = kmalloc(sizeof(MEMREGION), GFP_KERNEL|__GFP_NORETRY); + if (memregion == NULL) { + ERRDRV("%s allocation failed", __func__); + return NULL; + } + memset(memregion, 0, sizeof(MEMREGION)); + memregion->physaddr = parent->physaddr + offset; + memregion->nbytes = nbytes; + memregion->mapped = ((u8 *) (parent->mapped)) + offset; + memregion->requested = FALSE; + memregion->overlapped = TRUE; + return memregion; +} +EXPORT_SYMBOL_GPL(memregion_create_overlapped); + + +static BOOL +mapit(MEMREGION *memregion) +{ + ulong physaddr = (ulong) (memregion->physaddr); + ulong nbytes = memregion->nbytes; + + memregion->requested = FALSE; + if (!request_mem_region(physaddr, nbytes, MYDRVNAME)) + ERRDRV("cannot reserve channel memory @0x%lx for 0x%lx-- no big deal", physaddr, nbytes); + else + memregion->requested = TRUE; + memregion->mapped = ioremap_cache(physaddr, nbytes); + if (memregion->mapped == NULL) { + ERRDRV("cannot ioremap_cache channel memory @0x%lx for 0x%lx", + physaddr, nbytes); + return FALSE; + } + return TRUE; +} + +static void +unmapit(MEMREGION *memregion) +{ + if (memregion->mapped != NULL) { + iounmap(memregion->mapped); + memregion->mapped = NULL; + } + if (memregion->requested) { + release_mem_region((ulong) (memregion->physaddr), + memregion->nbytes); + memregion->requested = FALSE; + } +} + +HOSTADDRESS +memregion_get_physaddr(MEMREGION *memregion) +{ + return memregion->physaddr; +} +EXPORT_SYMBOL_GPL(memregion_get_physaddr); + +ulong +memregion_get_nbytes(MEMREGION *memregion) +{ + return memregion->nbytes; +} +EXPORT_SYMBOL_GPL(memregion_get_nbytes); + +void * +memregion_get_pointer(MEMREGION *memregion) +{ + return memregion->mapped; +} +EXPORT_SYMBOL_GPL(memregion_get_pointer); + +int +memregion_resize(MEMREGION *memregion, ulong newsize) +{ + if (newsize == memregion->nbytes) + return 0; + if (memregion->overlapped) + /* no error check here - we no longer know the + * parent's range! + */ + memregion->nbytes = newsize; + else { + unmapit(memregion); + memregion->nbytes = newsize; + if (!mapit(memregion)) + return -1; + } + return 0; +} +EXPORT_SYMBOL_GPL(memregion_resize); + + +static int +memregion_readwrite(BOOL is_write, + MEMREGION *memregion, ulong offset, + void *local, ulong nbytes) +{ + if (offset + nbytes > memregion->nbytes) { + ERRDRV("memregion_readwrite offset out of range!!"); + return -EFAULT; + } + if (is_write) + memcpy_toio(memregion->mapped + offset, local, nbytes); + else + memcpy_fromio(local, memregion->mapped + offset, nbytes); + + return 0; +} + +int +memregion_read(MEMREGION *memregion, ulong offset, void *dest, ulong nbytes) +{ + return memregion_readwrite(FALSE, memregion, offset, dest, nbytes); +} +EXPORT_SYMBOL_GPL(memregion_read); + +int +memregion_write(MEMREGION *memregion, ulong offset, void *src, ulong nbytes) +{ + return memregion_readwrite(TRUE, memregion, offset, src, nbytes); +} +EXPORT_SYMBOL_GPL(memregion_write); + +void +memregion_destroy(MEMREGION *memregion) +{ + if (memregion == NULL) + return; + if (!memregion->overlapped) + unmapit(memregion); + kfree(memregion); +} +EXPORT_SYMBOL_GPL(memregion_destroy); + diff --git a/drivers/staging/unisys/visorutil/periodic_work.c b/drivers/staging/unisys/visorutil/periodic_work.c new file mode 100644 index 00000000000..1350b8ef59a --- /dev/null +++ b/drivers/staging/unisys/visorutil/periodic_work.c @@ -0,0 +1,230 @@ +/* periodic_work.c + * + * Copyright © 2010 - 2013 UNISYS CORPORATION + * 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. + */ + +/* + * Helper functions to schedule periodic work in Linux kernel mode. + */ + +#include "uniklog.h" +#include "timskmod.h" +#include "periodic_work.h" + +#define MYDRVNAME "periodic_work" + + + +struct PERIODIC_WORK_Tag { + rwlock_t lock; + struct delayed_work work; + void (*workfunc)(void *); + void *workfuncarg; + BOOL is_scheduled; + BOOL want_to_stop; + ulong jiffy_interval; + struct workqueue_struct *workqueue; + const char *devnam; +}; + + + +static void periodic_work_func(struct work_struct *work) +{ + PERIODIC_WORK *periodic_work = + container_of(work, struct PERIODIC_WORK_Tag, work.work); + (*periodic_work->workfunc)(periodic_work->workfuncarg); +} + + + +PERIODIC_WORK *periodic_work_create(ulong jiffy_interval, + struct workqueue_struct *workqueue, + void (*workfunc)(void *), + void *workfuncarg, + const char *devnam) +{ + PERIODIC_WORK *periodic_work = kmalloc(sizeof(PERIODIC_WORK), + GFP_KERNEL|__GFP_NORETRY); + if (periodic_work == NULL) { + ERRDRV("periodic_work allocation failed "); + return NULL; + } + memset(periodic_work, '\0', sizeof(PERIODIC_WORK)); + rwlock_init(&periodic_work->lock); + periodic_work->jiffy_interval = jiffy_interval; + periodic_work->workqueue = workqueue; + periodic_work->workfunc = workfunc; + periodic_work->workfuncarg = workfuncarg; + periodic_work->devnam = devnam; + return periodic_work; +} +EXPORT_SYMBOL_GPL(periodic_work_create); + + + +void periodic_work_destroy(PERIODIC_WORK *periodic_work) +{ + if (periodic_work == NULL) + return; + kfree(periodic_work); +} +EXPORT_SYMBOL_GPL(periodic_work_destroy); + + + +/** Call this from your periodic work worker function to schedule the next + * call. + * If this function returns FALSE, there was a failure and the + * periodic work is no longer scheduled + */ +BOOL periodic_work_nextperiod(PERIODIC_WORK *periodic_work) +{ + BOOL rc = FALSE; + write_lock(&periodic_work->lock); + if (periodic_work->want_to_stop) { + periodic_work->is_scheduled = FALSE; + periodic_work->want_to_stop = FALSE; + RETBOOL(TRUE); /* yes, TRUE; see periodic_work_stop() */ + } else if (queue_delayed_work(periodic_work->workqueue, + &periodic_work->work, + periodic_work->jiffy_interval) < 0) { + ERRDEV(periodic_work->devnam, "queue_delayed_work failed!"); + periodic_work->is_scheduled = FALSE; + RETBOOL(FALSE); + } + RETBOOL(TRUE); +Away: + write_unlock(&periodic_work->lock); + return rc; +} +EXPORT_SYMBOL_GPL(periodic_work_nextperiod); + + + +/** This function returns TRUE iff new periodic work was actually started. + * If this function returns FALSE, then no work was started + * (either because it was already started, or because of a failure). + */ +BOOL periodic_work_start(PERIODIC_WORK *periodic_work) +{ + BOOL rc = FALSE; + + write_lock(&periodic_work->lock); + if (periodic_work->is_scheduled) + RETBOOL(FALSE); + if (periodic_work->want_to_stop) { + ERRDEV(periodic_work->devnam, + "dev_start_periodic_work failed!"); + RETBOOL(FALSE); + } + INIT_DELAYED_WORK(&periodic_work->work, &periodic_work_func); + if (queue_delayed_work(periodic_work->workqueue, + &periodic_work->work, + periodic_work->jiffy_interval) < 0) { + ERRDEV(periodic_work->devnam, + "%s queue_delayed_work failed!", __func__); + RETBOOL(FALSE); + } + periodic_work->is_scheduled = TRUE; + RETBOOL(TRUE); +Away: + write_unlock(&periodic_work->lock); + return rc; + +} +EXPORT_SYMBOL_GPL(periodic_work_start); + + + + +/** This function returns TRUE iff your call actually stopped the periodic + * work. + * + * -- PAY ATTENTION... this is important -- + * + * NO NO #1 + * + * Do NOT call this function from some function that is running on the + * same workqueue as the work you are trying to stop might be running + * on! If you violate this rule, periodic_work_stop() MIGHT work, but it + * also MIGHT get hung up in an infinite loop saying + * "waiting for delayed work...". This will happen if the delayed work + * you are trying to cancel has been put in the workqueue list, but can't + * run yet because we are running that same workqueue thread right now. + * + * Bottom line: If you need to call periodic_work_stop() from a workitem, + * be sure the workitem is on a DIFFERENT workqueue than the workitem that + * you are trying to cancel. + * + * If I could figure out some way to check for this "no no" condition in + * the code, I would. It would have saved me the trouble of writing this + * long comment. And also, don't think this is some "theoretical" race + * condition. It is REAL, as I have spent the day chasing it. + * + * NO NO #2 + * + * Take close note of the locks that you own when you call this function. + * You must NOT own any locks that are needed by the periodic work + * function that is currently installed. If you DO, a deadlock may result, + * because stopping the periodic work often involves waiting for the last + * iteration of the periodic work function to complete. Again, if you hit + * this deadlock, you will get hung up in an infinite loop saying + * "waiting for delayed work...". + */ +BOOL periodic_work_stop(PERIODIC_WORK *periodic_work) +{ + BOOL stopped_something = FALSE; + + write_lock(&periodic_work->lock); + stopped_something = periodic_work->is_scheduled && + (!periodic_work->want_to_stop); + while (periodic_work->is_scheduled) { + periodic_work->want_to_stop = TRUE; + if (cancel_delayed_work(&periodic_work->work)) { + /* We get here if the delayed work was pending as + * delayed work, but was NOT run. + */ + ASSERT(periodic_work->is_scheduled); + periodic_work->is_scheduled = FALSE; + } else { + /* If we get here, either the delayed work: + * - was run, OR, + * - is running RIGHT NOW on another processor, OR, + * - wasn't even scheduled (there is a miniscule + * timing window where this could be the case) + * flush_workqueue() would make sure it is finished + * executing, but that still isn't very useful, which + * explains the loop... + */ + } + if (periodic_work->is_scheduled) { + write_unlock(&periodic_work->lock); + WARNDEV(periodic_work->devnam, + "waiting for delayed work..."); + /* We rely on the delayed work function running here, + * and eventually calling periodic_work_nextperiod(), + * which will see that want_to_stop is set, and + * subsequently clear is_scheduled. + */ + SLEEPJIFFIES(10); + write_lock(&periodic_work->lock); + } else + periodic_work->want_to_stop = FALSE; + } + write_unlock(&periodic_work->lock); + return stopped_something; +} +EXPORT_SYMBOL_GPL(periodic_work_stop); diff --git a/drivers/staging/unisys/visorutil/procobjecttree.c b/drivers/staging/unisys/visorutil/procobjecttree.c new file mode 100644 index 00000000000..f59b37e27d1 --- /dev/null +++ b/drivers/staging/unisys/visorutil/procobjecttree.c @@ -0,0 +1,334 @@ +/* procobjecttree.c + * + * Copyright © 2010 - 2013 UNISYS CORPORATION + * 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. + */ + +#include "procobjecttree.h" + +#define MYDRVNAME "procobjecttree" + + + +/** This is context info that we stash in each /proc file entry, which we + * need in order to call the callback function that supplies the /proc read + * info for that file. + */ +typedef struct { + void (*show_property)(struct seq_file *, void *, int); + MYPROCOBJECT *procObject; + int propertyIndex; + +} PROCDIRENTRYCONTEXT; + +/** This describes the attributes of a tree rooted at + * <procDirRoot>/<name[0]>/<name[1]>/... + * Properties for each object of this type will be located under + * <procDirRoot>/<name[0]>/<name[1]>/.../<objectName>/<propertyName>. + */ +struct MYPROCTYPE_Tag { + const char **name; /**< node names for this type, ending with NULL */ + int nNames; /**< num of node names in <name> */ + + /** root dir for this type tree in /proc */ + struct proc_dir_entry *procDirRoot; + + struct proc_dir_entry **procDirs; /**< for each node in <name> */ + + /** bottom dir where objects will be rooted; i.e., this is + * <procDirRoot>/<name[0]>/<name[1]>/.../, which is the same as the + * last entry in the <procDirs> array. */ + struct proc_dir_entry *procDir; + + /** name for each property that objects of this type can have */ + const char **propertyNames; + + int nProperties; /**< num of names in <propertyNames> */ + + /** Call this, passing MYPROCOBJECT.context and the property index + * whenever someone reads the proc entry */ + void (*show_property)(struct seq_file *, void *, int); +}; + + + +struct MYPROCOBJECT_Tag { + MYPROCTYPE *type; + + /** This is the name of the dir node in /proc under which the + * properties of this object will appear as files. */ + char *name; + + int namesize; /**< number of bytes allocated for name */ + void *context; /**< passed to MYPROCTYPE.show_property */ + + /** <type.procDirRoot>/<type.name[0]>/<type.name[1]>/.../<name> */ + struct proc_dir_entry *procDir; + + /** a proc dir entry for each of the properties of the object; + * properties are identified in MYPROCTYPE.propertyNames, so each of + * the <procDirProperties> describes a single file like + * <type.procDirRoot>/<type.name[0]>/<type.name[1]>/... + * /<name>/<propertyName> + */ + struct proc_dir_entry **procDirProperties; + + /** this is a holding area for the context information that is needed + * to run the /proc callback function */ + PROCDIRENTRYCONTEXT *procDirPropertyContexts; +}; + + + +static struct proc_dir_entry * +createProcDir(const char *name, struct proc_dir_entry *parent) +{ + struct proc_dir_entry *p = proc_mkdir_mode(name, S_IFDIR, parent); + if (p == NULL) + ERRDRV("failed to create /proc directory %s", name); + return p; +} + +static struct proc_dir_entry * +createProcFile(const char *name, struct proc_dir_entry *parent, + const struct file_operations *fops, void *data) +{ + struct proc_dir_entry *p = proc_create_data(name, 0, parent, + fops, data); + if (p == NULL) + ERRDRV("failed to create /proc file %s", name); + return p; +} + +static int seq_show(struct seq_file *seq, void *offset); +static int proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, seq_show, PDE_DATA(inode)); +} + +static const struct file_operations proc_fops = { + .open = proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + + + +MYPROCTYPE *proc_CreateType(struct proc_dir_entry *procDirRoot, + const char **name, + const char **propertyNames, + void (*show_property)(struct seq_file *, + void *, int)) +{ + int i = 0; + MYPROCTYPE *rc = NULL, *type = NULL; + struct proc_dir_entry *parent = NULL; + + if (procDirRoot == NULL) + FAIL("procDirRoot cannot be NULL!", 0); + if (name == NULL || name[0] == NULL) + FAIL("name must contain at least 1 node name!", 0); + type = kmalloc(sizeof(MYPROCTYPE), GFP_KERNEL|__GFP_NORETRY); + if (type == NULL) + FAIL("out of memory", 0); + memset(type, 0, sizeof(MYPROCTYPE)); + type->name = name; + type->propertyNames = propertyNames; + type->nProperties = 0; + type->nNames = 0; + type->show_property = show_property; + type->procDirRoot = procDirRoot; + if (type->propertyNames != 0) + while (type->propertyNames[type->nProperties] != NULL) + type->nProperties++; + while (type->name[type->nNames] != NULL) + type->nNames++; + type->procDirs = kmalloc((type->nNames+1)* + sizeof(struct proc_dir_entry *), + GFP_KERNEL|__GFP_NORETRY); + if (type->procDirs == NULL) + FAIL("out of memory", 0); + memset(type->procDirs, 0, (type->nNames + 1) * + sizeof(struct proc_dir_entry *)); + parent = procDirRoot; + for (i = 0; i < type->nNames; i++) { + type->procDirs[i] = createProcDir(type->name[i], parent); + if (type->procDirs[i] == NULL) + RETPTR(NULL); + parent = type->procDirs[i]; + } + type->procDir = type->procDirs[type->nNames-1]; + RETPTR(type); +Away: + if (rc == NULL) { + if (type != NULL) { + proc_DestroyType(type); + type = NULL; + } + } + return rc; +} +EXPORT_SYMBOL_GPL(proc_CreateType); + + + +void proc_DestroyType(MYPROCTYPE *type) +{ + if (type == NULL) + return; + if (type->procDirs != NULL) { + int i = type->nNames-1; + while (i >= 0) { + if (type->procDirs[i] != NULL) { + struct proc_dir_entry *parent = NULL; + if (i == 0) + parent = type->procDirRoot; + else + parent = type->procDirs[i-1]; + remove_proc_entry(type->name[i], parent); + } + i--; + } + kfree(type->procDirs); + type->procDirs = NULL; + } + kfree(type); +} +EXPORT_SYMBOL_GPL(proc_DestroyType); + + + +MYPROCOBJECT *proc_CreateObject(MYPROCTYPE *type, + const char *name, void *context) +{ + MYPROCOBJECT *obj = NULL, *rc = NULL; + int i = 0; + + if (type == NULL) + FAIL("type cannot be NULL", 0); + obj = kmalloc(sizeof(MYPROCOBJECT), GFP_KERNEL | __GFP_NORETRY); + if (obj == NULL) + FAIL("out of memory", 0); + memset(obj, 0, sizeof(MYPROCOBJECT)); + obj->type = type; + obj->context = context; + if (name == NULL) { + obj->name = NULL; + obj->procDir = type->procDir; + } else { + obj->namesize = strlen(name)+1; + obj->name = kmalloc(obj->namesize, GFP_KERNEL | __GFP_NORETRY); + if (obj->name == NULL) { + obj->namesize = 0; + FAIL("out of memory", 0); + } + strcpy(obj->name, name); + obj->procDir = createProcDir(obj->name, type->procDir); + if (obj->procDir == NULL) + RETPTR(NULL); + } + obj->procDirPropertyContexts = + kmalloc((type->nProperties+1)*sizeof(PROCDIRENTRYCONTEXT), + GFP_KERNEL|__GFP_NORETRY); + if (obj->procDirPropertyContexts == NULL) + FAIL("out of memory", 0); + memset(obj->procDirPropertyContexts, 0, + (type->nProperties+1)*sizeof(PROCDIRENTRYCONTEXT)); + obj->procDirProperties = + kmalloc((type->nProperties+1) * sizeof(struct proc_dir_entry *), + GFP_KERNEL|__GFP_NORETRY); + if (obj->procDirProperties == NULL) + FAIL("out of memory", 0); + memset(obj->procDirProperties, 0, + (type->nProperties+1) * sizeof(struct proc_dir_entry *)); + for (i = 0; i < type->nProperties; i++) { + obj->procDirPropertyContexts[i].procObject = obj; + obj->procDirPropertyContexts[i].propertyIndex = i; + obj->procDirPropertyContexts[i].show_property = + type->show_property; + if (type->propertyNames[i][0] != '\0') { + /* only create properties that have names */ + obj->procDirProperties[i] = + createProcFile(type->propertyNames[i], + obj->procDir, &proc_fops, + &obj->procDirPropertyContexts[i]); + if (obj->procDirProperties[i] == NULL) + RETPTR(NULL); + } + } + RETPTR(obj); +Away: + if (rc == NULL) { + if (obj != NULL) { + proc_DestroyObject(obj); + obj = NULL; + } + } + return rc; +} +EXPORT_SYMBOL_GPL(proc_CreateObject); + + + +void proc_DestroyObject(MYPROCOBJECT *obj) +{ + MYPROCTYPE *type = NULL; + if (obj == NULL) + return; + type = obj->type; + if (type == NULL) + return; + if (obj->procDirProperties != NULL) { + int i = 0; + for (i = 0; i < type->nProperties; i++) { + if (obj->procDirProperties[i] != NULL) { + remove_proc_entry(type->propertyNames[i], + obj->procDir); + obj->procDirProperties[i] = NULL; + } + } + kfree(obj->procDirProperties); + obj->procDirProperties = NULL; + } + if (obj->procDirPropertyContexts != NULL) { + kfree(obj->procDirPropertyContexts); + obj->procDirPropertyContexts = NULL; + } + if (obj->procDir != NULL) { + if (obj->name != NULL) + remove_proc_entry(obj->name, type->procDir); + obj->procDir = NULL; + } + if (obj->name != NULL) { + kfree(obj->name); + obj->name = NULL; + } + kfree(obj); +} +EXPORT_SYMBOL_GPL(proc_DestroyObject); + + + +static int seq_show(struct seq_file *seq, void *offset) +{ + PROCDIRENTRYCONTEXT *ctx = (PROCDIRENTRYCONTEXT *)(seq->private); + if (ctx == NULL) { + ERRDRV("I don't have a freakin' clue..."); + return 0; + } + (*ctx->show_property)(seq, ctx->procObject->context, + ctx->propertyIndex); + return 0; +} diff --git a/drivers/staging/unisys/visorutil/visorkmodutils.c b/drivers/staging/unisys/visorutil/visorkmodutils.c new file mode 100644 index 00000000000..13e73266ea5 --- /dev/null +++ b/drivers/staging/unisys/visorutil/visorkmodutils.c @@ -0,0 +1,721 @@ +/* timskmodutils.c + * + * Copyright © 2010 - 2013 UNISYS CORPORATION + * 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. + */ + +#include "uniklog.h" +#include "timskmod.h" + +#define MYDRVNAME "timskmodutils" + +BOOL Debug_Malloc_Enabled = FALSE; + + + +void myprintk(const char *myDrvName, const char *devname, + const char *template, ...) +{ + va_list ap; + char temp[999]; + char *ptemp = temp; + char pfx[20]; + char msg[sizeof(pfx) + strlen(myDrvName) + 50]; + + if (myDrvName == NULL) + return; + temp[sizeof(temp)-1] = '\0'; + pfx[0] = '\0'; + msg[0] = '\0'; + va_start(ap, template); + vsprintf(temp, template, ap); + va_end(ap); + if (temp[0] == '<') { + size_t i = 0; + for (i = 0; i < sizeof(pfx) - 1; i++) { + pfx[i] = temp[i]; + if (pfx[i] == '>' || pfx[i] == '\0') { + if (pfx[i] == '>') + ptemp = temp+i+1; + i++; + break; + } + } + pfx[i] = '\0'; + } + if (devname == NULL) + sprintf(msg, "%s%s: ", pfx, myDrvName); + else + sprintf(msg, "%s%s[%s]: ", pfx, myDrvName, devname); + printk(KERN_INFO "%s", msg); + + /* The <prefix> applies up until the \n, so we should not include + * it in these printks. That's why we use <ptemp> to point to the + * first char after the ">" in the prefix. + */ + printk(KERN_INFO "%s", ptemp); + printk("\n"); + +} + + + +void myprintkx(const char *myDrvName, int devno, const char *template, ...) +{ + va_list ap; + char temp[999]; + char *ptemp = temp; + char pfx[20]; + char msg[sizeof(pfx) + strlen(myDrvName) + 50]; + + if (myDrvName == NULL) + return; + temp[sizeof(temp)-1] = '\0'; + pfx[0] = '\0'; + msg[0] = '\0'; + va_start(ap, template); + vsprintf(temp, template, ap); + va_end(ap); + if (temp[0] == '<') { + size_t i = 0; + for (i = 0; i < sizeof(pfx) - 1; i++) { + pfx[i] = temp[i]; + if (pfx[i] == '>' || pfx[i] == '\0') { + if (pfx[i] == '>') + ptemp = temp+i+1; + i++; + break; + } + } + pfx[i] = '\0'; + } + if (devno < 0) + sprintf(msg, "%s%s: ", pfx, myDrvName); + else + sprintf(msg, "%s%s[%d]: ", pfx, myDrvName, devno); + printk(KERN_INFO "%s", msg); + + /* The <prefix> applies up until the \n, so we should not include + * it in these printks. That's why we use <ptemp> to point to the + * first char after the ">" in the prefix. + */ + printk(KERN_INFO "%s", ptemp); + printk("\n"); +} + + + +int hexDumpWordsToBuffer(char *dest, + int destSize, + char *prefix, + uint32_t *src, + int srcWords, + int wordsToDumpPerLine) +{ + int i = 0; + int pos = 0; + char hex[(wordsToDumpPerLine * 9) + 1]; + char *line = NULL; + int linesize = 1000; + int linelen = 0; + int currentlen = 0; + char emptystring[] = ""; + char *pfx = prefix; + int baseaddr = 0; + int rc = 0; + uint8_t b1, b2, b3, b4; + + line = vmalloc(linesize); + if (line == NULL) + RETINT(currentlen); + + if (pfx == NULL || (strlen(pfx) > 50)) + pfx = emptystring; + memset(hex, ' ', wordsToDumpPerLine * 9); + hex[wordsToDumpPerLine * 9] = '\0'; + if (destSize > 0) + dest[0] = '\0'; + + for (i = 0; i < srcWords; i++) { + pos = i % wordsToDumpPerLine; + if ((pos == 0) && (i > 0)) { + hex[wordsToDumpPerLine * 9] = '\0'; + linelen = sprintf(line, "%s%-6.6x %s\n", pfx, + baseaddr, hex); + if ((currentlen) + (linelen) >= destSize) + RETINT(currentlen); + strcat(dest, line); + currentlen += linelen; + memset(hex, ' ', wordsToDumpPerLine * 9); + baseaddr = i * 4; + } + b1 = (uint8_t)((src[i] >> 24) & 0xff); + b2 = (uint8_t)((src[i] >> 16) & 0xff); + b3 = (uint8_t)((src[i] >> 8) & 0xff); + b4 = (uint8_t)((src[i]) & 0xff); + sprintf(hex + (pos * 9), "%-2.2x%-2.2x%-2.2x%-2.2x ", + b1, b2, b3, b4); + *(hex + (pos * 9) + 9) = ' '; /* get rid of null */ + } + pos = i%wordsToDumpPerLine; + if (i > 0) { + hex[wordsToDumpPerLine * 9] = '\0'; + linelen = sprintf(line, "%s%-6.6x %s\n", pfx, baseaddr, hex); + if ((currentlen) + (linelen) >= destSize) + RETINT(currentlen); + strcat(dest, line); + currentlen += linelen; + } + RETINT(currentlen); + +Away: + if (line) + vfree(line); + return rc; +} +EXPORT_SYMBOL_GPL(hexDumpWordsToBuffer); + + + +int myPrintkHexDump(char *myDrvName, + char *devname, + char *prefix, + char *src, + int srcLen, + int bytesToDumpPerLine) +{ + int i = 0; + int pos = 0; + char printable[bytesToDumpPerLine + 1]; + char hex[(bytesToDumpPerLine*3) + 1]; + char *line = NULL; + int linesize = 1000; + int linelen = 0; + int currentlen = 0; + char emptystring[] = ""; + char *pfx = prefix; + int baseaddr = 0; + int rc = 0; + int linecount = 0; + + line = vmalloc(linesize); + if (line == NULL) + RETINT(currentlen); + + if (pfx == NULL || (strlen(pfx) > 50)) + pfx = emptystring; + memset(hex, ' ', bytesToDumpPerLine * 3); + hex[bytesToDumpPerLine * 3] = '\0'; + memset(printable, ' ', bytesToDumpPerLine); + printable[bytesToDumpPerLine] = '\0'; + + for (i = 0; i < srcLen; i++) { + pos = i % bytesToDumpPerLine; + if ((pos == 0) && (i > 0)) { + hex[bytesToDumpPerLine*3] = '\0'; + linelen = sprintf(line, "%s%-6.6x %s %s", + pfx, baseaddr, hex, printable); + myprintk(myDrvName, devname, KERN_INFO "%s", line); + currentlen += linelen; + linecount++; + if ((linecount % 50) == 0) + SLEEPJIFFIES(10); + memset(hex, ' ', bytesToDumpPerLine*3); + memset(printable, ' ', bytesToDumpPerLine); + baseaddr = i; + } + sprintf(hex + (pos * 3), "%-2.2x ", (uint8_t)(src[i])); + *(hex + (pos * 3) + 3) = ' '; /* get rid of null */ + if (((uint8_t)(src[i]) >= ' ') && (uint8_t)(src[i]) < 127) + printable[pos] = src[i]; + else + printable[pos] = '.'; + } + pos = i%bytesToDumpPerLine; + if (i > 0) { + hex[bytesToDumpPerLine*3] = '\0'; + linelen = sprintf(line, "%s%-6.6x %s %s", + pfx, baseaddr, hex, printable); + myprintk(myDrvName, devname, KERN_INFO "%s", line); + currentlen += linelen; + } + RETINT(currentlen); + +Away: + if (line) + vfree(line); + return rc; +} + + + +/** Given as input a number of seconds in #seconds, creates text describing + the time within #s. Also breaks down the number of seconds into component + days, hours, minutes, and seconds, and stores to *#days, *#hours, + *#minutes, and *#secondsx. + * @param seconds input number of seconds + * @param days points to a long value where the days component for the + * days+hours+minutes+seconds representation of #seconds will + * be stored + * @param hours points to a long value where the hours component for the + * days+hours+minutes+seconds representation of #seconds will + * be stored + * @param minutes points to a long value where the minutes component for the + * days+hours+minutes+seconds representation of #seconds will + * be stored + * @param secondsx points to a long value where the seconds component for the + * days+hours+minutes+seconds representation of #seconds will + * be stored + * @param s points to a character buffer where a text representation of + * the #seconds value will be stored. This buffer MUST be + * large enough to hold the resulting string; to be safe it + * should be at least 100 bytes long. + */ +void expandSeconds(time_t seconds, long *days, long *hours, long *minutes, + long *secondsx, char *s) +{ + BOOL started = FALSE; + char buf[99]; + + *days = seconds / (60*60*24); + seconds -= ((*days)*(60*60*24)); + *hours = seconds / (60*60); + seconds -= ((*hours)*(60*60)); + *minutes = seconds/60; + seconds -= ((*minutes)*60); + *secondsx = (long)seconds; + if (s == NULL) + RETVOID; + s[0] = '\0'; + if (*days > 0) { + sprintf(buf, "%lu day", *days); + strcat(s, buf); + if (*days != 1) + strcat(s, "s"); + started = TRUE; + } + if ((*hours > 0) || started) { + if (started) + strcat(s, ", "); + sprintf(buf, "%lu hour", *hours); + strcat(s, buf); + if (*hours != 1) + strcat(s, "s"); + started = TRUE; + } + if ((*minutes > 0) || started) { + if (started) + strcat(s, ", "); + sprintf(buf, "%lu minute", *minutes); + strcat(s, buf); + if (*minutes != 1) + strcat(s, "s"); + started = TRUE; + } + if (started) + strcat(s, ", "); + sprintf(buf, "%lu second", *secondsx); + strcat(s, buf); + if (*secondsx != 1) + strcat(s, "s"); + +Away: + return; +} + + + +/** Initialize a #MESSAGEQ for use (initially it will be empty, of course). + * @param q the #MESSAGEQ to initialize + * @ingroup messageq + */ +void initMessageQ(MESSAGEQ *q) +{ + q->qHead = NULL; + q->qTail = NULL; + sema_init(&q->nQEntries, 0); /* will block initially */ + spin_lock_init(&q->queueLock); +} + + + +/** Initialize #p with your data structure in #data, + * so you can later place #p onto a #MESSAGEQ. + * @param p the queue entry that will house your data structure + * @param data a pointer to your data structure that you want + * to queue + * @ingroup messageq + */ +void initMessageQEntry(MESSAGEQENTRY *p, void *data) +{ + p->data = data; + p->qNext = NULL; + p->qPrev = NULL; +} + + + +MESSAGEQENTRY *dequeueMessageGuts(MESSAGEQ *q, BOOL canBlock) +{ + MESSAGEQENTRY *pEntry = NULL; + MESSAGEQENTRY *rc = NULL; + BOOL locked = FALSE; + ulong flags = 0; + int res = 0; + + if (canBlock) { + /* wait for non-empty q */ + res = down_interruptible(&q->nQEntries); + if (signal_pending(current)) { + DEBUGDRV("got signal in dequeueMessage"); + RETPTR(NULL); + } + } else if (down_trylock(&q->nQEntries)) + RETPTR(NULL); + spin_lock_irqsave(&q->queueLock, flags); + locked = TRUE; +#ifdef PARANOID + if (q->qHead == NULL) { + HUHDRV("unexpected empty queue in getQueue"); + RETPTR(NULL); + } +#endif + pEntry = q->qHead; + if (pEntry == q->qTail) { + /* only 1 item in the queue */ + q->qHead = NULL; + q->qTail = NULL; + } else { + q->qHead = pEntry->qNext; + q->qHead->qPrev = NULL; + } + RETPTR(pEntry); +Away: + if (locked) { + spin_unlock_irqrestore(&q->queueLock, flags); + locked = FALSE; + } + return rc; +} + + + +/** Remove the next message at the head of the FIFO queue, and return it. + * Wait for the queue to become non-empty if it is empty when this + * function is called. + * @param q the queue where the message is to be obtained from + * @return the queue entry obtained from the head of the + * FIFO queue, or NULL iff a signal was received + * while waiting for the queue to become non-empty + * @ingroup messageq + */ +MESSAGEQENTRY *dequeueMessage(MESSAGEQ *q) +{ + return dequeueMessageGuts(q, TRUE); +} + + + +/** Remove the next message at the head of the FIFO queue, and return it. + * This function will never block (it returns NULL instead). + * @param q the queue where the message is to be obtained from + * @return the queue entry obtained from the head of the + * FIFO queue, or NULL iff the queue is empty. + * @ingroup messageq + */ +MESSAGEQENTRY *dequeueMessageNoBlock(MESSAGEQ *q) +{ + return dequeueMessageGuts(q, FALSE); +} + + + +/** Add an entry to a FIFO queue. + * @param q the queue where the entry is to be added + * @param pEntry the entry you want to add to the queue + * @ingroup messageq + */ +void enqueueMessage(MESSAGEQ *q, MESSAGEQENTRY *pEntry) +{ + BOOL locked = FALSE; + ulong flags = 0; + + spin_lock_irqsave(&q->queueLock, flags); + locked = TRUE; + if (q->qHead == NULL) { +#ifdef PARANOID + if (q->qTail != NULL) { + HUHDRV("qHead/qTail not consistent"); + RETVOID; + } +#endif + q->qHead = pEntry; + q->qTail = pEntry; + pEntry->qNext = NULL; + pEntry->qPrev = NULL; + } else { +#ifdef PARANOID + if (q->qTail == NULL) { + HUHDRV("qTail should not be NULL here"); + RETVOID; + } +#endif + q->qTail->qNext = pEntry; + pEntry->qPrev = q->qTail; + pEntry->qNext = NULL; + q->qTail = pEntry; + } + spin_unlock_irqrestore(&q->queueLock, flags); + locked = FALSE; + up(&q->nQEntries); + RETVOID; +Away: + if (locked) { + spin_unlock_irqrestore(&q->queueLock, flags); + locked = FALSE; + } + return; +} + + + +/** Return the number of entries in the queue. + * @param q the queue to be examined + * @return the number of entries on #q + * @ingroup messageq + */ +size_t getQueueCount(MESSAGEQ *q) +{ + return (size_t)__sync_fetch_and_add(&(q->nQEntries.count), 0); +} + + + +/** Return the number of processes waiting in a standard wait queue. + * @param q the pointer to the wait queue to be + * examined + * @return the number of waiters + * @ingroup internal + */ +int waitQueueLen(wait_queue_head_t *q) +{ + struct list_head *x; + int count = 0; + list_for_each(x, &(q->task_list)) + count++; + return count; +} + + + +/** Display information about the processes on a standard wait queue. + * @param q the pointer to the wait queue to be + * examined + * @ingroup internal + */ +void debugWaitQ(wait_queue_head_t *q) +{ + DEBUGDRV("task_list.next= %-8.8x", + ((struct __wait_queue_head *)(q))->task_list.next); + DEBUGDRV("task_list.prev= %-8.8x", + ((struct __wait_queue_head *)(q))->task_list.prev); +} + + + +/** Print the hexadecimal contents of a data buffer to a supplied print buffer. + * @param dest the print buffer where text characters will + * be written + * @param destSize the maximum number of bytes that can be written + * to #dest + * @param src the buffer that contains the data that is to be + * hex-dumped + * @param srcLen the number of bytes at #src to be hex-dumped + * @param bytesToDumpPerLine output will be formatted such that at most + * this many of the input data bytes will be + * represented on each line of output + * @return the number of text characters written to #dest + * (not including the trailing '\0' byte) + * @ingroup internal + */ +int hexDumpToBuffer(char *dest, int destSize, char *prefix, char *src, + int srcLen, int bytesToDumpPerLine) +{ + int i = 0; + int pos = 0; + char printable[bytesToDumpPerLine + 1]; + char hex[(bytesToDumpPerLine * 3) + 1]; + char *line = NULL; + int linesize = 1000; + int linelen = 0; + int currentlen = 0; + char emptystring[] = ""; + char *pfx = prefix; + int baseaddr = 0; + int rc = 0; + + line = vmalloc(linesize); + if (line == NULL) + RETINT(currentlen); + + if (pfx == NULL || (strlen(pfx) > 50)) + pfx = emptystring; + memset(hex, ' ', bytesToDumpPerLine * 3); + hex[bytesToDumpPerLine * 3] = '\0'; + memset(printable, ' ', bytesToDumpPerLine); + printable[bytesToDumpPerLine] = '\0'; + if (destSize > 0) + dest[0] = '\0'; + + for (i = 0; i < srcLen; i++) { + pos = i % bytesToDumpPerLine; + if ((pos == 0) && (i > 0)) { + hex[bytesToDumpPerLine*3] = '\0'; + linelen = sprintf(line, "%s%-6.6x %s %s\n", pfx, + baseaddr, hex, printable); + if ((currentlen) + (linelen) >= destSize) + RETINT(currentlen); + strcat(dest, line); + currentlen += linelen; + memset(hex, ' ', bytesToDumpPerLine * 3); + memset(printable, ' ', bytesToDumpPerLine); + baseaddr = i; + } + sprintf(hex + (pos * 3), "%-2.2x ", (uint8_t)(src[i])); + *(hex + (pos * 3) + 3) = ' '; /* get rid of null */ + if (((uint8_t)(src[i]) >= ' ') && (uint8_t)(src[i]) < 127) + printable[pos] = src[i]; + else + printable[pos] = '.'; + } + pos = i%bytesToDumpPerLine; + if (i > 0) { + hex[bytesToDumpPerLine * 3] = '\0'; + linelen = sprintf(line, "%s%-6.6x %s %s\n", + pfx, baseaddr, hex, printable); + if ((currentlen) + (linelen) >= destSize) + RETINT(currentlen); + strcat(dest, line); + currentlen += linelen; + } + RETINT(currentlen); + +Away: + if (line) + vfree(line); + return rc; +} +EXPORT_SYMBOL_GPL(hexDumpToBuffer); + + +/** Callers to interfaces that set __GFP_NORETRY flag below + * must check for a NULL (error) result as we are telling the + * kernel interface that it is okay to fail. + */ + +void *kmalloc_kernel(size_t siz) +{ + return kmalloc(siz, GFP_KERNEL | __GFP_NORETRY); +} + +void *kmalloc_kernel_dma(size_t siz) +{ + return kmalloc(siz, GFP_KERNEL | __GFP_NORETRY|GFP_DMA); +} + +void kfree_kernel(const void *p, size_t siz) +{ + kfree(p); +} + +void *vmalloc_kernel(size_t siz) +{ + return vmalloc((unsigned long)(siz)); +} + +void vfree_kernel(const void *p, size_t siz) +{ + vfree((void *)(p)); +} + +void *pgalloc_kernel(size_t siz) +{ + return (void *)__get_free_pages(GFP_KERNEL|__GFP_NORETRY, + get_order(siz)); +} + +void pgfree_kernel(const void *p, size_t siz) +{ + free_pages((ulong)(p), get_order(siz)); +} + + + +/* Use these handy-dandy seq_file_xxx functions if you want to call some + * functions that write stuff into a seq_file, but you actually just want + * to dump that output into a buffer. Use them as follows: + * - call seq_file_new_buffer to create the seq_file (you supply the buf) + * - call whatever functions you want that take a seq_file as an argument + * (the buf you supplied will get the output data) + * - call seq_file_done_buffer to dispose of your seq_file + */ +struct seq_file *seq_file_new_buffer(void *buf, size_t buf_size) +{ + struct seq_file *rc = NULL; + struct seq_file *m = kmalloc_kernel(sizeof(struct seq_file)); + + if (m == NULL) + RETPTR(NULL); + memset(m, 0, sizeof(struct seq_file)); + m->buf = buf; + m->size = buf_size; + RETPTR(m); +Away: + if (rc == NULL) { + seq_file_done_buffer(m); + m = NULL; + } + return rc; +} +EXPORT_SYMBOL_GPL(seq_file_new_buffer); + + + +void seq_file_done_buffer(struct seq_file *m) +{ + if (!m) + return; + kfree(m); +} +EXPORT_SYMBOL_GPL(seq_file_done_buffer); + + + +void seq_hexdump(struct seq_file *seq, u8 *pfx, void *buf, ulong nbytes) +{ + int fmtbufsize = 100 * COVQ(nbytes, 16); + char *fmtbuf = NULL; + int i = 0; + if (buf == NULL) { + seq_printf(seq, "%s<NULL>\n", pfx); + return; + } + fmtbuf = kmalloc_kernel(fmtbufsize); + if (fmtbuf == NULL) + return; + hexDumpToBuffer(fmtbuf, fmtbufsize, pfx, (char *)(buf), nbytes, 16); + for (i = 0; fmtbuf[i] != '\0'; i++) + seq_printf(seq, "%c", fmtbuf[i]); + kfree(fmtbuf); +} diff --git a/drivers/staging/usbip/stub_dev.c b/drivers/staging/usbip/stub_dev.c index b0bfd3430d4..60a3e3fe4dc 100644 --- a/drivers/staging/usbip/stub_dev.c +++ b/drivers/staging/usbip/stub_dev.c @@ -87,13 +87,16 @@ static ssize_t store_sockfd(struct device *dev, struct device_attribute *attr, int sockfd = 0; struct socket *socket; ssize_t err = -EINVAL; + int rv; if (!sdev) { dev_err(dev, "sdev is null\n"); return -ENODEV; } - sscanf(buf, "%d", &sockfd); + rv = sscanf(buf, "%d", &sockfd); + if (rv != 1) + return -EINVAL; if (sockfd != -1) { dev_info(dev, "stub up\n"); diff --git a/drivers/staging/usbip/uapi/usbip.h b/drivers/staging/usbip/uapi/usbip.h new file mode 100644 index 00000000000..fa5db30ede3 --- /dev/null +++ b/drivers/staging/usbip/uapi/usbip.h @@ -0,0 +1,26 @@ +/* + * usbip.h + * + * USBIP uapi defines and function prototypes etc. +*/ + +#ifndef _UAPI_LINUX_USBIP_H +#define _UAPI_LINUX_USBIP_H + +/* usbip device status - exported in usbip device sysfs status */ +enum usbip_device_status { + /* sdev is available. */ + SDEV_ST_AVAILABLE = 0x01, + /* sdev is now used. */ + SDEV_ST_USED, + /* sdev is unusable because of a fatal error. */ + SDEV_ST_ERROR, + + /* vdev does not connect a remote device. */ + VDEV_ST_NULL, + /* vdev is used, but the USB address is not assigned yet */ + VDEV_ST_NOTASSIGNED, + VDEV_ST_USED, + VDEV_ST_ERROR +}; +#endif /* _UAPI_LINUX_USBIP_H */ diff --git a/drivers/staging/usbip/usbip_common.h b/drivers/staging/usbip/usbip_common.h index 7e6c5436d97..732fb636a1e 100644 --- a/drivers/staging/usbip/usbip_common.h +++ b/drivers/staging/usbip/usbip_common.h @@ -29,6 +29,7 @@ #include <linux/types.h> #include <linux/usb.h> #include <linux/wait.h> +#include "uapi/usbip.h" #define USBIP_VERSION "1.0.0" @@ -235,22 +236,6 @@ enum usbip_side { USBIP_STUB, }; -enum usbip_status { - /* sdev is available. */ - SDEV_ST_AVAILABLE = 0x01, - /* sdev is now used. */ - SDEV_ST_USED, - /* sdev is unusable because of a fatal error. */ - SDEV_ST_ERROR, - - /* vdev does not connect a remote device. */ - VDEV_ST_NULL, - /* vdev is used, but the USB address is not assigned yet */ - VDEV_ST_NOTASSIGNED, - VDEV_ST_USED, - VDEV_ST_ERROR -}; - /* event handler */ #define USBIP_EH_SHUTDOWN (1 << 0) #define USBIP_EH_BYE (1 << 1) @@ -271,7 +256,7 @@ enum usbip_status { /* a common structure for stub_device and vhci_device */ struct usbip_device { enum usbip_side side; - enum usbip_status status; + enum usbip_device_status status; /* lock for status */ spinlock_t lock; diff --git a/drivers/staging/usbip/userspace/libsrc/usbip_common.h b/drivers/staging/usbip/userspace/libsrc/usbip_common.h index 2cb81b3b35f..5af59d42911 100644 --- a/drivers/staging/usbip/userspace/libsrc/usbip_common.h +++ b/drivers/staging/usbip/userspace/libsrc/usbip_common.h @@ -15,6 +15,7 @@ #include <syslog.h> #include <unistd.h> #include <linux/usb/ch9.h> +#include "../../uapi/usbip.h" #ifndef USBIDS_FILE #define USBIDS_FILE "/usr/share/hwdata/usb.ids" @@ -77,23 +78,6 @@ extern int usbip_use_debug ; abort(); \ } while (0) -/* FIXME: how to sync with drivers/usbip_common.h ? */ -enum usbip_device_status { - /* sdev is available. */ - SDEV_ST_AVAILABLE = 0x01, - /* sdev is now used. */ - SDEV_ST_USED, - /* sdev is unusable because of a fatal error. */ - SDEV_ST_ERROR, - - /* vdev does not connect a remote device. */ - VDEV_ST_NULL, - /* vdev is used, but the USB address is not assigned yet */ - VDEV_ST_NOTASSIGNED, - VDEV_ST_USED, - VDEV_ST_ERROR -}; - struct usbip_usb_interface { uint8_t bInterfaceClass; uint8_t bInterfaceSubClass; diff --git a/drivers/staging/usbip/userspace/libsrc/usbip_host_driver.c b/drivers/staging/usbip/userspace/libsrc/usbip_host_driver.c index 86a867582de..35b2f5b0e35 100644 --- a/drivers/staging/usbip/userspace/libsrc/usbip_host_driver.c +++ b/drivers/staging/usbip/userspace/libsrc/usbip_host_driver.c @@ -101,6 +101,7 @@ static int32_t read_attr_usbip_status(struct usbip_usb_device *udev) static struct usbip_exported_device *usbip_exported_device_new(char *sdevpath) { struct usbip_exported_device *edev = NULL; + struct usbip_exported_device *edev_old; size_t size; int i; @@ -126,8 +127,10 @@ static struct usbip_exported_device *usbip_exported_device_new(char *sdevpath) size = sizeof(*edev) + edev->udev.bNumInterfaces * sizeof(struct usbip_usb_interface); + edev_old = edev; edev = realloc(edev, size); if (!edev) { + edev = edev_old; dbg("realloc failed"); goto err; } diff --git a/drivers/staging/usbip/userspace/libsrc/vhci_driver.c b/drivers/staging/usbip/userspace/libsrc/vhci_driver.c index f4bfefec5fc..d80d37c64cb 100644 --- a/drivers/staging/usbip/userspace/libsrc/vhci_driver.c +++ b/drivers/staging/usbip/userspace/libsrc/vhci_driver.c @@ -545,7 +545,7 @@ int usbip_vhci_attach_device2(uint8_t port, int sockfd, uint32_t devid, return -1; } - snprintf(buff, sizeof(buff), "%u %u %u %u", + snprintf(buff, sizeof(buff), "%u %d %u %u", port, sockfd, devid, speed); dbg("writing: %s", buff); diff --git a/drivers/staging/vt6656/device.h b/drivers/staging/vt6656/device.h index e5f0be3b4ae..e2abe3ddd24 100644 --- a/drivers/staging/vt6656/device.h +++ b/drivers/staging/vt6656/device.h @@ -158,10 +158,10 @@ typedef enum __device_msg_level { /* * Enum of context types for SendPacket */ -typedef enum _CONTEXT_TYPE { - CONTEXT_DATA_PACKET = 1, - CONTEXT_MGMT_PACKET -} CONTEXT_TYPE; +enum { + CONTEXT_DATA_PACKET = 1, + CONTEXT_MGMT_PACKET +}; /* RCB (Receive Control Block) */ struct vnt_rcb { @@ -180,9 +180,7 @@ struct vnt_usb_send_context { struct sk_buff *pPacket; struct urb *pUrb; unsigned int uBufLen; - CONTEXT_TYPE Type; - struct ethhdr sEthHeader; - void *Next; + u8 type; bool bBoolInUse; unsigned char Data[MAX_TOTAL_SIZE_WITH_ALL_HEADERS]; }; @@ -206,12 +204,10 @@ typedef struct _DEFAULT_CONFIG { /* * Structure to keep track of USB interrupt packets */ -typedef struct { - unsigned int uDataLen; - u8 * pDataBuf; - /* struct urb *pUrb; */ - bool bInUse; -} INT_BUFFER, *PINT_BUFFER; +struct vnt_interrupt_buffer { + u8 *data_buf; + bool in_use; +}; /*++ NDIS related */ @@ -280,16 +276,6 @@ typedef struct tagSPMKIDCandidateEvent { PMKID_CANDIDATE CandidateList[MAX_PMKIDLIST]; } SPMKIDCandidateEvent, *PSPMKIDCandidateEvent; -/*++ 802.11h related */ -#define MAX_QUIET_COUNT 8 - -typedef struct tagSQuietControl { - bool bEnable; - u32 dwStartTime; - u8 byPeriod; - u16 wDuration; -} SQuietControl, *PSQuietControl; - /* The receive duplicate detection cache entry */ typedef struct tagSCacheEntry{ u16 wFmSequence; @@ -369,8 +355,6 @@ struct vnt_private { OPTIONS sOpts; - struct tasklet_struct CmdWorkItem; - struct tasklet_struct EventWorkItem; struct work_struct read_work_item; struct work_struct rx_mng_work_item; @@ -420,28 +404,11 @@ struct vnt_private { struct vnt_tx_pkt_info pkt_info[16]; /* Variables to track resources for the Interrupt In Pipe */ - INT_BUFFER intBuf; - int bEventAvailable; + struct vnt_interrupt_buffer int_buf; /* default config from file by user setting */ DEFAULT_CONFIG config_file; - /* Statistic for USB */ - unsigned long ulBulkInPosted; - unsigned long ulBulkInError; - unsigned long ulBulkInContCRCError; - unsigned long ulBulkInBytesRead; - - unsigned long ulBulkOutPosted; - unsigned long ulBulkOutError; - unsigned long ulBulkOutContCRCError; - unsigned long ulBulkOutBytesWrite; - - unsigned long ulIntInPosted; - unsigned long ulIntInError; - unsigned long ulIntInContCRCError; - unsigned long ulIntInBytesRead; - /* Version control */ u16 wFirmwareVersion; u8 byLocalID; @@ -462,11 +429,6 @@ struct vnt_private { int bExistSWNetAddr; /* Maintain statistical debug info. */ - unsigned long packetsReceived; - unsigned long packetsReceivedDropped; - unsigned long packetsReceivedOverflow; - unsigned long packetsSent; - unsigned long packetsSentDropped; unsigned long SendContextsInUse; unsigned long RcvBuffersInUse; @@ -791,5 +753,6 @@ struct vnt_private { (fMP_DISCONNECTED | fMP_RESET_IN_PROGRESS | fMP_HALT_IN_PROGRESS | fMP_INIT_IN_PROGRESS | fMP_SURPRISE_REMOVED)) == 0) int device_alloc_frag_buf(struct vnt_private *, PSDeFragControlBlock pDeF); +void vnt_configure_filter(struct vnt_private *); #endif diff --git a/drivers/staging/vt6656/dpc.c b/drivers/staging/vt6656/dpc.c index 03351e741bd..4ccaa7e29a1 100644 --- a/drivers/staging/vt6656/dpc.c +++ b/drivers/staging/vt6656/dpc.c @@ -1227,14 +1227,13 @@ static int s_bAPModeRxData(struct vnt_private *pDevice, struct sk_buff *skb, if (is_multicast_ether_addr((u8 *)(skb->data+cbHeaderOffset))) { if (pMgmt->sNodeDBTable[0].bPSEnable) { - skbcpy = dev_alloc_skb((int)pDevice->rx_buf_sz); + skbcpy = netdev_alloc_skb(pDevice->dev, pDevice->rx_buf_sz); // if any node in PS mode, buffer packet until DTIM. if (skbcpy == NULL) { DBG_PRT(MSG_LEVEL_NOTICE, KERN_INFO "relay multicast no skb available \n"); } else { - skbcpy->dev = pDevice->dev; skbcpy->len = FrameSize; memcpy(skbcpy->data, skb->data+cbHeaderOffset, FrameSize); skb_queue_tail(&(pMgmt->sNodeDBTable[0].sTxPSQueue), skbcpy); @@ -1295,63 +1294,66 @@ static int s_bAPModeRxData(struct vnt_private *pDevice, struct sk_buff *skb, void RXvWorkItem(struct work_struct *work) { - struct vnt_private *pDevice = + struct vnt_private *priv = container_of(work, struct vnt_private, read_work_item); - int ntStatus; - struct vnt_rcb *pRCB = NULL; + int status; + struct vnt_rcb *rcb = NULL; - if (pDevice->Flags & fMP_DISCONNECTED) + if (priv->Flags & fMP_DISCONNECTED) return; - DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"---->Rx Polling Thread\n"); - spin_lock_irq(&pDevice->lock); + DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"---->Rx Polling Thread\n"); - while ((pDevice->Flags & fMP_POST_READS) && - MP_IS_READY(pDevice) && - (pDevice->NumRecvFreeList != 0) ) { - pRCB = pDevice->FirstRecvFreeList; - pDevice->NumRecvFreeList--; - DequeueRCB(pDevice->FirstRecvFreeList, pDevice->LastRecvFreeList); - ntStatus = PIPEnsBulkInUsbRead(pDevice, pRCB); - } - pDevice->bIsRxWorkItemQueued = false; - spin_unlock_irq(&pDevice->lock); + spin_lock_irq(&priv->lock); + + while ((priv->Flags & fMP_POST_READS) && MP_IS_READY(priv) && + (priv->NumRecvFreeList != 0)) { + rcb = priv->FirstRecvFreeList; + + priv->NumRecvFreeList--; + + DequeueRCB(priv->FirstRecvFreeList, priv->LastRecvFreeList); + + status = PIPEnsBulkInUsbRead(priv, rcb); + } + priv->bIsRxWorkItemQueued = false; + + spin_unlock_irq(&priv->lock); } -void RXvFreeRCB(struct vnt_rcb *pRCB, int bReAllocSkb) +void RXvFreeRCB(struct vnt_rcb *rcb, int re_alloc_skb) { - struct vnt_private *pDevice = pRCB->pDevice; + struct vnt_private *priv = rcb->pDevice; - DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"---->RXvFreeRCB\n"); + DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"---->RXvFreeRCB\n"); - if (bReAllocSkb == false) { - kfree_skb(pRCB->skb); - bReAllocSkb = true; + if (re_alloc_skb == false) { + kfree_skb(rcb->skb); + re_alloc_skb = true; } - if (bReAllocSkb == true) { - pRCB->skb = dev_alloc_skb((int)pDevice->rx_buf_sz); - // todo error handling - if (pRCB->skb == NULL) { - DBG_PRT(MSG_LEVEL_ERR,KERN_ERR" Failed to re-alloc rx skb\n"); - }else { - pRCB->skb->dev = pDevice->dev; - } - } - // - // Insert the RCB back in the Recv free list - // - EnqueueRCB(pDevice->FirstRecvFreeList, pDevice->LastRecvFreeList, pRCB); - pDevice->NumRecvFreeList++; + if (re_alloc_skb == true) { + rcb->skb = netdev_alloc_skb(priv->dev, priv->rx_buf_sz); + /* TODO error handling */ + if (!rcb->skb) { + DBG_PRT(MSG_LEVEL_ERR, KERN_ERR + " Failed to re-alloc rx skb\n"); + } + } - if ((pDevice->Flags & fMP_POST_READS) && MP_IS_READY(pDevice) && - (pDevice->bIsRxWorkItemQueued == false) ) { + /* Insert the RCB back in the Recv free list */ + EnqueueRCB(priv->FirstRecvFreeList, priv->LastRecvFreeList, rcb); + priv->NumRecvFreeList++; - pDevice->bIsRxWorkItemQueued = true; - schedule_work(&pDevice->read_work_item); - } - DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"<----RXFreeRCB %d %d\n",pDevice->NumRecvFreeList, pDevice->NumRecvMngList); + if ((priv->Flags & fMP_POST_READS) && MP_IS_READY(priv) && + (priv->bIsRxWorkItemQueued == false)) { + priv->bIsRxWorkItemQueued = true; + schedule_work(&priv->read_work_item); + } + + DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"<----RXFreeRCB %d %d\n", + priv->NumRecvFreeList, priv->NumRecvMngList); } void RXvMngWorkItem(struct work_struct *work) diff --git a/drivers/staging/vt6656/int.c b/drivers/staging/vt6656/int.c index 34c45280a9c..cca56b2f243 100644 --- a/drivers/staging/vt6656/int.c +++ b/drivers/staging/vt6656/int.c @@ -84,7 +84,7 @@ void INTnsProcessData(struct vnt_private *priv) DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"---->s_nsInterruptProcessData\n"); - int_data = (struct vnt_interrupt_data *)priv->intBuf.pDataBuf; + int_data = (struct vnt_interrupt_data *)priv->int_buf.data_buf; if (int_data->tsr0 & TSR_VALID) { if (int_data->tsr0 & (TSR_TMO | TSR_RETRYTMO)) @@ -178,8 +178,8 @@ void INTnsProcessData(struct vnt_private *priv) bScheduleCommand((void *) priv, WLAN_CMD_RADIO, NULL); - priv->intBuf.uDataLen = 0; - priv->intBuf.bInUse = false; + + priv->int_buf.in_use = false; stats->tx_errors = priv->wstats.discard.retries; stats->tx_dropped = priv->wstats.discard.retries; diff --git a/drivers/staging/vt6656/main_usb.c b/drivers/staging/vt6656/main_usb.c index bea1ad93336..7dd885fe201 100644 --- a/drivers/staging/vt6656/main_usb.c +++ b/drivers/staging/vt6656/main_usb.c @@ -749,44 +749,47 @@ err_nomem: return rc; } -static void device_free_tx_bufs(struct vnt_private *pDevice) +static void device_free_tx_bufs(struct vnt_private *priv) { - struct vnt_usb_send_context *pTxContext; - int ii; + struct vnt_usb_send_context *tx_context; + int ii; - for (ii = 0; ii < pDevice->cbTD; ii++) { + for (ii = 0; ii < priv->cbTD; ii++) { + tx_context = priv->apTD[ii]; + /* deallocate URBs */ + if (tx_context->pUrb) { + usb_kill_urb(tx_context->pUrb); + usb_free_urb(tx_context->pUrb); + } - pTxContext = pDevice->apTD[ii]; - /* deallocate URBs */ - if (pTxContext->pUrb) { - usb_kill_urb(pTxContext->pUrb); - usb_free_urb(pTxContext->pUrb); - } - kfree(pTxContext); - } - return; + kfree(tx_context); + } + + return; } -static void device_free_rx_bufs(struct vnt_private *pDevice) +static void device_free_rx_bufs(struct vnt_private *priv) { - struct vnt_rcb *pRCB; + struct vnt_rcb *rcb; int ii; - for (ii = 0; ii < pDevice->cbRD; ii++) { + for (ii = 0; ii < priv->cbRD; ii++) { + rcb = priv->apRCB[ii]; - pRCB = pDevice->apRCB[ii]; - /* deallocate URBs */ - if (pRCB->pUrb) { - usb_kill_urb(pRCB->pUrb); - usb_free_urb(pRCB->pUrb); - } - /* deallocate skb */ - if (pRCB->skb) - dev_kfree_skb(pRCB->skb); - } - kfree(pDevice->pRCBMem); + /* deallocate URBs */ + if (rcb->pUrb) { + usb_kill_urb(rcb->pUrb); + usb_free_urb(rcb->pUrb); + } - return; + /* deallocate skb */ + if (rcb->skb) + dev_kfree_skb(rcb->skb); + } + + kfree(priv->pRCBMem); + + return; } static void usb_device_reset(struct vnt_private *pDevice) @@ -798,95 +801,109 @@ static void usb_device_reset(struct vnt_private *pDevice) return ; } -static void device_free_int_bufs(struct vnt_private *pDevice) +static void device_free_int_bufs(struct vnt_private *priv) { - kfree(pDevice->intBuf.pDataBuf); - return; + kfree(priv->int_buf.data_buf); + + return; } -static bool device_alloc_bufs(struct vnt_private *pDevice) +static bool device_alloc_bufs(struct vnt_private *priv) { - struct vnt_usb_send_context *pTxContext; - struct vnt_rcb *pRCB; + struct vnt_usb_send_context *tx_context; + struct vnt_rcb *rcb; int ii; - for (ii = 0; ii < pDevice->cbTD; ii++) { + for (ii = 0; ii < priv->cbTD; ii++) { + tx_context = kmalloc(sizeof(struct vnt_usb_send_context), + GFP_KERNEL); + if (tx_context == NULL) { + DBG_PRT(MSG_LEVEL_ERR, KERN_ERR + "%s : allocate tx usb context failed\n", + priv->dev->name); + goto free_tx; + } - pTxContext = kmalloc(sizeof(struct vnt_usb_send_context), GFP_KERNEL); - if (pTxContext == NULL) { - DBG_PRT(MSG_LEVEL_ERR,KERN_ERR "%s : allocate tx usb context failed\n", pDevice->dev->name); - goto free_tx; - } - pDevice->apTD[ii] = pTxContext; - pTxContext->pDevice = (void *) pDevice; - /* allocate URBs */ - pTxContext->pUrb = usb_alloc_urb(0, GFP_ATOMIC); - if (pTxContext->pUrb == NULL) { - DBG_PRT(MSG_LEVEL_ERR,KERN_ERR "alloc tx urb failed\n"); - goto free_tx; - } - pTxContext->bBoolInUse = false; - } + priv->apTD[ii] = tx_context; + tx_context->pDevice = priv; - /* allocate RCB mem */ - pDevice->pRCBMem = kzalloc((sizeof(struct vnt_rcb) * pDevice->cbRD), + /* allocate URBs */ + tx_context->pUrb = usb_alloc_urb(0, GFP_ATOMIC); + if (tx_context->pUrb == NULL) { + DBG_PRT(MSG_LEVEL_ERR, + KERN_ERR "alloc tx urb failed\n"); + goto free_tx; + } + + tx_context->bBoolInUse = false; + } + + /* allocate RCB mem */ + priv->pRCBMem = kzalloc((sizeof(struct vnt_rcb) * priv->cbRD), GFP_KERNEL); - if (pDevice->pRCBMem == NULL) { - DBG_PRT(MSG_LEVEL_ERR,KERN_ERR "%s : alloc rx usb context failed\n", pDevice->dev->name); - goto free_tx; - } + if (priv->pRCBMem == NULL) { + DBG_PRT(MSG_LEVEL_ERR, KERN_ERR + "%s : alloc rx usb context failed\n", + priv->dev->name); + goto free_tx; + } + + priv->FirstRecvFreeList = NULL; + priv->LastRecvFreeList = NULL; + priv->FirstRecvMngList = NULL; + priv->LastRecvMngList = NULL; + priv->NumRecvFreeList = 0; - pDevice->FirstRecvFreeList = NULL; - pDevice->LastRecvFreeList = NULL; - pDevice->FirstRecvMngList = NULL; - pDevice->LastRecvMngList = NULL; - pDevice->NumRecvFreeList = 0; + rcb = (struct vnt_rcb *)priv->pRCBMem; - pRCB = (struct vnt_rcb *)pDevice->pRCBMem; + for (ii = 0; ii < priv->cbRD; ii++) { + priv->apRCB[ii] = rcb; + rcb->pDevice = priv; - for (ii = 0; ii < pDevice->cbRD; ii++) { + /* allocate URBs */ + rcb->pUrb = usb_alloc_urb(0, GFP_ATOMIC); + if (rcb->pUrb == NULL) { + DBG_PRT(MSG_LEVEL_ERR, KERN_ERR + " Failed to alloc rx urb\n"); + goto free_rx_tx; + } - pDevice->apRCB[ii] = pRCB; - pRCB->pDevice = (void *) pDevice; - /* allocate URBs */ - pRCB->pUrb = usb_alloc_urb(0, GFP_ATOMIC); + rcb->skb = netdev_alloc_skb(priv->dev, priv->rx_buf_sz); + if (rcb->skb == NULL) { + DBG_PRT(MSG_LEVEL_ERR, KERN_ERR + " Failed to alloc rx skb\n"); + goto free_rx_tx; + } - if (pRCB->pUrb == NULL) { - DBG_PRT(MSG_LEVEL_ERR,KERN_ERR" Failed to alloc rx urb\n"); - goto free_rx_tx; - } - pRCB->skb = dev_alloc_skb((int)pDevice->rx_buf_sz); - if (pRCB->skb == NULL) { - DBG_PRT(MSG_LEVEL_ERR,KERN_ERR" Failed to alloc rx skb\n"); - goto free_rx_tx; - } - pRCB->skb->dev = pDevice->dev; - pRCB->bBoolInUse = false; - EnqueueRCB(pDevice->FirstRecvFreeList, pDevice->LastRecvFreeList, pRCB); - pDevice->NumRecvFreeList++; - pRCB++; - } + rcb->bBoolInUse = false; + + EnqueueRCB(priv->FirstRecvFreeList, + priv->LastRecvFreeList, rcb); - pDevice->pInterruptURB = usb_alloc_urb(0, GFP_ATOMIC); - if (pDevice->pInterruptURB == NULL) { - DBG_PRT(MSG_LEVEL_ERR,KERN_ERR"Failed to alloc int urb\n"); - goto free_rx_tx; + priv->NumRecvFreeList++; + rcb++; } - pDevice->intBuf.pDataBuf = kmalloc(MAX_INTERRUPT_SIZE, GFP_KERNEL); - if (pDevice->intBuf.pDataBuf == NULL) { - DBG_PRT(MSG_LEVEL_ERR,KERN_ERR"Failed to alloc int buf\n"); - usb_free_urb(pDevice->pInterruptURB); - goto free_rx_tx; + priv->pInterruptURB = usb_alloc_urb(0, GFP_ATOMIC); + if (priv->pInterruptURB == NULL) { + DBG_PRT(MSG_LEVEL_ERR, KERN_ERR"Failed to alloc int urb\n"); + goto free_rx_tx; } - return true; + priv->int_buf.data_buf = kmalloc(MAX_INTERRUPT_SIZE, GFP_KERNEL); + if (priv->int_buf.data_buf == NULL) { + DBG_PRT(MSG_LEVEL_ERR, KERN_ERR"Failed to alloc int buf\n"); + usb_free_urb(priv->pInterruptURB); + goto free_rx_tx; + } + + return true; free_rx_tx: - device_free_rx_bufs(pDevice); + device_free_rx_bufs(priv); free_tx: - device_free_tx_bufs(pDevice); + device_free_tx_bufs(priv); return false; } @@ -931,13 +948,11 @@ static void device_free_frag_bufs(struct vnt_private *pDevice) int device_alloc_frag_buf(struct vnt_private *pDevice, PSDeFragControlBlock pDeF) { + pDeF->skb = netdev_alloc_skb(pDevice->dev, pDevice->rx_buf_sz); + if (!pDeF->skb) + return false; - pDeF->skb = dev_alloc_skb((int)pDevice->rx_buf_sz); - if (pDeF->skb == NULL) - return false; - pDeF->skb->dev = pDevice->dev; - - return true; + return true; } static int device_open(struct net_device *dev) @@ -974,8 +989,6 @@ static int device_open(struct net_device *dev) goto free_all; } - device_set_multi(pDevice->dev); - /* init for key management */ KeyvInitTable(pDevice,&pDevice->sKey); memcpy(pDevice->vnt_mgmt.abyMACAddr, @@ -992,15 +1005,12 @@ static int device_open(struct net_device *dev) vMgrObjectInit(pDevice); - tasklet_init(&pDevice->EventWorkItem, (void *)INTvWorkItem, (unsigned long)pDevice); - schedule_delayed_work(&pDevice->second_callback_work, HZ); pDevice->int_interval = 100; /* max 100 microframes */ pDevice->eEncryptionStatus = Ndis802_11EncryptionDisabled; pDevice->bIsRxWorkItemQueued = true; - pDevice->bEventAvailable = false; pDevice->bWPADEVUp = false; pDevice->bwextstep0 = false; @@ -1096,8 +1106,6 @@ static int device_close(struct net_device *dev) cancel_work_sync(&pDevice->rx_mng_work_item); cancel_work_sync(&pDevice->read_work_item); - tasklet_kill(&pDevice->EventWorkItem); - pDevice->bRoaming = false; pDevice->bIsRoaming = false; pDevice->bEnableRoaming = false; @@ -1349,14 +1357,26 @@ static int Read_config_file(struct vnt_private *pDevice) static void device_set_multi(struct net_device *dev) { struct vnt_private *priv = netdev_priv(dev); + unsigned long flags; + + if (priv->flags & DEVICE_FLAGS_OPENED) { + spin_lock_irqsave(&priv->lock, flags); + + bScheduleCommand(priv, WLAN_CMD_CONFIGURE_FILTER, NULL); + + spin_unlock_irqrestore(&priv->lock, flags); + } +} + +void vnt_configure_filter(struct vnt_private *priv) +{ + struct net_device *dev = priv->dev; struct vnt_manager *mgmt = &priv->vnt_mgmt; struct netdev_hw_addr *ha; u64 mc_filter = 0; u8 tmp = 0; int rc; - spin_lock_irq(&priv->lock); - rc = CONTROLnsRequestIn(priv, MESSAGE_TYPE_READ, MAC_REG_RCR, MESSAGE_REQUEST_MACREG, 1, &tmp); if (rc == 0) @@ -1403,8 +1423,6 @@ static void device_set_multi(struct net_device *dev) DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "priv->byRxMode out= %x\n", priv->byRxMode); - - spin_unlock_irq(&priv->lock); } static struct net_device_stats *device_get_stats(struct net_device *dev) diff --git a/drivers/staging/vt6656/rxtx.c b/drivers/staging/vt6656/rxtx.c index 92146e50315..7083af32e43 100644 --- a/drivers/staging/vt6656/rxtx.c +++ b/drivers/staging/vt6656/rxtx.c @@ -1610,7 +1610,7 @@ CMD_STATUS csMgmt_xmit(struct vnt_private *pDevice, pTX_Buffer->byType = 0x00; pContext->pPacket = NULL; - pContext->Type = CONTEXT_MGMT_PACKET; + pContext->type = CONTEXT_MGMT_PACKET; pContext->uBufLen = (u16)cbReqCount + 4; //USB header if (WLAN_GET_FC_TODS(pMACHeader->frame_control) == 0) { @@ -1702,7 +1702,7 @@ CMD_STATUS csBeacon_xmit(struct vnt_private *pDevice, pTX_Buffer->byType = 0x01; pContext->pPacket = NULL; - pContext->Type = CONTEXT_MGMT_PACKET; + pContext->type = CONTEXT_MGMT_PACKET; pContext->uBufLen = (u16)cbReqCount + 4; //USB header PIPEnsSendBulkOut(pDevice,pContext); @@ -2050,7 +2050,7 @@ void vDMA0_tx_80211(struct vnt_private *pDevice, struct sk_buff *skb) pTX_Buffer->byType = 0x00; pContext->pPacket = skb; - pContext->Type = CONTEXT_MGMT_PACKET; + pContext->type = CONTEXT_MGMT_PACKET; pContext->uBufLen = (u16)cbReqCount + 4; //USB header if (WLAN_GET_FC_TODS(pMACHeader->frame_control) == 0) { @@ -2440,11 +2440,11 @@ int nsDMA_tx_packet(struct vnt_private *pDevice, pTX_Buffer->wTxByteCount = (u16)BytesToWrite; pContext->pPacket = skb; - pContext->Type = CONTEXT_DATA_PACKET; + pContext->type = CONTEXT_DATA_PACKET; pContext->uBufLen = (u16)BytesToWrite + 4 ; //USB header s_vSaveTxPktInfo(pDevice, (u8)(pTX_Buffer->byPKTNO & 0x0F), - &pContext->sEthHeader.h_dest[0], + &pDevice->sTxEthHeader.h_dest[0], (u16)(BytesToWrite-uHeaderLen), pTX_Buffer->fifo_head.wFIFOCtl); @@ -2594,11 +2594,11 @@ int bRelayPacketSend(struct vnt_private *pDevice, u8 *pbySkbData, u32 uDataLen, pTX_Buffer->wTxByteCount = (u16)BytesToWrite; pContext->pPacket = NULL; - pContext->Type = CONTEXT_DATA_PACKET; + pContext->type = CONTEXT_DATA_PACKET; pContext->uBufLen = (u16)BytesToWrite + 4 ; //USB header s_vSaveTxPktInfo(pDevice, (u8)(pTX_Buffer->byPKTNO & 0x0F), - &pContext->sEthHeader.h_dest[0], + &pDevice->sTxEthHeader.h_dest[0], (u16)(BytesToWrite - uHeaderLen), pTX_Buffer->fifo_head.wFIFOCtl); diff --git a/drivers/staging/vt6656/usbpipe.c b/drivers/staging/vt6656/usbpipe.c index 119f6560324..a4a4bf24aad 100644 --- a/drivers/staging/vt6656/usbpipe.c +++ b/drivers/staging/vt6656/usbpipe.c @@ -295,40 +295,38 @@ static void s_nsControlInUsbIoCompleteRead(struct urb *urb) * */ -int PIPEnsInterruptRead(struct vnt_private *pDevice) +int PIPEnsInterruptRead(struct vnt_private *priv) { - int ntStatus = STATUS_FAILURE; + int status = STATUS_FAILURE; - DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"---->s_nsStartInterruptUsbRead()\n"); + DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO + "---->s_nsStartInterruptUsbRead()\n"); - if(pDevice->intBuf.bInUse == true){ - return (STATUS_FAILURE); - } - pDevice->intBuf.bInUse = true; -// pDevice->bEventAvailable = false; - pDevice->ulIntInPosted++; - - // - // Now that we have created the urb, we will send a - // request to the USB device object. - // - pDevice->pInterruptURB->interval = pDevice->int_interval; - -usb_fill_bulk_urb(pDevice->pInterruptURB, - pDevice->usb, - usb_rcvbulkpipe(pDevice->usb, 1), - (void *) pDevice->intBuf.pDataBuf, + if (priv->int_buf.in_use == true) + return STATUS_FAILURE; + + priv->int_buf.in_use = true; + + usb_fill_int_urb(priv->pInterruptURB, + priv->usb, + usb_rcvbulkpipe(priv->usb, 1), + priv->int_buf.data_buf, MAX_INTERRUPT_SIZE, s_nsInterruptUsbIoCompleteRead, - pDevice); + priv, + priv->int_interval); - ntStatus = usb_submit_urb(pDevice->pInterruptURB, GFP_ATOMIC); - if (ntStatus != 0) { - DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Submit int URB failed %d\n", ntStatus); - } + status = usb_submit_urb(priv->pInterruptURB, GFP_ATOMIC); + if (status) { + DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO + "Submit int URB failed %d\n", status); + priv->int_buf.in_use = false; + } - DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"<----s_nsStartInterruptUsbRead Return(%x)\n",ntStatus); - return ntStatus; + DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO + "<----s_nsStartInterruptUsbRead Return(%x)\n", status); + + return status; } /* @@ -348,7 +346,7 @@ usb_fill_bulk_urb(pDevice->pInterruptURB, static void s_nsInterruptUsbIoCompleteRead(struct urb *urb) { - struct vnt_private *priv = (struct vnt_private *)urb->context; + struct vnt_private *priv = urb->context; int status; DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO @@ -361,7 +359,7 @@ static void s_nsInterruptUsbIoCompleteRead(struct urb *urb) case -ECONNRESET: case -ENOENT: case -ESHUTDOWN: - priv->intBuf.bInUse = false; + priv->int_buf.in_use = false; return; default: break; @@ -373,15 +371,11 @@ static void s_nsInterruptUsbIoCompleteRead(struct urb *urb) "s_nsInterruptUsbIoCompleteRead Status %d\n", status); if (status != STATUS_SUCCESS) { - priv->ulBulkInError++; - priv->intBuf.bInUse = false; + priv->int_buf.in_use = false; DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "IntUSBIoCompleteControl STATUS = %d\n", status); } else { - priv->ulIntInBytesRead += (unsigned long)urb->actual_length; - priv->ulIntInContCRCError = 0; - priv->bEventAvailable = true; INTnsProcessData(priv); } @@ -390,7 +384,7 @@ static void s_nsInterruptUsbIoCompleteRead(struct urb *urb) DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Submit int URB failed %d\n", status); } else { - priv->intBuf.bInUse = true; + priv->int_buf.in_use = true; } return; @@ -410,45 +404,41 @@ static void s_nsInterruptUsbIoCompleteRead(struct urb *urb) * */ -int PIPEnsBulkInUsbRead(struct vnt_private *pDevice, struct vnt_rcb *pRCB) +int PIPEnsBulkInUsbRead(struct vnt_private *priv, struct vnt_rcb *rcb) { - int ntStatus = 0; - struct urb *pUrb; - - DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"---->s_nsStartBulkInUsbRead\n"); + int status = 0; + struct urb *urb; - if (pDevice->Flags & fMP_DISCONNECTED) - return STATUS_FAILURE; + DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"---->s_nsStartBulkInUsbRead\n"); - pDevice->ulBulkInPosted++; + if (priv->Flags & fMP_DISCONNECTED) + return STATUS_FAILURE; - pUrb = pRCB->pUrb; - // - // Now that we have created the urb, we will send a - // request to the USB device object. - // - if (pRCB->skb == NULL) { - DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"pRCB->skb is null \n"); - return ntStatus; - } + urb = rcb->pUrb; + if (rcb->skb == NULL) { + DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"rcb->skb is null\n"); + return status; + } - usb_fill_bulk_urb(pUrb, - pDevice->usb, - usb_rcvbulkpipe(pDevice->usb, 2), - (void *) (pRCB->skb->data), + usb_fill_bulk_urb(urb, + priv->usb, + usb_rcvbulkpipe(priv->usb, 2), + (void *) (rcb->skb->data), MAX_TOTAL_SIZE_WITH_ALL_HEADERS, s_nsBulkInUsbIoCompleteRead, - pRCB); + rcb); - ntStatus = usb_submit_urb(pUrb, GFP_ATOMIC); - if (ntStatus != 0) { - DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Submit Rx URB failed %d\n", ntStatus); + status = usb_submit_urb(urb, GFP_ATOMIC); + if (status != 0) { + DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO + "Submit Rx URB failed %d\n", status); return STATUS_FAILURE ; } - pRCB->Ref = 1; - pRCB->bBoolInUse= true; - return ntStatus; + rcb->Ref = 1; + rcb->bBoolInUse = true; + + return status; } /* @@ -468,51 +458,47 @@ int PIPEnsBulkInUsbRead(struct vnt_private *pDevice, struct vnt_rcb *pRCB) static void s_nsBulkInUsbIoCompleteRead(struct urb *urb) { - struct vnt_rcb *pRCB = (struct vnt_rcb *)urb->context; - struct vnt_private *pDevice = pRCB->pDevice; - unsigned long bytesRead; - int bIndicateReceive = false; - int bReAllocSkb = false; - int status; + struct vnt_rcb *rcb = urb->context; + struct vnt_private *priv = rcb->pDevice; + int re_alloc_skb = false; - DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"---->s_nsBulkInUsbIoCompleteRead\n"); - status = urb->status; - bytesRead = urb->actual_length; - - if (status) { - pDevice->ulBulkInError++; - DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"BULK In failed %d\n", status); -//todo...xxxxxx -// if (status == USBD_STATUS_CRC) { -// pDevice->ulBulkInContCRCError++; -// } -// if (status == STATUS_DEVICE_NOT_CONNECTED ) -// { -// MP_SET_FLAG(pDevice, fMP_DISCONNECTED); -// } - } else { - if (bytesRead) - bIndicateReceive = true; - pDevice->ulBulkInContCRCError = 0; - pDevice->ulBulkInBytesRead += bytesRead; - } + DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"---->s_nsBulkInUsbIoCompleteRead\n"); - if (bIndicateReceive) { - spin_lock(&pDevice->lock); - if (RXbBulkInProcessData(pDevice, pRCB, bytesRead) == true) - bReAllocSkb = true; - spin_unlock(&pDevice->lock); - } - pRCB->Ref--; - if (pRCB->Ref == 0) - { - DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"RxvFreeNormal %d \n",pDevice->NumRecvFreeList); - spin_lock(&pDevice->lock); - RXvFreeRCB(pRCB, bReAllocSkb); - spin_unlock(&pDevice->lock); - } + switch (urb->status) { + case 0: + break; + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + return; + case -ETIMEDOUT: + default: + DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO + "BULK In failed %d\n", urb->status); + break; + } + + if (urb->actual_length) { + spin_lock(&priv->lock); + + if (RXbBulkInProcessData(priv, rcb, urb->actual_length) == true) + re_alloc_skb = true; + + spin_unlock(&priv->lock); + } - return; + rcb->Ref--; + if (rcb->Ref == 0) { + DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"RxvFreeNormal %d\n", + priv->NumRecvFreeList); + spin_lock(&priv->lock); + + RXvFreeRCB(rcb, re_alloc_skb); + + spin_unlock(&priv->lock); + } + + return; } /* @@ -529,53 +515,40 @@ static void s_nsBulkInUsbIoCompleteRead(struct urb *urb) * */ -int PIPEnsSendBulkOut(struct vnt_private *pDevice, - struct vnt_usb_send_context *pContext) +int PIPEnsSendBulkOut(struct vnt_private *priv, + struct vnt_usb_send_context *context) { int status; - struct urb *pUrb; + struct urb *urb; - pDevice->bPWBitOn = false; + priv->bPWBitOn = false; -/* - if (pDevice->pPendingBulkOutContext != NULL) { - pDevice->NumContextsQueued++; - EnqueueContext(pDevice->FirstTxContextQueue, pDevice->LastTxContextQueue, pContext); - status = STATUS_PENDING; - DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Send pending!\n"); - return status; - } -*/ - - DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"s_nsSendBulkOut\n"); - - if (MP_IS_READY(pDevice) && (pDevice->Flags & fMP_POST_WRITES)) { - - pUrb = pContext->pUrb; - pDevice->ulBulkOutPosted++; -// pDevice->pPendingBulkOutContext = pContext; - usb_fill_bulk_urb( - pUrb, - pDevice->usb, - usb_sndbulkpipe(pDevice->usb, 3), - (void *) &(pContext->Data[0]), - pContext->uBufLen, - s_nsBulkOutIoCompleteWrite, - pContext); - - status = usb_submit_urb(pUrb, GFP_ATOMIC); - if (status != 0) - { - DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Submit Tx URB failed %d\n", status); - pContext->bBoolInUse = false; - return STATUS_FAILURE; - } - return STATUS_PENDING; - } - else { - pContext->bBoolInUse = false; - return STATUS_RESOURCES; - } + DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"s_nsSendBulkOut\n"); + + if (!(MP_IS_READY(priv) && priv->Flags & fMP_POST_WRITES)) { + context->bBoolInUse = false; + return STATUS_RESOURCES; + } + + urb = context->pUrb; + + usb_fill_bulk_urb(urb, + priv->usb, + usb_sndbulkpipe(priv->usb, 3), + context->Data, + context->uBufLen, + s_nsBulkOutIoCompleteWrite, + context); + + status = usb_submit_urb(urb, GFP_ATOMIC); + if (status != 0) { + DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO + "Submit Tx URB failed %d\n", status); + context->bBoolInUse = false; + return STATUS_FAILURE; + } + + return STATUS_PENDING; } /* @@ -608,68 +581,49 @@ int PIPEnsSendBulkOut(struct vnt_private *pDevice, static void s_nsBulkOutIoCompleteWrite(struct urb *urb) { - struct vnt_private *pDevice; - int status; - CONTEXT_TYPE ContextType; - unsigned long ulBufLen; - struct vnt_usb_send_context *pContext; - - DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"---->s_nsBulkOutIoCompleteWrite\n"); - // - // The context given to IoSetCompletionRoutine is an USB_CONTEXT struct - // - pContext = (struct vnt_usb_send_context *)urb->context; - - pDevice = pContext->pDevice; - ContextType = pContext->Type; - ulBufLen = pContext->uBufLen; - - if (!netif_device_present(pDevice->dev)) - return; - - // - // Perform various IRP, URB, and buffer 'sanity checks' - // + struct vnt_usb_send_context *context = urb->context; + struct vnt_private *priv = context->pDevice; + u8 context_type = context->type; - status = urb->status; + DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"---->s_nsBulkOutIoCompleteWrite\n"); - if(status == STATUS_SUCCESS) { - DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Write %d bytes\n",(int)ulBufLen); - pDevice->ulBulkOutBytesWrite += ulBufLen; - pDevice->ulBulkOutContCRCError = 0; - } else { - DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"BULK Out failed %d\n", status); - pDevice->ulBulkOutError++; - } + switch (urb->status) { + case 0: + DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO + "Write %d bytes\n", context->uBufLen); + break; + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + context->bBoolInUse = false; + return; + case -ETIMEDOUT: + default: + DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO + "BULK Out failed %d\n", urb->status); + break; + } -// pDevice->ulCheckForHangCount = 0; -// pDevice->pPendingBulkOutContext = NULL; + if (!netif_device_present(priv->dev)) + return; - if ( CONTEXT_DATA_PACKET == ContextType ) { - // Indicate to the protocol the status of the sent packet and return - // ownership of the packet. - if (pContext->pPacket != NULL) { - dev_kfree_skb_irq(pContext->pPacket); - pContext->pPacket = NULL; - DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"tx %d bytes\n",(int)ulBufLen); - } + if (CONTEXT_DATA_PACKET == context_type) { + if (context->pPacket != NULL) { + dev_kfree_skb_irq(context->pPacket); + context->pPacket = NULL; + DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO + "tx %d bytes\n", context->uBufLen); + } - pDevice->dev->trans_start = jiffies; + priv->dev->trans_start = jiffies; + } - if (status == STATUS_SUCCESS) { - pDevice->packetsSent++; - } - else { - DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Send USB error! [%08xh]\n", status); - pDevice->packetsSentDropped++; - } + if (priv->bLinkPass == true) { + if (netif_queue_stopped(priv->dev)) + netif_wake_queue(priv->dev); + } - } - if (pDevice->bLinkPass == true) { - if (netif_queue_stopped(pDevice->dev)) - netif_wake_queue(pDevice->dev); - } - pContext->bBoolInUse = false; + context->bBoolInUse = false; - return; + return; } diff --git a/drivers/staging/vt6656/wcmd.c b/drivers/staging/vt6656/wcmd.c index 6b952291463..3cf3f24247a 100644 --- a/drivers/staging/vt6656/wcmd.c +++ b/drivers/staging/vt6656/wcmd.c @@ -293,17 +293,11 @@ void vRunCommand(struct work_struct *work) case WLAN_CMD_SCAN_START: pDevice->byReAssocCount = 0; - if (pDevice->bRadioOff == true) { - s_bCommandComplete(pDevice); - spin_unlock_irq(&pDevice->lock); - return; - } + if (pDevice->bRadioOff == true) + break; - if (pMgmt->eCurrMode == WMAC_MODE_ESS_AP) { - s_bCommandComplete(pDevice); - spin_unlock_irq(&pDevice->lock); - return; - } + if (pMgmt->eCurrMode == WMAC_MODE_ESS_AP) + break; pItemSSID = (PWLAN_IE_SSID)pMgmt->abyScanSSID; @@ -311,16 +305,12 @@ void vRunCommand(struct work_struct *work) pMgmt->uScanChannel = pDevice->byMinChannel; if (pMgmt->uScanChannel > pDevice->byMaxChannel) { pDevice->eCommandState = WLAN_CMD_SCAN_END; - s_bCommandComplete(pDevice); - spin_unlock_irq(&pDevice->lock); - return; + break; } else { if (!ChannelValid(pDevice->byZoneType, pMgmt->uScanChannel)) { DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Invalid channel pMgmt->uScanChannel = %d\n", pMgmt->uScanChannel); pMgmt->uScanChannel++; - s_bCommandComplete(pDevice); - spin_unlock_irq(&pDevice->lock); - return; + break; } if (pMgmt->uScanChannel == pDevice->byMinChannel) { // pMgmt->eScanType = WMAC_SCAN_ACTIVE; //mike mark @@ -420,16 +410,13 @@ void vRunCommand(struct work_struct *work) memset(&wrqu, 0, sizeof(wrqu)); wireless_send_event(pDevice->dev, SIOCGIWSCAN, &wrqu, NULL); - s_bCommandComplete(pDevice); break; case WLAN_CMD_DISASSOCIATE_START: pDevice->byReAssocCount = 0; if ((pMgmt->eCurrMode == WMAC_MODE_ESS_STA) && (pMgmt->eCurrState != WMAC_STATE_ASSOC)) { - s_bCommandComplete(pDevice); - spin_unlock_irq(&pDevice->lock); - return; + break; } else { pDevice->bwextstep0 = false; pDevice->bwextstep1 = false; @@ -458,17 +445,14 @@ void vRunCommand(struct work_struct *work) netif_stop_queue(pDevice->dev); if (pDevice->bNeedRadioOFF == true) CARDbRadioPowerOff(pDevice); - s_bCommandComplete(pDevice); + break; case WLAN_CMD_SSID_START: pDevice->byReAssocCount = 0; - if (pDevice->bRadioOff == true) { - s_bCommandComplete(pDevice); - spin_unlock_irq(&pDevice->lock); - return; - } + if (pDevice->bRadioOff == true) + break; memcpy(pMgmt->abyAdHocSSID, pMgmt->abyDesireSSID, ((PWLAN_IE_SSID)pMgmt->abyDesireSSID)->len + WLAN_IEHDR_LEN); @@ -489,11 +473,9 @@ void vRunCommand(struct work_struct *work) if ((pMgmt->eCurrState == WMAC_STATE_ASSOC) || ((pMgmt->eCurrMode == WMAC_MODE_IBSS_STA) && (pMgmt->eCurrState == WMAC_STATE_JOINTED))) { if (pItemSSID->len == pItemSSIDCurr->len) { - if (memcmp(pItemSSID->abySSID, pItemSSIDCurr->abySSID, pItemSSID->len) == 0) { - s_bCommandComplete(pDevice); - spin_unlock_irq(&pDevice->lock); - return; - } + if (!memcmp(pItemSSID->abySSID, + pItemSSIDCurr->abySSID, pItemSSID->len)) + break; } netif_stop_queue(pDevice->dev); pDevice->bLinkPass = false; @@ -582,7 +564,6 @@ void vRunCommand(struct work_struct *work) } } } - s_bCommandComplete(pDevice); break; case WLAN_AUTHENTICATE_WAIT: @@ -612,7 +593,6 @@ void vRunCommand(struct work_struct *work) } pDevice->byLinkWaitCount = 0; - s_bCommandComplete(pDevice); break; case WLAN_ASSOCIATE_WAIT: @@ -647,7 +627,6 @@ void vRunCommand(struct work_struct *work) return; } - s_bCommandComplete(pDevice); break; case WLAN_CMD_AP_MODE_START: @@ -683,7 +662,6 @@ void vRunCommand(struct work_struct *work) ControlvMaskByte(pDevice, MESSAGE_REQUEST_MACREG, MAC_REG_PAPEDELAY, LEDSTS_STS, LEDSTS_INTER); schedule_delayed_work(&pDevice->second_callback_work, HZ); } - s_bCommandComplete(pDevice); break; case WLAN_CMD_TX_PSPACKET_START: @@ -738,8 +716,6 @@ void vRunCommand(struct work_struct *work) pMgmt->sNodeDBTable[ii].bRxPSPoll = false; } } - - s_bCommandComplete(pDevice); break; case WLAN_CMD_RADIO_START: @@ -760,11 +736,8 @@ void vRunCommand(struct work_struct *work) 1, &byTmp); - if (ntStatus != STATUS_SUCCESS) { - s_bCommandComplete(pDevice); - spin_unlock_irq(&pDevice->lock); - return; - } + if (ntStatus != STATUS_SUCCESS) + break; if ((byTmp & GPIO3_DATA) == 0) { DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO" WLAN_CMD_RADIO_START_OFF........................\n"); // Old commands are useless. @@ -833,7 +806,6 @@ void vRunCommand(struct work_struct *work) } } - s_bCommandComplete(pDevice); break; case WLAN_CMD_CHANGE_BBSENSITIVITY_START: @@ -843,24 +815,20 @@ void vRunCommand(struct work_struct *work) BBvSetVGAGainOffset(pDevice, pDevice->byBBVGACurrent); DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Change sensitivity pDevice->byBBVGACurrent = %x\n", pDevice->byBBVGACurrent); pDevice->bStopDataPkt = false; - s_bCommandComplete(pDevice); break; case WLAN_CMD_TBTT_WAKEUP_START: PSbIsNextTBTTWakeUp(pDevice); - s_bCommandComplete(pDevice); break; case WLAN_CMD_BECON_SEND_START: bMgrPrepareBeaconToSend(pDevice, pMgmt); - s_bCommandComplete(pDevice); break; case WLAN_CMD_SETPOWER_START: RFbSetPower(pDevice, pDevice->wCurrentRate, pMgmt->uCurrChannel); - s_bCommandComplete(pDevice); break; case WLAN_CMD_CHANGE_ANTENNA_START: @@ -878,12 +846,10 @@ void vRunCommand(struct work_struct *work) else BBvSetAntennaMode(pDevice, ANT_RXA); } - s_bCommandComplete(pDevice); break; case WLAN_CMD_REMOVE_ALLKEY_START: KeybRemoveAllKey(pDevice, &(pDevice->sKey), pDevice->abyBSSID); - s_bCommandComplete(pDevice); break; case WLAN_CMD_MAC_DISPOWERSAVING_START: @@ -898,7 +864,6 @@ void vRunCommand(struct work_struct *work) NULL ); } - s_bCommandComplete(pDevice); break; case WLAN_CMD_11H_CHSW_START: @@ -906,14 +871,17 @@ void vRunCommand(struct work_struct *work) pDevice->bChannelSwitch = false; pMgmt->uCurrChannel = pDevice->byNewChannel; pDevice->bStopDataPkt = false; - s_bCommandComplete(pDevice); break; + case WLAN_CMD_CONFIGURE_FILTER_START: + vnt_configure_filter(pDevice); + break; default: - s_bCommandComplete(pDevice); break; } //switch + s_bCommandComplete(pDevice); + spin_unlock_irq(&pDevice->lock); return; } @@ -1009,6 +977,11 @@ static int s_bCommandComplete(struct vnt_private *pDevice) pDevice->eCommandState = WLAN_CMD_11H_CHSW_START; break; + case WLAN_CMD_CONFIGURE_FILTER: + pDevice->eCommandState = + WLAN_CMD_CONFIGURE_FILTER_START; + break; + default: break; } diff --git a/drivers/staging/vt6656/wcmd.h b/drivers/staging/vt6656/wcmd.h index caf2684ce91..736572101ba 100644 --- a/drivers/staging/vt6656/wcmd.h +++ b/drivers/staging/vt6656/wcmd.h @@ -51,7 +51,8 @@ typedef enum tagCMD_CODE { WLAN_CMD_REMOVE_ALLKEY, WLAN_CMD_MAC_DISPOWERSAVING, WLAN_CMD_11H_CHSW, - WLAN_CMD_RUN_AP + WLAN_CMD_RUN_AP, + WLAN_CMD_CONFIGURE_FILTER } CMD_CODE, *PCMD_CODE; #define CMD_Q_SIZE 32 @@ -96,6 +97,7 @@ typedef enum tagCMD_STATE { WLAN_CMD_REMOVE_ALLKEY_START, WLAN_CMD_MAC_DISPOWERSAVING_START, WLAN_CMD_11H_CHSW_START, + WLAN_CMD_CONFIGURE_FILTER_START, WLAN_CMD_IDLE } CMD_STATE, *PCMD_STATE; diff --git a/drivers/staging/xgifb/XGI_main_26.c b/drivers/staging/xgifb/XGI_main_26.c index b3ff603e622..466804687fc 100644 --- a/drivers/staging/xgifb/XGI_main_26.c +++ b/drivers/staging/xgifb/XGI_main_26.c @@ -1754,8 +1754,7 @@ static int xgifb_probe(struct pci_dev *pdev, dev_err(&pdev->dev, "Unable request memory size %x\n", xgifb_info->video_size); dev_err(&pdev->dev, - "Fatal error: Unable to reserve frame buffer memory. " - "Is there another framebuffer driver active?\n"); + "Fatal error: Unable to reserve frame buffer memory. Is there another framebuffer driver active?\n"); ret = -ENODEV; goto error_disable; } @@ -2087,23 +2086,19 @@ static struct pci_driver xgifb_driver = { module_param(mode, charp, 0); MODULE_PARM_DESC(mode, - "Selects the desired default display mode in the format XxYxDepth " - "(eg. 1024x768x16)."); + "Selects the desired default display mode in the format XxYxDepth (eg. 1024x768x16)."); module_param(forcecrt2type, charp, 0); MODULE_PARM_DESC(forcecrt2type, - "Force the second display output type. Possible values are NONE, " - "LCD, TV, VGA, SVIDEO or COMPOSITE."); + "Force the second display output type. Possible values are NONE, LCD, TV, VGA, SVIDEO or COMPOSITE."); module_param(vesa, int, 0); MODULE_PARM_DESC(vesa, - "Selects the desired default display mode by VESA mode number " - "(eg. 0x117)."); + "Selects the desired default display mode by VESA mode number (eg. 0x117)."); module_param(filter, int, 0); MODULE_PARM_DESC(filter, - "Selects TV flicker filter type (only for systems with a SiS301 video bridge). " - "Possible values 0-7. Default: [no filter])."); + "Selects TV flicker filter type (only for systems with a SiS301 video bridge). Possible values 0-7. Default: [no filter])."); static int __init xgifb_init(void) { diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c index a4489444ffb..42f18fc1067 100644 --- a/drivers/target/target_core_sbc.c +++ b/drivers/target/target_core_sbc.c @@ -1074,7 +1074,7 @@ sbc_dif_copy_prot(struct se_cmd *cmd, unsigned int sectors, bool read, struct scatterlist *psg; void *paddr, *addr; unsigned int i, len, left; - unsigned int offset = 0; + unsigned int offset = sg_off; left = sectors * dev->prot_length; @@ -1084,11 +1084,10 @@ sbc_dif_copy_prot(struct se_cmd *cmd, unsigned int sectors, bool read, if (offset >= sg->length) { sg = sg_next(sg); offset = 0; - sg_off = sg->offset; } paddr = kmap_atomic(sg_page(psg)) + psg->offset; - addr = kmap_atomic(sg_page(sg)) + sg_off; + addr = kmap_atomic(sg_page(sg)) + sg->offset + offset; if (read) memcpy(paddr, addr, len); @@ -1163,7 +1162,7 @@ sbc_dif_verify_read(struct se_cmd *cmd, sector_t start, unsigned int sectors, { struct se_device *dev = cmd->se_dev; struct se_dif_v1_tuple *sdt; - struct scatterlist *dsg; + struct scatterlist *dsg, *psg = sg; sector_t sector = start; void *daddr, *paddr; int i, j, offset = sg_off; @@ -1171,14 +1170,14 @@ sbc_dif_verify_read(struct se_cmd *cmd, sector_t start, unsigned int sectors, for_each_sg(cmd->t_data_sg, dsg, cmd->t_data_nents, i) { daddr = kmap_atomic(sg_page(dsg)) + dsg->offset; - paddr = kmap_atomic(sg_page(sg)) + sg->offset; + paddr = kmap_atomic(sg_page(psg)) + sg->offset; for (j = 0; j < dsg->length; j += dev->dev_attrib.block_size) { - if (offset >= sg->length) { + if (offset >= psg->length) { kunmap_atomic(paddr); - sg = sg_next(sg); - paddr = kmap_atomic(sg_page(sg)) + sg->offset; + psg = sg_next(psg); + paddr = kmap_atomic(sg_page(psg)) + psg->offset; offset = 0; } diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 24b4f65d877..2956250b722 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -1601,6 +1601,9 @@ void transport_generic_request_failure(struct se_cmd *cmd, case TCM_CHECK_CONDITION_ABORT_CMD: case TCM_CHECK_CONDITION_UNIT_ATTENTION: case TCM_CHECK_CONDITION_NOT_READY: + case TCM_LOGICAL_BLOCK_GUARD_CHECK_FAILED: + case TCM_LOGICAL_BLOCK_APP_TAG_CHECK_FAILED: + case TCM_LOGICAL_BLOCK_REF_TAG_CHECK_FAILED: break; case TCM_OUT_OF_RESOURCES: sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index bd2715a9d8e..c74a00ad7ad 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -1267,17 +1267,16 @@ static void pty_line_name(struct tty_driver *driver, int index, char *p) * @p: output buffer of at least 7 bytes * * Generate a name from a driver reference and write it to the output - * buffer. Return the number of bytes written. + * buffer. * * Locking: None */ -static ssize_t tty_line_name(struct tty_driver *driver, int index, char *p) +static void tty_line_name(struct tty_driver *driver, int index, char *p) { if (driver->flags & TTY_DRIVER_UNNUMBERED_NODE) - return sprintf(p, "%s", driver->name); + strcpy(p, driver->name); else - return sprintf(p, "%s%d", driver->name, - index + driver->name_base); + sprintf(p, "%s%d", driver->name, index + driver->name_base); } /** @@ -3546,19 +3545,9 @@ static ssize_t show_cons_active(struct device *dev, if (i >= ARRAY_SIZE(cs)) break; } - while (i--) { - struct tty_driver *driver; - const char *name = cs[i]->name; - int index = cs[i]->index; - - driver = cs[i]->device(cs[i], &index); - if (driver) { - count += tty_line_name(driver, index, buf + count); - count += sprintf(buf + count, "%c", i ? ' ':'\n'); - } else - count += sprintf(buf + count, "%s%d%c", - name, index, i ? ' ':'\n'); - } + while (i--) + count += sprintf(buf + count, "%s%d%c", + cs[i]->name, cs[i]->index, i ? ' ':'\n'); console_unlock(); return count; diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index 80de2f88ed2..4ab2cb62dfc 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c @@ -105,7 +105,7 @@ static int hw_ep_flush(struct ci_hdrc *ci, int num, int dir) do { /* flush any pending transfer */ - hw_write(ci, OP_ENDPTFLUSH, BIT(n), BIT(n)); + hw_write(ci, OP_ENDPTFLUSH, ~0, BIT(n)); while (hw_read(ci, OP_ENDPTFLUSH, BIT(n))) cpu_relax(); } while (hw_read(ci, OP_ENDPTSTAT, BIT(n))); @@ -205,7 +205,7 @@ static int hw_ep_prime(struct ci_hdrc *ci, int num, int dir, int is_ctrl) if (is_ctrl && dir == RX && hw_read(ci, OP_ENDPTSETUPSTAT, BIT(num))) return -EAGAIN; - hw_write(ci, OP_ENDPTPRIME, BIT(n), BIT(n)); + hw_write(ci, OP_ENDPTPRIME, ~0, BIT(n)); while (hw_read(ci, OP_ENDPTPRIME, BIT(n))) cpu_relax(); diff --git a/drivers/usb/gadget/bcm63xx_udc.c b/drivers/usb/gadget/bcm63xx_udc.c index 888fbb43b33..e969eb809a8 100644 --- a/drivers/usb/gadget/bcm63xx_udc.c +++ b/drivers/usb/gadget/bcm63xx_udc.c @@ -360,24 +360,30 @@ static inline void usb_dma_writel(struct bcm63xx_udc *udc, u32 val, u32 off) bcm_writel(val, udc->iudma_regs + off); } -static inline u32 usb_dmac_readl(struct bcm63xx_udc *udc, u32 off) +static inline u32 usb_dmac_readl(struct bcm63xx_udc *udc, u32 off, int chan) { - return bcm_readl(udc->iudma_regs + IUDMA_DMAC_OFFSET + off); + return bcm_readl(udc->iudma_regs + IUDMA_DMAC_OFFSET + off + + (ENETDMA_CHAN_WIDTH * chan)); } -static inline void usb_dmac_writel(struct bcm63xx_udc *udc, u32 val, u32 off) +static inline void usb_dmac_writel(struct bcm63xx_udc *udc, u32 val, u32 off, + int chan) { - bcm_writel(val, udc->iudma_regs + IUDMA_DMAC_OFFSET + off); + bcm_writel(val, udc->iudma_regs + IUDMA_DMAC_OFFSET + off + + (ENETDMA_CHAN_WIDTH * chan)); } -static inline u32 usb_dmas_readl(struct bcm63xx_udc *udc, u32 off) +static inline u32 usb_dmas_readl(struct bcm63xx_udc *udc, u32 off, int chan) { - return bcm_readl(udc->iudma_regs + IUDMA_DMAS_OFFSET + off); + return bcm_readl(udc->iudma_regs + IUDMA_DMAS_OFFSET + off + + (ENETDMA_CHAN_WIDTH * chan)); } -static inline void usb_dmas_writel(struct bcm63xx_udc *udc, u32 val, u32 off) +static inline void usb_dmas_writel(struct bcm63xx_udc *udc, u32 val, u32 off, + int chan) { - bcm_writel(val, udc->iudma_regs + IUDMA_DMAS_OFFSET + off); + bcm_writel(val, udc->iudma_regs + IUDMA_DMAS_OFFSET + off + + (ENETDMA_CHAN_WIDTH * chan)); } static inline void set_clocks(struct bcm63xx_udc *udc, bool is_enabled) @@ -638,7 +644,7 @@ static void iudma_write(struct bcm63xx_udc *udc, struct iudma_ch *iudma, } while (!last_bd); usb_dmac_writel(udc, ENETDMAC_CHANCFG_EN_MASK, - ENETDMAC_CHANCFG_REG(iudma->ch_idx)); + ENETDMAC_CHANCFG_REG, iudma->ch_idx); } /** @@ -694,9 +700,9 @@ static void iudma_reset_channel(struct bcm63xx_udc *udc, struct iudma_ch *iudma) bcm63xx_fifo_reset_ep(udc, max(0, iudma->ep_num)); /* stop DMA, then wait for the hardware to wrap up */ - usb_dmac_writel(udc, 0, ENETDMAC_CHANCFG_REG(ch_idx)); + usb_dmac_writel(udc, 0, ENETDMAC_CHANCFG_REG, ch_idx); - while (usb_dmac_readl(udc, ENETDMAC_CHANCFG_REG(ch_idx)) & + while (usb_dmac_readl(udc, ENETDMAC_CHANCFG_REG, ch_idx) & ENETDMAC_CHANCFG_EN_MASK) { udelay(1); @@ -713,10 +719,10 @@ static void iudma_reset_channel(struct bcm63xx_udc *udc, struct iudma_ch *iudma) dev_warn(udc->dev, "forcibly halting IUDMA channel %d\n", ch_idx); usb_dmac_writel(udc, ENETDMAC_CHANCFG_BUFHALT_MASK, - ENETDMAC_CHANCFG_REG(ch_idx)); + ENETDMAC_CHANCFG_REG, ch_idx); } } - usb_dmac_writel(udc, ~0, ENETDMAC_IR_REG(ch_idx)); + usb_dmac_writel(udc, ~0, ENETDMAC_IR_REG, ch_idx); /* don't leave "live" HW-owned entries for the next guy to step on */ for (d = iudma->bd_ring; d <= iudma->end_bd; d++) @@ -728,11 +734,11 @@ static void iudma_reset_channel(struct bcm63xx_udc *udc, struct iudma_ch *iudma) /* set up IRQs, UBUS burst size, and BD base for this channel */ usb_dmac_writel(udc, ENETDMAC_IR_BUFDONE_MASK, - ENETDMAC_IRMASK_REG(ch_idx)); - usb_dmac_writel(udc, 8, ENETDMAC_MAXBURST_REG(ch_idx)); + ENETDMAC_IRMASK_REG, ch_idx); + usb_dmac_writel(udc, 8, ENETDMAC_MAXBURST_REG, ch_idx); - usb_dmas_writel(udc, iudma->bd_ring_dma, ENETDMAS_RSTART_REG(ch_idx)); - usb_dmas_writel(udc, 0, ENETDMAS_SRAM2_REG(ch_idx)); + usb_dmas_writel(udc, iudma->bd_ring_dma, ENETDMAS_RSTART_REG, ch_idx); + usb_dmas_writel(udc, 0, ENETDMAS_SRAM2_REG, ch_idx); } /** @@ -2035,7 +2041,7 @@ static irqreturn_t bcm63xx_udc_data_isr(int irq, void *dev_id) spin_lock(&udc->lock); usb_dmac_writel(udc, ENETDMAC_IR_BUFDONE_MASK, - ENETDMAC_IR_REG(iudma->ch_idx)); + ENETDMAC_IR_REG, iudma->ch_idx); bep = iudma->bep; rc = iudma_read(udc, iudma); @@ -2175,18 +2181,18 @@ static int bcm63xx_iudma_dbg_show(struct seq_file *s, void *p) seq_printf(s, " [ep%d]:\n", max_t(int, iudma_defaults[ch_idx].ep_num, 0)); seq_printf(s, " cfg: %08x; irqstat: %08x; irqmask: %08x; maxburst: %08x\n", - usb_dmac_readl(udc, ENETDMAC_CHANCFG_REG(ch_idx)), - usb_dmac_readl(udc, ENETDMAC_IR_REG(ch_idx)), - usb_dmac_readl(udc, ENETDMAC_IRMASK_REG(ch_idx)), - usb_dmac_readl(udc, ENETDMAC_MAXBURST_REG(ch_idx))); + usb_dmac_readl(udc, ENETDMAC_CHANCFG_REG, ch_idx), + usb_dmac_readl(udc, ENETDMAC_IR_REG, ch_idx), + usb_dmac_readl(udc, ENETDMAC_IRMASK_REG, ch_idx), + usb_dmac_readl(udc, ENETDMAC_MAXBURST_REG, ch_idx)); - sram2 = usb_dmas_readl(udc, ENETDMAS_SRAM2_REG(ch_idx)); - sram3 = usb_dmas_readl(udc, ENETDMAS_SRAM3_REG(ch_idx)); + sram2 = usb_dmas_readl(udc, ENETDMAS_SRAM2_REG, ch_idx); + sram3 = usb_dmas_readl(udc, ENETDMAS_SRAM3_REG, ch_idx); seq_printf(s, " base: %08x; index: %04x_%04x; desc: %04x_%04x %08x\n", - usb_dmas_readl(udc, ENETDMAS_RSTART_REG(ch_idx)), + usb_dmas_readl(udc, ENETDMAS_RSTART_REG, ch_idx), sram2 >> 16, sram2 & 0xffff, sram3 >> 16, sram3 & 0xffff, - usb_dmas_readl(udc, ENETDMAS_SRAM4_REG(ch_idx))); + usb_dmas_readl(udc, ENETDMAS_SRAM4_REG, ch_idx)); seq_printf(s, " desc: %d/%d used", iudma->n_bds_used, iudma->n_bds); diff --git a/drivers/usb/gadget/f_fs.c b/drivers/usb/gadget/f_fs.c index 306a2b52125..2b433439407 100644 --- a/drivers/usb/gadget/f_fs.c +++ b/drivers/usb/gadget/f_fs.c @@ -585,7 +585,6 @@ static ssize_t ffs_epfile_io(struct file *file, char __user *buf, size_t len, int read) { struct ffs_epfile *epfile = file->private_data; - struct usb_gadget *gadget = epfile->ffs->gadget; struct ffs_ep *ep; char *data = NULL; ssize_t ret, data_len; @@ -622,6 +621,12 @@ static ssize_t ffs_epfile_io(struct file *file, /* Allocate & copy */ if (!halt) { /* + * if we _do_ wait above, the epfile->ffs->gadget might be NULL + * before the waiting completes, so do not assign to 'gadget' earlier + */ + struct usb_gadget *gadget = epfile->ffs->gadget; + + /* * Controller may require buffer size to be aligned to * maxpacketsize of an out endpoint. */ diff --git a/drivers/usb/gadget/printer.c b/drivers/usb/gadget/printer.c index bf7a56b6d48..69b76efd11e 100644 --- a/drivers/usb/gadget/printer.c +++ b/drivers/usb/gadget/printer.c @@ -1157,7 +1157,7 @@ static int __init printer_bind_config(struct usb_configuration *c) usb_gadget_set_selfpowered(gadget); - if (gadget->is_otg) { + if (gadget_is_otg(gadget)) { otg_descriptor.bmAttributes |= USB_OTG_HNP; printer_cfg_driver.descriptors = otg_desc; printer_cfg_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP; diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c index f04b2c3154d..dd9678f85c5 100644 --- a/drivers/usb/gadget/s3c2410_udc.c +++ b/drivers/usb/gadget/s3c2410_udc.c @@ -1629,7 +1629,7 @@ static void s3c2410_udc_reinit(struct s3c2410_udc *dev) ep->ep.desc = NULL; ep->halted = 0; INIT_LIST_HEAD(&ep->queue); - usb_ep_set_maxpacket_limit(&ep->ep, &ep->ep.maxpacket); + usb_ep_set_maxpacket_limit(&ep->ep, ep->ep.maxpacket); } } diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 471142725ff..81cda09b47e 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -685,8 +685,15 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd) struct ehci_hcd *ehci = hcd_to_ehci (hcd); u32 status, masked_status, pcd_status = 0, cmd; int bh; + unsigned long flags; - spin_lock (&ehci->lock); + /* + * For threadirqs option we use spin_lock_irqsave() variant to prevent + * deadlock with ehci hrtimer callback, because hrtimer callbacks run + * in interrupt context even when threadirqs is specified. We can go + * back to spin_lock() variant when hrtimer callbacks become threaded. + */ + spin_lock_irqsave(&ehci->lock, flags); status = ehci_readl(ehci, &ehci->regs->status); @@ -704,7 +711,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd) /* Shared IRQ? */ if (!masked_status || unlikely(ehci->rh_state == EHCI_RH_HALTED)) { - spin_unlock(&ehci->lock); + spin_unlock_irqrestore(&ehci->lock, flags); return IRQ_NONE; } @@ -815,7 +822,7 @@ dead: if (bh) ehci_work (ehci); - spin_unlock (&ehci->lock); + spin_unlock_irqrestore(&ehci->lock, flags); if (pcd_status) usb_hcd_poll_rh_status(hcd); return IRQ_HANDLED; diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index 47b858fc50b..7ae0c4d5174 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c @@ -238,6 +238,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd) int port; int mask; int changed; + bool fs_idle_delay; ehci_dbg(ehci, "suspend root hub\n"); @@ -272,6 +273,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd) ehci->bus_suspended = 0; ehci->owned_ports = 0; changed = 0; + fs_idle_delay = false; port = HCS_N_PORTS(ehci->hcs_params); while (port--) { u32 __iomem *reg = &ehci->regs->port_status [port]; @@ -300,16 +302,32 @@ static int ehci_bus_suspend (struct usb_hcd *hcd) } if (t1 != t2) { + /* + * On some controllers, Wake-On-Disconnect will + * generate false wakeup signals until the bus + * switches over to full-speed idle. For their + * sake, add a delay if we need one. + */ + if ((t2 & PORT_WKDISC_E) && + ehci_port_speed(ehci, t2) == + USB_PORT_STAT_HIGH_SPEED) + fs_idle_delay = true; ehci_writel(ehci, t2, reg); changed = 1; } } + spin_unlock_irq(&ehci->lock); + + if ((changed && ehci->has_tdi_phy_lpm) || fs_idle_delay) { + /* + * Wait for HCD to enter low-power mode or for the bus + * to switch to full-speed idle. + */ + usleep_range(5000, 5500); + } if (changed && ehci->has_tdi_phy_lpm) { - spin_unlock_irq(&ehci->lock); - msleep(5); /* 5 ms for HCD to enter low-power mode */ spin_lock_irq(&ehci->lock); - port = HCS_N_PORTS(ehci->hcs_params); while (port--) { u32 __iomem *hostpc_reg = &ehci->regs->hostpc[port]; @@ -322,8 +340,8 @@ static int ehci_bus_suspend (struct usb_hcd *hcd) port, (t3 & HOSTPC_PHCD) ? "succeeded" : "failed"); } + spin_unlock_irq(&ehci->lock); } - spin_unlock_irq(&ehci->lock); /* Apparently some devices need a >= 1-uframe delay here */ if (ehci->bus_suspended) diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index fc192ad9cc6..239ad0b1ceb 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -477,8 +477,11 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, musb->port1_status |= (USB_PORT_STAT_C_SUSPEND << 16) | MUSB_PORT_STAT_RESUME; + musb->rh_timer = jiffies + + msecs_to_jiffies(20); schedule_delayed_work( - &musb->finish_resume_work, 20); + &musb->finish_resume_work, + msecs_to_jiffies(20)); musb->xceiv->state = OTG_STATE_A_HOST; musb->is_active = 1; @@ -2157,11 +2160,19 @@ static void musb_restore_context(struct musb *musb) void __iomem *musb_base = musb->mregs; void __iomem *ep_target_regs; void __iomem *epio; + u8 power; musb_writew(musb_base, MUSB_FRAME, musb->context.frame); musb_writeb(musb_base, MUSB_TESTMODE, musb->context.testmode); musb_write_ulpi_buscontrol(musb->mregs, musb->context.busctl); - musb_writeb(musb_base, MUSB_POWER, musb->context.power); + + /* Don't affect SUSPENDM/RESUME bits in POWER reg */ + power = musb_readb(musb_base, MUSB_POWER); + power &= MUSB_POWER_SUSPENDM | MUSB_POWER_RESUME; + musb->context.power &= ~(MUSB_POWER_SUSPENDM | MUSB_POWER_RESUME); + power |= musb->context.power; + musb_writeb(musb_base, MUSB_POWER, power); + musb_writew(musb_base, MUSB_INTRTXE, musb->intrtxe); musb_writew(musb_base, MUSB_INTRRXE, musb->intrrxe); musb_writeb(musb_base, MUSB_INTRUSBE, musb->context.intrusbe); diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c index ed455724017..abb38c3833e 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c @@ -1183,6 +1183,9 @@ irqreturn_t musb_h_ep0_irq(struct musb *musb) csr = MUSB_CSR0_H_STATUSPKT | MUSB_CSR0_TXPKTRDY; + /* disable ping token in status phase */ + csr |= MUSB_CSR0_H_DIS_PING; + /* flag status stage */ musb->ep0_stage = MUSB_EP0_STATUS; diff --git a/drivers/usb/musb/musb_virthub.c b/drivers/usb/musb/musb_virthub.c index eb634433ef0..e2d2d8c9891 100644 --- a/drivers/usb/musb/musb_virthub.c +++ b/drivers/usb/musb/musb_virthub.c @@ -135,7 +135,8 @@ void musb_port_suspend(struct musb *musb, bool do_suspend) /* later, GetPortStatus will stop RESUME signaling */ musb->port1_status |= MUSB_PORT_STAT_RESUME; - schedule_delayed_work(&musb->finish_resume_work, 20); + schedule_delayed_work(&musb->finish_resume_work, + msecs_to_jiffies(20)); } } @@ -158,7 +159,6 @@ void musb_port_reset(struct musb *musb, bool do_reset) */ power = musb_readb(mbase, MUSB_POWER); if (do_reset) { - /* * If RESUME is set, we must make sure it stays minimum 20 ms. * Then we must clear RESUME and wait a bit to let musb start @@ -167,11 +167,22 @@ void musb_port_reset(struct musb *musb, bool do_reset) * detected". */ if (power & MUSB_POWER_RESUME) { - while (time_before(jiffies, musb->rh_timer)) - msleep(1); + long remain = (unsigned long) musb->rh_timer - jiffies; + + if (musb->rh_timer > 0 && remain > 0) { + /* take into account the minimum delay after resume */ + schedule_delayed_work( + &musb->deassert_reset_work, remain); + return; + } + musb_writeb(mbase, MUSB_POWER, - power & ~MUSB_POWER_RESUME); - msleep(1); + power & ~MUSB_POWER_RESUME); + + /* Give the core 1 ms to clear MUSB_POWER_RESUME */ + schedule_delayed_work(&musb->deassert_reset_work, + msecs_to_jiffies(1)); + return; } power &= 0xf0; @@ -180,7 +191,8 @@ void musb_port_reset(struct musb *musb, bool do_reset) musb->port1_status |= USB_PORT_STAT_RESET; musb->port1_status &= ~USB_PORT_STAT_ENABLE; - schedule_delayed_work(&musb->deassert_reset_work, 50); + schedule_delayed_work(&musb->deassert_reset_work, + msecs_to_jiffies(50)); } else { dev_dbg(musb->controller, "root port reset stopped\n"); musb_writeb(mbase, MUSB_POWER, diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c index 2a408cdaf7b..8aa59a2c5eb 100644 --- a/drivers/usb/musb/omap2430.c +++ b/drivers/usb/musb/omap2430.c @@ -659,7 +659,6 @@ static int omap2430_runtime_suspend(struct device *dev) OTG_INTERFSEL); omap2430_low_level_exit(musb); - phy_power_off(musb->phy); } return 0; @@ -674,7 +673,6 @@ static int omap2430_runtime_resume(struct device *dev) omap2430_low_level_init(musb); musb_writel(musb->mregs, OTG_INTERFSEL, musb->context.otg_interfsel); - phy_power_on(musb->phy); } return 0; diff --git a/drivers/usb/phy/phy-msm-usb.c b/drivers/usb/phy/phy-msm-usb.c index 8546c8dccd5..d204f745ed0 100644 --- a/drivers/usb/phy/phy-msm-usb.c +++ b/drivers/usb/phy/phy-msm-usb.c @@ -159,32 +159,6 @@ put_3p3: return rc; } -#ifdef CONFIG_PM_SLEEP -#define USB_PHY_SUSP_DIG_VOL 500000 -static int msm_hsusb_config_vddcx(int high) -{ - int max_vol = USB_PHY_VDD_DIG_VOL_MAX; - int min_vol; - int ret; - - if (high) - min_vol = USB_PHY_VDD_DIG_VOL_MIN; - else - min_vol = USB_PHY_SUSP_DIG_VOL; - - ret = regulator_set_voltage(hsusb_vddcx, min_vol, max_vol); - if (ret) { - pr_err("%s: unable to set the voltage for regulator " - "HSUSB_VDDCX\n", __func__); - return ret; - } - - pr_debug("%s: min_vol:%d max_vol:%d\n", __func__, min_vol, max_vol); - - return ret; -} -#endif - static int msm_hsusb_ldo_set_mode(int on) { int ret = 0; @@ -440,7 +414,32 @@ static int msm_otg_reset(struct usb_phy *phy) #define PHY_SUSPEND_TIMEOUT_USEC (500 * 1000) #define PHY_RESUME_TIMEOUT_USEC (100 * 1000) -#ifdef CONFIG_PM_SLEEP +#ifdef CONFIG_PM + +#define USB_PHY_SUSP_DIG_VOL 500000 +static int msm_hsusb_config_vddcx(int high) +{ + int max_vol = USB_PHY_VDD_DIG_VOL_MAX; + int min_vol; + int ret; + + if (high) + min_vol = USB_PHY_VDD_DIG_VOL_MIN; + else + min_vol = USB_PHY_SUSP_DIG_VOL; + + ret = regulator_set_voltage(hsusb_vddcx, min_vol, max_vol); + if (ret) { + pr_err("%s: unable to set the voltage for regulator " + "HSUSB_VDDCX\n", __func__); + return ret; + } + + pr_debug("%s: min_vol:%d max_vol:%d\n", __func__, min_vol, max_vol); + + return ret; +} + static int msm_otg_suspend(struct msm_otg *motg) { struct usb_phy *phy = &motg->phy; @@ -1733,22 +1732,18 @@ static int msm_otg_pm_resume(struct device *dev) } #endif -#ifdef CONFIG_PM static const struct dev_pm_ops msm_otg_dev_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(msm_otg_pm_suspend, msm_otg_pm_resume) SET_RUNTIME_PM_OPS(msm_otg_runtime_suspend, msm_otg_runtime_resume, msm_otg_runtime_idle) }; -#endif static struct platform_driver msm_otg_driver = { .remove = msm_otg_remove, .driver = { .name = DRIVER_NAME, .owner = THIS_MODULE, -#ifdef CONFIG_PM .pm = &msm_otg_dev_pm_ops, -#endif }, }; diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index ee1f00f03c4..44ab1298680 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -907,6 +907,8 @@ static const struct usb_device_id id_table_combined[] = { /* Crucible Devices */ { USB_DEVICE(FTDI_VID, FTDI_CT_COMET_PID) }, { USB_DEVICE(FTDI_VID, FTDI_Z3X_PID) }, + /* Cressi Devices */ + { USB_DEVICE(FTDI_VID, FTDI_CRESSI_PID) }, { } /* Terminating entry */ }; diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index 1e2d369df86..e599fbfcde5 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -1320,3 +1320,9 @@ * Manufacturer: Smart GSM Team */ #define FTDI_Z3X_PID 0x0011 + +/* + * Product: Cressi PC Interface + * Manufacturer: Cressi + */ +#define FTDI_CRESSI_PID 0x87d0 diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 216d20affba..68fc9fe6593 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -1526,7 +1526,8 @@ static const struct usb_device_id option_ids[] = { /* Cinterion */ { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_EU3_E) }, { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_EU3_P) }, - { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_PH8) }, + { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_PH8), + .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_AHXX) }, { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_PLXX), .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c index 9a68409580d..a0fa5de210c 100644 --- a/drivers/vhost/net.c +++ b/drivers/vhost/net.c @@ -70,7 +70,12 @@ enum { }; struct vhost_net_ubuf_ref { - struct kref kref; + /* refcount follows semantics similar to kref: + * 0: object is released + * 1: no outstanding ubufs + * >1: outstanding ubufs + */ + atomic_t refcount; wait_queue_head_t wait; struct vhost_virtqueue *vq; }; @@ -116,14 +121,6 @@ static void vhost_net_enable_zcopy(int vq) vhost_net_zcopy_mask |= 0x1 << vq; } -static void vhost_net_zerocopy_done_signal(struct kref *kref) -{ - struct vhost_net_ubuf_ref *ubufs; - - ubufs = container_of(kref, struct vhost_net_ubuf_ref, kref); - wake_up(&ubufs->wait); -} - static struct vhost_net_ubuf_ref * vhost_net_ubuf_alloc(struct vhost_virtqueue *vq, bool zcopy) { @@ -134,21 +131,24 @@ vhost_net_ubuf_alloc(struct vhost_virtqueue *vq, bool zcopy) ubufs = kmalloc(sizeof(*ubufs), GFP_KERNEL); if (!ubufs) return ERR_PTR(-ENOMEM); - kref_init(&ubufs->kref); + atomic_set(&ubufs->refcount, 1); init_waitqueue_head(&ubufs->wait); ubufs->vq = vq; return ubufs; } -static void vhost_net_ubuf_put(struct vhost_net_ubuf_ref *ubufs) +static int vhost_net_ubuf_put(struct vhost_net_ubuf_ref *ubufs) { - kref_put(&ubufs->kref, vhost_net_zerocopy_done_signal); + int r = atomic_sub_return(1, &ubufs->refcount); + if (unlikely(!r)) + wake_up(&ubufs->wait); + return r; } static void vhost_net_ubuf_put_and_wait(struct vhost_net_ubuf_ref *ubufs) { - kref_put(&ubufs->kref, vhost_net_zerocopy_done_signal); - wait_event(ubufs->wait, !atomic_read(&ubufs->kref.refcount)); + vhost_net_ubuf_put(ubufs); + wait_event(ubufs->wait, !atomic_read(&ubufs->refcount)); } static void vhost_net_ubuf_put_wait_and_free(struct vhost_net_ubuf_ref *ubufs) @@ -306,23 +306,26 @@ static void vhost_zerocopy_callback(struct ubuf_info *ubuf, bool success) { struct vhost_net_ubuf_ref *ubufs = ubuf->ctx; struct vhost_virtqueue *vq = ubufs->vq; - int cnt = atomic_read(&ubufs->kref.refcount); + int cnt; + + rcu_read_lock_bh(); /* set len to mark this desc buffers done DMA */ vq->heads[ubuf->desc].len = success ? VHOST_DMA_DONE_LEN : VHOST_DMA_FAILED_LEN; - vhost_net_ubuf_put(ubufs); + cnt = vhost_net_ubuf_put(ubufs); /* * Trigger polling thread if guest stopped submitting new buffers: - * in this case, the refcount after decrement will eventually reach 1 - * so here it is 2. + * in this case, the refcount after decrement will eventually reach 1. * We also trigger polling periodically after each 16 packets * (the value 16 here is more or less arbitrary, it's tuned to trigger * less than 10% of times). */ - if (cnt <= 2 || !(cnt % 16)) + if (cnt <= 1 || !(cnt % 16)) vhost_poll_queue(&vq->poll); + + rcu_read_unlock_bh(); } /* Expects to be always run from workqueue - which acts as @@ -420,7 +423,7 @@ static void handle_tx(struct vhost_net *net) msg.msg_control = ubuf; msg.msg_controllen = sizeof(ubuf); ubufs = nvq->ubufs; - kref_get(&ubufs->kref); + atomic_inc(&ubufs->refcount); nvq->upend_idx = (nvq->upend_idx + 1) % UIO_MAXIOV; } else { msg.msg_control = NULL; @@ -780,7 +783,7 @@ static void vhost_net_flush(struct vhost_net *n) vhost_net_ubuf_put_and_wait(n->vqs[VHOST_NET_VQ_TX].ubufs); mutex_lock(&n->vqs[VHOST_NET_VQ_TX].vq.mutex); n->tx_flush = false; - kref_init(&n->vqs[VHOST_NET_VQ_TX].ubufs->kref); + atomic_set(&n->vqs[VHOST_NET_VQ_TX].ubufs->refcount, 1); mutex_unlock(&n->vqs[VHOST_NET_VQ_TX].vq.mutex); } } @@ -800,6 +803,8 @@ static int vhost_net_release(struct inode *inode, struct file *f) fput(tx_sock->file); if (rx_sock) fput(rx_sock->file); + /* Make sure no callbacks are outstanding */ + synchronize_rcu_bh(); /* We do an extra flush before freeing memory, * since jobs can re-queue themselves. */ vhost_net_flush(n); diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c index 0a025b8e2a1..e48d4a67258 100644 --- a/drivers/vhost/scsi.c +++ b/drivers/vhost/scsi.c @@ -1001,6 +1001,12 @@ vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq) break; } + /* virtio-scsi spec requires byte 0 of the lun to be 1 */ + if (unlikely(v_req.lun[0] != 1)) { + vhost_scsi_send_bad_target(vs, vq, head, out); + continue; + } + /* Extract the tpgt */ target = v_req.lun[1]; tpg = ACCESS_ONCE(vs_tpg[target]); diff --git a/drivers/watchdog/w83697hf_wdt.c b/drivers/watchdog/w83697hf_wdt.c index aaf2995d37f..68b45fc9ba6 100644 --- a/drivers/watchdog/w83697hf_wdt.c +++ b/drivers/watchdog/w83697hf_wdt.c @@ -402,7 +402,7 @@ static int __init wdt_init(void) if (!found) { pr_err("No W83697HF/HG could be found\n"); - ret = -EIO; + ret = -ENODEV; goto out; } diff --git a/fs/ceph/acl.c b/fs/ceph/acl.c index 4c2d452c4bf..21887d63dad 100644 --- a/fs/ceph/acl.c +++ b/fs/ceph/acl.c @@ -54,11 +54,6 @@ static inline struct posix_acl *ceph_get_cached_acl(struct inode *inode, return acl; } -void ceph_forget_all_cached_acls(struct inode *inode) -{ - forget_all_cached_acls(inode); -} - struct posix_acl *ceph_get_acl(struct inode *inode, int type) { int size; @@ -160,11 +155,7 @@ int ceph_set_acl(struct inode *inode, struct posix_acl *acl, int type) goto out_dput; } - if (value) - ret = __ceph_setxattr(dentry, name, value, size, 0); - else - ret = __ceph_removexattr(dentry, name); - + ret = __ceph_setxattr(dentry, name, value, size, 0); if (ret) { if (new_mode != old_mode) { newattrs.ia_mode = old_mode; diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c index 6da4df84ba3..45eda6d7a40 100644 --- a/fs/ceph/dir.c +++ b/fs/ceph/dir.c @@ -100,6 +100,14 @@ static unsigned fpos_off(loff_t p) return p & 0xffffffff; } +static int fpos_cmp(loff_t l, loff_t r) +{ + int v = ceph_frag_compare(fpos_frag(l), fpos_frag(r)); + if (v) + return v; + return (int)(fpos_off(l) - fpos_off(r)); +} + /* * When possible, we try to satisfy a readdir by peeking at the * dcache. We make this work by carefully ordering dentries on @@ -156,7 +164,7 @@ more: if (!d_unhashed(dentry) && dentry->d_inode && ceph_snap(dentry->d_inode) != CEPH_SNAPDIR && ceph_ino(dentry->d_inode) != CEPH_INO_CEPH && - ctx->pos <= di->offset) + fpos_cmp(ctx->pos, di->offset) <= 0) break; dout(" skipping %p %.*s at %llu (%llu)%s%s\n", dentry, dentry->d_name.len, dentry->d_name.name, di->offset, @@ -695,9 +703,8 @@ static int ceph_mknod(struct inode *dir, struct dentry *dentry, ceph_mdsc_put_request(req); if (!err) - err = ceph_init_acl(dentry, dentry->d_inode, dir); - - if (err) + ceph_init_acl(dentry, dentry->d_inode, dir); + else d_drop(dentry); return err; } @@ -735,7 +742,9 @@ static int ceph_symlink(struct inode *dir, struct dentry *dentry, if (!err && !req->r_reply_info.head->is_dentry) err = ceph_handle_notrace_create(dir, dentry); ceph_mdsc_put_request(req); - if (err) + if (!err) + ceph_init_acl(dentry, dentry->d_inode, dir); + else d_drop(dentry); return err; } @@ -776,7 +785,9 @@ static int ceph_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) err = ceph_handle_notrace_create(dir, dentry); ceph_mdsc_put_request(req); out: - if (err < 0) + if (!err) + ceph_init_acl(dentry, dentry->d_inode, dir); + else d_drop(dentry); return err; } diff --git a/fs/ceph/file.c b/fs/ceph/file.c index dfd2ce3419f..09c7afe32e4 100644 --- a/fs/ceph/file.c +++ b/fs/ceph/file.c @@ -286,6 +286,7 @@ int ceph_atomic_open(struct inode *dir, struct dentry *dentry, } else { dout("atomic_open finish_open on dn %p\n", dn); if (req->r_op == CEPH_MDS_OP_CREATE && req->r_reply_info.has_create_ino) { + ceph_init_acl(dentry, dentry->d_inode, dir); *opened |= FILE_CREATED; } err = finish_open(file, dentry, ceph_open, opened); diff --git a/fs/ceph/super.c b/fs/ceph/super.c index 2df963f1cf5..10a4ccbf38d 100644 --- a/fs/ceph/super.c +++ b/fs/ceph/super.c @@ -144,7 +144,11 @@ enum { Opt_ino32, Opt_noino32, Opt_fscache, - Opt_nofscache + Opt_nofscache, +#ifdef CONFIG_CEPH_FS_POSIX_ACL + Opt_acl, +#endif + Opt_noacl }; static match_table_t fsopt_tokens = { @@ -172,6 +176,10 @@ static match_table_t fsopt_tokens = { {Opt_noino32, "noino32"}, {Opt_fscache, "fsc"}, {Opt_nofscache, "nofsc"}, +#ifdef CONFIG_CEPH_FS_POSIX_ACL + {Opt_acl, "acl"}, +#endif + {Opt_noacl, "noacl"}, {-1, NULL} }; @@ -271,6 +279,14 @@ static int parse_fsopt_token(char *c, void *private) case Opt_nofscache: fsopt->flags &= ~CEPH_MOUNT_OPT_FSCACHE; break; +#ifdef CONFIG_CEPH_FS_POSIX_ACL + case Opt_acl: + fsopt->sb_flags |= MS_POSIXACL; + break; +#endif + case Opt_noacl: + fsopt->sb_flags &= ~MS_POSIXACL; + break; default: BUG_ON(token); } @@ -438,6 +454,13 @@ static int ceph_show_options(struct seq_file *m, struct dentry *root) else seq_puts(m, ",nofsc"); +#ifdef CONFIG_CEPH_FS_POSIX_ACL + if (fsopt->sb_flags & MS_POSIXACL) + seq_puts(m, ",acl"); + else + seq_puts(m, ",noacl"); +#endif + if (fsopt->wsize) seq_printf(m, ",wsize=%d", fsopt->wsize); if (fsopt->rsize != CEPH_RSIZE_DEFAULT) @@ -819,9 +842,6 @@ static int ceph_set_super(struct super_block *s, void *data) s->s_flags = fsc->mount_options->sb_flags; s->s_maxbytes = 1ULL << 40; /* temp value until we get mdsmap */ -#ifdef CONFIG_CEPH_FS_POSIX_ACL - s->s_flags |= MS_POSIXACL; -#endif s->s_xattr = ceph_xattr_handlers; s->s_fs_info = fsc; @@ -911,6 +931,10 @@ static struct dentry *ceph_mount(struct file_system_type *fs_type, struct ceph_options *opt = NULL; dout("ceph_mount\n"); + +#ifdef CONFIG_CEPH_FS_POSIX_ACL + flags |= MS_POSIXACL; +#endif err = parse_mount_options(&fsopt, &opt, flags, data, dev_name, &path); if (err < 0) { res = ERR_PTR(err); diff --git a/fs/ceph/super.h b/fs/ceph/super.h index 19793b56d0a..d8801a95b68 100644 --- a/fs/ceph/super.h +++ b/fs/ceph/super.h @@ -13,6 +13,7 @@ #include <linux/wait.h> #include <linux/writeback.h> #include <linux/slab.h> +#include <linux/posix_acl.h> #include <linux/ceph/libceph.h> @@ -743,7 +744,11 @@ extern const struct xattr_handler *ceph_xattr_handlers[]; struct posix_acl *ceph_get_acl(struct inode *, int); int ceph_set_acl(struct inode *inode, struct posix_acl *acl, int type); int ceph_init_acl(struct dentry *, struct inode *, struct inode *); -void ceph_forget_all_cached_acls(struct inode *inode); + +static inline void ceph_forget_all_cached_acls(struct inode *inode) +{ + forget_all_cached_acls(inode); +} #else diff --git a/fs/ceph/xattr.c b/fs/ceph/xattr.c index 898b6565ad3..a55ec37378c 100644 --- a/fs/ceph/xattr.c +++ b/fs/ceph/xattr.c @@ -12,6 +12,9 @@ #define XATTR_CEPH_PREFIX "ceph." #define XATTR_CEPH_PREFIX_LEN (sizeof (XATTR_CEPH_PREFIX) - 1) +static int __remove_xattr(struct ceph_inode_info *ci, + struct ceph_inode_xattr *xattr); + /* * List of handlers for synthetic system.* attributes. Other * attributes are handled directly. @@ -319,8 +322,7 @@ static struct ceph_vxattr *ceph_match_vxattr(struct inode *inode, static int __set_xattr(struct ceph_inode_info *ci, const char *name, int name_len, const char *val, int val_len, - int dirty, - int should_free_name, int should_free_val, + int flags, int update_xattr, struct ceph_inode_xattr **newxattr) { struct rb_node **p; @@ -349,12 +351,31 @@ static int __set_xattr(struct ceph_inode_info *ci, xattr = NULL; } + if (update_xattr) { + int err = 0; + if (xattr && (flags & XATTR_CREATE)) + err = -EEXIST; + else if (!xattr && (flags & XATTR_REPLACE)) + err = -ENODATA; + if (err) { + kfree(name); + kfree(val); + return err; + } + if (update_xattr < 0) { + if (xattr) + __remove_xattr(ci, xattr); + kfree(name); + return 0; + } + } + if (!xattr) { new = 1; xattr = *newxattr; xattr->name = name; xattr->name_len = name_len; - xattr->should_free_name = should_free_name; + xattr->should_free_name = update_xattr; ci->i_xattrs.count++; dout("__set_xattr count=%d\n", ci->i_xattrs.count); @@ -364,7 +385,7 @@ static int __set_xattr(struct ceph_inode_info *ci, if (xattr->should_free_val) kfree((void *)xattr->val); - if (should_free_name) { + if (update_xattr) { kfree((void *)name); name = xattr->name; } @@ -379,8 +400,8 @@ static int __set_xattr(struct ceph_inode_info *ci, xattr->val = ""; xattr->val_len = val_len; - xattr->dirty = dirty; - xattr->should_free_val = (val && should_free_val); + xattr->dirty = update_xattr; + xattr->should_free_val = (val && update_xattr); if (new) { rb_link_node(&xattr->node, parent, p); @@ -442,7 +463,7 @@ static int __remove_xattr(struct ceph_inode_info *ci, struct ceph_inode_xattr *xattr) { if (!xattr) - return -EOPNOTSUPP; + return -ENODATA; rb_erase(&xattr->node, &ci->i_xattrs.index); @@ -588,7 +609,7 @@ start: p += len; err = __set_xattr(ci, name, namelen, val, len, - 0, 0, 0, &xattrs[numattr]); + 0, 0, &xattrs[numattr]); if (err < 0) goto bad; @@ -850,6 +871,9 @@ static int ceph_sync_setxattr(struct dentry *dentry, const char *name, dout("setxattr value=%.*s\n", (int)size, value); + if (!value) + flags |= CEPH_XATTR_REMOVE; + /* do request */ req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_SETXATTR, USE_AUTH_MDS); @@ -892,7 +916,7 @@ int __ceph_setxattr(struct dentry *dentry, const char *name, struct ceph_inode_info *ci = ceph_inode(inode); int issued; int err; - int dirty; + int dirty = 0; int name_len = strlen(name); int val_len = size; char *newname = NULL; @@ -953,12 +977,14 @@ retry: goto retry; } - err = __set_xattr(ci, newname, name_len, newval, - val_len, 1, 1, 1, &xattr); + err = __set_xattr(ci, newname, name_len, newval, val_len, + flags, value ? 1 : -1, &xattr); - dirty = __ceph_mark_dirty_caps(ci, CEPH_CAP_XATTR_EXCL); - ci->i_xattrs.dirty = true; - inode->i_ctime = CURRENT_TIME; + if (!err) { + dirty = __ceph_mark_dirty_caps(ci, CEPH_CAP_XATTR_EXCL); + ci->i_xattrs.dirty = true; + inode->i_ctime = CURRENT_TIME; + } spin_unlock(&ci->i_ceph_lock); if (dirty) diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c index c819b0bd491..7ff866dbb89 100644 --- a/fs/cifs/cifsacl.c +++ b/fs/cifs/cifsacl.c @@ -865,8 +865,8 @@ static int build_sec_desc(struct cifs_ntsd *pntsd, struct cifs_ntsd *pnntsd, return rc; } -static struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb, - __u16 fid, u32 *pacllen) +struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb, + const struct cifs_fid *cifsfid, u32 *pacllen) { struct cifs_ntsd *pntsd = NULL; unsigned int xid; @@ -877,7 +877,8 @@ static struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *cifs_sb, return ERR_CAST(tlink); xid = get_xid(); - rc = CIFSSMBGetCIFSACL(xid, tlink_tcon(tlink), fid, &pntsd, pacllen); + rc = CIFSSMBGetCIFSACL(xid, tlink_tcon(tlink), cifsfid->netfid, &pntsd, + pacllen); free_xid(xid); cifs_put_tlink(tlink); @@ -946,7 +947,7 @@ struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *cifs_sb, if (!open_file) return get_cifs_acl_by_path(cifs_sb, path, pacllen); - pntsd = get_cifs_acl_by_fid(cifs_sb, open_file->fid.netfid, pacllen); + pntsd = get_cifs_acl_by_fid(cifs_sb, &open_file->fid, pacllen); cifsFileInfo_put(open_file); return pntsd; } @@ -1006,19 +1007,31 @@ out: /* Translate the CIFS ACL (simlar to NTFS ACL) for a file into mode bits */ int cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr, - struct inode *inode, const char *path, const __u16 *pfid) + struct inode *inode, const char *path, + const struct cifs_fid *pfid) { struct cifs_ntsd *pntsd = NULL; u32 acllen = 0; int rc = 0; + struct tcon_link *tlink = cifs_sb_tlink(cifs_sb); + struct cifs_tcon *tcon; cifs_dbg(NOISY, "converting ACL to mode for %s\n", path); - if (pfid) - pntsd = get_cifs_acl_by_fid(cifs_sb, *pfid, &acllen); - else - pntsd = get_cifs_acl(cifs_sb, inode, path, &acllen); + if (IS_ERR(tlink)) + return PTR_ERR(tlink); + tcon = tlink_tcon(tlink); + if (pfid && (tcon->ses->server->ops->get_acl_by_fid)) + pntsd = tcon->ses->server->ops->get_acl_by_fid(cifs_sb, pfid, + &acllen); + else if (tcon->ses->server->ops->get_acl) + pntsd = tcon->ses->server->ops->get_acl(cifs_sb, inode, path, + &acllen); + else { + cifs_put_tlink(tlink); + return -EOPNOTSUPP; + } /* if we can retrieve the ACL, now parse Access Control Entries, ACEs */ if (IS_ERR(pntsd)) { rc = PTR_ERR(pntsd); @@ -1030,6 +1043,8 @@ cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr, cifs_dbg(VFS, "parse sec desc failed rc = %d\n", rc); } + cifs_put_tlink(tlink); + return rc; } diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 86dc28c7aa5..cf32f039336 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -398,6 +398,8 @@ struct smb_version_operations { const struct nls_table *, int); struct cifs_ntsd * (*get_acl)(struct cifs_sb_info *, struct inode *, const char *, u32 *); + struct cifs_ntsd * (*get_acl_by_fid)(struct cifs_sb_info *, + const struct cifs_fid *, u32 *); int (*set_acl)(struct cifs_ntsd *, __u32, struct inode *, const char *, int); }; diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index d00e09dfc45..acc4ee8ed07 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -151,7 +151,7 @@ extern struct inode *cifs_iget(struct super_block *sb, extern int cifs_get_inode_info(struct inode **inode, const char *full_path, FILE_ALL_INFO *data, struct super_block *sb, - int xid, const __u16 *fid); + int xid, const struct cifs_fid *fid); extern int cifs_get_inode_info_unix(struct inode **pinode, const unsigned char *search_path, struct super_block *sb, unsigned int xid); @@ -162,11 +162,13 @@ extern int cifs_rename_pending_delete(const char *full_path, const unsigned int xid); extern int cifs_acl_to_fattr(struct cifs_sb_info *cifs_sb, struct cifs_fattr *fattr, struct inode *inode, - const char *path, const __u16 *pfid); + const char *path, const struct cifs_fid *pfid); extern int id_mode_to_cifs_acl(struct inode *inode, const char *path, __u64, kuid_t, kgid_t); extern struct cifs_ntsd *get_cifs_acl(struct cifs_sb_info *, struct inode *, const char *, u32 *); +extern struct cifs_ntsd *get_cifs_acl_by_fid(struct cifs_sb_info *, + const struct cifs_fid *, u32 *); extern int set_cifs_acl(struct cifs_ntsd *, __u32, struct inode *, const char *, int); diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index d3a6796caa5..3db0c5fd9a1 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -378,7 +378,7 @@ cifs_create_get_file_info: xid); else { rc = cifs_get_inode_info(&newinode, full_path, buf, inode->i_sb, - xid, &fid->netfid); + xid, fid); if (newinode) { if (server->ops->set_lease_key) server->ops->set_lease_key(newinode, fid); diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 755584684f6..53c15074bb3 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -244,7 +244,7 @@ cifs_nt_open(char *full_path, struct inode *inode, struct cifs_sb_info *cifs_sb, xid); else rc = cifs_get_inode_info(&inode, full_path, buf, inode->i_sb, - xid, &fid->netfid); + xid, fid); out: kfree(buf); @@ -2389,7 +2389,7 @@ cifs_iovec_write(struct file *file, const struct iovec *iov, unsigned long nr_segs, loff_t *poffset) { unsigned long nr_pages, i; - size_t copied, len, cur_len; + size_t bytes, copied, len, cur_len; ssize_t total_written = 0; loff_t offset; struct iov_iter it; @@ -2444,14 +2444,45 @@ cifs_iovec_write(struct file *file, const struct iovec *iov, save_len = cur_len; for (i = 0; i < nr_pages; i++) { - copied = min_t(const size_t, cur_len, PAGE_SIZE); + bytes = min_t(const size_t, cur_len, PAGE_SIZE); copied = iov_iter_copy_from_user(wdata->pages[i], &it, - 0, copied); + 0, bytes); cur_len -= copied; iov_iter_advance(&it, copied); + /* + * If we didn't copy as much as we expected, then that + * may mean we trod into an unmapped area. Stop copying + * at that point. On the next pass through the big + * loop, we'll likely end up getting a zero-length + * write and bailing out of it. + */ + if (copied < bytes) + break; } cur_len = save_len - cur_len; + /* + * If we have no data to send, then that probably means that + * the copy above failed altogether. That's most likely because + * the address in the iovec was bogus. Set the rc to -EFAULT, + * free anything we allocated and bail out. + */ + if (!cur_len) { + for (i = 0; i < nr_pages; i++) + put_page(wdata->pages[i]); + kfree(wdata); + rc = -EFAULT; + break; + } + + /* + * i + 1 now represents the number of pages we actually used in + * the copy phase above. Bring nr_pages down to that, and free + * any pages that we didn't use. + */ + for ( ; nr_pages > i + 1; nr_pages--) + put_page(wdata->pages[nr_pages - 1]); + wdata->sync_mode = WB_SYNC_ALL; wdata->nr_pages = nr_pages; wdata->offset = (__u64)offset; diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index be58b8fcdb3..aadc2b68678 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -677,7 +677,7 @@ cgfi_exit: int cifs_get_inode_info(struct inode **inode, const char *full_path, FILE_ALL_INFO *data, struct super_block *sb, int xid, - const __u16 *fid) + const struct cifs_fid *fid) { bool validinum = false; __u16 srchflgs; diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c index bfd66d84831..526fb89f923 100644 --- a/fs/cifs/smb1ops.c +++ b/fs/cifs/smb1ops.c @@ -1073,6 +1073,7 @@ struct smb_version_operations smb1_operations = { #endif /* CIFS_XATTR */ #ifdef CONFIG_CIFS_ACL .get_acl = get_cifs_acl, + .get_acl_by_fid = get_cifs_acl_by_fid, .set_acl = set_cifs_acl, #endif /* CIFS_ACL */ }; diff --git a/fs/cifs/smb2glob.h b/fs/cifs/smb2glob.h index c38350851b0..bc0bb9c34f7 100644 --- a/fs/cifs/smb2glob.h +++ b/fs/cifs/smb2glob.h @@ -57,4 +57,7 @@ #define SMB2_CMACAES_SIZE (16) #define SMB3_SIGNKEY_SIZE (16) +/* Maximum buffer size value we can send with 1 credit */ +#define SMB2_MAX_BUFFER_SIZE 65536 + #endif /* _SMB2_GLOB_H */ diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index 757da3e54d3..192f51a12cf 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -182,11 +182,8 @@ smb2_negotiate_wsize(struct cifs_tcon *tcon, struct smb_vol *volume_info) /* start with specified wsize, or default */ wsize = volume_info->wsize ? volume_info->wsize : CIFS_DEFAULT_IOSIZE; wsize = min_t(unsigned int, wsize, server->max_write); - /* - * limit write size to 2 ** 16, because we don't support multicredit - * requests now. - */ - wsize = min_t(unsigned int, wsize, 2 << 15); + /* set it to the maximum buffer size value we can send with 1 credit */ + wsize = min_t(unsigned int, wsize, SMB2_MAX_BUFFER_SIZE); return wsize; } @@ -200,11 +197,8 @@ smb2_negotiate_rsize(struct cifs_tcon *tcon, struct smb_vol *volume_info) /* start with specified rsize, or default */ rsize = volume_info->rsize ? volume_info->rsize : CIFS_DEFAULT_IOSIZE; rsize = min_t(unsigned int, rsize, server->max_read); - /* - * limit write size to 2 ** 16, because we don't support multicredit - * requests now. - */ - rsize = min_t(unsigned int, rsize, 2 << 15); + /* set it to the maximum buffer size value we can send with 1 credit */ + rsize = min_t(unsigned int, rsize, SMB2_MAX_BUFFER_SIZE); return rsize; } diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index a3f7a9c3cc6..86034470106 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c @@ -413,7 +413,9 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses) /* SMB2 only has an extended negflavor */ server->negflavor = CIFS_NEGFLAVOR_EXTENDED; - server->maxBuf = le32_to_cpu(rsp->MaxTransactSize); + /* set it to the maximum buffer size value we can send with 1 credit */ + server->maxBuf = min_t(unsigned int, le32_to_cpu(rsp->MaxTransactSize), + SMB2_MAX_BUFFER_SIZE); server->max_read = le32_to_cpu(rsp->MaxReadSize); server->max_write = le32_to_cpu(rsp->MaxWriteSize); /* BB Do we need to validate the SecurityMode? */ diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index ece55565b9c..d3a534fdc5f 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -771,6 +771,8 @@ do { \ if (EXT4_FITS_IN_INODE(raw_inode, einode, xtime)) \ (einode)->xtime.tv_sec = \ (signed)le32_to_cpu((raw_inode)->xtime); \ + else \ + (einode)->xtime.tv_sec = 0; \ if (EXT4_FITS_IN_INODE(raw_inode, einode, xtime ## _extra)) \ ext4_decode_extra_time(&(einode)->xtime, \ raw_inode->xtime ## _extra); \ diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 10cff4736b1..74bc2d549c5 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -3906,6 +3906,7 @@ ext4_ext_handle_uninitialized_extents(handle_t *handle, struct inode *inode, } else err = ret; map->m_flags |= EXT4_MAP_MAPPED; + map->m_pblk = newblock; if (allocated > map->m_len) allocated = map->m_len; map->m_len = allocated; diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c index 6bea80614d7..a2a837f0040 100644 --- a/fs/ext4/ioctl.c +++ b/fs/ext4/ioctl.c @@ -140,7 +140,7 @@ static long swap_inode_boot_loader(struct super_block *sb, handle = ext4_journal_start(inode_bl, EXT4_HT_MOVE_EXTENTS, 2); if (IS_ERR(handle)) { err = -EINVAL; - goto swap_boot_out; + goto journal_err_out; } /* Protect extent tree against block allocations via delalloc */ @@ -198,6 +198,7 @@ static long swap_inode_boot_loader(struct super_block *sb, ext4_double_up_write_data_sem(inode, inode_bl); +journal_err_out: ext4_inode_resume_unlocked_dio(inode); ext4_inode_resume_unlocked_dio(inode_bl); diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c index c5adbb318a9..f3b84cd9de5 100644 --- a/fs/ext4/resize.c +++ b/fs/ext4/resize.c @@ -243,6 +243,7 @@ static int ext4_alloc_group_tables(struct super_block *sb, ext4_group_t group; ext4_group_t last_group; unsigned overhead; + __u16 uninit_mask = (flexbg_size > 1) ? ~EXT4_BG_BLOCK_UNINIT : ~0; BUG_ON(flex_gd->count == 0 || group_data == NULL); @@ -266,7 +267,7 @@ next_group: src_group++; for (; src_group <= last_group; src_group++) { overhead = ext4_group_overhead_blocks(sb, src_group); - if (overhead != 0) + if (overhead == 0) last_blk += group_data[src_group - group].blocks_count; else break; @@ -280,8 +281,7 @@ next_group: group = ext4_get_group_number(sb, start_blk - 1); group -= group_data[0].group; group_data[group].free_blocks_count--; - if (flexbg_size > 1) - flex_gd->bg_flags[group] &= ~EXT4_BG_BLOCK_UNINIT; + flex_gd->bg_flags[group] &= uninit_mask; } /* Allocate inode bitmaps */ @@ -292,22 +292,30 @@ next_group: group = ext4_get_group_number(sb, start_blk - 1); group -= group_data[0].group; group_data[group].free_blocks_count--; - if (flexbg_size > 1) - flex_gd->bg_flags[group] &= ~EXT4_BG_BLOCK_UNINIT; + flex_gd->bg_flags[group] &= uninit_mask; } /* Allocate inode tables */ for (; it_index < flex_gd->count; it_index++) { - if (start_blk + EXT4_SB(sb)->s_itb_per_group > last_blk) + unsigned int itb = EXT4_SB(sb)->s_itb_per_group; + ext4_fsblk_t next_group_start; + + if (start_blk + itb > last_blk) goto next_group; group_data[it_index].inode_table = start_blk; - group = ext4_get_group_number(sb, start_blk - 1); + group = ext4_get_group_number(sb, start_blk); + next_group_start = ext4_group_first_block_no(sb, group + 1); group -= group_data[0].group; - group_data[group].free_blocks_count -= - EXT4_SB(sb)->s_itb_per_group; - if (flexbg_size > 1) - flex_gd->bg_flags[group] &= ~EXT4_BG_BLOCK_UNINIT; + if (start_blk + itb > next_group_start) { + flex_gd->bg_flags[group + 1] &= uninit_mask; + overhead = start_blk + itb - next_group_start; + group_data[group + 1].free_blocks_count -= overhead; + itb -= overhead; + } + + group_data[group].free_blocks_count -= itb; + flex_gd->bg_flags[group] &= uninit_mask; start_blk += EXT4_SB(sb)->s_itb_per_group; } @@ -401,7 +409,7 @@ static int set_flexbg_block_bitmap(struct super_block *sb, handle_t *handle, start = ext4_group_first_block_no(sb, group); group -= flex_gd->groups[0].group; - count2 = sb->s_blocksize * 8 - (block - start); + count2 = EXT4_BLOCKS_PER_GROUP(sb) - (block - start); if (count2 > count) count2 = count; @@ -620,7 +628,7 @@ handle_ib: if (err) goto out; count = group_table_count[j]; - start = group_data[i].block_bitmap; + start = (&group_data[i].block_bitmap)[j]; block = start; } diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 1f7784de05b..710fed2377d 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -3695,16 +3695,22 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) for (i = 0; i < 4; i++) sbi->s_hash_seed[i] = le32_to_cpu(es->s_hash_seed[i]); sbi->s_def_hash_version = es->s_def_hash_version; - i = le32_to_cpu(es->s_flags); - if (i & EXT2_FLAGS_UNSIGNED_HASH) - sbi->s_hash_unsigned = 3; - else if ((i & EXT2_FLAGS_SIGNED_HASH) == 0) { + if (EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_DIR_INDEX)) { + i = le32_to_cpu(es->s_flags); + if (i & EXT2_FLAGS_UNSIGNED_HASH) + sbi->s_hash_unsigned = 3; + else if ((i & EXT2_FLAGS_SIGNED_HASH) == 0) { #ifdef __CHAR_UNSIGNED__ - es->s_flags |= cpu_to_le32(EXT2_FLAGS_UNSIGNED_HASH); - sbi->s_hash_unsigned = 3; + if (!(sb->s_flags & MS_RDONLY)) + es->s_flags |= + cpu_to_le32(EXT2_FLAGS_UNSIGNED_HASH); + sbi->s_hash_unsigned = 3; #else - es->s_flags |= cpu_to_le32(EXT2_FLAGS_SIGNED_HASH); + if (!(sb->s_flags & MS_RDONLY)) + es->s_flags |= + cpu_to_le32(EXT2_FLAGS_SIGNED_HASH); #endif + } } /* Handle clustersize */ diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index e0259a163f9..d754e3cf99a 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c @@ -40,18 +40,13 @@ struct wb_writeback_work { long nr_pages; struct super_block *sb; - /* - * Write only inodes dirtied before this time. Don't forget to set - * older_than_this_is_set when you set this. - */ - unsigned long older_than_this; + unsigned long *older_than_this; enum writeback_sync_modes sync_mode; unsigned int tagged_writepages:1; unsigned int for_kupdate:1; unsigned int range_cyclic:1; unsigned int for_background:1; unsigned int for_sync:1; /* sync(2) WB_SYNC_ALL writeback */ - unsigned int older_than_this_is_set:1; enum wb_reason reason; /* why was writeback initiated? */ struct list_head list; /* pending work list */ @@ -252,10 +247,10 @@ static int move_expired_inodes(struct list_head *delaying_queue, int do_sb_sort = 0; int moved = 0; - WARN_ON_ONCE(!work->older_than_this_is_set); while (!list_empty(delaying_queue)) { inode = wb_inode(delaying_queue->prev); - if (inode_dirtied_after(inode, work->older_than_this)) + if (work->older_than_this && + inode_dirtied_after(inode, *work->older_than_this)) break; list_move(&inode->i_wb_list, &tmp); moved++; @@ -742,8 +737,6 @@ static long writeback_inodes_wb(struct bdi_writeback *wb, long nr_pages, .sync_mode = WB_SYNC_NONE, .range_cyclic = 1, .reason = reason, - .older_than_this = jiffies, - .older_than_this_is_set = 1, }; spin_lock(&wb->list_lock); @@ -802,13 +795,12 @@ static long wb_writeback(struct bdi_writeback *wb, { unsigned long wb_start = jiffies; long nr_pages = work->nr_pages; + unsigned long oldest_jif; struct inode *inode; long progress; - if (!work->older_than_this_is_set) { - work->older_than_this = jiffies; - work->older_than_this_is_set = 1; - } + oldest_jif = jiffies; + work->older_than_this = &oldest_jif; spin_lock(&wb->list_lock); for (;;) { @@ -842,10 +834,10 @@ static long wb_writeback(struct bdi_writeback *wb, * safe. */ if (work->for_kupdate) { - work->older_than_this = jiffies - + oldest_jif = jiffies - msecs_to_jiffies(dirty_expire_interval * 10); } else if (work->for_background) - work->older_than_this = jiffies; + oldest_jif = jiffies; trace_writeback_start(wb->bdi, work); if (list_empty(&wb->b_io)) @@ -1357,21 +1349,18 @@ EXPORT_SYMBOL(try_to_writeback_inodes_sb); /** * sync_inodes_sb - sync sb inode pages - * @sb: the superblock - * @older_than_this: timestamp + * @sb: the superblock * * This function writes and waits on any dirty inode belonging to this - * superblock that has been dirtied before given timestamp. + * super_block. */ -void sync_inodes_sb(struct super_block *sb, unsigned long older_than_this) +void sync_inodes_sb(struct super_block *sb) { DECLARE_COMPLETION_ONSTACK(done); struct wb_writeback_work work = { .sb = sb, .sync_mode = WB_SYNC_ALL, .nr_pages = LONG_MAX, - .older_than_this = older_than_this, - .older_than_this_is_set = 1, .range_cyclic = 0, .done = &done, .reason = WB_REASON_SYNC, diff --git a/fs/fscache/object-list.c b/fs/fscache/object-list.c index e1959efad64..b5ebc2d7d80 100644 --- a/fs/fscache/object-list.c +++ b/fs/fscache/object-list.c @@ -50,6 +50,8 @@ void fscache_objlist_add(struct fscache_object *obj) struct fscache_object *xobj; struct rb_node **p = &fscache_object_list.rb_node, *parent = NULL; + ASSERT(RB_EMPTY_NODE(&obj->objlist_link)); + write_lock(&fscache_object_list_lock); while (*p) { @@ -75,6 +77,9 @@ void fscache_objlist_add(struct fscache_object *obj) */ void fscache_objlist_remove(struct fscache_object *obj) { + if (RB_EMPTY_NODE(&obj->objlist_link)) + return; + write_lock(&fscache_object_list_lock); BUG_ON(RB_EMPTY_ROOT(&fscache_object_list)); diff --git a/fs/fscache/object.c b/fs/fscache/object.c index 53d35c50424..d3b4539f165 100644 --- a/fs/fscache/object.c +++ b/fs/fscache/object.c @@ -314,6 +314,9 @@ void fscache_object_init(struct fscache_object *object, object->cache = cache; object->cookie = cookie; object->parent = NULL; +#ifdef CONFIG_FSCACHE_OBJECT_LIST + RB_CLEAR_NODE(&object->objlist_link); +#endif object->oob_event_mask = 0; for (t = object->oob_table; t->events; t++) diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c index 8360674c85b..60bb365f54a 100644 --- a/fs/jbd2/transaction.c +++ b/fs/jbd2/transaction.c @@ -514,11 +514,13 @@ int jbd2_journal_start_reserved(handle_t *handle, unsigned int type, * similarly constrained call sites */ ret = start_this_handle(journal, handle, GFP_NOFS); - if (ret < 0) + if (ret < 0) { jbd2_journal_free_reserved(handle); + return ret; + } handle->h_type = type; handle->h_line_no = line_no; - return ret; + return 0; } EXPORT_SYMBOL(jbd2_journal_start_reserved); diff --git a/fs/jfs/acl.c b/fs/jfs/acl.c index e973b85d6af..5a8ea16eedb 100644 --- a/fs/jfs/acl.c +++ b/fs/jfs/acl.c @@ -86,6 +86,8 @@ static int __jfs_set_acl(tid_t tid, struct inode *inode, int type, rc = posix_acl_equiv_mode(acl, &inode->i_mode); if (rc < 0) return rc; + inode->i_ctime = CURRENT_TIME; + mark_inode_dirty(inode); if (rc == 0) acl = NULL; break; diff --git a/fs/kernfs/mount.c b/fs/kernfs/mount.c index 0d6ce895a9e..0f4152defe7 100644 --- a/fs/kernfs/mount.c +++ b/fs/kernfs/mount.c @@ -94,6 +94,7 @@ const void *kernfs_super_ns(struct super_block *sb) * @fs_type: file_system_type of the fs being mounted * @flags: mount flags specified for the mount * @root: kernfs_root of the hierarchy being mounted + * @new_sb_created: tell the caller if we allocated a new superblock * @ns: optional namespace tag of the mount * * This is to be called from each kernfs user's file_system_type->mount() @@ -104,7 +105,8 @@ const void *kernfs_super_ns(struct super_block *sb) * The return value can be passed to the vfs layer verbatim. */ struct dentry *kernfs_mount_ns(struct file_system_type *fs_type, int flags, - struct kernfs_root *root, const void *ns) + struct kernfs_root *root, bool *new_sb_created, + const void *ns) { struct super_block *sb; struct kernfs_super_info *info; @@ -122,6 +124,10 @@ struct dentry *kernfs_mount_ns(struct file_system_type *fs_type, int flags, kfree(info); if (IS_ERR(sb)) return ERR_CAST(sb); + + if (new_sb_created) + *new_sb_created = !sb->s_root; + if (!sb->s_root) { error = kernfs_fill_super(sb); if (error) { diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 28a0a3cbd3b..360114ae8b8 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -164,17 +164,16 @@ static void nfs_zap_caches_locked(struct inode *inode) if (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)) { nfs_fscache_invalidate(inode); nfsi->cache_validity |= NFS_INO_INVALID_ATTR - | NFS_INO_INVALID_LABEL | NFS_INO_INVALID_DATA | NFS_INO_INVALID_ACCESS | NFS_INO_INVALID_ACL | NFS_INO_REVAL_PAGECACHE; } else nfsi->cache_validity |= NFS_INO_INVALID_ATTR - | NFS_INO_INVALID_LABEL | NFS_INO_INVALID_ACCESS | NFS_INO_INVALID_ACL | NFS_INO_REVAL_PAGECACHE; + nfs_zap_label_cache_locked(nfsi); } void nfs_zap_caches(struct inode *inode) @@ -266,6 +265,13 @@ nfs_init_locked(struct inode *inode, void *opaque) } #ifdef CONFIG_NFS_V4_SECURITY_LABEL +static void nfs_clear_label_invalid(struct inode *inode) +{ + spin_lock(&inode->i_lock); + NFS_I(inode)->cache_validity &= ~NFS_INO_INVALID_LABEL; + spin_unlock(&inode->i_lock); +} + void nfs_setsecurity(struct inode *inode, struct nfs_fattr *fattr, struct nfs4_label *label) { @@ -283,6 +289,7 @@ void nfs_setsecurity(struct inode *inode, struct nfs_fattr *fattr, __func__, (char *)label->label, label->len, error); + nfs_clear_label_invalid(inode); } } @@ -1648,7 +1655,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) inode->i_blocks = fattr->du.nfs2.blocks; /* Update attrtimeo value if we're out of the unstable period */ - if (invalid & (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_LABEL)) { + if (invalid & NFS_INO_INVALID_ATTR) { nfs_inc_stats(inode, NFSIOS_ATTRINVALIDATE); nfsi->attrtimeo = NFS_MINATTRTIMEO(inode); nfsi->attrtimeo_timestamp = now; @@ -1661,7 +1668,6 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) } } invalid &= ~NFS_INO_INVALID_ATTR; - invalid &= ~NFS_INO_INVALID_LABEL; /* Don't invalidate the data if we were to blame */ if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode))) diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index 8b5cc04a861..b46cf5a6732 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h @@ -176,7 +176,8 @@ extern struct nfs_server *nfs4_create_server( extern struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *, struct nfs_fh *); extern int nfs4_update_server(struct nfs_server *server, const char *hostname, - struct sockaddr *sap, size_t salen); + struct sockaddr *sap, size_t salen, + struct net *net); extern void nfs_free_server(struct nfs_server *server); extern struct nfs_server *nfs_clone_server(struct nfs_server *, struct nfs_fh *, @@ -279,9 +280,18 @@ static inline void nfs4_label_free(struct nfs4_label *label) } return; } + +static inline void nfs_zap_label_cache_locked(struct nfs_inode *nfsi) +{ + if (nfs_server_capable(&nfsi->vfs_inode, NFS_CAP_SECURITY_LABEL)) + nfsi->cache_validity |= NFS_INO_INVALID_LABEL; +} #else static inline struct nfs4_label *nfs4_label_alloc(struct nfs_server *server, gfp_t flags) { return NULL; } static inline void nfs4_label_free(void *label) {} +static inline void nfs_zap_label_cache_locked(struct nfs_inode *nfsi) +{ +} #endif /* CONFIG_NFS_V4_SECURITY_LABEL */ /* proc.c */ diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c index aa9bc973f36..a462ef0fb5d 100644 --- a/fs/nfs/nfs3proc.c +++ b/fs/nfs/nfs3proc.c @@ -18,6 +18,7 @@ #include <linux/lockd/bind.h> #include <linux/nfs_mount.h> #include <linux/freezer.h> +#include <linux/xattr.h> #include "iostat.h" #include "internal.h" diff --git a/fs/nfs/nfs4client.c b/fs/nfs/nfs4client.c index 860ad26a559..0e46d3d1b6c 100644 --- a/fs/nfs/nfs4client.c +++ b/fs/nfs/nfs4client.c @@ -1135,6 +1135,7 @@ static int nfs_probe_destination(struct nfs_server *server) * @hostname: new end-point's hostname * @sap: new end-point's socket address * @salen: size of "sap" + * @net: net namespace * * The nfs_server must be quiescent before this function is invoked. * Either its session is drained (NFSv4.1+), or its transport is @@ -1143,13 +1144,13 @@ static int nfs_probe_destination(struct nfs_server *server) * Returns zero on success, or a negative errno value. */ int nfs4_update_server(struct nfs_server *server, const char *hostname, - struct sockaddr *sap, size_t salen) + struct sockaddr *sap, size_t salen, struct net *net) { struct nfs_client *clp = server->nfs_client; struct rpc_clnt *clnt = server->client; struct xprt_create xargs = { .ident = clp->cl_proto, - .net = &init_net, + .net = net, .dstaddr = sap, .addrlen = salen, .servername = hostname, @@ -1189,7 +1190,7 @@ int nfs4_update_server(struct nfs_server *server, const char *hostname, error = nfs4_set_client(server, hostname, sap, salen, buf, clp->cl_rpcclient->cl_auth->au_flavor, clp->cl_proto, clnt->cl_timeout, - clp->cl_minorversion, clp->cl_net); + clp->cl_minorversion, net); nfs_put_client(clp); if (error != 0) { nfs_server_insert_lists(server); diff --git a/fs/nfs/nfs4namespace.c b/fs/nfs/nfs4namespace.c index 4e7f05d3e9d..3d5dbf80d46 100644 --- a/fs/nfs/nfs4namespace.c +++ b/fs/nfs/nfs4namespace.c @@ -121,9 +121,8 @@ static int nfs4_validate_fspath(struct dentry *dentry, } static size_t nfs_parse_server_name(char *string, size_t len, - struct sockaddr *sa, size_t salen, struct nfs_server *server) + struct sockaddr *sa, size_t salen, struct net *net) { - struct net *net = rpc_net_ns(server->client); ssize_t ret; ret = rpc_pton(net, string, len, sa, salen); @@ -223,6 +222,7 @@ static struct vfsmount *try_location(struct nfs_clone_mount *mountdata, const struct nfs4_fs_location *location) { const size_t addr_bufsize = sizeof(struct sockaddr_storage); + struct net *net = rpc_net_ns(NFS_SB(mountdata->sb)->client); struct vfsmount *mnt = ERR_PTR(-ENOENT); char *mnt_path; unsigned int maxbuflen; @@ -248,8 +248,7 @@ static struct vfsmount *try_location(struct nfs_clone_mount *mountdata, continue; mountdata->addrlen = nfs_parse_server_name(buf->data, buf->len, - mountdata->addr, addr_bufsize, - NFS_SB(mountdata->sb)); + mountdata->addr, addr_bufsize, net); if (mountdata->addrlen == 0) continue; @@ -419,6 +418,7 @@ static int nfs4_try_replacing_one_location(struct nfs_server *server, const struct nfs4_fs_location *location) { const size_t addr_bufsize = sizeof(struct sockaddr_storage); + struct net *net = rpc_net_ns(server->client); struct sockaddr *sap; unsigned int s; size_t salen; @@ -440,7 +440,7 @@ static int nfs4_try_replacing_one_location(struct nfs_server *server, continue; salen = nfs_parse_server_name(buf->data, buf->len, - sap, addr_bufsize, server); + sap, addr_bufsize, net); if (salen == 0) continue; rpc_set_port(sap, NFS_PORT); @@ -450,7 +450,7 @@ static int nfs4_try_replacing_one_location(struct nfs_server *server, if (hostname == NULL) break; - error = nfs4_update_server(server, hostname, sap, salen); + error = nfs4_update_server(server, hostname, sap, salen, net); kfree(hostname); if (error == 0) break; diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index e5be72518bd..e1a47217c05 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c @@ -1015,8 +1015,11 @@ int nfs4_select_rw_stateid(nfs4_stateid *dst, struct nfs4_state *state, if (ret == -EIO) /* A lost lock - don't even consider delegations */ goto out; - if (nfs4_copy_delegation_stateid(dst, state->inode, fmode)) + /* returns true if delegation stateid found and copied */ + if (nfs4_copy_delegation_stateid(dst, state->inode, fmode)) { + ret = 0; goto out; + } if (ret != -ENOENT) /* nfs4_copy_delegation_stateid() didn't over-write * dst, so it still has the lock stateid which we now diff --git a/fs/notify/dnotify/dnotify.c b/fs/notify/dnotify/dnotify.c index 0b9ff4395e6..abc8cbcfe90 100644 --- a/fs/notify/dnotify/dnotify.c +++ b/fs/notify/dnotify/dnotify.c @@ -86,7 +86,7 @@ static int dnotify_handle_event(struct fsnotify_group *group, struct fsnotify_mark *inode_mark, struct fsnotify_mark *vfsmount_mark, u32 mask, void *data, int data_type, - const unsigned char *file_name) + const unsigned char *file_name, u32 cookie) { struct dnotify_mark *dn_mark; struct dnotify_struct *dn; diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c index 0e792f5e314..dc638f786d5 100644 --- a/fs/notify/fanotify/fanotify.c +++ b/fs/notify/fanotify/fanotify.c @@ -147,7 +147,7 @@ static int fanotify_handle_event(struct fsnotify_group *group, struct fsnotify_mark *inode_mark, struct fsnotify_mark *fanotify_mark, u32 mask, void *data, int data_type, - const unsigned char *file_name) + const unsigned char *file_name, u32 cookie) { int ret = 0; struct fanotify_event_info *event; @@ -192,10 +192,12 @@ static int fanotify_handle_event(struct fsnotify_group *group, ret = fsnotify_add_notify_event(group, fsn_event, fanotify_merge); if (ret) { - BUG_ON(mask & FAN_ALL_PERM_EVENTS); + /* Permission events shouldn't be merged */ + BUG_ON(ret == 1 && mask & FAN_ALL_PERM_EVENTS); /* Our event wasn't used in the end. Free it. */ fsnotify_destroy_event(group, fsn_event); - ret = 0; + + return 0; } #ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c index b6175fa11bf..287a22c0414 100644 --- a/fs/notify/fanotify/fanotify_user.c +++ b/fs/notify/fanotify/fanotify_user.c @@ -698,6 +698,7 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags) struct fsnotify_group *group; int f_flags, fd; struct user_struct *user; + struct fanotify_event_info *oevent; pr_debug("%s: flags=%d event_f_flags=%d\n", __func__, flags, event_f_flags); @@ -730,8 +731,20 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags) group->fanotify_data.user = user; atomic_inc(&user->fanotify_listeners); + oevent = kmem_cache_alloc(fanotify_event_cachep, GFP_KERNEL); + if (unlikely(!oevent)) { + fd = -ENOMEM; + goto out_destroy_group; + } + group->overflow_event = &oevent->fse; + fsnotify_init_event(group->overflow_event, NULL, FS_Q_OVERFLOW); + oevent->tgid = get_pid(task_tgid(current)); + oevent->path.mnt = NULL; + oevent->path.dentry = NULL; + group->fanotify_data.f_flags = event_f_flags; #ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS + oevent->response = 0; mutex_init(&group->fanotify_data.access_mutex); init_waitqueue_head(&group->fanotify_data.access_waitq); INIT_LIST_HEAD(&group->fanotify_data.access_list); diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c index 1d4e1ea2f37..9d3e9c50066 100644 --- a/fs/notify/fsnotify.c +++ b/fs/notify/fsnotify.c @@ -179,7 +179,7 @@ static int send_to_group(struct inode *to_tell, return group->ops->handle_event(group, to_tell, inode_mark, vfsmount_mark, mask, data, data_is, - file_name); + file_name, cookie); } /* diff --git a/fs/notify/group.c b/fs/notify/group.c index ee674fe2cec..ad199598045 100644 --- a/fs/notify/group.c +++ b/fs/notify/group.c @@ -55,6 +55,13 @@ void fsnotify_destroy_group(struct fsnotify_group *group) /* clear the notification queue of all events */ fsnotify_flush_notify(group); + /* + * Destroy overflow event (we cannot use fsnotify_destroy_event() as + * that deliberately ignores overflow events. + */ + if (group->overflow_event) + group->ops->free_event(group->overflow_event); + fsnotify_put_group(group); } @@ -99,7 +106,6 @@ struct fsnotify_group *fsnotify_alloc_group(const struct fsnotify_ops *ops) INIT_LIST_HEAD(&group->marks_list); group->ops = ops; - fsnotify_init_event(&group->overflow_event, NULL, FS_Q_OVERFLOW); return group; } diff --git a/fs/notify/inotify/inotify.h b/fs/notify/inotify/inotify.h index 485eef3f440..ed855ef6f07 100644 --- a/fs/notify/inotify/inotify.h +++ b/fs/notify/inotify/inotify.h @@ -27,6 +27,6 @@ extern int inotify_handle_event(struct fsnotify_group *group, struct fsnotify_mark *inode_mark, struct fsnotify_mark *vfsmount_mark, u32 mask, void *data, int data_type, - const unsigned char *file_name); + const unsigned char *file_name, u32 cookie); extern const struct fsnotify_ops inotify_fsnotify_ops; diff --git a/fs/notify/inotify/inotify_fsnotify.c b/fs/notify/inotify/inotify_fsnotify.c index d5ee56348bb..43ab1e1a07a 100644 --- a/fs/notify/inotify/inotify_fsnotify.c +++ b/fs/notify/inotify/inotify_fsnotify.c @@ -67,7 +67,7 @@ int inotify_handle_event(struct fsnotify_group *group, struct fsnotify_mark *inode_mark, struct fsnotify_mark *vfsmount_mark, u32 mask, void *data, int data_type, - const unsigned char *file_name) + const unsigned char *file_name, u32 cookie) { struct inotify_inode_mark *i_mark; struct inotify_event_info *event; @@ -103,6 +103,7 @@ int inotify_handle_event(struct fsnotify_group *group, fsn_event = &event->fse; fsnotify_init_event(fsn_event, inode, mask); event->wd = i_mark->wd; + event->sync_cookie = cookie; event->name_len = len; if (len) strcpy(event->name, file_name); diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c index 497395c8274..78a2ca3966c 100644 --- a/fs/notify/inotify/inotify_user.c +++ b/fs/notify/inotify/inotify_user.c @@ -495,7 +495,7 @@ void inotify_ignored_and_remove_idr(struct fsnotify_mark *fsn_mark, /* Queue ignore event for the watch */ inotify_handle_event(group, NULL, fsn_mark, NULL, FS_IN_IGNORED, - NULL, FSNOTIFY_EVENT_NONE, NULL); + NULL, FSNOTIFY_EVENT_NONE, NULL, 0); i_mark = container_of(fsn_mark, struct inotify_inode_mark, fsn_mark); /* remove this mark from the idr */ @@ -633,11 +633,23 @@ static int inotify_update_watch(struct fsnotify_group *group, struct inode *inod static struct fsnotify_group *inotify_new_group(unsigned int max_events) { struct fsnotify_group *group; + struct inotify_event_info *oevent; group = fsnotify_alloc_group(&inotify_fsnotify_ops); if (IS_ERR(group)) return group; + oevent = kmalloc(sizeof(struct inotify_event_info), GFP_KERNEL); + if (unlikely(!oevent)) { + fsnotify_destroy_group(group); + return ERR_PTR(-ENOMEM); + } + group->overflow_event = &oevent->fse; + fsnotify_init_event(group->overflow_event, NULL, FS_Q_OVERFLOW); + oevent->wd = -1; + oevent->sync_cookie = 0; + oevent->name_len = 0; + group->max_events = max_events; spin_lock_init(&group->inotify_data.idr_lock); diff --git a/fs/notify/notification.c b/fs/notify/notification.c index 18b3c4427dc..1e58402171a 100644 --- a/fs/notify/notification.c +++ b/fs/notify/notification.c @@ -80,7 +80,8 @@ void fsnotify_destroy_event(struct fsnotify_group *group, /* * Add an event to the group notification queue. The group can later pull this * event off the queue to deal with. The function returns 0 if the event was - * added to the queue, 1 if the event was merged with some other queued event. + * added to the queue, 1 if the event was merged with some other queued event, + * 2 if the queue of events has overflown. */ int fsnotify_add_notify_event(struct fsnotify_group *group, struct fsnotify_event *event, @@ -95,10 +96,14 @@ int fsnotify_add_notify_event(struct fsnotify_group *group, mutex_lock(&group->notification_mutex); if (group->q_len >= group->max_events) { + ret = 2; /* Queue overflow event only if it isn't already queued */ - if (list_empty(&group->overflow_event.list)) - event = &group->overflow_event; - ret = 1; + if (!list_empty(&group->overflow_event->list)) { + mutex_unlock(&group->notification_mutex); + return ret; + } + event = group->overflow_event; + goto queue; } if (!list_empty(list) && merge) { @@ -109,6 +114,7 @@ int fsnotify_add_notify_event(struct fsnotify_group *group, } } +queue: group->q_len++; list_add_tail(&event->list, list); mutex_unlock(&group->notification_mutex); @@ -132,7 +138,11 @@ struct fsnotify_event *fsnotify_remove_notify_event(struct fsnotify_group *group event = list_first_entry(&group->notification_list, struct fsnotify_event, list); - list_del(&event->list); + /* + * We need to init list head for the case of overflow event so that + * check in fsnotify_add_notify_events() works + */ + list_del_init(&event->list); group->q_len--; return event; diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c index 831d49a4111..cfc8dcc1604 100644 --- a/fs/quota/dquot.c +++ b/fs/quota/dquot.c @@ -581,9 +581,17 @@ int dquot_scan_active(struct super_block *sb, dqstats_inc(DQST_LOOKUPS); dqput(old_dquot); old_dquot = dquot; - ret = fn(dquot, priv); - if (ret < 0) - goto out; + /* + * ->release_dquot() can be racing with us. Our reference + * protects us from new calls to it so just wait for any + * outstanding call and recheck the DQ_ACTIVE_B after that. + */ + wait_on_dquot(dquot); + if (test_bit(DQ_ACTIVE_B, &dquot->dq_flags)) { + ret = fn(dquot, priv); + if (ret < 0) + goto out; + } spin_lock(&dq_list_lock); /* We are safe to continue now because our dquot could not * be moved out of the inuse list while we hold the reference */ diff --git a/fs/reiserfs/do_balan.c b/fs/reiserfs/do_balan.c index 2b7882b508d..9a3c68cf602 100644 --- a/fs/reiserfs/do_balan.c +++ b/fs/reiserfs/do_balan.c @@ -324,23 +324,17 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h switch (flag) { case M_INSERT: /* insert item into L[0] */ - if (item_pos == tb->lnum[0] - 1 - && tb->lbytes != -1) { + if (item_pos == tb->lnum[0] - 1 && tb->lbytes != -1) { /* part of new item falls into L[0] */ int new_item_len; int version; - ret_val = - leaf_shift_left(tb, tb->lnum[0] - 1, - -1); + ret_val = leaf_shift_left(tb, tb->lnum[0] - 1, -1); /* Calculate item length to insert to S[0] */ - new_item_len = - ih_item_len(ih) - tb->lbytes; + new_item_len = ih_item_len(ih) - tb->lbytes; /* Calculate and check item length to insert to L[0] */ - put_ih_item_len(ih, - ih_item_len(ih) - - new_item_len); + put_ih_item_len(ih, ih_item_len(ih) - new_item_len); RFALSE(ih_item_len(ih) <= 0, "PAP-12080: there is nothing to insert into L[0]: ih_item_len=%d", @@ -349,30 +343,18 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h /* Insert new item into L[0] */ buffer_info_init_left(tb, &bi); leaf_insert_into_buf(&bi, - n + item_pos - - ret_val, ih, body, - zeros_num > - ih_item_len(ih) ? - ih_item_len(ih) : - zeros_num); + n + item_pos - ret_val, ih, body, + zeros_num > ih_item_len(ih) ? ih_item_len(ih) : zeros_num); version = ih_version(ih); /* Calculate key component, item length and body to insert into S[0] */ - set_le_ih_k_offset(ih, - le_ih_k_offset(ih) + - (tb-> - lbytes << - (is_indirect_le_ih - (ih) ? tb->tb_sb-> - s_blocksize_bits - - UNFM_P_SHIFT : - 0))); + set_le_ih_k_offset(ih, le_ih_k_offset(ih) + + (tb-> lbytes << (is_indirect_le_ih(ih) ? tb->tb_sb-> s_blocksize_bits - UNFM_P_SHIFT : 0))); put_ih_item_len(ih, new_item_len); if (tb->lbytes > zeros_num) { - body += - (tb->lbytes - zeros_num); + body += (tb->lbytes - zeros_num); zeros_num = 0; } else zeros_num -= tb->lbytes; @@ -383,15 +365,10 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h } else { /* new item in whole falls into L[0] */ /* Shift lnum[0]-1 items to L[0] */ - ret_val = - leaf_shift_left(tb, tb->lnum[0] - 1, - tb->lbytes); + ret_val = leaf_shift_left(tb, tb->lnum[0] - 1, tb->lbytes); /* Insert new item into L[0] */ buffer_info_init_left(tb, &bi); - leaf_insert_into_buf(&bi, - n + item_pos - - ret_val, ih, body, - zeros_num); + leaf_insert_into_buf(&bi, n + item_pos - ret_val, ih, body, zeros_num); tb->insert_size[0] = 0; zeros_num = 0; } @@ -399,264 +376,117 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h case M_PASTE: /* append item in L[0] */ - if (item_pos == tb->lnum[0] - 1 - && tb->lbytes != -1) { + if (item_pos == tb->lnum[0] - 1 && tb->lbytes != -1) { /* we must shift the part of the appended item */ - if (is_direntry_le_ih - (B_N_PITEM_HEAD(tbS0, item_pos))) { + if (is_direntry_le_ih(B_N_PITEM_HEAD(tbS0, item_pos))) { RFALSE(zeros_num, "PAP-12090: invalid parameter in case of a directory"); /* directory item */ if (tb->lbytes > pos_in_item) { /* new directory entry falls into L[0] */ - struct item_head - *pasted; - int l_pos_in_item = - pos_in_item; + struct item_head *pasted; + int l_pos_in_item = pos_in_item; /* Shift lnum[0] - 1 items in whole. Shift lbytes - 1 entries from given directory item */ - ret_val = - leaf_shift_left(tb, - tb-> - lnum - [0], - tb-> - lbytes - - - 1); - if (ret_val - && !item_pos) { - pasted = - B_N_PITEM_HEAD - (tb->L[0], - B_NR_ITEMS - (tb-> - L[0]) - - 1); - l_pos_in_item += - I_ENTRY_COUNT - (pasted) - - (tb-> - lbytes - - 1); + ret_val = leaf_shift_left(tb, tb->lnum[0], tb->lbytes-1); + if (ret_val && !item_pos) { + pasted = B_N_PITEM_HEAD(tb->L[0], B_NR_ITEMS(tb->L[0]) - 1); + l_pos_in_item += I_ENTRY_COUNT(pasted) - (tb->lbytes -1); } /* Append given directory entry to directory item */ buffer_info_init_left(tb, &bi); - leaf_paste_in_buffer - (&bi, - n + item_pos - - ret_val, - l_pos_in_item, - tb->insert_size[0], - body, zeros_num); + leaf_paste_in_buffer(&bi, n + item_pos - ret_val, l_pos_in_item, tb->insert_size[0], body, zeros_num); /* previous string prepared space for pasting new entry, following string pastes this entry */ /* when we have merge directory item, pos_in_item has been changed too */ /* paste new directory entry. 1 is entry number */ - leaf_paste_entries(&bi, - n + - item_pos - - - ret_val, - l_pos_in_item, - 1, - (struct - reiserfs_de_head - *) - body, - body - + - DEH_SIZE, - tb-> - insert_size - [0] - ); + leaf_paste_entries(&bi, n + item_pos - ret_val, l_pos_in_item, + 1, (struct reiserfs_de_head *) body, + body + DEH_SIZE, tb->insert_size[0]); tb->insert_size[0] = 0; } else { /* new directory item doesn't fall into L[0] */ /* Shift lnum[0]-1 items in whole. Shift lbytes directory entries from directory item number lnum[0] */ - leaf_shift_left(tb, - tb-> - lnum[0], - tb-> - lbytes); + leaf_shift_left(tb, tb->lnum[0], tb->lbytes); } /* Calculate new position to append in item body */ pos_in_item -= tb->lbytes; } else { /* regular object */ - RFALSE(tb->lbytes <= 0, - "PAP-12095: there is nothing to shift to L[0]. lbytes=%d", - tb->lbytes); - RFALSE(pos_in_item != - ih_item_len - (B_N_PITEM_HEAD - (tbS0, item_pos)), + RFALSE(tb->lbytes <= 0, "PAP-12095: there is nothing to shift to L[0]. lbytes=%d", tb->lbytes); + RFALSE(pos_in_item != ih_item_len(B_N_PITEM_HEAD(tbS0, item_pos)), "PAP-12100: incorrect position to paste: item_len=%d, pos_in_item=%d", - ih_item_len - (B_N_PITEM_HEAD - (tbS0, item_pos)), - pos_in_item); + ih_item_len(B_N_PITEM_HEAD(tbS0, item_pos)),pos_in_item); if (tb->lbytes >= pos_in_item) { /* appended item will be in L[0] in whole */ int l_n; /* this bytes number must be appended to the last item of L[h] */ - l_n = - tb->lbytes - - pos_in_item; + l_n = tb->lbytes - pos_in_item; /* Calculate new insert_size[0] */ - tb->insert_size[0] -= - l_n; + tb->insert_size[0] -= l_n; - RFALSE(tb-> - insert_size[0] <= - 0, + RFALSE(tb->insert_size[0] <= 0, "PAP-12105: there is nothing to paste into L[0]. insert_size=%d", - tb-> - insert_size[0]); - ret_val = - leaf_shift_left(tb, - tb-> - lnum - [0], - ih_item_len - (B_N_PITEM_HEAD - (tbS0, - item_pos))); + tb->insert_size[0]); + ret_val = leaf_shift_left(tb, tb->lnum[0], ih_item_len + (B_N_PITEM_HEAD(tbS0, item_pos))); /* Append to body of item in L[0] */ buffer_info_init_left(tb, &bi); leaf_paste_in_buffer - (&bi, - n + item_pos - - ret_val, - ih_item_len - (B_N_PITEM_HEAD - (tb->L[0], - n + item_pos - - ret_val)), l_n, - body, - zeros_num > - l_n ? l_n : - zeros_num); + (&bi, n + item_pos - ret_val, ih_item_len + (B_N_PITEM_HEAD(tb->L[0], n + item_pos - ret_val)), + l_n, body, + zeros_num > l_n ? l_n : zeros_num); /* 0-th item in S0 can be only of DIRECT type when l_n != 0 */ { int version; - int temp_l = - l_n; - - RFALSE - (ih_item_len - (B_N_PITEM_HEAD - (tbS0, - 0)), + int temp_l = l_n; + + RFALSE(ih_item_len(B_N_PITEM_HEAD(tbS0, 0)), "PAP-12106: item length must be 0"); - RFALSE - (comp_short_le_keys - (B_N_PKEY - (tbS0, 0), - B_N_PKEY - (tb->L[0], - n + - item_pos - - - ret_val)), + RFALSE(comp_short_le_keys(B_N_PKEY(tbS0, 0), B_N_PKEY + (tb->L[0], n + item_pos - ret_val)), "PAP-12107: items must be of the same file"); if (is_indirect_le_ih(B_N_PITEM_HEAD(tb->L[0], n + item_pos - ret_val))) { - temp_l = - l_n - << - (tb-> - tb_sb-> - s_blocksize_bits - - - UNFM_P_SHIFT); + temp_l = l_n << (tb->tb_sb-> s_blocksize_bits - UNFM_P_SHIFT); } /* update key of first item in S0 */ - version = - ih_version - (B_N_PITEM_HEAD - (tbS0, 0)); - set_le_key_k_offset - (version, - B_N_PKEY - (tbS0, 0), - le_key_k_offset - (version, - B_N_PKEY - (tbS0, - 0)) + - temp_l); + version = ih_version(B_N_PITEM_HEAD(tbS0, 0)); + set_le_key_k_offset(version, B_N_PKEY(tbS0, 0), + le_key_k_offset(version,B_N_PKEY(tbS0, 0)) + temp_l); /* update left delimiting key */ - set_le_key_k_offset - (version, - B_N_PDELIM_KEY - (tb-> - CFL[0], - tb-> - lkey[0]), - le_key_k_offset - (version, - B_N_PDELIM_KEY - (tb-> - CFL[0], - tb-> - lkey[0])) - + temp_l); + set_le_key_k_offset(version, B_N_PDELIM_KEY(tb->CFL[0], tb->lkey[0]), + le_key_k_offset(version, B_N_PDELIM_KEY(tb->CFL[0], tb->lkey[0])) + temp_l); } /* Calculate new body, position in item and insert_size[0] */ if (l_n > zeros_num) { - body += - (l_n - - zeros_num); + body += (l_n - zeros_num); zeros_num = 0; } else - zeros_num -= - l_n; + zeros_num -= l_n; pos_in_item = 0; - RFALSE - (comp_short_le_keys - (B_N_PKEY(tbS0, 0), - B_N_PKEY(tb->L[0], - B_NR_ITEMS - (tb-> - L[0]) - - 1)) - || - !op_is_left_mergeable - (B_N_PKEY(tbS0, 0), - tbS0->b_size) - || - !op_is_left_mergeable - (B_N_PDELIM_KEY - (tb->CFL[0], - tb->lkey[0]), - tbS0->b_size), + RFALSE(comp_short_le_keys(B_N_PKEY(tbS0, 0), B_N_PKEY(tb->L[0], B_NR_ITEMS(tb->L[0]) - 1)) + || !op_is_left_mergeable(B_N_PKEY(tbS0, 0), tbS0->b_size) + || !op_is_left_mergeable(B_N_PDELIM_KEY(tb->CFL[0], tb->lkey[0]), tbS0->b_size), "PAP-12120: item must be merge-able with left neighboring item"); } else { /* only part of the appended item will be in L[0] */ /* Calculate position in item for append in S[0] */ - pos_in_item -= - tb->lbytes; + pos_in_item -= tb->lbytes; - RFALSE(pos_in_item <= 0, - "PAP-12125: no place for paste. pos_in_item=%d", - pos_in_item); + RFALSE(pos_in_item <= 0, "PAP-12125: no place for paste. pos_in_item=%d", pos_in_item); /* Shift lnum[0] - 1 items in whole. Shift lbytes - 1 byte from item number lnum[0] */ - leaf_shift_left(tb, - tb-> - lnum[0], - tb-> - lbytes); + leaf_shift_left(tb, tb->lnum[0], tb->lbytes); } } } else { /* appended item will be in L[0] in whole */ @@ -665,52 +495,30 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h if (!item_pos && op_is_left_mergeable(B_N_PKEY(tbS0, 0), tbS0->b_size)) { /* if we paste into first item of S[0] and it is left mergable */ /* then increment pos_in_item by the size of the last item in L[0] */ - pasted = - B_N_PITEM_HEAD(tb->L[0], - n - 1); + pasted = B_N_PITEM_HEAD(tb->L[0], n - 1); if (is_direntry_le_ih(pasted)) - pos_in_item += - ih_entry_count - (pasted); + pos_in_item += ih_entry_count(pasted); else - pos_in_item += - ih_item_len(pasted); + pos_in_item += ih_item_len(pasted); } /* Shift lnum[0] - 1 items in whole. Shift lbytes - 1 byte from item number lnum[0] */ - ret_val = - leaf_shift_left(tb, tb->lnum[0], - tb->lbytes); + ret_val = leaf_shift_left(tb, tb->lnum[0], tb->lbytes); /* Append to body of item in L[0] */ buffer_info_init_left(tb, &bi); - leaf_paste_in_buffer(&bi, - n + item_pos - - ret_val, + leaf_paste_in_buffer(&bi, n + item_pos - ret_val, pos_in_item, tb->insert_size[0], body, zeros_num); /* if appended item is directory, paste entry */ - pasted = - B_N_PITEM_HEAD(tb->L[0], - n + item_pos - - ret_val); + pasted = B_N_PITEM_HEAD(tb->L[0], n + item_pos - ret_val); if (is_direntry_le_ih(pasted)) - leaf_paste_entries(&bi, - n + - item_pos - - ret_val, - pos_in_item, - 1, - (struct - reiserfs_de_head - *)body, - body + - DEH_SIZE, - tb-> - insert_size - [0] - ); + leaf_paste_entries(&bi, n + item_pos - ret_val, + pos_in_item, 1, + (struct reiserfs_de_head *) body, + body + DEH_SIZE, + tb->insert_size[0]); /* if appended item is indirect item, put unformatted node into un list */ if (is_indirect_le_ih(pasted)) set_ih_free_space(pasted, 0); @@ -722,13 +530,7 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h reiserfs_panic(tb->tb_sb, "PAP-12130", "lnum > 0: unexpected mode: " " %s(%d)", - (flag == - M_DELETE) ? "DELETE" : ((flag == - M_CUT) - ? "CUT" - : - "UNKNOWN"), - flag); + (flag == M_DELETE) ? "DELETE" : ((flag == M_CUT) ? "CUT" : "UNKNOWN"), flag); } } else { /* new item doesn't fall into L[0] */ @@ -748,14 +550,12 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h case M_INSERT: /* insert item */ if (n - tb->rnum[0] < item_pos) { /* new item or its part falls to R[0] */ if (item_pos == n - tb->rnum[0] + 1 && tb->rbytes != -1) { /* part of new item falls into R[0] */ - loff_t old_key_comp, old_len, - r_zeros_number; + loff_t old_key_comp, old_len, r_zeros_number; const char *r_body; int version; loff_t offset; - leaf_shift_right(tb, tb->rnum[0] - 1, - -1); + leaf_shift_right(tb, tb->rnum[0] - 1, -1); version = ih_version(ih); /* Remember key component and item length */ @@ -763,29 +563,17 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h old_len = ih_item_len(ih); /* Calculate key component and item length to insert into R[0] */ - offset = - le_ih_k_offset(ih) + - ((old_len - - tb-> - rbytes) << (is_indirect_le_ih(ih) - ? tb->tb_sb-> - s_blocksize_bits - - UNFM_P_SHIFT : 0)); + offset = le_ih_k_offset(ih) + ((old_len - tb->rbytes) << (is_indirect_le_ih(ih) ? tb->tb_sb->s_blocksize_bits - UNFM_P_SHIFT : 0)); set_le_ih_k_offset(ih, offset); put_ih_item_len(ih, tb->rbytes); /* Insert part of the item into R[0] */ buffer_info_init_right(tb, &bi); if ((old_len - tb->rbytes) > zeros_num) { r_zeros_number = 0; - r_body = - body + (old_len - - tb->rbytes) - - zeros_num; + r_body = body + (old_len - tb->rbytes) - zeros_num; } else { r_body = body; - r_zeros_number = - zeros_num - (old_len - - tb->rbytes); + r_zeros_number = zeros_num - (old_len - tb->rbytes); zeros_num -= r_zeros_number; } @@ -798,25 +586,18 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h /* Calculate key component and item length to insert into S[0] */ set_le_ih_k_offset(ih, old_key_comp); - put_ih_item_len(ih, - old_len - tb->rbytes); + put_ih_item_len(ih, old_len - tb->rbytes); tb->insert_size[0] -= tb->rbytes; } else { /* whole new item falls into R[0] */ /* Shift rnum[0]-1 items to R[0] */ - ret_val = - leaf_shift_right(tb, - tb->rnum[0] - 1, - tb->rbytes); + ret_val = leaf_shift_right(tb, tb->rnum[0] - 1, tb->rbytes); /* Insert new item into R[0] */ buffer_info_init_right(tb, &bi); - leaf_insert_into_buf(&bi, - item_pos - n + - tb->rnum[0] - 1, - ih, body, - zeros_num); + leaf_insert_into_buf(&bi, item_pos - n + tb->rnum[0] - 1, + ih, body, zeros_num); if (item_pos - n + tb->rnum[0] - 1 == 0) { replace_key(tb, tb->CFR[0], @@ -841,200 +622,97 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h RFALSE(zeros_num, "PAP-12145: invalid parameter in case of a directory"); - entry_count = - I_ENTRY_COUNT(B_N_PITEM_HEAD - (tbS0, - item_pos)); + entry_count = I_ENTRY_COUNT(B_N_PITEM_HEAD + (tbS0, item_pos)); if (entry_count - tb->rbytes < pos_in_item) /* new directory entry falls into R[0] */ { int paste_entry_position; - RFALSE(tb->rbytes - 1 >= - entry_count - || !tb-> - insert_size[0], + RFALSE(tb->rbytes - 1 >= entry_count || !tb-> insert_size[0], "PAP-12150: no enough of entries to shift to R[0]: rbytes=%d, entry_count=%d", - tb->rbytes, - entry_count); + tb->rbytes, entry_count); /* Shift rnum[0]-1 items in whole. Shift rbytes-1 directory entries from directory item number rnum[0] */ - leaf_shift_right(tb, - tb-> - rnum - [0], - tb-> - rbytes - - 1); + leaf_shift_right(tb, tb->rnum[0], tb->rbytes - 1); /* Paste given directory entry to directory item */ - paste_entry_position = - pos_in_item - - entry_count + - tb->rbytes - 1; + paste_entry_position = pos_in_item - entry_count + tb->rbytes - 1; buffer_info_init_right(tb, &bi); - leaf_paste_in_buffer - (&bi, 0, - paste_entry_position, - tb->insert_size[0], - body, zeros_num); + leaf_paste_in_buffer(&bi, 0, paste_entry_position, tb->insert_size[0], body, zeros_num); /* paste entry */ - leaf_paste_entries(&bi, - 0, - paste_entry_position, - 1, - (struct - reiserfs_de_head - *) - body, - body - + - DEH_SIZE, - tb-> - insert_size - [0] - ); - - if (paste_entry_position - == 0) { + leaf_paste_entries(&bi, 0, paste_entry_position, 1, + (struct reiserfs_de_head *) body, + body + DEH_SIZE, tb->insert_size[0]); + + if (paste_entry_position == 0) { /* change delimiting keys */ - replace_key(tb, - tb-> - CFR - [0], - tb-> - rkey - [0], - tb-> - R - [0], - 0); + replace_key(tb, tb->CFR[0], tb->rkey[0], tb->R[0],0); } tb->insert_size[0] = 0; pos_in_item++; } else { /* new directory entry doesn't fall into R[0] */ - leaf_shift_right(tb, - tb-> - rnum - [0], - tb-> - rbytes); + leaf_shift_right(tb, tb->rnum[0], tb->rbytes); } } else { /* regular object */ - int n_shift, n_rem, - r_zeros_number; + int n_shift, n_rem, r_zeros_number; const char *r_body; /* Calculate number of bytes which must be shifted from appended item */ - if ((n_shift = - tb->rbytes - - tb->insert_size[0]) < 0) + if ((n_shift = tb->rbytes - tb->insert_size[0]) < 0) n_shift = 0; - RFALSE(pos_in_item != - ih_item_len - (B_N_PITEM_HEAD - (tbS0, item_pos)), + RFALSE(pos_in_item != ih_item_len + (B_N_PITEM_HEAD(tbS0, item_pos)), "PAP-12155: invalid position to paste. ih_item_len=%d, pos_in_item=%d", - pos_in_item, - ih_item_len - (B_N_PITEM_HEAD - (tbS0, item_pos))); - - leaf_shift_right(tb, - tb->rnum[0], - n_shift); + pos_in_item, ih_item_len + (B_N_PITEM_HEAD(tbS0, item_pos))); + + leaf_shift_right(tb, tb->rnum[0], n_shift); /* Calculate number of bytes which must remain in body after appending to R[0] */ - if ((n_rem = - tb->insert_size[0] - - tb->rbytes) < 0) + if ((n_rem = tb->insert_size[0] - tb->rbytes) < 0) n_rem = 0; { int version; - unsigned long temp_rem = - n_rem; - - version = - ih_version - (B_N_PITEM_HEAD - (tb->R[0], 0)); - if (is_indirect_le_key - (version, - B_N_PKEY(tb->R[0], - 0))) { - temp_rem = - n_rem << - (tb->tb_sb-> - s_blocksize_bits - - - UNFM_P_SHIFT); + unsigned long temp_rem = n_rem; + + version = ih_version(B_N_PITEM_HEAD(tb->R[0], 0)); + if (is_indirect_le_key(version, B_N_PKEY(tb->R[0], 0))) { + temp_rem = n_rem << (tb->tb_sb->s_blocksize_bits - UNFM_P_SHIFT); } - set_le_key_k_offset - (version, - B_N_PKEY(tb->R[0], - 0), - le_key_k_offset - (version, - B_N_PKEY(tb->R[0], - 0)) + - temp_rem); - set_le_key_k_offset - (version, - B_N_PDELIM_KEY(tb-> - CFR - [0], - tb-> - rkey - [0]), - le_key_k_offset - (version, - B_N_PDELIM_KEY - (tb->CFR[0], - tb->rkey[0])) + - temp_rem); + set_le_key_k_offset(version, B_N_PKEY(tb->R[0], 0), + le_key_k_offset(version, B_N_PKEY(tb->R[0], 0)) + temp_rem); + set_le_key_k_offset(version, B_N_PDELIM_KEY(tb->CFR[0], tb->rkey[0]), + le_key_k_offset(version, B_N_PDELIM_KEY(tb->CFR[0], tb->rkey[0])) + temp_rem); } /* k_offset (B_N_PKEY(tb->R[0],0)) += n_rem; k_offset (B_N_PDELIM_KEY(tb->CFR[0],tb->rkey[0])) += n_rem;*/ - do_balance_mark_internal_dirty - (tb, tb->CFR[0], 0); + do_balance_mark_internal_dirty(tb, tb->CFR[0], 0); /* Append part of body into R[0] */ buffer_info_init_right(tb, &bi); if (n_rem > zeros_num) { r_zeros_number = 0; - r_body = - body + n_rem - - zeros_num; + r_body = body + n_rem - zeros_num; } else { r_body = body; - r_zeros_number = - zeros_num - n_rem; - zeros_num -= - r_zeros_number; + r_zeros_number = zeros_num - n_rem; + zeros_num -= r_zeros_number; } - leaf_paste_in_buffer(&bi, 0, - n_shift, - tb-> - insert_size - [0] - - n_rem, - r_body, - r_zeros_number); - - if (is_indirect_le_ih - (B_N_PITEM_HEAD - (tb->R[0], 0))) { + leaf_paste_in_buffer(&bi, 0, n_shift, + tb->insert_size[0] - n_rem, + r_body, r_zeros_number); + + if (is_indirect_le_ih(B_N_PITEM_HEAD(tb->R[0], 0))) { #if 0 RFALSE(n_rem, "PAP-12160: paste more than one unformatted node pointer"); #endif - set_ih_free_space - (B_N_PITEM_HEAD - (tb->R[0], 0), 0); + set_ih_free_space(B_N_PITEM_HEAD(tb->R[0], 0), 0); } tb->insert_size[0] = n_rem; if (!n_rem) @@ -1044,58 +722,28 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h struct item_head *pasted; - ret_val = - leaf_shift_right(tb, tb->rnum[0], - tb->rbytes); + ret_val = leaf_shift_right(tb, tb->rnum[0], tb->rbytes); /* append item in R[0] */ if (pos_in_item >= 0) { buffer_info_init_right(tb, &bi); - leaf_paste_in_buffer(&bi, - item_pos - - n + - tb-> - rnum[0], - pos_in_item, - tb-> - insert_size - [0], body, - zeros_num); + leaf_paste_in_buffer(&bi, item_pos - n + tb->rnum[0], pos_in_item, + tb->insert_size[0], body, zeros_num); } /* paste new entry, if item is directory item */ - pasted = - B_N_PITEM_HEAD(tb->R[0], - item_pos - n + - tb->rnum[0]); - if (is_direntry_le_ih(pasted) - && pos_in_item >= 0) { - leaf_paste_entries(&bi, - item_pos - - n + - tb->rnum[0], - pos_in_item, - 1, - (struct - reiserfs_de_head - *)body, - body + - DEH_SIZE, - tb-> - insert_size - [0] - ); + pasted = B_N_PITEM_HEAD(tb->R[0], item_pos - n + tb->rnum[0]); + if (is_direntry_le_ih(pasted) && pos_in_item >= 0) { + leaf_paste_entries(&bi, item_pos - n + tb->rnum[0], + pos_in_item, 1, + (struct reiserfs_de_head *) body, + body + DEH_SIZE, tb->insert_size[0]); if (!pos_in_item) { - RFALSE(item_pos - n + - tb->rnum[0], + RFALSE(item_pos - n + tb->rnum[0], "PAP-12165: directory item must be first item of node when pasting is in 0th position"); /* update delimiting keys */ - replace_key(tb, - tb->CFR[0], - tb->rkey[0], - tb->R[0], - 0); + replace_key(tb, tb->CFR[0], tb->rkey[0], tb->R[0], 0); } } @@ -1111,22 +759,16 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h default: /* cases d and t */ reiserfs_panic(tb->tb_sb, "PAP-12175", "rnum > 0: unexpected mode: %s(%d)", - (flag == - M_DELETE) ? "DELETE" : ((flag == - M_CUT) ? "CUT" - : "UNKNOWN"), - flag); + (flag == M_DELETE) ? "DELETE" : ((flag == M_CUT) ? "CUT" : "UNKNOWN"), flag); } } /* tb->rnum[0] > 0 */ RFALSE(tb->blknum[0] > 3, - "PAP-12180: blknum can not be %d. It must be <= 3", - tb->blknum[0]); + "PAP-12180: blknum can not be %d. It must be <= 3", tb->blknum[0]); RFALSE(tb->blknum[0] < 0, - "PAP-12185: blknum can not be %d. It must be >= 0", - tb->blknum[0]); + "PAP-12185: blknum can not be %d. It must be >= 0", tb->blknum[0]); /* if while adding to a node we discover that it is possible to split it in two, and merge the left part into the left neighbor and the @@ -1177,8 +819,7 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h if (n - snum[i] < item_pos) { /* new item or it's part falls to first new node S_new[i] */ if (item_pos == n - snum[i] + 1 && sbytes[i] != -1) { /* part of new item falls into S_new[i] */ - int old_key_comp, old_len, - r_zeros_number; + int old_key_comp, old_len, r_zeros_number; const char *r_body; int version; @@ -1192,15 +833,8 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h old_len = ih_item_len(ih); /* Calculate key component and item length to insert into S_new[i] */ - set_le_ih_k_offset(ih, - le_ih_k_offset(ih) + - ((old_len - - sbytes[i]) << - (is_indirect_le_ih - (ih) ? tb->tb_sb-> - s_blocksize_bits - - UNFM_P_SHIFT : - 0))); + set_le_ih_k_offset(ih, le_ih_k_offset(ih) + + ((old_len - sbytes[i]) << (is_indirect_le_ih(ih) ? tb->tb_sb-> s_blocksize_bits - UNFM_P_SHIFT : 0))); put_ih_item_len(ih, sbytes[i]); @@ -1209,39 +843,29 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h if ((old_len - sbytes[i]) > zeros_num) { r_zeros_number = 0; - r_body = - body + (old_len - - sbytes[i]) - - zeros_num; + r_body = body + (old_len - sbytes[i]) - zeros_num; } else { r_body = body; - r_zeros_number = - zeros_num - (old_len - - sbytes[i]); + r_zeros_number = zeros_num - (old_len - sbytes[i]); zeros_num -= r_zeros_number; } - leaf_insert_into_buf(&bi, 0, ih, r_body, - r_zeros_number); + leaf_insert_into_buf(&bi, 0, ih, r_body, r_zeros_number); /* Calculate key component and item length to insert into S[i] */ set_le_ih_k_offset(ih, old_key_comp); - put_ih_item_len(ih, - old_len - sbytes[i]); + put_ih_item_len(ih, old_len - sbytes[i]); tb->insert_size[0] -= sbytes[i]; } else { /* whole new item falls into S_new[i] */ /* Shift snum[0] - 1 items to S_new[i] (sbytes[i] of split item) */ leaf_move_items(LEAF_FROM_S_TO_SNEW, tb, - snum[i] - 1, sbytes[i], - S_new[i]); + snum[i] - 1, sbytes[i], S_new[i]); /* Insert new item into S_new[i] */ buffer_info_init_bh(tb, &bi, S_new[i]); - leaf_insert_into_buf(&bi, - item_pos - n + - snum[i] - 1, ih, - body, zeros_num); + leaf_insert_into_buf(&bi, item_pos - n + snum[i] - 1, + ih, body, zeros_num); zeros_num = tb->insert_size[0] = 0; } @@ -1268,150 +892,73 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h int entry_count; - entry_count = - ih_entry_count(aux_ih); + entry_count = ih_entry_count(aux_ih); - if (entry_count - sbytes[i] < - pos_in_item - && pos_in_item <= - entry_count) { + if (entry_count - sbytes[i] < pos_in_item && pos_in_item <= entry_count) { /* new directory entry falls into S_new[i] */ - RFALSE(!tb-> - insert_size[0], - "PAP-12215: insert_size is already 0"); - RFALSE(sbytes[i] - 1 >= - entry_count, + RFALSE(!tb->insert_size[0], "PAP-12215: insert_size is already 0"); + RFALSE(sbytes[i] - 1 >= entry_count, "PAP-12220: there are no so much entries (%d), only %d", - sbytes[i] - 1, - entry_count); + sbytes[i] - 1, entry_count); /* Shift snum[i]-1 items in whole. Shift sbytes[i] directory entries from directory item number snum[i] */ - leaf_move_items - (LEAF_FROM_S_TO_SNEW, - tb, snum[i], - sbytes[i] - 1, - S_new[i]); + leaf_move_items(LEAF_FROM_S_TO_SNEW, tb, snum[i], sbytes[i] - 1, S_new[i]); /* Paste given directory entry to directory item */ buffer_info_init_bh(tb, &bi, S_new[i]); - leaf_paste_in_buffer - (&bi, 0, - pos_in_item - - entry_count + - sbytes[i] - 1, - tb->insert_size[0], - body, zeros_num); + leaf_paste_in_buffer(&bi, 0, pos_in_item - entry_count + sbytes[i] - 1, + tb->insert_size[0], body, zeros_num); /* paste new directory entry */ - leaf_paste_entries(&bi, - 0, - pos_in_item - - - entry_count - + - sbytes - [i] - - 1, 1, - (struct - reiserfs_de_head - *) - body, - body - + - DEH_SIZE, - tb-> - insert_size - [0] - ); + leaf_paste_entries(&bi, 0, pos_in_item - entry_count + sbytes[i] - 1, 1, + (struct reiserfs_de_head *) body, + body + DEH_SIZE, tb->insert_size[0]); tb->insert_size[0] = 0; pos_in_item++; } else { /* new directory entry doesn't fall into S_new[i] */ - leaf_move_items - (LEAF_FROM_S_TO_SNEW, - tb, snum[i], - sbytes[i], - S_new[i]); + leaf_move_items(LEAF_FROM_S_TO_SNEW,tb, snum[i], sbytes[i], S_new[i]); } } else { /* regular object */ - int n_shift, n_rem, - r_zeros_number; + int n_shift, n_rem, r_zeros_number; const char *r_body; - RFALSE(pos_in_item != - ih_item_len - (B_N_PITEM_HEAD - (tbS0, item_pos)) - || tb->insert_size[0] <= - 0, + RFALSE(pos_in_item != ih_item_len(B_N_PITEM_HEAD(tbS0, item_pos)) || tb->insert_size[0] <= 0, "PAP-12225: item too short or insert_size <= 0"); /* Calculate number of bytes which must be shifted from appended item */ - n_shift = - sbytes[i] - - tb->insert_size[0]; + n_shift = sbytes[i] - tb->insert_size[0]; if (n_shift < 0) n_shift = 0; - leaf_move_items - (LEAF_FROM_S_TO_SNEW, tb, - snum[i], n_shift, - S_new[i]); + leaf_move_items(LEAF_FROM_S_TO_SNEW, tb, snum[i], n_shift, S_new[i]); /* Calculate number of bytes which must remain in body after append to S_new[i] */ - n_rem = - tb->insert_size[0] - - sbytes[i]; + n_rem = tb->insert_size[0] - sbytes[i]; if (n_rem < 0) n_rem = 0; /* Append part of body into S_new[0] */ buffer_info_init_bh(tb, &bi, S_new[i]); if (n_rem > zeros_num) { r_zeros_number = 0; - r_body = - body + n_rem - - zeros_num; + r_body = body + n_rem - zeros_num; } else { r_body = body; - r_zeros_number = - zeros_num - n_rem; - zeros_num -= - r_zeros_number; + r_zeros_number = zeros_num - n_rem; + zeros_num -= r_zeros_number; } - leaf_paste_in_buffer(&bi, 0, - n_shift, - tb-> - insert_size - [0] - - n_rem, - r_body, - r_zeros_number); + leaf_paste_in_buffer(&bi, 0, n_shift, + tb->insert_size[0] - n_rem, + r_body, r_zeros_number); { struct item_head *tmp; - tmp = - B_N_PITEM_HEAD(S_new - [i], - 0); + tmp = B_N_PITEM_HEAD(S_new[i], 0); if (is_indirect_le_ih (tmp)) { - set_ih_free_space - (tmp, 0); - set_le_ih_k_offset - (tmp, - le_ih_k_offset - (tmp) + - (n_rem << - (tb-> - tb_sb-> - s_blocksize_bits - - - UNFM_P_SHIFT))); + set_ih_free_space(tmp, 0); + set_le_ih_k_offset(tmp, le_ih_k_offset(tmp) + (n_rem << (tb->tb_sb->s_blocksize_bits - UNFM_P_SHIFT))); } else { - set_le_ih_k_offset - (tmp, - le_ih_k_offset - (tmp) + - n_rem); + set_le_ih_k_offset(tmp, le_ih_k_offset(tmp) + n_rem); } } @@ -1426,8 +973,7 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h struct item_head *pasted; #ifdef CONFIG_REISERFS_CHECK - struct item_head *ih_check = - B_N_PITEM_HEAD(tbS0, item_pos); + struct item_head *ih_check = B_N_PITEM_HEAD(tbS0, item_pos); if (!is_direntry_le_ih(ih_check) && (pos_in_item != ih_item_len(ih_check) @@ -1439,8 +985,7 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h "to ih_item_len"); #endif /* CONFIG_REISERFS_CHECK */ - leaf_mi = - leaf_move_items(LEAF_FROM_S_TO_SNEW, + leaf_mi = leaf_move_items(LEAF_FROM_S_TO_SNEW, tb, snum[i], sbytes[i], S_new[i]); @@ -1452,30 +997,19 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h /* paste into item */ buffer_info_init_bh(tb, &bi, S_new[i]); leaf_paste_in_buffer(&bi, - item_pos - n + - snum[i], + item_pos - n + snum[i], pos_in_item, tb->insert_size[0], body, zeros_num); - pasted = - B_N_PITEM_HEAD(S_new[i], - item_pos - n + - snum[i]); + pasted = B_N_PITEM_HEAD(S_new[i], item_pos - n + snum[i]); if (is_direntry_le_ih(pasted)) { leaf_paste_entries(&bi, - item_pos - - n + snum[i], - pos_in_item, - 1, - (struct - reiserfs_de_head - *)body, - body + - DEH_SIZE, - tb-> - insert_size - [0] + item_pos - n + snum[i], + pos_in_item, 1, + (struct reiserfs_de_head *)body, + body + DEH_SIZE, + tb->insert_size[0] ); } @@ -1495,11 +1029,7 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h default: /* cases d and t */ reiserfs_panic(tb->tb_sb, "PAP-12245", "blknum > 2: unexpected mode: %s(%d)", - (flag == - M_DELETE) ? "DELETE" : ((flag == - M_CUT) ? "CUT" - : "UNKNOWN"), - flag); + (flag == M_DELETE) ? "DELETE" : ((flag == M_CUT) ? "CUT" : "UNKNOWN"), flag); } memcpy(insert_key + i, B_N_PKEY(S_new[i], 0), KEY_SIZE); @@ -1524,9 +1054,7 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h /* If we insert the first key change the delimiting key */ if (item_pos == 0) { if (tb->CFL[0]) /* can be 0 in reiserfsck */ - replace_key(tb, tb->CFL[0], tb->lkey[0], - tbS0, 0); - + replace_key(tb, tb->CFL[0], tb->lkey[0], tbS0, 0); } break; @@ -1536,53 +1064,27 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h pasted = B_N_PITEM_HEAD(tbS0, item_pos); /* when directory, may be new entry already pasted */ if (is_direntry_le_ih(pasted)) { - if (pos_in_item >= 0 && - pos_in_item <= - ih_entry_count(pasted)) { + if (pos_in_item >= 0 && pos_in_item <= ih_entry_count(pasted)) { RFALSE(!tb->insert_size[0], "PAP-12260: insert_size is 0 already"); /* prepare space */ buffer_info_init_tbS0(tb, &bi); - leaf_paste_in_buffer(&bi, - item_pos, - pos_in_item, - tb-> - insert_size - [0], body, + leaf_paste_in_buffer(&bi, item_pos, pos_in_item, + tb->insert_size[0], body, zeros_num); /* paste entry */ - leaf_paste_entries(&bi, - item_pos, - pos_in_item, - 1, - (struct - reiserfs_de_head - *)body, - body + - DEH_SIZE, - tb-> - insert_size - [0] - ); + leaf_paste_entries(&bi, item_pos, pos_in_item, 1, + (struct reiserfs_de_head *)body, + body + DEH_SIZE, + tb->insert_size[0]); if (!item_pos && !pos_in_item) { - RFALSE(!tb->CFL[0] - || !tb->L[0], + RFALSE(!tb->CFL[0] || !tb->L[0], "PAP-12270: CFL[0]/L[0] must be specified"); - if (tb->CFL[0]) { - replace_key(tb, - tb-> - CFL - [0], - tb-> - lkey - [0], - tbS0, - 0); - - } + if (tb->CFL[0]) + replace_key(tb, tb->CFL[0], tb->lkey[0], tbS0, 0); } tb->insert_size[0] = 0; } @@ -1593,13 +1095,8 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h "PAP-12275: insert size must not be %d", tb->insert_size[0]); buffer_info_init_tbS0(tb, &bi); - leaf_paste_in_buffer(&bi, - item_pos, - pos_in_item, - tb-> - insert_size - [0], body, - zeros_num); + leaf_paste_in_buffer(&bi, item_pos, pos_in_item, + tb->insert_size[0], body, zeros_num); if (is_indirect_le_ih(pasted)) { #if 0 @@ -1611,8 +1108,7 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h tb-> insert_size[0]); #endif - set_ih_free_space - (pasted, 0); + set_ih_free_space(pasted, 0); } tb->insert_size[0] = 0; } @@ -1620,8 +1116,7 @@ static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item h else { if (tb->insert_size[0]) { print_cur_tb("12285"); - reiserfs_panic(tb-> - tb_sb, + reiserfs_panic(tb->tb_sb, "PAP-12285", "insert_size " "must be 0 " diff --git a/fs/sync.c b/fs/sync.c index e8ba024a055..b28d1dd10e8 100644 --- a/fs/sync.c +++ b/fs/sync.c @@ -27,11 +27,10 @@ * wait == 1 case since in that case write_inode() functions do * sync_dirty_buffer() and thus effectively write one block at a time. */ -static int __sync_filesystem(struct super_block *sb, int wait, - unsigned long start) +static int __sync_filesystem(struct super_block *sb, int wait) { if (wait) - sync_inodes_sb(sb, start); + sync_inodes_sb(sb); else writeback_inodes_sb(sb, WB_REASON_SYNC); @@ -48,7 +47,6 @@ static int __sync_filesystem(struct super_block *sb, int wait, int sync_filesystem(struct super_block *sb) { int ret; - unsigned long start = jiffies; /* * We need to be protected against the filesystem going from @@ -62,17 +60,17 @@ int sync_filesystem(struct super_block *sb) if (sb->s_flags & MS_RDONLY) return 0; - ret = __sync_filesystem(sb, 0, start); + ret = __sync_filesystem(sb, 0); if (ret < 0) return ret; - return __sync_filesystem(sb, 1, start); + return __sync_filesystem(sb, 1); } EXPORT_SYMBOL_GPL(sync_filesystem); static void sync_inodes_one_sb(struct super_block *sb, void *arg) { if (!(sb->s_flags & MS_RDONLY)) - sync_inodes_sb(sb, *((unsigned long *)arg)); + sync_inodes_sb(sb); } static void sync_fs_one_sb(struct super_block *sb, void *arg) @@ -104,10 +102,9 @@ static void fdatawait_one_bdev(struct block_device *bdev, void *arg) SYSCALL_DEFINE0(sync) { int nowait = 0, wait = 1; - unsigned long start = jiffies; wakeup_flusher_threads(0, WB_REASON_SYNC); - iterate_supers(sync_inodes_one_sb, &start); + iterate_supers(sync_inodes_one_sb, NULL); iterate_supers(sync_fs_one_sb, &nowait); iterate_supers(sync_fs_one_sb, &wait); iterate_bdevs(fdatawrite_one_bdev, NULL); diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c index 6211230814f..3eaf5c6622e 100644 --- a/fs/sysfs/mount.c +++ b/fs/sysfs/mount.c @@ -27,6 +27,7 @@ static struct dentry *sysfs_mount(struct file_system_type *fs_type, { struct dentry *root; void *ns; + bool new_sb; if (!(flags & MS_KERNMOUNT)) { if (!capable(CAP_SYS_ADMIN) && !fs_fully_visible(fs_type)) @@ -37,8 +38,8 @@ static struct dentry *sysfs_mount(struct file_system_type *fs_type, } ns = kobj_ns_grab_current(KOBJ_NS_TYPE_NET); - root = kernfs_mount_ns(fs_type, flags, sysfs_root, ns); - if (IS_ERR(root)) + root = kernfs_mount_ns(fs_type, flags, sysfs_root, &new_sb, ns); + if (IS_ERR(root) || !new_sb) kobj_ns_drop(KOBJ_NS_TYPE_NET, ns); return root; } diff --git a/fs/udf/file.c b/fs/udf/file.c index c02a27a19c6..1037637957c 100644 --- a/fs/udf/file.c +++ b/fs/udf/file.c @@ -144,6 +144,7 @@ static ssize_t udf_file_aio_write(struct kiocb *iocb, const struct iovec *iov, size_t count = iocb->ki_nbytes; struct udf_inode_info *iinfo = UDF_I(inode); + mutex_lock(&inode->i_mutex); down_write(&iinfo->i_data_sem); if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) { if (file->f_flags & O_APPEND) @@ -156,6 +157,7 @@ static ssize_t udf_file_aio_write(struct kiocb *iocb, const struct iovec *iov, pos + count)) { err = udf_expand_file_adinicb(inode); if (err) { + mutex_unlock(&inode->i_mutex); udf_debug("udf_expand_adinicb: err=%d\n", err); return err; } @@ -169,9 +171,17 @@ static ssize_t udf_file_aio_write(struct kiocb *iocb, const struct iovec *iov, } else up_write(&iinfo->i_data_sem); - retval = generic_file_aio_write(iocb, iov, nr_segs, ppos); - if (retval > 0) + retval = __generic_file_aio_write(iocb, iov, nr_segs, &iocb->ki_pos); + mutex_unlock(&inode->i_mutex); + + if (retval > 0) { + ssize_t err; + mark_inode_dirty(inode); + err = generic_write_sync(file, iocb->ki_pos - retval, retval); + if (err < 0) + retval = err; + } return retval; } diff --git a/fs/udf/inode.c b/fs/udf/inode.c index 062b7925bca..982ce05c87e 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c @@ -265,6 +265,7 @@ int udf_expand_file_adinicb(struct inode *inode) .nr_to_write = 1, }; + WARN_ON_ONCE(!mutex_is_locked(&inode->i_mutex)); if (!iinfo->i_lenAlloc) { if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_USE_SHORT_AD)) iinfo->i_alloc_type = ICBTAG_FLAG_AD_SHORT; diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c index f35d5c953ff..9ddfb8190ca 100644 --- a/fs/xfs/xfs_iops.c +++ b/fs/xfs/xfs_iops.c @@ -705,7 +705,6 @@ xfs_setattr_size( { struct xfs_mount *mp = ip->i_mount; struct inode *inode = VFS_I(ip); - int mask = iattr->ia_valid; xfs_off_t oldsize, newsize; struct xfs_trans *tp; int error; @@ -726,8 +725,8 @@ xfs_setattr_size( ASSERT(xfs_isilocked(ip, XFS_IOLOCK_EXCL)); ASSERT(S_ISREG(ip->i_d.di_mode)); - ASSERT((mask & (ATTR_UID|ATTR_GID|ATTR_ATIME|ATTR_ATIME_SET| - ATTR_MTIME_SET|ATTR_KILL_PRIV|ATTR_TIMES_SET)) == 0); + ASSERT((iattr->ia_valid & (ATTR_UID|ATTR_GID|ATTR_ATIME|ATTR_ATIME_SET| + ATTR_MTIME_SET|ATTR_KILL_PRIV|ATTR_TIMES_SET)) == 0); oldsize = inode->i_size; newsize = iattr->ia_size; @@ -736,7 +735,7 @@ xfs_setattr_size( * Short circuit the truncate case for zero length files. */ if (newsize == 0 && oldsize == 0 && ip->i_d.di_nextents == 0) { - if (!(mask & (ATTR_CTIME|ATTR_MTIME))) + if (!(iattr->ia_valid & (ATTR_CTIME|ATTR_MTIME))) return 0; /* @@ -824,10 +823,11 @@ xfs_setattr_size( * these flags set. For all other operations the VFS set these flags * explicitly if it wants a timestamp update. */ - if (newsize != oldsize && (!(mask & (ATTR_CTIME | ATTR_MTIME)))) { + if (newsize != oldsize && + !(iattr->ia_valid & (ATTR_CTIME | ATTR_MTIME))) { iattr->ia_ctime = iattr->ia_mtime = current_fs_time(inode->i_sb); - mask |= ATTR_CTIME | ATTR_MTIME; + iattr->ia_valid |= ATTR_CTIME | ATTR_MTIME; } /* @@ -863,9 +863,9 @@ xfs_setattr_size( xfs_inode_clear_eofblocks_tag(ip); } - if (mask & ATTR_MODE) + if (iattr->ia_valid & ATTR_MODE) xfs_setattr_mode(ip, iattr); - if (mask & (ATTR_ATIME|ATTR_CTIME|ATTR_MTIME)) + if (iattr->ia_valid & (ATTR_ATIME|ATTR_CTIME|ATTR_MTIME)) xfs_setattr_time(ip, iattr); xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); diff --git a/fs/xfs/xfs_log_cil.c b/fs/xfs/xfs_log_cil.c index cdebd832c3d..4ef6fdbced7 100644 --- a/fs/xfs/xfs_log_cil.c +++ b/fs/xfs/xfs_log_cil.c @@ -205,16 +205,25 @@ xlog_cil_insert_format_items( /* * We 64-bit align the length of each iovec so that the start * of the next one is naturally aligned. We'll need to - * account for that slack space here. + * account for that slack space here. Then round nbytes up + * to 64-bit alignment so that the initial buffer alignment is + * easy to calculate and verify. */ nbytes += niovecs * sizeof(uint64_t); + nbytes = round_up(nbytes, sizeof(uint64_t)); /* grab the old item if it exists for reservation accounting */ old_lv = lip->li_lv; - /* calc buffer size */ - buf_size = sizeof(struct xfs_log_vec) + nbytes + - niovecs * sizeof(struct xfs_log_iovec); + /* + * The data buffer needs to start 64-bit aligned, so round up + * that space to ensure we can align it appropriately and not + * overrun the buffer. + */ + buf_size = nbytes + + round_up((sizeof(struct xfs_log_vec) + + niovecs * sizeof(struct xfs_log_iovec)), + sizeof(uint64_t)); /* compare to existing item size */ if (lip->li_lv && buf_size <= lip->li_lv->lv_size) { @@ -251,6 +260,8 @@ xlog_cil_insert_format_items( /* The allocated data region lies beyond the iovec region */ lv->lv_buf_len = 0; lv->lv_buf = (char *)lv + buf_size - nbytes; + ASSERT(IS_ALIGNED((unsigned long)lv->lv_buf, sizeof(uint64_t))); + lip->li_ops->iop_format(lip, lv); insert: ASSERT(lv->lv_buf_len <= nbytes); diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c index 02df7b408a2..f96c05669a9 100644 --- a/fs/xfs/xfs_mount.c +++ b/fs/xfs/xfs_mount.c @@ -282,22 +282,29 @@ xfs_readsb( struct xfs_sb *sbp = &mp->m_sb; int error; int loud = !(flags & XFS_MFSI_QUIET); + const struct xfs_buf_ops *buf_ops; ASSERT(mp->m_sb_bp == NULL); ASSERT(mp->m_ddev_targp != NULL); /* + * For the initial read, we must guess at the sector + * size based on the block device. It's enough to + * get the sb_sectsize out of the superblock and + * then reread with the proper length. + * We don't verify it yet, because it may not be complete. + */ + sector_size = xfs_getsize_buftarg(mp->m_ddev_targp); + buf_ops = NULL; + + /* * Allocate a (locked) buffer to hold the superblock. * This will be kept around at all times to optimize * access to the superblock. */ - sector_size = xfs_getsize_buftarg(mp->m_ddev_targp); - reread: bp = xfs_buf_read_uncached(mp->m_ddev_targp, XFS_SB_DADDR, - BTOBB(sector_size), 0, - loud ? &xfs_sb_buf_ops - : &xfs_sb_quiet_buf_ops); + BTOBB(sector_size), 0, buf_ops); if (!bp) { if (loud) xfs_warn(mp, "SB buffer read failed"); @@ -328,12 +335,13 @@ reread: } /* - * If device sector size is smaller than the superblock size, - * re-read the superblock so the buffer is correctly sized. + * Re-read the superblock so the buffer is correctly sized, + * and properly verified. */ - if (sector_size < sbp->sb_sectsize) { + if (buf_ops == NULL) { xfs_buf_relse(bp); sector_size = sbp->sb_sectsize; + buf_ops = loud ? &xfs_sb_buf_ops : &xfs_sb_quiet_buf_ops; goto reread; } diff --git a/fs/xfs/xfs_sb.c b/fs/xfs/xfs_sb.c index b7c9aea77f8..1e116794bb6 100644 --- a/fs/xfs/xfs_sb.c +++ b/fs/xfs/xfs_sb.c @@ -295,8 +295,7 @@ xfs_mount_validate_sb( sbp->sb_dblocks == 0 || sbp->sb_dblocks > XFS_MAX_DBLOCKS(sbp) || sbp->sb_dblocks < XFS_MIN_DBLOCKS(sbp))) { - XFS_CORRUPTION_ERROR("SB sanity check failed", - XFS_ERRLEVEL_LOW, mp, sbp); + xfs_notice(mp, "SB sanity check failed"); return XFS_ERROR(EFSCORRUPTED); } @@ -611,10 +610,10 @@ xfs_sb_read_verify( XFS_SB_VERSION_5) || dsb->sb_crc != 0)) { - if (!xfs_verify_cksum(bp->b_addr, be16_to_cpu(dsb->sb_sectsize), + if (!xfs_verify_cksum(bp->b_addr, BBTOB(bp->b_length), offsetof(struct xfs_sb, sb_crc))) { /* Only fail bad secondaries on a known V5 filesystem */ - if (bp->b_bn != XFS_SB_DADDR && + if (bp->b_bn == XFS_SB_DADDR || xfs_sb_version_hascrc(&mp->m_sb)) { error = EFSCORRUPTED; goto out_error; @@ -625,7 +624,7 @@ xfs_sb_read_verify( out_error: if (error) { - if (error != EWRONGFS) + if (error == EFSCORRUPTED) XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, bp->b_addr); xfs_buf_ioerror(bp, error); @@ -644,7 +643,6 @@ xfs_sb_quiet_read_verify( { struct xfs_dsb *dsb = XFS_BUF_TO_SBP(bp); - if (dsb->sb_magicnum == cpu_to_be32(XFS_SB_MAGIC)) { /* XFS filesystem, verify noisily! */ xfs_sb_read_verify(bp); diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c index f317488263d..d971f4932b5 100644 --- a/fs/xfs/xfs_super.c +++ b/fs/xfs/xfs_super.c @@ -913,7 +913,7 @@ xfs_flush_inodes( struct super_block *sb = mp->m_super; if (down_read_trylock(&sb->s_umount)) { - sync_inodes_sb(sb, jiffies); + sync_inodes_sb(sb); up_read(&sb->s_umount); } } diff --git a/include/asm-generic/pgtable.h b/include/asm-generic/pgtable.h index 8e4f41d9af4..34c7bdc0601 100644 --- a/include/asm-generic/pgtable.h +++ b/include/asm-generic/pgtable.h @@ -701,6 +701,18 @@ static inline pte_t pte_mknuma(pte_t pte) } #endif +#ifndef ptep_set_numa +static inline void ptep_set_numa(struct mm_struct *mm, unsigned long addr, + pte_t *ptep) +{ + pte_t ptent = *ptep; + + ptent = pte_mknuma(ptent); + set_pte_at(mm, addr, ptep, ptent); + return; +} +#endif + #ifndef pmd_mknuma static inline pmd_t pmd_mknuma(pmd_t pmd) { @@ -708,6 +720,18 @@ static inline pmd_t pmd_mknuma(pmd_t pmd) return pmd_clear_flags(pmd, _PAGE_PRESENT); } #endif + +#ifndef pmdp_set_numa +static inline void pmdp_set_numa(struct mm_struct *mm, unsigned long addr, + pmd_t *pmdp) +{ + pmd_t pmd = *pmdp; + + pmd = pmd_mknuma(pmd); + set_pmd_at(mm, addr, pmdp, pmd); + return; +} +#endif #else extern int pte_numa(pte_t pte); extern int pmd_numa(pmd_t pmd); @@ -715,6 +739,8 @@ extern pte_t pte_mknonnuma(pte_t pte); extern pmd_t pmd_mknonnuma(pmd_t pmd); extern pte_t pte_mknuma(pte_t pte); extern pmd_t pmd_mknuma(pmd_t pmd); +extern void ptep_set_numa(struct mm_struct *mm, unsigned long addr, pte_t *ptep); +extern void pmdp_set_numa(struct mm_struct *mm, unsigned long addr, pmd_t *pmdp); #endif /* CONFIG_ARCH_USES_NUMA_PROT_NONE */ #else static inline int pmd_numa(pmd_t pmd) @@ -742,10 +768,23 @@ static inline pte_t pte_mknuma(pte_t pte) return pte; } +static inline void ptep_set_numa(struct mm_struct *mm, unsigned long addr, + pte_t *ptep) +{ + return; +} + + static inline pmd_t pmd_mknuma(pmd_t pmd) { return pmd; } + +static inline void pmdp_set_numa(struct mm_struct *mm, unsigned long addr, + pmd_t *pmdp) +{ + return ; +} #endif /* CONFIG_NUMA_BALANCING */ #endif /* CONFIG_MMU */ diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 71727b6210a..8f3dee09757 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -907,6 +907,9 @@ struct drm_mode_config { /* whether async page flip is supported or not */ bool async_page_flip; + + /* cursor size */ + uint32_t cursor_width, cursor_height; }; #define obj_to_crtc(x) container_of(x, struct drm_crtc, base) diff --git a/include/drm/ttm/ttm_page_alloc.h b/include/drm/ttm/ttm_page_alloc.h index d1f61bfe0eb..49a828425fa 100644 --- a/include/drm/ttm/ttm_page_alloc.h +++ b/include/drm/ttm/ttm_page_alloc.h @@ -29,6 +29,8 @@ #include <drm/ttm/ttm_bo_driver.h> #include <drm/ttm/ttm_memory.h> +struct device; + /** * Initialize pool allocator. */ diff --git a/include/linux/ceph/ceph_fs.h b/include/linux/ceph/ceph_fs.h index 2623cffc73a..25bfb0eff77 100644 --- a/include/linux/ceph/ceph_fs.h +++ b/include/linux/ceph/ceph_fs.h @@ -373,8 +373,9 @@ extern const char *ceph_mds_op_name(int op); /* * Ceph setxattr request flags. */ -#define CEPH_XATTR_CREATE 1 -#define CEPH_XATTR_REPLACE 2 +#define CEPH_XATTR_CREATE (1 << 0) +#define CEPH_XATTR_REPLACE (1 << 1) +#define CEPH_XATTR_REMOVE (1 << 31) union ceph_mds_request_args { struct { diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h index 5c097596104..9450f025fe0 100644 --- a/include/linux/cgroup.h +++ b/include/linux/cgroup.h @@ -166,6 +166,8 @@ struct cgroup { * * The ID of the root cgroup is always 0, and a new cgroup * will be assigned with a smallest available ID. + * + * Allocating/Removing ID must be protected by cgroup_mutex. */ int id; diff --git a/include/linux/dma-buf.h b/include/linux/dma-buf.h index dfac5ed3112..f886985a28b 100644 --- a/include/linux/dma-buf.h +++ b/include/linux/dma-buf.h @@ -171,7 +171,7 @@ struct dma_buf *dma_buf_export_named(void *priv, const struct dma_buf_ops *ops, size_t size, int flags, const char *); #define dma_buf_export(priv, ops, size, flags) \ - dma_buf_export_named(priv, ops, size, flags, __FILE__) + dma_buf_export_named(priv, ops, size, flags, KBUILD_MODNAME) int dma_buf_fd(struct dma_buf *dmabuf, int flags); struct dma_buf *dma_buf_get(int fd); diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h index 3d286ff49ab..64cf3ef5069 100644 --- a/include/linux/fsnotify_backend.h +++ b/include/linux/fsnotify_backend.h @@ -99,7 +99,7 @@ struct fsnotify_ops { struct fsnotify_mark *inode_mark, struct fsnotify_mark *vfsmount_mark, u32 mask, void *data, int data_type, - const unsigned char *file_name); + const unsigned char *file_name, u32 cookie); void (*free_group_priv)(struct fsnotify_group *group); void (*freeing_mark)(struct fsnotify_mark *mark, struct fsnotify_group *group); void (*free_event)(struct fsnotify_event *event); @@ -160,7 +160,7 @@ struct fsnotify_group { struct fasync_struct *fsn_fa; /* async notification */ - struct fsnotify_event overflow_event; /* Event we queue when the + struct fsnotify_event *overflow_event; /* Event we queue when the * notification list is too * full */ diff --git a/include/linux/ipc_namespace.h b/include/linux/ipc_namespace.h index e7831d20373..35e7eca4e33 100644 --- a/include/linux/ipc_namespace.h +++ b/include/linux/ipc_namespace.h @@ -118,9 +118,7 @@ extern int mq_init_ns(struct ipc_namespace *ns); * the new maximum will handle anyone else. I may have to revisit this * in the future. */ -#define MIN_QUEUESMAX 1 #define DFLT_QUEUESMAX 256 -#define HARD_QUEUESMAX 1024 #define MIN_MSGMAX 1 #define DFLT_MSG 10U #define DFLT_MSGMAX 10 diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h index 5be9f0228a3..d267623c28c 100644 --- a/include/linux/kernfs.h +++ b/include/linux/kernfs.h @@ -249,7 +249,8 @@ void kernfs_notify(struct kernfs_node *kn); const void *kernfs_super_ns(struct super_block *sb); struct dentry *kernfs_mount_ns(struct file_system_type *fs_type, int flags, - struct kernfs_root *root, const void *ns); + struct kernfs_root *root, bool *new_sb_created, + const void *ns); void kernfs_kill_sb(struct super_block *sb); void kernfs_init(void); @@ -317,7 +318,7 @@ static inline const void *kernfs_super_ns(struct super_block *sb) static inline struct dentry * kernfs_mount_ns(struct file_system_type *fs_type, int flags, - struct kernfs_root *root, const void *ns) + struct kernfs_root *root, bool *new_sb_created, const void *ns) { return ERR_PTR(-ENOSYS); } static inline void kernfs_kill_sb(struct super_block *sb) { } @@ -368,9 +369,9 @@ static inline int kernfs_remove_by_name(struct kernfs_node *parent, static inline struct dentry * kernfs_mount(struct file_system_type *fs_type, int flags, - struct kernfs_root *root) + struct kernfs_root *root, bool *new_sb_created) { - return kernfs_mount_ns(fs_type, flags, root, NULL); + return kernfs_mount_ns(fs_type, flags, root, new_sb_created, NULL); } #endif /* __LINUX_KERNFS_H */ diff --git a/include/linux/mfd/max8997-private.h b/include/linux/mfd/max8997-private.h index ad1ae7f345a..78c76cd4d37 100644 --- a/include/linux/mfd/max8997-private.h +++ b/include/linux/mfd/max8997-private.h @@ -387,7 +387,7 @@ struct max8997_dev { struct i2c_client *muic; /* slave addr 0x4a */ struct mutex iolock; - int type; + unsigned long type; struct platform_device *battery; /* battery control (not fuel gauge) */ int irq; diff --git a/include/linux/mfd/max8998-private.h b/include/linux/mfd/max8998-private.h index 4ecb24b4b86..d68ada502ff 100644 --- a/include/linux/mfd/max8998-private.h +++ b/include/linux/mfd/max8998-private.h @@ -163,7 +163,7 @@ struct max8998_dev { int ono; u8 irq_masks_cur[MAX8998_NUM_IRQ_REGS]; u8 irq_masks_cache[MAX8998_NUM_IRQ_REGS]; - int type; + unsigned long type; bool wakeup; }; diff --git a/include/linux/mfd/tps65217.h b/include/linux/mfd/tps65217.h index a5a7f0130e9..54b5458ec08 100644 --- a/include/linux/mfd/tps65217.h +++ b/include/linux/mfd/tps65217.h @@ -252,7 +252,7 @@ struct tps65217_board { struct tps65217 { struct device *dev; struct tps65217_board *pdata; - unsigned int id; + unsigned long id; struct regulator_desc desc[TPS65217_NUM_REGULATOR]; struct regulator_dev *rdev[TPS65217_NUM_REGULATOR]; struct regmap *regmap; @@ -263,7 +263,7 @@ static inline struct tps65217 *dev_to_tps65217(struct device *dev) return dev_get_drvdata(dev); } -static inline int tps65217_chip_id(struct tps65217 *tps65217) +static inline unsigned long tps65217_chip_id(struct tps65217 *tps65217) { return tps65217->id; } diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 440a02ee6f9..e8eeebd49a9 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -752,6 +752,9 @@ struct netdev_phys_port_id { unsigned char id_len; }; +typedef u16 (*select_queue_fallback_t)(struct net_device *dev, + struct sk_buff *skb); + /* * This structure defines the management hooks for network devices. * The following hooks can be defined; unless noted otherwise, they are @@ -783,7 +786,7 @@ struct netdev_phys_port_id { * Required can not be NULL. * * u16 (*ndo_select_queue)(struct net_device *dev, struct sk_buff *skb, - * void *accel_priv); + * void *accel_priv, select_queue_fallback_t fallback); * Called to decide which queue to when device supports multiple * transmit queues. * @@ -1005,7 +1008,8 @@ struct net_device_ops { struct net_device *dev); u16 (*ndo_select_queue)(struct net_device *dev, struct sk_buff *skb, - void *accel_priv); + void *accel_priv, + select_queue_fallback_t fallback); void (*ndo_change_rx_flags)(struct net_device *dev, int flags); void (*ndo_set_rx_mode)(struct net_device *dev); @@ -1551,7 +1555,6 @@ static inline void netdev_for_each_tx_queue(struct net_device *dev, struct netdev_queue *netdev_pick_tx(struct net_device *dev, struct sk_buff *skb, void *accel_priv); -u16 __netdev_pick_tx(struct net_device *dev, struct sk_buff *skb); /* * Net namespace inlines @@ -2276,6 +2279,26 @@ static inline void netdev_reset_queue(struct net_device *dev_queue) } /** + * netdev_cap_txqueue - check if selected tx queue exceeds device queues + * @dev: network device + * @queue_index: given tx queue index + * + * Returns 0 if given tx queue index >= number of device tx queues, + * otherwise returns the originally passed tx queue index. + */ +static inline u16 netdev_cap_txqueue(struct net_device *dev, u16 queue_index) +{ + if (unlikely(queue_index >= dev->real_num_tx_queues)) { + net_warn_ratelimited("%s selects TX queue %d, but real number of TX queues is %d\n", + dev->name, queue_index, + dev->real_num_tx_queues); + return 0; + } + + return queue_index; +} + +/** * netif_running - test if up * @dev: network device * @@ -3068,7 +3091,12 @@ void netdev_change_features(struct net_device *dev); void netif_stacked_transfer_operstate(const struct net_device *rootdev, struct net_device *dev); -netdev_features_t netif_skb_features(struct sk_buff *skb); +netdev_features_t netif_skb_dev_features(struct sk_buff *skb, + const struct net_device *dev); +static inline netdev_features_t netif_skb_features(struct sk_buff *skb) +{ + return netif_skb_dev_features(skb, skb->dev); +} static inline bool net_gso_ok(netdev_features_t features, int gso_type) { diff --git a/include/linux/pci.h b/include/linux/pci.h index fb57c892b21..33aa2caf0f0 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -1169,8 +1169,23 @@ void msi_remove_pci_irq_vectors(struct pci_dev *dev); void pci_restore_msi_state(struct pci_dev *dev); int pci_msi_enabled(void); int pci_enable_msi_range(struct pci_dev *dev, int minvec, int maxvec); +static inline int pci_enable_msi_exact(struct pci_dev *dev, int nvec) +{ + int rc = pci_enable_msi_range(dev, nvec, nvec); + if (rc < 0) + return rc; + return 0; +} int pci_enable_msix_range(struct pci_dev *dev, struct msix_entry *entries, int minvec, int maxvec); +static inline int pci_enable_msix_exact(struct pci_dev *dev, + struct msix_entry *entries, int nvec) +{ + int rc = pci_enable_msix_range(dev, entries, nvec, nvec); + if (rc < 0) + return rc; + return 0; +} #else static inline int pci_msi_vec_count(struct pci_dev *dev) { return -ENOSYS; } static inline int pci_enable_msi_block(struct pci_dev *dev, int nvec) @@ -1189,9 +1204,14 @@ static inline int pci_msi_enabled(void) { return 0; } static inline int pci_enable_msi_range(struct pci_dev *dev, int minvec, int maxvec) { return -ENOSYS; } +static inline int pci_enable_msi_exact(struct pci_dev *dev, int nvec) +{ return -ENOSYS; } static inline int pci_enable_msix_range(struct pci_dev *dev, struct msix_entry *entries, int minvec, int maxvec) { return -ENOSYS; } +static inline int pci_enable_msix_exact(struct pci_dev *dev, + struct msix_entry *entries, int nvec) +{ return -ENOSYS; } #endif #ifdef CONFIG_PCIEPORTBUS diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index f589c9af8cb..3ebbbe7b6d0 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -2916,5 +2916,22 @@ static inline bool skb_head_is_locked(const struct sk_buff *skb) { return !skb->head_frag || skb_cloned(skb); } + +/** + * skb_gso_network_seglen - Return length of individual segments of a gso packet + * + * @skb: GSO skb + * + * skb_gso_network_seglen is used to determine the real size of the + * individual segments, including Layer3 (IP, IPv6) and L4 headers (TCP/UDP). + * + * The MAC/L2 header is not accounted for. + */ +static inline unsigned int skb_gso_network_seglen(const struct sk_buff *skb) +{ + unsigned int hdr_len = skb_transport_header(skb) - + skb_network_header(skb); + return hdr_len + skb_gso_transport_seglen(skb); +} #endif /* __KERNEL__ */ #endif /* _LINUX_SKBUFF_H */ diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index 40ed9e9a77e..a747a77ea58 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h @@ -281,13 +281,15 @@ asmlinkage long sys_sched_setscheduler(pid_t pid, int policy, asmlinkage long sys_sched_setparam(pid_t pid, struct sched_param __user *param); asmlinkage long sys_sched_setattr(pid_t pid, - struct sched_attr __user *attr); + struct sched_attr __user *attr, + unsigned int flags); asmlinkage long sys_sched_getscheduler(pid_t pid); asmlinkage long sys_sched_getparam(pid_t pid, struct sched_param __user *param); asmlinkage long sys_sched_getattr(pid_t pid, struct sched_attr __user *attr, - unsigned int size); + unsigned int size, + unsigned int flags); asmlinkage long sys_sched_setaffinity(pid_t pid, unsigned int len, unsigned long __user *user_mask_ptr); asmlinkage long sys_sched_getaffinity(pid_t pid, unsigned int len, diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h index 594521ba0d4..704f4f652d0 100644 --- a/include/linux/workqueue.h +++ b/include/linux/workqueue.h @@ -419,10 +419,7 @@ __alloc_workqueue_key(const char *fmt, unsigned int flags, int max_active, static struct lock_class_key __key; \ const char *__lock_name; \ \ - if (__builtin_constant_p(fmt)) \ - __lock_name = (fmt); \ - else \ - __lock_name = #fmt; \ + __lock_name = #fmt#args; \ \ __alloc_workqueue_key((fmt), (flags), (max_active), \ &__key, __lock_name, ##args); \ diff --git a/include/linux/writeback.h b/include/linux/writeback.h index fc0e4320aa6..021b8a319b9 100644 --- a/include/linux/writeback.h +++ b/include/linux/writeback.h @@ -97,7 +97,7 @@ void writeback_inodes_sb_nr(struct super_block *, unsigned long nr, int try_to_writeback_inodes_sb(struct super_block *, enum wb_reason reason); int try_to_writeback_inodes_sb_nr(struct super_block *, unsigned long nr, enum wb_reason reason); -void sync_inodes_sb(struct super_block *sb, unsigned long older_than_this); +void sync_inodes_sb(struct super_block *); void wakeup_flusher_threads(long nr_pages, enum wb_reason reason); void inode_wait_for_writeback(struct inode *inode); diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index d992ca3145f..6ee76c80489 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -1653,17 +1653,6 @@ struct sctp_association { /* This is the last advertised value of rwnd over a SACK chunk. */ __u32 a_rwnd; - /* Number of bytes by which the rwnd has slopped. The rwnd is allowed - * to slop over a maximum of the association's frag_point. - */ - __u32 rwnd_over; - - /* Keeps treack of rwnd pressure. This happens when we have - * a window, but not recevie buffer (i.e small packets). This one - * is releases slowly (1 PMTU at a time ). - */ - __u32 rwnd_press; - /* This is the sndbuf size in use for the association. * This corresponds to the sndbuf size for the association, * as specified in the sk->sndbuf. @@ -1892,8 +1881,7 @@ void sctp_assoc_update(struct sctp_association *old, __u32 sctp_association_get_next_tsn(struct sctp_association *); void sctp_assoc_sync_pmtu(struct sock *, struct sctp_association *); -void sctp_assoc_rwnd_increase(struct sctp_association *, unsigned int); -void sctp_assoc_rwnd_decrease(struct sctp_association *, unsigned int); +void sctp_assoc_rwnd_update(struct sctp_association *, bool); void sctp_assoc_set_primary(struct sctp_association *, struct sctp_transport *); void sctp_assoc_del_nonprimary_peers(struct sctp_association *, diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index 68d92e36fac..6e89ef6c11c 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -449,14 +449,22 @@ void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm, /* dapm audio pin control and status */ int snd_soc_dapm_enable_pin(struct snd_soc_dapm_context *dapm, const char *pin); +int snd_soc_dapm_enable_pin_unlocked(struct snd_soc_dapm_context *dapm, + const char *pin); int snd_soc_dapm_disable_pin(struct snd_soc_dapm_context *dapm, const char *pin); +int snd_soc_dapm_disable_pin_unlocked(struct snd_soc_dapm_context *dapm, + const char *pin); int snd_soc_dapm_nc_pin(struct snd_soc_dapm_context *dapm, const char *pin); +int snd_soc_dapm_nc_pin_unlocked(struct snd_soc_dapm_context *dapm, + const char *pin); int snd_soc_dapm_get_pin_status(struct snd_soc_dapm_context *dapm, const char *pin); int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm); int snd_soc_dapm_force_enable_pin(struct snd_soc_dapm_context *dapm, const char *pin); +int snd_soc_dapm_force_enable_pin_unlocked(struct snd_soc_dapm_context *dapm, + const char *pin); int snd_soc_dapm_ignore_suspend(struct snd_soc_dapm_context *dapm, const char *pin); void snd_soc_dapm_auto_nc_codec_pins(struct snd_soc_codec *codec); diff --git a/include/trace/events/writeback.h b/include/trace/events/writeback.h index c7bbbe794e6..464ea82e10d 100644 --- a/include/trace/events/writeback.h +++ b/include/trace/events/writeback.h @@ -287,11 +287,11 @@ TRACE_EVENT(writeback_queue_io, __field(int, reason) ), TP_fast_assign( - unsigned long older_than_this = work->older_than_this; + unsigned long *older_than_this = work->older_than_this; strncpy(__entry->name, dev_name(wb->bdi->dev), 32); - __entry->older = older_than_this; + __entry->older = older_than_this ? *older_than_this : 0; __entry->age = older_than_this ? - (jiffies - older_than_this) * 1000 / HZ : -1; + (jiffies - *older_than_this) * 1000 / HZ : -1; __entry->moved = moved; __entry->reason = work->reason; ), diff --git a/include/uapi/asm-generic/unistd.h b/include/uapi/asm-generic/unistd.h index a20a9b4d387..dde8041f40d 100644 --- a/include/uapi/asm-generic/unistd.h +++ b/include/uapi/asm-generic/unistd.h @@ -692,9 +692,13 @@ __SC_COMP(__NR_process_vm_writev, sys_process_vm_writev, \ __SYSCALL(__NR_kcmp, sys_kcmp) #define __NR_finit_module 273 __SYSCALL(__NR_finit_module, sys_finit_module) +#define __NR_sched_setattr 274 +__SYSCALL(__NR_sched_setattr, sys_sched_setattr) +#define __NR_sched_getattr 275 +__SYSCALL(__NR_sched_getattr, sys_sched_getattr) #undef __NR_syscalls -#define __NR_syscalls 274 +#define __NR_syscalls 276 /* * All syscalls below here should go away really, diff --git a/include/uapi/drm/drm.h b/include/uapi/drm/drm.h index 3c9a833992e..b06c8ed6870 100644 --- a/include/uapi/drm/drm.h +++ b/include/uapi/drm/drm.h @@ -619,6 +619,8 @@ struct drm_gem_open { #define DRM_PRIME_CAP_EXPORT 0x2 #define DRM_CAP_TIMESTAMP_MONOTONIC 0x6 #define DRM_CAP_ASYNC_PAGE_FLIP 0x7 +#define DRM_CAP_CURSOR_WIDTH 0x8 +#define DRM_CAP_CURSOR_HEIGHT 0x9 /** DRM_IOCTL_GET_CAP ioctl argument type */ struct drm_get_cap { diff --git a/include/uapi/drm/vmwgfx_drm.h b/include/uapi/drm/vmwgfx_drm.h index 9971c560ed9..87792a5fee3 100644 --- a/include/uapi/drm/vmwgfx_drm.h +++ b/include/uapi/drm/vmwgfx_drm.h @@ -87,6 +87,7 @@ #define DRM_VMW_PARAM_MAX_SURF_MEMORY 7 #define DRM_VMW_PARAM_3D_CAPS_SIZE 8 #define DRM_VMW_PARAM_MAX_MOB_MEMORY 9 +#define DRM_VMW_PARAM_MAX_MOB_SIZE 10 /** * struct drm_vmw_getparam_arg diff --git a/ipc/mq_sysctl.c b/ipc/mq_sysctl.c index 383d638340b..5bb8bfe6714 100644 --- a/ipc/mq_sysctl.c +++ b/ipc/mq_sysctl.c @@ -22,6 +22,16 @@ static void *get_mq(ctl_table *table) return which; } +static int proc_mq_dointvec(ctl_table *table, int write, + void __user *buffer, size_t *lenp, loff_t *ppos) +{ + struct ctl_table mq_table; + memcpy(&mq_table, table, sizeof(mq_table)); + mq_table.data = get_mq(table); + + return proc_dointvec(&mq_table, write, buffer, lenp, ppos); +} + static int proc_mq_dointvec_minmax(ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos) { @@ -33,12 +43,10 @@ static int proc_mq_dointvec_minmax(ctl_table *table, int write, lenp, ppos); } #else +#define proc_mq_dointvec NULL #define proc_mq_dointvec_minmax NULL #endif -static int msg_queues_limit_min = MIN_QUEUESMAX; -static int msg_queues_limit_max = HARD_QUEUESMAX; - static int msg_max_limit_min = MIN_MSGMAX; static int msg_max_limit_max = HARD_MSGMAX; @@ -51,9 +59,7 @@ static ctl_table mq_sysctls[] = { .data = &init_ipc_ns.mq_queues_max, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = proc_mq_dointvec_minmax, - .extra1 = &msg_queues_limit_min, - .extra2 = &msg_queues_limit_max, + .proc_handler = proc_mq_dointvec, }, { .procname = "msg_max", diff --git a/ipc/mqueue.c b/ipc/mqueue.c index ccf1f9fd263..c3b31179122 100644 --- a/ipc/mqueue.c +++ b/ipc/mqueue.c @@ -433,9 +433,9 @@ static int mqueue_create(struct inode *dir, struct dentry *dentry, error = -EACCES; goto out_unlock; } - if (ipc_ns->mq_queues_count >= HARD_QUEUESMAX || - (ipc_ns->mq_queues_count >= ipc_ns->mq_queues_max && - !capable(CAP_SYS_RESOURCE))) { + + if (ipc_ns->mq_queues_count >= ipc_ns->mq_queues_max && + !capable(CAP_SYS_RESOURCE)) { error = -ENOSPC; goto out_unlock; } diff --git a/kernel/audit_tree.c b/kernel/audit_tree.c index 67ccf0e7cca..135944a7b28 100644 --- a/kernel/audit_tree.c +++ b/kernel/audit_tree.c @@ -916,7 +916,7 @@ static int audit_tree_handle_event(struct fsnotify_group *group, struct fsnotify_mark *inode_mark, struct fsnotify_mark *vfsmount_mark, u32 mask, void *data, int data_type, - const unsigned char *file_name) + const unsigned char *file_name, u32 cookie) { return 0; } diff --git a/kernel/audit_watch.c b/kernel/audit_watch.c index 2596fac5dcb..70b4554d2fb 100644 --- a/kernel/audit_watch.c +++ b/kernel/audit_watch.c @@ -471,7 +471,7 @@ static int audit_watch_handle_event(struct fsnotify_group *group, struct fsnotify_mark *inode_mark, struct fsnotify_mark *vfsmount_mark, u32 mask, void *data, int data_type, - const unsigned char *dname) + const unsigned char *dname, u32 cookie) { struct inode *inode; struct audit_parent *parent; diff --git a/kernel/cgroup.c b/kernel/cgroup.c index e2f46ba37f7..105f273b6f8 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -886,7 +886,9 @@ static void cgroup_diput(struct dentry *dentry, struct inode *inode) * per-subsystem and moved to css->id so that lookups are * successful until the target css is released. */ + mutex_lock(&cgroup_mutex); idr_remove(&cgrp->root->cgroup_idr, cgrp->id); + mutex_unlock(&cgroup_mutex); cgrp->id = -1; call_rcu(&cgrp->rcu_head, cgroup_free_rcu); @@ -1566,10 +1568,10 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type, mutex_lock(&cgroup_mutex); mutex_lock(&cgroup_root_mutex); - root_cgrp->id = idr_alloc(&root->cgroup_idr, root_cgrp, - 0, 1, GFP_KERNEL); - if (root_cgrp->id < 0) + ret = idr_alloc(&root->cgroup_idr, root_cgrp, 0, 1, GFP_KERNEL); + if (ret < 0) goto unlock_drop; + root_cgrp->id = ret; /* Check for name clashes with existing mounts */ ret = -EBUSY; @@ -2763,10 +2765,7 @@ static int cgroup_cfts_commit(struct cftype *cfts, bool is_add) */ update_before = cgroup_serial_nr_next; - mutex_unlock(&cgroup_mutex); - /* add/rm files for all cgroups created before */ - rcu_read_lock(); css_for_each_descendant_pre(css, cgroup_css(root, ss)) { struct cgroup *cgrp = css->cgroup; @@ -2775,23 +2774,19 @@ static int cgroup_cfts_commit(struct cftype *cfts, bool is_add) inode = cgrp->dentry->d_inode; dget(cgrp->dentry); - rcu_read_unlock(); - dput(prev); prev = cgrp->dentry; + mutex_unlock(&cgroup_mutex); mutex_lock(&inode->i_mutex); mutex_lock(&cgroup_mutex); if (cgrp->serial_nr < update_before && !cgroup_is_dead(cgrp)) ret = cgroup_addrm_files(cgrp, cfts, is_add); - mutex_unlock(&cgroup_mutex); mutex_unlock(&inode->i_mutex); - - rcu_read_lock(); if (ret) break; } - rcu_read_unlock(); + mutex_unlock(&cgroup_mutex); dput(prev); deactivate_super(sb); return ret; @@ -2910,9 +2905,14 @@ static void cgroup_enable_task_cg_lists(void) * We should check if the process is exiting, otherwise * it will race with cgroup_exit() in that the list * entry won't be deleted though the process has exited. + * Do it while holding siglock so that we don't end up + * racing against cgroup_exit(). */ + spin_lock_irq(&p->sighand->siglock); if (!(p->flags & PF_EXITING) && list_empty(&p->cg_list)) list_add(&p->cg_list, &task_css_set(p)->tasks); + spin_unlock_irq(&p->sighand->siglock); + task_unlock(p); } while_each_thread(g, p); read_unlock(&tasklist_lock); @@ -4158,7 +4158,7 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry, struct cgroup *cgrp; struct cgroup_name *name; struct cgroupfs_root *root = parent->root; - int ssid, err = 0; + int ssid, err; struct cgroup_subsys *ss; struct super_block *sb = root->sb; @@ -4168,19 +4168,13 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry, return -ENOMEM; name = cgroup_alloc_name(dentry); - if (!name) + if (!name) { + err = -ENOMEM; goto err_free_cgrp; + } rcu_assign_pointer(cgrp->name, name); /* - * Temporarily set the pointer to NULL, so idr_find() won't return - * a half-baked cgroup. - */ - cgrp->id = idr_alloc(&root->cgroup_idr, NULL, 1, 0, GFP_KERNEL); - if (cgrp->id < 0) - goto err_free_name; - - /* * Only live parents can have children. Note that the liveliness * check isn't strictly necessary because cgroup_mkdir() and * cgroup_rmdir() are fully synchronized by i_mutex; however, do it @@ -4189,7 +4183,17 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry, */ if (!cgroup_lock_live_group(parent)) { err = -ENODEV; - goto err_free_id; + goto err_free_name; + } + + /* + * Temporarily set the pointer to NULL, so idr_find() won't return + * a half-baked cgroup. + */ + cgrp->id = idr_alloc(&root->cgroup_idr, NULL, 1, 0, GFP_KERNEL); + if (cgrp->id < 0) { + err = -ENOMEM; + goto err_unlock; } /* Grab a reference on the superblock so the hierarchy doesn't @@ -4221,7 +4225,7 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry, */ err = cgroup_create_file(dentry, S_IFDIR | mode, sb); if (err < 0) - goto err_unlock; + goto err_free_id; lockdep_assert_held(&dentry->d_inode->i_mutex); cgrp->serial_nr = cgroup_serial_nr_next++; @@ -4257,12 +4261,12 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry, return 0; -err_unlock: - mutex_unlock(&cgroup_mutex); - /* Release the reference count that we took on the superblock */ - deactivate_super(sb); err_free_id: idr_remove(&root->cgroup_idr, cgrp->id); + /* Release the reference count that we took on the superblock */ + deactivate_super(sb); +err_unlock: + mutex_unlock(&cgroup_mutex); err_free_name: kfree(rcu_dereference_raw(cgrp->name)); err_free_cgrp: diff --git a/kernel/events/core.c b/kernel/events/core.c index 56003c6edfd..fa0b2d4ad83 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -7856,14 +7856,14 @@ static void perf_pmu_rotate_stop(struct pmu *pmu) static void __perf_event_exit_context(void *__info) { struct perf_event_context *ctx = __info; - struct perf_event *event, *tmp; + struct perf_event *event; perf_pmu_rotate_stop(ctx->pmu); - list_for_each_entry_safe(event, tmp, &ctx->pinned_groups, group_entry) - __perf_remove_from_context(event); - list_for_each_entry_safe(event, tmp, &ctx->flexible_groups, group_entry) + rcu_read_lock(); + list_for_each_entry_rcu(event, &ctx->event_list, event_entry) __perf_remove_from_context(event); + rcu_read_unlock(); } static void perf_event_exit_cpu_context(int cpu) @@ -7887,11 +7887,11 @@ static void perf_event_exit_cpu(int cpu) { struct swevent_htable *swhash = &per_cpu(swevent_htable, cpu); + perf_event_exit_cpu_context(cpu); + mutex_lock(&swhash->hlist_mutex); swevent_hlist_release(swhash); mutex_unlock(&swhash->hlist_mutex); - - perf_event_exit_cpu_context(cpu); } #else static inline void perf_event_exit_cpu(int cpu) { } diff --git a/kernel/power/console.c b/kernel/power/console.c index eacb8bd8cab..aba9c545a0e 100644 --- a/kernel/power/console.c +++ b/kernel/power/console.c @@ -9,6 +9,7 @@ #include <linux/kbd_kern.h> #include <linux/vt.h> #include <linux/module.h> +#include <linux/slab.h> #include "power.h" #define SUSPEND_CONSOLE (MAX_NR_CONSOLES-1) diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index b1d255f0413..4dae9cbe925 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -1076,7 +1076,6 @@ static int syslog_print_all(char __user *buf, int size, bool clear) next_seq = log_next_seq; len = 0; - prev = 0; while (len >= 0 && seq < next_seq) { struct printk_log *msg = log_from_idx(idx); int textlen; @@ -2788,7 +2787,6 @@ bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog, next_idx = idx; l = 0; - prev = 0; while (seq < dumper->next_seq) { struct printk_log *msg = log_from_idx(idx); diff --git a/kernel/sched/core.c b/kernel/sched/core.c index b46131ef6aa..6edbef296ec 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -1952,7 +1952,7 @@ static int dl_overflow(struct task_struct *p, int policy, { struct dl_bw *dl_b = dl_bw_of(task_cpu(p)); - u64 period = attr->sched_period; + u64 period = attr->sched_period ?: attr->sched_deadline; u64 runtime = attr->sched_runtime; u64 new_bw = dl_policy(policy) ? to_ratio(period, runtime) : 0; int cpus, err = -1; @@ -3661,13 +3661,14 @@ SYSCALL_DEFINE2(sched_setparam, pid_t, pid, struct sched_param __user *, param) * @pid: the pid in question. * @uattr: structure containing the extended parameters. */ -SYSCALL_DEFINE2(sched_setattr, pid_t, pid, struct sched_attr __user *, uattr) +SYSCALL_DEFINE3(sched_setattr, pid_t, pid, struct sched_attr __user *, uattr, + unsigned int, flags) { struct sched_attr attr; struct task_struct *p; int retval; - if (!uattr || pid < 0) + if (!uattr || pid < 0 || flags) return -EINVAL; if (sched_copy_attr(uattr, &attr)) @@ -3786,7 +3787,7 @@ static int sched_read_attr(struct sched_attr __user *uattr, attr->size = usize; } - ret = copy_to_user(uattr, attr, usize); + ret = copy_to_user(uattr, attr, attr->size); if (ret) return -EFAULT; @@ -3804,8 +3805,8 @@ err_size: * @uattr: structure containing the extended parameters. * @size: sizeof(attr) for fwd/bwd comp. */ -SYSCALL_DEFINE3(sched_getattr, pid_t, pid, struct sched_attr __user *, uattr, - unsigned int, size) +SYSCALL_DEFINE4(sched_getattr, pid_t, pid, struct sched_attr __user *, uattr, + unsigned int, size, unsigned int, flags) { struct sched_attr attr = { .size = sizeof(struct sched_attr), @@ -3814,7 +3815,7 @@ SYSCALL_DEFINE3(sched_getattr, pid_t, pid, struct sched_attr __user *, uattr, int retval; if (!uattr || pid < 0 || size > PAGE_SIZE || - size < SCHED_ATTR_SIZE_VER0) + size < SCHED_ATTR_SIZE_VER0 || flags) return -EINVAL; rcu_read_lock(); @@ -7422,6 +7423,7 @@ static int sched_dl_global_constraints(void) u64 period = global_rt_period(); u64 new_bw = to_ratio(period, runtime); int cpu, ret = 0; + unsigned long flags; /* * Here we want to check the bandwidth not being set to some @@ -7435,10 +7437,10 @@ static int sched_dl_global_constraints(void) for_each_possible_cpu(cpu) { struct dl_bw *dl_b = dl_bw_of(cpu); - raw_spin_lock(&dl_b->lock); + raw_spin_lock_irqsave(&dl_b->lock, flags); if (new_bw < dl_b->total_bw) ret = -EBUSY; - raw_spin_unlock(&dl_b->lock); + raw_spin_unlock_irqrestore(&dl_b->lock, flags); if (ret) break; @@ -7451,6 +7453,7 @@ static void sched_dl_do_global(void) { u64 new_bw = -1; int cpu; + unsigned long flags; def_dl_bandwidth.dl_period = global_rt_period(); def_dl_bandwidth.dl_runtime = global_rt_runtime(); @@ -7464,9 +7467,9 @@ static void sched_dl_do_global(void) for_each_possible_cpu(cpu) { struct dl_bw *dl_b = dl_bw_of(cpu); - raw_spin_lock(&dl_b->lock); + raw_spin_lock_irqsave(&dl_b->lock, flags); dl_b->bw = new_bw; - raw_spin_unlock(&dl_b->lock); + raw_spin_unlock_irqrestore(&dl_b->lock, flags); } } @@ -7475,7 +7478,8 @@ static int sched_rt_global_validate(void) if (sysctl_sched_rt_period <= 0) return -EINVAL; - if (sysctl_sched_rt_runtime > sysctl_sched_rt_period) + if ((sysctl_sched_rt_runtime != RUNTIME_INF) && + (sysctl_sched_rt_runtime > sysctl_sched_rt_period)) return -EINVAL; return 0; diff --git a/kernel/sched/cpudeadline.c b/kernel/sched/cpudeadline.c index 045fc74e3f0..5b8838b56d1 100644 --- a/kernel/sched/cpudeadline.c +++ b/kernel/sched/cpudeadline.c @@ -70,7 +70,7 @@ static void cpudl_heapify(struct cpudl *cp, int idx) static void cpudl_change_key(struct cpudl *cp, int idx, u64 new_dl) { - WARN_ON(idx > num_present_cpus() || idx == IDX_INVALID); + WARN_ON(!cpu_present(idx) || idx == IDX_INVALID); if (dl_time_before(new_dl, cp->elements[idx].dl)) { cp->elements[idx].dl = new_dl; @@ -117,7 +117,7 @@ int cpudl_find(struct cpudl *cp, struct task_struct *p, } out: - WARN_ON(best_cpu > num_present_cpus() && best_cpu != -1); + WARN_ON(!cpu_present(best_cpu) && best_cpu != -1); return best_cpu; } @@ -137,7 +137,7 @@ void cpudl_set(struct cpudl *cp, int cpu, u64 dl, int is_valid) int old_idx, new_cpu; unsigned long flags; - WARN_ON(cpu > num_present_cpus()); + WARN_ON(!cpu_present(cpu)); raw_spin_lock_irqsave(&cp->lock, flags); old_idx = cp->cpu_to_idx[cpu]; diff --git a/kernel/sched/deadline.c b/kernel/sched/deadline.c index 0dd5e0971a0..15cbc17fbf8 100644 --- a/kernel/sched/deadline.c +++ b/kernel/sched/deadline.c @@ -121,7 +121,7 @@ static inline void dl_clear_overload(struct rq *rq) static void update_dl_migration(struct dl_rq *dl_rq) { - if (dl_rq->dl_nr_migratory && dl_rq->dl_nr_total > 1) { + if (dl_rq->dl_nr_migratory && dl_rq->dl_nr_running > 1) { if (!dl_rq->overloaded) { dl_set_overload(rq_of_dl_rq(dl_rq)); dl_rq->overloaded = 1; @@ -137,7 +137,6 @@ static void inc_dl_migration(struct sched_dl_entity *dl_se, struct dl_rq *dl_rq) struct task_struct *p = dl_task_of(dl_se); dl_rq = &rq_of_dl_rq(dl_rq)->dl; - dl_rq->dl_nr_total++; if (p->nr_cpus_allowed > 1) dl_rq->dl_nr_migratory++; @@ -149,7 +148,6 @@ static void dec_dl_migration(struct sched_dl_entity *dl_se, struct dl_rq *dl_rq) struct task_struct *p = dl_task_of(dl_se); dl_rq = &rq_of_dl_rq(dl_rq)->dl; - dl_rq->dl_nr_total--; if (p->nr_cpus_allowed > 1) dl_rq->dl_nr_migratory--; @@ -717,6 +715,7 @@ void inc_dl_tasks(struct sched_dl_entity *dl_se, struct dl_rq *dl_rq) WARN_ON(!dl_prio(prio)); dl_rq->dl_nr_running++; + inc_nr_running(rq_of_dl_rq(dl_rq)); inc_dl_deadline(dl_rq, deadline); inc_dl_migration(dl_se, dl_rq); @@ -730,6 +729,7 @@ void dec_dl_tasks(struct sched_dl_entity *dl_se, struct dl_rq *dl_rq) WARN_ON(!dl_prio(prio)); WARN_ON(!dl_rq->dl_nr_running); dl_rq->dl_nr_running--; + dec_nr_running(rq_of_dl_rq(dl_rq)); dec_dl_deadline(dl_rq, dl_se->deadline); dec_dl_migration(dl_se, dl_rq); @@ -836,8 +836,6 @@ static void enqueue_task_dl(struct rq *rq, struct task_struct *p, int flags) if (!task_current(rq, p) && p->nr_cpus_allowed > 1) enqueue_pushable_dl_task(rq, p); - - inc_nr_running(rq); } static void __dequeue_task_dl(struct rq *rq, struct task_struct *p, int flags) @@ -850,8 +848,6 @@ static void dequeue_task_dl(struct rq *rq, struct task_struct *p, int flags) { update_curr_dl(rq); __dequeue_task_dl(rq, p, flags); - - dec_nr_running(rq); } /* diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 966cc2bfcb7..78157099b16 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -1757,6 +1757,8 @@ void task_numa_work(struct callback_head *work) start = end; if (pages <= 0) goto out; + + cond_resched(); } while (end != vma->vm_end); } diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index c2119fd20f8..f964add50f3 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -462,7 +462,6 @@ struct dl_rq { } earliest_dl; unsigned long dl_nr_migratory; - unsigned long dl_nr_total; int overloaded; /* diff --git a/kernel/time/sched_clock.c b/kernel/time/sched_clock.c index 0abb3646428..4d23dc4d813 100644 --- a/kernel/time/sched_clock.c +++ b/kernel/time/sched_clock.c @@ -116,20 +116,42 @@ static enum hrtimer_restart sched_clock_poll(struct hrtimer *hrt) void __init sched_clock_register(u64 (*read)(void), int bits, unsigned long rate) { + u64 res, wrap, new_mask, new_epoch, cyc, ns; + u32 new_mult, new_shift; + ktime_t new_wrap_kt; unsigned long r; - u64 res, wrap; char r_unit; if (cd.rate > rate) return; WARN_ON(!irqs_disabled()); - read_sched_clock = read; - sched_clock_mask = CLOCKSOURCE_MASK(bits); - cd.rate = rate; /* calculate the mult/shift to convert counter ticks to ns. */ - clocks_calc_mult_shift(&cd.mult, &cd.shift, rate, NSEC_PER_SEC, 3600); + clocks_calc_mult_shift(&new_mult, &new_shift, rate, NSEC_PER_SEC, 3600); + + new_mask = CLOCKSOURCE_MASK(bits); + + /* calculate how many ns until we wrap */ + wrap = clocks_calc_max_nsecs(new_mult, new_shift, 0, new_mask); + new_wrap_kt = ns_to_ktime(wrap - (wrap >> 3)); + + /* update epoch for new counter and update epoch_ns from old counter*/ + new_epoch = read(); + cyc = read_sched_clock(); + ns = cd.epoch_ns + cyc_to_ns((cyc - cd.epoch_cyc) & sched_clock_mask, + cd.mult, cd.shift); + + raw_write_seqcount_begin(&cd.seq); + read_sched_clock = read; + sched_clock_mask = new_mask; + cd.rate = rate; + cd.wrap_kt = new_wrap_kt; + cd.mult = new_mult; + cd.shift = new_shift; + cd.epoch_cyc = new_epoch; + cd.epoch_ns = ns; + raw_write_seqcount_end(&cd.seq); r = rate; if (r >= 4000000) { @@ -141,22 +163,12 @@ void __init sched_clock_register(u64 (*read)(void), int bits, } else r_unit = ' '; - /* calculate how many ns until we wrap */ - wrap = clocks_calc_max_nsecs(cd.mult, cd.shift, 0, sched_clock_mask); - cd.wrap_kt = ns_to_ktime(wrap - (wrap >> 3)); - /* calculate the ns resolution of this counter */ - res = cyc_to_ns(1ULL, cd.mult, cd.shift); + res = cyc_to_ns(1ULL, new_mult, new_shift); + pr_info("sched_clock: %u bits at %lu%cHz, resolution %lluns, wraps every %lluns\n", bits, r, r_unit, res, wrap); - update_sched_clock(); - - /* - * Ensure that sched_clock() starts off at 0ns - */ - cd.epoch_ns = 0; - /* Enable IRQ time accounting if we have a fast enough sched_clock */ if (irqtime > 0 || (irqtime == -1 && rate >= 1000000)) enable_sched_clock_irqtime(); diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c index 240fb62cf39..dd06439b9c8 100644 --- a/kernel/user_namespace.c +++ b/kernel/user_namespace.c @@ -225,7 +225,7 @@ static u32 map_id_up(struct uid_gid_map *map, u32 id) * * When there is no mapping defined for the user-namespace uid * pair INVALID_UID is returned. Callers are expected to test - * for and handle handle INVALID_UID being returned. INVALID_UID + * for and handle INVALID_UID being returned. INVALID_UID * may be tested for using uid_valid(). */ kuid_t make_kuid(struct user_namespace *ns, uid_t uid) diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 82ef9f3b747..193e977a10e 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -1851,6 +1851,12 @@ static void destroy_worker(struct worker *worker) if (worker->flags & WORKER_IDLE) pool->nr_idle--; + /* + * Once WORKER_DIE is set, the kworker may destroy itself at any + * point. Pin to ensure the task stays until we're done with it. + */ + get_task_struct(worker->task); + list_del_init(&worker->entry); worker->flags |= WORKER_DIE; @@ -1859,6 +1865,7 @@ static void destroy_worker(struct worker *worker) spin_unlock_irq(&pool->lock); kthread_stop(worker->task); + put_task_struct(worker->task); kfree(worker); spin_lock_irq(&pool->lock); diff --git a/mm/huge_memory.c b/mm/huge_memory.c index 82166bf974e..4df39b1bde9 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -1166,8 +1166,10 @@ alloc: } else { ret = do_huge_pmd_wp_page_fallback(mm, vma, address, pmd, orig_pmd, page, haddr); - if (ret & VM_FAULT_OOM) + if (ret & VM_FAULT_OOM) { split_huge_page(page); + ret |= VM_FAULT_FALLBACK; + } put_page(page); } count_vm_event(THP_FAULT_FALLBACK); @@ -1179,9 +1181,10 @@ alloc: if (page) { split_huge_page(page); put_page(page); - } + } else + split_huge_page_pmd(vma, address, pmd); + ret |= VM_FAULT_FALLBACK; count_vm_event(THP_FAULT_FALLBACK); - ret |= VM_FAULT_OOM; goto out; } @@ -1545,6 +1548,7 @@ int change_huge_pmd(struct vm_area_struct *vma, pmd_t *pmd, entry = pmd_mknonnuma(entry); entry = pmd_modify(entry, newprot); ret = HPAGE_PMD_NR; + set_pmd_at(mm, addr, pmd, entry); BUG_ON(pmd_write(entry)); } else { struct page *page = pmd_page(*pmd); @@ -1557,16 +1561,10 @@ int change_huge_pmd(struct vm_area_struct *vma, pmd_t *pmd, */ if (!is_huge_zero_page(page) && !pmd_numa(*pmd)) { - entry = *pmd; - entry = pmd_mknuma(entry); + pmdp_set_numa(mm, addr, pmd); ret = HPAGE_PMD_NR; } } - - /* Set PMD if cleared earlier */ - if (ret == HPAGE_PMD_NR) - set_pmd_at(mm, addr, pmd, entry); - spin_unlock(ptl); } diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 53385cd4e6f..ce7a8cc7b40 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -1687,7 +1687,7 @@ void mem_cgroup_print_oom_info(struct mem_cgroup *memcg, struct task_struct *p) * protects memcg_name and makes sure that parallel ooms do not * interleave */ - static DEFINE_SPINLOCK(oom_info_lock); + static DEFINE_MUTEX(oom_info_lock); struct cgroup *task_cgrp; struct cgroup *mem_cgrp; static char memcg_name[PATH_MAX]; @@ -1698,7 +1698,7 @@ void mem_cgroup_print_oom_info(struct mem_cgroup *memcg, struct task_struct *p) if (!p) return; - spin_lock(&oom_info_lock); + mutex_lock(&oom_info_lock); rcu_read_lock(); mem_cgrp = memcg->css.cgroup; @@ -1767,7 +1767,7 @@ done: pr_cont("\n"); } - spin_unlock(&oom_info_lock); + mutex_unlock(&oom_info_lock); } /* diff --git a/mm/memory.c b/mm/memory.c index be6a0c0d4ae..22dfa617bdd 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -3348,6 +3348,7 @@ static int __do_fault(struct mm_struct *mm, struct vm_area_struct *vma, if (ret & VM_FAULT_LOCKED) unlock_page(vmf.page); ret = VM_FAULT_HWPOISON; + page_cache_release(vmf.page); goto uncharge_out; } @@ -3703,7 +3704,6 @@ static int __handle_mm_fault(struct mm_struct *mm, struct vm_area_struct *vma, if (unlikely(is_vm_hugetlb_page(vma))) return hugetlb_fault(mm, vma, address, flags); -retry: pgd = pgd_offset(mm, address); pud = pud_alloc(mm, pgd, address); if (!pud) @@ -3741,20 +3741,13 @@ retry: if (dirty && !pmd_write(orig_pmd)) { ret = do_huge_pmd_wp_page(mm, vma, address, pmd, orig_pmd); - /* - * If COW results in an oom, the huge pmd will - * have been split, so retry the fault on the - * pte for a smaller charge. - */ - if (unlikely(ret & VM_FAULT_OOM)) - goto retry; - return ret; + if (!(ret & VM_FAULT_FALLBACK)) + return ret; } else { huge_pmd_set_accessed(mm, vma, address, pmd, orig_pmd, dirty); + return 0; } - - return 0; } } diff --git a/mm/mprotect.c b/mm/mprotect.c index 7332c178574..769a67a1580 100644 --- a/mm/mprotect.c +++ b/mm/mprotect.c @@ -58,36 +58,27 @@ static unsigned long change_pte_range(struct vm_area_struct *vma, pmd_t *pmd, if (pte_numa(ptent)) ptent = pte_mknonnuma(ptent); ptent = pte_modify(ptent, newprot); + /* + * Avoid taking write faults for pages we + * know to be dirty. + */ + if (dirty_accountable && pte_dirty(ptent)) + ptent = pte_mkwrite(ptent); + ptep_modify_prot_commit(mm, addr, pte, ptent); updated = true; } else { struct page *page; - ptent = *pte; page = vm_normal_page(vma, addr, oldpte); if (page && !PageKsm(page)) { if (!pte_numa(oldpte)) { - ptent = pte_mknuma(ptent); - set_pte_at(mm, addr, pte, ptent); + ptep_set_numa(mm, addr, pte); updated = true; } } } - - /* - * Avoid taking write faults for pages we know to be - * dirty. - */ - if (dirty_accountable && pte_dirty(ptent)) { - ptent = pte_mkwrite(ptent); - updated = true; - } - if (updated) pages++; - - /* Only !prot_numa always clears the pte */ - if (!prot_numa) - ptep_modify_prot_commit(mm, addr, pte, ptent); } else if (IS_ENABLED(CONFIG_MIGRATION) && !pte_file(oldpte)) { swp_entry_t entry = pte_to_swp_entry(oldpte); diff --git a/mm/vmpressure.c b/mm/vmpressure.c index 196970a4541..d4042e75f7c 100644 --- a/mm/vmpressure.c +++ b/mm/vmpressure.c @@ -19,6 +19,7 @@ #include <linux/mm.h> #include <linux/vmstat.h> #include <linux/eventfd.h> +#include <linux/slab.h> #include <linux/swap.h> #include <linux/printk.h> #include <linux/vmpressure.h> diff --git a/net/batman-adv/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c index 512159bf607..8323bced8e5 100644 --- a/net/batman-adv/bat_iv_ogm.c +++ b/net/batman-adv/bat_iv_ogm.c @@ -241,19 +241,19 @@ batadv_iv_ogm_orig_get(struct batadv_priv *bat_priv, const uint8_t *addr) size = bat_priv->num_ifaces * sizeof(uint8_t); orig_node->bat_iv.bcast_own_sum = kzalloc(size, GFP_ATOMIC); if (!orig_node->bat_iv.bcast_own_sum) - goto free_bcast_own; + goto free_orig_node; hash_added = batadv_hash_add(bat_priv->orig_hash, batadv_compare_orig, batadv_choose_orig, orig_node, &orig_node->hash_entry); if (hash_added != 0) - goto free_bcast_own; + goto free_orig_node; return orig_node; -free_bcast_own: - kfree(orig_node->bat_iv.bcast_own); free_orig_node: + /* free twice, as batadv_orig_node_new sets refcount to 2 */ + batadv_orig_node_free_ref(orig_node); batadv_orig_node_free_ref(orig_node); return NULL; @@ -266,7 +266,7 @@ batadv_iv_ogm_neigh_new(struct batadv_hard_iface *hard_iface, struct batadv_orig_node *orig_neigh) { struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface); - struct batadv_neigh_node *neigh_node; + struct batadv_neigh_node *neigh_node, *tmp_neigh_node; neigh_node = batadv_neigh_node_new(hard_iface, neigh_addr, orig_node); if (!neigh_node) @@ -281,14 +281,24 @@ batadv_iv_ogm_neigh_new(struct batadv_hard_iface *hard_iface, neigh_node->orig_node = orig_neigh; neigh_node->if_incoming = hard_iface; - batadv_dbg(BATADV_DBG_BATMAN, bat_priv, - "Creating new neighbor %pM for orig_node %pM on interface %s\n", - neigh_addr, orig_node->orig, hard_iface->net_dev->name); - spin_lock_bh(&orig_node->neigh_list_lock); - hlist_add_head_rcu(&neigh_node->list, &orig_node->neigh_list); + tmp_neigh_node = batadv_neigh_node_get(orig_node, hard_iface, + neigh_addr); + if (!tmp_neigh_node) { + hlist_add_head_rcu(&neigh_node->list, &orig_node->neigh_list); + } else { + kfree(neigh_node); + batadv_hardif_free_ref(hard_iface); + neigh_node = tmp_neigh_node; + } spin_unlock_bh(&orig_node->neigh_list_lock); + if (!tmp_neigh_node) + batadv_dbg(BATADV_DBG_BATMAN, bat_priv, + "Creating new neighbor %pM for orig_node %pM on interface %s\n", + neigh_addr, orig_node->orig, + hard_iface->net_dev->name); + out: return neigh_node; } diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c index 3d417d3641c..b851cc58085 100644 --- a/net/batman-adv/hard-interface.c +++ b/net/batman-adv/hard-interface.c @@ -241,7 +241,7 @@ int batadv_hardif_min_mtu(struct net_device *soft_iface) { struct batadv_priv *bat_priv = netdev_priv(soft_iface); const struct batadv_hard_iface *hard_iface; - int min_mtu = ETH_DATA_LEN; + int min_mtu = INT_MAX; rcu_read_lock(); list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) { @@ -256,8 +256,6 @@ int batadv_hardif_min_mtu(struct net_device *soft_iface) } rcu_read_unlock(); - atomic_set(&bat_priv->packet_size_max, min_mtu); - if (atomic_read(&bat_priv->fragmentation) == 0) goto out; @@ -268,13 +266,21 @@ int batadv_hardif_min_mtu(struct net_device *soft_iface) min_mtu = min_t(int, min_mtu, BATADV_FRAG_MAX_FRAG_SIZE); min_mtu -= sizeof(struct batadv_frag_packet); min_mtu *= BATADV_FRAG_MAX_FRAGMENTS; - atomic_set(&bat_priv->packet_size_max, min_mtu); - - /* with fragmentation enabled we can fragment external packets easily */ - min_mtu = min_t(int, min_mtu, ETH_DATA_LEN); out: - return min_mtu - batadv_max_header_len(); + /* report to the other components the maximum amount of bytes that + * batman-adv can send over the wire (without considering the payload + * overhead). For example, this value is used by TT to compute the + * maximum local table table size + */ + atomic_set(&bat_priv->packet_size_max, min_mtu); + + /* the real soft-interface MTU is computed by removing the payload + * overhead from the maximum amount of bytes that was just computed. + * + * However batman-adv does not support MTUs bigger than ETH_DATA_LEN + */ + return min_t(int, min_mtu - batadv_max_header_len(), ETH_DATA_LEN); } /* adjusts the MTU if a new interface with a smaller MTU appeared. */ diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c index 6df12a2e360..853941629dc 100644 --- a/net/batman-adv/originator.c +++ b/net/batman-adv/originator.c @@ -458,6 +458,42 @@ out: } /** + * batadv_neigh_node_get - retrieve a neighbour from the list + * @orig_node: originator which the neighbour belongs to + * @hard_iface: the interface where this neighbour is connected to + * @addr: the address of the neighbour + * + * Looks for and possibly returns a neighbour belonging to this originator list + * which is connected through the provided hard interface. + * Returns NULL if the neighbour is not found. + */ +struct batadv_neigh_node * +batadv_neigh_node_get(const struct batadv_orig_node *orig_node, + const struct batadv_hard_iface *hard_iface, + const uint8_t *addr) +{ + struct batadv_neigh_node *tmp_neigh_node, *res = NULL; + + rcu_read_lock(); + hlist_for_each_entry_rcu(tmp_neigh_node, &orig_node->neigh_list, list) { + if (!batadv_compare_eth(tmp_neigh_node->addr, addr)) + continue; + + if (tmp_neigh_node->if_incoming != hard_iface) + continue; + + if (!atomic_inc_not_zero(&tmp_neigh_node->refcount)) + continue; + + res = tmp_neigh_node; + break; + } + rcu_read_unlock(); + + return res; +} + +/** * batadv_orig_ifinfo_free_rcu - free the orig_ifinfo object * @rcu: rcu pointer of the orig_ifinfo object */ diff --git a/net/batman-adv/originator.h b/net/batman-adv/originator.h index 37be290f63f..db3a9ed734c 100644 --- a/net/batman-adv/originator.h +++ b/net/batman-adv/originator.h @@ -29,6 +29,10 @@ void batadv_orig_node_free_ref_now(struct batadv_orig_node *orig_node); struct batadv_orig_node *batadv_orig_node_new(struct batadv_priv *bat_priv, const uint8_t *addr); struct batadv_neigh_node * +batadv_neigh_node_get(const struct batadv_orig_node *orig_node, + const struct batadv_hard_iface *hard_iface, + const uint8_t *addr); +struct batadv_neigh_node * batadv_neigh_node_new(struct batadv_hard_iface *hard_iface, const uint8_t *neigh_addr, struct batadv_orig_node *orig_node); diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c index 1ed9f7c9ece..a953d5b196a 100644 --- a/net/batman-adv/routing.c +++ b/net/batman-adv/routing.c @@ -688,7 +688,7 @@ static int batadv_check_unicast_ttvn(struct batadv_priv *bat_priv, int is_old_ttvn; /* check if there is enough data before accessing it */ - if (pskb_may_pull(skb, hdr_len + ETH_HLEN) < 0) + if (!pskb_may_pull(skb, hdr_len + ETH_HLEN)) return 0; /* create a copy of the skb (in case of for re-routing) to modify it. */ @@ -918,6 +918,8 @@ int batadv_recv_unicast_tvlv(struct sk_buff *skb, if (ret != NET_RX_SUCCESS) ret = batadv_route_unicast_packet(skb, recv_if); + else + consume_skb(skb); return ret; } diff --git a/net/batman-adv/send.c b/net/batman-adv/send.c index 579f5f00a38..843febd1e51 100644 --- a/net/batman-adv/send.c +++ b/net/batman-adv/send.c @@ -254,9 +254,9 @@ static int batadv_send_skb_unicast(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node, unsigned short vid) { - struct ethhdr *ethhdr = (struct ethhdr *)skb->data; + struct ethhdr *ethhdr; struct batadv_unicast_packet *unicast_packet; - int ret = NET_XMIT_DROP; + int ret = NET_XMIT_DROP, hdr_size; if (!orig_node) goto out; @@ -265,12 +265,16 @@ static int batadv_send_skb_unicast(struct batadv_priv *bat_priv, case BATADV_UNICAST: if (!batadv_send_skb_prepare_unicast(skb, orig_node)) goto out; + + hdr_size = sizeof(*unicast_packet); break; case BATADV_UNICAST_4ADDR: if (!batadv_send_skb_prepare_unicast_4addr(bat_priv, skb, orig_node, packet_subtype)) goto out; + + hdr_size = sizeof(struct batadv_unicast_4addr_packet); break; default: /* this function supports UNICAST and UNICAST_4ADDR only. It @@ -279,6 +283,7 @@ static int batadv_send_skb_unicast(struct batadv_priv *bat_priv, goto out; } + ethhdr = (struct ethhdr *)(skb->data + hdr_size); unicast_packet = (struct batadv_unicast_packet *)skb->data; /* inform the destination node that we are still missing a correct route diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c index b6071f675a3..959dde721c4 100644 --- a/net/batman-adv/translation-table.c +++ b/net/batman-adv/translation-table.c @@ -1975,6 +1975,7 @@ static uint32_t batadv_tt_global_crc(struct batadv_priv *bat_priv, struct hlist_head *head; uint32_t i, crc_tmp, crc = 0; uint8_t flags; + __be16 tmp_vid; for (i = 0; i < hash->size; i++) { head = &hash->table[i]; @@ -2011,8 +2012,11 @@ static uint32_t batadv_tt_global_crc(struct batadv_priv *bat_priv, orig_node)) continue; - crc_tmp = crc32c(0, &tt_common->vid, - sizeof(tt_common->vid)); + /* use network order to read the VID: this ensures that + * every node reads the bytes in the same order. + */ + tmp_vid = htons(tt_common->vid); + crc_tmp = crc32c(0, &tmp_vid, sizeof(tmp_vid)); /* compute the CRC on flags that have to be kept in sync * among nodes @@ -2046,6 +2050,7 @@ static uint32_t batadv_tt_local_crc(struct batadv_priv *bat_priv, struct hlist_head *head; uint32_t i, crc_tmp, crc = 0; uint8_t flags; + __be16 tmp_vid; for (i = 0; i < hash->size; i++) { head = &hash->table[i]; @@ -2064,8 +2069,11 @@ static uint32_t batadv_tt_local_crc(struct batadv_priv *bat_priv, if (tt_common->flags & BATADV_TT_CLIENT_NEW) continue; - crc_tmp = crc32c(0, &tt_common->vid, - sizeof(tt_common->vid)); + /* use network order to read the VID: this ensures that + * every node reads the bytes in the same order. + */ + tmp_vid = htons(tt_common->vid); + crc_tmp = crc32c(0, &tmp_vid, sizeof(tmp_vid)); /* compute the CRC on flags that have to be kept in sync * among nodes @@ -2262,6 +2270,7 @@ static bool batadv_tt_global_check_crc(struct batadv_orig_node *orig_node, { struct batadv_tvlv_tt_vlan_data *tt_vlan_tmp; struct batadv_orig_node_vlan *vlan; + uint32_t crc; int i; /* check if each received CRC matches the locally stored one */ @@ -2281,7 +2290,10 @@ static bool batadv_tt_global_check_crc(struct batadv_orig_node *orig_node, if (!vlan) return false; - if (vlan->tt.crc != ntohl(tt_vlan_tmp->crc)) + crc = vlan->tt.crc; + batadv_orig_node_vlan_free_ref(vlan); + + if (crc != ntohl(tt_vlan_tmp->crc)) return false; } @@ -3218,7 +3230,6 @@ static void batadv_tt_update_orig(struct batadv_priv *bat_priv, spin_lock_bh(&orig_node->tt_lock); - tt_change = (struct batadv_tvlv_tt_change *)tt_buff; batadv_tt_update_changes(bat_priv, orig_node, tt_num_changes, ttvn, tt_change); diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c index 292e619db89..d9fb9345144 100644 --- a/net/bluetooth/hidp/core.c +++ b/net/bluetooth/hidp/core.c @@ -430,6 +430,16 @@ static void hidp_del_timer(struct hidp_session *session) del_timer(&session->timer); } +static void hidp_process_report(struct hidp_session *session, + int type, const u8 *data, int len, int intr) +{ + if (len > HID_MAX_BUFFER_SIZE) + len = HID_MAX_BUFFER_SIZE; + + memcpy(session->input_buf, data, len); + hid_input_report(session->hid, type, session->input_buf, len, intr); +} + static void hidp_process_handshake(struct hidp_session *session, unsigned char param) { @@ -502,7 +512,8 @@ static int hidp_process_data(struct hidp_session *session, struct sk_buff *skb, hidp_input_report(session, skb); if (session->hid) - hid_input_report(session->hid, HID_INPUT_REPORT, skb->data, skb->len, 0); + hidp_process_report(session, HID_INPUT_REPORT, + skb->data, skb->len, 0); break; case HIDP_DATA_RTYPE_OTHER: @@ -584,7 +595,8 @@ static void hidp_recv_intr_frame(struct hidp_session *session, hidp_input_report(session, skb); if (session->hid) { - hid_input_report(session->hid, HID_INPUT_REPORT, skb->data, skb->len, 1); + hidp_process_report(session, HID_INPUT_REPORT, + skb->data, skb->len, 1); BT_DBG("report len %d", skb->len); } } else { diff --git a/net/bluetooth/hidp/hidp.h b/net/bluetooth/hidp/hidp.h index ab5241400cf..8798492a6e9 100644 --- a/net/bluetooth/hidp/hidp.h +++ b/net/bluetooth/hidp/hidp.h @@ -24,6 +24,7 @@ #define __HIDP_H #include <linux/types.h> +#include <linux/hid.h> #include <linux/kref.h> #include <net/bluetooth/bluetooth.h> #include <net/bluetooth/l2cap.h> @@ -179,6 +180,9 @@ struct hidp_session { /* Used in hidp_output_raw_report() */ int output_report_success; /* boolean */ + + /* temporary input buffer */ + u8 input_buf[HID_MAX_BUFFER_SIZE]; }; /* HIDP init defines */ diff --git a/net/core/dev.c b/net/core/dev.c index 4ad1b78c9c7..b1b0c8d4d7d 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -2420,7 +2420,7 @@ EXPORT_SYMBOL(netdev_rx_csum_fault); * 2. No high memory really exists on this machine. */ -static int illegal_highdma(struct net_device *dev, struct sk_buff *skb) +static int illegal_highdma(const struct net_device *dev, struct sk_buff *skb) { #ifdef CONFIG_HIGHMEM int i; @@ -2495,34 +2495,36 @@ static int dev_gso_segment(struct sk_buff *skb, netdev_features_t features) } static netdev_features_t harmonize_features(struct sk_buff *skb, - netdev_features_t features) + const struct net_device *dev, + netdev_features_t features) { if (skb->ip_summed != CHECKSUM_NONE && !can_checksum_protocol(features, skb_network_protocol(skb))) { features &= ~NETIF_F_ALL_CSUM; - } else if (illegal_highdma(skb->dev, skb)) { + } else if (illegal_highdma(dev, skb)) { features &= ~NETIF_F_SG; } return features; } -netdev_features_t netif_skb_features(struct sk_buff *skb) +netdev_features_t netif_skb_dev_features(struct sk_buff *skb, + const struct net_device *dev) { __be16 protocol = skb->protocol; - netdev_features_t features = skb->dev->features; + netdev_features_t features = dev->features; - if (skb_shinfo(skb)->gso_segs > skb->dev->gso_max_segs) + if (skb_shinfo(skb)->gso_segs > dev->gso_max_segs) features &= ~NETIF_F_GSO_MASK; if (protocol == htons(ETH_P_8021Q) || protocol == htons(ETH_P_8021AD)) { struct vlan_ethhdr *veh = (struct vlan_ethhdr *)skb->data; protocol = veh->h_vlan_encapsulated_proto; } else if (!vlan_tx_tag_present(skb)) { - return harmonize_features(skb, features); + return harmonize_features(skb, dev, features); } - features &= (skb->dev->vlan_features | NETIF_F_HW_VLAN_CTAG_TX | + features &= (dev->vlan_features | NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_STAG_TX); if (protocol == htons(ETH_P_8021Q) || protocol == htons(ETH_P_8021AD)) @@ -2530,9 +2532,9 @@ netdev_features_t netif_skb_features(struct sk_buff *skb) NETIF_F_GEN_CSUM | NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_STAG_TX; - return harmonize_features(skb, features); + return harmonize_features(skb, dev, features); } -EXPORT_SYMBOL(netif_skb_features); +EXPORT_SYMBOL(netif_skb_dev_features); int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev, struct netdev_queue *txq) diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index 87577d44755..e29e810663d 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c @@ -323,17 +323,6 @@ u32 __skb_get_poff(const struct sk_buff *skb) return poff; } -static inline u16 dev_cap_txqueue(struct net_device *dev, u16 queue_index) -{ - if (unlikely(queue_index >= dev->real_num_tx_queues)) { - net_warn_ratelimited("%s selects TX queue %d, but real number of TX queues is %d\n", - dev->name, queue_index, - dev->real_num_tx_queues); - return 0; - } - return queue_index; -} - static inline int get_xps_queue(struct net_device *dev, struct sk_buff *skb) { #ifdef CONFIG_XPS @@ -372,7 +361,7 @@ static inline int get_xps_queue(struct net_device *dev, struct sk_buff *skb) #endif } -u16 __netdev_pick_tx(struct net_device *dev, struct sk_buff *skb) +static u16 __netdev_pick_tx(struct net_device *dev, struct sk_buff *skb) { struct sock *sk = skb->sk; int queue_index = sk_tx_queue_get(sk); @@ -392,7 +381,6 @@ u16 __netdev_pick_tx(struct net_device *dev, struct sk_buff *skb) return queue_index; } -EXPORT_SYMBOL(__netdev_pick_tx); struct netdev_queue *netdev_pick_tx(struct net_device *dev, struct sk_buff *skb, @@ -403,13 +391,13 @@ struct netdev_queue *netdev_pick_tx(struct net_device *dev, if (dev->real_num_tx_queues != 1) { const struct net_device_ops *ops = dev->netdev_ops; if (ops->ndo_select_queue) - queue_index = ops->ndo_select_queue(dev, skb, - accel_priv); + queue_index = ops->ndo_select_queue(dev, skb, accel_priv, + __netdev_pick_tx); else queue_index = __netdev_pick_tx(dev, skb); if (!accel_priv) - queue_index = dev_cap_txqueue(dev, queue_index); + queue_index = netdev_cap_txqueue(dev, queue_index); } skb_set_queue_mapping(skb, queue_index); diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 048dc8d183a..1a0dac2ef9a 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -1963,16 +1963,21 @@ replay: dev->ifindex = ifm->ifi_index; - if (ops->newlink) + if (ops->newlink) { err = ops->newlink(net, dev, tb, data); - else + /* Drivers should call free_netdev() in ->destructor + * and unregister it on failure so that device could be + * finally freed in rtnl_unlock. + */ + if (err < 0) + goto out; + } else { err = register_netdevice(dev); - - if (err < 0) { - free_netdev(dev); - goto out; + if (err < 0) { + free_netdev(dev); + goto out; + } } - err = rtnl_configure_link(dev, ifm); if (err < 0) unregister_netdevice(dev); diff --git a/net/dccp/ccids/lib/tfrc.c b/net/dccp/ccids/lib/tfrc.c index c073b81a1f3..62b5828acde 100644 --- a/net/dccp/ccids/lib/tfrc.c +++ b/net/dccp/ccids/lib/tfrc.c @@ -8,7 +8,7 @@ #include "tfrc.h" #ifdef CONFIG_IP_DCCP_TFRC_DEBUG -static bool tfrc_debug; +bool tfrc_debug; module_param(tfrc_debug, bool, 0644); MODULE_PARM_DESC(tfrc_debug, "Enable TFRC debug messages"); #endif diff --git a/net/dccp/ccids/lib/tfrc.h b/net/dccp/ccids/lib/tfrc.h index a3d8f7c76ae..40ee7d62b65 100644 --- a/net/dccp/ccids/lib/tfrc.h +++ b/net/dccp/ccids/lib/tfrc.h @@ -21,6 +21,7 @@ #include "packet_history.h" #ifdef CONFIG_IP_DCCP_TFRC_DEBUG +extern bool tfrc_debug; #define tfrc_pr_debug(format, a...) DCCP_PR_DEBUG(tfrc_debug, format, ##a) #else #define tfrc_pr_debug(format, a...) diff --git a/net/ipv4/ip_forward.c b/net/ipv4/ip_forward.c index e9f1217a8af..f3869c186d9 100644 --- a/net/ipv4/ip_forward.c +++ b/net/ipv4/ip_forward.c @@ -39,6 +39,71 @@ #include <net/route.h> #include <net/xfrm.h> +static bool ip_may_fragment(const struct sk_buff *skb) +{ + return unlikely((ip_hdr(skb)->frag_off & htons(IP_DF)) == 0) || + !skb->local_df; +} + +static bool ip_exceeds_mtu(const struct sk_buff *skb, unsigned int mtu) +{ + if (skb->len <= mtu || skb->local_df) + return false; + + if (skb_is_gso(skb) && skb_gso_network_seglen(skb) <= mtu) + return false; + + return true; +} + +static bool ip_gso_exceeds_dst_mtu(const struct sk_buff *skb) +{ + unsigned int mtu; + + if (skb->local_df || !skb_is_gso(skb)) + return false; + + mtu = ip_dst_mtu_maybe_forward(skb_dst(skb), true); + + /* if seglen > mtu, do software segmentation for IP fragmentation on + * output. DF bit cannot be set since ip_forward would have sent + * icmp error. + */ + return skb_gso_network_seglen(skb) > mtu; +} + +/* called if GSO skb needs to be fragmented on forward */ +static int ip_forward_finish_gso(struct sk_buff *skb) +{ + struct dst_entry *dst = skb_dst(skb); + netdev_features_t features; + struct sk_buff *segs; + int ret = 0; + + features = netif_skb_dev_features(skb, dst->dev); + segs = skb_gso_segment(skb, features & ~NETIF_F_GSO_MASK); + if (IS_ERR(segs)) { + kfree_skb(skb); + return -ENOMEM; + } + + consume_skb(skb); + + do { + struct sk_buff *nskb = segs->next; + int err; + + segs->next = NULL; + err = dst_output(segs); + + if (err && ret == 0) + ret = err; + segs = nskb; + } while (segs); + + return ret; +} + static int ip_forward_finish(struct sk_buff *skb) { struct ip_options *opt = &(IPCB(skb)->opt); @@ -49,6 +114,9 @@ static int ip_forward_finish(struct sk_buff *skb) if (unlikely(opt->optlen)) ip_forward_options(skb); + if (ip_gso_exceeds_dst_mtu(skb)) + return ip_forward_finish_gso(skb); + return dst_output(skb); } @@ -91,8 +159,7 @@ int ip_forward(struct sk_buff *skb) IPCB(skb)->flags |= IPSKB_FORWARDED; mtu = ip_dst_mtu_maybe_forward(&rt->dst, true); - if (unlikely(skb->len > mtu && !skb_is_gso(skb) && - (ip_hdr(skb)->frag_off & htons(IP_DF))) && !skb->local_df) { + if (!ip_may_fragment(skb) && ip_exceeds_mtu(skb, mtu)) { IP_INC_STATS(dev_net(rt->dst.dev), IPSTATS_MIB_FRAGFAILS); icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu)); diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c index efa1138fa52..b3e86ea7b71 100644 --- a/net/ipv4/ipconfig.c +++ b/net/ipv4/ipconfig.c @@ -273,7 +273,7 @@ static int __init ic_open_devs(void) msleep(1); - if time_before(jiffies, next_msg) + if (time_before(jiffies, next_msg)) continue; elapsed = jiffies_to_msecs(jiffies - start); diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 25071b48921..4c011ec69ed 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -1597,6 +1597,7 @@ static int __mkroute_input(struct sk_buff *skb, rth->rt_gateway = 0; rth->rt_uses_gateway = 0; INIT_LIST_HEAD(&rth->rt_uncached); + RT_CACHE_STAT_INC(in_slow_tot); rth->dst.input = ip_forward; rth->dst.output = ip_output; @@ -1695,10 +1696,11 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr, fl4.daddr = daddr; fl4.saddr = saddr; err = fib_lookup(net, &fl4, &res); - if (err != 0) + if (err != 0) { + if (!IN_DEV_FORWARD(in_dev)) + err = -EHOSTUNREACH; goto no_route; - - RT_CACHE_STAT_INC(in_slow_tot); + } if (res.type == RTN_BROADCAST) goto brd_input; @@ -1712,8 +1714,10 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr, goto local_input; } - if (!IN_DEV_FORWARD(in_dev)) + if (!IN_DEV_FORWARD(in_dev)) { + err = -EHOSTUNREACH; goto no_route; + } if (res.type != RTN_UNICAST) goto martian_destination; @@ -1768,6 +1772,7 @@ local_input: rth->rt_gateway = 0; rth->rt_uses_gateway = 0; INIT_LIST_HEAD(&rth->rt_uncached); + RT_CACHE_STAT_INC(in_slow_tot); if (res.type == RTN_UNREACHABLE) { rth->dst.input= ip_error; rth->dst.error= -err; diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index ad235690684..fdbfeca36d6 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -2783,6 +2783,8 @@ static void addrconf_gre_config(struct net_device *dev) ipv6_addr_set(&addr, htonl(0xFE800000), 0, 0, 0); if (!ipv6_generate_eui64(addr.s6_addr + 8, dev)) addrconf_add_linklocal(idev, &addr); + else + addrconf_prefix_route(&addr, 64, dev, 0, 0); } #endif diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index ef02b26ccf8..070a2fae237 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -342,6 +342,20 @@ static unsigned int ip6_dst_mtu_forward(const struct dst_entry *dst) return mtu; } +static bool ip6_pkt_too_big(const struct sk_buff *skb, unsigned int mtu) +{ + if (skb->len <= mtu || skb->local_df) + return false; + + if (IP6CB(skb)->frag_max_size && IP6CB(skb)->frag_max_size > mtu) + return true; + + if (skb_is_gso(skb) && skb_gso_network_seglen(skb) <= mtu) + return false; + + return true; +} + int ip6_forward(struct sk_buff *skb) { struct dst_entry *dst = skb_dst(skb); @@ -466,8 +480,7 @@ int ip6_forward(struct sk_buff *skb) if (mtu < IPV6_MIN_MTU) mtu = IPV6_MIN_MTU; - if ((!skb->local_df && skb->len > mtu && !skb_is_gso(skb)) || - (IP6CB(skb)->frag_max_size && IP6CB(skb)->frag_max_size > mtu)) { + if (ip6_pkt_too_big(skb, mtu)) { /* Again, force OUTPUT device used as source address */ skb->dev = dst->dev; icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index d6d1f1df911..ce1c4437061 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -1057,7 +1057,8 @@ static void ieee80211_uninit(struct net_device *dev) static u16 ieee80211_netdev_select_queue(struct net_device *dev, struct sk_buff *skb, - void *accel_priv) + void *accel_priv, + select_queue_fallback_t fallback) { return ieee80211_select_queue(IEEE80211_DEV_TO_SUB_IF(dev), skb); } @@ -1075,7 +1076,8 @@ static const struct net_device_ops ieee80211_dataif_ops = { static u16 ieee80211_monitor_select_queue(struct net_device *dev, struct sk_buff *skb, - void *accel_priv) + void *accel_priv, + select_queue_fallback_t fallback) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_local *local = sdata->local; diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 6a2bb37506c..48a6a93db29 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -308,11 +308,27 @@ static bool packet_use_direct_xmit(const struct packet_sock *po) return po->xmit == packet_direct_xmit; } -static u16 packet_pick_tx_queue(struct net_device *dev) +static u16 __packet_pick_tx_queue(struct net_device *dev, struct sk_buff *skb) { return (u16) raw_smp_processor_id() % dev->real_num_tx_queues; } +static void packet_pick_tx_queue(struct net_device *dev, struct sk_buff *skb) +{ + const struct net_device_ops *ops = dev->netdev_ops; + u16 queue_index; + + if (ops->ndo_select_queue) { + queue_index = ops->ndo_select_queue(dev, skb, NULL, + __packet_pick_tx_queue); + queue_index = netdev_cap_txqueue(dev, queue_index); + } else { + queue_index = __packet_pick_tx_queue(dev, skb); + } + + skb_set_queue_mapping(skb, queue_index); +} + /* register_prot_hook must be invoked with the po->bind_lock held, * or from a context in which asynchronous accesses to the packet * socket is not possible (packet_create()). @@ -2285,7 +2301,8 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg) } } - skb_set_queue_mapping(skb, packet_pick_tx_queue(dev)); + packet_pick_tx_queue(dev, skb); + skb->destructor = tpacket_destruct_skb; __packet_set_status(po, ph, TP_STATUS_SENDING); packet_inc_pending(&po->tx_ring); @@ -2499,7 +2516,8 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len) skb->dev = dev; skb->priority = sk->sk_priority; skb->mark = sk->sk_mark; - skb_set_queue_mapping(skb, packet_pick_tx_queue(dev)); + + packet_pick_tx_queue(dev, skb); if (po->has_vnet_hdr) { if (vnet_hdr.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) { @@ -3786,7 +3804,7 @@ static int packet_set_ring(struct sock *sk, union tpacket_req_u *req_u, */ if (!tx_ring) init_prb_bdqc(po, rb, pg_vec, req_u, tx_ring); - break; + break; default: break; } diff --git a/net/sched/sch_pie.c b/net/sched/sch_pie.c index a255d0200a5..fefeeb73f15 100644 --- a/net/sched/sch_pie.c +++ b/net/sched/sch_pie.c @@ -15,6 +15,11 @@ * * ECN support is added by Naeem Khademi <naeemk@ifi.uio.no> * University of Oslo, Norway. + * + * References: + * IETF draft submission: http://tools.ietf.org/html/draft-pan-aqm-pie-00 + * IEEE Conference on High Performance Switching and Routing 2013 : + * "PIE: A * Lightweight Control Scheme to Address the Bufferbloat Problem" */ #include <linux/module.h> @@ -36,7 +41,7 @@ struct pie_params { psched_time_t target; /* user specified target delay in pschedtime */ u32 tupdate; /* timer frequency (in jiffies) */ u32 limit; /* number of packets that can be enqueued */ - u32 alpha; /* alpha and beta are between -4 and 4 */ + u32 alpha; /* alpha and beta are between 0 and 32 */ u32 beta; /* and are used for shift relative to 1 */ bool ecn; /* true if ecn is enabled */ bool bytemode; /* to scale drop early prob based on pkt size */ @@ -326,10 +331,16 @@ static void calculate_probability(struct Qdisc *sch) if (qdelay == 0 && qlen != 0) update_prob = false; - /* Add ranges for alpha and beta, more aggressive for high dropping - * mode and gentle steps for light dropping mode - * In light dropping mode, take gentle steps; in medium dropping mode, - * take medium steps; in high dropping mode, take big steps. + /* In the algorithm, alpha and beta are between 0 and 2 with typical + * value for alpha as 0.125. In this implementation, we use values 0-32 + * passed from user space to represent this. Also, alpha and beta have + * unit of HZ and need to be scaled before they can used to update + * probability. alpha/beta are updated locally below by 1) scaling them + * appropriately 2) scaling down by 16 to come to 0-2 range. + * Please see paper for details. + * + * We scale alpha and beta differently depending on whether we are in + * light, medium or high dropping mode. */ if (q->vars.prob < MAX_PROB / 100) { alpha = diff --git a/net/sctp/associola.c b/net/sctp/associola.c index 5ae60920067..f558433537b 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c @@ -1367,44 +1367,35 @@ static inline bool sctp_peer_needs_update(struct sctp_association *asoc) return false; } -/* Increase asoc's rwnd by len and send any window update SACK if needed. */ -void sctp_assoc_rwnd_increase(struct sctp_association *asoc, unsigned int len) +/* Update asoc's rwnd for the approximated state in the buffer, + * and check whether SACK needs to be sent. + */ +void sctp_assoc_rwnd_update(struct sctp_association *asoc, bool update_peer) { + int rx_count; struct sctp_chunk *sack; struct timer_list *timer; - if (asoc->rwnd_over) { - if (asoc->rwnd_over >= len) { - asoc->rwnd_over -= len; - } else { - asoc->rwnd += (len - asoc->rwnd_over); - asoc->rwnd_over = 0; - } - } else { - asoc->rwnd += len; - } + if (asoc->ep->rcvbuf_policy) + rx_count = atomic_read(&asoc->rmem_alloc); + else + rx_count = atomic_read(&asoc->base.sk->sk_rmem_alloc); - /* If we had window pressure, start recovering it - * once our rwnd had reached the accumulated pressure - * threshold. The idea is to recover slowly, but up - * to the initial advertised window. - */ - if (asoc->rwnd_press && asoc->rwnd >= asoc->rwnd_press) { - int change = min(asoc->pathmtu, asoc->rwnd_press); - asoc->rwnd += change; - asoc->rwnd_press -= change; - } + if ((asoc->base.sk->sk_rcvbuf - rx_count) > 0) + asoc->rwnd = (asoc->base.sk->sk_rcvbuf - rx_count) >> 1; + else + asoc->rwnd = 0; - pr_debug("%s: asoc:%p rwnd increased by %d to (%u, %u) - %u\n", - __func__, asoc, len, asoc->rwnd, asoc->rwnd_over, - asoc->a_rwnd); + pr_debug("%s: asoc:%p rwnd=%u, rx_count=%d, sk_rcvbuf=%d\n", + __func__, asoc, asoc->rwnd, rx_count, + asoc->base.sk->sk_rcvbuf); /* Send a window update SACK if the rwnd has increased by at least the * minimum of the association's PMTU and half of the receive buffer. * The algorithm used is similar to the one described in * Section 4.2.3.3 of RFC 1122. */ - if (sctp_peer_needs_update(asoc)) { + if (update_peer && sctp_peer_needs_update(asoc)) { asoc->a_rwnd = asoc->rwnd; pr_debug("%s: sending window update SACK- asoc:%p rwnd:%u " @@ -1426,45 +1417,6 @@ void sctp_assoc_rwnd_increase(struct sctp_association *asoc, unsigned int len) } } -/* Decrease asoc's rwnd by len. */ -void sctp_assoc_rwnd_decrease(struct sctp_association *asoc, unsigned int len) -{ - int rx_count; - int over = 0; - - if (unlikely(!asoc->rwnd || asoc->rwnd_over)) - pr_debug("%s: association:%p has asoc->rwnd:%u, " - "asoc->rwnd_over:%u!\n", __func__, asoc, - asoc->rwnd, asoc->rwnd_over); - - if (asoc->ep->rcvbuf_policy) - rx_count = atomic_read(&asoc->rmem_alloc); - else - rx_count = atomic_read(&asoc->base.sk->sk_rmem_alloc); - - /* If we've reached or overflowed our receive buffer, announce - * a 0 rwnd if rwnd would still be positive. Store the - * the potential pressure overflow so that the window can be restored - * back to original value. - */ - if (rx_count >= asoc->base.sk->sk_rcvbuf) - over = 1; - - if (asoc->rwnd >= len) { - asoc->rwnd -= len; - if (over) { - asoc->rwnd_press += asoc->rwnd; - asoc->rwnd = 0; - } - } else { - asoc->rwnd_over = len - asoc->rwnd; - asoc->rwnd = 0; - } - - pr_debug("%s: asoc:%p rwnd decreased by %d to (%u, %u, %u)\n", - __func__, asoc, len, asoc->rwnd, asoc->rwnd_over, - asoc->rwnd_press); -} /* Build the bind address list for the association based on info from the * local endpoint and the remote peer. diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index 483dcd71b3c..591b44d3b7d 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -6176,7 +6176,7 @@ static int sctp_eat_data(const struct sctp_association *asoc, * PMTU. In cases, such as loopback, this might be a rather * large spill over. */ - if ((!chunk->data_accepted) && (!asoc->rwnd || asoc->rwnd_over || + if ((!chunk->data_accepted) && (!asoc->rwnd || (datalen > asoc->rwnd + asoc->frag_point))) { /* If this is the next TSN, consider reneging to make diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 9e91d6e5df6..981aaf8b6ac 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -64,6 +64,7 @@ #include <linux/crypto.h> #include <linux/slab.h> #include <linux/file.h> +#include <linux/compat.h> #include <net/ip.h> #include <net/icmp.h> @@ -1368,11 +1369,19 @@ static int sctp_setsockopt_connectx(struct sock *sk, /* * New (hopefully final) interface for the API. * We use the sctp_getaddrs_old structure so that use-space library - * can avoid any unnecessary allocations. The only defferent part + * can avoid any unnecessary allocations. The only different part * is that we store the actual length of the address buffer into the - * addrs_num structure member. That way we can re-use the existing + * addrs_num structure member. That way we can re-use the existing * code. */ +#ifdef CONFIG_COMPAT +struct compat_sctp_getaddrs_old { + sctp_assoc_t assoc_id; + s32 addr_num; + compat_uptr_t addrs; /* struct sockaddr * */ +}; +#endif + static int sctp_getsockopt_connectx3(struct sock *sk, int len, char __user *optval, int __user *optlen) @@ -1381,16 +1390,30 @@ static int sctp_getsockopt_connectx3(struct sock *sk, int len, sctp_assoc_t assoc_id = 0; int err = 0; - if (len < sizeof(param)) - return -EINVAL; +#ifdef CONFIG_COMPAT + if (is_compat_task()) { + struct compat_sctp_getaddrs_old param32; - if (copy_from_user(¶m, optval, sizeof(param))) - return -EFAULT; + if (len < sizeof(param32)) + return -EINVAL; + if (copy_from_user(¶m32, optval, sizeof(param32))) + return -EFAULT; - err = __sctp_setsockopt_connectx(sk, - (struct sockaddr __user *)param.addrs, - param.addr_num, &assoc_id); + param.assoc_id = param32.assoc_id; + param.addr_num = param32.addr_num; + param.addrs = compat_ptr(param32.addrs); + } else +#endif + { + if (len < sizeof(param)) + return -EINVAL; + if (copy_from_user(¶m, optval, sizeof(param))) + return -EFAULT; + } + err = __sctp_setsockopt_connectx(sk, (struct sockaddr __user *) + param.addrs, param.addr_num, + &assoc_id); if (err == 0 || err == -EINPROGRESS) { if (copy_to_user(optval, &assoc_id, sizeof(assoc_id))) return -EFAULT; @@ -2092,12 +2115,6 @@ static int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, sctp_skb_pull(skb, copied); skb_queue_head(&sk->sk_receive_queue, skb); - /* When only partial message is copied to the user, increase - * rwnd by that amount. If all the data in the skb is read, - * rwnd is updated when the event is freed. - */ - if (!sctp_ulpevent_is_notification(event)) - sctp_assoc_rwnd_increase(event->asoc, copied); goto out; } else if ((event->msg_flags & MSG_NOTIFICATION) || (event->msg_flags & MSG_EOR)) diff --git a/net/sctp/sysctl.c b/net/sctp/sysctl.c index 7135e617ab0..35c8923b555 100644 --- a/net/sctp/sysctl.c +++ b/net/sctp/sysctl.c @@ -151,6 +151,7 @@ static struct ctl_table sctp_net_table[] = { }, { .procname = "cookie_hmac_alg", + .data = &init_net.sctp.sctp_hmac_alg, .maxlen = 8, .mode = 0644, .proc_handler = proc_sctp_do_hmac_alg, @@ -401,15 +402,18 @@ static int proc_sctp_do_rto_max(struct ctl_table *ctl, int write, int sctp_sysctl_net_register(struct net *net) { - struct ctl_table *table; - int i; + struct ctl_table *table = sctp_net_table; + + if (!net_eq(net, &init_net)) { + int i; - table = kmemdup(sctp_net_table, sizeof(sctp_net_table), GFP_KERNEL); - if (!table) - return -ENOMEM; + table = kmemdup(sctp_net_table, sizeof(sctp_net_table), GFP_KERNEL); + if (!table) + return -ENOMEM; - for (i = 0; table[i].data; i++) - table[i].data += (char *)(&net->sctp) - (char *)&init_net.sctp; + for (i = 0; table[i].data; i++) + table[i].data += (char *)(&net->sctp) - (char *)&init_net.sctp; + } net->sctp.sysctl_header = register_net_sysctl(net, "net/sctp", table); return 0; diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c index 85c64658bd0..8d198ae0360 100644 --- a/net/sctp/ulpevent.c +++ b/net/sctp/ulpevent.c @@ -989,7 +989,7 @@ static void sctp_ulpevent_receive_data(struct sctp_ulpevent *event, skb = sctp_event2skb(event); /* Set the owner and charge rwnd for bytes received. */ sctp_ulpevent_set_owner(event, asoc); - sctp_assoc_rwnd_decrease(asoc, skb_headlen(skb)); + sctp_assoc_rwnd_update(asoc, false); if (!skb->data_len) return; @@ -1011,6 +1011,7 @@ static void sctp_ulpevent_release_data(struct sctp_ulpevent *event) { struct sk_buff *skb, *frag; unsigned int len; + struct sctp_association *asoc; /* Current stack structures assume that the rcv buffer is * per socket. For UDP style sockets this is not true as @@ -1035,8 +1036,11 @@ static void sctp_ulpevent_release_data(struct sctp_ulpevent *event) } done: - sctp_assoc_rwnd_increase(event->asoc, len); + asoc = event->asoc; + sctp_association_hold(asoc); sctp_ulpevent_release_owner(event); + sctp_assoc_rwnd_update(asoc, true); + sctp_association_put(asoc); } static void sctp_ulpevent_release_frag_data(struct sctp_ulpevent *event) diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index 6c0513a7f99..36e431ee1c9 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c @@ -108,6 +108,7 @@ struct gss_auth { static DEFINE_SPINLOCK(pipe_version_lock); static struct rpc_wait_queue pipe_version_rpc_waitqueue; static DECLARE_WAIT_QUEUE_HEAD(pipe_version_waitqueue); +static void gss_put_auth(struct gss_auth *gss_auth); static void gss_free_ctx(struct gss_cl_ctx *); static const struct rpc_pipe_ops gss_upcall_ops_v0; @@ -320,6 +321,7 @@ gss_release_msg(struct gss_upcall_msg *gss_msg) if (gss_msg->ctx != NULL) gss_put_ctx(gss_msg->ctx); rpc_destroy_wait_queue(&gss_msg->rpc_waitqueue); + gss_put_auth(gss_msg->auth); kfree(gss_msg); } @@ -498,9 +500,12 @@ gss_alloc_msg(struct gss_auth *gss_auth, default: err = gss_encode_v1_msg(gss_msg, service_name, gss_auth->target_name); if (err) - goto err_free_msg; + goto err_put_pipe_version; }; + kref_get(&gss_auth->kref); return gss_msg; +err_put_pipe_version: + put_pipe_version(gss_auth->net); err_free_msg: kfree(gss_msg); err: @@ -991,6 +996,8 @@ gss_create_new(struct rpc_auth_create_args *args, struct rpc_clnt *clnt) gss_auth->service = gss_pseudoflavor_to_service(gss_auth->mech, flavor); if (gss_auth->service == 0) goto err_put_mech; + if (!gssd_running(gss_auth->net)) + goto err_put_mech; auth = &gss_auth->rpc_auth; auth->au_cslack = GSS_CRED_SLACK >> 2; auth->au_rslack = GSS_VERF_SLACK >> 2; @@ -1062,6 +1069,12 @@ gss_free_callback(struct kref *kref) } static void +gss_put_auth(struct gss_auth *gss_auth) +{ + kref_put(&gss_auth->kref, gss_free_callback); +} + +static void gss_destroy(struct rpc_auth *auth) { struct gss_auth *gss_auth = container_of(auth, @@ -1082,7 +1095,7 @@ gss_destroy(struct rpc_auth *auth) gss_auth->gss_pipe[1] = NULL; rpcauth_destroy_credcache(auth); - kref_put(&gss_auth->kref, gss_free_callback); + gss_put_auth(gss_auth); } /* @@ -1253,7 +1266,7 @@ gss_destroy_nullcred(struct rpc_cred *cred) call_rcu(&cred->cr_rcu, gss_free_cred_callback); if (ctx) gss_put_ctx(ctx); - kref_put(&gss_auth->kref, gss_free_callback); + gss_put_auth(gss_auth); } static void diff --git a/net/sunrpc/backchannel_rqst.c b/net/sunrpc/backchannel_rqst.c index 890a29912d5..e860d4f7ed2 100644 --- a/net/sunrpc/backchannel_rqst.c +++ b/net/sunrpc/backchannel_rqst.c @@ -64,7 +64,6 @@ static void xprt_free_allocation(struct rpc_rqst *req) free_page((unsigned long)xbufp->head[0].iov_base); xbufp = &req->rq_snd_buf; free_page((unsigned long)xbufp->head[0].iov_base); - list_del(&req->rq_bc_pa_list); kfree(req); } @@ -168,8 +167,10 @@ out_free: /* * Memory allocation failed, free the temporary list */ - list_for_each_entry_safe(req, tmp, &tmp_list, rq_bc_pa_list) + list_for_each_entry_safe(req, tmp, &tmp_list, rq_bc_pa_list) { + list_del(&req->rq_bc_pa_list); xprt_free_allocation(req); + } dprintk("RPC: setup backchannel transport failed\n"); return -ENOMEM; @@ -198,6 +199,7 @@ void xprt_destroy_backchannel(struct rpc_xprt *xprt, unsigned int max_reqs) xprt_dec_alloc_count(xprt, max_reqs); list_for_each_entry_safe(req, tmp, &xprt->bc_pa_list, rq_bc_pa_list) { dprintk("RPC: req=%p\n", req); + list_del(&req->rq_bc_pa_list); xprt_free_allocation(req); if (--max_reqs == 0) break; diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 817a1e52396..0addefca8e7 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -510,6 +510,7 @@ static int xs_nospace(struct rpc_task *task) struct rpc_rqst *req = task->tk_rqstp; struct rpc_xprt *xprt = req->rq_xprt; struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); + struct sock *sk = transport->inet; int ret = -EAGAIN; dprintk("RPC: %5u xmit incomplete (%u left of %u)\n", @@ -527,7 +528,7 @@ static int xs_nospace(struct rpc_task *task) * window size */ set_bit(SOCK_NOSPACE, &transport->sock->flags); - transport->inet->sk_write_pending++; + sk->sk_write_pending++; /* ...and wait for more buffer space */ xprt_wait_for_buffer_space(task, xs_nospace_callback); } @@ -537,6 +538,9 @@ static int xs_nospace(struct rpc_task *task) } spin_unlock_bh(&xprt->transport_lock); + + /* Race breaker in case memory is freed before above code is called */ + sk->sk_write_space(sk); return ret; } diff --git a/net/tipc/core.h b/net/tipc/core.h index 1ff477b0450..5569d96b4da 100644 --- a/net/tipc/core.h +++ b/net/tipc/core.h @@ -192,6 +192,7 @@ static inline void k_term_timer(struct timer_list *timer) struct tipc_skb_cb { void *handle; + bool deferred; }; #define TIPC_SKB_CB(__skb) ((struct tipc_skb_cb *)&((__skb)->cb[0])) diff --git a/net/tipc/link.c b/net/tipc/link.c index d4b5de41b68..da6018beb6e 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -1391,6 +1391,12 @@ static int link_recv_buf_validate(struct sk_buff *buf) u32 hdr_size; u32 min_hdr_size; + /* If this packet comes from the defer queue, the skb has already + * been validated + */ + if (unlikely(TIPC_SKB_CB(buf)->deferred)) + return 1; + if (unlikely(buf->len < MIN_H_SIZE)) return 0; @@ -1703,6 +1709,7 @@ static void link_handle_out_of_seq_msg(struct tipc_link *l_ptr, &l_ptr->newest_deferred_in, buf)) { l_ptr->deferred_inqueue_sz++; l_ptr->stats.deferred_recv++; + TIPC_SKB_CB(buf)->deferred = true; if ((l_ptr->deferred_inqueue_sz % 16) == 1) tipc_link_send_proto_msg(l_ptr, STATE_MSG, 0, 0, 0, 0, 0); } else diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index 49392ecbef1..79c059e7086 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -152,6 +152,7 @@ ld_flags = $(LDFLAGS) $(ldflags-y) dtc_cpp_flags = -Wp,-MD,$(depfile).pre.tmp -nostdinc \ -I$(srctree)/arch/$(SRCARCH)/boot/dts \ -I$(srctree)/arch/$(SRCARCH)/boot/dts/include \ + -I$(srctree)/drivers/of/testcase-data \ -undef -D__DTS__ # Finds the multi-part object the current object will be linked into diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index c0f49884212..9c5cdc2caae 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c @@ -3338,10 +3338,10 @@ static int filename_write_helper(void *key, void *data, void *ptr) if (rc) return rc; - buf[0] = ft->stype; - buf[1] = ft->ttype; - buf[2] = ft->tclass; - buf[3] = otype->otype; + buf[0] = cpu_to_le32(ft->stype); + buf[1] = cpu_to_le32(ft->ttype); + buf[2] = cpu_to_le32(ft->tclass); + buf[3] = cpu_to_le32(otype->otype); rc = put_entry(buf, sizeof(u32), 4, fp); if (rc) diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 54d14793725..46ecdbb9053 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -2662,60 +2662,6 @@ static bool dspload_wait_loaded(struct hda_codec *codec) } /* - * PCM stuffs - */ -static void ca0132_setup_stream(struct hda_codec *codec, hda_nid_t nid, - u32 stream_tag, - int channel_id, int format) -{ - unsigned int oldval, newval; - - if (!nid) - return; - - snd_printdd( - "ca0132_setup_stream: NID=0x%x, stream=0x%x, " - "channel=%d, format=0x%x\n", - nid, stream_tag, channel_id, format); - - /* update the format-id if changed */ - oldval = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_STREAM_FORMAT, - 0); - if (oldval != format) { - msleep(20); - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_STREAM_FORMAT, - format); - } - - oldval = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0); - newval = (stream_tag << 4) | channel_id; - if (oldval != newval) { - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_CHANNEL_STREAMID, - newval); - } -} - -static void ca0132_cleanup_stream(struct hda_codec *codec, hda_nid_t nid) -{ - unsigned int val; - - if (!nid) - return; - - snd_printdd(KERN_INFO "ca0132_cleanup_stream: NID=0x%x\n", nid); - - val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0); - if (!val) - return; - - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_STREAM_FORMAT, 0); - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CHANNEL_STREAMID, 0); -} - -/* * PCM callbacks */ static int ca0132_playback_pcm_prepare(struct hda_pcm_stream *hinfo, @@ -2726,7 +2672,7 @@ static int ca0132_playback_pcm_prepare(struct hda_pcm_stream *hinfo, { struct ca0132_spec *spec = codec->spec; - ca0132_setup_stream(codec, spec->dacs[0], stream_tag, 0, format); + snd_hda_codec_setup_stream(codec, spec->dacs[0], stream_tag, 0, format); return 0; } @@ -2745,7 +2691,7 @@ static int ca0132_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, if (spec->effects_switch[PLAY_ENHANCEMENT - EFFECT_START_NID]) msleep(50); - ca0132_cleanup_stream(codec, spec->dacs[0]); + snd_hda_codec_cleanup_stream(codec, spec->dacs[0]); return 0; } @@ -2822,10 +2768,8 @@ static int ca0132_capture_pcm_prepare(struct hda_pcm_stream *hinfo, unsigned int format, struct snd_pcm_substream *substream) { - struct ca0132_spec *spec = codec->spec; - - ca0132_setup_stream(codec, spec->adcs[substream->number], - stream_tag, 0, format); + snd_hda_codec_setup_stream(codec, hinfo->nid, + stream_tag, 0, format); return 0; } @@ -2839,7 +2783,7 @@ static int ca0132_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, if (spec->dsp_state == DSP_DOWNLOADING) return 0; - ca0132_cleanup_stream(codec, hinfo->nid); + snd_hda_codec_cleanup_stream(codec, hinfo->nid); return 0; } @@ -4742,6 +4686,8 @@ static int patch_ca0132(struct hda_codec *codec) return err; codec->patch_ops = ca0132_patch_ops; + codec->pcm_format_first = 1; + codec->no_sticky_stream = 1; return 0; } diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index a9a83b85517..ec304f3ae3b 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -4308,7 +4308,9 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1028, 0x0651, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x0652, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x0653, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x0657, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x0658, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x065f, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x0662, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x15cc, "Dell X5 Precision", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x15cd, "Dell X5 Precision", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE), @@ -4317,6 +4319,54 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x1973, "HP Pavilion", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x1983, "HP Pavilion", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK(0x103c, 0x218b, "HP", ALC269_FIXUP_LIMIT_INT_MIC_BOOST_MUTE_LED), + /* ALC282 */ + SND_PCI_QUIRK(0x103c, 0x220f, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x2213, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x2266, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x2267, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x2268, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x2269, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x226a, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x226b, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x227a, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x227b, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x229e, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x22a0, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x22b2, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x22b7, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x22bf, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x22c0, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x22c1, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x22c2, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x22cd, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x22ce, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x22cf, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x22d0, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + /* ALC290 */ + SND_PCI_QUIRK(0x103c, 0x2260, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x2261, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x2262, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x2263, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x2264, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x2265, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x227d, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x227e, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x227f, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x2280, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x2281, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x2282, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x2289, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x228a, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x228b, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x228c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x228d, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x228e, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x22c5, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x22c6, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x22c7, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x22c8, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x22c3, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x22c4, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), SND_PCI_QUIRK_VENDOR(0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED), SND_PCI_QUIRK(0x1043, 0x103f, "ASUS TX300", ALC282_FIXUP_ASUS_TX300), SND_PCI_QUIRK(0x1043, 0x106d, "Asus K53BE", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 7311badf6a9..3bc29c9b252 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -83,6 +83,7 @@ enum { STAC_DELL_M6_BOTH, STAC_DELL_EQ, STAC_ALIENWARE_M17X, + STAC_92HD89XX_HP_FRONT_JACK, STAC_92HD73XX_MODELS }; @@ -97,6 +98,7 @@ enum { STAC_92HD83XXX_HP_LED, STAC_92HD83XXX_HP_INV_LED, STAC_92HD83XXX_HP_MIC_LED, + STAC_HP_LED_GPIO10, STAC_92HD83XXX_HEADSET_JACK, STAC_92HD83XXX_HP, STAC_HP_ENVY_BASS, @@ -1795,6 +1797,12 @@ static const struct hda_pintbl intel_dg45id_pin_configs[] = { {} }; +static const struct hda_pintbl stac92hd89xx_hp_front_jack_pin_configs[] = { + { 0x0a, 0x02214030 }, + { 0x0b, 0x02A19010 }, + {} +}; + static void stac92hd73xx_fixup_ref(struct hda_codec *codec, const struct hda_fixup *fix, int action) { @@ -1913,6 +1921,10 @@ static const struct hda_fixup stac92hd73xx_fixups[] = { [STAC_92HD73XX_NO_JD] = { .type = HDA_FIXUP_FUNC, .v.func = stac92hd73xx_fixup_no_jd, + }, + [STAC_92HD89XX_HP_FRONT_JACK] = { + .type = HDA_FIXUP_PINS, + .v.pins = stac92hd89xx_hp_front_jack_pin_configs, } }; @@ -1973,6 +1985,8 @@ static const struct snd_pci_quirk stac92hd73xx_fixup_tbl[] = { "Alienware M17x", STAC_ALIENWARE_M17X), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0490, "Alienware M17x R3", STAC_DELL_EQ), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x2b17, + "unknown HP", STAC_92HD89XX_HP_FRONT_JACK), {} /* terminator */ }; @@ -2117,6 +2131,17 @@ static void stac92hd83xxx_fixup_hp_mic_led(struct hda_codec *codec, } } +static void stac92hd83xxx_fixup_hp_led_gpio10(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct sigmatel_spec *spec = codec->spec; + + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + spec->gpio_led = 0x10; /* GPIO4 */ + spec->default_polarity = 0; + } +} + static void stac92hd83xxx_fixup_headset_jack(struct hda_codec *codec, const struct hda_fixup *fix, int action) { @@ -2611,6 +2636,12 @@ static const struct hda_fixup stac92hd83xxx_fixups[] = { .chained = true, .chain_id = STAC_92HD83XXX_HP, }, + [STAC_HP_LED_GPIO10] = { + .type = HDA_FIXUP_FUNC, + .v.func = stac92hd83xxx_fixup_hp_led_gpio10, + .chained = true, + .chain_id = STAC_92HD83XXX_HP, + }, [STAC_92HD83XXX_HEADSET_JACK] = { .type = HDA_FIXUP_FUNC, .v.func = stac92hd83xxx_fixup_headset_jack, @@ -2689,6 +2720,8 @@ static const struct snd_pci_quirk stac92hd83xxx_fixup_tbl[] = { "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1888, "HP Envy Spectre", STAC_HP_ENVY_BASS), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1899, + "HP Folio 13", STAC_HP_LED_GPIO10), SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x18df, "HP Folio", STAC_HP_BNB13_EQ), SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x18F8, diff --git a/sound/soc/blackfin/Kconfig b/sound/soc/blackfin/Kconfig index 54f74f8cbb7..4544d8eb145 100644 --- a/sound/soc/blackfin/Kconfig +++ b/sound/soc/blackfin/Kconfig @@ -11,7 +11,7 @@ config SND_BF5XX_I2S config SND_BF5XX_SOC_SSM2602 tristate "SoC SSM2602 Audio Codec Add-On Card support" - depends on SND_BF5XX_I2S && (SPI_MASTER || I2C) + depends on SND_BF5XX_I2S && SND_SOC_I2C_AND_SPI select SND_BF5XX_SOC_I2S if !BF60x select SND_BF6XX_SOC_I2S if BF60x select SND_SOC_SSM2602 @@ -21,10 +21,9 @@ config SND_BF5XX_SOC_SSM2602 config SND_SOC_BFIN_EVAL_ADAU1701 tristate "Support for the EVAL-ADAU1701MINIZ board on Blackfin eval boards" - depends on SND_BF5XX_I2S + depends on SND_BF5XX_I2S && I2C select SND_BF5XX_SOC_I2S select SND_SOC_ADAU1701 - select I2C help Say Y if you want to add support for the Analog Devices EVAL-ADAU1701MINIZ board connected to one of the Blackfin evaluation boards like the @@ -45,7 +44,7 @@ config SND_SOC_BFIN_EVAL_ADAU1373 config SND_SOC_BFIN_EVAL_ADAV80X tristate "Support for the EVAL-ADAV80X boards on Blackfin eval boards" - depends on SND_BF5XX_I2S && (SPI_MASTER || I2C) + depends on SND_BF5XX_I2S && SND_SOC_I2C_AND_SPI select SND_BF5XX_SOC_I2S select SND_SOC_ADAV80X help @@ -58,7 +57,7 @@ config SND_SOC_BFIN_EVAL_ADAV80X config SND_BF5XX_SOC_AD1836 tristate "SoC AD1836 Audio support for BF5xx" - depends on SND_BF5XX_I2S + depends on SND_BF5XX_I2S && SPI_MASTER select SND_BF5XX_SOC_I2S select SND_SOC_AD1836 help @@ -66,7 +65,7 @@ config SND_BF5XX_SOC_AD1836 config SND_BF5XX_SOC_AD193X tristate "SoC AD193X Audio support for Blackfin" - depends on SND_BF5XX_I2S + depends on SND_BF5XX_I2S && SND_SOC_I2C_AND_SPI select SND_BF5XX_SOC_I2S select SND_SOC_AD193X help diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c index 7257a8885f4..34d965a4a04 100644 --- a/sound/soc/codecs/ad1980.c +++ b/sound/soc/codecs/ad1980.c @@ -57,8 +57,8 @@ static const u16 ad1980_reg[] = { static const char *ad1980_rec_sel[] = {"Mic", "CD", "NC", "AUX", "Line", "Stereo Mix", "Mono Mix", "Phone"}; -static const struct soc_enum ad1980_cap_src = - SOC_ENUM_DOUBLE(AC97_REC_SEL, 8, 0, 7, ad1980_rec_sel); +static SOC_ENUM_DOUBLE_DECL(ad1980_cap_src, + AC97_REC_SEL, 8, 0, ad1980_rec_sel); static const struct snd_kcontrol_new ad1980_snd_ac97_controls[] = { SOC_DOUBLE("Master Playback Volume", AC97_MASTER, 8, 0, 31, 1), diff --git a/sound/soc/codecs/da732x.c b/sound/soc/codecs/da732x.c index f295b656991..f4d965ebc29 100644 --- a/sound/soc/codecs/da732x.c +++ b/sound/soc/codecs/da732x.c @@ -1268,11 +1268,23 @@ static struct snd_soc_dai_driver da732x_dai[] = { }, }; +static bool da732x_volatile(struct device *dev, unsigned int reg) +{ + switch (reg) { + case DA732X_REG_HPL_DAC_OFF_CNTL: + case DA732X_REG_HPR_DAC_OFF_CNTL: + return true; + default: + return false; + } +} + static const struct regmap_config da732x_regmap = { .reg_bits = 8, .val_bits = 8, .max_register = DA732X_MAX_REG, + .volatile_reg = da732x_volatile, .reg_defaults = da732x_reg_cache, .num_reg_defaults = ARRAY_SIZE(da732x_reg_cache), .cache_type = REGCACHE_RBTREE, diff --git a/sound/soc/codecs/da9055.c b/sound/soc/codecs/da9055.c index 52b79a487ac..422812613a2 100644 --- a/sound/soc/codecs/da9055.c +++ b/sound/soc/codecs/da9055.c @@ -1523,8 +1523,15 @@ static int da9055_remove(struct i2c_client *client) return 0; } +/* + * DO NOT change the device Ids. The naming is intentionally specific as both + * the CODEC and PMIC 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 CODEC + * and PMIC, which must be different to operate together. + */ static const struct i2c_device_id da9055_i2c_id[] = { - { "da9055", 0 }, + { "da9055-codec", 0 }, { } }; MODULE_DEVICE_TABLE(i2c, da9055_i2c_id); @@ -1532,7 +1539,7 @@ MODULE_DEVICE_TABLE(i2c, da9055_i2c_id); /* I2C codec control layer */ static struct i2c_driver da9055_i2c_driver = { .driver = { - .name = "da9055", + .name = "da9055-codec", .owner = THIS_MODULE, }, .probe = da9055_i2c_probe, diff --git a/sound/soc/codecs/isabelle.c b/sound/soc/codecs/isabelle.c index 5839048ec46..cb736ddc446 100644 --- a/sound/soc/codecs/isabelle.c +++ b/sound/soc/codecs/isabelle.c @@ -140,13 +140,17 @@ static const char *isabelle_rx1_texts[] = {"VRX1", "ARX1"}; static const char *isabelle_rx2_texts[] = {"VRX2", "ARX2"}; static const struct soc_enum isabelle_rx1_enum[] = { - SOC_ENUM_SINGLE(ISABELLE_VOICE_HPF_CFG_REG, 3, 1, isabelle_rx1_texts), - SOC_ENUM_SINGLE(ISABELLE_AUDIO_HPF_CFG_REG, 5, 1, isabelle_rx1_texts), + SOC_ENUM_SINGLE(ISABELLE_VOICE_HPF_CFG_REG, 3, + ARRAY_SIZE(isabelle_rx1_texts), isabelle_rx1_texts), + SOC_ENUM_SINGLE(ISABELLE_AUDIO_HPF_CFG_REG, 5, + ARRAY_SIZE(isabelle_rx1_texts), isabelle_rx1_texts), }; static const struct soc_enum isabelle_rx2_enum[] = { - SOC_ENUM_SINGLE(ISABELLE_VOICE_HPF_CFG_REG, 2, 1, isabelle_rx2_texts), - SOC_ENUM_SINGLE(ISABELLE_AUDIO_HPF_CFG_REG, 4, 1, isabelle_rx2_texts), + SOC_ENUM_SINGLE(ISABELLE_VOICE_HPF_CFG_REG, 2, + ARRAY_SIZE(isabelle_rx2_texts), isabelle_rx2_texts), + SOC_ENUM_SINGLE(ISABELLE_AUDIO_HPF_CFG_REG, 4, + ARRAY_SIZE(isabelle_rx2_texts), isabelle_rx2_texts), }; /* Headset DAC playback switches */ @@ -161,13 +165,17 @@ static const char *isabelle_atx_texts[] = {"AMIC1", "DMIC"}; static const char *isabelle_vtx_texts[] = {"AMIC2", "DMIC"}; static const struct soc_enum isabelle_atx_enum[] = { - SOC_ENUM_SINGLE(ISABELLE_AMIC_CFG_REG, 7, 1, isabelle_atx_texts), - SOC_ENUM_SINGLE(ISABELLE_DMIC_CFG_REG, 0, 1, isabelle_atx_texts), + SOC_ENUM_SINGLE(ISABELLE_AMIC_CFG_REG, 7, + ARRAY_SIZE(isabelle_atx_texts), isabelle_atx_texts), + SOC_ENUM_SINGLE(ISABELLE_DMIC_CFG_REG, 0, + ARRAY_SIZE(isabelle_atx_texts), isabelle_atx_texts), }; static const struct soc_enum isabelle_vtx_enum[] = { - SOC_ENUM_SINGLE(ISABELLE_AMIC_CFG_REG, 6, 1, isabelle_vtx_texts), - SOC_ENUM_SINGLE(ISABELLE_DMIC_CFG_REG, 0, 1, isabelle_vtx_texts), + SOC_ENUM_SINGLE(ISABELLE_AMIC_CFG_REG, 6, + ARRAY_SIZE(isabelle_vtx_texts), isabelle_vtx_texts), + SOC_ENUM_SINGLE(ISABELLE_DMIC_CFG_REG, 0, + ARRAY_SIZE(isabelle_vtx_texts), isabelle_vtx_texts), }; static const struct snd_kcontrol_new atx_mux_controls = @@ -183,17 +191,13 @@ static const char *isabelle_amic1_texts[] = { /* Left analog microphone selection */ static const char *isabelle_amic2_texts[] = {"Sub Mic", "Aux/FM Right"}; -static const struct soc_enum isabelle_amic1_enum[] = { - SOC_ENUM_SINGLE(ISABELLE_AMIC_CFG_REG, 5, - ARRAY_SIZE(isabelle_amic1_texts), - isabelle_amic1_texts), -}; +static SOC_ENUM_SINGLE_DECL(isabelle_amic1_enum, + ISABELLE_AMIC_CFG_REG, 5, + isabelle_amic1_texts); -static const struct soc_enum isabelle_amic2_enum[] = { - SOC_ENUM_SINGLE(ISABELLE_AMIC_CFG_REG, 4, - ARRAY_SIZE(isabelle_amic2_texts), - isabelle_amic2_texts), -}; +static SOC_ENUM_SINGLE_DECL(isabelle_amic2_enum, + ISABELLE_AMIC_CFG_REG, 4, + isabelle_amic2_texts); static const struct snd_kcontrol_new amic1_control = SOC_DAPM_ENUM("Route", isabelle_amic1_enum); @@ -206,16 +210,20 @@ static const char *isabelle_st_audio_texts[] = {"ATX1", "ATX2"}; static const char *isabelle_st_voice_texts[] = {"VTX1", "VTX2"}; static const struct soc_enum isabelle_st_audio_enum[] = { - SOC_ENUM_SINGLE(ISABELLE_ATX_STPGA1_CFG_REG, 7, 1, + SOC_ENUM_SINGLE(ISABELLE_ATX_STPGA1_CFG_REG, 7, + ARRAY_SIZE(isabelle_st_audio_texts), isabelle_st_audio_texts), - SOC_ENUM_SINGLE(ISABELLE_ATX_STPGA2_CFG_REG, 7, 1, + SOC_ENUM_SINGLE(ISABELLE_ATX_STPGA2_CFG_REG, 7, + ARRAY_SIZE(isabelle_st_audio_texts), isabelle_st_audio_texts), }; static const struct soc_enum isabelle_st_voice_enum[] = { - SOC_ENUM_SINGLE(ISABELLE_VTX_STPGA1_CFG_REG, 7, 1, + SOC_ENUM_SINGLE(ISABELLE_VTX_STPGA1_CFG_REG, 7, + ARRAY_SIZE(isabelle_st_voice_texts), isabelle_st_voice_texts), - SOC_ENUM_SINGLE(ISABELLE_VTX2_STPGA2_CFG_REG, 7, 1, + SOC_ENUM_SINGLE(ISABELLE_VTX2_STPGA2_CFG_REG, 7, + ARRAY_SIZE(isabelle_st_voice_texts), isabelle_st_voice_texts), }; diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c index 51f9b3d16b4..9f714ea8661 100644 --- a/sound/soc/codecs/max98090.c +++ b/sound/soc/codecs/max98090.c @@ -336,6 +336,7 @@ static bool max98090_readable_register(struct device *dev, unsigned int reg) case M98090_REG_RECORD_TDM_SLOT: case M98090_REG_SAMPLE_RATE: case M98090_REG_DMIC34_BIQUAD_BASE ... M98090_REG_DMIC34_BIQUAD_BASE + 0x0E: + case M98090_REG_REVISION_ID: return true; default: return false; @@ -1769,16 +1770,6 @@ static int max98090_set_bias_level(struct snd_soc_codec *codec, switch (level) { case SND_SOC_BIAS_ON: - if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { - ret = regcache_sync(max98090->regmap); - - if (ret != 0) { - dev_err(codec->dev, - "Failed to sync cache: %d\n", ret); - return ret; - } - } - if (max98090->jack_state == M98090_JACK_STATE_HEADSET) { /* * Set to normal bias level. @@ -1792,6 +1783,16 @@ static int max98090_set_bias_level(struct snd_soc_codec *codec, break; case SND_SOC_BIAS_STANDBY: + if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { + ret = regcache_sync(max98090->regmap); + if (ret != 0) { + dev_err(codec->dev, + "Failed to sync cache: %d\n", ret); + return ret; + } + } + break; + case SND_SOC_BIAS_OFF: /* Set internal pull-up to lowest power mode */ snd_soc_update_bits(codec, M98090_REG_JACK_DETECT, diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index a3fb4117963..886924934aa 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -2093,6 +2093,7 @@ MODULE_DEVICE_TABLE(i2c, rt5640_i2c_id); #ifdef CONFIG_ACPI static struct acpi_device_id rt5640_acpi_match[] = { { "INT33CA", 0 }, + { "10EC5640", 0 }, { }, }; MODULE_DEVICE_TABLE(acpi, rt5640_acpi_match); diff --git a/sound/soc/codecs/sta32x.c b/sound/soc/codecs/sta32x.c index 06edb396e73..2735361a4c3 100644 --- a/sound/soc/codecs/sta32x.c +++ b/sound/soc/codecs/sta32x.c @@ -187,42 +187,42 @@ static const unsigned int sta32x_limiter_drc_release_tlv[] = { 13, 16, TLV_DB_SCALE_ITEM(-1500, 300, 0), }; -static const struct soc_enum sta32x_drc_ac_enum = - SOC_ENUM_SINGLE(STA32X_CONFD, STA32X_CONFD_DRC_SHIFT, - 2, sta32x_drc_ac); -static const struct soc_enum sta32x_auto_eq_enum = - SOC_ENUM_SINGLE(STA32X_AUTO1, STA32X_AUTO1_AMEQ_SHIFT, - 3, sta32x_auto_eq_mode); -static const struct soc_enum sta32x_auto_gc_enum = - SOC_ENUM_SINGLE(STA32X_AUTO1, STA32X_AUTO1_AMGC_SHIFT, - 4, sta32x_auto_gc_mode); -static const struct soc_enum sta32x_auto_xo_enum = - SOC_ENUM_SINGLE(STA32X_AUTO2, STA32X_AUTO2_XO_SHIFT, - 16, sta32x_auto_xo_mode); -static const struct soc_enum sta32x_preset_eq_enum = - SOC_ENUM_SINGLE(STA32X_AUTO3, STA32X_AUTO3_PEQ_SHIFT, - 32, sta32x_preset_eq_mode); -static const struct soc_enum sta32x_limiter_ch1_enum = - SOC_ENUM_SINGLE(STA32X_C1CFG, STA32X_CxCFG_LS_SHIFT, - 3, sta32x_limiter_select); -static const struct soc_enum sta32x_limiter_ch2_enum = - SOC_ENUM_SINGLE(STA32X_C2CFG, STA32X_CxCFG_LS_SHIFT, - 3, sta32x_limiter_select); -static const struct soc_enum sta32x_limiter_ch3_enum = - SOC_ENUM_SINGLE(STA32X_C3CFG, STA32X_CxCFG_LS_SHIFT, - 3, sta32x_limiter_select); -static const struct soc_enum sta32x_limiter1_attack_rate_enum = - SOC_ENUM_SINGLE(STA32X_L1AR, STA32X_LxA_SHIFT, - 16, sta32x_limiter_attack_rate); -static const struct soc_enum sta32x_limiter2_attack_rate_enum = - SOC_ENUM_SINGLE(STA32X_L2AR, STA32X_LxA_SHIFT, - 16, sta32x_limiter_attack_rate); -static const struct soc_enum sta32x_limiter1_release_rate_enum = - SOC_ENUM_SINGLE(STA32X_L1AR, STA32X_LxR_SHIFT, - 16, sta32x_limiter_release_rate); -static const struct soc_enum sta32x_limiter2_release_rate_enum = - SOC_ENUM_SINGLE(STA32X_L2AR, STA32X_LxR_SHIFT, - 16, sta32x_limiter_release_rate); +static SOC_ENUM_SINGLE_DECL(sta32x_drc_ac_enum, + STA32X_CONFD, STA32X_CONFD_DRC_SHIFT, + sta32x_drc_ac); +static SOC_ENUM_SINGLE_DECL(sta32x_auto_eq_enum, + STA32X_AUTO1, STA32X_AUTO1_AMEQ_SHIFT, + sta32x_auto_eq_mode); +static SOC_ENUM_SINGLE_DECL(sta32x_auto_gc_enum, + STA32X_AUTO1, STA32X_AUTO1_AMGC_SHIFT, + sta32x_auto_gc_mode); +static SOC_ENUM_SINGLE_DECL(sta32x_auto_xo_enum, + STA32X_AUTO2, STA32X_AUTO2_XO_SHIFT, + sta32x_auto_xo_mode); +static SOC_ENUM_SINGLE_DECL(sta32x_preset_eq_enum, + STA32X_AUTO3, STA32X_AUTO3_PEQ_SHIFT, + sta32x_preset_eq_mode); +static SOC_ENUM_SINGLE_DECL(sta32x_limiter_ch1_enum, + STA32X_C1CFG, STA32X_CxCFG_LS_SHIFT, + sta32x_limiter_select); +static SOC_ENUM_SINGLE_DECL(sta32x_limiter_ch2_enum, + STA32X_C2CFG, STA32X_CxCFG_LS_SHIFT, + sta32x_limiter_select); +static SOC_ENUM_SINGLE_DECL(sta32x_limiter_ch3_enum, + STA32X_C3CFG, STA32X_CxCFG_LS_SHIFT, + sta32x_limiter_select); +static SOC_ENUM_SINGLE_DECL(sta32x_limiter1_attack_rate_enum, + STA32X_L1AR, STA32X_LxA_SHIFT, + sta32x_limiter_attack_rate); +static SOC_ENUM_SINGLE_DECL(sta32x_limiter2_attack_rate_enum, + STA32X_L2AR, STA32X_LxA_SHIFT, + sta32x_limiter_attack_rate); +static SOC_ENUM_SINGLE_DECL(sta32x_limiter1_release_rate_enum, + STA32X_L1AR, STA32X_LxR_SHIFT, + sta32x_limiter_release_rate); +static SOC_ENUM_SINGLE_DECL(sta32x_limiter2_release_rate_enum, + STA32X_L2AR, STA32X_LxR_SHIFT, + sta32x_limiter_release_rate); /* byte array controls for setting biquad, mixer, scaling coefficients; * for biquads all five coefficients need to be set in one go, @@ -331,7 +331,7 @@ static int sta32x_sync_coef_shadow(struct snd_soc_codec *codec) static int sta32x_cache_sync(struct snd_soc_codec *codec) { - struct sta32x_priv *sta32x = codec->control_data; + struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec); unsigned int mute; int rc; @@ -434,7 +434,7 @@ SOC_SINGLE_TLV("Treble Tone Control", STA32X_TONE, STA32X_TONE_TTC_SHIFT, 15, 0, SOC_ENUM("Limiter1 Attack Rate (dB/ms)", sta32x_limiter1_attack_rate_enum), SOC_ENUM("Limiter2 Attack Rate (dB/ms)", sta32x_limiter2_attack_rate_enum), SOC_ENUM("Limiter1 Release Rate (dB/ms)", sta32x_limiter1_release_rate_enum), -SOC_ENUM("Limiter2 Release Rate (dB/ms)", sta32x_limiter1_release_rate_enum), +SOC_ENUM("Limiter2 Release Rate (dB/ms)", sta32x_limiter2_release_rate_enum), /* depending on mode, the attack/release thresholds have * two different enum definitions; provide both diff --git a/sound/soc/codecs/wm8400.c b/sound/soc/codecs/wm8400.c index 48dc7d2fee3..6d684d934f4 100644 --- a/sound/soc/codecs/wm8400.c +++ b/sound/soc/codecs/wm8400.c @@ -117,19 +117,23 @@ static int wm8400_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol, static const char *wm8400_digital_sidetone[] = {"None", "Left ADC", "Right ADC", "Reserved"}; -static const struct soc_enum wm8400_left_digital_sidetone_enum = -SOC_ENUM_SINGLE(WM8400_DIGITAL_SIDE_TONE, - WM8400_ADC_TO_DACL_SHIFT, 2, wm8400_digital_sidetone); +static SOC_ENUM_SINGLE_DECL(wm8400_left_digital_sidetone_enum, + WM8400_DIGITAL_SIDE_TONE, + WM8400_ADC_TO_DACL_SHIFT, + wm8400_digital_sidetone); -static const struct soc_enum wm8400_right_digital_sidetone_enum = -SOC_ENUM_SINGLE(WM8400_DIGITAL_SIDE_TONE, - WM8400_ADC_TO_DACR_SHIFT, 2, wm8400_digital_sidetone); +static SOC_ENUM_SINGLE_DECL(wm8400_right_digital_sidetone_enum, + WM8400_DIGITAL_SIDE_TONE, + WM8400_ADC_TO_DACR_SHIFT, + wm8400_digital_sidetone); static const char *wm8400_adcmode[] = {"Hi-fi mode", "Voice mode 1", "Voice mode 2", "Voice mode 3"}; -static const struct soc_enum wm8400_right_adcmode_enum = -SOC_ENUM_SINGLE(WM8400_ADC_CTRL, WM8400_ADC_HPF_CUT_SHIFT, 3, wm8400_adcmode); +static SOC_ENUM_SINGLE_DECL(wm8400_right_adcmode_enum, + WM8400_ADC_CTRL, + WM8400_ADC_HPF_CUT_SHIFT, + wm8400_adcmode); static const struct snd_kcontrol_new wm8400_snd_controls[] = { /* INMIXL */ @@ -422,9 +426,10 @@ SOC_DAPM_SINGLE("RINPGA34 Switch", WM8400_INPUT_MIXER3, WM8400_L34MNB_SHIFT, static const char *wm8400_ainlmux[] = {"INMIXL Mix", "RXVOICE Mix", "DIFFINL Mix"}; -static const struct soc_enum wm8400_ainlmux_enum = -SOC_ENUM_SINGLE( WM8400_INPUT_MIXER1, WM8400_AINLMODE_SHIFT, - ARRAY_SIZE(wm8400_ainlmux), wm8400_ainlmux); +static SOC_ENUM_SINGLE_DECL(wm8400_ainlmux_enum, + WM8400_INPUT_MIXER1, + WM8400_AINLMODE_SHIFT, + wm8400_ainlmux); static const struct snd_kcontrol_new wm8400_dapm_ainlmux_controls = SOC_DAPM_ENUM("Route", wm8400_ainlmux_enum); @@ -435,9 +440,10 @@ SOC_DAPM_ENUM("Route", wm8400_ainlmux_enum); static const char *wm8400_ainrmux[] = {"INMIXR Mix", "RXVOICE Mix", "DIFFINR Mix"}; -static const struct soc_enum wm8400_ainrmux_enum = -SOC_ENUM_SINGLE( WM8400_INPUT_MIXER1, WM8400_AINRMODE_SHIFT, - ARRAY_SIZE(wm8400_ainrmux), wm8400_ainrmux); +static SOC_ENUM_SINGLE_DECL(wm8400_ainrmux_enum, + WM8400_INPUT_MIXER1, + WM8400_AINRMODE_SHIFT, + wm8400_ainrmux); static const struct snd_kcontrol_new wm8400_dapm_ainrmux_controls = SOC_DAPM_ENUM("Route", wm8400_ainrmux_enum); diff --git a/sound/soc/codecs/wm8770.c b/sound/soc/codecs/wm8770.c index 89a18d82f30..5bce2101348 100644 --- a/sound/soc/codecs/wm8770.c +++ b/sound/soc/codecs/wm8770.c @@ -196,8 +196,8 @@ static const char *ain_text[] = { "AIN5", "AIN6", "AIN7", "AIN8" }; -static const struct soc_enum ain_enum = - SOC_ENUM_DOUBLE(WM8770_ADCMUX, 0, 4, 8, ain_text); +static SOC_ENUM_DOUBLE_DECL(ain_enum, + WM8770_ADCMUX, 0, 4, ain_text); static const struct snd_kcontrol_new ain_mux = SOC_DAPM_ENUM("Capture Mux", ain_enum); diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c index e98bc7038a0..43c2201cb90 100644 --- a/sound/soc/codecs/wm8900.c +++ b/sound/soc/codecs/wm8900.c @@ -304,53 +304,53 @@ static const DECLARE_TLV_DB_SCALE(adc_tlv, -7200, 75, 1); static const char *mic_bias_level_txt[] = { "0.9*AVDD", "0.65*AVDD" }; -static const struct soc_enum mic_bias_level = -SOC_ENUM_SINGLE(WM8900_REG_INCTL, 8, 2, mic_bias_level_txt); +static SOC_ENUM_SINGLE_DECL(mic_bias_level, + WM8900_REG_INCTL, 8, mic_bias_level_txt); static const char *dac_mute_rate_txt[] = { "Fast", "Slow" }; -static const struct soc_enum dac_mute_rate = -SOC_ENUM_SINGLE(WM8900_REG_DACCTRL, 7, 2, dac_mute_rate_txt); +static SOC_ENUM_SINGLE_DECL(dac_mute_rate, + WM8900_REG_DACCTRL, 7, dac_mute_rate_txt); static const char *dac_deemphasis_txt[] = { "Disabled", "32kHz", "44.1kHz", "48kHz" }; -static const struct soc_enum dac_deemphasis = -SOC_ENUM_SINGLE(WM8900_REG_DACCTRL, 4, 4, dac_deemphasis_txt); +static SOC_ENUM_SINGLE_DECL(dac_deemphasis, + WM8900_REG_DACCTRL, 4, dac_deemphasis_txt); static const char *adc_hpf_cut_txt[] = { "Hi-fi mode", "Voice mode 1", "Voice mode 2", "Voice mode 3" }; -static const struct soc_enum adc_hpf_cut = -SOC_ENUM_SINGLE(WM8900_REG_ADCCTRL, 5, 4, adc_hpf_cut_txt); +static SOC_ENUM_SINGLE_DECL(adc_hpf_cut, + WM8900_REG_ADCCTRL, 5, adc_hpf_cut_txt); static const char *lr_txt[] = { "Left", "Right" }; -static const struct soc_enum aifl_src = -SOC_ENUM_SINGLE(WM8900_REG_AUDIO1, 15, 2, lr_txt); +static SOC_ENUM_SINGLE_DECL(aifl_src, + WM8900_REG_AUDIO1, 15, lr_txt); -static const struct soc_enum aifr_src = -SOC_ENUM_SINGLE(WM8900_REG_AUDIO1, 14, 2, lr_txt); +static SOC_ENUM_SINGLE_DECL(aifr_src, + WM8900_REG_AUDIO1, 14, lr_txt); -static const struct soc_enum dacl_src = -SOC_ENUM_SINGLE(WM8900_REG_AUDIO2, 15, 2, lr_txt); +static SOC_ENUM_SINGLE_DECL(dacl_src, + WM8900_REG_AUDIO2, 15, lr_txt); -static const struct soc_enum dacr_src = -SOC_ENUM_SINGLE(WM8900_REG_AUDIO2, 14, 2, lr_txt); +static SOC_ENUM_SINGLE_DECL(dacr_src, + WM8900_REG_AUDIO2, 14, lr_txt); static const char *sidetone_txt[] = { "Disabled", "Left ADC", "Right ADC" }; -static const struct soc_enum dacl_sidetone = -SOC_ENUM_SINGLE(WM8900_REG_SIDETONE, 2, 3, sidetone_txt); +static SOC_ENUM_SINGLE_DECL(dacl_sidetone, + WM8900_REG_SIDETONE, 2, sidetone_txt); -static const struct soc_enum dacr_sidetone = -SOC_ENUM_SINGLE(WM8900_REG_SIDETONE, 0, 3, sidetone_txt); +static SOC_ENUM_SINGLE_DECL(dacr_sidetone, + WM8900_REG_SIDETONE, 0, sidetone_txt); static const struct snd_kcontrol_new wm8900_snd_controls[] = { SOC_ENUM("Mic Bias Level", mic_bias_level), @@ -496,8 +496,8 @@ SOC_DAPM_SINGLE("RINPUT3 Switch", WM8900_REG_INCTL, 0, 1, 0), static const char *wm8900_lp_mux[] = { "Disabled", "Enabled" }; -static const struct soc_enum wm8900_lineout2_lp_mux = -SOC_ENUM_SINGLE(WM8900_REG_LOUTMIXCTL1, 1, 2, wm8900_lp_mux); +static SOC_ENUM_SINGLE_DECL(wm8900_lineout2_lp_mux, + WM8900_REG_LOUTMIXCTL1, 1, wm8900_lp_mux); static const struct snd_kcontrol_new wm8900_lineout2_lp = SOC_DAPM_ENUM("Route", wm8900_lineout2_lp_mux); diff --git a/sound/soc/codecs/wm8958-dsp2.c b/sound/soc/codecs/wm8958-dsp2.c index b7488f190d2..d4248e00160 100644 --- a/sound/soc/codecs/wm8958-dsp2.c +++ b/sound/soc/codecs/wm8958-dsp2.c @@ -153,7 +153,7 @@ static int wm8958_dsp2_fw(struct snd_soc_codec *codec, const char *name, data32 &= 0xffffff; - wm8994_bulk_write(codec->control_data, + wm8994_bulk_write(wm8994->wm8994, data32 & 0xffffff, block_len / 2, (void *)(data + 8)); diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c index 433d59a0f3e..2ee23a39622 100644 --- a/sound/soc/codecs/wm8993.c +++ b/sound/soc/codecs/wm8993.c @@ -1562,7 +1562,6 @@ static int wm8993_remove(struct snd_soc_codec *codec) struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec); wm8993_set_bias_level(codec, SND_SOC_BIAS_OFF); - regulator_bulk_free(ARRAY_SIZE(wm8993->supplies), wm8993->supplies); return 0; } diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index b9be9cbc460..adb72063d44 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -265,21 +265,21 @@ static const char *sidetone_hpf_text[] = { "2.7kHz", "1.35kHz", "675Hz", "370Hz", "180Hz", "90Hz", "45Hz" }; -static const struct soc_enum sidetone_hpf = - SOC_ENUM_SINGLE(WM8994_SIDETONE, 7, 7, sidetone_hpf_text); +static SOC_ENUM_SINGLE_DECL(sidetone_hpf, + WM8994_SIDETONE, 7, sidetone_hpf_text); static const char *adc_hpf_text[] = { "HiFi", "Voice 1", "Voice 2", "Voice 3" }; -static const struct soc_enum aif1adc1_hpf = - SOC_ENUM_SINGLE(WM8994_AIF1_ADC1_FILTERS, 13, 4, adc_hpf_text); +static SOC_ENUM_SINGLE_DECL(aif1adc1_hpf, + WM8994_AIF1_ADC1_FILTERS, 13, adc_hpf_text); -static const struct soc_enum aif1adc2_hpf = - SOC_ENUM_SINGLE(WM8994_AIF1_ADC2_FILTERS, 13, 4, adc_hpf_text); +static SOC_ENUM_SINGLE_DECL(aif1adc2_hpf, + WM8994_AIF1_ADC2_FILTERS, 13, adc_hpf_text); -static const struct soc_enum aif2adc_hpf = - SOC_ENUM_SINGLE(WM8994_AIF2_ADC_FILTERS, 13, 4, adc_hpf_text); +static SOC_ENUM_SINGLE_DECL(aif2adc_hpf, + WM8994_AIF2_ADC_FILTERS, 13, adc_hpf_text); static const DECLARE_TLV_DB_SCALE(aif_tlv, 0, 600, 0); static const DECLARE_TLV_DB_SCALE(digital_tlv, -7200, 75, 1); @@ -501,39 +501,39 @@ static const char *aif_chan_src_text[] = { "Left", "Right" }; -static const struct soc_enum aif1adcl_src = - SOC_ENUM_SINGLE(WM8994_AIF1_CONTROL_1, 15, 2, aif_chan_src_text); +static SOC_ENUM_SINGLE_DECL(aif1adcl_src, + WM8994_AIF1_CONTROL_1, 15, aif_chan_src_text); -static const struct soc_enum aif1adcr_src = - SOC_ENUM_SINGLE(WM8994_AIF1_CONTROL_1, 14, 2, aif_chan_src_text); +static SOC_ENUM_SINGLE_DECL(aif1adcr_src, + WM8994_AIF1_CONTROL_1, 14, aif_chan_src_text); -static const struct soc_enum aif2adcl_src = - SOC_ENUM_SINGLE(WM8994_AIF2_CONTROL_1, 15, 2, aif_chan_src_text); +static SOC_ENUM_SINGLE_DECL(aif2adcl_src, + WM8994_AIF2_CONTROL_1, 15, aif_chan_src_text); -static const struct soc_enum aif2adcr_src = - SOC_ENUM_SINGLE(WM8994_AIF2_CONTROL_1, 14, 2, aif_chan_src_text); +static SOC_ENUM_SINGLE_DECL(aif2adcr_src, + WM8994_AIF2_CONTROL_1, 14, aif_chan_src_text); -static const struct soc_enum aif1dacl_src = - SOC_ENUM_SINGLE(WM8994_AIF1_CONTROL_2, 15, 2, aif_chan_src_text); +static SOC_ENUM_SINGLE_DECL(aif1dacl_src, + WM8994_AIF1_CONTROL_2, 15, aif_chan_src_text); -static const struct soc_enum aif1dacr_src = - SOC_ENUM_SINGLE(WM8994_AIF1_CONTROL_2, 14, 2, aif_chan_src_text); +static SOC_ENUM_SINGLE_DECL(aif1dacr_src, + WM8994_AIF1_CONTROL_2, 14, aif_chan_src_text); -static const struct soc_enum aif2dacl_src = - SOC_ENUM_SINGLE(WM8994_AIF2_CONTROL_2, 15, 2, aif_chan_src_text); +static SOC_ENUM_SINGLE_DECL(aif2dacl_src, + WM8994_AIF2_CONTROL_2, 15, aif_chan_src_text); -static const struct soc_enum aif2dacr_src = - SOC_ENUM_SINGLE(WM8994_AIF2_CONTROL_2, 14, 2, aif_chan_src_text); +static SOC_ENUM_SINGLE_DECL(aif2dacr_src, + WM8994_AIF2_CONTROL_2, 14, aif_chan_src_text); static const char *osr_text[] = { "Low Power", "High Performance", }; -static const struct soc_enum dac_osr = - SOC_ENUM_SINGLE(WM8994_OVERSAMPLING, 0, 2, osr_text); +static SOC_ENUM_SINGLE_DECL(dac_osr, + WM8994_OVERSAMPLING, 0, osr_text); -static const struct soc_enum adc_osr = - SOC_ENUM_SINGLE(WM8994_OVERSAMPLING, 1, 2, osr_text); +static SOC_ENUM_SINGLE_DECL(adc_osr, + WM8994_OVERSAMPLING, 1, osr_text); static const struct snd_kcontrol_new wm8994_snd_controls[] = { SOC_DOUBLE_R_TLV("AIF1ADC1 Volume", WM8994_AIF1_ADC1_LEFT_VOLUME, @@ -690,17 +690,20 @@ static const char *wm8958_ng_text[] = { "30ms", "125ms", "250ms", "500ms", }; -static const struct soc_enum wm8958_aif1dac1_ng_hold = - SOC_ENUM_SINGLE(WM8958_AIF1_DAC1_NOISE_GATE, - WM8958_AIF1DAC1_NG_THR_SHIFT, 4, wm8958_ng_text); +static SOC_ENUM_SINGLE_DECL(wm8958_aif1dac1_ng_hold, + WM8958_AIF1_DAC1_NOISE_GATE, + WM8958_AIF1DAC1_NG_THR_SHIFT, + wm8958_ng_text); -static const struct soc_enum wm8958_aif1dac2_ng_hold = - SOC_ENUM_SINGLE(WM8958_AIF1_DAC2_NOISE_GATE, - WM8958_AIF1DAC2_NG_THR_SHIFT, 4, wm8958_ng_text); +static SOC_ENUM_SINGLE_DECL(wm8958_aif1dac2_ng_hold, + WM8958_AIF1_DAC2_NOISE_GATE, + WM8958_AIF1DAC2_NG_THR_SHIFT, + wm8958_ng_text); -static const struct soc_enum wm8958_aif2dac_ng_hold = - SOC_ENUM_SINGLE(WM8958_AIF2_DAC_NOISE_GATE, - WM8958_AIF2DAC_NG_THR_SHIFT, 4, wm8958_ng_text); +static SOC_ENUM_SINGLE_DECL(wm8958_aif2dac_ng_hold, + WM8958_AIF2_DAC_NOISE_GATE, + WM8958_AIF2DAC_NG_THR_SHIFT, + wm8958_ng_text); static const struct snd_kcontrol_new wm8958_snd_controls[] = { SOC_SINGLE_TLV("AIF3 Boost Volume", WM8958_AIF3_CONTROL_2, 10, 3, 0, aif_tlv), @@ -1341,8 +1344,8 @@ static const char *adc_mux_text[] = { "DMIC", }; -static const struct soc_enum adc_enum = - SOC_ENUM_SINGLE(0, 0, 2, adc_mux_text); +static SOC_ENUM_SINGLE_DECL(adc_enum, + 0, 0, adc_mux_text); static const struct snd_kcontrol_new adcl_mux = SOC_DAPM_ENUM_VIRT("ADCL Mux", adc_enum); @@ -1478,14 +1481,14 @@ static const char *sidetone_text[] = { "ADC/DMIC1", "DMIC2", }; -static const struct soc_enum sidetone1_enum = - SOC_ENUM_SINGLE(WM8994_SIDETONE, 0, 2, sidetone_text); +static SOC_ENUM_SINGLE_DECL(sidetone1_enum, + WM8994_SIDETONE, 0, sidetone_text); static const struct snd_kcontrol_new sidetone1_mux = SOC_DAPM_ENUM("Left Sidetone Mux", sidetone1_enum); -static const struct soc_enum sidetone2_enum = - SOC_ENUM_SINGLE(WM8994_SIDETONE, 1, 2, sidetone_text); +static SOC_ENUM_SINGLE_DECL(sidetone2_enum, + WM8994_SIDETONE, 1, sidetone_text); static const struct snd_kcontrol_new sidetone2_mux = SOC_DAPM_ENUM("Right Sidetone Mux", sidetone2_enum); @@ -1498,22 +1501,24 @@ static const char *loopback_text[] = { "None", "ADCDAT", }; -static const struct soc_enum aif1_loopback_enum = - SOC_ENUM_SINGLE(WM8994_AIF1_CONTROL_2, WM8994_AIF1_LOOPBACK_SHIFT, 2, - loopback_text); +static SOC_ENUM_SINGLE_DECL(aif1_loopback_enum, + WM8994_AIF1_CONTROL_2, + WM8994_AIF1_LOOPBACK_SHIFT, + loopback_text); static const struct snd_kcontrol_new aif1_loopback = SOC_DAPM_ENUM("AIF1 Loopback", aif1_loopback_enum); -static const struct soc_enum aif2_loopback_enum = - SOC_ENUM_SINGLE(WM8994_AIF2_CONTROL_2, WM8994_AIF2_LOOPBACK_SHIFT, 2, - loopback_text); +static SOC_ENUM_SINGLE_DECL(aif2_loopback_enum, + WM8994_AIF2_CONTROL_2, + WM8994_AIF2_LOOPBACK_SHIFT, + loopback_text); static const struct snd_kcontrol_new aif2_loopback = SOC_DAPM_ENUM("AIF2 Loopback", aif2_loopback_enum); -static const struct soc_enum aif1dac_enum = - SOC_ENUM_SINGLE(WM8994_POWER_MANAGEMENT_6, 0, 2, aif1dac_text); +static SOC_ENUM_SINGLE_DECL(aif1dac_enum, + WM8994_POWER_MANAGEMENT_6, 0, aif1dac_text); static const struct snd_kcontrol_new aif1dac_mux = SOC_DAPM_ENUM("AIF1DAC Mux", aif1dac_enum); @@ -1522,8 +1527,8 @@ static const char *aif2dac_text[] = { "AIF2DACDAT", "AIF3DACDAT", }; -static const struct soc_enum aif2dac_enum = - SOC_ENUM_SINGLE(WM8994_POWER_MANAGEMENT_6, 1, 2, aif2dac_text); +static SOC_ENUM_SINGLE_DECL(aif2dac_enum, + WM8994_POWER_MANAGEMENT_6, 1, aif2dac_text); static const struct snd_kcontrol_new aif2dac_mux = SOC_DAPM_ENUM("AIF2DAC Mux", aif2dac_enum); @@ -1532,8 +1537,8 @@ static const char *aif2adc_text[] = { "AIF2ADCDAT", "AIF3DACDAT", }; -static const struct soc_enum aif2adc_enum = - SOC_ENUM_SINGLE(WM8994_POWER_MANAGEMENT_6, 2, 2, aif2adc_text); +static SOC_ENUM_SINGLE_DECL(aif2adc_enum, + WM8994_POWER_MANAGEMENT_6, 2, aif2adc_text); static const struct snd_kcontrol_new aif2adc_mux = SOC_DAPM_ENUM("AIF2ADC Mux", aif2adc_enum); @@ -1542,14 +1547,14 @@ static const char *aif3adc_text[] = { "AIF1ADCDAT", "AIF2ADCDAT", "AIF2DACDAT", "Mono PCM", }; -static const struct soc_enum wm8994_aif3adc_enum = - SOC_ENUM_SINGLE(WM8994_POWER_MANAGEMENT_6, 3, 3, aif3adc_text); +static SOC_ENUM_SINGLE_DECL(wm8994_aif3adc_enum, + WM8994_POWER_MANAGEMENT_6, 3, aif3adc_text); static const struct snd_kcontrol_new wm8994_aif3adc_mux = SOC_DAPM_ENUM("AIF3ADC Mux", wm8994_aif3adc_enum); -static const struct soc_enum wm8958_aif3adc_enum = - SOC_ENUM_SINGLE(WM8994_POWER_MANAGEMENT_6, 3, 4, aif3adc_text); +static SOC_ENUM_SINGLE_DECL(wm8958_aif3adc_enum, + WM8994_POWER_MANAGEMENT_6, 3, aif3adc_text); static const struct snd_kcontrol_new wm8958_aif3adc_mux = SOC_DAPM_ENUM("AIF3ADC Mux", wm8958_aif3adc_enum); @@ -1558,8 +1563,8 @@ static const char *mono_pcm_out_text[] = { "None", "AIF2ADCL", "AIF2ADCR", }; -static const struct soc_enum mono_pcm_out_enum = - SOC_ENUM_SINGLE(WM8994_POWER_MANAGEMENT_6, 9, 3, mono_pcm_out_text); +static SOC_ENUM_SINGLE_DECL(mono_pcm_out_enum, + WM8994_POWER_MANAGEMENT_6, 9, mono_pcm_out_text); static const struct snd_kcontrol_new mono_pcm_out_mux = SOC_DAPM_ENUM("Mono PCM Out Mux", mono_pcm_out_enum); @@ -1569,14 +1574,14 @@ static const char *aif2dac_src_text[] = { }; /* Note that these two control shouldn't be simultaneously switched to AIF3 */ -static const struct soc_enum aif2dacl_src_enum = - SOC_ENUM_SINGLE(WM8994_POWER_MANAGEMENT_6, 7, 2, aif2dac_src_text); +static SOC_ENUM_SINGLE_DECL(aif2dacl_src_enum, + WM8994_POWER_MANAGEMENT_6, 7, aif2dac_src_text); static const struct snd_kcontrol_new aif2dacl_src_mux = SOC_DAPM_ENUM("AIF2DACL Mux", aif2dacl_src_enum); -static const struct soc_enum aif2dacr_src_enum = - SOC_ENUM_SINGLE(WM8994_POWER_MANAGEMENT_6, 8, 2, aif2dac_src_text); +static SOC_ENUM_SINGLE_DECL(aif2dacr_src_enum, + WM8994_POWER_MANAGEMENT_6, 8, aif2dac_src_text); static const struct snd_kcontrol_new aif2dacr_src_mux = SOC_DAPM_ENUM("AIF2DACR Mux", aif2dacr_src_enum); diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c index 70ff3772079..5e3bc3c6801 100644 --- a/sound/soc/davinci/davinci-evm.c +++ b/sound/soc/davinci/davinci-evm.c @@ -399,6 +399,7 @@ static struct platform_driver davinci_evm_driver = { .driver = { .name = "davinci_evm", .owner = THIS_MODULE, + .pm = &snd_soc_pm_ops, .of_match_table = of_match_ptr(davinci_evm_dt_ids), }, }; diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index b7858bfa029..670afa29e30 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -263,7 +263,9 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) { struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai); + int ret = 0; + pm_runtime_get_sync(mcasp->dev); switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_DSP_B: case SND_SOC_DAIFMT_AC97: @@ -317,7 +319,8 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, break; default: - return -EINVAL; + ret = -EINVAL; + goto out; } switch (fmt & SND_SOC_DAIFMT_INV_MASK) { @@ -354,10 +357,12 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, break; default: - return -EINVAL; + ret = -EINVAL; + break; } - - return 0; +out: + pm_runtime_put_sync(mcasp->dev); + return ret; } static int davinci_mcasp_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div) @@ -448,7 +453,7 @@ static int davinci_config_channel_size(struct davinci_mcasp *mcasp, return 0; } -static int davinci_hw_common_param(struct davinci_mcasp *mcasp, int stream, +static int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream, int channels) { int i; @@ -524,12 +529,18 @@ static int davinci_hw_common_param(struct davinci_mcasp *mcasp, int stream, return 0; } -static void davinci_hw_param(struct davinci_mcasp *mcasp, int stream) +static int mcasp_i2s_hw_param(struct davinci_mcasp *mcasp, int stream) { int i, active_slots; u32 mask = 0; u32 busel = 0; + if ((mcasp->tdm_slots < 2) || (mcasp->tdm_slots > 32)) { + dev_err(mcasp->dev, "tdm slot %d not supported\n", + mcasp->tdm_slots); + return -EINVAL; + } + active_slots = (mcasp->tdm_slots > 31) ? 32 : mcasp->tdm_slots; for (i = 0; i < active_slots; i++) mask |= (1 << i); @@ -539,35 +550,21 @@ static void davinci_hw_param(struct davinci_mcasp *mcasp, int stream) if (!mcasp->dat_port) busel = TXSEL; - if (stream == SNDRV_PCM_STREAM_PLAYBACK) { - /* bit stream is MSB first with no delay */ - /* DSP_B mode */ - mcasp_set_reg(mcasp, DAVINCI_MCASP_TXTDM_REG, mask); - mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, busel | TXORD); - - if ((mcasp->tdm_slots >= 2) && (mcasp->tdm_slots <= 32)) - mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, - FSXMOD(mcasp->tdm_slots), FSXMOD(0x1FF)); - else - printk(KERN_ERR "playback tdm slot %d not supported\n", - mcasp->tdm_slots); - } else { - /* bit stream is MSB first with no delay */ - /* DSP_B mode */ - mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, busel | RXORD); - mcasp_set_reg(mcasp, DAVINCI_MCASP_RXTDM_REG, mask); - - if ((mcasp->tdm_slots >= 2) && (mcasp->tdm_slots <= 32)) - mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, - FSRMOD(mcasp->tdm_slots), FSRMOD(0x1FF)); - else - printk(KERN_ERR "capture tdm slot %d not supported\n", - mcasp->tdm_slots); - } + mcasp_set_reg(mcasp, DAVINCI_MCASP_TXTDM_REG, mask); + mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, busel | TXORD); + mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, + FSXMOD(mcasp->tdm_slots), FSXMOD(0x1FF)); + + mcasp_set_reg(mcasp, DAVINCI_MCASP_RXTDM_REG, mask); + mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, busel | RXORD); + mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, + FSRMOD(mcasp->tdm_slots), FSRMOD(0x1FF)); + + return 0; } /* S/PDIF */ -static void davinci_hw_dit_param(struct davinci_mcasp *mcasp) +static int mcasp_dit_hw_param(struct davinci_mcasp *mcasp) { /* Set the TX format : 24 bit right rotation, 32 bit slot, Pad 0 and LSB first */ @@ -589,6 +586,8 @@ static void davinci_hw_dit_param(struct davinci_mcasp *mcasp) /* Enable the DIT */ mcasp_set_bits(mcasp, DAVINCI_MCASP_TXDITCTL_REG, DITEN); + + return 0; } static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, @@ -605,13 +604,14 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, u8 slots = mcasp->tdm_slots; u8 active_serializers; int channels; + int ret; struct snd_interval *pcm_channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); channels = pcm_channels->min; active_serializers = (channels + slots - 1) / slots; - if (davinci_hw_common_param(mcasp, substream->stream, channels) == -EINVAL) + if (mcasp_common_hw_param(mcasp, substream->stream, channels) == -EINVAL) return -EINVAL; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) fifo_level = mcasp->txnumevt * active_serializers; @@ -619,9 +619,12 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, fifo_level = mcasp->rxnumevt * active_serializers; if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE) - davinci_hw_dit_param(mcasp); + ret = mcasp_dit_hw_param(mcasp); else - davinci_hw_param(mcasp, substream->stream); + ret = mcasp_i2s_hw_param(mcasp, substream->stream); + + if (ret) + return ret; switch (params_format(params)) { case SNDRV_PCM_FORMAT_U8: @@ -678,19 +681,9 @@ static int davinci_mcasp_trigger(struct snd_pcm_substream *substream, case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - ret = pm_runtime_get_sync(mcasp->dev); - if (IS_ERR_VALUE(ret)) - dev_err(mcasp->dev, "pm_runtime_get_sync() failed\n"); davinci_mcasp_start(mcasp, substream->stream); break; - case SNDRV_PCM_TRIGGER_SUSPEND: - davinci_mcasp_stop(mcasp, substream->stream); - ret = pm_runtime_put_sync(mcasp->dev); - if (IS_ERR_VALUE(ret)) - dev_err(mcasp->dev, "pm_runtime_put_sync() failed\n"); - break; - case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: davinci_mcasp_stop(mcasp, substream->stream); diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c index d0c72ed261e..c84026c9913 100644 --- a/sound/soc/fsl/fsl_esai.c +++ b/sound/soc/fsl/fsl_esai.c @@ -326,7 +326,7 @@ static int fsl_esai_set_dai_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask, regmap_update_bits(esai_priv->regmap, REG_ESAI_TSMA, ESAI_xSMA_xS_MASK, ESAI_xSMA_xS(tx_mask)); regmap_update_bits(esai_priv->regmap, REG_ESAI_TSMB, - ESAI_xSMA_xS_MASK, ESAI_xSMB_xS(tx_mask)); + ESAI_xSMB_xS_MASK, ESAI_xSMB_xS(tx_mask)); regmap_update_bits(esai_priv->regmap, REG_ESAI_RCCR, ESAI_xCCR_xDC_MASK, ESAI_xCCR_xDC(slots)); @@ -334,7 +334,7 @@ static int fsl_esai_set_dai_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask, regmap_update_bits(esai_priv->regmap, REG_ESAI_RSMA, ESAI_xSMA_xS_MASK, ESAI_xSMA_xS(rx_mask)); regmap_update_bits(esai_priv->regmap, REG_ESAI_RSMB, - ESAI_xSMA_xS_MASK, ESAI_xSMB_xS(rx_mask)); + ESAI_xSMB_xS_MASK, ESAI_xSMB_xS(rx_mask)); esai_priv->slot_width = slot_width; diff --git a/sound/soc/fsl/fsl_esai.h b/sound/soc/fsl/fsl_esai.h index 9c9f957fcae..75e14033e8d 100644 --- a/sound/soc/fsl/fsl_esai.h +++ b/sound/soc/fsl/fsl_esai.h @@ -322,7 +322,7 @@ #define ESAI_xSMB_xS_SHIFT 0 #define ESAI_xSMB_xS_WIDTH 16 #define ESAI_xSMB_xS_MASK (((1 << ESAI_xSMB_xS_WIDTH) - 1) << ESAI_xSMB_xS_SHIFT) -#define ESAI_xSMB_xS(v) (((v) >> ESAI_xSMA_xS_WIDTH) & ESAI_xSMA_xS_MASK) +#define ESAI_xSMB_xS(v) (((v) >> ESAI_xSMA_xS_WIDTH) & ESAI_xSMB_xS_MASK) /* Port C Direction Register -- REG_ESAI_PRRC 0xF8 */ #define ESAI_PRRC_PDC_SHIFT 0 diff --git a/sound/soc/fsl/imx-mc13783.c b/sound/soc/fsl/imx-mc13783.c index 79cee782dbb..a2fd7321b5a 100644 --- a/sound/soc/fsl/imx-mc13783.c +++ b/sound/soc/fsl/imx-mc13783.c @@ -160,7 +160,6 @@ static struct platform_driver imx_mc13783_audio_driver = { .driver = { .name = "imx_mc13783", .owner = THIS_MODULE, - .pm = &snd_soc_pm_ops, }, .probe = imx_mc13783_probe, .remove = imx_mc13783_remove diff --git a/sound/soc/fsl/imx-sgtl5000.c b/sound/soc/fsl/imx-sgtl5000.c index f2beae78969..1cb22dd034e 100644 --- a/sound/soc/fsl/imx-sgtl5000.c +++ b/sound/soc/fsl/imx-sgtl5000.c @@ -33,8 +33,7 @@ struct imx_sgtl5000_data { static int imx_sgtl5000_dai_init(struct snd_soc_pcm_runtime *rtd) { - struct imx_sgtl5000_data *data = container_of(rtd->card, - struct imx_sgtl5000_data, card); + struct imx_sgtl5000_data *data = snd_soc_card_get_drvdata(rtd->card); struct device *dev = rtd->card->dev; int ret; @@ -159,13 +158,15 @@ static int imx_sgtl5000_probe(struct platform_device *pdev) data->card.dapm_widgets = imx_sgtl5000_dapm_widgets; data->card.num_dapm_widgets = ARRAY_SIZE(imx_sgtl5000_dapm_widgets); + platform_set_drvdata(pdev, &data->card); + snd_soc_card_set_drvdata(&data->card, data); + ret = devm_snd_soc_register_card(&pdev->dev, &data->card); if (ret) { dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret); goto fail; } - platform_set_drvdata(pdev, data); of_node_put(ssi_np); of_node_put(codec_np); @@ -184,7 +185,8 @@ fail: static int imx_sgtl5000_remove(struct platform_device *pdev) { - struct imx_sgtl5000_data *data = platform_get_drvdata(pdev); + struct snd_soc_card *card = platform_get_drvdata(pdev); + struct imx_sgtl5000_data *data = snd_soc_card_get_drvdata(card); clk_put(data->codec_clk); diff --git a/sound/soc/fsl/imx-wm8962.c b/sound/soc/fsl/imx-wm8962.c index 3fd76bc391d..3a3d17ce6ba 100644 --- a/sound/soc/fsl/imx-wm8962.c +++ b/sound/soc/fsl/imx-wm8962.c @@ -71,7 +71,7 @@ static int imx_wm8962_set_bias_level(struct snd_soc_card *card, { struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai; struct imx_priv *priv = &card_priv; - struct imx_wm8962_data *data = platform_get_drvdata(priv->pdev); + struct imx_wm8962_data *data = snd_soc_card_get_drvdata(card); struct device *dev = &priv->pdev->dev; unsigned int pll_out; int ret; @@ -137,7 +137,7 @@ static int imx_wm8962_late_probe(struct snd_soc_card *card) { struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai; struct imx_priv *priv = &card_priv; - struct imx_wm8962_data *data = platform_get_drvdata(priv->pdev); + struct imx_wm8962_data *data = snd_soc_card_get_drvdata(card); struct device *dev = &priv->pdev->dev; int ret; @@ -264,13 +264,15 @@ static int imx_wm8962_probe(struct platform_device *pdev) data->card.late_probe = imx_wm8962_late_probe; data->card.set_bias_level = imx_wm8962_set_bias_level; + platform_set_drvdata(pdev, &data->card); + snd_soc_card_set_drvdata(&data->card, data); + ret = devm_snd_soc_register_card(&pdev->dev, &data->card); if (ret) { dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret); goto clk_fail; } - platform_set_drvdata(pdev, data); of_node_put(ssi_np); of_node_put(codec_np); @@ -289,7 +291,8 @@ fail: static int imx_wm8962_remove(struct platform_device *pdev) { - struct imx_wm8962_data *data = platform_get_drvdata(pdev); + struct snd_soc_card *card = platform_get_drvdata(pdev); + struct imx_wm8962_data *data = snd_soc_card_get_drvdata(card); if (!IS_ERR(data->codec_clk)) clk_disable_unprepare(data->codec_clk); diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig index 454f41cfc82..35075740039 100644 --- a/sound/soc/samsung/Kconfig +++ b/sound/soc/samsung/Kconfig @@ -59,7 +59,7 @@ config SND_SOC_SAMSUNG_JIVE_WM8750 select SND_SOC_WM8750 select SND_S3C2412_SOC_I2S help - Sat Y if you want to add support for SoC audio on the Jive. + Say Y if you want to add support for SoC audio on the Jive. config SND_SOC_SAMSUNG_SMDK_WM8580 tristate "SoC I2S Audio support for WM8580 on SMDK" @@ -145,11 +145,11 @@ config SND_SOC_SAMSUNG_RX1950_UDA1380 config SND_SOC_SAMSUNG_SMDK_WM9713 tristate "SoC AC97 Audio support for SMDK with WM9713" - depends on SND_SOC_SAMSUNG && (MACH_SMDK6410 || MACH_SMDKC100 || MACH_SMDKV210 || MACH_SMDKC110 || MACH_SMDKV310 || MACH_SMDKC210) + depends on SND_SOC_SAMSUNG && (MACH_SMDK6410 || MACH_SMDKC100 || MACH_SMDKV210 || MACH_SMDKC110) select SND_SOC_WM9713 select SND_SAMSUNG_AC97 help - Sat Y if you want to add support for SoC audio on the SMDK. + Say Y if you want to add support for SoC audio on the SMDK. config SND_SOC_SMARTQ tristate "SoC I2S Audio support for SmartQ board" diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index dc8ff13187f..b9dc6acbba8 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -1218,7 +1218,7 @@ int dapm_regulator_event(struct snd_soc_dapm_widget *w, ret = regulator_allow_bypass(w->regulator, false); if (ret != 0) dev_warn(w->dapm->dev, - "ASoC: Failed to bypass %s: %d\n", + "ASoC: Failed to unbypass %s: %d\n", w->name, ret); } @@ -1228,7 +1228,7 @@ int dapm_regulator_event(struct snd_soc_dapm_widget *w, ret = regulator_allow_bypass(w->regulator, true); if (ret != 0) dev_warn(w->dapm->dev, - "ASoC: Failed to unbypass %s: %d\n", + "ASoC: Failed to bypass %s: %d\n", w->name, ret); } @@ -3210,15 +3210,11 @@ int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol, struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); const char *pin = (const char *)kcontrol->private_value; - mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); - if (ucontrol->value.integer.value[0]) snd_soc_dapm_enable_pin(&card->dapm, pin); else snd_soc_dapm_disable_pin(&card->dapm, pin); - mutex_unlock(&card->dapm_mutex); - snd_soc_dapm_sync(&card->dapm); return 0; } @@ -3248,7 +3244,7 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, ret = regulator_allow_bypass(w->regulator, true); if (ret != 0) dev_warn(w->dapm->dev, - "ASoC: Failed to unbypass %s: %d\n", + "ASoC: Failed to bypass %s: %d\n", w->name, ret); } break; @@ -3767,23 +3763,52 @@ void snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream, } /** + * snd_soc_dapm_enable_pin_unlocked - enable pin. + * @dapm: DAPM context + * @pin: pin name + * + * Enables input/output pin and its parents or children widgets iff there is + * a valid audio route and active audio stream. + * + * Requires external locking. + * + * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to + * do any widget power switching. + */ +int snd_soc_dapm_enable_pin_unlocked(struct snd_soc_dapm_context *dapm, + const char *pin) +{ + return snd_soc_dapm_set_pin(dapm, pin, 1); +} +EXPORT_SYMBOL_GPL(snd_soc_dapm_enable_pin_unlocked); + +/** * snd_soc_dapm_enable_pin - enable pin. * @dapm: DAPM context * @pin: pin name * * Enables input/output pin and its parents or children widgets iff there is * a valid audio route and active audio stream. + * * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to * do any widget power switching. */ int snd_soc_dapm_enable_pin(struct snd_soc_dapm_context *dapm, const char *pin) { - return snd_soc_dapm_set_pin(dapm, pin, 1); + int ret; + + mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); + + ret = snd_soc_dapm_set_pin(dapm, pin, 1); + + mutex_unlock(&dapm->card->dapm_mutex); + + return ret; } EXPORT_SYMBOL_GPL(snd_soc_dapm_enable_pin); /** - * snd_soc_dapm_force_enable_pin - force a pin to be enabled + * snd_soc_dapm_force_enable_pin_unlocked - force a pin to be enabled * @dapm: DAPM context * @pin: pin name * @@ -3791,11 +3816,13 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_enable_pin); * intended for use with microphone bias supplies used in microphone * jack detection. * + * Requires external locking. + * * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to * do any widget power switching. */ -int snd_soc_dapm_force_enable_pin(struct snd_soc_dapm_context *dapm, - const char *pin) +int snd_soc_dapm_force_enable_pin_unlocked(struct snd_soc_dapm_context *dapm, + const char *pin) { struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true); @@ -3811,25 +3838,103 @@ int snd_soc_dapm_force_enable_pin(struct snd_soc_dapm_context *dapm, return 0; } +EXPORT_SYMBOL_GPL(snd_soc_dapm_force_enable_pin_unlocked); + +/** + * snd_soc_dapm_force_enable_pin - force a pin to be enabled + * @dapm: DAPM context + * @pin: pin name + * + * Enables input/output pin regardless of any other state. This is + * intended for use with microphone bias supplies used in microphone + * jack detection. + * + * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to + * do any widget power switching. + */ +int snd_soc_dapm_force_enable_pin(struct snd_soc_dapm_context *dapm, + const char *pin) +{ + int ret; + + mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); + + ret = snd_soc_dapm_force_enable_pin_unlocked(dapm, pin); + + mutex_unlock(&dapm->card->dapm_mutex); + + return ret; +} EXPORT_SYMBOL_GPL(snd_soc_dapm_force_enable_pin); /** + * snd_soc_dapm_disable_pin_unlocked - disable pin. + * @dapm: DAPM context + * @pin: pin name + * + * Disables input/output pin and its parents or children widgets. + * + * Requires external locking. + * + * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to + * do any widget power switching. + */ +int snd_soc_dapm_disable_pin_unlocked(struct snd_soc_dapm_context *dapm, + const char *pin) +{ + return snd_soc_dapm_set_pin(dapm, pin, 0); +} +EXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin_unlocked); + +/** * snd_soc_dapm_disable_pin - disable pin. * @dapm: DAPM context * @pin: pin name * * Disables input/output pin and its parents or children widgets. + * * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to * do any widget power switching. */ int snd_soc_dapm_disable_pin(struct snd_soc_dapm_context *dapm, const char *pin) { - return snd_soc_dapm_set_pin(dapm, pin, 0); + int ret; + + mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); + + ret = snd_soc_dapm_set_pin(dapm, pin, 0); + + mutex_unlock(&dapm->card->dapm_mutex); + + return ret; } EXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin); /** + * snd_soc_dapm_nc_pin_unlocked - permanently disable pin. + * @dapm: DAPM context + * @pin: pin name + * + * Marks the specified pin as being not connected, disabling it along + * any parent or child widgets. At present this is identical to + * snd_soc_dapm_disable_pin() but in future it will be extended to do + * additional things such as disabling controls which only affect + * paths through the pin. + * + * Requires external locking. + * + * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to + * do any widget power switching. + */ +int snd_soc_dapm_nc_pin_unlocked(struct snd_soc_dapm_context *dapm, + const char *pin) +{ + return snd_soc_dapm_set_pin(dapm, pin, 0); +} +EXPORT_SYMBOL_GPL(snd_soc_dapm_nc_pin_unlocked); + +/** * snd_soc_dapm_nc_pin - permanently disable pin. * @dapm: DAPM context * @pin: pin name @@ -3845,7 +3950,15 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin); */ int snd_soc_dapm_nc_pin(struct snd_soc_dapm_context *dapm, const char *pin) { - return snd_soc_dapm_set_pin(dapm, pin, 0); + int ret; + + mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); + + ret = snd_soc_dapm_set_pin(dapm, pin, 0); + + mutex_unlock(&dapm->card->dapm_mutex); + + return ret; } EXPORT_SYMBOL_GPL(snd_soc_dapm_nc_pin); diff --git a/sound/soc/txx9/txx9aclc-ac97.c b/sound/soc/txx9/txx9aclc-ac97.c index e0305a14856..9edd68db9f4 100644 --- a/sound/soc/txx9/txx9aclc-ac97.c +++ b/sound/soc/txx9/txx9aclc-ac97.c @@ -183,14 +183,16 @@ static int txx9aclc_ac97_dev_probe(struct platform_device *pdev) irq = platform_get_irq(pdev, 0); if (irq < 0) return irq; + + drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL); + if (!drvdata) + return -ENOMEM; + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); drvdata->base = devm_ioremap_resource(&pdev->dev, r); if (IS_ERR(drvdata->base)) return PTR_ERR(drvdata->base); - drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL); - if (!drvdata) - return -ENOMEM; platform_set_drvdata(pdev, drvdata); drvdata->physbase = r->start; if (sizeof(drvdata->physbase) > sizeof(r->start) && diff --git a/sound/usb/mixer_maps.c b/sound/usb/mixer_maps.c index 32af6b741ef..d1d72ff5034 100644 --- a/sound/usb/mixer_maps.c +++ b/sound/usb/mixer_maps.c @@ -328,6 +328,11 @@ static struct usbmix_name_map gamecom780_map[] = { {} }; +static const struct usbmix_name_map kef_x300a_map[] = { + { 10, NULL }, /* firmware locks up (?) when we try to access this FU */ + { 0 } +}; + /* * Control map entries */ @@ -419,6 +424,10 @@ static struct usbmix_ctl_map usbmix_ctl_maps[] = { .id = USB_ID(0x200c, 0x1018), .map = ebox44_map, }, + { + .id = USB_ID(0x27ac, 0x1000), + .map = kef_x300a_map, + }, { 0 } /* terminator */ }; diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 3c53ec268fb..02f985f3a39 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -113,14 +113,16 @@ static int report__add_mem_hist_entry(struct perf_tool *tool, struct addr_locati if (!he) return -ENOMEM; - err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr); - if (err) - goto out; + if (ui__has_annotation()) { + err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr); + if (err) + goto out; - mx = he->mem_info; - err = addr_map_symbol__inc_samples(&mx->daddr, evsel->idx); - if (err) - goto out; + mx = he->mem_info; + err = addr_map_symbol__inc_samples(&mx->daddr, evsel->idx); + if (err) + goto out; + } evsel->hists.stats.total_period += cost; hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE); @@ -164,14 +166,18 @@ static int report__add_branch_hist_entry(struct perf_tool *tool, struct addr_loc he = __hists__add_entry(&evsel->hists, al, parent, &bi[i], NULL, 1, 1, 0); if (he) { - bx = he->branch_info; - err = addr_map_symbol__inc_samples(&bx->from, evsel->idx); - if (err) - goto out; - - err = addr_map_symbol__inc_samples(&bx->to, evsel->idx); - if (err) - goto out; + if (ui__has_annotation()) { + bx = he->branch_info; + err = addr_map_symbol__inc_samples(&bx->from, + evsel->idx); + if (err) + goto out; + + err = addr_map_symbol__inc_samples(&bx->to, + evsel->idx); + if (err) + goto out; + } evsel->hists.stats.total_period += 1; hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE); @@ -205,7 +211,9 @@ static int report__add_hist_entry(struct perf_tool *tool, struct perf_evsel *evs if (err) goto out; - err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr); + if (ui__has_annotation()) + err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr); + evsel->hists.stats.total_period += sample->period; hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE); out: diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 76cd510d34d..5f989a7d8bc 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -176,7 +176,7 @@ static void perf_top__record_precise_ip(struct perf_top *top, { struct annotation *notes; struct symbol *sym; - int err; + int err = 0; if (he == NULL || he->ms.sym == NULL || ((top->sym_filter_entry == NULL || @@ -190,7 +190,9 @@ static void perf_top__record_precise_ip(struct perf_top *top, return; ip = he->ms.map->map_ip(he->ms.map, ip); - err = hist_entry__inc_addr_samples(he, counter, ip); + + if (ui__has_annotation()) + err = hist_entry__inc_addr_samples(he, counter, ip); pthread_mutex_unlock(¬es->lock); diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 896f27047ed..6aa6fb6f7bd 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -37,6 +37,10 @@ # define MADV_UNMERGEABLE 13 #endif +#ifndef EFD_SEMAPHORE +# define EFD_SEMAPHORE 1 +#endif + struct tp_field { int offset; union { @@ -279,6 +283,11 @@ static size_t syscall_arg__scnprintf_strarray(char *bf, size_t size, #define SCA_STRARRAY syscall_arg__scnprintf_strarray +#if defined(__i386__) || defined(__x86_64__) +/* + * FIXME: Make this available to all arches as soon as the ioctl beautifier + * gets rewritten to support all arches. + */ static size_t syscall_arg__scnprintf_strhexarray(char *bf, size_t size, struct syscall_arg *arg) { @@ -286,6 +295,7 @@ static size_t syscall_arg__scnprintf_strhexarray(char *bf, size_t size, } #define SCA_STRHEXARRAY syscall_arg__scnprintf_strhexarray +#endif /* defined(__i386__) || defined(__x86_64__) */ static size_t syscall_arg__scnprintf_fd(char *bf, size_t size, struct syscall_arg *arg); @@ -839,6 +849,10 @@ static size_t syscall_arg__scnprintf_signum(char *bf, size_t size, struct syscal #define SCA_SIGNUM syscall_arg__scnprintf_signum +#if defined(__i386__) || defined(__x86_64__) +/* + * FIXME: Make this available to all arches. + */ #define TCGETS 0x5401 static const char *tioctls[] = { @@ -860,6 +874,7 @@ static const char *tioctls[] = { }; static DEFINE_STRARRAY_OFFSET(tioctls, 0x5401); +#endif /* defined(__i386__) || defined(__x86_64__) */ #define STRARRAY(arg, name, array) \ .arg_scnprintf = { [arg] = SCA_STRARRAY, }, \ @@ -941,9 +956,16 @@ static struct syscall_fmt { { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), }, { .name = "ioctl", .errmsg = true, .arg_scnprintf = { [0] = SCA_FD, /* fd */ +#if defined(__i386__) || defined(__x86_64__) +/* + * FIXME: Make this available to all arches. + */ [1] = SCA_STRHEXARRAY, /* cmd */ [2] = SCA_HEX, /* arg */ }, .arg_parm = { [1] = &strarray__tioctls, /* cmd */ }, }, +#else + [2] = SCA_HEX, /* arg */ }, }, +#endif { .name = "kill", .errmsg = true, .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, }, { .name = "linkat", .errmsg = true, diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile index c48d4495817..0331ea2701a 100644 --- a/tools/perf/config/Makefile +++ b/tools/perf/config/Makefile @@ -478,7 +478,7 @@ else endif ifeq ($(feature-libbfd), 1) - EXTLIBS += -lbfd + EXTLIBS += -lbfd -lz -liberty endif ifdef NO_DEMANGLE diff --git a/tools/perf/config/feature-checks/Makefile b/tools/perf/config/feature-checks/Makefile index 12e551346fa..523b7bc1055 100644 --- a/tools/perf/config/feature-checks/Makefile +++ b/tools/perf/config/feature-checks/Makefile @@ -121,7 +121,7 @@ test-libpython-version.bin: $(BUILD) $(FLAGS_PYTHON_EMBED) test-libbfd.bin: - $(BUILD) -DPACKAGE='"perf"' -lbfd -ldl + $(BUILD) -DPACKAGE='"perf"' -lbfd -lz -liberty -ldl test-liberty.bin: $(CC) -o $(OUTPUT)$@ test-libbfd.c -DPACKAGE='"perf"' -lbfd -ldl -liberty diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 469eb679fb9..3aa555ff9d8 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -8,6 +8,8 @@ */ #include "util.h" +#include "ui/ui.h" +#include "sort.h" #include "build-id.h" #include "color.h" #include "cache.h" @@ -489,7 +491,7 @@ static int symbol__inc_addr_samples(struct symbol *sym, struct map *map, { struct annotation *notes; - if (sym == NULL || use_browser != 1 || !sort__has_sym) + if (sym == NULL) return 0; notes = symbol__annotation(sym); @@ -1399,3 +1401,8 @@ int hist_entry__annotate(struct hist_entry *he, size_t privsize) { return symbol__annotate(he->ms.sym, he->ms.map, privsize); } + +bool ui__has_annotation(void) +{ + return use_browser == 1 && sort__has_sym; +} diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index b2aef59d6bb..56ad4f5287d 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -151,6 +151,8 @@ void symbol__annotate_zero_histogram(struct symbol *sym, int evidx); void symbol__annotate_decay_histogram(struct symbol *sym, int evidx); void disasm__purge(struct list_head *head); +bool ui__has_annotation(void); + int symbol__tty_annotate(struct symbol *sym, struct map *map, struct perf_evsel *evsel, bool print_lines, bool full_paths, int min_pcnt, int max_lines); diff --git a/tools/perf/util/include/linux/bitops.h b/tools/perf/util/include/linux/bitops.h index 45cf10a562b..dadfa7e5428 100644 --- a/tools/perf/util/include/linux/bitops.h +++ b/tools/perf/util/include/linux/bitops.h @@ -87,13 +87,15 @@ static __always_inline unsigned long __ffs(unsigned long word) return num; } +typedef const unsigned long __attribute__((__may_alias__)) long_alias_t; + /* * Find the first set bit in a memory region. */ static inline unsigned long find_first_bit(const unsigned long *addr, unsigned long size) { - const unsigned long *p = addr; + long_alias_t *p = (long_alias_t *) addr; unsigned long result = 0; unsigned long tmp; diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index d248fca6d7e..1e15df10a88 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c @@ -1091,12 +1091,12 @@ int is_valid_tracepoint(const char *event_string) static bool is_event_supported(u8 type, unsigned config) { bool ret = true; + int open_return; struct perf_evsel *evsel; struct perf_event_attr attr = { .type = type, .config = config, .disabled = 1, - .exclude_kernel = 1, }; struct { struct thread_map map; @@ -1108,7 +1108,20 @@ static bool is_event_supported(u8 type, unsigned config) evsel = perf_evsel__new(&attr); if (evsel) { - ret = perf_evsel__open(evsel, NULL, &tmap.map) >= 0; + open_return = perf_evsel__open(evsel, NULL, &tmap.map); + ret = open_return >= 0; + + if (open_return == -EACCES) { + /* + * This happens if the paranoid value + * /proc/sys/kernel/perf_event_paranoid is set to 2 + * Re-run with exclude_kernel set; we don't do that + * by default as some ARM machines do not support it. + * + */ + evsel->attr.exclude_kernel = 1; + ret = perf_evsel__open(evsel, NULL, &tmap.map) >= 0; + } perf_evsel__delete(evsel); } diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index a8a9b6cd93a..d8b048c20cd 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -336,8 +336,8 @@ static int add_exec_to_probe_trace_events(struct probe_trace_event *tevs, return ret; for (i = 0; i < ntevs && ret >= 0; i++) { + /* point.address is the addres of point.symbol + point.offset */ offset = tevs[i].point.address - stext; - offset += tevs[i].point.offset; tevs[i].point.offset = 0; zfree(&tevs[i].point.symbol); ret = e_snprintf(buf, 32, "0x%lx", offset); diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 0b39a48e511..5da6ce74c67 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -1008,6 +1008,12 @@ static int perf_session__process_user_event(struct perf_session *session, union if (err == 0) perf_session__set_id_hdr_size(session); return err; + case PERF_RECORD_HEADER_EVENT_TYPE: + /* + * Depreceated, but we need to handle it for sake + * of old data files create in pipe mode. + */ + return 0; case PERF_RECORD_HEADER_TRACING_DATA: /* setup for reading amidst mmap */ lseek(fd, file_offset, SEEK_SET); diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index a9d758a3b37..e89afc097d8 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -1336,6 +1336,8 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter) if (syms_ss && runtime_ss) break; + } else { + symsrc__destroy(ss); } } |