Merge remote-tracking branch 'char-misc/char-misc-next'
authorStephen Rothwell <sfr@canb.auug.org.au>
Tue, 13 Sep 2016 02:49:15 +0000 (12:49 +1000)
committerStephen Rothwell <sfr@canb.auug.org.au>
Tue, 13 Sep 2016 02:49:15 +0000 (12:49 +1000)
119 files changed:
CREDITS
Documentation/ABI/testing/sysfs-class-mic.txt
Documentation/ABI/testing/sysfs-i2c-bmp085 [deleted file]
Documentation/devicetree/bindings/nvmem/rockchip-efuse.txt
Documentation/vme_api.txt
MAINTAINERS
arch/arm/common/bL_switcher_dummy_if.c
arch/blackfin/mach-bf561/coreb.c
arch/um/drivers/harddog_kern.c
drivers/bluetooth/hci_vhci.c
drivers/char/bfin-otp.c
drivers/char/mem.c
drivers/char/mwave/3780i.c
drivers/char/mwave/3780i.h
drivers/char/mwave/mwavedd.c
drivers/char/mwave/mwavedd.h
drivers/char/mwave/smapi.c
drivers/char/mwave/smapi.h
drivers/char/mwave/tp3780i.c
drivers/char/ppdev.c
drivers/char/snsc.c
drivers/char/xillybus/xillybus_core.c
drivers/fpga/Kconfig
drivers/hid/uhid.c
drivers/hv/channel.c
drivers/hv/channel_mgmt.c
drivers/hv/connection.c
drivers/hv/hv.c
drivers/hv/hv_balloon.c
drivers/hv/hv_fcopy.c
drivers/hv/hv_kvp.c
drivers/hv/hv_snapshot.c
drivers/hv/hv_util.c
drivers/hv/hv_utils_transport.c
drivers/hv/hv_utils_transport.h
drivers/hv/hyperv_vmbus.h
drivers/hv/ring_buffer.c
drivers/hv/vmbus_drv.c
drivers/hwtracing/coresight/coresight-etb10.c
drivers/hwtracing/coresight/coresight-etm-perf.c
drivers/hwtracing/coresight/coresight-etm-perf.h
drivers/hwtracing/coresight/coresight-etm.h
drivers/hwtracing/coresight/coresight-etm3x-sysfs.c
drivers/hwtracing/coresight/coresight-etm3x.c
drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
drivers/hwtracing/coresight/coresight-etm4x.c
drivers/hwtracing/coresight/coresight-etm4x.h
drivers/hwtracing/coresight/coresight-funnel.c
drivers/hwtracing/coresight/coresight-priv.h
drivers/hwtracing/coresight/coresight-replicator-qcom.c
drivers/hwtracing/coresight/coresight-replicator.c
drivers/hwtracing/coresight/coresight-stm.c
drivers/hwtracing/coresight/coresight-tmc-etf.c
drivers/hwtracing/coresight/coresight-tmc-etr.c
drivers/hwtracing/coresight/coresight-tmc.c
drivers/hwtracing/coresight/coresight-tmc.h
drivers/hwtracing/coresight/coresight-tpiu.c
drivers/hwtracing/coresight/coresight.c
drivers/hwtracing/coresight/of_coresight.c
drivers/iio/pressure/Kconfig
drivers/input/misc/uinput.c
drivers/lightnvm/core.c
drivers/mcb/Kconfig
drivers/mcb/Makefile
drivers/mcb/mcb-core.c
drivers/mcb/mcb-internal.h
drivers/mcb/mcb-lpc.c [new file with mode: 0644]
drivers/mcb/mcb-parse.c
drivers/memory/of_memory.c
drivers/misc/Kconfig
drivers/misc/Makefile
drivers/misc/bmp085-i2c.c [deleted file]
drivers/misc/bmp085-spi.c [deleted file]
drivers/misc/bmp085.c [deleted file]
drivers/misc/bmp085.h [deleted file]
drivers/misc/genwqe/card_base.c
drivers/misc/mei/amthif.c
drivers/misc/mei/bus.c
drivers/misc/mei/client.c
drivers/misc/mei/client.h
drivers/misc/mei/hbm.c
drivers/misc/mei/hw-me-regs.h
drivers/misc/mei/hw-me.c
drivers/misc/mei/hw-txe.c
drivers/misc/mei/interrupt.c
drivers/misc/mei/main.c
drivers/misc/mei/mei_dev.h
drivers/misc/mei/pci-me.c
drivers/misc/mei/pci-txe.c
drivers/misc/mic/scif/scif_dma.c
drivers/misc/mic/scif/scif_mmap.c
drivers/misc/pch_phub.c
drivers/misc/vmw_vmci/vmci_host.c
drivers/nvmem/rockchip-efuse.c
drivers/s390/char/sclp_ctl.c
drivers/tty/serial/Kconfig
drivers/tty/serial/pch_uart.c
drivers/uio/uio_dmem_genirq.c
drivers/vhost/test.c
drivers/vme/bridges/Kconfig
drivers/vme/bridges/Makefile
drivers/vme/bridges/vme_ca91cx42.c
drivers/vme/bridges/vme_ca91cx42.h
drivers/vme/bridges/vme_fake.c [new file with mode: 0644]
drivers/vme/bridges/vme_tsi148.c
drivers/vme/bridges/vme_tsi148.h
drivers/vme/vme.c
drivers/vme/vme_bridge.h
drivers/w1/slaves/w1_therm.c
drivers/w1/w1.c
include/linux/coresight.h
include/linux/hyperv.h
include/linux/mcb.h
include/linux/miscdevice.h
include/linux/vme.h
scripts/checkkconfigsymbols.py
scripts/ver_linux
tools/hv/hv_kvp_daemon.c
tools/hv/hv_vss_daemon.c

diff --git a/CREDITS b/CREDITS
index 1b48cd74bf5d97d7260e17bd174d8f56940a3347..69873aaa2f92b9f5553eeef0570991f5cea4a97d 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -1948,6 +1948,11 @@ E: kraxel@bytesex.org
 E: kraxel@suse.de
 D: video4linux, bttv, vesafb, some scsi, misc fixes
 
+N: Hans J. Koch
+D: USERSPACE I/O, MAX6650
+D: Hans passed away in June 2016, and will be greatly missed.
+W: https://lwn.net/Articles/691000/
+
 N: Harald Koenig
 E: koenig@tat.physik.uni-tuebingen.de
 D: XFree86 (S3), DCF77, some kernel hacks and fixes
index d45eed2bf12863b782103a4f16ed6199675c0660..6ef68260317975d0daf1b62c2070430fef1ba91d 100644 (file)
@@ -153,7 +153,7 @@ Description:
 
 What:          /sys/class/mic/mic(x)/heartbeat_enable
 Date:          March 2015
-KernelVersion: 3.20
+KernelVersion: 4.4
 Contact:       Ashutosh Dixit <ashutosh.dixit@intel.com>
 Description:
                The MIC drivers detect and inform user space about card crashes
diff --git a/Documentation/ABI/testing/sysfs-i2c-bmp085 b/Documentation/ABI/testing/sysfs-i2c-bmp085
deleted file mode 100644 (file)
index 585962a..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-What:          /sys/bus/i2c/devices/<busnum>-<devaddr>/pressure0_input
-Date:          June 2010
-Contact:       Christoph Mair <christoph.mair@gmail.com>
-Description:   Start a pressure measurement and read the result. Values
-               represent the ambient air pressure in pascal (0.01 millibar).
-
-               Reading: returns the current air pressure.
-
-
-What:          /sys/bus/i2c/devices/<busnum>-<devaddr>/temp0_input
-Date:          June 2010
-Contact:       Christoph Mair <christoph.mair@gmail.com>
-Description:   Measure the ambient temperature. The returned value represents
-               the ambient temperature in units of 0.1 degree celsius.
-
-               Reading: returns the current temperature.
-
-
-What:          /sys/bus/i2c/devices/<busnum>-<devaddr>/oversampling
-Date:          June 2010
-Contact:       Christoph Mair <christoph.mair@gmail.com>
-Description:   Tell the bmp085 to use more samples to calculate a pressure
-               value. When writing to this file the chip will use 2^x samples
-               to calculate the next pressure value with x being the value
-               written. Using this feature will decrease RMS noise and
-               increase the measurement time.
-
-               Reading: returns the current oversampling setting.
-
-               Writing: sets a new oversampling setting.
-               Accepted values: 0..3.
index 8f86ab3b10468f99f91c43cfe4ca7e479fd9f010..94aeeeabadd5309b809e888605ff5816f8f51df3 100644 (file)
@@ -1,11 +1,20 @@
 = Rockchip eFuse device tree bindings =
 
 Required properties:
-- compatible: Should be "rockchip,rockchip-efuse"
+- compatible: Should be one of the following.
+  - "rockchip,rk3066a-efuse" - for RK3066a SoCs.
+  - "rockchip,rk3188-efuse" - for RK3188 SoCs.
+  - "rockchip,rk3288-efuse" - for RK3288 SoCs.
+  - "rockchip,rk3399-efuse" - for RK3399 SoCs.
 - reg: Should contain the registers location and exact eFuse size
 - clocks: Should be the clock id of eFuse
 - clock-names: Should be "pclk_efuse"
 
+Deprecated properties:
+- compatible: "rockchip,rockchip-efuse"
+  Old efuse compatible value compatible to rk3066a, rk3188 and rk3288
+  efuses
+
 = Data cells =
 Are child nodes of eFuse, bindings of which as described in
 bindings/nvmem/nvmem.txt
@@ -13,7 +22,7 @@ bindings/nvmem/nvmem.txt
 Example:
 
        efuse: efuse@ffb40000 {
-               compatible = "rockchip,rockchip-efuse";
+               compatible = "rockchip,rk3288-efuse";
                reg = <0xffb40000 0x20>;
                #address-cells = <1>;
                #size-cells = <1>;
index ca5b82797f6c5c79c949a38cd7d7c19270035993..90006550f4858373fef6e4f1f2d5cf10d24340cd 100644 (file)
@@ -8,13 +8,14 @@ As with other subsystems within the Linux kernel, VME device drivers register
 with the VME subsystem, typically called from the devices init routine.  This is
 achieved via a call to the following function:
 
-       int vme_register_driver (struct vme_driver *driver);
+       int vme_register_driver (struct vme_driver *driver, unsigned int ndevs);
 
 If driver registration is successful this function returns zero, if an error
 occurred a negative error code will be returned.
 
 A pointer to a structure of type 'vme_driver' must be provided to the
-registration function. The structure is as follows:
+registration function. Along with ndevs, which is the number of devices your
+driver is able to support. The structure is as follows:
 
        struct vme_driver {
                struct list_head node;
@@ -32,8 +33,8 @@ At the minimum, the '.name', '.match' and '.probe' elements of this structure
 should be correctly set. The '.name' element is a pointer to a string holding
 the device driver's name.
 
-The '.match' function allows controlling the number of devices that need to
-be registered. The match function should return 1 if a device should be
+The '.match' function allows control over which VME devices should be registered
+with the driver. The match function should return 1 if a device should be
 probed and 0 otherwise. This example match function (from vme_user.c) limits
 the number of devices probed to one:
 
@@ -385,13 +386,13 @@ location monitor location. Each location monitor can monitor a number of
 adjacent locations:
 
        int vme_lm_attach(struct vme_resource *res, int num,
-               void (*callback)(int));
+               void (*callback)(void *));
 
        int vme_lm_detach(struct vme_resource *res, int num);
 
 The callback function is declared as follows.
 
-       void callback(int num);
+       void callback(void *data);
 
 
 Slot Detection
index 2c62ea5dce5d5e3e8e4b210726ac2f79a3cc1ffe..993f47292dbcf21172020011944588dd119780c8 100644 (file)
@@ -7500,9 +7500,8 @@ F:        Documentation/hwmon/max20751
 F:     drivers/hwmon/max20751.c
 
 MAX6650 HARDWARE MONITOR AND FAN CONTROLLER DRIVER
-M:     "Hans J. Koch" <hjk@hansjkoch.de>
 L:     linux-hwmon@vger.kernel.org
-S:     Maintained
+S:     Orphan
 F:     Documentation/hwmon/max6650
 F:     drivers/hwmon/max6650.c
 
@@ -12483,7 +12482,6 @@ F:      fs/hostfs/
 F:     fs/hppfs/
 
 USERSPACE I/O (UIO)
-M:     "Hans J. Koch" <hjk@hansjkoch.de>
 M:     Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 S:     Maintained
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc.git
index 3f47f1203c6b971f3df5ec9c7499c1c6bcc3f523..6053f64c3752c64034e80f5e811e645f5bb3794c 100644 (file)
@@ -56,16 +56,4 @@ static struct miscdevice bL_switcher_device = {
        "b.L_switcher",
        &bL_switcher_fops
 };
-
-static int __init bL_switcher_dummy_if_init(void)
-{
-       return misc_register(&bL_switcher_device);
-}
-
-static void __exit bL_switcher_dummy_if_exit(void)
-{
-       misc_deregister(&bL_switcher_device);
-}
-
-module_init(bL_switcher_dummy_if_init);
-module_exit(bL_switcher_dummy_if_exit);
+module_misc_device(bL_switcher_device);
index 78ecb50bafc8653049ee563118ae8e48cdad1c49..8a2543c654b3be9735c4d8919527193e9c33316b 100644 (file)
@@ -59,18 +59,7 @@ static struct miscdevice coreb_dev = {
        .name  = "coreb",
        .fops  = &coreb_fops,
 };
-
-static int __init bf561_coreb_init(void)
-{
-       return misc_register(&coreb_dev);
-}
-module_init(bf561_coreb_init);
-
-static void __exit bf561_coreb_exit(void)
-{
-       misc_deregister(&coreb_dev);
-}
-module_exit(bf561_coreb_exit);
+module_misc_device(coreb_dev);
 
 MODULE_AUTHOR("Bas Vermeulen <bvermeul@blackstar.xs4all.nl>");
 MODULE_DESCRIPTION("BF561 Core B Support");
index 2d0266d0254d5eef5477a7da2d5e9ea36378ca46..3282787bbcfbaa69fb735929438a7f189c63000e 100644 (file)
@@ -175,27 +175,4 @@ static struct miscdevice harddog_miscdev = {
        .name           = "watchdog",
        .fops           = &harddog_fops,
 };
-
-static char banner[] __initdata = KERN_INFO "UML Watchdog Timer\n";
-
-static int __init harddog_init(void)
-{
-       int ret;
-
-       ret = misc_register(&harddog_miscdev);
-
-       if (ret)
-               return ret;
-
-       printk(banner);
-
-       return 0;
-}
-
-static void __exit harddog_exit(void)
-{
-       misc_deregister(&harddog_miscdev);
-}
-
-module_init(harddog_init);
-module_exit(harddog_exit);
+module_misc_device(harddog_miscdev);
index 3ff229b2e7f3746880a2db4deec9141d7d297a56..c4a75a18dcae5e8d4d1d7778b356a4a4a17e0bf4 100644 (file)
@@ -377,21 +377,7 @@ static struct miscdevice vhci_miscdev = {
        .fops   = &vhci_fops,
        .minor  = VHCI_MINOR,
 };
-
-static int __init vhci_init(void)
-{
-       BT_INFO("Virtual HCI driver ver %s", VERSION);
-
-       return misc_register(&vhci_miscdev);
-}
-
-static void __exit vhci_exit(void)
-{
-       misc_deregister(&vhci_miscdev);
-}
-
-module_init(vhci_init);
-module_exit(vhci_exit);
+module_misc_device(vhci_miscdev);
 
 module_param(amp, bool, 0644);
 MODULE_PARM_DESC(amp, "Create AMP controller device");
index 44660f1c484932cc24421372558b5e8ed0049147..35d46da754d79d14e598d785118303ef7f852849 100644 (file)
@@ -230,45 +230,7 @@ static struct miscdevice bfin_otp_misc_device = {
        .name     = DRIVER_NAME,
        .fops     = &bfin_otp_fops,
 };
-
-/**
- *     bfin_otp_init - Initialize module
- *
- *     Registers the device and notifier handler. Actual device
- *     initialization is handled by bfin_otp_open().
- */
-static int __init bfin_otp_init(void)
-{
-       int ret;
-
-       stampit();
-
-       ret = misc_register(&bfin_otp_misc_device);
-       if (ret) {
-               pr_init(KERN_ERR PFX "unable to register a misc device\n");
-               return ret;
-       }
-
-       pr_init(KERN_INFO PFX "initialized\n");
-
-       return 0;
-}
-
-/**
- *     bfin_otp_exit - Deinitialize module
- *
- *     Unregisters the device and notifier handler. Actual device
- *     deinitialization is handled by bfin_otp_close().
- */
-static void __exit bfin_otp_exit(void)
-{
-       stampit();
-
-       misc_deregister(&bfin_otp_misc_device);
-}
-
-module_init(bfin_otp_init);
-module_exit(bfin_otp_exit);
+module_misc_device(bfin_otp_misc_device);
 
 MODULE_AUTHOR("Mike Frysinger <vapier@gentoo.org>");
 MODULE_DESCRIPTION("Blackfin OTP Memory Interface");
index a33163dbb913541ad6649de8e9a43f8256e1742a..5bb1985ec484aef267e3c551c3068ec0dee14b1c 100644 (file)
@@ -381,6 +381,9 @@ static ssize_t read_kmem(struct file *file, char __user *buf,
        char *kbuf; /* k-addr because vread() takes vmlist_lock rwlock */
        int err = 0;
 
+       if (!pfn_valid(PFN_DOWN(p)))
+               return -EIO;
+
        read = 0;
        if (p < (unsigned long) high_memory) {
                low_count = count;
@@ -509,6 +512,9 @@ static ssize_t write_kmem(struct file *file, const char __user *buf,
        char *kbuf; /* k-addr because vwrite() takes vmlist_lock rwlock */
        int err = 0;
 
+       if (!pfn_valid(PFN_DOWN(p)))
+               return -EIO;
+
        if (p < (unsigned long) high_memory) {
                unsigned long to_write = min_t(unsigned long, count,
                                               (unsigned long)high_memory - p);
index 28740046bc83752ffbe3ba47b3ec1a540a8bb648..972c40a19629c73271b10b1042f0b8f3601160d6 100644 (file)
@@ -124,7 +124,7 @@ static void dsp3780I_WriteGenCfg(unsigned short usDspBaseIO, unsigned uIndex,
                MKBYTE(rSlaveControl));
 
        rSlaveControl_Save = rSlaveControl;
-       rSlaveControl.ConfigMode = TRUE;
+       rSlaveControl.ConfigMode = true;
 
        PRINTK_2(TRACE_3780I,
                "3780i::dsp3780i_WriteGenCfg entry rSlaveControl+ConfigMode %x\n",
@@ -155,7 +155,7 @@ unsigned char dsp3780I_ReadGenCfg(unsigned short usDspBaseIO,
 
        MKBYTE(rSlaveControl) = InByteDsp(DSP_IsaSlaveControl);
        rSlaveControl_Save = rSlaveControl;
-       rSlaveControl.ConfigMode = TRUE;
+       rSlaveControl.ConfigMode = true;
        OutByteDsp(DSP_IsaSlaveControl, MKBYTE(rSlaveControl));
        OutByteDsp(DSP_ConfigAddress, (unsigned char) uIndex);
        ucValue = InByteDsp(DSP_ConfigData);
@@ -230,7 +230,7 @@ int dsp3780I_EnableDSP(DSP_3780I_CONFIG_SETTINGS * pSettings,
                        rUartCfg1.BaseIO = 3;
                        break;
                }
-               rUartCfg2.Enable = TRUE;
+               rUartCfg2.Enable = true;
        }
 
        rHBridgeCfg1.Reserved = rHBridgeCfg2.Reserved = 0;
@@ -238,7 +238,7 @@ int dsp3780I_EnableDSP(DSP_3780I_CONFIG_SETTINGS * pSettings,
        rHBridgeCfg1.IrqPulse = pSettings->bDspIrqPulse;
        rHBridgeCfg1.Irq = (unsigned char) pIrqMap[pSettings->usDspIrq];
        rHBridgeCfg1.AccessMode = 1;
-       rHBridgeCfg2.Enable = TRUE;
+       rHBridgeCfg2.Enable = true;
 
 
        rBusmasterCfg2.Reserved = 0;
@@ -278,8 +278,8 @@ int dsp3780I_EnableDSP(DSP_3780I_CONFIG_SETTINGS * pSettings,
        * soft-reset active for 10ms.
        */
        rSlaveControl.ClockControl = 0;
-       rSlaveControl.SoftReset = TRUE;
-       rSlaveControl.ConfigMode = FALSE;
+       rSlaveControl.SoftReset = true;
+       rSlaveControl.ConfigMode = false;
        rSlaveControl.Reserved = 0;
 
        PRINTK_4(TRACE_3780I,
@@ -302,7 +302,7 @@ int dsp3780I_EnableDSP(DSP_3780I_CONFIG_SETTINGS * pSettings,
        for (i = 0; i < 11; i++)
                udelay(2000);
 
-       rSlaveControl.SoftReset = FALSE;
+       rSlaveControl.SoftReset = false;
        OutWordDsp(DSP_IsaSlaveControl, MKWORD(rSlaveControl));
 
        MKWORD(tval) = InWordDsp(DSP_IsaSlaveControl);
@@ -326,10 +326,10 @@ int dsp3780I_EnableDSP(DSP_3780I_CONFIG_SETTINGS * pSettings,
        }
 
 
-       rHBridgeControl.EnableDspInt = FALSE;
-       rHBridgeControl.MemAutoInc = TRUE;
-       rHBridgeControl.IoAutoInc = FALSE;
-       rHBridgeControl.DiagnosticMode = FALSE;
+       rHBridgeControl.EnableDspInt = false;
+       rHBridgeControl.MemAutoInc = true;
+       rHBridgeControl.IoAutoInc = false;
+       rHBridgeControl.DiagnosticMode = false;
 
        PRINTK_3(TRACE_3780I,
                "3780i::dsp3780i_EnableDSP DSP_HBridgeControl %x rHBridgeControl %x\n",
@@ -345,7 +345,7 @@ int dsp3780I_EnableDSP(DSP_3780I_CONFIG_SETTINGS * pSettings,
        ChipID = ReadMsaCfg(DSP_ChipID);
 
        PRINTK_2(TRACE_3780I,
-               "3780i::dsp3780I_EnableDSP exiting bRC=TRUE, ChipID %x\n",
+               "3780i::dsp3780I_EnableDSP exiting bRC=true, ChipID %x\n",
                ChipID);
 
        return 0;
@@ -361,8 +361,8 @@ int dsp3780I_DisableDSP(DSP_3780I_CONFIG_SETTINGS * pSettings)
        PRINTK_1(TRACE_3780I, "3780i::dsp3780i_DisableDSP entry\n");
 
        rSlaveControl.ClockControl = 0;
-       rSlaveControl.SoftReset = TRUE;
-       rSlaveControl.ConfigMode = FALSE;
+       rSlaveControl.SoftReset = true;
+       rSlaveControl.ConfigMode = false;
        rSlaveControl.Reserved = 0;
        spin_lock_irqsave(&dsp_lock, flags);
        OutWordDsp(DSP_IsaSlaveControl, MKWORD(rSlaveControl));
@@ -398,14 +398,14 @@ int dsp3780I_Reset(DSP_3780I_CONFIG_SETTINGS * pSettings)
        PRINTK_2(TRACE_3780I, "3780i::dsp3780i_Reset rHBridgeControl %x\n",
                MKWORD(rHBridgeControl));
 
-       rHBridgeControl.EnableDspInt = FALSE;
+       rHBridgeControl.EnableDspInt = false;
        OutWordDsp(DSP_HBridgeControl, MKWORD(rHBridgeControl));
        spin_unlock_irqrestore(&dsp_lock, flags);
 
        /* Reset the core via the boot domain register */
-       rBootDomain.ResetCore = TRUE;
-       rBootDomain.Halt = TRUE;
-       rBootDomain.NMI = TRUE;
+       rBootDomain.ResetCore = true;
+       rBootDomain.Halt = true;
+       rBootDomain.NMI = true;
        rBootDomain.Reserved = 0;
 
        PRINTK_2(TRACE_3780I, "3780i::dsp3780i_Reset rBootDomain %x\n",
@@ -438,26 +438,26 @@ int dsp3780I_Run(DSP_3780I_CONFIG_SETTINGS * pSettings)
 
 
        /* Transition the core to a running state */
-       rBootDomain.ResetCore = TRUE;
-       rBootDomain.Halt = FALSE;
-       rBootDomain.NMI = TRUE;
+       rBootDomain.ResetCore = true;
+       rBootDomain.Halt = false;
+       rBootDomain.NMI = true;
        rBootDomain.Reserved = 0;
        WriteMsaCfg(DSP_MspBootDomain, MKWORD(rBootDomain));
 
        udelay(5);
 
-       rBootDomain.ResetCore = FALSE;
+       rBootDomain.ResetCore = false;
        WriteMsaCfg(DSP_MspBootDomain, MKWORD(rBootDomain));
        udelay(5);
 
-       rBootDomain.NMI = FALSE;
+       rBootDomain.NMI = false;
        WriteMsaCfg(DSP_MspBootDomain, MKWORD(rBootDomain));
        udelay(5);
 
        /* Enable DSP to PC interrupt */
        spin_lock_irqsave(&dsp_lock, flags);
        MKWORD(rHBridgeControl) = InWordDsp(DSP_HBridgeControl);
-       rHBridgeControl.EnableDspInt = TRUE;
+       rHBridgeControl.EnableDspInt = true;
 
        PRINTK_2(TRACE_3780I, "3780i::dsp3780i_Run rHBridgeControl %x\n",
                MKWORD(rHBridgeControl));
@@ -466,7 +466,7 @@ int dsp3780I_Run(DSP_3780I_CONFIG_SETTINGS * pSettings)
        spin_unlock_irqrestore(&dsp_lock, flags);
 
 
-       PRINTK_1(TRACE_3780I, "3780i::dsp3780i_Run exit bRC=TRUE\n");
+       PRINTK_1(TRACE_3780I, "3780i::dsp3780i_Run exit bRC=true\n");
 
        return 0;
 }
@@ -508,7 +508,7 @@ int dsp3780I_ReadDStore(unsigned short usDspBaseIO, void __user *pvBuffer,
 
 
        PRINTK_1(TRACE_3780I,
-               "3780I::dsp3780I_ReadDStore exit bRC=TRUE\n");
+               "3780I::dsp3780I_ReadDStore exit bRC=true\n");
 
        return 0;
 }
@@ -550,7 +550,7 @@ int dsp3780I_ReadAndClearDStore(unsigned short usDspBaseIO,
 
 
        PRINTK_1(TRACE_3780I,
-               "3780I::dsp3780I_ReadAndClearDStore exit bRC=TRUE\n");
+               "3780I::dsp3780I_ReadAndClearDStore exit bRC=true\n");
 
        return 0;
 }
@@ -592,7 +592,7 @@ int dsp3780I_WriteDStore(unsigned short usDspBaseIO, void __user *pvBuffer,
 
 
        PRINTK_1(TRACE_3780I,
-               "3780I::dsp3780D_WriteDStore exit bRC=TRUE\n");
+               "3780I::dsp3780D_WriteDStore exit bRC=true\n");
 
        return 0;
 }
@@ -640,7 +640,7 @@ int dsp3780I_ReadIStore(unsigned short usDspBaseIO, void __user *pvBuffer,
        }
 
        PRINTK_1(TRACE_3780I,
-               "3780I::dsp3780I_ReadIStore exit bRC=TRUE\n");
+               "3780I::dsp3780I_ReadIStore exit bRC=true\n");
 
        return 0;
 }
@@ -689,7 +689,7 @@ int dsp3780I_WriteIStore(unsigned short usDspBaseIO, void __user *pvBuffer,
        }
 
        PRINTK_1(TRACE_3780I,
-               "3780I::dsp3780I_WriteIStore exit bRC=TRUE\n");
+               "3780I::dsp3780I_WriteIStore exit bRC=true\n");
 
        return 0;
 }
@@ -713,7 +713,7 @@ int dsp3780I_GetIPCSource(unsigned short usDspBaseIO,
        */
        spin_lock_irqsave(&dsp_lock, flags);
        MKWORD(rHBridgeControl) = InWordDsp(DSP_HBridgeControl);
-       rHBridgeControl.EnableDspInt = FALSE;
+       rHBridgeControl.EnableDspInt = false;
        OutWordDsp(DSP_HBridgeControl, MKWORD(rHBridgeControl));
 
        *pusIPCSource = InWordDsp(DSP_Interrupt);
@@ -725,7 +725,7 @@ int dsp3780I_GetIPCSource(unsigned short usDspBaseIO,
 
        OutWordDsp(DSP_Interrupt, (unsigned short) ~(*pusIPCSource));
 
-       rHBridgeControl.EnableDspInt = TRUE;
+       rHBridgeControl.EnableDspInt = true;
        OutWordDsp(DSP_HBridgeControl, MKWORD(rHBridgeControl));
        spin_unlock_irqrestore(&dsp_lock, flags);
 
index fba6ab1160ce84432523607e2a13f7fbcc29250b..9ccb6b270b071cfbf03b250d1af442f28d75bafe 100644 (file)
@@ -101,7 +101,7 @@ typedef struct {
 } DSP_UART_CFG_1;
 
 typedef struct {
-       unsigned char Enable:1; /* RW: Enable I/O and IRQ: 0=FALSE, 1=TRUE */
+       unsigned char Enable:1; /* RW: Enable I/O and IRQ: 0=false, 1=true */
        unsigned char Reserved:7;       /* 0: Reserved */
 } DSP_UART_CFG_2;
 
@@ -114,7 +114,7 @@ typedef struct {
 } DSP_HBRIDGE_CFG_1;
 
 typedef struct {
-       unsigned char Enable:1; /* RW: enable I/O and IRQ: 0=FALSE, 1=TRUE */
+       unsigned char Enable:1; /* RW: enable I/O and IRQ: 0=false, 1=true */
        unsigned char Reserved:7;       /* 0: Reserved */
 } DSP_HBRIDGE_CFG_2;
 
@@ -133,12 +133,12 @@ typedef struct {
 
 
 typedef struct {
-       unsigned char GateIOCHRDY:1;    /* RW: Enable IOCHRDY gating: 0=FALSE, 1=TRUE */
+       unsigned char GateIOCHRDY:1;    /* RW: Enable IOCHRDY gating: 0=false, 1=true */
        unsigned char Reserved:7;       /* 0: Reserved */
 } DSP_ISA_PROT_CFG;
 
 typedef struct {
-       unsigned char Enable:1; /* RW: Enable low power suspend/resume 0=FALSE, 1=TRUE */
+       unsigned char Enable:1; /* RW: Enable low power suspend/resume 0=false, 1=true */
        unsigned char Reserved:7;       /* 0: Reserved */
 } DSP_POWER_MGMT_CFG;
 
index 164544afd6809b1c1287c5d3fb02c99a29de7ab6..3a3ff2eb6cba3f2e530e11700cfb133451badb70 100644 (file)
@@ -296,8 +296,8 @@ static long mwave_ioctl(struct file *file, unsigned int iocmd,
                                pDrvData->IPCs[ipcnum].usIntCount);
 
                        mutex_lock(&mwave_mutex);
-                       pDrvData->IPCs[ipcnum].bIsHere = FALSE;
-                       pDrvData->IPCs[ipcnum].bIsEnabled = TRUE;
+                       pDrvData->IPCs[ipcnum].bIsHere = false;
+                       pDrvData->IPCs[ipcnum].bIsEnabled = true;
                        mutex_unlock(&mwave_mutex);
        
                        PRINTK_2(TRACE_MWAVE,
@@ -324,7 +324,7 @@ static long mwave_ioctl(struct file *file, unsigned int iocmd,
                                pDrvData->IPCs[ipcnum].usIntCount);
        
                        mutex_lock(&mwave_mutex);
-                       if (pDrvData->IPCs[ipcnum].bIsEnabled == TRUE) {
+                       if (pDrvData->IPCs[ipcnum].bIsEnabled == true) {
                                DECLARE_WAITQUEUE(wait, current);
 
                                PRINTK_2(TRACE_MWAVE,
@@ -332,7 +332,7 @@ static long mwave_ioctl(struct file *file, unsigned int iocmd,
                                        " ipc %x going to sleep\n",
                                        ipcnum);
                                add_wait_queue(&pDrvData->IPCs[ipcnum].ipc_wait_queue, &wait);
-                               pDrvData->IPCs[ipcnum].bIsHere = TRUE;
+                               pDrvData->IPCs[ipcnum].bIsHere = true;
                                set_current_state(TASK_INTERRUPTIBLE);
                                /* check whether an event was signalled by */
                                /* the interrupt handler while we were gone */
@@ -355,7 +355,7 @@ static long mwave_ioctl(struct file *file, unsigned int iocmd,
                                                " application\n",
                                                ipcnum);
                                }
-                               pDrvData->IPCs[ipcnum].bIsHere = FALSE;
+                               pDrvData->IPCs[ipcnum].bIsHere = false;
                                remove_wait_queue(&pDrvData->IPCs[ipcnum].ipc_wait_queue, &wait);
                                set_current_state(TASK_RUNNING);
                                PRINTK_2(TRACE_MWAVE,
@@ -384,9 +384,9 @@ static long mwave_ioctl(struct file *file, unsigned int iocmd,
                                return -EINVAL;
                        }
                        mutex_lock(&mwave_mutex);
-                       if (pDrvData->IPCs[ipcnum].bIsEnabled == TRUE) {
-                               pDrvData->IPCs[ipcnum].bIsEnabled = FALSE;
-                               if (pDrvData->IPCs[ipcnum].bIsHere == TRUE) {
+                       if (pDrvData->IPCs[ipcnum].bIsEnabled == true) {
+                               pDrvData->IPCs[ipcnum].bIsEnabled = false;
+                               if (pDrvData->IPCs[ipcnum].bIsHere == true) {
                                        wake_up_interruptible(&pDrvData->IPCs[ipcnum].ipc_wait_queue);
                                }
                        }
@@ -541,7 +541,7 @@ static void mwave_exit(void)
 
        if (pDrvData->device_registered) {
                device_unregister(&mwave_device);
-               pDrvData->device_registered = FALSE;
+               pDrvData->device_registered = false;
        }
 #endif
 
@@ -576,16 +576,16 @@ static int __init mwave_init(void)
 
        memset(&mwave_s_mdd, 0, sizeof(MWAVE_DEVICE_DATA));
 
-       pDrvData->bBDInitialized = FALSE;
-       pDrvData->bResourcesClaimed = FALSE;
-       pDrvData->bDSPEnabled = FALSE;
-       pDrvData->bDSPReset = FALSE;
-       pDrvData->bMwaveDevRegistered = FALSE;
+       pDrvData->bBDInitialized = false;
+       pDrvData->bResourcesClaimed = false;
+       pDrvData->bDSPEnabled = false;
+       pDrvData->bDSPReset = false;
+       pDrvData->bMwaveDevRegistered = false;
        pDrvData->sLine = -1;
 
        for (i = 0; i < ARRAY_SIZE(pDrvData->IPCs); i++) {
-               pDrvData->IPCs[i].bIsEnabled = FALSE;
-               pDrvData->IPCs[i].bIsHere = FALSE;
+               pDrvData->IPCs[i].bIsEnabled = false;
+               pDrvData->IPCs[i].bIsHere = false;
                pDrvData->IPCs[i].usIntCount = 0;       /* no ints received yet */
                init_waitqueue_head(&pDrvData->IPCs[i].ipc_wait_queue);
        }
@@ -601,7 +601,7 @@ static int __init mwave_init(void)
                                " Failed to initialize board data\n");
                goto cleanup_error;
        }
-       pDrvData->bBDInitialized = TRUE;
+       pDrvData->bBDInitialized = true;
 
        retval = tp3780I_CalcResources(&pDrvData->rBDData);
        PRINTK_2(TRACE_MWAVE,
@@ -626,7 +626,7 @@ static int __init mwave_init(void)
                                " Failed to claim resources\n");
                goto cleanup_error;
        }
-       pDrvData->bResourcesClaimed = TRUE;
+       pDrvData->bResourcesClaimed = true;
 
        retval = tp3780I_EnableDSP(&pDrvData->rBDData);
        PRINTK_2(TRACE_MWAVE,
@@ -639,7 +639,7 @@ static int __init mwave_init(void)
                                " Failed to enable DSP\n");
                goto cleanup_error;
        }
-       pDrvData->bDSPEnabled = TRUE;
+       pDrvData->bDSPEnabled = true;
 
        if (misc_register(&mwave_misc_dev) < 0) {
                PRINTK_ERROR(KERN_ERR_MWAVE
@@ -647,7 +647,7 @@ static int __init mwave_init(void)
                                " Failed to register misc device\n");
                goto cleanup_error;
        }
-       pDrvData->bMwaveDevRegistered = TRUE;
+       pDrvData->bMwaveDevRegistered = true;
 
        pDrvData->sLine = register_serial_portandirq(
                pDrvData->rBDData.rDspSettings.usUartBaseIO,
@@ -668,7 +668,7 @@ static int __init mwave_init(void)
 
        if (device_register(&mwave_device))
                goto cleanup_error;
-       pDrvData->device_registered = TRUE;
+       pDrvData->device_registered = true;
        for (i = 0; i < ARRAY_SIZE(mwave_dev_attrs); i++) {
                if(device_create_file(&mwave_device, mwave_dev_attrs[i])) {
                        PRINTK_ERROR(KERN_ERR_MWAVE
index 7e0d530e2e07f151e93fa0a0b39fc9514a2b9b83..37e0a49260801eea400147905162b6bd7a835515 100644 (file)
@@ -125,8 +125,8 @@ extern int mwave_uart_io;
 
 typedef struct _MWAVE_IPC {
        unsigned short usIntCount;      /* 0=none, 1=first, 2=greater than 1st */
-       BOOLEAN bIsEnabled;
-       BOOLEAN bIsHere;
+       bool bIsEnabled;
+       bool bIsHere;
        /* entry spin lock */
        wait_queue_head_t ipc_wait_queue;
 } MWAVE_IPC;
@@ -135,12 +135,12 @@ typedef struct _MWAVE_DEVICE_DATA {
        THINKPAD_BD_DATA rBDData;       /* board driver's data area */
        unsigned long ulIPCSource_ISR;  /* IPC source bits for recently processed intr, set during ISR processing */
        unsigned long ulIPCSource_DPC;  /* IPC source bits for recently processed intr, set during DPC processing */
-       BOOLEAN bBDInitialized;
-       BOOLEAN bResourcesClaimed;
-       BOOLEAN bDSPEnabled;
-       BOOLEAN bDSPReset;
+       bool bBDInitialized;
+       bool bResourcesClaimed;
+       bool bDSPEnabled;
+       bool bDSPReset;
        MWAVE_IPC IPCs[16];
-       BOOLEAN bMwaveDevRegistered;
+       bool bMwaveDevRegistered;
        short sLine;
        int nr_registered_attrs;
        int device_registered;
index 6187fd14b3fe52bdf11d35f8f2d26bb4a0b786e4..8c5411a8f33f27d917c0057da042126300976133 100644 (file)
@@ -493,7 +493,7 @@ exit_smapi_request_error:
 }
 
 
-int smapi_set_DSP_power_state(BOOLEAN bOn)
+int smapi_set_DSP_power_state(bool bOn)
 {
        int bRC = -EIO;
        unsigned short usAX, usBX, usCX, usDX, usDI, usSI;
@@ -556,7 +556,7 @@ int smapi_init(void)
                        PRINTK_ERROR("smapi::smapi_init, ERROR unable to read from SMAPI port\n");
                } else {
                        PRINTK_2(TRACE_SMAPI,
-                               "smapi::smapi_init, exit TRUE g_usSmapiPort %x\n",
+                               "smapi::smapi_init, exit true g_usSmapiPort %x\n",
                                g_usSmapiPort);
                        retval = 0;
                        //SmapiQuerySystemID();
index 64b2ec1420e3ae6f715edf99a2f79430b66ab64e..ebc206b000b925303fefe9d7e30ea146ccbdf0a6 100644 (file)
 #ifndef _LINUX_SMAPI_H
 #define _LINUX_SMAPI_H
 
-#define TRUE 1
-#define FALSE 0
-#define BOOLEAN int
-
 typedef struct {
        int bDSPPresent;
        int bDSPEnabled;
@@ -74,7 +70,7 @@ typedef struct {
 int smapi_init(void);
 int smapi_query_DSP_cfg(SMAPI_DSP_SETTINGS * pSettings);
 int smapi_set_DSP_cfg(void);
-int smapi_set_DSP_power_state(BOOLEAN bOn);
+int smapi_set_DSP_power_state(bool bOn);
 
 
 #endif
index 04e6d6a27994392f14e72aa1a45e0c8525fa52fb..5e1618a76b2a31df845d9b9c16787b20207a8a02 100644 (file)
@@ -80,13 +80,13 @@ static void EnableSRAM(THINKPAD_BD_DATA * pBDData)
        WriteMsaCfg(DSP_GpioModeControl_15_8, MKWORD(rGpioMode));
 
        MKWORD(rGpioDriverEnable) = 0;
-       rGpioDriverEnable.Enable10 = TRUE;
-       rGpioDriverEnable.Mask10 = TRUE;
+       rGpioDriverEnable.Enable10 = true;
+       rGpioDriverEnable.Mask10 = true;
        WriteMsaCfg(DSP_GpioDriverEnable_15_8, MKWORD(rGpioDriverEnable));
 
        MKWORD(rGpioOutputData) = 0;
        rGpioOutputData.Latch10 = 0;
-       rGpioOutputData.Mask10 = TRUE;
+       rGpioOutputData.Mask10 = true;
        WriteMsaCfg(DSP_GpioOutputData_15_8, MKWORD(rGpioOutputData));
 
        PRINTK_1(TRACE_TP3780I, "tp3780i::EnableSRAM exit\n");
@@ -127,7 +127,7 @@ static irqreturn_t DspInterrupt(int irq, void *dev_id)
                                PRINTK_2(TRACE_TP3780I,
                                        "tp3780i::DspInterrupt usIntCount %x\n",
                                        pDrvData->IPCs[usPCNum - 1].usIntCount);
-                               if (pDrvData->IPCs[usPCNum - 1].bIsEnabled == TRUE) {
+                               if (pDrvData->IPCs[usPCNum - 1].bIsEnabled == true) {
                                        PRINTK_2(TRACE_TP3780I,
                                                "tp3780i::DspInterrupt, waking up usPCNum %x\n",
                                                usPCNum - 1);
@@ -160,8 +160,8 @@ int tp3780I_InitializeBoardData(THINKPAD_BD_DATA * pBDData)
 
        PRINTK_2(TRACE_TP3780I, "tp3780i::tp3780I_InitializeBoardData entry pBDData %p\n", pBDData);
 
-       pBDData->bDSPEnabled = FALSE;
-       pSettings->bInterruptClaimed = FALSE;
+       pBDData->bDSPEnabled = false;
+       pSettings->bInterruptClaimed = false;
 
        retval = smapi_init();
        if (retval) {
@@ -269,7 +269,7 @@ int tp3780I_ReleaseResources(THINKPAD_BD_DATA * pBDData)
 
        if (pSettings->bInterruptClaimed) {
                free_irq(pSettings->usDspIrq, NULL);
-               pSettings->bInterruptClaimed = FALSE;
+               pSettings->bInterruptClaimed = false;
        }
 
        PRINTK_2(TRACE_TP3780I,
@@ -283,7 +283,7 @@ int tp3780I_ReleaseResources(THINKPAD_BD_DATA * pBDData)
 int tp3780I_EnableDSP(THINKPAD_BD_DATA * pBDData)
 {
        DSP_3780I_CONFIG_SETTINGS *pSettings = &pBDData->rDspSettings;
-       BOOLEAN bDSPPoweredUp = FALSE, bInterruptAllocated = FALSE;
+       bool bDSPPoweredUp = false, bInterruptAllocated = false;
 
        PRINTK_2(TRACE_TP3780I, "tp3780i::tp3780I_EnableDSP entry pBDData %p\n", pBDData);
 
@@ -336,14 +336,14 @@ int tp3780I_EnableDSP(THINKPAD_BD_DATA * pBDData)
                }
        }
 
-       pSettings->bDspIrqActiveLow = pSettings->bDspIrqPulse = TRUE;
-       pSettings->bUartIrqActiveLow = pSettings->bUartIrqPulse = TRUE;
+       pSettings->bDspIrqActiveLow = pSettings->bDspIrqPulse = true;
+       pSettings->bUartIrqActiveLow = pSettings->bUartIrqPulse = true;
 
        if (pBDData->bShareDspIrq) {
-               pSettings->bDspIrqActiveLow = FALSE;
+               pSettings->bDspIrqActiveLow = false;
        }
        if (pBDData->bShareUartIrq) {
-               pSettings->bUartIrqActiveLow = FALSE;
+               pSettings->bUartIrqActiveLow = false;
        }
 
        pSettings->usNumTransfers = TP_CFG_NumTransfers;
@@ -373,16 +373,16 @@ int tp3780I_EnableDSP(THINKPAD_BD_DATA * pBDData)
                PRINTK_3(TRACE_TP3780I,
                        "tp3780i::tp3780I_EnableDSP, got interrupt %x bShareDspIrq %x\n",
                        pSettings->usDspIrq, pBDData->bShareDspIrq);
-               bInterruptAllocated = TRUE;
-               pSettings->bInterruptClaimed = TRUE;
+               bInterruptAllocated = true;
+               pSettings->bInterruptClaimed = true;
        }
 
-       smapi_set_DSP_power_state(FALSE);
-       if (smapi_set_DSP_power_state(TRUE)) {
-               PRINTK_ERROR(KERN_ERR_MWAVE "tp3780i::tp3780I_EnableDSP: Error: smapi_set_DSP_power_state(TRUE) failed\n");
+       smapi_set_DSP_power_state(false);
+       if (smapi_set_DSP_power_state(true)) {
+               PRINTK_ERROR(KERN_ERR_MWAVE "tp3780i::tp3780I_EnableDSP: Error: smapi_set_DSP_power_state(true) failed\n");
                goto exit_cleanup;
        } else {
-               bDSPPoweredUp = TRUE;
+               bDSPPoweredUp = true;
        }
 
        if (dsp3780I_EnableDSP(pSettings, s_ausThinkpadIrqToField, s_ausThinkpadDmaToField)) {
@@ -392,7 +392,7 @@ int tp3780I_EnableDSP(THINKPAD_BD_DATA * pBDData)
 
        EnableSRAM(pBDData);
 
-       pBDData->bDSPEnabled = TRUE;
+       pBDData->bDSPEnabled = true;
 
        PRINTK_1(TRACE_TP3780I, "tp3780i::tp3780I_EnableDSP exit\n");
 
@@ -401,10 +401,10 @@ int tp3780I_EnableDSP(THINKPAD_BD_DATA * pBDData)
 exit_cleanup:
        PRINTK_ERROR("tp3780i::tp3780I_EnableDSP: Cleaning up\n");
        if (bDSPPoweredUp)
-               smapi_set_DSP_power_state(FALSE);
+               smapi_set_DSP_power_state(false);
        if (bInterruptAllocated) {
                free_irq(pSettings->usDspIrq, NULL);
-               pSettings->bInterruptClaimed = FALSE;
+               pSettings->bInterruptClaimed = false;
        }
        return -EIO;
 }
@@ -421,10 +421,10 @@ int tp3780I_DisableDSP(THINKPAD_BD_DATA * pBDData)
                dsp3780I_DisableDSP(&pBDData->rDspSettings);
                if (pSettings->bInterruptClaimed) {
                        free_irq(pSettings->usDspIrq, NULL);
-                       pSettings->bInterruptClaimed = FALSE;
+                       pSettings->bInterruptClaimed = false;
                }
-               smapi_set_DSP_power_state(FALSE);
-               pBDData->bDSPEnabled = FALSE;
+               smapi_set_DSP_power_state(false);
+               pBDData->bDSPEnabled = false;
        }
 
        PRINTK_2(TRACE_TP3780I, "tp3780i::tp3780I_DisableDSP exit retval %x\n", retval);
@@ -516,7 +516,7 @@ int tp3780I_ReadWriteDspDStore(THINKPAD_BD_DATA * pBDData, unsigned int uOpcode,
        int retval = 0;
        DSP_3780I_CONFIG_SETTINGS *pSettings = &pBDData->rDspSettings;
        unsigned short usDspBaseIO = pSettings->usDspBaseIO;
-       BOOLEAN bRC = 0;
+       bool bRC = 0;
 
        PRINTK_6(TRACE_TP3780I,
                "tp3780i::tp3780I_ReadWriteDspDStore entry pBDData %p, uOpcode %x, pvBuffer %p, uCount %x, ulDSPAddr %lx\n",
@@ -552,7 +552,7 @@ int tp3780I_ReadWriteDspIStore(THINKPAD_BD_DATA * pBDData, unsigned int uOpcode,
        int retval = 0;
        DSP_3780I_CONFIG_SETTINGS *pSettings = &pBDData->rDspSettings;
        unsigned short usDspBaseIO = pSettings->usDspBaseIO;
-       BOOLEAN bRC = 0;
+       bool bRC = 0;
 
        PRINTK_6(TRACE_TP3780I,
                "tp3780i::tp3780I_ReadWriteDspIStore entry pBDData %p, uOpcode %x, pvBuffer %p, uCount %x, ulDSPAddr %lx\n",
index f8a483c67b07719be1f97af6bd1750bc53b04ae6..d23368874710f726d485917e4d3f1ef93f3e3843 100644 (file)
@@ -286,7 +286,7 @@ static int register_device(int minor, struct pp_struct *pp)
        struct parport *port;
        struct pardevice *pdev = NULL;
        char *name;
-       int fl;
+       struct pardev_cb ppdev_cb;
 
        name = kasprintf(GFP_KERNEL, CHRDEV "%x", minor);
        if (name == NULL)
@@ -299,9 +299,11 @@ static int register_device(int minor, struct pp_struct *pp)
                return -ENXIO;
        }
 
-       fl = (pp->flags & PP_EXCL) ? PARPORT_FLAG_EXCL : 0;
-       pdev = parport_register_device(port, name, NULL,
-                                      NULL, pp_irq, fl, pp);
+       memset(&ppdev_cb, 0, sizeof(ppdev_cb));
+       ppdev_cb.irq_func = pp_irq;
+       ppdev_cb.flags = (pp->flags & PP_EXCL) ? PARPORT_FLAG_EXCL : 0;
+       ppdev_cb.private = pp;
+       pdev = parport_register_dev_model(port, name, &ppdev_cb, minor);
        parport_put_port(port);
 
        if (!pdev) {
@@ -799,10 +801,23 @@ static void pp_detach(struct parport *port)
        device_destroy(ppdev_class, MKDEV(PP_MAJOR, port->number));
 }
 
+static int pp_probe(struct pardevice *par_dev)
+{
+       struct device_driver *drv = par_dev->dev.driver;
+       int len = strlen(drv->name);
+
+       if (strncmp(par_dev->name, drv->name, len))
+               return -ENODEV;
+
+       return 0;
+}
+
 static struct parport_driver pp_driver = {
        .name           = CHRDEV,
-       .attach         = pp_attach,
+       .probe          = pp_probe,
+       .match_port     = pp_attach,
        .detach         = pp_detach,
+       .devmodel       = true,
 };
 
 static int __init ppdev_init(void)
index 94006f9c2e4312d6b4f7dbafa7726daa93e2c1e7..10e56323f3902faf66cd5fc5b8fd83272505b378 100644 (file)
@@ -385,13 +385,18 @@ scdrv_init(void)
 
        event_nasid = ia64_sn_get_console_nasid();
 
+       snsc_class = class_create(THIS_MODULE, SYSCTL_BASENAME);
+       if (IS_ERR(snsc_class)) {
+               printk("%s: failed to allocate class\n", __func__);
+               return PTR_ERR(snsc_class);
+       }
+
        if (alloc_chrdev_region(&first_dev, 0, num_cnodes,
                                SYSCTL_BASENAME) < 0) {
                printk("%s: failed to register SN system controller device\n",
                       __func__);
                return -ENODEV;
        }
-       snsc_class = class_create(THIS_MODULE, SYSCTL_BASENAME);
 
        for (cnode = 0; cnode < num_cnodes; cnode++) {
                        geoid = cnodeid_get_geoid(cnode);
index dcd19f3f182e569e4e8e991653afdfb3b5af14be..b6c9cdead7f3a0bbccd4744374da00d95d902931 100644 (file)
@@ -655,10 +655,10 @@ static int xilly_obtain_idt(struct xilly_endpoint *endpoint)
 
        version = channel->wr_buffers[0]->addr;
 
-       /* Check version number. Accept anything below 0x82 for now. */
+       /* Check version number. Reject anything above 0x82. */
        if (*version > 0x82) {
                dev_err(endpoint->dev,
-                       "No support for IDT version 0x%02x. Maybe the xillybus driver needs an upgarde. Aborting.\n",
+                       "No support for IDT version 0x%02x. Maybe the xillybus driver needs an upgrade. Aborting.\n",
                        *version);
                return -ENODEV;
        }
index d61410299ec0cf806a7c0e613f97e894c5efcd73..cd84934774cc72f854bdea788a4b2308522f52c1 100644 (file)
@@ -21,6 +21,7 @@ config FPGA_MGR_SOCFPGA
 
 config FPGA_MGR_ZYNQ_FPGA
        tristate "Xilinx Zynq FPGA"
+       depends on ARCH_ZYNQ || COMPILE_TEST
        depends on HAS_DMA
        help
          FPGA manager driver support for Xilinx Zynq FPGAs.
index 99ec3ff7563b3e75ce0c050ba7d28064d445c7af..7f8ff39ed44bd7900f006956b001e57f93c22143 100644 (file)
@@ -779,19 +779,8 @@ static struct miscdevice uhid_misc = {
        .minor          = UHID_MINOR,
        .name           = UHID_NAME,
 };
+module_misc_device(uhid_misc);
 
-static int __init uhid_init(void)
-{
-       return misc_register(&uhid_misc);
-}
-
-static void __exit uhid_exit(void)
-{
-       misc_deregister(&uhid_misc);
-}
-
-module_init(uhid_init);
-module_exit(uhid_exit);
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("David Herrmann <dh.herrmann@gmail.com>");
 MODULE_DESCRIPTION("User-space I/O driver support for HID subsystem");
index 56dd261f7142f3957aef255ffaec43ce38a05ee7..16f91c8490fe01a0fe455c70b4356339e55ed935 100644 (file)
@@ -43,7 +43,12 @@ static void vmbus_setevent(struct vmbus_channel *channel)
 {
        struct hv_monitor_page *monitorpage;
 
-       if (channel->offermsg.monitor_allocated) {
+       /*
+        * For channels marked as in "low latency" mode
+        * bypass the monitor page mechanism.
+        */
+       if ((channel->offermsg.monitor_allocated) &&
+           (!channel->low_latency)) {
                /* Each u32 represents 32 channels */
                sync_set_bit(channel->offermsg.child_relid & 31,
                        (unsigned long *) vmbus_connection.send_int_page +
@@ -70,12 +75,14 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size,
 {
        struct vmbus_channel_open_channel *open_msg;
        struct vmbus_channel_msginfo *open_info = NULL;
-       void *in, *out;
        unsigned long flags;
        int ret, err = 0;
-       unsigned long t;
        struct page *page;
 
+       if (send_ringbuffer_size % PAGE_SIZE ||
+           recv_ringbuffer_size % PAGE_SIZE)
+               return -EINVAL;
+
        spin_lock_irqsave(&newchannel->lock, flags);
        if (newchannel->state == CHANNEL_OPEN_STATE) {
                newchannel->state = CHANNEL_OPENING_STATE;
@@ -95,36 +102,33 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size,
                                recv_ringbuffer_size));
 
        if (!page)
-               out = (void *)__get_free_pages(GFP_KERNEL|__GFP_ZERO,
-                                              get_order(send_ringbuffer_size +
-                                              recv_ringbuffer_size));
-       else
-               out = (void *)page_address(page);
+               page = alloc_pages(GFP_KERNEL|__GFP_ZERO,
+                                  get_order(send_ringbuffer_size +
+                                            recv_ringbuffer_size));
 
-       if (!out) {
+       if (!page) {
                err = -ENOMEM;
-               goto error0;
+               goto error_set_chnstate;
        }
 
-       in = (void *)((unsigned long)out + send_ringbuffer_size);
-
-       newchannel->ringbuffer_pages = out;
+       newchannel->ringbuffer_pages = page_address(page);
        newchannel->ringbuffer_pagecount = (send_ringbuffer_size +
                                           recv_ringbuffer_size) >> PAGE_SHIFT;
 
-       ret = hv_ringbuffer_init(
-               &newchannel->outbound, out, send_ringbuffer_size);
+       ret = hv_ringbuffer_init(&newchannel->outbound, page,
+                                send_ringbuffer_size >> PAGE_SHIFT);
 
        if (ret != 0) {
                err = ret;
-               goto error0;
+               goto error_free_pages;
        }
 
-       ret = hv_ringbuffer_init(
-               &newchannel->inbound, in, recv_ringbuffer_size);
+       ret = hv_ringbuffer_init(&newchannel->inbound,
+                                &page[send_ringbuffer_size >> PAGE_SHIFT],
+                                recv_ringbuffer_size >> PAGE_SHIFT);
        if (ret != 0) {
                err = ret;
-               goto error0;
+               goto error_free_pages;
        }
 
 
@@ -132,14 +136,14 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size,
        newchannel->ringbuffer_gpadlhandle = 0;
 
        ret = vmbus_establish_gpadl(newchannel,
-                                        newchannel->outbound.ring_buffer,
-                                        send_ringbuffer_size +
-                                        recv_ringbuffer_size,
-                                        &newchannel->ringbuffer_gpadlhandle);
+                                   page_address(page),
+                                   send_ringbuffer_size +
+                                   recv_ringbuffer_size,
+                                   &newchannel->ringbuffer_gpadlhandle);
 
        if (ret != 0) {
                err = ret;
-               goto error0;
+               goto error_free_pages;
        }
 
        /* Create and init the channel open message */
@@ -148,7 +152,7 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size,
                           GFP_KERNEL);
        if (!open_info) {
                err = -ENOMEM;
-               goto error_gpadl;
+               goto error_free_gpadl;
        }
 
        init_completion(&open_info->waitevent);
@@ -164,7 +168,7 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size,
 
        if (userdatalen > MAX_USER_DEFINED_BYTES) {
                err = -EINVAL;
-               goto error_gpadl;
+               goto error_free_gpadl;
        }
 
        if (userdatalen)
@@ -180,14 +184,10 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size,
 
        if (ret != 0) {
                err = ret;
-               goto error1;
+               goto error_clean_msglist;
        }
 
-       t = wait_for_completion_timeout(&open_info->waitevent, 5*HZ);
-       if (t == 0) {
-               err = -ETIMEDOUT;
-               goto error1;
-       }
+       wait_for_completion(&open_info->waitevent);
 
        spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
        list_del(&open_info->msglistentry);
@@ -195,25 +195,27 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size,
 
        if (open_info->response.open_result.status) {
                err = -EAGAIN;
-               goto error_gpadl;
+               goto error_free_gpadl;
        }
 
        newchannel->state = CHANNEL_OPENED_STATE;
        kfree(open_info);
        return 0;
 
-error1:
+error_clean_msglist:
        spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
        list_del(&open_info->msglistentry);
        spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
 
-error_gpadl:
+error_free_gpadl:
        vmbus_teardown_gpadl(newchannel, newchannel->ringbuffer_gpadlhandle);
-
-error0:
-       free_pages((unsigned long)out,
-               get_order(send_ringbuffer_size + recv_ringbuffer_size));
        kfree(open_info);
+error_free_pages:
+       hv_ringbuffer_cleanup(&newchannel->outbound);
+       hv_ringbuffer_cleanup(&newchannel->inbound);
+       __free_pages(page,
+                    get_order(send_ringbuffer_size + recv_ringbuffer_size));
+error_set_chnstate:
        newchannel->state = CHANNEL_OPEN_STATE;
        return err;
 }
@@ -238,8 +240,7 @@ EXPORT_SYMBOL_GPL(vmbus_send_tl_connect_request);
  * create_gpadl_header - Creates a gpadl for the specified buffer
  */
 static int create_gpadl_header(void *kbuffer, u32 size,
-                                        struct vmbus_channel_msginfo **msginfo,
-                                        u32 *messagecount)
+                              struct vmbus_channel_msginfo **msginfo)
 {
        int i;
        int pagecount;
@@ -283,7 +284,6 @@ static int create_gpadl_header(void *kbuffer, u32 size,
                        gpadl_header->range[0].pfn_array[i] = slow_virt_to_phys(
                                kbuffer + PAGE_SIZE * i) >> PAGE_SHIFT;
                *msginfo = msgheader;
-               *messagecount = 1;
 
                pfnsum = pfncount;
                pfnleft = pagecount - pfncount;
@@ -323,7 +323,6 @@ static int create_gpadl_header(void *kbuffer, u32 size,
                        }
 
                        msgbody->msgsize = msgsize;
-                       (*messagecount)++;
                        gpadl_body =
                                (struct vmbus_channel_gpadl_body *)msgbody->msg;
 
@@ -352,6 +351,8 @@ static int create_gpadl_header(void *kbuffer, u32 size,
                msgheader = kzalloc(msgsize, GFP_KERNEL);
                if (msgheader == NULL)
                        goto nomem;
+
+               INIT_LIST_HEAD(&msgheader->submsglist);
                msgheader->msgsize = msgsize;
 
                gpadl_header = (struct vmbus_channel_gpadl_header *)
@@ -366,7 +367,6 @@ static int create_gpadl_header(void *kbuffer, u32 size,
                                kbuffer + PAGE_SIZE * i) >> PAGE_SHIFT;
 
                *msginfo = msgheader;
-               *messagecount = 1;
        }
 
        return 0;
@@ -390,8 +390,7 @@ int vmbus_establish_gpadl(struct vmbus_channel *channel, void *kbuffer,
        struct vmbus_channel_gpadl_header *gpadlmsg;
        struct vmbus_channel_gpadl_body *gpadl_body;
        struct vmbus_channel_msginfo *msginfo = NULL;
-       struct vmbus_channel_msginfo *submsginfo;
-       u32 msgcount;
+       struct vmbus_channel_msginfo *submsginfo, *tmp;
        struct list_head *curr;
        u32 next_gpadl_handle;
        unsigned long flags;
@@ -400,7 +399,7 @@ int vmbus_establish_gpadl(struct vmbus_channel *channel, void *kbuffer,
        next_gpadl_handle =
                (atomic_inc_return(&vmbus_connection.next_gpadl_handle) - 1);
 
-       ret = create_gpadl_header(kbuffer, size, &msginfo, &msgcount);
+       ret = create_gpadl_header(kbuffer, size, &msginfo);
        if (ret)
                return ret;
 
@@ -423,24 +422,21 @@ int vmbus_establish_gpadl(struct vmbus_channel *channel, void *kbuffer,
        if (ret != 0)
                goto cleanup;
 
-       if (msgcount > 1) {
-               list_for_each(curr, &msginfo->submsglist) {
-
-                       submsginfo = (struct vmbus_channel_msginfo *)curr;
-                       gpadl_body =
-                            (struct vmbus_channel_gpadl_body *)submsginfo->msg;
+       list_for_each(curr, &msginfo->submsglist) {
+               submsginfo = (struct vmbus_channel_msginfo *)curr;
+               gpadl_body =
+                       (struct vmbus_channel_gpadl_body *)submsginfo->msg;
 
-                       gpadl_body->header.msgtype =
-                               CHANNELMSG_GPADL_BODY;
-                       gpadl_body->gpadl = next_gpadl_handle;
+               gpadl_body->header.msgtype =
+                       CHANNELMSG_GPADL_BODY;
+               gpadl_body->gpadl = next_gpadl_handle;
 
-                       ret = vmbus_post_msg(gpadl_body,
-                                              submsginfo->msgsize -
-                                              sizeof(*submsginfo));
-                       if (ret != 0)
-                               goto cleanup;
+               ret = vmbus_post_msg(gpadl_body,
+                                    submsginfo->msgsize -
+                                    sizeof(*submsginfo));
+               if (ret != 0)
+                       goto cleanup;
 
-               }
        }
        wait_for_completion(&msginfo->waitevent);
 
@@ -451,6 +447,10 @@ cleanup:
        spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags);
        list_del(&msginfo->msglistentry);
        spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags);
+       list_for_each_entry_safe(submsginfo, tmp, &msginfo->submsglist,
+                                msglistentry) {
+               kfree(submsginfo);
+       }
 
        kfree(msginfo);
        return ret;
@@ -512,7 +512,6 @@ static void reset_channel_cb(void *arg)
 static int vmbus_close_internal(struct vmbus_channel *channel)
 {
        struct vmbus_channel_close_channel *msg;
-       struct tasklet_struct *tasklet;
        int ret;
 
        /*
@@ -524,8 +523,7 @@ static int vmbus_close_internal(struct vmbus_channel *channel)
         * To resolve the race, we can serialize them by disabling the
         * tasklet when the latter is running here.
         */
-       tasklet = hv_context.event_dpc[channel->target_cpu];
-       tasklet_disable(tasklet);
+       hv_event_tasklet_disable(channel);
 
        /*
         * In case a device driver's probe() fails (e.g.,
@@ -591,7 +589,7 @@ static int vmbus_close_internal(struct vmbus_channel *channel)
                get_order(channel->ringbuffer_pagecount * PAGE_SIZE));
 
 out:
-       tasklet_enable(tasklet);
+       hv_event_tasklet_enable(channel);
 
        return ret;
 }
@@ -659,7 +657,7 @@ int vmbus_sendpacket_ctl(struct vmbus_channel *channel, void *buffer,
        bufferlist[2].iov_len = (packetlen_aligned - packetlen);
 
        ret = hv_ringbuffer_write(&channel->outbound, bufferlist, num_vecs,
-                                 &signal, lock);
+                                 &signal, lock, channel->signal_policy);
 
        /*
         * Signalling the host is conditional on many factors:
@@ -680,11 +678,6 @@ int vmbus_sendpacket_ctl(struct vmbus_channel *channel, void *buffer,
         * mechanism which can hurt the performance otherwise.
         */
 
-       if (channel->signal_policy)
-               signal = true;
-       else
-               kick_q = true;
-
        if (((ret == 0) && kick_q && signal) ||
            (ret && !is_hvsock_channel(channel)))
                vmbus_setevent(channel);
@@ -777,7 +770,7 @@ int vmbus_sendpacket_pagebuffer_ctl(struct vmbus_channel *channel,
        bufferlist[2].iov_len = (packetlen_aligned - packetlen);
 
        ret = hv_ringbuffer_write(&channel->outbound, bufferlist, 3,
-                                 &signal, lock);
+                                 &signal, lock, channel->signal_policy);
 
        /*
         * Signalling the host is conditional on many factors:
@@ -795,11 +788,6 @@ int vmbus_sendpacket_pagebuffer_ctl(struct vmbus_channel *channel,
         * enough condition that it should not matter.
         */
 
-       if (channel->signal_policy)
-               signal = true;
-       else
-               kick_q = true;
-
        if (((ret == 0) && kick_q && signal) || (ret))
                vmbus_setevent(channel);
 
@@ -861,7 +849,7 @@ int vmbus_sendpacket_mpb_desc(struct vmbus_channel *channel,
        bufferlist[2].iov_len = (packetlen_aligned - packetlen);
 
        ret = hv_ringbuffer_write(&channel->outbound, bufferlist, 3,
-                                 &signal, lock);
+                                 &signal, lock, channel->signal_policy);
 
        if (ret == 0 && signal)
                vmbus_setevent(channel);
@@ -926,7 +914,7 @@ int vmbus_sendpacket_multipagebuffer(struct vmbus_channel *channel,
        bufferlist[2].iov_len = (packetlen_aligned - packetlen);
 
        ret = hv_ringbuffer_write(&channel->outbound, bufferlist, 3,
-                                 &signal, lock);
+                                 &signal, lock, channel->signal_policy);
 
        if (ret == 0 && signal)
                vmbus_setevent(channel);
index b6c1211b4df72959ad0cf4c3a6a5950ca7a560b8..759ba4d624171daf576683e62ba9187bd89a2cbf 100644 (file)
@@ -21,6 +21,7 @@
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include <linux/kernel.h>
+#include <linux/interrupt.h>
 #include <linux/sched.h>
 #include <linux/wait.h>
 #include <linux/mm.h>
@@ -138,10 +139,32 @@ static const struct vmbus_device vmbus_devs[] = {
        },
 };
 
-static u16 hv_get_dev_type(const uuid_le *guid)
+static const struct {
+       uuid_le guid;
+} vmbus_unsupported_devs[] = {
+       { HV_AVMA1_GUID },
+       { HV_AVMA2_GUID },
+       { HV_RDV_GUID   },
+};
+
+static bool is_unsupported_vmbus_devs(const uuid_le *guid)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(vmbus_unsupported_devs); i++)
+               if (!uuid_le_cmp(*guid, vmbus_unsupported_devs[i].guid))
+                       return true;
+       return false;
+}
+
+static u16 hv_get_dev_type(const struct vmbus_channel *channel)
 {
+       const uuid_le *guid = &channel->offermsg.offer.if_type;
        u16 i;
 
+       if (is_hvsock_channel(channel) || is_unsupported_vmbus_devs(guid))
+               return HV_UNKOWN;
+
        for (i = HV_IDE; i < HV_UNKOWN; i++) {
                if (!uuid_le_cmp(*guid, vmbus_devs[i].guid))
                        return i;
@@ -303,16 +326,32 @@ static void vmbus_release_relid(u32 relid)
        vmbus_post_msg(&msg, sizeof(struct vmbus_channel_relid_released));
 }
 
+void hv_event_tasklet_disable(struct vmbus_channel *channel)
+{
+       struct tasklet_struct *tasklet;
+       tasklet = hv_context.event_dpc[channel->target_cpu];
+       tasklet_disable(tasklet);
+}
+
+void hv_event_tasklet_enable(struct vmbus_channel *channel)
+{
+       struct tasklet_struct *tasklet;
+       tasklet = hv_context.event_dpc[channel->target_cpu];
+       tasklet_enable(tasklet);
+
+       /* In case there is any pending event */
+       tasklet_schedule(tasklet);
+}
+
 void hv_process_channel_removal(struct vmbus_channel *channel, u32 relid)
 {
        unsigned long flags;
        struct vmbus_channel *primary_channel;
 
-       vmbus_release_relid(relid);
-
        BUG_ON(!channel->rescind);
        BUG_ON(!mutex_is_locked(&vmbus_connection.channel_mutex));
 
+       hv_event_tasklet_disable(channel);
        if (channel->target_cpu != get_cpu()) {
                put_cpu();
                smp_call_function_single(channel->target_cpu,
@@ -321,6 +360,7 @@ void hv_process_channel_removal(struct vmbus_channel *channel, u32 relid)
                percpu_channel_deq(channel);
                put_cpu();
        }
+       hv_event_tasklet_enable(channel);
 
        if (channel->primary_channel == NULL) {
                list_del(&channel->listentry);
@@ -338,8 +378,11 @@ void hv_process_channel_removal(struct vmbus_channel *channel, u32 relid)
         * We need to free the bit for init_vp_index() to work in the case
         * of sub-channel, when we reload drivers like hv_netvsc.
         */
-       cpumask_clear_cpu(channel->target_cpu,
-                         &primary_channel->alloced_cpus_in_node);
+       if (channel->affinity_policy == HV_LOCALIZED)
+               cpumask_clear_cpu(channel->target_cpu,
+                                 &primary_channel->alloced_cpus_in_node);
+
+       vmbus_release_relid(relid);
 
        free_channel(channel);
 }
@@ -405,10 +448,13 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel)
                        goto err_free_chan;
        }
 
-       dev_type = hv_get_dev_type(&newchannel->offermsg.offer.if_type);
+       dev_type = hv_get_dev_type(newchannel);
+       if (dev_type == HV_NIC)
+               set_channel_signal_state(newchannel, HV_SIGNAL_POLICY_EXPLICIT);
 
        init_vp_index(newchannel, dev_type);
 
+       hv_event_tasklet_disable(newchannel);
        if (newchannel->target_cpu != get_cpu()) {
                put_cpu();
                smp_call_function_single(newchannel->target_cpu,
@@ -418,6 +464,7 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel)
                percpu_channel_enq(newchannel);
                put_cpu();
        }
+       hv_event_tasklet_enable(newchannel);
 
        /*
         * This state is used to indicate a successful open
@@ -463,12 +510,11 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel)
        return;
 
 err_deq_chan:
-       vmbus_release_relid(newchannel->offermsg.child_relid);
-
        mutex_lock(&vmbus_connection.channel_mutex);
        list_del(&newchannel->listentry);
        mutex_unlock(&vmbus_connection.channel_mutex);
 
+       hv_event_tasklet_disable(newchannel);
        if (newchannel->target_cpu != get_cpu()) {
                put_cpu();
                smp_call_function_single(newchannel->target_cpu,
@@ -477,6 +523,9 @@ err_deq_chan:
                percpu_channel_deq(newchannel);
                put_cpu();
        }
+       hv_event_tasklet_enable(newchannel);
+
+       vmbus_release_relid(newchannel->offermsg.child_relid);
 
 err_free_chan:
        free_channel(newchannel);
@@ -522,17 +571,17 @@ static void init_vp_index(struct vmbus_channel *channel, u16 dev_type)
        }
 
        /*
-        * We distribute primary channels evenly across all the available
-        * NUMA nodes and within the assigned NUMA node we will assign the
-        * first available CPU to the primary channel.
-        * The sub-channels will be assigned to the CPUs available in the
-        * NUMA node evenly.
+        * Based on the channel affinity policy, we will assign the NUMA
+        * nodes.
         */
-       if (!primary) {
+
+       if ((channel->affinity_policy == HV_BALANCED) || (!primary)) {
                while (true) {
                        next_node = next_numa_node_id++;
-                       if (next_node == nr_node_ids)
+                       if (next_node == nr_node_ids) {
                                next_node = next_numa_node_id = 0;
+                               continue;
+                       }
                        if (cpumask_empty(cpumask_of_node(next_node)))
                                continue;
                        break;
@@ -556,15 +605,17 @@ static void init_vp_index(struct vmbus_channel *channel, u16 dev_type)
 
        cur_cpu = -1;
 
-       /*
-        * Normally Hyper-V host doesn't create more subchannels than there
-        * are VCPUs on the node but it is possible when not all present VCPUs
-        * on the node are initialized by guest. Clear the alloced_cpus_in_node
-        * to start over.
-        */
-       if (cpumask_equal(&primary->alloced_cpus_in_node,
-                         cpumask_of_node(primary->numa_node)))
-               cpumask_clear(&primary->alloced_cpus_in_node);
+       if (primary->affinity_policy == HV_LOCALIZED) {
+               /*
+                * Normally Hyper-V host doesn't create more subchannels
+                * than there are VCPUs on the node but it is possible when not
+                * all present VCPUs on the node are initialized by guest.
+                * Clear the alloced_cpus_in_node to start over.
+                */
+               if (cpumask_equal(&primary->alloced_cpus_in_node,
+                                 cpumask_of_node(primary->numa_node)))
+                       cpumask_clear(&primary->alloced_cpus_in_node);
+       }
 
        while (true) {
                cur_cpu = cpumask_next(cur_cpu, &available_mask);
@@ -575,17 +626,24 @@ static void init_vp_index(struct vmbus_channel *channel, u16 dev_type)
                        continue;
                }
 
-               /*
-                * NOTE: in the case of sub-channel, we clear the sub-channel
-                * related bit(s) in primary->alloced_cpus_in_node in
-                * hv_process_channel_removal(), so when we reload drivers
-                * like hv_netvsc in SMP guest, here we're able to re-allocate
-                * bit from primary->alloced_cpus_in_node.
-                */
-               if (!cpumask_test_cpu(cur_cpu,
-                               &primary->alloced_cpus_in_node)) {
-                       cpumask_set_cpu(cur_cpu,
-                                       &primary->alloced_cpus_in_node);
+               if (primary->affinity_policy == HV_LOCALIZED) {
+                       /*
+                        * NOTE: in the case of sub-channel, we clear the
+                        * sub-channel related bit(s) in
+                        * primary->alloced_cpus_in_node in
+                        * hv_process_channel_removal(), so when we
+                        * reload drivers like hv_netvsc in SMP guest, here
+                        * we're able to re-allocate
+                        * bit from primary->alloced_cpus_in_node.
+                        */
+                       if (!cpumask_test_cpu(cur_cpu,
+                                             &primary->alloced_cpus_in_node)) {
+                               cpumask_set_cpu(cur_cpu,
+                                               &primary->alloced_cpus_in_node);
+                               cpumask_set_cpu(cur_cpu, alloced_mask);
+                               break;
+                       }
+               } else {
                        cpumask_set_cpu(cur_cpu, alloced_mask);
                        break;
                }
index fcf8a02dc0eadb04522ce782be64a37dc8014813..78e6368a4423cfab47d9d697c1510550d1188ad3 100644 (file)
@@ -439,7 +439,7 @@ int vmbus_post_msg(void *buffer, size_t buflen)
        union hv_connection_id conn_id;
        int ret = 0;
        int retries = 0;
-       u32 msec = 1;
+       u32 usec = 1;
 
        conn_id.asu32 = 0;
        conn_id.u.id = VMBUS_MESSAGE_CONNECTION_ID;
@@ -472,9 +472,9 @@ int vmbus_post_msg(void *buffer, size_t buflen)
                }
 
                retries++;
-               msleep(msec);
-               if (msec < 2048)
-                       msec *= 2;
+               udelay(usec);
+               if (usec < 2048)
+                       usec *= 2;
        }
        return ret;
 }
index a1c086ba3b9a0736c522d648092d04d4ac92a3c7..60dbd6cb4640cd6caeb36a8c07585660d812f3b9 100644 (file)
@@ -278,7 +278,7 @@ cleanup:
  *
  * This routine is called normally during driver unloading or exiting.
  */
-void hv_cleanup(void)
+void hv_cleanup(bool crash)
 {
        union hv_x64_msr_hypercall_contents hypercall_msr;
 
@@ -288,7 +288,8 @@ void hv_cleanup(void)
        if (hv_context.hypercall_page) {
                hypercall_msr.as_uint64 = 0;
                wrmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
-               vfree(hv_context.hypercall_page);
+               if (!crash)
+                       vfree(hv_context.hypercall_page);
                hv_context.hypercall_page = NULL;
        }
 
@@ -308,7 +309,8 @@ void hv_cleanup(void)
 
                hypercall_msr.as_uint64 = 0;
                wrmsrl(HV_X64_MSR_REFERENCE_TSC, hypercall_msr.as_uint64);
-               vfree(hv_context.tsc_page);
+               if (!crash)
+                       vfree(hv_context.tsc_page);
                hv_context.tsc_page = NULL;
        }
 #endif
index df35fb7ed5dfcf4e782839616c26533159f5b5a4..fdf8da929cbea6f3962f19b1ccc6110de22b1adc 100644 (file)
@@ -430,16 +430,27 @@ struct dm_info_msg {
  * currently hot added. We hot add in multiples of 128M
  * chunks; it is possible that we may not be able to bring
  * online all the pages in the region. The range
- * covered_end_pfn defines the pages that can
+ * covered_start_pfn:covered_end_pfn defines the pages that can
  * be brough online.
  */
 
 struct hv_hotadd_state {
        struct list_head list;
        unsigned long start_pfn;
+       unsigned long covered_start_pfn;
        unsigned long covered_end_pfn;
        unsigned long ha_end_pfn;
        unsigned long end_pfn;
+       /*
+        * A list of gaps.
+        */
+       struct list_head gap_list;
+};
+
+struct hv_hotadd_gap {
+       struct list_head list;
+       unsigned long start_pfn;
+       unsigned long end_pfn;
 };
 
 struct balloon_state {
@@ -536,7 +547,11 @@ struct hv_dynmem_device {
         */
        struct task_struct *thread;
 
-       struct mutex ha_region_mutex;
+       /*
+        * Protects ha_region_list, num_pages_onlined counter and individual
+        * regions from ha_region_list.
+        */
+       spinlock_t ha_lock;
 
        /*
         * A list of hot-add regions.
@@ -560,18 +575,14 @@ static int hv_memory_notifier(struct notifier_block *nb, unsigned long val,
                              void *v)
 {
        struct memory_notify *mem = (struct memory_notify *)v;
+       unsigned long flags;
 
        switch (val) {
-       case MEM_GOING_ONLINE:
-               mutex_lock(&dm_device.ha_region_mutex);
-               break;
-
        case MEM_ONLINE:
+               spin_lock_irqsave(&dm_device.ha_lock, flags);
                dm_device.num_pages_onlined += mem->nr_pages;
+               spin_unlock_irqrestore(&dm_device.ha_lock, flags);
        case MEM_CANCEL_ONLINE:
-               if (val == MEM_ONLINE ||
-                   mutex_is_locked(&dm_device.ha_region_mutex))
-                       mutex_unlock(&dm_device.ha_region_mutex);
                if (dm_device.ha_waiting) {
                        dm_device.ha_waiting = false;
                        complete(&dm_device.ol_waitevent);
@@ -579,10 +590,11 @@ static int hv_memory_notifier(struct notifier_block *nb, unsigned long val,
                break;
 
        case MEM_OFFLINE:
-               mutex_lock(&dm_device.ha_region_mutex);
+               spin_lock_irqsave(&dm_device.ha_lock, flags);
                dm_device.num_pages_onlined -= mem->nr_pages;
-               mutex_unlock(&dm_device.ha_region_mutex);
+               spin_unlock_irqrestore(&dm_device.ha_lock, flags);
                break;
+       case MEM_GOING_ONLINE:
        case MEM_GOING_OFFLINE:
        case MEM_CANCEL_OFFLINE:
                break;
@@ -595,18 +607,46 @@ static struct notifier_block hv_memory_nb = {
        .priority = 0
 };
 
+/* Check if the particular page is backed and can be onlined and online it. */
+static void hv_page_online_one(struct hv_hotadd_state *has, struct page *pg)
+{
+       unsigned long cur_start_pgp;
+       unsigned long cur_end_pgp;
+       struct hv_hotadd_gap *gap;
+
+       cur_start_pgp = (unsigned long)pfn_to_page(has->covered_start_pfn);
+       cur_end_pgp = (unsigned long)pfn_to_page(has->covered_end_pfn);
+
+       /* The page is not backed. */
+       if (((unsigned long)pg < cur_start_pgp) ||
+           ((unsigned long)pg >= cur_end_pgp))
+               return;
+
+       /* Check for gaps. */
+       list_for_each_entry(gap, &has->gap_list, list) {
+               cur_start_pgp = (unsigned long)
+                       pfn_to_page(gap->start_pfn);
+               cur_end_pgp = (unsigned long)
+                       pfn_to_page(gap->end_pfn);
+               if (((unsigned long)pg >= cur_start_pgp) &&
+                   ((unsigned long)pg < cur_end_pgp)) {
+                       return;
+               }
+       }
+
+       /* This frame is currently backed; online the page. */
+       __online_page_set_limits(pg);
+       __online_page_increment_counters(pg);
+       __online_page_free(pg);
+}
 
-static void hv_bring_pgs_online(unsigned long start_pfn, unsigned long size)
+static void hv_bring_pgs_online(struct hv_hotadd_state *has,
+                               unsigned long start_pfn, unsigned long size)
 {
        int i;
 
-       for (i = 0; i < size; i++) {
-               struct page *pg;
-               pg = pfn_to_page(start_pfn + i);
-               __online_page_set_limits(pg);
-               __online_page_increment_counters(pg);
-               __online_page_free(pg);
-       }
+       for (i = 0; i < size; i++)
+               hv_page_online_one(has, pfn_to_page(start_pfn + i));
 }
 
 static void hv_mem_hot_add(unsigned long start, unsigned long size,
@@ -618,9 +658,12 @@ static void hv_mem_hot_add(unsigned long start, unsigned long size,
        unsigned long start_pfn;
        unsigned long processed_pfn;
        unsigned long total_pfn = pfn_count;
+       unsigned long flags;
 
        for (i = 0; i < (size/HA_CHUNK); i++) {
                start_pfn = start + (i * HA_CHUNK);
+
+               spin_lock_irqsave(&dm_device.ha_lock, flags);
                has->ha_end_pfn +=  HA_CHUNK;
 
                if (total_pfn > HA_CHUNK) {
@@ -632,11 +675,11 @@ static void hv_mem_hot_add(unsigned long start, unsigned long size,
                }
 
                has->covered_end_pfn +=  processed_pfn;
+               spin_unlock_irqrestore(&dm_device.ha_lock, flags);
 
                init_completion(&dm_device.ol_waitevent);
-               dm_device.ha_waiting = true;
+               dm_device.ha_waiting = !memhp_auto_online;
 
-               mutex_unlock(&dm_device.ha_region_mutex);
                nid = memory_add_physaddr_to_nid(PFN_PHYS(start_pfn));
                ret = add_memory(nid, PFN_PHYS((start_pfn)),
                                (HA_CHUNK << PAGE_SHIFT));
@@ -653,20 +696,23 @@ static void hv_mem_hot_add(unsigned long start, unsigned long size,
                                 */
                                do_hot_add = false;
                        }
+                       spin_lock_irqsave(&dm_device.ha_lock, flags);
                        has->ha_end_pfn -= HA_CHUNK;
                        has->covered_end_pfn -=  processed_pfn;
-                       mutex_lock(&dm_device.ha_region_mutex);
+                       spin_unlock_irqrestore(&dm_device.ha_lock, flags);
                        break;
                }
 
                /*
-                * Wait for the memory block to be onlined.
-                * Since the hot add has succeeded, it is ok to
-                * proceed even if the pages in the hot added region
-                * have not been "onlined" within the allowed time.
+                * Wait for the memory block to be onlined when memory onlining
+                * is done outside of kernel (memhp_auto_online). Since the hot
+                * add has succeeded, it is ok to proceed even if the pages in
+                * the hot added region have not been "onlined" within the
+                * allowed time.
                 */
-               wait_for_completion_timeout(&dm_device.ol_waitevent, 5*HZ);
-               mutex_lock(&dm_device.ha_region_mutex);
+               if (dm_device.ha_waiting)
+                       wait_for_completion_timeout(&dm_device.ol_waitevent,
+                                                   5*HZ);
                post_status(&dm_device);
        }
 
@@ -675,47 +721,64 @@ static void hv_mem_hot_add(unsigned long start, unsigned long size,
 
 static void hv_online_page(struct page *pg)
 {
-       struct list_head *cur;
        struct hv_hotadd_state *has;
        unsigned long cur_start_pgp;
        unsigned long cur_end_pgp;
+       unsigned long flags;
 
-       list_for_each(cur, &dm_device.ha_region_list) {
-               has = list_entry(cur, struct hv_hotadd_state, list);
-               cur_start_pgp = (unsigned long)pfn_to_page(has->start_pfn);
-               cur_end_pgp = (unsigned long)pfn_to_page(has->covered_end_pfn);
+       spin_lock_irqsave(&dm_device.ha_lock, flags);
+       list_for_each_entry(has, &dm_device.ha_region_list, list) {
+               cur_start_pgp = (unsigned long)
+                       pfn_to_page(has->start_pfn);
+               cur_end_pgp = (unsigned long)pfn_to_page(has->end_pfn);
 
-               if (((unsigned long)pg >= cur_start_pgp) &&
-                       ((unsigned long)pg < cur_end_pgp)) {
-                       /*
-                        * This frame is currently backed; online the
-                        * page.
-                        */
-                       __online_page_set_limits(pg);
-                       __online_page_increment_counters(pg);
-                       __online_page_free(pg);
-               }
+               /* The page belongs to a different HAS. */
+               if (((unsigned long)pg < cur_start_pgp) ||
+                   ((unsigned long)pg >= cur_end_pgp))
+                       continue;
+
+               hv_page_online_one(has, pg);
+               break;
        }
+       spin_unlock_irqrestore(&dm_device.ha_lock, flags);
 }
 
-static bool pfn_covered(unsigned long start_pfn, unsigned long pfn_cnt)
+static int pfn_covered(unsigned long start_pfn, unsigned long pfn_cnt)
 {
-       struct list_head *cur;
        struct hv_hotadd_state *has;
+       struct hv_hotadd_gap *gap;
        unsigned long residual, new_inc;
+       int ret = 0;
+       unsigned long flags;
 
-       if (list_empty(&dm_device.ha_region_list))
-               return false;
-
-       list_for_each(cur, &dm_device.ha_region_list) {
-               has = list_entry(cur, struct hv_hotadd_state, list);
-
+       spin_lock_irqsave(&dm_device.ha_lock, flags);
+       list_for_each_entry(has, &dm_device.ha_region_list, list) {
                /*
                 * If the pfn range we are dealing with is not in the current
                 * "hot add block", move on.
                 */
                if (start_pfn < has->start_pfn || start_pfn >= has->end_pfn)
                        continue;
+
+               /*
+                * If the current start pfn is not where the covered_end
+                * is, create a gap and update covered_end_pfn.
+                */
+               if (has->covered_end_pfn != start_pfn) {
+                       gap = kzalloc(sizeof(struct hv_hotadd_gap), GFP_ATOMIC);
+                       if (!gap) {
+                               ret = -ENOMEM;
+                               break;
+                       }
+
+                       INIT_LIST_HEAD(&gap->list);
+                       gap->start_pfn = has->covered_end_pfn;
+                       gap->end_pfn = start_pfn;
+                       list_add_tail(&gap->list, &has->gap_list);
+
+                       has->covered_end_pfn = start_pfn;
+               }
+
                /*
                 * If the current hot add-request extends beyond
                 * our current limit; extend it.
@@ -732,19 +795,12 @@ static bool pfn_covered(unsigned long start_pfn, unsigned long pfn_cnt)
                        has->end_pfn += new_inc;
                }
 
-               /*
-                * If the current start pfn is not where the covered_end
-                * is, update it.
-                */
-
-               if (has->covered_end_pfn != start_pfn)
-                       has->covered_end_pfn = start_pfn;
-
-               return true;
-
+               ret = 1;
+               break;
        }
+       spin_unlock_irqrestore(&dm_device.ha_lock, flags);
 
-       return false;
+       return ret;
 }
 
 static unsigned long handle_pg_range(unsigned long pg_start,
@@ -753,17 +809,13 @@ static unsigned long handle_pg_range(unsigned long pg_start,
        unsigned long start_pfn = pg_start;
        unsigned long pfn_cnt = pg_count;
        unsigned long size;
-       struct list_head *cur;
        struct hv_hotadd_state *has;
        unsigned long pgs_ol = 0;
        unsigned long old_covered_state;
+       unsigned long res = 0, flags;
 
-       if (list_empty(&dm_device.ha_region_list))
-               return 0;
-
-       list_for_each(cur, &dm_device.ha_region_list) {
-               has = list_entry(cur, struct hv_hotadd_state, list);
-
+       spin_lock_irqsave(&dm_device.ha_lock, flags);
+       list_for_each_entry(has, &dm_device.ha_region_list, list) {
                /*
                 * If the pfn range we are dealing with is not in the current
                 * "hot add block", move on.
@@ -783,6 +835,8 @@ static unsigned long handle_pg_range(unsigned long pg_start,
                        if (pgs_ol > pfn_cnt)
                                pgs_ol = pfn_cnt;
 
+                       has->covered_end_pfn +=  pgs_ol;
+                       pfn_cnt -= pgs_ol;
                        /*
                         * Check if the corresponding memory block is already
                         * online by checking its last previously backed page.
@@ -791,10 +845,8 @@ static unsigned long handle_pg_range(unsigned long pg_start,
                         */
                        if (start_pfn > has->start_pfn &&
                            !PageReserved(pfn_to_page(start_pfn - 1)))
-                               hv_bring_pgs_online(start_pfn, pgs_ol);
+                               hv_bring_pgs_online(has, start_pfn, pgs_ol);
 
-                       has->covered_end_pfn +=  pgs_ol;
-                       pfn_cnt -= pgs_ol;
                }
 
                if ((has->ha_end_pfn < has->end_pfn) && (pfn_cnt > 0)) {
@@ -813,17 +865,20 @@ static unsigned long handle_pg_range(unsigned long pg_start,
                        } else {
                                pfn_cnt = size;
                        }
+                       spin_unlock_irqrestore(&dm_device.ha_lock, flags);
                        hv_mem_hot_add(has->ha_end_pfn, size, pfn_cnt, has);
+                       spin_lock_irqsave(&dm_device.ha_lock, flags);
                }
                /*
                 * If we managed to online any pages that were given to us,
                 * we declare success.
                 */
-               return has->covered_end_pfn - old_covered_state;
-
+               res = has->covered_end_pfn - old_covered_state;
+               break;
        }
+       spin_unlock_irqrestore(&dm_device.ha_lock, flags);
 
-       return 0;
+       return res;
 }
 
 static unsigned long process_hot_add(unsigned long pg_start,
@@ -832,13 +887,20 @@ static unsigned long process_hot_add(unsigned long pg_start,
                                        unsigned long rg_size)
 {
        struct hv_hotadd_state *ha_region = NULL;
+       int covered;
+       unsigned long flags;
 
        if (pfn_cnt == 0)
                return 0;
 
-       if (!dm_device.host_specified_ha_region)
-               if (pfn_covered(pg_start, pfn_cnt))
+       if (!dm_device.host_specified_ha_region) {
+               covered = pfn_covered(pg_start, pfn_cnt);
+               if (covered < 0)
+                       return 0;
+
+               if (covered)
                        goto do_pg_range;
+       }
 
        /*
         * If the host has specified a hot-add range; deal with it first.
@@ -850,12 +912,17 @@ static unsigned long process_hot_add(unsigned long pg_start,
                        return 0;
 
                INIT_LIST_HEAD(&ha_region->list);
+               INIT_LIST_HEAD(&ha_region->gap_list);
 
-               list_add_tail(&ha_region->list, &dm_device.ha_region_list);
                ha_region->start_pfn = rg_start;
                ha_region->ha_end_pfn = rg_start;
+               ha_region->covered_start_pfn = pg_start;
                ha_region->covered_end_pfn = pg_start;
                ha_region->end_pfn = rg_start + rg_size;
+
+               spin_lock_irqsave(&dm_device.ha_lock, flags);
+               list_add_tail(&ha_region->list, &dm_device.ha_region_list);
+               spin_unlock_irqrestore(&dm_device.ha_lock, flags);
        }
 
 do_pg_range:
@@ -882,7 +949,6 @@ static void hot_add_req(struct work_struct *dummy)
        resp.hdr.size = sizeof(struct dm_hot_add_response);
 
 #ifdef CONFIG_MEMORY_HOTPLUG
-       mutex_lock(&dm_device.ha_region_mutex);
        pg_start = dm->ha_wrk.ha_page_range.finfo.start_page;
        pfn_cnt = dm->ha_wrk.ha_page_range.finfo.page_cnt;
 
@@ -916,7 +982,6 @@ static void hot_add_req(struct work_struct *dummy)
                                                rg_start, rg_sz);
 
        dm->num_pages_added += resp.page_count;
-       mutex_unlock(&dm_device.ha_region_mutex);
 #endif
        /*
         * The result field of the response structure has the
@@ -1010,7 +1075,6 @@ static unsigned long compute_balloon_floor(void)
 static void post_status(struct hv_dynmem_device *dm)
 {
        struct dm_status status;
-       struct sysinfo val;
        unsigned long now = jiffies;
        unsigned long last_post = last_post_time;
 
@@ -1022,7 +1086,6 @@ static void post_status(struct hv_dynmem_device *dm)
        if (!time_after(now, (last_post_time + HZ)))
                return;
 
-       si_meminfo(&val);
        memset(&status, 0, sizeof(struct dm_status));
        status.hdr.type = DM_STATUS_REPORT;
        status.hdr.size = sizeof(struct dm_status);
@@ -1038,7 +1101,7 @@ static void post_status(struct hv_dynmem_device *dm)
         * num_pages_onlined) as committed to the host, otherwise it can try
         * asking us to balloon them out.
         */
-       status.num_avail = val.freeram;
+       status.num_avail = si_mem_available();
        status.num_committed = vm_memory_committed() +
                dm->num_pages_ballooned +
                (dm->num_pages_added > dm->num_pages_onlined ?
@@ -1144,7 +1207,7 @@ static void balloon_up(struct work_struct *dummy)
        int ret;
        bool done = false;
        int i;
-       struct sysinfo val;
+       long avail_pages;
        unsigned long floor;
 
        /* The host balloons pages in 2M granularity. */
@@ -1156,12 +1219,12 @@ static void balloon_up(struct work_struct *dummy)
         */
        alloc_unit = 512;
 
-       si_meminfo(&val);
+       avail_pages = si_mem_available();
        floor = compute_balloon_floor();
 
        /* Refuse to balloon below the floor, keep the 2M granularity. */
-       if (val.freeram < num_pages || val.freeram - num_pages < floor) {
-               num_pages = val.freeram > floor ? (val.freeram - floor) : 0;
+       if (avail_pages < num_pages || avail_pages - num_pages < floor) {
+               num_pages = avail_pages > floor ? (avail_pages - floor) : 0;
                num_pages -= num_pages % PAGES_IN_2M;
        }
 
@@ -1172,7 +1235,6 @@ static void balloon_up(struct work_struct *dummy)
                bl_resp->hdr.size = sizeof(struct dm_balloon_response);
                bl_resp->more_pages = 1;
 
-
                num_pages -= num_ballooned;
                num_ballooned = alloc_balloon_pages(&dm_device, num_pages,
                                                    bl_resp, alloc_unit);
@@ -1461,7 +1523,7 @@ static int balloon_probe(struct hv_device *dev,
        init_completion(&dm_device.host_event);
        init_completion(&dm_device.config_event);
        INIT_LIST_HEAD(&dm_device.ha_region_list);
-       mutex_init(&dm_device.ha_region_mutex);
+       spin_lock_init(&dm_device.ha_lock);
        INIT_WORK(&dm_device.balloon_wrk.wrk, balloon_up);
        INIT_WORK(&dm_device.ha_wrk.wrk, hot_add_req);
        dm_device.host_specified_ha_region = false;
@@ -1580,8 +1642,9 @@ probe_error0:
 static int balloon_remove(struct hv_device *dev)
 {
        struct hv_dynmem_device *dm = hv_get_drvdata(dev);
-       struct list_head *cur, *tmp;
-       struct hv_hotadd_state *has;
+       struct hv_hotadd_state *has, *tmp;
+       struct hv_hotadd_gap *gap, *tmp_gap;
+       unsigned long flags;
 
        if (dm->num_pages_ballooned != 0)
                pr_warn("Ballooned pages: %d\n", dm->num_pages_ballooned);
@@ -1596,11 +1659,16 @@ static int balloon_remove(struct hv_device *dev)
        restore_online_page_callback(&hv_online_page);
        unregister_memory_notifier(&hv_memory_nb);
 #endif
-       list_for_each_safe(cur, tmp, &dm->ha_region_list) {
-               has = list_entry(cur, struct hv_hotadd_state, list);
+       spin_lock_irqsave(&dm_device.ha_lock, flags);
+       list_for_each_entry_safe(has, tmp, &dm->ha_region_list, list) {
+               list_for_each_entry_safe(gap, tmp_gap, &has->gap_list, list) {
+                       list_del(&gap->list);
+                       kfree(gap);
+               }
                list_del(&has->list);
                kfree(has);
        }
+       spin_unlock_irqrestore(&dm_device.ha_lock, flags);
 
        return 0;
 }
index 23c70799ad8ace23b5c83ae4a47d1e781d623313..8b2ba98831ec52a5ed60b4a06097db48e781daf9 100644 (file)
@@ -83,6 +83,12 @@ static void fcopy_timeout_func(struct work_struct *dummy)
        hv_poll_channel(fcopy_transaction.recv_channel, fcopy_poll_wrapper);
 }
 
+static void fcopy_register_done(void)
+{
+       pr_debug("FCP: userspace daemon registered\n");
+       hv_poll_channel(fcopy_transaction.recv_channel, fcopy_poll_wrapper);
+}
+
 static int fcopy_handle_handshake(u32 version)
 {
        u32 our_ver = FCOPY_CURRENT_VERSION;
@@ -94,7 +100,8 @@ static int fcopy_handle_handshake(u32 version)
                break;
        case FCOPY_VERSION_1:
                /* Daemon expects us to reply with our own version */
-               if (hvutil_transport_send(hvt, &our_ver, sizeof(our_ver)))
+               if (hvutil_transport_send(hvt, &our_ver, sizeof(our_ver),
+                   fcopy_register_done))
                        return -EFAULT;
                dm_reg_value = version;
                break;
@@ -107,8 +114,7 @@ static int fcopy_handle_handshake(u32 version)
                 */
                return -EINVAL;
        }
-       pr_debug("FCP: userspace daemon ver. %d registered\n", version);
-       hv_poll_channel(fcopy_transaction.recv_channel, fcopy_poll_wrapper);
+       pr_debug("FCP: userspace daemon ver. %d connected\n", version);
        return 0;
 }
 
@@ -161,7 +167,7 @@ static void fcopy_send_data(struct work_struct *dummy)
        }
 
        fcopy_transaction.state = HVUTIL_USERSPACE_REQ;
-       rc = hvutil_transport_send(hvt, out_src, out_len);
+       rc = hvutil_transport_send(hvt, out_src, out_len, NULL);
        if (rc) {
                pr_debug("FCP: failed to communicate to the daemon: %d\n", rc);
                if (cancel_delayed_work_sync(&fcopy_timeout_work)) {
index cb1a9160aab15064d95f710755ba4acdcad2eb69..5e1fdc8d32ab0c03d25bfcf7d3fbadbcedc6f2eb 100644 (file)
@@ -102,6 +102,17 @@ static void kvp_poll_wrapper(void *channel)
        hv_kvp_onchannelcallback(channel);
 }
 
+static void kvp_register_done(void)
+{
+       /*
+        * If we're still negotiating with the host cancel the timeout
+        * work to not poll the channel twice.
+        */
+       pr_debug("KVP: userspace daemon registered\n");
+       cancel_delayed_work_sync(&kvp_host_handshake_work);
+       hv_poll_channel(kvp_transaction.recv_channel, kvp_poll_wrapper);
+}
+
 static void
 kvp_register(int reg_value)
 {
@@ -116,7 +127,8 @@ kvp_register(int reg_value)
                kvp_msg->kvp_hdr.operation = reg_value;
                strcpy(version, HV_DRV_VERSION);
 
-               hvutil_transport_send(hvt, kvp_msg, sizeof(*kvp_msg));
+               hvutil_transport_send(hvt, kvp_msg, sizeof(*kvp_msg),
+                                     kvp_register_done);
                kfree(kvp_msg);
        }
 }
@@ -158,17 +170,10 @@ static int kvp_handle_handshake(struct hv_kvp_msg *msg)
        /*
         * We have a compatible daemon; complete the handshake.
         */
-       pr_debug("KVP: userspace daemon ver. %d registered\n",
-                KVP_OP_REGISTER);
+       pr_debug("KVP: userspace daemon ver. %d connected\n",
+                msg->kvp_hdr.operation);
        kvp_register(dm_reg_value);
 
-       /*
-        * If we're still negotiating with the host cancel the timeout
-        * work to not poll the channel twice.
-        */
-       cancel_delayed_work_sync(&kvp_host_handshake_work);
-       hv_poll_channel(kvp_transaction.recv_channel, kvp_poll_wrapper);
-
        return 0;
 }
 
@@ -455,7 +460,7 @@ kvp_send_key(struct work_struct *dummy)
        }
 
        kvp_transaction.state = HVUTIL_USERSPACE_REQ;
-       rc = hvutil_transport_send(hvt, message, sizeof(*message));
+       rc = hvutil_transport_send(hvt, message, sizeof(*message), NULL);
        if (rc) {
                pr_debug("KVP: failed to communicate to the daemon: %d\n", rc);
                if (cancel_delayed_work_sync(&kvp_timeout_work)) {
index 3fba14e88f038ffeee4f256c87bdc66fafc01b07..a6707133c297c7a1435b1bdcda446256671fc080 100644 (file)
@@ -67,11 +67,11 @@ static const char vss_devname[] = "vmbus/hv_vss";
 static __u8 *recv_buffer;
 static struct hvutil_transport *hvt;
 
-static void vss_send_op(struct work_struct *dummy);
 static void vss_timeout_func(struct work_struct *dummy);
+static void vss_handle_request(struct work_struct *dummy);
 
 static DECLARE_DELAYED_WORK(vss_timeout_work, vss_timeout_func);
-static DECLARE_WORK(vss_send_op_work, vss_send_op);
+static DECLARE_WORK(vss_handle_request_work, vss_handle_request);
 
 static void vss_poll_wrapper(void *channel)
 {
@@ -95,6 +95,12 @@ static void vss_timeout_func(struct work_struct *dummy)
        hv_poll_channel(vss_transaction.recv_channel, vss_poll_wrapper);
 }
 
+static void vss_register_done(void)
+{
+       hv_poll_channel(vss_transaction.recv_channel, vss_poll_wrapper);
+       pr_debug("VSS: userspace daemon registered\n");
+}
+
 static int vss_handle_handshake(struct hv_vss_msg *vss_msg)
 {
        u32 our_ver = VSS_OP_REGISTER1;
@@ -105,16 +111,16 @@ static int vss_handle_handshake(struct hv_vss_msg *vss_msg)
                dm_reg_value = VSS_OP_REGISTER;
                break;
        case VSS_OP_REGISTER1:
-               /* Daemon expects us to reply with our own version*/
-               if (hvutil_transport_send(hvt, &our_ver, sizeof(our_ver)))
+               /* Daemon expects us to reply with our own version */
+               if (hvutil_transport_send(hvt, &our_ver, sizeof(our_ver),
+                                         vss_register_done))
                        return -EFAULT;
                dm_reg_value = VSS_OP_REGISTER1;
                break;
        default:
                return -EINVAL;
        }
-       hv_poll_channel(vss_transaction.recv_channel, vss_poll_wrapper);
-       pr_debug("VSS: userspace daemon ver. %d registered\n", dm_reg_value);
+       pr_debug("VSS: userspace daemon ver. %d connected\n", dm_reg_value);
        return 0;
 }
 
@@ -136,6 +142,11 @@ static int vss_on_msg(void *msg, int len)
                return vss_handle_handshake(vss_msg);
        } else if (vss_transaction.state == HVUTIL_USERSPACE_REQ) {
                vss_transaction.state = HVUTIL_USERSPACE_RECV;
+
+               if (vss_msg->vss_hdr.operation == VSS_OP_HOT_BACKUP)
+                       vss_transaction.msg->vss_cf.flags =
+                               VSS_HBU_NO_AUTO_RECOVERY;
+
                if (cancel_delayed_work_sync(&vss_timeout_work)) {
                        vss_respond_to_host(vss_msg->error);
                        /* Transaction is finished, reset the state. */
@@ -150,8 +161,7 @@ static int vss_on_msg(void *msg, int len)
        return 0;
 }
 
-
-static void vss_send_op(struct work_struct *dummy)
+static void vss_send_op(void)
 {
        int op = vss_transaction.msg->vss_hdr.operation;
        int rc;
@@ -168,7 +178,10 @@ static void vss_send_op(struct work_struct *dummy)
        vss_msg->vss_hdr.operation = op;
 
        vss_transaction.state = HVUTIL_USERSPACE_REQ;
-       rc = hvutil_transport_send(hvt, vss_msg, sizeof(*vss_msg));
+
+       schedule_delayed_work(&vss_timeout_work, VSS_USERSPACE_TIMEOUT);
+
+       rc = hvutil_transport_send(hvt, vss_msg, sizeof(*vss_msg), NULL);
        if (rc) {
                pr_warn("VSS: failed to communicate to the daemon: %d\n", rc);
                if (cancel_delayed_work_sync(&vss_timeout_work)) {
@@ -182,6 +195,38 @@ static void vss_send_op(struct work_struct *dummy)
        return;
 }
 
+static void vss_handle_request(struct work_struct *dummy)
+{
+       switch (vss_transaction.msg->vss_hdr.operation) {
+       /*
+        * Initiate a "freeze/thaw" operation in the guest.
+        * We respond to the host once the operation is complete.
+        *
+        * We send the message to the user space daemon and the operation is
+        * performed in the daemon.
+        */
+       case VSS_OP_THAW:
+       case VSS_OP_FREEZE:
+       case VSS_OP_HOT_BACKUP:
+               if (vss_transaction.state < HVUTIL_READY) {
+                       /* Userspace is not registered yet */
+                       vss_respond_to_host(HV_E_FAIL);
+                       return;
+               }
+               vss_transaction.state = HVUTIL_HOSTMSG_RECEIVED;
+               vss_send_op();
+               return;
+       case VSS_OP_GET_DM_INFO:
+               vss_transaction.msg->dm_info.flags = 0;
+               break;
+       default:
+               break;
+       }
+
+       vss_respond_to_host(0);
+       hv_poll_channel(vss_transaction.recv_channel, vss_poll_wrapper);
+}
+
 /*
  * Send a response back to the host.
  */
@@ -266,48 +311,8 @@ void hv_vss_onchannelcallback(void *context)
                        vss_transaction.recv_req_id = requestid;
                        vss_transaction.msg = (struct hv_vss_msg *)vss_msg;
 
-                       switch (vss_msg->vss_hdr.operation) {
-                               /*
-                                * Initiate a "freeze/thaw"
-                                * operation in the guest.
-                                * We respond to the host once
-                                * the operation is complete.
-                                *
-                                * We send the message to the
-                                * user space daemon and the
-                                * operation is performed in
-                                * the daemon.
-                                */
-                       case VSS_OP_FREEZE:
-                       case VSS_OP_THAW:
-                               if (vss_transaction.state < HVUTIL_READY) {
-                                       /* Userspace is not registered yet */
-                                       vss_respond_to_host(HV_E_FAIL);
-                                       return;
-                               }
-                               vss_transaction.state = HVUTIL_HOSTMSG_RECEIVED;
-                               schedule_work(&vss_send_op_work);
-                               schedule_delayed_work(&vss_timeout_work,
-                                                     VSS_USERSPACE_TIMEOUT);
-                               return;
-
-                       case VSS_OP_HOT_BACKUP:
-                               vss_msg->vss_cf.flags =
-                                        VSS_HBU_NO_AUTO_RECOVERY;
-                               vss_respond_to_host(0);
-                               return;
-
-                       case VSS_OP_GET_DM_INFO:
-                               vss_msg->dm_info.flags = 0;
-                               vss_respond_to_host(0);
-                               return;
-
-                       default:
-                               vss_respond_to_host(0);
-                               return;
-
-                       }
-
+                       schedule_work(&vss_handle_request_work);
+                       return;
                }
 
                icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION
@@ -358,6 +363,6 @@ void hv_vss_deinit(void)
 {
        vss_transaction.state = HVUTIL_DEVICE_DYING;
        cancel_delayed_work_sync(&vss_timeout_work);
-       cancel_work_sync(&vss_send_op_work);
+       cancel_work_sync(&vss_handle_request_work);
        hvutil_transport_destroy(hvt);
 }
index d5acaa2d8e61d0a63f8dfcf65023c3aee6aa40b3..4aa3cb63fd41f4506254187608c995e22359aa28 100644 (file)
 #define SD_MINOR       0
 #define SD_VERSION     (SD_MAJOR << 16 | SD_MINOR)
 
-#define SD_WS2008_MAJOR                1
-#define SD_WS2008_VERSION      (SD_WS2008_MAJOR << 16 | SD_MINOR)
+#define SD_MAJOR_1     1
+#define SD_VERSION_1   (SD_MAJOR_1 << 16 | SD_MINOR)
 
-#define TS_MAJOR       3
+#define TS_MAJOR       4
 #define TS_MINOR       0
 #define TS_VERSION     (TS_MAJOR << 16 | TS_MINOR)
 
-#define TS_WS2008_MAJOR                1
-#define TS_WS2008_VERSION      (TS_WS2008_MAJOR << 16 | TS_MINOR)
+#define TS_MAJOR_1     1
+#define TS_VERSION_1   (TS_MAJOR_1 << 16 | TS_MINOR)
+
+#define TS_MAJOR_3     3
+#define TS_VERSION_3   (TS_MAJOR_3 << 16 | TS_MINOR)
 
 #define HB_MAJOR       3
-#define HB_MINOR 0
+#define HB_MINOR       0
 #define HB_VERSION     (HB_MAJOR << 16 | HB_MINOR)
 
-#define HB_WS2008_MAJOR        1
-#define HB_WS2008_VERSION      (HB_WS2008_MAJOR << 16 | HB_MINOR)
+#define HB_MAJOR_1     1
+#define HB_VERSION_1   (HB_MAJOR_1 << 16 | HB_MINOR)
 
 static int sd_srv_version;
 static int ts_srv_version;
@@ -61,9 +64,14 @@ static struct hv_util_service util_shutdown = {
        .util_cb = shutdown_onchannelcallback,
 };
 
+static int hv_timesync_init(struct hv_util_service *srv);
+static void hv_timesync_deinit(void);
+
 static void timesync_onchannelcallback(void *context);
 static struct hv_util_service util_timesynch = {
        .util_cb = timesync_onchannelcallback,
+       .util_init = hv_timesync_init,
+       .util_deinit = hv_timesync_deinit,
 };
 
 static void heartbeat_onchannelcallback(void *context);
@@ -160,20 +168,6 @@ static void shutdown_onchannelcallback(void *context)
                schedule_work(&shutdown_work);
 }
 
-/*
- * Set guest time to host UTC time.
- */
-static inline void do_adj_guesttime(u64 hosttime)
-{
-       s64 host_tns;
-       struct timespec host_ts;
-
-       host_tns = (hosttime - WLTIMEDELTA) * 100;
-       host_ts = ns_to_timespec(host_tns);
-
-       do_settimeofday(&host_ts);
-}
-
 /*
  * Set the host time in a process context.
  */
@@ -181,15 +175,37 @@ static inline void do_adj_guesttime(u64 hosttime)
 struct adj_time_work {
        struct work_struct work;
        u64     host_time;
+       u64     ref_time;
+       u8      flags;
 };
 
 static void hv_set_host_time(struct work_struct *work)
 {
        struct adj_time_work    *wrk;
+       s64 host_tns;
+       u64 newtime;
+       struct timespec host_ts;
 
        wrk = container_of(work, struct adj_time_work, work);
-       do_adj_guesttime(wrk->host_time);
-       kfree(wrk);
+
+       newtime = wrk->host_time;
+       if (ts_srv_version > TS_VERSION_3) {
+               /*
+                * Some latency has been introduced since Hyper-V generated
+                * its time sample. Take that latency into account before
+                * using TSC reference time sample from Hyper-V.
+                *
+                * This sample is given by TimeSync v4 and above hosts.
+                */
+               u64 current_tick;
+
+               rdmsrl(HV_X64_MSR_TIME_REF_COUNT, current_tick);
+               newtime += (current_tick - wrk->ref_time);
+       }
+       host_tns = (newtime - WLTIMEDELTA) * 100;
+       host_ts = ns_to_timespec(host_tns);
+
+       do_settimeofday(&host_ts);
 }
 
 /*
@@ -198,33 +214,31 @@ static void hv_set_host_time(struct work_struct *work)
  * ICTIMESYNCFLAG_SYNC flag bit indicates reboot, restore events of the VM.
  * After reboot the flag ICTIMESYNCFLAG_SYNC is included in the first time
  * message after the timesync channel is opened. Since the hv_utils module is
- * loaded after hv_vmbus, the first message is usually missed. The other
- * thing is, systime is automatically set to emulated hardware clock which may
- * not be UTC time or in the same time zone. So, to override these effects, we
- * use the first 50 time samples for initial system time setting.
+ * loaded after hv_vmbus, the first message is usually missed. This bit is
+ * considered a hard request to discipline the clock.
+ *
+ * ICTIMESYNCFLAG_SAMPLE bit indicates a time sample from host. This is
+ * typically used as a hint to the guest. The guest is under no obligation
+ * to discipline the clock.
  */
-static inline void adj_guesttime(u64 hosttime, u8 flags)
+static struct adj_time_work  wrk;
+static inline void adj_guesttime(u64 hosttime, u64 reftime, u8 flags)
 {
-       struct adj_time_work    *wrk;
-       static s32 scnt = 50;
 
-       wrk = kmalloc(sizeof(struct adj_time_work), GFP_ATOMIC);
-       if (wrk == NULL)
+       /*
+        * This check is safe since we are executing in the
+        * interrupt context and time synch messages arre always
+        * delivered on the same CPU.
+        */
+       if (work_pending(&wrk.work))
                return;
 
-       wrk->host_time = hosttime;
-       if ((flags & ICTIMESYNCFLAG_SYNC) != 0) {
-               INIT_WORK(&wrk->work, hv_set_host_time);
-               schedule_work(&wrk->work);
-               return;
+       wrk.host_time = hosttime;
+       wrk.ref_time = reftime;
+       wrk.flags = flags;
+       if ((flags & (ICTIMESYNCFLAG_SYNC | ICTIMESYNCFLAG_SAMPLE)) != 0) {
+               schedule_work(&wrk.work);
        }
-
-       if ((flags & ICTIMESYNCFLAG_SAMPLE) != 0 && scnt > 0) {
-               scnt--;
-               INIT_WORK(&wrk->work, hv_set_host_time);
-               schedule_work(&wrk->work);
-       } else
-               kfree(wrk);
 }
 
 /*
@@ -237,6 +251,7 @@ static void timesync_onchannelcallback(void *context)
        u64 requestid;
        struct icmsg_hdr *icmsghdrp;
        struct ictimesync_data *timedatap;
+       struct ictimesync_ref_data *refdata;
        u8 *time_txf_buf = util_timesynch.recv_buffer;
        struct icmsg_negotiate *negop = NULL;
 
@@ -252,11 +267,27 @@ static void timesync_onchannelcallback(void *context)
                                                time_txf_buf,
                                                util_fw_version,
                                                ts_srv_version);
+                       pr_info("Using TimeSync version %d.%d\n",
+                               ts_srv_version >> 16, ts_srv_version & 0xFFFF);
                } else {
-                       timedatap = (struct ictimesync_data *)&time_txf_buf[
-                               sizeof(struct vmbuspipe_hdr) +
-                               sizeof(struct icmsg_hdr)];
-                       adj_guesttime(timedatap->parenttime, timedatap->flags);
+                       if (ts_srv_version > TS_VERSION_3) {
+                               refdata = (struct ictimesync_ref_data *)
+                                       &time_txf_buf[
+                                       sizeof(struct vmbuspipe_hdr) +
+                                       sizeof(struct icmsg_hdr)];
+
+                               adj_guesttime(refdata->parenttime,
+                                               refdata->vmreferencetime,
+                                               refdata->flags);
+                       } else {
+                               timedatap = (struct ictimesync_data *)
+                                       &time_txf_buf[
+                                       sizeof(struct vmbuspipe_hdr) +
+                                       sizeof(struct icmsg_hdr)];
+                               adj_guesttime(timedatap->parenttime,
+                                               0,
+                                               timedatap->flags);
+                       }
                }
 
                icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION
@@ -350,16 +381,21 @@ static int util_probe(struct hv_device *dev,
        switch (vmbus_proto_version) {
        case (VERSION_WS2008):
                util_fw_version = UTIL_WS2K8_FW_VERSION;
-               sd_srv_version = SD_WS2008_VERSION;
-               ts_srv_version = TS_WS2008_VERSION;
-               hb_srv_version = HB_WS2008_VERSION;
+               sd_srv_version = SD_VERSION_1;
+               ts_srv_version = TS_VERSION_1;
+               hb_srv_version = HB_VERSION_1;
                break;
-
-       default:
+       case(VERSION_WIN10):
                util_fw_version = UTIL_FW_VERSION;
                sd_srv_version = SD_VERSION;
                ts_srv_version = TS_VERSION;
                hb_srv_version = HB_VERSION;
+               break;
+       default:
+               util_fw_version = UTIL_FW_VERSION;
+               sd_srv_version = SD_VERSION;
+               ts_srv_version = TS_VERSION_3;
+               hb_srv_version = HB_VERSION;
        }
 
        ret = vmbus_open(dev->channel, 4 * PAGE_SIZE, 4 * PAGE_SIZE, NULL, 0,
@@ -427,6 +463,17 @@ static  struct hv_driver util_drv = {
        .remove =  util_remove,
 };
 
+static int hv_timesync_init(struct hv_util_service *srv)
+{
+       INIT_WORK(&wrk.work, hv_set_host_time);
+       return 0;
+}
+
+static void hv_timesync_deinit(void)
+{
+       cancel_work_sync(&wrk.work);
+}
+
 static int __init init_hyperv_utils(void)
 {
        pr_info("Registering HyperV Utility Driver\n");
index 9a9983fa4531ad52a0f2918ffb51b42f9e8f2b89..c235a95152671104cd7042a451b16ccd0d0d06ab 100644 (file)
@@ -72,6 +72,10 @@ static ssize_t hvt_op_read(struct file *file, char __user *buf,
        hvt->outmsg = NULL;
        hvt->outmsg_len = 0;
 
+       if (hvt->on_read)
+               hvt->on_read();
+       hvt->on_read = NULL;
+
 out_unlock:
        mutex_unlock(&hvt->lock);
        return ret;
@@ -219,7 +223,8 @@ static void hvt_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp)
        mutex_unlock(&hvt->lock);
 }
 
-int hvutil_transport_send(struct hvutil_transport *hvt, void *msg, int len)
+int hvutil_transport_send(struct hvutil_transport *hvt, void *msg, int len,
+                         void (*on_read_cb)(void))
 {
        struct cn_msg *cn_msg;
        int ret = 0;
@@ -237,6 +242,13 @@ int hvutil_transport_send(struct hvutil_transport *hvt, void *msg, int len)
                memcpy(cn_msg->data, msg, len);
                ret = cn_netlink_send(cn_msg, 0, 0, GFP_ATOMIC);
                kfree(cn_msg);
+               /*
+                * We don't know when netlink messages are delivered but unlike
+                * in CHARDEV mode we're not blocked and we can send next
+                * messages right away.
+                */
+               if (on_read_cb)
+                       on_read_cb();
                return ret;
        }
        /* HVUTIL_TRANSPORT_CHARDEV */
@@ -255,6 +267,7 @@ int hvutil_transport_send(struct hvutil_transport *hvt, void *msg, int len)
        if (hvt->outmsg) {
                memcpy(hvt->outmsg, msg, len);
                hvt->outmsg_len = len;
+               hvt->on_read = on_read_cb;
                wake_up_interruptible(&hvt->outmsg_q);
        } else
                ret = -ENOMEM;
index 06254a165a18ae5781e9bbed74767eb611085fa1..d98f5225c3e693468fdb27ccc03de8d17e2a8576 100644 (file)
@@ -36,6 +36,7 @@ struct hvutil_transport {
        struct list_head list;              /* hvt_list */
        int (*on_msg)(void *, int);         /* callback on new user message */
        void (*on_reset)(void);             /* callback when userspace drops */
+       void (*on_read)(void);              /* callback on message read */
        u8 *outmsg;                         /* message to the userspace */
        int outmsg_len;                     /* its length */
        wait_queue_head_t outmsg_q;         /* poll/read wait queue */
@@ -46,7 +47,8 @@ struct hvutil_transport *hvutil_transport_init(const char *name,
                                               u32 cn_idx, u32 cn_val,
                                               int (*on_msg)(void *, int),
                                               void (*on_reset)(void));
-int hvutil_transport_send(struct hvutil_transport *hvt, void *msg, int len);
+int hvutil_transport_send(struct hvutil_transport *hvt, void *msg, int len,
+                         void (*on_read_cb)(void));
 void hvutil_transport_destroy(struct hvutil_transport *hvt);
 
 #endif /* _HV_UTILS_TRANSPORT_H */
index 718b5c72f0c8bd86a8a1a6caba5b556e60c1b6f8..a5b4442433c8922a507753e176d3b31b5af57101 100644 (file)
@@ -495,7 +495,7 @@ struct hv_ring_buffer_debug_info {
 
 extern int hv_init(void);
 
-extern void hv_cleanup(void);
+extern void hv_cleanup(bool crash);
 
 extern int hv_post_message(union hv_connection_id connection_id,
                         enum hv_message_type message_type,
@@ -522,14 +522,15 @@ extern unsigned int host_info_edx;
 /* Interface */
 
 
-int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info, void *buffer,
-                  u32 buflen);
+int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info,
+                      struct page *pages, u32 pagecnt);
 
 void hv_ringbuffer_cleanup(struct hv_ring_buffer_info *ring_info);
 
 int hv_ringbuffer_write(struct hv_ring_buffer_info *ring_info,
                    struct kvec *kv_list,
-                   u32 kv_count, bool *signal, bool lock);
+                   u32 kv_count, bool *signal, bool lock,
+                   enum hv_signal_policy policy);
 
 int hv_ringbuffer_read(struct hv_ring_buffer_info *inring_info,
                       void *buffer, u32 buflen, u32 *buffer_actual_len,
index fe586bf74e17c6c277e568922fa9ad6f16e30fdc..08043da1a61c5f90be36a44309e9fab78997ae15 100644 (file)
@@ -27,6 +27,8 @@
 #include <linux/mm.h>
 #include <linux/hyperv.h>
 #include <linux/uio.h>
+#include <linux/vmalloc.h>
+#include <linux/slab.h>
 
 #include "hyperv_vmbus.h"
 
@@ -66,12 +68,20 @@ u32 hv_end_read(struct hv_ring_buffer_info *rbi)
  *        arrived.
  */
 
-static bool hv_need_to_signal(u32 old_write, struct hv_ring_buffer_info *rbi)
+static bool hv_need_to_signal(u32 old_write, struct hv_ring_buffer_info *rbi,
+                             enum hv_signal_policy policy)
 {
        virt_mb();
        if (READ_ONCE(rbi->ring_buffer->interrupt_mask))
                return false;
 
+       /*
+        * When the client wants to control signaling,
+        * we only honour the host interrupt mask.
+        */
+       if (policy == HV_SIGNAL_POLICY_EXPLICIT)
+               return true;
+
        /* check interrupt_mask before read_index */
        virt_rmb();
        /*
@@ -162,18 +172,7 @@ static u32 hv_copyfrom_ringbuffer(
        void *ring_buffer = hv_get_ring_buffer(ring_info);
        u32 ring_buffer_size = hv_get_ring_buffersize(ring_info);
 
-       u32 frag_len;
-
-       /* wrap-around detected at the src */
-       if (destlen > ring_buffer_size - start_read_offset) {
-               frag_len = ring_buffer_size - start_read_offset;
-
-               memcpy(dest, ring_buffer + start_read_offset, frag_len);
-               memcpy(dest + frag_len, ring_buffer, destlen - frag_len);
-       } else
-
-               memcpy(dest, ring_buffer + start_read_offset, destlen);
-
+       memcpy(dest, ring_buffer + start_read_offset, destlen);
 
        start_read_offset += destlen;
        start_read_offset %= ring_buffer_size;
@@ -194,15 +193,8 @@ static u32 hv_copyto_ringbuffer(
 {
        void *ring_buffer = hv_get_ring_buffer(ring_info);
        u32 ring_buffer_size = hv_get_ring_buffersize(ring_info);
-       u32 frag_len;
 
-       /* wrap-around detected! */
-       if (srclen > ring_buffer_size - start_write_offset) {
-               frag_len = ring_buffer_size - start_write_offset;
-               memcpy(ring_buffer + start_write_offset, src, frag_len);
-               memcpy(ring_buffer, src + frag_len, srclen - frag_len);
-       } else
-               memcpy(ring_buffer + start_write_offset, src, srclen);
+       memcpy(ring_buffer + start_write_offset, src, srclen);
 
        start_write_offset += srclen;
        start_write_offset %= ring_buffer_size;
@@ -235,22 +227,46 @@ void hv_ringbuffer_get_debuginfo(struct hv_ring_buffer_info *ring_info,
 
 /* Initialize the ring buffer. */
 int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info,
-                  void *buffer, u32 buflen)
+                      struct page *pages, u32 page_cnt)
 {
-       if (sizeof(struct hv_ring_buffer) != PAGE_SIZE)
-               return -EINVAL;
+       int i;
+       struct page **pages_wraparound;
+
+       BUILD_BUG_ON((sizeof(struct hv_ring_buffer) != PAGE_SIZE));
 
        memset(ring_info, 0, sizeof(struct hv_ring_buffer_info));
 
-       ring_info->ring_buffer = (struct hv_ring_buffer *)buffer;
+       /*
+        * First page holds struct hv_ring_buffer, do wraparound mapping for
+        * the rest.
+        */
+       pages_wraparound = kzalloc(sizeof(struct page *) * (page_cnt * 2 - 1),
+                                  GFP_KERNEL);
+       if (!pages_wraparound)
+               return -ENOMEM;
+
+       pages_wraparound[0] = pages;
+       for (i = 0; i < 2 * (page_cnt - 1); i++)
+               pages_wraparound[i + 1] = &pages[i % (page_cnt - 1) + 1];
+
+       ring_info->ring_buffer = (struct hv_ring_buffer *)
+               vmap(pages_wraparound, page_cnt * 2 - 1, VM_MAP, PAGE_KERNEL);
+
+       kfree(pages_wraparound);
+
+
+       if (!ring_info->ring_buffer)
+               return -ENOMEM;
+
        ring_info->ring_buffer->read_index =
                ring_info->ring_buffer->write_index = 0;
 
        /* Set the feature bit for enabling flow control. */
        ring_info->ring_buffer->feature_bits.value = 1;
 
-       ring_info->ring_size = buflen;
-       ring_info->ring_datasize = buflen - sizeof(struct hv_ring_buffer);
+       ring_info->ring_size = page_cnt << PAGE_SHIFT;
+       ring_info->ring_datasize = ring_info->ring_size -
+               sizeof(struct hv_ring_buffer);
 
        spin_lock_init(&ring_info->ring_lock);
 
@@ -260,11 +276,13 @@ int hv_ringbuffer_init(struct hv_ring_buffer_info *ring_info,
 /* Cleanup the ring buffer. */
 void hv_ringbuffer_cleanup(struct hv_ring_buffer_info *ring_info)
 {
+       vunmap(ring_info->ring_buffer);
 }
 
 /* Write to the ring buffer. */
 int hv_ringbuffer_write(struct hv_ring_buffer_info *outring_info,
-                   struct kvec *kv_list, u32 kv_count, bool *signal, bool lock)
+                   struct kvec *kv_list, u32 kv_count, bool *signal, bool lock,
+                   enum hv_signal_policy policy)
 {
        int i = 0;
        u32 bytes_avail_towrite;
@@ -326,7 +344,7 @@ int hv_ringbuffer_write(struct hv_ring_buffer_info *outring_info,
        if (lock)
                spin_unlock_irqrestore(&outring_info->ring_lock, flags);
 
-       *signal = hv_need_to_signal(old_write, outring_info);
+       *signal = hv_need_to_signal(old_write, outring_info, policy);
        return 0;
 }
 
index e82f7e1c217cbfcfb39ed9c0e87876c78f3a22b5..6cbe074627853074f8bb0c333c6946bd38d19d1c 100644 (file)
@@ -105,8 +105,8 @@ static struct notifier_block hyperv_panic_block = {
 
 static const char *fb_mmio_name = "fb_range";
 static struct resource *fb_mmio;
-struct resource *hyperv_mmio;
-DEFINE_SEMAPHORE(hyperv_mmio_lock);
+static struct resource *hyperv_mmio;
+static DEFINE_SEMAPHORE(hyperv_mmio_lock);
 
 static int vmbus_exists(void)
 {
@@ -874,7 +874,7 @@ err_alloc:
        bus_unregister(&hv_bus);
 
 err_cleanup:
-       hv_cleanup();
+       hv_cleanup(false);
 
        return ret;
 }
@@ -1326,7 +1326,7 @@ static void hv_kexec_handler(void)
        vmbus_initiate_unload(false);
        for_each_online_cpu(cpu)
                smp_call_function_single(cpu, hv_synic_cleanup, NULL, 1);
-       hv_cleanup();
+       hv_cleanup(false);
 };
 
 static void hv_crash_handler(struct pt_regs *regs)
@@ -1338,7 +1338,7 @@ static void hv_crash_handler(struct pt_regs *regs)
         * for kdump.
         */
        hv_synic_cleanup(NULL);
-       hv_cleanup();
+       hv_cleanup(true);
 };
 
 static int __init hv_acpi_init(void)
@@ -1398,7 +1398,7 @@ static void __exit vmbus_exit(void)
                                                 &hyperv_panic_block);
        }
        bus_unregister(&hv_bus);
-       hv_cleanup();
+       hv_cleanup(false);
        for_each_online_cpu(cpu) {
                tasklet_kill(hv_context.event_dpc[cpu]);
                smp_call_function_single(cpu, hv_synic_cleanup, NULL, 1);
index 4d20b0be0c0b6a337cdec7cbbfd17f8ce94e2a63..d7325c6534ad9d96e899fce16ddb6fa2e6148c4b 100644 (file)
@@ -184,8 +184,7 @@ static void etb_disable_hw(struct etb_drvdata *drvdata)
 
        if (coresight_timeout(drvdata->base, ETB_FFCR, ETB_FFCR_BIT, 0)) {
                dev_err(drvdata->dev,
-                       "timeout observed when probing at offset %#x\n",
-                       ETB_FFCR);
+               "timeout while waiting for completion of Manual Flush\n");
        }
 
        /* disable trace capture */
@@ -193,8 +192,7 @@ static void etb_disable_hw(struct etb_drvdata *drvdata)
 
        if (coresight_timeout(drvdata->base, ETB_FFSR, ETB_FFSR_BIT, 1)) {
                dev_err(drvdata->dev,
-                       "timeout observed when probing at offset %#x\n",
-                       ETB_FFCR);
+                       "timeout while waiting for Formatter to Stop\n");
        }
 
        CS_LOCK(drvdata->base);
@@ -561,7 +559,7 @@ static const struct file_operations etb_fops = {
 };
 
 #define coresight_etb10_simple_func(name, offset)                       \
-       coresight_simple_func(struct etb_drvdata, name, offset)
+       coresight_simple_func(struct etb_drvdata, NULL, name, offset)
 
 coresight_etb10_simple_func(rdp, ETB_RAM_DEPTH_REG);
 coresight_etb10_simple_func(sts, ETB_STATUS_REG);
@@ -638,7 +636,7 @@ static int etb_probe(struct amba_device *adev, const struct amba_id *id)
        struct coresight_platform_data *pdata = NULL;
        struct etb_drvdata *drvdata;
        struct resource *res = &adev->res;
-       struct coresight_desc *desc;
+       struct coresight_desc desc = { 0 };
        struct device_node *np = adev->dev.of_node;
 
        if (np) {
@@ -684,17 +682,13 @@ static int etb_probe(struct amba_device *adev, const struct amba_id *id)
                return -ENOMEM;
        }
 
-       desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
-       if (!desc)
-               return -ENOMEM;
-
-       desc->type = CORESIGHT_DEV_TYPE_SINK;
-       desc->subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_BUFFER;
-       desc->ops = &etb_cs_ops;
-       desc->pdata = pdata;
-       desc->dev = dev;
-       desc->groups = coresight_etb_groups;
-       drvdata->csdev = coresight_register(desc);
+       desc.type = CORESIGHT_DEV_TYPE_SINK;
+       desc.subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_BUFFER;
+       desc.ops = &etb_cs_ops;
+       desc.pdata = pdata;
+       desc.dev = dev;
+       desc.groups = coresight_etb_groups;
+       drvdata->csdev = coresight_register(&desc);
        if (IS_ERR(drvdata->csdev))
                return PTR_ERR(drvdata->csdev);
 
index 755125f7917f2cb6aa369fd88d28d763e688a9d6..2cd7c718198a82e3a2aeecc5aed1c3a5643157d7 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/types.h>
 #include <linux/workqueue.h>
 
+#include "coresight-etm-perf.h"
 #include "coresight-priv.h"
 
 static struct pmu etm_pmu;
@@ -71,14 +72,48 @@ static const struct attribute_group *etm_pmu_attr_groups[] = {
 
 static void etm_event_read(struct perf_event *event) {}
 
-static int etm_event_init(struct perf_event *event)
+static int etm_addr_filters_alloc(struct perf_event *event)
 {
-       if (event->attr.type != etm_pmu.type)
-               return -ENOENT;
+       struct etm_filters *filters;
+       int node = event->cpu == -1 ? -1 : cpu_to_node(event->cpu);
+
+       filters = kzalloc_node(sizeof(struct etm_filters), GFP_KERNEL, node);
+       if (!filters)
+               return -ENOMEM;
+
+       if (event->parent)
+               memcpy(filters, event->parent->hw.addr_filters,
+                      sizeof(*filters));
+
+       event->hw.addr_filters = filters;
 
        return 0;
 }
 
+static void etm_event_destroy(struct perf_event *event)
+{
+       kfree(event->hw.addr_filters);
+       event->hw.addr_filters = NULL;
+}
+
+static int etm_event_init(struct perf_event *event)
+{
+       int ret = 0;
+
+       if (event->attr.type != etm_pmu.type) {
+               ret = -ENOENT;
+               goto out;
+       }
+
+       ret = etm_addr_filters_alloc(event);
+       if (ret)
+               goto out;
+
+       event->destroy = etm_event_destroy;
+out:
+       return ret;
+}
+
 static void free_event_data(struct work_struct *work)
 {
        int cpu;
@@ -100,7 +135,7 @@ static void free_event_data(struct work_struct *work)
        }
 
        for_each_cpu(cpu, mask) {
-               if (event_data->path[cpu])
+               if (!(IS_ERR_OR_NULL(event_data->path[cpu])))
                        coresight_release_path(event_data->path[cpu]);
        }
 
@@ -185,7 +220,7 @@ static void *etm_setup_aux(int event_cpu, void **pages,
                 * referenced later when the path is actually needed.
                 */
                event_data->path[cpu] = coresight_build_path(csdev);
-               if (!event_data->path[cpu])
+               if (IS_ERR(event_data->path[cpu]))
                        goto err;
        }
 
@@ -258,7 +293,7 @@ static void etm_event_start(struct perf_event *event, int flags)
        event->hw.state = 0;
 
        /* Finally enable the tracer */
-       if (source_ops(csdev)->enable(csdev, &event->attr, CS_MODE_PERF))
+       if (source_ops(csdev)->enable(csdev, event, CS_MODE_PERF))
                goto fail_end_stop;
 
 out:
@@ -291,7 +326,7 @@ static void etm_event_stop(struct perf_event *event, int mode)
                return;
 
        /* stop tracer */
-       source_ops(csdev)->disable(csdev);
+       source_ops(csdev)->disable(csdev, event);
 
        /* tell the core */
        event->hw.state = PERF_HES_STOPPED;
@@ -342,6 +377,87 @@ static void etm_event_del(struct perf_event *event, int mode)
        etm_event_stop(event, PERF_EF_UPDATE);
 }
 
+static int etm_addr_filters_validate(struct list_head *filters)
+{
+       bool range = false, address = false;
+       int index = 0;
+       struct perf_addr_filter *filter;
+
+       list_for_each_entry(filter, filters, entry) {
+               /*
+                * No need to go further if there's no more
+                * room for filters.
+                */
+               if (++index > ETM_ADDR_CMP_MAX)
+                       return -EOPNOTSUPP;
+
+               /*
+                * As taken from the struct perf_addr_filter documentation:
+                *      @range: 1: range, 0: address
+                *
+                * At this time we don't allow range and start/stop filtering
+                * to cohabitate, they have to be mutually exclusive.
+                */
+               if ((filter->range == 1) && address)
+                       return -EOPNOTSUPP;
+
+               if ((filter->range == 0) && range)
+                       return -EOPNOTSUPP;
+
+               /*
+                * For range filtering, the second address in the address
+                * range comparator needs to be higher than the first.
+                * Invalid otherwise.
+                */
+               if (filter->range && filter->size == 0)
+                       return -EINVAL;
+
+               /*
+                * Everything checks out with this filter, record what we've
+                * received before moving on to the next one.
+                */
+               if (filter->range)
+                       range = true;
+               else
+                       address = true;
+       }
+
+       return 0;
+}
+
+static void etm_addr_filters_sync(struct perf_event *event)
+{
+       struct perf_addr_filters_head *head = perf_event_addr_filters(event);
+       unsigned long start, stop, *offs = event->addr_filters_offs;
+       struct etm_filters *filters = event->hw.addr_filters;
+       struct etm_filter *etm_filter;
+       struct perf_addr_filter *filter;
+       int i = 0;
+
+       list_for_each_entry(filter, &head->list, entry) {
+               start = filter->offset + offs[i];
+               stop = start + filter->size;
+               etm_filter = &filters->etm_filter[i];
+
+               if (filter->range == 1) {
+                       etm_filter->start_addr = start;
+                       etm_filter->stop_addr = stop;
+                       etm_filter->type = ETM_ADDR_TYPE_RANGE;
+               } else {
+                       if (filter->filter == 1) {
+                               etm_filter->start_addr = start;
+                               etm_filter->type = ETM_ADDR_TYPE_START;
+                       } else {
+                               etm_filter->stop_addr = stop;
+                               etm_filter->type = ETM_ADDR_TYPE_STOP;
+                       }
+               }
+               i++;
+       }
+
+       filters->nr_filters = i;
+}
+
 int etm_perf_symlink(struct coresight_device *csdev, bool link)
 {
        char entry[sizeof("cpu9999999")];
@@ -371,18 +487,21 @@ static int __init etm_perf_init(void)
 {
        int ret;
 
-       etm_pmu.capabilities    = PERF_PMU_CAP_EXCLUSIVE;
-
-       etm_pmu.attr_groups     = etm_pmu_attr_groups;
-       etm_pmu.task_ctx_nr     = perf_sw_context;
-       etm_pmu.read            = etm_event_read;
-       etm_pmu.event_init      = etm_event_init;
-       etm_pmu.setup_aux       = etm_setup_aux;
-       etm_pmu.free_aux        = etm_free_aux;
-       etm_pmu.start           = etm_event_start;
-       etm_pmu.stop            = etm_event_stop;
-       etm_pmu.add             = etm_event_add;
-       etm_pmu.del             = etm_event_del;
+       etm_pmu.capabilities            = PERF_PMU_CAP_EXCLUSIVE;
+
+       etm_pmu.attr_groups             = etm_pmu_attr_groups;
+       etm_pmu.task_ctx_nr             = perf_sw_context;
+       etm_pmu.read                    = etm_event_read;
+       etm_pmu.event_init              = etm_event_init;
+       etm_pmu.setup_aux               = etm_setup_aux;
+       etm_pmu.free_aux                = etm_free_aux;
+       etm_pmu.start                   = etm_event_start;
+       etm_pmu.stop                    = etm_event_stop;
+       etm_pmu.add                     = etm_event_add;
+       etm_pmu.del                     = etm_event_del;
+       etm_pmu.addr_filters_sync       = etm_addr_filters_sync;
+       etm_pmu.addr_filters_validate   = etm_addr_filters_validate;
+       etm_pmu.nr_addr_filters         = ETM_ADDR_CMP_MAX;
 
        ret = perf_pmu_register(&etm_pmu, CORESIGHT_ETM_PMU_NAME, -1);
        if (ret == 0)
index 87f5a134eb6f6b1cf0e540e78fd19fdcc7adc95d..3ffc9feb2d646e17f4304e2f53bae4976778be5c 100644 (file)
 #ifndef _CORESIGHT_ETM_PERF_H
 #define _CORESIGHT_ETM_PERF_H
 
+#include "coresight-priv.h"
+
 struct coresight_device;
 
+/*
+ * In both ETMv3 and v4 the maximum number of address comparator implentable
+ * is 8.  The actual number is implementation specific and will be checked
+ * when filters are applied.
+ */
+#define ETM_ADDR_CMP_MAX       8
+
+/**
+ * struct etm_filter - single instruction range or start/stop configuration.
+ * @start_addr:        The address to start tracing on.
+ * @stop_addr: The address to stop tracing on.
+ * @type:      Is this a range or start/stop filter.
+ */
+struct etm_filter {
+       unsigned long start_addr;
+       unsigned long stop_addr;
+       enum etm_addr_type type;
+};
+
+/**
+ * struct etm_filters - set of filters for a session
+ * @etm_filter:        All the filters for this session.
+ * @nr_filters:        Number of filters
+ * @ssstatus:  Status of the start/stop logic.
+ */
+struct etm_filters {
+       struct etm_filter       etm_filter[ETM_ADDR_CMP_MAX];
+       unsigned int            nr_filters;
+       bool                    ssstatus;
+};
+
+
 #ifdef CONFIG_CORESIGHT
 int etm_perf_symlink(struct coresight_device *csdev, bool link);
 
index 51597cb2c08af69293c0b17d8698019fc8af949e..4a18ee4999658eccbe16eb619d83efecc1c682cb 100644 (file)
@@ -259,14 +259,6 @@ struct etm_drvdata {
        struct etm_config               config;
 };
 
-enum etm_addr_type {
-       ETM_ADDR_TYPE_NONE,
-       ETM_ADDR_TYPE_SINGLE,
-       ETM_ADDR_TYPE_RANGE,
-       ETM_ADDR_TYPE_START,
-       ETM_ADDR_TYPE_STOP,
-};
-
 static inline void etm_writel(struct etm_drvdata *drvdata,
                              u32 val, u32 off)
 {
index 02d4b629891f4a198b72a44910f18fa45abe1535..e9b071953f8099f832ac98f11acd563019dd6a45 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/pm_runtime.h>
 #include <linux/sysfs.h>
 #include "coresight-etm.h"
+#include "coresight-priv.h"
 
 static ssize_t nr_addr_cmp_show(struct device *dev,
                                struct device_attribute *attr, char *buf)
@@ -1222,7 +1223,7 @@ static struct attribute *coresight_etm_attrs[] = {
 };
 
 #define coresight_etm3x_simple_func(name, offset)                      \
-       coresight_simple_func(struct etm_drvdata, name, offset)
+       coresight_simple_func(struct etm_drvdata, NULL, name, offset)
 
 coresight_etm3x_simple_func(etmccr, ETMCCR);
 coresight_etm3x_simple_func(etmccer, ETMCCER);
index 2de4cad9c5ede9b5e2aa65f230dac8d446819adb..3fe368b23d158d56563285052df9aecb869d3ef2 100644 (file)
@@ -311,9 +311,10 @@ void etm_config_trace_mode(struct etm_config *config)
 #define ETM3X_SUPPORTED_OPTIONS (ETMCR_CYC_ACC | ETMCR_TIMESTAMP_EN)
 
 static int etm_parse_event_config(struct etm_drvdata *drvdata,
-                                 struct perf_event_attr *attr)
+                                 struct perf_event *event)
 {
        struct etm_config *config = &drvdata->config;
+       struct perf_event_attr *attr = &event->attr;
 
        if (!attr)
                return -EINVAL;
@@ -459,7 +460,7 @@ static int etm_trace_id(struct coresight_device *csdev)
 }
 
 static int etm_enable_perf(struct coresight_device *csdev,
-                          struct perf_event_attr *attr)
+                          struct perf_event *event)
 {
        struct etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
 
@@ -467,7 +468,7 @@ static int etm_enable_perf(struct coresight_device *csdev,
                return -EINVAL;
 
        /* Configure the tracer based on the session's specifics */
-       etm_parse_event_config(drvdata, attr);
+       etm_parse_event_config(drvdata, event);
        /* And enable it */
        etm_enable_hw(drvdata);
 
@@ -504,7 +505,7 @@ err:
 }
 
 static int etm_enable(struct coresight_device *csdev,
-                     struct perf_event_attr *attr, u32 mode)
+                     struct perf_event *event, u32 mode)
 {
        int ret;
        u32 val;
@@ -521,7 +522,7 @@ static int etm_enable(struct coresight_device *csdev,
                ret = etm_enable_sysfs(csdev);
                break;
        case CS_MODE_PERF:
-               ret = etm_enable_perf(csdev, attr);
+               ret = etm_enable_perf(csdev, event);
                break;
        default:
                ret = -EINVAL;
@@ -601,7 +602,8 @@ static void etm_disable_sysfs(struct coresight_device *csdev)
        dev_info(drvdata->dev, "ETM tracing disabled\n");
 }
 
-static void etm_disable(struct coresight_device *csdev)
+static void etm_disable(struct coresight_device *csdev,
+                       struct perf_event *event)
 {
        u32 mode;
        struct etm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
@@ -756,13 +758,9 @@ static int etm_probe(struct amba_device *adev, const struct amba_id *id)
        struct coresight_platform_data *pdata = NULL;
        struct etm_drvdata *drvdata;
        struct resource *res = &adev->res;
-       struct coresight_desc *desc;
+       struct coresight_desc desc = { 0 };
        struct device_node *np = adev->dev.of_node;
 
-       desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
-       if (!desc)
-               return -ENOMEM;
-
        drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
        if (!drvdata)
                return -ENOMEM;
@@ -825,13 +823,13 @@ static int etm_probe(struct amba_device *adev, const struct amba_id *id)
        etm_init_trace_id(drvdata);
        etm_set_default(&drvdata->config);
 
-       desc->type = CORESIGHT_DEV_TYPE_SOURCE;
-       desc->subtype.source_subtype = CORESIGHT_DEV_SUBTYPE_SOURCE_PROC;
-       desc->ops = &etm_cs_ops;
-       desc->pdata = pdata;
-       desc->dev = dev;
-       desc->groups = coresight_etm_groups;
-       drvdata->csdev = coresight_register(desc);
+       desc.type = CORESIGHT_DEV_TYPE_SOURCE;
+       desc.subtype.source_subtype = CORESIGHT_DEV_SUBTYPE_SOURCE_PROC;
+       desc.ops = &etm_cs_ops;
+       desc.pdata = pdata;
+       desc.dev = dev;
+       desc.groups = coresight_etm_groups;
+       drvdata->csdev = coresight_register(&desc);
        if (IS_ERR(drvdata->csdev)) {
                ret = PTR_ERR(drvdata->csdev);
                goto err_arch_supported;
@@ -893,6 +891,11 @@ static struct amba_id etm_ids[] = {
                .mask   = 0x0003ffff,
                .data   = "ETM 3.3",
        },
+       {       /* ETM 3.5 - Cortex-A5 */
+               .id     = 0x0003b955,
+               .mask   = 0x0003ffff,
+               .data   = "ETM 3.5",
+       },
        {       /* ETM 3.5 */
                .id     = 0x0003b956,
                .mask   = 0x0003ffff,
index 7c84308c55643440486517d26ca58b908e31188d..b9b1e9c8f4c4ffd528ecd6003c3a95a206febcc8 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/pm_runtime.h>
 #include <linux/sysfs.h>
 #include "coresight-etm4x.h"
+#include "coresight-priv.h"
 
 static int etm4_set_mode_exclude(struct etmv4_drvdata *drvdata, bool exclude)
 {
@@ -2039,15 +2040,42 @@ static struct attribute *coresight_etmv4_attrs[] = {
        NULL,
 };
 
+struct etmv4_reg {
+       void __iomem *addr;
+       u32 data;
+};
+
+static void do_smp_cross_read(void *data)
+{
+       struct etmv4_reg *reg = data;
+
+       reg->data = readl_relaxed(reg->addr);
+}
+
+static u32 etmv4_cross_read(const struct device *dev, u32 offset)
+{
+       struct etmv4_drvdata *drvdata = dev_get_drvdata(dev);
+       struct etmv4_reg reg;
+
+       reg.addr = drvdata->base + offset;
+       /*
+        * smp cross call ensures the CPU will be powered up before
+        * accessing the ETMv4 trace core registers
+        */
+       smp_call_function_single(drvdata->cpu, do_smp_cross_read, &reg, 1);
+       return reg.data;
+}
+
 #define coresight_etm4x_simple_func(name, offset)                      \
-       coresight_simple_func(struct etmv4_drvdata, name, offset)
+       coresight_simple_func(struct etmv4_drvdata, NULL, name, offset)
+
+#define coresight_etm4x_cross_read(name, offset)                       \
+       coresight_simple_func(struct etmv4_drvdata, etmv4_cross_read,   \
+                             name, offset)
 
-coresight_etm4x_simple_func(trcoslsr, TRCOSLSR);
 coresight_etm4x_simple_func(trcpdcr, TRCPDCR);
 coresight_etm4x_simple_func(trcpdsr, TRCPDSR);
 coresight_etm4x_simple_func(trclsr, TRCLSR);
-coresight_etm4x_simple_func(trcconfig, TRCCONFIGR);
-coresight_etm4x_simple_func(trctraceid, TRCTRACEIDR);
 coresight_etm4x_simple_func(trcauthstatus, TRCAUTHSTATUS);
 coresight_etm4x_simple_func(trcdevid, TRCDEVID);
 coresight_etm4x_simple_func(trcdevtype, TRCDEVTYPE);
@@ -2055,6 +2083,9 @@ coresight_etm4x_simple_func(trcpidr0, TRCPIDR0);
 coresight_etm4x_simple_func(trcpidr1, TRCPIDR1);
 coresight_etm4x_simple_func(trcpidr2, TRCPIDR2);
 coresight_etm4x_simple_func(trcpidr3, TRCPIDR3);
+coresight_etm4x_cross_read(trcoslsr, TRCOSLSR);
+coresight_etm4x_cross_read(trcconfig, TRCCONFIGR);
+coresight_etm4x_cross_read(trctraceid, TRCTRACEIDR);
 
 static struct attribute *coresight_etmv4_mgmt_attrs[] = {
        &dev_attr_trcoslsr.attr,
@@ -2073,19 +2104,19 @@ static struct attribute *coresight_etmv4_mgmt_attrs[] = {
        NULL,
 };
 
-coresight_etm4x_simple_func(trcidr0, TRCIDR0);
-coresight_etm4x_simple_func(trcidr1, TRCIDR1);
-coresight_etm4x_simple_func(trcidr2, TRCIDR2);
-coresight_etm4x_simple_func(trcidr3, TRCIDR3);
-coresight_etm4x_simple_func(trcidr4, TRCIDR4);
-coresight_etm4x_simple_func(trcidr5, TRCIDR5);
+coresight_etm4x_cross_read(trcidr0, TRCIDR0);
+coresight_etm4x_cross_read(trcidr1, TRCIDR1);
+coresight_etm4x_cross_read(trcidr2, TRCIDR2);
+coresight_etm4x_cross_read(trcidr3, TRCIDR3);
+coresight_etm4x_cross_read(trcidr4, TRCIDR4);
+coresight_etm4x_cross_read(trcidr5, TRCIDR5);
 /* trcidr[6,7] are reserved */
-coresight_etm4x_simple_func(trcidr8, TRCIDR8);
-coresight_etm4x_simple_func(trcidr9, TRCIDR9);
-coresight_etm4x_simple_func(trcidr10, TRCIDR10);
-coresight_etm4x_simple_func(trcidr11, TRCIDR11);
-coresight_etm4x_simple_func(trcidr12, TRCIDR12);
-coresight_etm4x_simple_func(trcidr13, TRCIDR13);
+coresight_etm4x_cross_read(trcidr8, TRCIDR8);
+coresight_etm4x_cross_read(trcidr9, TRCIDR9);
+coresight_etm4x_cross_read(trcidr10, TRCIDR10);
+coresight_etm4x_cross_read(trcidr11, TRCIDR11);
+coresight_etm4x_cross_read(trcidr12, TRCIDR12);
+coresight_etm4x_cross_read(trcidr13, TRCIDR13);
 
 static struct attribute *coresight_etmv4_trcidr_attrs[] = {
        &dev_attr_trcidr0.attr,
index 1a5e0d14c1dd4d3fc1b876d8ff8fd1dd07c6c61c..4db8d6a4d0cbbe0545e5724b7de75fbae0438c68 100644 (file)
@@ -33,7 +33,6 @@
 #include <linux/uaccess.h>
 #include <linux/perf_event.h>
 #include <linux/pm_runtime.h>
-#include <linux/perf_event.h>
 #include <asm/sections.h>
 #include <asm/local.h>
 
@@ -46,7 +45,9 @@ module_param_named(boot_enable, boot_enable, int, S_IRUGO);
 /* The number of ETMv4 currently registered */
 static int etm4_count;
 static struct etmv4_drvdata *etmdrvdata[NR_CPUS];
-static void etm4_set_default(struct etmv4_config *config);
+static void etm4_set_default_config(struct etmv4_config *config);
+static int etm4_set_event_filters(struct etmv4_drvdata *drvdata,
+                                 struct perf_event *event);
 
 static enum cpuhp_state hp_online;
 
@@ -79,22 +80,8 @@ static int etm4_cpu_id(struct coresight_device *csdev)
 static int etm4_trace_id(struct coresight_device *csdev)
 {
        struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
-       unsigned long flags;
-       int trace_id = -1;
-
-       if (!local_read(&drvdata->mode))
-               return drvdata->trcid;
-
-       spin_lock_irqsave(&drvdata->spinlock, flags);
-
-       CS_UNLOCK(drvdata->base);
-       trace_id = readl_relaxed(drvdata->base + TRCTRACEIDR);
-       trace_id &= ETM_TRACEID_MASK;
-       CS_LOCK(drvdata->base);
 
-       spin_unlock_irqrestore(&drvdata->spinlock, flags);
-
-       return trace_id;
+       return drvdata->trcid;
 }
 
 static void etm4_enable_hw(void *info)
@@ -113,8 +100,7 @@ static void etm4_enable_hw(void *info)
        /* wait for TRCSTATR.IDLE to go up */
        if (coresight_timeout(drvdata->base, TRCSTATR, TRCSTATR_IDLE_BIT, 1))
                dev_err(drvdata->dev,
-                       "timeout observed when probing at offset %#x\n",
-                       TRCSTATR);
+                       "timeout while waiting for Idle Trace Status\n");
 
        writel_relaxed(config->pe_sel, drvdata->base + TRCPROCSELR);
        writel_relaxed(config->cfg, drvdata->base + TRCCONFIGR);
@@ -180,14 +166,20 @@ static void etm4_enable_hw(void *info)
        writel_relaxed(config->vmid_mask0, drvdata->base + TRCVMIDCCTLR0);
        writel_relaxed(config->vmid_mask1, drvdata->base + TRCVMIDCCTLR1);
 
+       /*
+        * Request to keep the trace unit powered and also
+        * emulation of powerdown
+        */
+       writel_relaxed(readl_relaxed(drvdata->base + TRCPDCR) | TRCPDCR_PU,
+                      drvdata->base + TRCPDCR);
+
        /* Enable the trace unit */
        writel_relaxed(1, drvdata->base + TRCPRGCTLR);
 
        /* wait for TRCSTATR.IDLE to go back down to '0' */
        if (coresight_timeout(drvdata->base, TRCSTATR, TRCSTATR_IDLE_BIT, 0))
                dev_err(drvdata->dev,
-                       "timeout observed when probing at offset %#x\n",
-                       TRCSTATR);
+                       "timeout while waiting for Idle Trace Status\n");
 
        CS_LOCK(drvdata->base);
 
@@ -195,12 +187,16 @@ static void etm4_enable_hw(void *info)
 }
 
 static int etm4_parse_event_config(struct etmv4_drvdata *drvdata,
-                                  struct perf_event_attr *attr)
+                                  struct perf_event *event)
 {
+       int ret = 0;
        struct etmv4_config *config = &drvdata->config;
+       struct perf_event_attr *attr = &event->attr;
 
-       if (!attr)
-               return -EINVAL;
+       if (!attr) {
+               ret = -EINVAL;
+               goto out;
+       }
 
        /* Clear configuration from previous run */
        memset(config, 0, sizeof(struct etmv4_config));
@@ -212,14 +208,12 @@ static int etm4_parse_event_config(struct etmv4_drvdata *drvdata,
                config->mode = ETM_MODE_EXCL_USER;
 
        /* Always start from the default config */
-       etm4_set_default(config);
+       etm4_set_default_config(config);
 
-       /*
-        * By default the tracers are configured to trace the whole address
-        * range.  Narrow the field only if requested by user space.
-        */
-       if (config->mode)
-               etm4_config_trace_mode(config);
+       /* Configure filters specified on the perf cmd line, if any. */
+       ret = etm4_set_event_filters(drvdata, event);
+       if (ret)
+               goto out;
 
        /* Go from generic option to ETMv4 specifics */
        if (attr->config & BIT(ETM_OPT_CYCACC))
@@ -227,23 +221,30 @@ static int etm4_parse_event_config(struct etmv4_drvdata *drvdata,
        if (attr->config & BIT(ETM_OPT_TS))
                config->cfg |= ETMv4_MODE_TIMESTAMP;
 
-       return 0;
+out:
+       return ret;
 }
 
 static int etm4_enable_perf(struct coresight_device *csdev,
-                           struct perf_event_attr *attr)
+                           struct perf_event *event)
 {
+       int ret = 0;
        struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
 
-       if (WARN_ON_ONCE(drvdata->cpu != smp_processor_id()))
-               return -EINVAL;
+       if (WARN_ON_ONCE(drvdata->cpu != smp_processor_id())) {
+               ret = -EINVAL;
+               goto out;
+       }
 
        /* Configure the tracer based on the session's specifics */
-       etm4_parse_event_config(drvdata, attr);
+       ret = etm4_parse_event_config(drvdata, event);
+       if (ret)
+               goto out;
        /* And enable it */
        etm4_enable_hw(drvdata);
 
-       return 0;
+out:
+       return ret;
 }
 
 static int etm4_enable_sysfs(struct coresight_device *csdev)
@@ -274,7 +275,7 @@ err:
 }
 
 static int etm4_enable(struct coresight_device *csdev,
-                      struct perf_event_attr *attr, u32 mode)
+                      struct perf_event *event, u32 mode)
 {
        int ret;
        u32 val;
@@ -291,7 +292,7 @@ static int etm4_enable(struct coresight_device *csdev,
                ret = etm4_enable_sysfs(csdev);
                break;
        case CS_MODE_PERF:
-               ret = etm4_enable_perf(csdev, attr);
+               ret = etm4_enable_perf(csdev, event);
                break;
        default:
                ret = -EINVAL;
@@ -311,6 +312,11 @@ static void etm4_disable_hw(void *info)
 
        CS_UNLOCK(drvdata->base);
 
+       /* power can be removed from the trace unit now */
+       control = readl_relaxed(drvdata->base + TRCPDCR);
+       control &= ~TRCPDCR_PU;
+       writel_relaxed(control, drvdata->base + TRCPDCR);
+
        control = readl_relaxed(drvdata->base + TRCPRGCTLR);
 
        /* EN, bit[0] Trace unit enable bit */
@@ -326,14 +332,28 @@ static void etm4_disable_hw(void *info)
        dev_dbg(drvdata->dev, "cpu: %d disable smp call done\n", drvdata->cpu);
 }
 
-static int etm4_disable_perf(struct coresight_device *csdev)
+static int etm4_disable_perf(struct coresight_device *csdev,
+                            struct perf_event *event)
 {
+       u32 control;
+       struct etm_filters *filters = event->hw.addr_filters;
        struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
 
        if (WARN_ON_ONCE(drvdata->cpu != smp_processor_id()))
                return -EINVAL;
 
        etm4_disable_hw(drvdata);
+
+       /*
+        * Check if the start/stop logic was active when the unit was stopped.
+        * That way we can re-enable the start/stop logic when the process is
+        * scheduled again.  Configuration of the start/stop logic happens in
+        * function etm4_set_event_filters().
+        */
+       control = readl_relaxed(drvdata->base + TRCVICTLR);
+       /* TRCVICTLR::SSSTATUS, bit[9] */
+       filters->ssstatus = (control & BIT(9));
+
        return 0;
 }
 
@@ -362,7 +382,8 @@ static void etm4_disable_sysfs(struct coresight_device *csdev)
        dev_info(drvdata->dev, "ETM tracing disabled\n");
 }
 
-static void etm4_disable(struct coresight_device *csdev)
+static void etm4_disable(struct coresight_device *csdev,
+                        struct perf_event *event)
 {
        u32 mode;
        struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
@@ -381,7 +402,7 @@ static void etm4_disable(struct coresight_device *csdev)
                etm4_disable_sysfs(csdev);
                break;
        case CS_MODE_PERF:
-               etm4_disable_perf(csdev);
+               etm4_disable_perf(csdev, event);
                break;
        }
 
@@ -564,21 +585,8 @@ static void etm4_init_arch_data(void *info)
        CS_LOCK(drvdata->base);
 }
 
-static void etm4_set_default(struct etmv4_config *config)
+static void etm4_set_default_config(struct etmv4_config *config)
 {
-       if (WARN_ON_ONCE(!config))
-               return;
-
-       /*
-        * Make default initialisation trace everything
-        *
-        * Select the "always true" resource selector on the
-        * "Enablign Event" line and configure address range comparator
-        * '0' to trace all the possible address range.  From there
-        * configure the "include/exclude" engine to include address
-        * range comparator '0'.
-        */
-
        /* disable all events tracing */
        config->eventctrl0 = 0x0;
        config->eventctrl1 = 0x0;
@@ -594,6 +602,108 @@ static void etm4_set_default(struct etmv4_config *config)
 
        /* TRCVICTLR::EVENT = 0x01, select the always on logic */
        config->vinst_ctrl |= BIT(0);
+}
+
+static u64 etm4_get_access_type(struct etmv4_config *config)
+{
+       u64 access_type = 0;
+
+       /*
+        * EXLEVEL_NS, bits[15:12]
+        * The Exception levels are:
+        *   Bit[12] Exception level 0 - Application
+        *   Bit[13] Exception level 1 - OS
+        *   Bit[14] Exception level 2 - Hypervisor
+        *   Bit[15] Never implemented
+        *
+        * Always stay away from hypervisor mode.
+        */
+       access_type = ETM_EXLEVEL_NS_HYP;
+
+       if (config->mode & ETM_MODE_EXCL_KERN)
+               access_type |= ETM_EXLEVEL_NS_OS;
+
+       if (config->mode & ETM_MODE_EXCL_USER)
+               access_type |= ETM_EXLEVEL_NS_APP;
+
+       /*
+        * EXLEVEL_S, bits[11:8], don't trace anything happening
+        * in secure state.
+        */
+       access_type |= (ETM_EXLEVEL_S_APP       |
+                       ETM_EXLEVEL_S_OS        |
+                       ETM_EXLEVEL_S_HYP);
+
+       return access_type;
+}
+
+static void etm4_set_comparator_filter(struct etmv4_config *config,
+                                      u64 start, u64 stop, int comparator)
+{
+       u64 access_type = etm4_get_access_type(config);
+
+       /* First half of default address comparator */
+       config->addr_val[comparator] = start;
+       config->addr_acc[comparator] = access_type;
+       config->addr_type[comparator] = ETM_ADDR_TYPE_RANGE;
+
+       /* Second half of default address comparator */
+       config->addr_val[comparator + 1] = stop;
+       config->addr_acc[comparator + 1] = access_type;
+       config->addr_type[comparator + 1] = ETM_ADDR_TYPE_RANGE;
+
+       /*
+        * Configure the ViewInst function to include this address range
+        * comparator.
+        *
+        * @comparator is divided by two since it is the index in the
+        * etmv4_config::addr_val array but register TRCVIIECTLR deals with
+        * address range comparator _pairs_.
+        *
+        * Therefore:
+        *      index 0 -> compatator pair 0
+        *      index 2 -> comparator pair 1
+        *      index 4 -> comparator pair 2
+        *      ...
+        *      index 14 -> comparator pair 7
+        */
+       config->viiectlr |= BIT(comparator / 2);
+}
+
+static void etm4_set_start_stop_filter(struct etmv4_config *config,
+                                      u64 address, int comparator,
+                                      enum etm_addr_type type)
+{
+       int shift;
+       u64 access_type = etm4_get_access_type(config);
+
+       /* Configure the comparator */
+       config->addr_val[comparator] = address;
+       config->addr_acc[comparator] = access_type;
+       config->addr_type[comparator] = type;
+
+       /*
+        * Configure ViewInst Start-Stop control register.
+        * Addresses configured to start tracing go from bit 0 to n-1,
+        * while those configured to stop tracing from 16 to 16 + n-1.
+        */
+       shift = (type == ETM_ADDR_TYPE_START ? 0 : 16);
+       config->vissctlr |= BIT(shift + comparator);
+}
+
+static void etm4_set_default_filter(struct etmv4_config *config)
+{
+       u64 start, stop;
+
+       /*
+        * Configure address range comparator '0' to encompass all
+        * possible addresses.
+        */
+       start = 0x0;
+       stop = ~0x0;
+
+       etm4_set_comparator_filter(config, start, stop,
+                                  ETM_DEFAULT_ADDR_COMP);
 
        /*
         * TRCVICTLR::SSSTATUS == 1, the start-stop logic is
@@ -601,43 +711,156 @@ static void etm4_set_default(struct etmv4_config *config)
         */
        config->vinst_ctrl |= BIT(9);
 
+       /* No start-stop filtering for ViewInst */
+       config->vissctlr = 0x0;
+}
+
+static void etm4_set_default(struct etmv4_config *config)
+{
+       if (WARN_ON_ONCE(!config))
+               return;
+
        /*
-        * Configure address range comparator '0' to encompass all
-        * possible addresses.
+        * Make default initialisation trace everything
+        *
+        * Select the "always true" resource selector on the
+        * "Enablign Event" line and configure address range comparator
+        * '0' to trace all the possible address range.  From there
+        * configure the "include/exclude" engine to include address
+        * range comparator '0'.
         */
+       etm4_set_default_config(config);
+       etm4_set_default_filter(config);
+}
 
-       /* First half of default address comparator: start at address 0 */
-       config->addr_val[ETM_DEFAULT_ADDR_COMP] = 0x0;
-       /* trace instruction addresses */
-       config->addr_acc[ETM_DEFAULT_ADDR_COMP] &= ~(BIT(0) | BIT(1));
-       /* EXLEVEL_NS, bits[12:15], only trace application and kernel space */
-       config->addr_acc[ETM_DEFAULT_ADDR_COMP] |= ETM_EXLEVEL_NS_HYP;
-       /* EXLEVEL_S, bits[11:8], don't trace anything in secure state */
-       config->addr_acc[ETM_DEFAULT_ADDR_COMP] |= (ETM_EXLEVEL_S_APP |
-                                                   ETM_EXLEVEL_S_OS |
-                                                   ETM_EXLEVEL_S_HYP);
-       config->addr_type[ETM_DEFAULT_ADDR_COMP] = ETM_ADDR_TYPE_RANGE;
+static int etm4_get_next_comparator(struct etmv4_drvdata *drvdata, u32 type)
+{
+       int nr_comparator, index = 0;
+       struct etmv4_config *config = &drvdata->config;
 
        /*
-        * Second half of default address comparator: go all
-        * the way to the top.
-       */
-       config->addr_val[ETM_DEFAULT_ADDR_COMP + 1] = ~0x0;
-       /* trace instruction addresses */
-       config->addr_acc[ETM_DEFAULT_ADDR_COMP + 1] &= ~(BIT(0) | BIT(1));
-       /* Address comparator type must be equal for both halves */
-       config->addr_acc[ETM_DEFAULT_ADDR_COMP + 1] =
-                                       config->addr_acc[ETM_DEFAULT_ADDR_COMP];
-       config->addr_type[ETM_DEFAULT_ADDR_COMP + 1] = ETM_ADDR_TYPE_RANGE;
+        * nr_addr_cmp holds the number of comparator _pair_, so time 2
+        * for the total number of comparators.
+        */
+       nr_comparator = drvdata->nr_addr_cmp * 2;
+
+       /* Go through the tally of comparators looking for a free one. */
+       while (index < nr_comparator) {
+               switch (type) {
+               case ETM_ADDR_TYPE_RANGE:
+                       if (config->addr_type[index] == ETM_ADDR_TYPE_NONE &&
+                           config->addr_type[index + 1] == ETM_ADDR_TYPE_NONE)
+                               return index;
+
+                       /* Address range comparators go in pairs */
+                       index += 2;
+                       break;
+               case ETM_ADDR_TYPE_START:
+               case ETM_ADDR_TYPE_STOP:
+                       if (config->addr_type[index] == ETM_ADDR_TYPE_NONE)
+                               return index;
+
+                       /* Start/stop address can have odd indexes */
+                       index += 1;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+       }
+
+       /* If we are here all the comparators have been used. */
+       return -ENOSPC;
+}
+
+static int etm4_set_event_filters(struct etmv4_drvdata *drvdata,
+                                 struct perf_event *event)
+{
+       int i, comparator, ret = 0;
+       u64 address;
+       struct etmv4_config *config = &drvdata->config;
+       struct etm_filters *filters = event->hw.addr_filters;
+
+       if (!filters)
+               goto default_filter;
+
+       /* Sync events with what Perf got */
+       perf_event_addr_filters_sync(event);
 
        /*
-        * Configure the ViewInst function to filter on address range
-        * comparator '0'.
+        * If there are no filters to deal with simply go ahead with
+        * the default filter, i.e the entire address range.
         */
-       config->viiectlr = BIT(0);
+       if (!filters->nr_filters)
+               goto default_filter;
+
+       for (i = 0; i < filters->nr_filters; i++) {
+               struct etm_filter *filter = &filters->etm_filter[i];
+               enum etm_addr_type type = filter->type;
+
+               /* See if a comparator is free. */
+               comparator = etm4_get_next_comparator(drvdata, type);
+               if (comparator < 0) {
+                       ret = comparator;
+                       goto out;
+               }
+
+               switch (type) {
+               case ETM_ADDR_TYPE_RANGE:
+                       etm4_set_comparator_filter(config,
+                                                  filter->start_addr,
+                                                  filter->stop_addr,
+                                                  comparator);
+                       /*
+                        * TRCVICTLR::SSSTATUS == 1, the start-stop logic is
+                        * in the started state
+                        */
+                       config->vinst_ctrl |= BIT(9);
+
+                       /* No start-stop filtering for ViewInst */
+                       config->vissctlr = 0x0;
+                       break;
+               case ETM_ADDR_TYPE_START:
+               case ETM_ADDR_TYPE_STOP:
+                       /* Get the right start or stop address */
+                       address = (type == ETM_ADDR_TYPE_START ?
+                                  filter->start_addr :
+                                  filter->stop_addr);
+
+                       /* Configure comparator */
+                       etm4_set_start_stop_filter(config, address,
+                                                  comparator, type);
+
+                       /*
+                        * If filters::ssstatus == 1, trace acquisition was
+                        * started but the process was yanked away before the
+                        * the stop address was hit.  As such the start/stop
+                        * logic needs to be re-started so that tracing can
+                        * resume where it left.
+                        *
+                        * The start/stop logic status when a process is
+                        * scheduled out is checked in function
+                        * etm4_disable_perf().
+                        */
+                       if (filters->ssstatus)
+                               config->vinst_ctrl |= BIT(9);
+
+                       /* No include/exclude filtering for ViewInst */
+                       config->viiectlr = 0x0;
+                       break;
+               default:
+                       ret = -EINVAL;
+                       goto out;
+               }
+       }
 
-       /* no start-stop filtering for ViewInst */
-       config->vissctlr = 0x0;
+       goto out;
+
+
+default_filter:
+       etm4_set_default_filter(config);
+
+out:
+       return ret;
 }
 
 void etm4_config_trace_mode(struct etmv4_config *config)
@@ -727,13 +950,9 @@ static int etm4_probe(struct amba_device *adev, const struct amba_id *id)
        struct coresight_platform_data *pdata = NULL;
        struct etmv4_drvdata *drvdata;
        struct resource *res = &adev->res;
-       struct coresight_desc *desc;
+       struct coresight_desc desc = { 0 };
        struct device_node *np = adev->dev.of_node;
 
-       desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
-       if (!desc)
-               return -ENOMEM;
-
        drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
        if (!drvdata)
                return -ENOMEM;
@@ -788,13 +1007,13 @@ static int etm4_probe(struct amba_device *adev, const struct amba_id *id)
        etm4_init_trace_id(drvdata);
        etm4_set_default(&drvdata->config);
 
-       desc->type = CORESIGHT_DEV_TYPE_SOURCE;
-       desc->subtype.source_subtype = CORESIGHT_DEV_SUBTYPE_SOURCE_PROC;
-       desc->ops = &etm4_cs_ops;
-       desc->pdata = pdata;
-       desc->dev = dev;
-       desc->groups = coresight_etmv4_groups;
-       drvdata->csdev = coresight_register(desc);
+       desc.type = CORESIGHT_DEV_TYPE_SOURCE;
+       desc.subtype.source_subtype = CORESIGHT_DEV_SUBTYPE_SOURCE_PROC;
+       desc.ops = &etm4_cs_ops;
+       desc.pdata = pdata;
+       desc.dev = dev;
+       desc.groups = coresight_etmv4_groups;
+       drvdata->csdev = coresight_register(&desc);
        if (IS_ERR(drvdata->csdev)) {
                ret = PTR_ERR(drvdata->csdev);
                goto err_arch_supported;
@@ -826,12 +1045,12 @@ err_arch_supported:
 }
 
 static struct amba_id etm4_ids[] = {
-       {       /* ETM 4.0 - Qualcomm */
-               .id     = 0x0003b95d,
-               .mask   = 0x0003ffff,
+       {       /* ETM 4.0 - Cortex-A53  */
+               .id     = 0x000bb95d,
+               .mask   = 0x000fffff,
                .data   = "ETM 4.0",
        },
-       {       /* ETM 4.0 - Juno board */
+       {       /* ETM 4.0 - Cortex-A57 */
                .id     = 0x000bb95e,
                .mask   = 0x000fffff,
                .data   = "ETM 4.0",
index 5359c5197c1d6e4ccbbabe666785448bd47bdeef..ba8d3f86de2129dd869f156ade0d4a286ff158eb 100644 (file)
 #define TRCSTATR_IDLE_BIT              0
 #define ETM_DEFAULT_ADDR_COMP          0
 
+/* PowerDown Control Register bits */
+#define TRCPDCR_PU                     BIT(3)
+
 /* secure state access levels */
 #define ETM_EXLEVEL_S_APP              BIT(8)
 #define ETM_EXLEVEL_S_OS               BIT(9)
@@ -407,14 +410,6 @@ enum etm_addr_ctxtype {
        ETM_CTX_CTXID_VMID,
 };
 
-enum etm_addr_type {
-       ETM_ADDR_TYPE_NONE,
-       ETM_ADDR_TYPE_SINGLE,
-       ETM_ADDR_TYPE_RANGE,
-       ETM_ADDR_TYPE_START,
-       ETM_ADDR_TYPE_STOP,
-};
-
 extern const struct attribute_group *coresight_etmv4_groups[];
 void etm4_config_trace_mode(struct etmv4_config *config);
 #endif
index 05df789056ccfc823a103d3bc070bef1eaf46d85..860fe6ef563244295557f3b2364af4a0803fbabc 100644 (file)
@@ -176,7 +176,7 @@ static int funnel_probe(struct amba_device *adev, const struct amba_id *id)
        struct coresight_platform_data *pdata = NULL;
        struct funnel_drvdata *drvdata;
        struct resource *res = &adev->res;
-       struct coresight_desc *desc;
+       struct coresight_desc desc = { 0 };
        struct device_node *np = adev->dev.of_node;
 
        if (np) {
@@ -207,17 +207,13 @@ static int funnel_probe(struct amba_device *adev, const struct amba_id *id)
        drvdata->base = base;
        pm_runtime_put(&adev->dev);
 
-       desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
-       if (!desc)
-               return -ENOMEM;
-
-       desc->type = CORESIGHT_DEV_TYPE_LINK;
-       desc->subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_MERG;
-       desc->ops = &funnel_cs_ops;
-       desc->pdata = pdata;
-       desc->dev = dev;
-       desc->groups = coresight_funnel_groups;
-       drvdata->csdev = coresight_register(desc);
+       desc.type = CORESIGHT_DEV_TYPE_LINK;
+       desc.subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_MERG;
+       desc.ops = &funnel_cs_ops;
+       desc.pdata = pdata;
+       desc.dev = dev;
+       desc.groups = coresight_funnel_groups;
+       drvdata->csdev = coresight_register(&desc);
        if (IS_ERR(drvdata->csdev))
                return PTR_ERR(drvdata->csdev);
 
index ad975c58080d28b0a43034ff2938825262951322..196a14be4b3da95306ff0a8994e9ecdaad86162b 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/bitops.h>
 #include <linux/io.h>
 #include <linux/coresight.h>
+#include <linux/pm_runtime.h>
 
 /*
  * Coresight management registers (0xf00-0xfcc)
 #define ETM_MODE_EXCL_KERN     BIT(30)
 #define ETM_MODE_EXCL_USER     BIT(31)
 
-#define coresight_simple_func(type, name, offset)                      \
+typedef u32 (*coresight_read_fn)(const struct device *, u32 offset);
+#define coresight_simple_func(type, func, name, offset)                        \
 static ssize_t name##_show(struct device *_dev,                                \
                           struct device_attribute *attr, char *buf)    \
 {                                                                      \
        type *drvdata = dev_get_drvdata(_dev->parent);                  \
-       return scnprintf(buf, PAGE_SIZE, "0x%x\n",                      \
-                        readl_relaxed(drvdata->base + offset));        \
+       coresight_read_fn fn = func;                                    \
+       u32 val;                                                        \
+       pm_runtime_get_sync(_dev->parent);                              \
+       if (fn)                                                         \
+               val = fn(_dev->parent, offset);                         \
+       else                                                            \
+               val = readl_relaxed(drvdata->base + offset);            \
+       pm_runtime_put_sync(_dev->parent);                              \
+       return scnprintf(buf, PAGE_SIZE, "0x%x\n", val);                \
 }                                                                      \
 static DEVICE_ATTR_RO(name)
 
+enum etm_addr_type {
+       ETM_ADDR_TYPE_NONE,
+       ETM_ADDR_TYPE_SINGLE,
+       ETM_ADDR_TYPE_RANGE,
+       ETM_ADDR_TYPE_START,
+       ETM_ADDR_TYPE_STOP,
+};
+
 enum cs_mode {
        CS_MODE_DISABLED,
        CS_MODE_SYSFS,
index 700f710e4bfa6cc4449d04b2842eaf377f3b9368..0a3d15f0b009b3f5fa97a861854dd66bb46e62bd 100644 (file)
@@ -102,7 +102,7 @@ static int replicator_probe(struct amba_device *adev, const struct amba_id *id)
        struct resource *res = &adev->res;
        struct coresight_platform_data *pdata = NULL;
        struct replicator_state *drvdata;
-       struct coresight_desc *desc;
+       struct coresight_desc desc = { 0 };
        struct device_node *np = adev->dev.of_node;
        void __iomem *base;
 
@@ -134,16 +134,12 @@ static int replicator_probe(struct amba_device *adev, const struct amba_id *id)
        dev_set_drvdata(dev, drvdata);
        pm_runtime_put(&adev->dev);
 
-       desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
-       if (!desc)
-               return -ENOMEM;
-
-       desc->type = CORESIGHT_DEV_TYPE_LINK;
-       desc->subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_SPLIT;
-       desc->ops = &replicator_cs_ops;
-       desc->pdata = adev->dev.platform_data;
-       desc->dev = &adev->dev;
-       drvdata->csdev = coresight_register(desc);
+       desc.type = CORESIGHT_DEV_TYPE_LINK;
+       desc.subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_SPLIT;
+       desc.ops = &replicator_cs_ops;
+       desc.pdata = adev->dev.platform_data;
+       desc.dev = &adev->dev;
+       drvdata->csdev = coresight_register(&desc);
        if (IS_ERR(drvdata->csdev))
                return PTR_ERR(drvdata->csdev);
 
index c6982e312e156892eda2126ad061d23a73522939..3756e71cb8f56d604097d6ddfdfac9e9bbf3aebf 100644 (file)
@@ -69,7 +69,7 @@ static int replicator_probe(struct platform_device *pdev)
        struct device *dev = &pdev->dev;
        struct coresight_platform_data *pdata = NULL;
        struct replicator_drvdata *drvdata;
-       struct coresight_desc *desc;
+       struct coresight_desc desc = { 0 };
        struct device_node *np = pdev->dev.of_node;
 
        if (np) {
@@ -95,18 +95,12 @@ static int replicator_probe(struct platform_device *pdev)
        pm_runtime_enable(&pdev->dev);
        platform_set_drvdata(pdev, drvdata);
 
-       desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
-       if (!desc) {
-               ret = -ENOMEM;
-               goto out_disable_pm;
-       }
-
-       desc->type = CORESIGHT_DEV_TYPE_LINK;
-       desc->subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_SPLIT;
-       desc->ops = &replicator_cs_ops;
-       desc->pdata = pdev->dev.platform_data;
-       desc->dev = &pdev->dev;
-       drvdata->csdev = coresight_register(desc);
+       desc.type = CORESIGHT_DEV_TYPE_LINK;
+       desc.subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_SPLIT;
+       desc.ops = &replicator_cs_ops;
+       desc.pdata = pdev->dev.platform_data;
+       desc.dev = &pdev->dev;
+       drvdata->csdev = coresight_register(&desc);
        if (IS_ERR(drvdata->csdev)) {
                ret = PTR_ERR(drvdata->csdev);
                goto out_disable_pm;
index 73be58a11e4f88dfb8c4ed1be109fddce8e67ae8..49e0f1b925a5a656e228e9cb58c74c74997eb907 100644 (file)
@@ -105,10 +105,12 @@ module_param_named(
 /**
  * struct channel_space - central management entity for extended ports
  * @base:              memory mapped base address where channels start.
+ * @phys:              physical base address of channel region.
  * @guaraneed:         is the channel delivery guaranteed.
  */
 struct channel_space {
        void __iomem            *base;
+       phys_addr_t             phys;
        unsigned long           *guaranteed;
 };
 
@@ -196,7 +198,7 @@ static void stm_enable_hw(struct stm_drvdata *drvdata)
 }
 
 static int stm_enable(struct coresight_device *csdev,
-                     struct perf_event_attr *attr, u32 mode)
+                     struct perf_event *event, u32 mode)
 {
        u32 val;
        struct stm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
@@ -258,7 +260,8 @@ static void stm_disable_hw(struct stm_drvdata *drvdata)
                stm_hwevent_disable_hw(drvdata);
 }
 
-static void stm_disable(struct coresight_device *csdev)
+static void stm_disable(struct coresight_device *csdev,
+                       struct perf_event *event)
 {
        struct stm_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
 
@@ -353,7 +356,24 @@ static void stm_generic_unlink(struct stm_data *stm_data,
        if (!drvdata || !drvdata->csdev)
                return;
 
-       stm_disable(drvdata->csdev);
+       stm_disable(drvdata->csdev, NULL);
+}
+
+static phys_addr_t
+stm_mmio_addr(struct stm_data *stm_data, unsigned int master,
+             unsigned int channel, unsigned int nr_chans)
+{
+       struct stm_drvdata *drvdata = container_of(stm_data,
+                                                  struct stm_drvdata, stm);
+       phys_addr_t addr;
+
+       addr = drvdata->chs.phys + channel * BYTES_PER_CHANNEL;
+
+       if (offset_in_page(addr) ||
+           offset_in_page(nr_chans * BYTES_PER_CHANNEL))
+               return 0;
+
+       return addr;
 }
 
 static long stm_generic_set_options(struct stm_data *stm_data,
@@ -616,7 +636,7 @@ static ssize_t traceid_store(struct device *dev,
 static DEVICE_ATTR_RW(traceid);
 
 #define coresight_stm_simple_func(name, offset)        \
-       coresight_simple_func(struct stm_drvdata, name, offset)
+       coresight_simple_func(struct stm_drvdata, NULL, name, offset)
 
 coresight_stm_simple_func(tcsr, STMTCSR);
 coresight_stm_simple_func(tsfreqr, STMTSFREQR);
@@ -761,7 +781,9 @@ static void stm_init_generic_data(struct stm_drvdata *drvdata)
        drvdata->stm.sw_end = 1;
        drvdata->stm.hw_override = true;
        drvdata->stm.sw_nchannels = drvdata->numsp;
+       drvdata->stm.sw_mmiosz = BYTES_PER_CHANNEL;
        drvdata->stm.packet = stm_generic_packet;
+       drvdata->stm.mmio_addr = stm_mmio_addr;
        drvdata->stm.link = stm_generic_link;
        drvdata->stm.unlink = stm_generic_unlink;
        drvdata->stm.set_options = stm_generic_set_options;
@@ -778,7 +800,7 @@ static int stm_probe(struct amba_device *adev, const struct amba_id *id)
        struct resource *res = &adev->res;
        struct resource ch_res;
        size_t res_size, bitmap_size;
-       struct coresight_desc *desc;
+       struct coresight_desc desc = { 0 };
        struct device_node *np = adev->dev.of_node;
 
        if (np) {
@@ -808,6 +830,7 @@ static int stm_probe(struct amba_device *adev, const struct amba_id *id)
        ret = stm_get_resource_byname(np, "stm-stimulus-base", &ch_res);
        if (ret)
                return ret;
+       drvdata->chs.phys = ch_res.start;
 
        base = devm_ioremap_resource(dev, &ch_res);
        if (IS_ERR(base))
@@ -843,19 +866,13 @@ static int stm_probe(struct amba_device *adev, const struct amba_id *id)
                return -EPROBE_DEFER;
        }
 
-       desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
-       if (!desc) {
-               ret = -ENOMEM;
-               goto stm_unregister;
-       }
-
-       desc->type = CORESIGHT_DEV_TYPE_SOURCE;
-       desc->subtype.source_subtype = CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE;
-       desc->ops = &stm_cs_ops;
-       desc->pdata = pdata;
-       desc->dev = dev;
-       desc->groups = coresight_stm_groups;
-       drvdata->csdev = coresight_register(desc);
+       desc.type = CORESIGHT_DEV_TYPE_SOURCE;
+       desc.subtype.source_subtype = CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE;
+       desc.ops = &stm_cs_ops;
+       desc.pdata = pdata;
+       desc.dev = dev;
+       desc.groups = coresight_stm_groups;
+       drvdata->csdev = coresight_register(&desc);
        if (IS_ERR(drvdata->csdev)) {
                ret = PTR_ERR(drvdata->csdev);
                goto stm_unregister;
index 466af86fd76f5df9b81d0f9c8b59a18f686c664b..d6941ea24d8df1152baf39177e9ac9fea733f499 100644 (file)
@@ -22,7 +22,7 @@
 #include "coresight-priv.h"
 #include "coresight-tmc.h"
 
-void tmc_etb_enable_hw(struct tmc_drvdata *drvdata)
+static void tmc_etb_enable_hw(struct tmc_drvdata *drvdata)
 {
        CS_UNLOCK(drvdata->base);
 
@@ -48,6 +48,7 @@ static void tmc_etb_dump_hw(struct tmc_drvdata *drvdata)
        int i;
 
        bufp = drvdata->buf;
+       drvdata->len = 0;
        while (1) {
                for (i = 0; i < drvdata->memwidth; i++) {
                        read_data = readl_relaxed(drvdata->base + TMC_RRD);
@@ -55,6 +56,7 @@ static void tmc_etb_dump_hw(struct tmc_drvdata *drvdata)
                                return;
                        memcpy(bufp, &read_data, 4);
                        bufp += 4;
+                       drvdata->len += 4;
                }
        }
 }
@@ -166,7 +168,7 @@ out:
        spin_unlock_irqrestore(&drvdata->spinlock, flags);
 
        /* Free memory outside the spinlock if need be */
-       if (!used && buf)
+       if (!used)
                kfree(buf);
 
        if (!ret)
index 688be9e060fc547f57a259bae61a49579edfa8e8..886ea83c68e0cf2233398f46cb00edbe188c56b6 100644 (file)
@@ -20,7 +20,7 @@
 #include "coresight-priv.h"
 #include "coresight-tmc.h"
 
-void tmc_etr_enable_hw(struct tmc_drvdata *drvdata)
+static void tmc_etr_enable_hw(struct tmc_drvdata *drvdata)
 {
        u32 axictl;
 
@@ -64,11 +64,17 @@ static void tmc_etr_dump_hw(struct tmc_drvdata *drvdata)
        rwp = readl_relaxed(drvdata->base + TMC_RWP);
        val = readl_relaxed(drvdata->base + TMC_STS);
 
-       /* How much memory do we still have */
-       if (val & BIT(0))
+       /*
+        * Adjust the buffer to point to the beginning of the trace data
+        * and update the available trace data.
+        */
+       if (val & TMC_STS_FULL) {
                drvdata->buf = drvdata->vaddr + rwp - drvdata->paddr;
-       else
+               drvdata->len = drvdata->size;
+       } else {
                drvdata->buf = drvdata->vaddr;
+               drvdata->len = rwp - drvdata->paddr;
+       }
 }
 
 static void tmc_etr_disable_hw(struct tmc_drvdata *drvdata)
index 9e02ac963cd0e3fbb38f9ee5e3fd082719f38bf7..d8517d2a968caf8f97e1a2e5c89c9167a12bc58d 100644 (file)
@@ -38,8 +38,7 @@ void tmc_wait_for_tmcready(struct tmc_drvdata *drvdata)
        if (coresight_timeout(drvdata->base,
                              TMC_STS, TMC_STS_TMCREADY_BIT, 1)) {
                dev_err(drvdata->dev,
-                       "timeout observed when probing at offset %#x\n",
-                       TMC_STS);
+                       "timeout while waiting for TMC to be Ready\n");
        }
 }
 
@@ -56,8 +55,7 @@ void tmc_flush_and_stop(struct tmc_drvdata *drvdata)
        if (coresight_timeout(drvdata->base,
                              TMC_FFCR, TMC_FFCR_FLUSHMAN_BIT, 0)) {
                dev_err(drvdata->dev,
-                       "timeout observed when probing at offset %#x\n",
-                       TMC_FFCR);
+               "timeout while waiting for completion of Manual Flush\n");
        }
 
        tmc_wait_for_tmcready(drvdata);
@@ -140,8 +138,8 @@ static ssize_t tmc_read(struct file *file, char __user *data, size_t len,
                                                   struct tmc_drvdata, miscdev);
        char *bufp = drvdata->buf + *ppos;
 
-       if (*ppos + len > drvdata->size)
-               len = drvdata->size - *ppos;
+       if (*ppos + len > drvdata->len)
+               len = drvdata->len - *ppos;
 
        if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
                if (bufp == (char *)(drvdata->vaddr + drvdata->size))
@@ -160,7 +158,7 @@ static ssize_t tmc_read(struct file *file, char __user *data, size_t len,
        *ppos += len;
 
        dev_dbg(drvdata->dev, "%s: %zu bytes copied, %d bytes left\n",
-               __func__, len, (int)(drvdata->size - *ppos));
+               __func__, len, (int)(drvdata->len - *ppos));
        return len;
 }
 
@@ -220,7 +218,7 @@ static enum tmc_mem_intf_width tmc_get_memwidth(u32 devid)
 }
 
 #define coresight_tmc_simple_func(name, offset)                        \
-       coresight_simple_func(struct tmc_drvdata, name, offset)
+       coresight_simple_func(struct tmc_drvdata, NULL, name, offset)
 
 coresight_tmc_simple_func(rsz, TMC_RSZ);
 coresight_tmc_simple_func(sts, TMC_STS);
@@ -249,8 +247,8 @@ static struct attribute *coresight_tmc_mgmt_attrs[] = {
        NULL,
 };
 
-ssize_t trigger_cntr_show(struct device *dev,
-                         struct device_attribute *attr, char *buf)
+static ssize_t trigger_cntr_show(struct device *dev,
+                                struct device_attribute *attr, char *buf)
 {
        struct tmc_drvdata *drvdata = dev_get_drvdata(dev->parent);
        unsigned long val = drvdata->trigger_cntr;
@@ -304,27 +302,32 @@ static int tmc_probe(struct amba_device *adev, const struct amba_id *id)
        struct coresight_platform_data *pdata = NULL;
        struct tmc_drvdata *drvdata;
        struct resource *res = &adev->res;
-       struct coresight_desc *desc;
+       struct coresight_desc desc = { 0 };
        struct device_node *np = adev->dev.of_node;
 
        if (np) {
                pdata = of_get_coresight_platform_data(dev, np);
-               if (IS_ERR(pdata))
-                       return PTR_ERR(pdata);
+               if (IS_ERR(pdata)) {
+                       ret = PTR_ERR(pdata);
+                       goto out;
+               }
                adev->dev.platform_data = pdata;
        }
 
+       ret = -ENOMEM;
        drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
        if (!drvdata)
-               return -ENOMEM;
+               goto out;
 
        drvdata->dev = &adev->dev;
        dev_set_drvdata(dev, drvdata);
 
        /* Validity for the resource is already checked by the AMBA core */
        base = devm_ioremap_resource(dev, res);
-       if (IS_ERR(base))
-               return PTR_ERR(base);
+       if (IS_ERR(base)) {
+               ret = PTR_ERR(base);
+               goto out;
+       }
 
        drvdata->base = base;
 
@@ -347,33 +350,28 @@ static int tmc_probe(struct amba_device *adev, const struct amba_id *id)
 
        pm_runtime_put(&adev->dev);
 
-       desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
-       if (!desc) {
-               ret = -ENOMEM;
-               goto err_devm_kzalloc;
-       }
-
-       desc->pdata = pdata;
-       desc->dev = dev;
-       desc->subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_BUFFER;
-       desc->groups = coresight_tmc_groups;
+       desc.pdata = pdata;
+       desc.dev = dev;
+       desc.groups = coresight_tmc_groups;
 
        if (drvdata->config_type == TMC_CONFIG_TYPE_ETB) {
-               desc->type = CORESIGHT_DEV_TYPE_SINK;
-               desc->ops = &tmc_etb_cs_ops;
+               desc.type = CORESIGHT_DEV_TYPE_SINK;
+               desc.subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_BUFFER;
+               desc.ops = &tmc_etb_cs_ops;
        } else if (drvdata->config_type == TMC_CONFIG_TYPE_ETR) {
-               desc->type = CORESIGHT_DEV_TYPE_SINK;
-               desc->ops = &tmc_etr_cs_ops;
+               desc.type = CORESIGHT_DEV_TYPE_SINK;
+               desc.subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_BUFFER;
+               desc.ops = &tmc_etr_cs_ops;
        } else {
-               desc->type = CORESIGHT_DEV_TYPE_LINKSINK;
-               desc->subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_FIFO;
-               desc->ops = &tmc_etf_cs_ops;
+               desc.type = CORESIGHT_DEV_TYPE_LINKSINK;
+               desc.subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_FIFO;
+               desc.ops = &tmc_etf_cs_ops;
        }
 
-       drvdata->csdev = coresight_register(desc);
+       drvdata->csdev = coresight_register(&desc);
        if (IS_ERR(drvdata->csdev)) {
                ret = PTR_ERR(drvdata->csdev);
-               goto err_devm_kzalloc;
+               goto out;
        }
 
        drvdata->miscdev.name = pdata->name;
@@ -381,16 +379,8 @@ static int tmc_probe(struct amba_device *adev, const struct amba_id *id)
        drvdata->miscdev.fops = &tmc_fops;
        ret = misc_register(&drvdata->miscdev);
        if (ret)
-               goto err_misc_register;
-
-       return 0;
-
-err_misc_register:
-       coresight_unregister(drvdata->csdev);
-err_devm_kzalloc:
-       if (drvdata->config_type == TMC_CONFIG_TYPE_ETR)
-               dma_free_coherent(dev, drvdata->size,
-                               drvdata->vaddr, drvdata->paddr);
+               coresight_unregister(drvdata->csdev);
+out:
        return ret;
 }
 
index 5c5fe2ad2ca70f351e80cef2970641d462da6647..44b3ae346118f45b7dc5d2dd79ed550cee8d8144 100644 (file)
@@ -98,7 +98,8 @@ enum tmc_mem_intf_width {
  * @buf:       area of memory where trace data get sent.
  * @paddr:     DMA start location in RAM.
  * @vaddr:     virtual representation of @paddr.
- * @size:      @buf size.
+ * @size:      trace buffer size.
+ * @len:       size of the available trace.
  * @mode:      how this TMC is being used.
  * @config_type: TMC variant, must be of type @tmc_config_type.
  * @memwidth:  width of the memory interface databus, in bytes.
@@ -115,6 +116,7 @@ struct tmc_drvdata {
        dma_addr_t              paddr;
        void __iomem            *vaddr;
        u32                     size;
+       u32                     len;
        local_t                 mode;
        enum tmc_config_type    config_type;
        enum tmc_mem_intf_width memwidth;
index 4e471e2e9d896df24399c9e02cdd06a463ac27be..0673baf0f2f5b93bbe9c14c2a7c9a7d390f338b7 100644 (file)
@@ -119,7 +119,7 @@ static int tpiu_probe(struct amba_device *adev, const struct amba_id *id)
        struct coresight_platform_data *pdata = NULL;
        struct tpiu_drvdata *drvdata;
        struct resource *res = &adev->res;
-       struct coresight_desc *desc;
+       struct coresight_desc desc = { 0 };
        struct device_node *np = adev->dev.of_node;
 
        if (np) {
@@ -154,16 +154,12 @@ static int tpiu_probe(struct amba_device *adev, const struct amba_id *id)
 
        pm_runtime_put(&adev->dev);
 
-       desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL);
-       if (!desc)
-               return -ENOMEM;
-
-       desc->type = CORESIGHT_DEV_TYPE_SINK;
-       desc->subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_PORT;
-       desc->ops = &tpiu_cs_ops;
-       desc->pdata = pdata;
-       desc->dev = dev;
-       drvdata->csdev = coresight_register(desc);
+       desc.type = CORESIGHT_DEV_TYPE_SINK;
+       desc.subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_PORT;
+       desc.ops = &tpiu_cs_ops;
+       desc.pdata = pdata;
+       desc.dev = dev;
+       drvdata->csdev = coresight_register(&desc);
        if (IS_ERR(drvdata->csdev))
                return PTR_ERR(drvdata->csdev);
 
index d08d1ab9bba5d7e1c0772d48b6d43802057e323d..7bf00a0beb6f14b4c69cdaf619a2d981e58f612a 100644 (file)
@@ -257,7 +257,7 @@ static void coresight_disable_source(struct coresight_device *csdev)
 {
        if (atomic_dec_return(csdev->refcnt) == 0) {
                if (source_ops(csdev)->disable) {
-                       source_ops(csdev)->disable(csdev);
+                       source_ops(csdev)->disable(csdev, NULL);
                        csdev->enable = false;
                }
        }
@@ -429,7 +429,7 @@ struct list_head *coresight_build_path(struct coresight_device *csdev)
 
        path = kzalloc(sizeof(struct list_head), GFP_KERNEL);
        if (!path)
-               return NULL;
+               return ERR_PTR(-ENOMEM);
 
        INIT_LIST_HEAD(path);
 
@@ -725,7 +725,8 @@ static int coresight_orphan_match(struct device *dev, void *data)
                /* We have found at least one orphan connection */
                if (conn->child_dev == NULL) {
                        /* Does it match this newly added device? */
-                       if (!strcmp(dev_name(&csdev->dev), conn->child_name)) {
+                       if (conn->child_name &&
+                           !strcmp(dev_name(&csdev->dev), conn->child_name)) {
                                conn->child_dev = csdev;
                        } else {
                                /* This component still has an orphan */
@@ -893,7 +894,7 @@ struct coresight_device *coresight_register(struct coresight_desc *desc)
        int nr_refcnts = 1;
        atomic_t *refcnts = NULL;
        struct coresight_device *csdev;
-       struct coresight_connection *conns;
+       struct coresight_connection *conns = NULL;
 
        csdev = kzalloc(sizeof(*csdev), GFP_KERNEL);
        if (!csdev) {
@@ -921,16 +922,20 @@ struct coresight_device *coresight_register(struct coresight_desc *desc)
 
        csdev->nr_inport = desc->pdata->nr_inport;
        csdev->nr_outport = desc->pdata->nr_outport;
-       conns = kcalloc(csdev->nr_outport, sizeof(*conns), GFP_KERNEL);
-       if (!conns) {
-               ret = -ENOMEM;
-               goto err_kzalloc_conns;
-       }
 
-       for (i = 0; i < csdev->nr_outport; i++) {
-               conns[i].outport = desc->pdata->outports[i];
-               conns[i].child_name = desc->pdata->child_names[i];
-               conns[i].child_port = desc->pdata->child_ports[i];
+       /* Initialise connections if there is at least one outport */
+       if (csdev->nr_outport) {
+               conns = kcalloc(csdev->nr_outport, sizeof(*conns), GFP_KERNEL);
+               if (!conns) {
+                       ret = -ENOMEM;
+                       goto err_kzalloc_conns;
+               }
+
+               for (i = 0; i < csdev->nr_outport; i++) {
+                       conns[i].outport = desc->pdata->outports[i];
+                       conns[i].child_name = desc->pdata->child_names[i];
+                       conns[i].child_port = desc->pdata->child_ports[i];
+               }
        }
 
        csdev->conns = conns;
index b68da1888fd515879a43df8f6173dd77cdb8754e..629e031b745651f136916d482506b953dc12597a 100644 (file)
@@ -166,7 +166,7 @@ struct coresight_platform_data *of_get_coresight_platform_data(
 
                        rdev = of_coresight_get_endpoint_device(rparent);
                        if (!rdev)
-                               continue;
+                               return ERR_PTR(-EPROBE_DEFER);
 
                        pdata->child_names[i] = dev_name(rdev);
                        pdata->child_ports[i] = rendpoint.id;
@@ -184,6 +184,7 @@ struct coresight_platform_data *of_get_coresight_platform_data(
                        break;
                }
        }
+       of_node_put(dn);
 
        return pdata;
 }
index d130cdc78f4344a885b1fac599a1330beb4ee3eb..7fa65ab664fb940d7ce4fe4a5fdaad53fec17656 100644 (file)
@@ -8,8 +8,6 @@ menu "Pressure sensors"
 config BMP280
        tristate "Bosch Sensortec BMP180/BMP280 pressure sensor I2C driver"
        depends on (I2C || SPI_MASTER)
-       depends on !(BMP085_I2C=y || BMP085_I2C=m)
-       depends on !(BMP085_SPI=y || BMP085_SPI=m)
        select REGMAP
        select BMP280_I2C if (I2C)
        select BMP280_SPI if (SPI_MASTER)
index 65ebbd11170221c8d0180958040c1d1c2f939dda..92595b98e7ede7b96dc4c9dd44f4629262f6e3a6 100644 (file)
@@ -1013,23 +1013,12 @@ static struct miscdevice uinput_misc = {
        .minor          = UINPUT_MINOR,
        .name           = UINPUT_NAME,
 };
+module_misc_device(uinput_misc);
+
 MODULE_ALIAS_MISCDEV(UINPUT_MINOR);
 MODULE_ALIAS("devname:" UINPUT_NAME);
 
-static int __init uinput_init(void)
-{
-       return misc_register(&uinput_misc);
-}
-
-static void __exit uinput_exit(void)
-{
-       misc_deregister(&uinput_misc);
-}
-
 MODULE_AUTHOR("Aristeu Sergio Rozanski Filho");
 MODULE_DESCRIPTION("User level driver support for input subsystem");
 MODULE_LICENSE("GPL");
 MODULE_VERSION("0.3");
-
-module_init(uinput_init);
-module_exit(uinput_exit);
index 9ebd2cfbd8490d212502cc077f8f2fe2e36a551a..c784ddcd4405a6a0c384eb9275915ff6e34784b2 100644 (file)
@@ -1171,27 +1171,10 @@ static struct miscdevice _nvm_misc = {
        .nodename       = "lightnvm/control",
        .fops           = &_ctl_fops,
 };
+module_misc_device(_nvm_misc);
 
 MODULE_ALIAS_MISCDEV(MISC_DYNAMIC_MINOR);
 
-static int __init nvm_mod_init(void)
-{
-       int ret;
-
-       ret = misc_register(&_nvm_misc);
-       if (ret)
-               pr_err("nvm: misc_register failed for control device");
-
-       return ret;
-}
-
-static void __exit nvm_mod_exit(void)
-{
-       misc_deregister(&_nvm_misc);
-}
-
 MODULE_AUTHOR("Matias Bjorling <m@bjorling.me>");
 MODULE_LICENSE("GPL v2");
 MODULE_VERSION("0.1");
-module_init(nvm_mod_init);
-module_exit(nvm_mod_exit);
index e9a6976e101071b99fd8149d2cf9741911d8a6cc..76d9c51de6c99d3cdef92cbe40e07077cb690994 100644 (file)
@@ -28,4 +28,13 @@ config MCB_PCI
 
           If build as a module, the module is called mcb-pci.ko
 
+config MCB_LPC
+          tristate "LPC (non PCI) based MCB carrier"
+          default n
+          help
+
+          This is a MCB carrier on a LPC or non PCI device.
+
+          If build as a module, the module is called mcb-lpc.ko
+
 endif # MCB
index 1ae141311defb9888e24ca404a733147ead9956e..bcc7745774abfee8ffa2e552c5f0175cd25be01b 100644 (file)
@@ -5,3 +5,4 @@ mcb-y += mcb-core.o
 mcb-y += mcb-parse.o
 
 obj-$(CONFIG_MCB_PCI) += mcb-pci.o
+obj-$(CONFIG_MCB_LPC) += mcb-lpc.o
index 6f2c8522e14aaf74e0ed7eef7a1cdf60ee335b9b..5306966efc11d04a8c56a8f9a2d2a1d44ebed743 100644 (file)
@@ -369,7 +369,6 @@ struct mcb_device *mcb_alloc_dev(struct mcb_bus *bus)
        if (!dev)
                return NULL;
 
-       INIT_LIST_HEAD(&dev->bus_list);
        dev->bus = bus;
 
        return dev;
@@ -405,20 +404,6 @@ static int __mcb_bus_add_devices(struct device *dev, void *data)
        return 0;
 }
 
-static int __mcb_bus_add_child(struct device *dev, void *data)
-{
-       struct mcb_device *mdev = to_mcb_device(dev);
-       struct mcb_bus *child;
-
-       BUG_ON(!mdev->is_added);
-       child = mdev->subordinate;
-
-       if (child)
-               mcb_bus_add_devices(child);
-
-       return 0;
-}
-
 /**
  * mcb_bus_add_devices() - Add devices in the bus' internal device list
  * @bus: The @mcb_bus we add the devices
@@ -428,8 +413,6 @@ static int __mcb_bus_add_child(struct device *dev, void *data)
 void mcb_bus_add_devices(const struct mcb_bus *bus)
 {
        bus_for_each_dev(&mcb_bus_type, NULL, NULL, __mcb_bus_add_devices);
-       bus_for_each_dev(&mcb_bus_type, NULL, NULL, __mcb_bus_add_child);
-
 }
 EXPORT_SYMBOL_GPL(mcb_bus_add_devices);
 
index 5254e0285725cc85f36b1a0258b9de41367f8e74..d6e6933b19f1863f72a2b5fdc810dc3086a36f6f 100644 (file)
@@ -112,6 +112,15 @@ struct chameleon_bdd {
        u32 size;
 } __packed;
 
+struct chameleon_bar {
+       u32 addr;
+       u32 size;
+};
+
+#define BAR_CNT(x) ((x) & 0x07)
+#define CHAMELEON_BAR_MAX      6
+#define BAR_DESC_SIZE(x)       ((x) * sizeof(struct chameleon_bar) + sizeof(__le32))
+
 int chameleon_parse_cells(struct mcb_bus *bus, phys_addr_t mapbase,
                          void __iomem *base);
 
diff --git a/drivers/mcb/mcb-lpc.c b/drivers/mcb/mcb-lpc.c
new file mode 100644 (file)
index 0000000..d072c08
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * MEN Chameleon Bus.
+ *
+ * Copyright (C) 2014 MEN Mikroelektronik GmbH (www.men.de)
+ * Author: Andreas Werner <andreas.werner@men.de>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; version 2 of the License.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/dmi.h>
+#include <linux/mcb.h>
+#include <linux/io.h>
+#include "mcb-internal.h"
+
+struct priv {
+       struct mcb_bus *bus;
+       struct resource *mem;
+       void __iomem *base;
+};
+
+static int mcb_lpc_probe(struct platform_device *pdev)
+{
+       struct resource *res;
+       struct priv *priv;
+       int ret = 0;
+
+       priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       priv->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!priv->mem) {
+               dev_err(&pdev->dev, "No Memory resource\n");
+               return -ENODEV;
+       }
+
+       res = devm_request_mem_region(&pdev->dev, priv->mem->start,
+                                     resource_size(priv->mem),
+                                     KBUILD_MODNAME);
+       if (!res) {
+               dev_err(&pdev->dev, "Failed to request IO memory\n");
+               return -EBUSY;
+       }
+
+       priv->base = devm_ioremap(&pdev->dev, priv->mem->start,
+                                 resource_size(priv->mem));
+       if (!priv->base) {
+               dev_err(&pdev->dev, "Cannot ioremap\n");
+               return -ENOMEM;
+       }
+
+       platform_set_drvdata(pdev, priv);
+
+       priv->bus = mcb_alloc_bus(&pdev->dev);
+       if (IS_ERR(priv->bus))
+               return PTR_ERR(priv->bus);
+
+       ret = chameleon_parse_cells(priv->bus, priv->mem->start, priv->base);
+       if (ret < 0) {
+               mcb_release_bus(priv->bus);
+               return ret;
+       }
+
+       dev_dbg(&pdev->dev, "Found %d cells\n", ret);
+
+       mcb_bus_add_devices(priv->bus);
+
+       return 0;
+
+}
+
+static int mcb_lpc_remove(struct platform_device *pdev)
+{
+       struct priv *priv = platform_get_drvdata(pdev);
+
+       mcb_release_bus(priv->bus);
+
+       return 0;
+}
+
+static struct platform_device *mcb_lpc_pdev;
+
+static int mcb_lpc_create_platform_device(const struct dmi_system_id *id)
+{
+       struct resource *res = id->driver_data;
+       int ret;
+
+       mcb_lpc_pdev = platform_device_alloc("mcb-lpc", -1);
+       if (!mcb_lpc_pdev)
+               return -ENOMEM;
+
+       ret = platform_device_add_resources(mcb_lpc_pdev, res, 1);
+       if (ret)
+               goto out_put;
+
+       ret = platform_device_add(mcb_lpc_pdev);
+       if (ret)
+               goto out_put;
+
+       return 0;
+
+out_put:
+       platform_device_put(mcb_lpc_pdev);
+       return ret;
+}
+
+static struct resource sc24_fpga_resource = {
+       .start = 0xe000e000,
+       .end = 0xe000e000 + CHAM_HEADER_SIZE,
+       .flags = IORESOURCE_MEM,
+};
+
+static struct platform_driver mcb_lpc_driver = {
+       .driver         = {
+               .name = "mcb-lpc",
+       },
+       .probe          = mcb_lpc_probe,
+       .remove         = mcb_lpc_remove,
+};
+
+static const struct dmi_system_id mcb_lpc_dmi_table[] = {
+       {
+               .ident = "SC24",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "MEN"),
+                       DMI_MATCH(DMI_PRODUCT_VERSION, "14SC24"),
+               },
+               .driver_data = (void *)&sc24_fpga_resource,
+               .callback = mcb_lpc_create_platform_device,
+       },
+       {}
+};
+MODULE_DEVICE_TABLE(dmi, mcb_lpc_dmi_table);
+
+static int __init mcb_lpc_init(void)
+{
+       if (!dmi_check_system(mcb_lpc_dmi_table))
+               return -ENODEV;
+
+       return platform_driver_register(&mcb_lpc_driver);
+}
+
+static void __exit mcb_lpc_exit(void)
+{
+       platform_device_unregister(mcb_lpc_pdev);
+       platform_driver_unregister(&mcb_lpc_driver);
+}
+
+module_init(mcb_lpc_init);
+module_exit(mcb_lpc_exit);
+
+MODULE_AUTHOR("Andreas Werner <andreas.werner@men.de>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("MCB over LPC support");
index dbecbed0d258031d3a81e31dbdd878eb0b7ba9f7..4ca2739b4fad54f0b3c07089f3802d43e75c4e3b 100644 (file)
@@ -26,19 +26,20 @@ static inline uint32_t get_next_dtype(void __iomem *p)
 }
 
 static int chameleon_parse_bdd(struct mcb_bus *bus,
-                       phys_addr_t mapbase,
+                       struct chameleon_bar *cb,
                        void __iomem *base)
 {
        return 0;
 }
 
 static int chameleon_parse_gdd(struct mcb_bus *bus,
-                       phys_addr_t mapbase,
-                       void __iomem *base)
+                       struct chameleon_bar *cb,
+                       void __iomem *base, int bar_count)
 {
        struct chameleon_gdd __iomem *gdd =
                (struct chameleon_gdd __iomem *) base;
        struct mcb_device *mdev;
+       u32 dev_mapbase;
        u32 offset;
        u32 size;
        int ret;
@@ -61,13 +62,39 @@ static int chameleon_parse_gdd(struct mcb_bus *bus,
        mdev->group = GDD_GRP(reg2);
        mdev->inst = GDD_INS(reg2);
 
+       /*
+        * If the BAR is missing, dev_mapbase is zero, or if the
+        * device is IO mapped we just print a warning and go on with the
+        * next device, instead of completely stop the gdd parser
+        */
+       if (mdev->bar > bar_count - 1) {
+               pr_info("No BAR for 16z%03d\n", mdev->id);
+               ret = 0;
+               goto err;
+       }
+
+       dev_mapbase = cb[mdev->bar].addr;
+       if (!dev_mapbase) {
+               pr_info("BAR not assigned for 16z%03d\n", mdev->id);
+               ret = 0;
+               goto err;
+       }
+
+       if (dev_mapbase & 0x01) {
+               pr_info("IO mapped Device (16z%03d) not yet supported\n",
+                       mdev->id);
+               ret = 0;
+               goto err;
+       }
+
        pr_debug("Found a 16z%03d\n", mdev->id);
 
        mdev->irq.start = GDD_IRQ(reg1);
        mdev->irq.end = GDD_IRQ(reg1);
        mdev->irq.flags = IORESOURCE_IRQ;
 
-       mdev->mem.start = mapbase + offset;
+       mdev->mem.start = dev_mapbase + offset;
+
        mdev->mem.end = mdev->mem.start + size - 1;
        mdev->mem.flags = IORESOURCE_MEM;
 
@@ -85,13 +112,76 @@ err:
        return ret;
 }
 
+static void chameleon_parse_bar(void __iomem *base,
+                               struct chameleon_bar *cb, int bar_count)
+{
+       char __iomem *p = base;
+       int i;
+
+       /* skip reg1 */
+       p += sizeof(__le32);
+
+       for (i = 0; i < bar_count; i++) {
+               cb[i].addr = readl(p);
+               cb[i].size = readl(p + 4);
+
+               p += sizeof(struct chameleon_bar);
+       }
+}
+
+static int chameleon_get_bar(char __iomem **base, phys_addr_t mapbase,
+                            struct chameleon_bar **cb)
+{
+       struct chameleon_bar *c;
+       int bar_count;
+       __le32 reg;
+       u32 dtype;
+
+       /*
+        * For those devices which are not connected
+        * to the PCI Bus (e.g. LPC) there is a bar
+        * descriptor located directly after the
+        * chameleon header. This header is comparable
+        * to a PCI header.
+        */
+       dtype = get_next_dtype(*base);
+       if (dtype == CHAMELEON_DTYPE_BAR) {
+               reg = readl(*base);
+
+               bar_count = BAR_CNT(reg);
+               if (bar_count <= 0 && bar_count > CHAMELEON_BAR_MAX)
+                       return -ENODEV;
+
+               c = kcalloc(bar_count, sizeof(struct chameleon_bar),
+                           GFP_KERNEL);
+               if (!c)
+                       return -ENOMEM;
+
+               chameleon_parse_bar(*base, c, bar_count);
+               *base += BAR_DESC_SIZE(bar_count);
+       } else {
+               c = kzalloc(sizeof(struct chameleon_bar), GFP_KERNEL);
+               if (!c)
+                       return -ENOMEM;
+
+               bar_count = 1;
+               c->addr = mapbase;
+       }
+
+       *cb = c;
+
+       return bar_count;
+}
+
 int chameleon_parse_cells(struct mcb_bus *bus, phys_addr_t mapbase,
                        void __iomem *base)
 {
-       char __iomem *p = base;
        struct chameleon_fpga_header *header;
-       uint32_t dtype;
+       struct chameleon_bar *cb;
+       char __iomem *p = base;
        int num_cells = 0;
+       uint32_t dtype;
+       int bar_count;
        int ret = 0;
        u32 hsize;
 
@@ -108,8 +198,8 @@ int chameleon_parse_cells(struct mcb_bus *bus, phys_addr_t mapbase,
        if (header->magic != CHAMELEONV2_MAGIC) {
                pr_err("Unsupported chameleon version 0x%x\n",
                                header->magic);
-               kfree(header);
-               return -ENODEV;
+               ret = -ENODEV;
+               goto free_header;
        }
        p += hsize;
 
@@ -119,16 +209,20 @@ int chameleon_parse_cells(struct mcb_bus *bus, phys_addr_t mapbase,
        snprintf(bus->name, CHAMELEON_FILENAME_LEN + 1, "%s",
                 header->filename);
 
+       bar_count = chameleon_get_bar(&p, mapbase, &cb);
+       if (bar_count < 0)
+               goto free_header;
+
        for_each_chameleon_cell(dtype, p) {
                switch (dtype) {
                case CHAMELEON_DTYPE_GENERAL:
-                       ret = chameleon_parse_gdd(bus, mapbase, p);
+                       ret = chameleon_parse_gdd(bus, cb, p, bar_count);
                        if (ret < 0)
-                               goto out;
+                               goto free_bar;
                        p += sizeof(struct chameleon_gdd);
                        break;
                case CHAMELEON_DTYPE_BRIDGE:
-                       chameleon_parse_bdd(bus, mapbase, p);
+                       chameleon_parse_bdd(bus, cb, p);
                        p += sizeof(struct chameleon_bdd);
                        break;
                case CHAMELEON_DTYPE_END:
@@ -136,8 +230,8 @@ int chameleon_parse_cells(struct mcb_bus *bus, phys_addr_t mapbase,
                default:
                        pr_err("Invalid chameleon descriptor type 0x%x\n",
                                dtype);
-                       kfree(header);
-                       return -EINVAL;
+                       ret = -EINVAL;
+                       goto free_bar;
                }
                num_cells++;
        }
@@ -145,11 +239,15 @@ int chameleon_parse_cells(struct mcb_bus *bus, phys_addr_t mapbase,
        if (num_cells == 0)
                num_cells = -EINVAL;
 
+       kfree(cb);
        kfree(header);
        return num_cells;
 
-out:
+free_bar:
+       kfree(cb);
+free_header:
        kfree(header);
+
        return ret;
 }
 EXPORT_SYMBOL_GPL(chameleon_parse_cells);
index 9daf94bb8f27fcfe39391d0d78e9e9f61820f7bd..568f05ed961a8764a23c0a909d68c384c5afc127 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/gfp.h>
 #include <memory/jedec_ddr.h>
 #include <linux/export.h>
+#include "of_memory.h"
 
 /**
  * of_get_min_tck() - extract min timing values for ddr
index d002528289667732e9032f68aa0dba6624abfd9c..64971baf11faebaff879c58067d23fd9bf29895a 100644 (file)
@@ -429,34 +429,6 @@ config ARM_CHARLCD
          line and the Linux version on the second line, but that's
          still useful.
 
-config BMP085
-       tristate
-       depends on SYSFS
-
-config BMP085_I2C
-       tristate "BMP085 digital pressure sensor on I2C"
-       select BMP085
-       select REGMAP_I2C
-       depends on I2C && SYSFS
-       help
-         Say Y here if you want to support Bosch Sensortec's digital pressure
-         sensor hooked to an I2C bus.
-
-         To compile this driver as a module, choose M here: the
-         module will be called bmp085-i2c.
-
-config BMP085_SPI
-       tristate "BMP085 digital pressure sensor on SPI"
-       select BMP085
-       select REGMAP_SPI
-       depends on SPI_MASTER && SYSFS
-       help
-         Say Y here if you want to support Bosch Sensortec's digital pressure
-         sensor hooked to an SPI bus.
-
-         To compile this driver as a module, choose M here: the
-         module will be called bmp085-spi.
-
 config PCH_PHUB
        tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) PHUB"
        select GENERIC_NET_UTILS
index fb32516ddfe2e4f8112beee9e831bcc4eb729667..31983366090a781441a3235cac5883d6fbb27fa4 100644 (file)
@@ -9,9 +9,6 @@ obj-$(CONFIG_AD525X_DPOT_SPI)   += ad525x_dpot-spi.o
 obj-$(CONFIG_INTEL_MID_PTI)    += pti.o
 obj-$(CONFIG_ATMEL_SSC)                += atmel-ssc.o
 obj-$(CONFIG_ATMEL_TCLIB)      += atmel_tclib.o
-obj-$(CONFIG_BMP085)           += bmp085.o
-obj-$(CONFIG_BMP085_I2C)       += bmp085-i2c.o
-obj-$(CONFIG_BMP085_SPI)       += bmp085-spi.o
 obj-$(CONFIG_DUMMY_IRQ)                += dummy-irq.o
 obj-$(CONFIG_ICS932S401)       += ics932s401.o
 obj-$(CONFIG_LKDTM)            += lkdtm.o
diff --git a/drivers/misc/bmp085-i2c.c b/drivers/misc/bmp085-i2c.c
deleted file mode 100644 (file)
index f35c218..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (c) 2012  Bosch Sensortec GmbH
- * Copyright (c) 2012  Unixphere AB
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/module.h>
-#include <linux/i2c.h>
-#include <linux/err.h>
-#include "bmp085.h"
-
-#define BMP085_I2C_ADDRESS     0x77
-
-static const unsigned short normal_i2c[] = { BMP085_I2C_ADDRESS,
-                                                       I2C_CLIENT_END };
-
-static int bmp085_i2c_detect(struct i2c_client *client,
-                            struct i2c_board_info *info)
-{
-       if (client->addr != BMP085_I2C_ADDRESS)
-               return -ENODEV;
-
-       return bmp085_detect(&client->dev);
-}
-
-static int bmp085_i2c_probe(struct i2c_client *client,
-                                     const struct i2c_device_id *id)
-{
-       int err;
-       struct regmap *regmap = devm_regmap_init_i2c(client,
-                                                    &bmp085_regmap_config);
-
-       if (IS_ERR(regmap)) {
-               err = PTR_ERR(regmap);
-               dev_err(&client->dev, "Failed to init regmap: %d\n", err);
-               return err;
-       }
-
-       return bmp085_probe(&client->dev, regmap, client->irq);
-}
-
-static int bmp085_i2c_remove(struct i2c_client *client)
-{
-       return bmp085_remove(&client->dev);
-}
-
-static const struct i2c_device_id bmp085_id[] = {
-       { BMP085_NAME, 0 },
-       { "bmp180", 0 },
-       { }
-};
-MODULE_DEVICE_TABLE(i2c, bmp085_id);
-
-static struct i2c_driver bmp085_i2c_driver = {
-       .driver = {
-               .name   = BMP085_NAME,
-       },
-       .id_table       = bmp085_id,
-       .probe          = bmp085_i2c_probe,
-       .remove         = bmp085_i2c_remove,
-
-       .detect         = bmp085_i2c_detect,
-       .address_list   = normal_i2c
-};
-
-module_i2c_driver(bmp085_i2c_driver);
-
-MODULE_AUTHOR("Eric Andersson <eric.andersson@unixphere.com>");
-MODULE_DESCRIPTION("BMP085 I2C bus driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/misc/bmp085-spi.c b/drivers/misc/bmp085-spi.c
deleted file mode 100644 (file)
index 17ecbf9..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (c) 2012  Bosch Sensortec GmbH
- * Copyright (c) 2012  Unixphere AB
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/module.h>
-#include <linux/spi/spi.h>
-#include <linux/err.h>
-#include "bmp085.h"
-
-static int bmp085_spi_probe(struct spi_device *client)
-{
-       int err;
-       struct regmap *regmap;
-
-       client->bits_per_word = 8;
-       err = spi_setup(client);
-       if (err < 0) {
-               dev_err(&client->dev, "spi_setup failed!\n");
-               return err;
-       }
-
-       regmap = devm_regmap_init_spi(client, &bmp085_regmap_config);
-       if (IS_ERR(regmap)) {
-               err = PTR_ERR(regmap);
-               dev_err(&client->dev, "Failed to init regmap: %d\n", err);
-               return err;
-       }
-
-       return bmp085_probe(&client->dev, regmap, client->irq);
-}
-
-static int bmp085_spi_remove(struct spi_device *client)
-{
-       return bmp085_remove(&client->dev);
-}
-
-static const struct of_device_id bmp085_of_match[] = {
-       { .compatible = "bosch,bmp085", },
-       { },
-};
-MODULE_DEVICE_TABLE(of, bmp085_of_match);
-
-static const struct spi_device_id bmp085_id[] = {
-       { "bmp180", 0 },
-       { "bmp181", 0 },
-       { }
-};
-MODULE_DEVICE_TABLE(spi, bmp085_id);
-
-static struct spi_driver bmp085_spi_driver = {
-       .driver = {
-               .name   = BMP085_NAME,
-               .of_match_table = bmp085_of_match
-       },
-       .id_table       = bmp085_id,
-       .probe          = bmp085_spi_probe,
-       .remove         = bmp085_spi_remove
-};
-
-module_spi_driver(bmp085_spi_driver);
-
-MODULE_AUTHOR("Eric Andersson <eric.andersson@unixphere.com>");
-MODULE_DESCRIPTION("BMP085 SPI bus driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/misc/bmp085.c b/drivers/misc/bmp085.c
deleted file mode 100644 (file)
index 9b313f7..0000000
+++ /dev/null
@@ -1,506 +0,0 @@
-/*  Copyright (c) 2010  Christoph Mair <christoph.mair@gmail.com>
- *  Copyright (c) 2012  Bosch Sensortec GmbH
- *  Copyright (c) 2012  Unixphere AB
- *
- *  This driver supports the bmp085 and bmp18x digital barometric pressure
- *  and temperature sensors from Bosch Sensortec. The datasheets
- *  are available from their website:
- *  http://www.bosch-sensortec.com/content/language1/downloads/BST-BMP085-DS000-05.pdf
- *  http://www.bosch-sensortec.com/content/language1/downloads/BST-BMP180-DS000-07.pdf
- *
- *  A pressure measurement is issued by reading from pressure0_input.
- *  The return value ranges from 30000 to 110000 pascal with a resulution
- *  of 1 pascal (0.01 millibar) which enables measurements from 9000m above
- *  to 500m below sea level.
- *
- *  The temperature can be read from temp0_input. Values range from
- *  -400 to 850 representing the ambient temperature in degree celsius
- *  multiplied by 10.The resolution is 0.1 celsius.
- *
- *  Because ambient pressure is temperature dependent, a temperature
- *  measurement will be executed automatically even if the user is reading
- *  from pressure0_input. This happens if the last temperature measurement
- *  has been executed more then one second ago.
- *
- *  To decrease RMS noise from pressure measurements, the bmp085 can
- *  autonomously calculate the average of up to eight samples. This is
- *  set up by writing to the oversampling sysfs file. Accepted values
- *  are 0, 1, 2 and 3. 2^x when x is the value written to this file
- *  specifies the number of samples used to calculate the ambient pressure.
- *  RMS noise is specified with six pascal (without averaging) and decreases
- *  down to 3 pascal when using an oversampling setting of 3.
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/slab.h>
-#include <linux/of.h>
-#include "bmp085.h"
-#include <linux/interrupt.h>
-#include <linux/completion.h>
-#include <linux/gpio.h>
-
-#define BMP085_CHIP_ID                 0x55
-#define BMP085_CALIBRATION_DATA_START  0xAA
-#define BMP085_CALIBRATION_DATA_LENGTH 11      /* 16 bit values */
-#define BMP085_CHIP_ID_REG             0xD0
-#define BMP085_CTRL_REG                        0xF4
-#define BMP085_TEMP_MEASUREMENT                0x2E
-#define BMP085_PRESSURE_MEASUREMENT    0x34
-#define BMP085_CONVERSION_REGISTER_MSB 0xF6
-#define BMP085_CONVERSION_REGISTER_LSB 0xF7
-#define BMP085_CONVERSION_REGISTER_XLSB        0xF8
-#define BMP085_TEMP_CONVERSION_TIME    5
-
-struct bmp085_calibration_data {
-       s16 AC1, AC2, AC3;
-       u16 AC4, AC5, AC6;
-       s16 B1, B2;
-       s16 MB, MC, MD;
-};
-
-struct bmp085_data {
-       struct  device *dev;
-       struct  regmap *regmap;
-       struct  mutex lock;
-       struct  bmp085_calibration_data calibration;
-       u8      oversampling_setting;
-       u32     raw_temperature;
-       u32     raw_pressure;
-       u32     temp_measurement_period;
-       unsigned long last_temp_measurement;
-       u8      chip_id;
-       s32     b6; /* calculated temperature correction coefficient */
-       int     irq;
-       struct  completion done;
-};
-
-static irqreturn_t bmp085_eoc_isr(int irq, void *devid)
-{
-       struct bmp085_data *data = devid;
-
-       complete(&data->done);
-
-       return IRQ_HANDLED;
-}
-
-static s32 bmp085_read_calibration_data(struct bmp085_data *data)
-{
-       u16 tmp[BMP085_CALIBRATION_DATA_LENGTH];
-       struct bmp085_calibration_data *cali = &(data->calibration);
-       s32 status = regmap_bulk_read(data->regmap,
-                               BMP085_CALIBRATION_DATA_START, (u8 *)tmp,
-                               (BMP085_CALIBRATION_DATA_LENGTH << 1));
-       if (status < 0)
-               return status;
-
-       cali->AC1 =  be16_to_cpu(tmp[0]);
-       cali->AC2 =  be16_to_cpu(tmp[1]);
-       cali->AC3 =  be16_to_cpu(tmp[2]);
-       cali->AC4 =  be16_to_cpu(tmp[3]);
-       cali->AC5 =  be16_to_cpu(tmp[4]);
-       cali->AC6 = be16_to_cpu(tmp[5]);
-       cali->B1 = be16_to_cpu(tmp[6]);
-       cali->B2 = be16_to_cpu(tmp[7]);
-       cali->MB = be16_to_cpu(tmp[8]);
-       cali->MC = be16_to_cpu(tmp[9]);
-       cali->MD = be16_to_cpu(tmp[10]);
-       return 0;
-}
-
-static s32 bmp085_update_raw_temperature(struct bmp085_data *data)
-{
-       u16 tmp;
-       s32 status;
-
-       mutex_lock(&data->lock);
-
-       init_completion(&data->done);
-
-       status = regmap_write(data->regmap, BMP085_CTRL_REG,
-                             BMP085_TEMP_MEASUREMENT);
-       if (status < 0) {
-               dev_err(data->dev,
-                       "Error while requesting temperature measurement.\n");
-               goto exit;
-       }
-       wait_for_completion_timeout(&data->done, 1 + msecs_to_jiffies(
-                                           BMP085_TEMP_CONVERSION_TIME));
-
-       status = regmap_bulk_read(data->regmap, BMP085_CONVERSION_REGISTER_MSB,
-                                &tmp, sizeof(tmp));
-       if (status < 0) {
-               dev_err(data->dev,
-                       "Error while reading temperature measurement result\n");
-               goto exit;
-       }
-       data->raw_temperature = be16_to_cpu(tmp);
-       data->last_temp_measurement = jiffies;
-       status = 0;     /* everything ok, return 0 */
-
-exit:
-       mutex_unlock(&data->lock);
-       return status;
-}
-
-static s32 bmp085_update_raw_pressure(struct bmp085_data *data)
-{
-       u32 tmp = 0;
-       s32 status;
-
-       mutex_lock(&data->lock);
-
-       init_completion(&data->done);
-
-       status = regmap_write(data->regmap, BMP085_CTRL_REG,
-                       BMP085_PRESSURE_MEASUREMENT +
-                       (data->oversampling_setting << 6));
-       if (status < 0) {
-               dev_err(data->dev,
-                       "Error while requesting pressure measurement.\n");
-               goto exit;
-       }
-
-       /* wait for the end of conversion */
-       wait_for_completion_timeout(&data->done, 1 + msecs_to_jiffies(
-                                       2+(3 << data->oversampling_setting)));
-       /* copy data into a u32 (4 bytes), but skip the first byte. */
-       status = regmap_bulk_read(data->regmap, BMP085_CONVERSION_REGISTER_MSB,
-                                ((u8 *)&tmp)+1, 3);
-       if (status < 0) {
-               dev_err(data->dev,
-                       "Error while reading pressure measurement results\n");
-               goto exit;
-       }
-       data->raw_pressure = be32_to_cpu((tmp));
-       data->raw_pressure >>= (8-data->oversampling_setting);
-       status = 0;     /* everything ok, return 0 */
-
-exit:
-       mutex_unlock(&data->lock);
-       return status;
-}
-
-/*
- * This function starts the temperature measurement and returns the value
- * in tenth of a degree celsius.
- */
-static s32 bmp085_get_temperature(struct bmp085_data *data, int *temperature)
-{
-       struct bmp085_calibration_data *cali = &data->calibration;
-       long x1, x2;
-       int status;
-
-       status = bmp085_update_raw_temperature(data);
-       if (status < 0)
-               goto exit;
-
-       x1 = ((data->raw_temperature - cali->AC6) * cali->AC5) >> 15;
-       x2 = (cali->MC << 11) / (x1 + cali->MD);
-       data->b6 = x1 + x2 - 4000;
-       /* if NULL just update b6. Used for pressure only measurements */
-       if (temperature != NULL)
-               *temperature = (x1+x2+8) >> 4;
-
-exit:
-       return status;
-}
-
-/*
- * This function starts the pressure measurement and returns the value
- * in millibar. Since the pressure depends on the ambient temperature,
- * a temperature measurement is executed according to the given temperature
- * measurement period (default is 1 sec boundary). This period could vary
- * and needs to be adjusted according to the sensor environment, i.e. if big
- * temperature variations then the temperature needs to be read out often.
- */
-static s32 bmp085_get_pressure(struct bmp085_data *data, int *pressure)
-{
-       struct bmp085_calibration_data *cali = &data->calibration;
-       s32 x1, x2, x3, b3;
-       u32 b4, b7;
-       s32 p;
-       int status;
-
-       /* alt least every second force an update of the ambient temperature */
-       if ((data->last_temp_measurement == 0) ||
-           time_is_before_jiffies(data->last_temp_measurement + 1*HZ)) {
-               status = bmp085_get_temperature(data, NULL);
-               if (status < 0)
-                       return status;
-       }
-
-       status = bmp085_update_raw_pressure(data);
-       if (status < 0)
-               return status;
-
-       x1 = (data->b6 * data->b6) >> 12;
-       x1 *= cali->B2;
-       x1 >>= 11;
-
-       x2 = cali->AC2 * data->b6;
-       x2 >>= 11;
-
-       x3 = x1 + x2;
-
-       b3 = (((((s32)cali->AC1) * 4 + x3) << data->oversampling_setting) + 2);
-       b3 >>= 2;
-
-       x1 = (cali->AC3 * data->b6) >> 13;
-       x2 = (cali->B1 * ((data->b6 * data->b6) >> 12)) >> 16;
-       x3 = (x1 + x2 + 2) >> 2;
-       b4 = (cali->AC4 * (u32)(x3 + 32768)) >> 15;
-
-       b7 = ((u32)data->raw_pressure - b3) *
-                                       (50000 >> data->oversampling_setting);
-       p = ((b7 < 0x80000000) ? ((b7 << 1) / b4) : ((b7 / b4) * 2));
-
-       x1 = p >> 8;
-       x1 *= x1;
-       x1 = (x1 * 3038) >> 16;
-       x2 = (-7357 * p) >> 16;
-       p += (x1 + x2 + 3791) >> 4;
-
-       *pressure = p;
-
-       return 0;
-}
-
-/*
- * This function sets the chip-internal oversampling. Valid values are 0..3.
- * The chip will use 2^oversampling samples for internal averaging.
- * This influences the measurement time and the accuracy; larger values
- * increase both. The datasheet gives an overview on how measurement time,
- * accuracy and noise correlate.
- */
-static void bmp085_set_oversampling(struct bmp085_data *data,
-                                               unsigned char oversampling)
-{
-       if (oversampling > 3)
-               oversampling = 3;
-       data->oversampling_setting = oversampling;
-}
-
-/*
- * Returns the currently selected oversampling. Range: 0..3
- */
-static unsigned char bmp085_get_oversampling(struct bmp085_data *data)
-{
-       return data->oversampling_setting;
-}
-
-/* sysfs callbacks */
-static ssize_t set_oversampling(struct device *dev,
-                               struct device_attribute *attr,
-                               const char *buf, size_t count)
-{
-       struct bmp085_data *data = dev_get_drvdata(dev);
-       unsigned long oversampling;
-       int err = kstrtoul(buf, 10, &oversampling);
-
-       if (err == 0) {
-               mutex_lock(&data->lock);
-               bmp085_set_oversampling(data, oversampling);
-               mutex_unlock(&data->lock);
-               return count;
-       }
-
-       return err;
-}
-
-static ssize_t show_oversampling(struct device *dev,
-                                struct device_attribute *attr, char *buf)
-{
-       struct bmp085_data *data = dev_get_drvdata(dev);
-
-       return sprintf(buf, "%u\n", bmp085_get_oversampling(data));
-}
-static DEVICE_ATTR(oversampling, S_IWUSR | S_IRUGO,
-                                       show_oversampling, set_oversampling);
-
-
-static ssize_t show_temperature(struct device *dev,
-                               struct device_attribute *attr, char *buf)
-{
-       int temperature;
-       int status;
-       struct bmp085_data *data = dev_get_drvdata(dev);
-
-       status = bmp085_get_temperature(data, &temperature);
-       if (status < 0)
-               return status;
-       else
-               return sprintf(buf, "%d\n", temperature);
-}
-static DEVICE_ATTR(temp0_input, S_IRUGO, show_temperature, NULL);
-
-
-static ssize_t show_pressure(struct device *dev,
-                            struct device_attribute *attr, char *buf)
-{
-       int pressure;
-       int status;
-       struct bmp085_data *data = dev_get_drvdata(dev);
-
-       status = bmp085_get_pressure(data, &pressure);
-       if (status < 0)
-               return status;
-       else
-               return sprintf(buf, "%d\n", pressure);
-}
-static DEVICE_ATTR(pressure0_input, S_IRUGO, show_pressure, NULL);
-
-
-static struct attribute *bmp085_attributes[] = {
-       &dev_attr_temp0_input.attr,
-       &dev_attr_pressure0_input.attr,
-       &dev_attr_oversampling.attr,
-       NULL
-};
-
-static const struct attribute_group bmp085_attr_group = {
-       .attrs = bmp085_attributes,
-};
-
-int bmp085_detect(struct device *dev)
-{
-       struct bmp085_data *data = dev_get_drvdata(dev);
-       unsigned int id;
-       int ret;
-
-       ret = regmap_read(data->regmap, BMP085_CHIP_ID_REG, &id);
-       if (ret < 0)
-               return ret;
-
-       if (id != data->chip_id)
-               return -ENODEV;
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(bmp085_detect);
-
-static void bmp085_get_of_properties(struct bmp085_data *data)
-{
-#ifdef CONFIG_OF
-       struct device_node *np = data->dev->of_node;
-       u32 prop;
-
-       if (!np)
-               return;
-
-       if (!of_property_read_u32(np, "chip-id", &prop))
-               data->chip_id = prop & 0xff;
-
-       if (!of_property_read_u32(np, "temp-measurement-period", &prop))
-               data->temp_measurement_period = (prop/100)*HZ;
-
-       if (!of_property_read_u32(np, "default-oversampling", &prop))
-               data->oversampling_setting = prop & 0xff;
-#endif
-}
-
-static int bmp085_init_client(struct bmp085_data *data)
-{
-       int status = bmp085_read_calibration_data(data);
-
-       if (status < 0)
-               return status;
-
-       /* default settings */
-       data->chip_id = BMP085_CHIP_ID;
-       data->last_temp_measurement = 0;
-       data->temp_measurement_period = 1*HZ;
-       data->oversampling_setting = 3;
-
-       bmp085_get_of_properties(data);
-
-       mutex_init(&data->lock);
-
-       return 0;
-}
-
-struct regmap_config bmp085_regmap_config = {
-       .reg_bits = 8,
-       .val_bits = 8
-};
-EXPORT_SYMBOL_GPL(bmp085_regmap_config);
-
-int bmp085_probe(struct device *dev, struct regmap *regmap, int irq)
-{
-       struct bmp085_data *data;
-       int err = 0;
-
-       data = kzalloc(sizeof(struct bmp085_data), GFP_KERNEL);
-       if (!data) {
-               err = -ENOMEM;
-               goto exit;
-       }
-
-       dev_set_drvdata(dev, data);
-       data->dev = dev;
-       data->regmap = regmap;
-       data->irq = irq;
-
-       if (data->irq > 0) {
-               err = devm_request_irq(dev, data->irq, bmp085_eoc_isr,
-                                             IRQF_TRIGGER_RISING, "bmp085",
-                                             data);
-               if (err < 0)
-                       goto exit_free;
-       }
-
-       /* Initialize the BMP085 chip */
-       err = bmp085_init_client(data);
-       if (err < 0)
-               goto exit_free;
-
-       err = bmp085_detect(dev);
-       if (err < 0) {
-               dev_err(dev, "%s: chip_id failed!\n", BMP085_NAME);
-               goto exit_free;
-       }
-
-       /* Register sysfs hooks */
-       err = sysfs_create_group(&dev->kobj, &bmp085_attr_group);
-       if (err)
-               goto exit_free;
-
-       dev_info(dev, "Successfully initialized %s!\n", BMP085_NAME);
-
-       return 0;
-
-exit_free:
-       kfree(data);
-exit:
-       return err;
-}
-EXPORT_SYMBOL_GPL(bmp085_probe);
-
-int bmp085_remove(struct device *dev)
-{
-       struct bmp085_data *data = dev_get_drvdata(dev);
-
-       sysfs_remove_group(&data->dev->kobj, &bmp085_attr_group);
-       kfree(data);
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(bmp085_remove);
-
-MODULE_AUTHOR("Christoph Mair <christoph.mair@gmail.com>");
-MODULE_DESCRIPTION("BMP085 driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/misc/bmp085.h b/drivers/misc/bmp085.h
deleted file mode 100644 (file)
index 8b8e3b1..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (c) 2012  Bosch Sensortec GmbH
- * Copyright (c) 2012  Unixphere AB
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef _BMP085_H
-#define _BMP085_H
-
-#include <linux/regmap.h>
-
-#define BMP085_NAME            "bmp085"
-
-extern struct regmap_config bmp085_regmap_config;
-
-int bmp085_probe(struct device *dev, struct regmap *regmap, int irq);
-int bmp085_remove(struct device *dev);
-int bmp085_detect(struct device *dev);
-
-#endif
index a70b853fa2c99b330583189e5b4b103771531eed..6c1f49a85023e6abd80804ab71c27d57c1ccd5e0 100644 (file)
@@ -1350,6 +1350,19 @@ static struct pci_driver genwqe_driver = {
        .err_handler = &genwqe_err_handler,
 };
 
+/**
+ * genwqe_devnode() - Set default access mode for genwqe devices.
+ *
+ * Default mode should be rw for everybody. Do not change default
+ * device name.
+ */
+static char *genwqe_devnode(struct device *dev, umode_t *mode)
+{
+       if (mode)
+               *mode = 0666;
+       return NULL;
+}
+
 /**
  * genwqe_init_module() - Driver registration and initialization
  */
@@ -1363,6 +1376,8 @@ static int __init genwqe_init_module(void)
                return -ENOMEM;
        }
 
+       class_genwqe->devnode = genwqe_devnode;
+
        debugfs_genwqe = debugfs_create_dir(GENWQE_DEVNAME, NULL);
        if (!debugfs_genwqe) {
                rc = -ENOMEM;
index a039a5df6f2147f3a86074ee50e7a73eeb5177f0..082462ea90c92ec47cbf5bd7695ea705cfcecea0 100644 (file)
@@ -47,7 +47,6 @@ const uuid_le mei_amthif_guid  = UUID_LE(0x12f80028, 0xb4b7, 0x4b2d,
 void mei_amthif_reset_params(struct mei_device *dev)
 {
        /* reset iamthif parameters. */
-       dev->iamthif_current_cb = NULL;
        dev->iamthif_canceled = false;
        dev->iamthif_state = MEI_IAMTHIF_IDLE;
        dev->iamthif_stall_timer = 0;
@@ -67,8 +66,12 @@ int mei_amthif_host_init(struct mei_device *dev, struct mei_me_client *me_cl)
        struct mei_cl *cl = &dev->iamthif_cl;
        int ret;
 
-       if (mei_cl_is_connected(cl))
-               return 0;
+       mutex_lock(&dev->device_lock);
+
+       if (mei_cl_is_connected(cl)) {
+               ret = 0;
+               goto out;
+       }
 
        dev->iamthif_state = MEI_IAMTHIF_IDLE;
 
@@ -77,179 +80,37 @@ int mei_amthif_host_init(struct mei_device *dev, struct mei_me_client *me_cl)
        ret = mei_cl_link(cl);
        if (ret < 0) {
                dev_err(dev->dev, "amthif: failed cl_link %d\n", ret);
-               return ret;
+               goto out;
        }
 
        ret = mei_cl_connect(cl, me_cl, NULL);
 
-       return ret;
-}
-
-/**
- * mei_amthif_read - read data from AMTHIF client
- *
- * @dev: the device structure
- * @file: pointer to file object
- * @ubuf: pointer to user data in user space
- * @length: data length to read
- * @offset: data read offset
- *
- * Locking: called under "dev->device_lock" lock
- *
- * Return:
- *  returned data length on success,
- *  zero if no data to read,
- *  negative on failure.
- */
-int mei_amthif_read(struct mei_device *dev, struct file *file,
-              char __user *ubuf, size_t length, loff_t *offset)
-{
-       struct mei_cl *cl = file->private_data;
-       struct mei_cl_cb *cb;
-       int rets;
-       int wait_ret;
-
-       dev_dbg(dev->dev, "checking amthif data\n");
-       cb = mei_cl_read_cb(cl, file);
-
-       /* Check for if we can block or not*/
-       if (cb == NULL && file->f_flags & O_NONBLOCK)
-               return -EAGAIN;
-
-
-       dev_dbg(dev->dev, "waiting for amthif data\n");
-       while (cb == NULL) {
-               /* unlock the Mutex */
-               mutex_unlock(&dev->device_lock);
-
-               wait_ret = wait_event_interruptible(cl->rx_wait,
-                                       !list_empty(&cl->rd_completed) ||
-                                       !mei_cl_is_connected(cl));
-
-               /* Locking again the Mutex */
-               mutex_lock(&dev->device_lock);
-
-               if (wait_ret)
-                       return -ERESTARTSYS;
-
-               if (!mei_cl_is_connected(cl)) {
-                       rets = -EBUSY;
-                       goto out;
-               }
-
-               cb = mei_cl_read_cb(cl, file);
-       }
-
-       if (cb->status) {
-               rets = cb->status;
-               dev_dbg(dev->dev, "read operation failed %d\n", rets);
-               goto free;
-       }
-
-       dev_dbg(dev->dev, "Got amthif data\n");
-       /* if the whole message will fit remove it from the list */
-       if (cb->buf_idx >= *offset && length >= (cb->buf_idx - *offset))
-               list_del_init(&cb->list);
-       else if (cb->buf_idx <= *offset) {
-               /* end of the message has been reached */
-               list_del_init(&cb->list);
-               rets = 0;
-               goto free;
-       }
-               /* else means that not full buffer will be read and do not
-                * remove message from deletion list
-                */
-
-       dev_dbg(dev->dev, "amthif cb->buf.size - %zu cb->buf_idx - %zu\n",
-               cb->buf.size, cb->buf_idx);
-
-       /* length is being truncated to PAGE_SIZE, however,
-        * the buf_idx may point beyond */
-       length = min_t(size_t, length, (cb->buf_idx - *offset));
-
-       if (copy_to_user(ubuf, cb->buf.data + *offset, length)) {
-               dev_dbg(dev->dev, "failed to copy data to userland\n");
-               rets = -EFAULT;
-       } else {
-               rets = length;
-               if ((*offset + length) < cb->buf_idx) {
-                       *offset += length;
-                       goto out;
-               }
-       }
-free:
-       dev_dbg(dev->dev, "free amthif cb memory.\n");
-       *offset = 0;
-       mei_io_cb_free(cb);
 out:
-       return rets;
+       mutex_unlock(&dev->device_lock);
+       return ret;
 }
 
 /**
  * mei_amthif_read_start - queue message for sending read credential
  *
  * @cl: host client
- * @file: file pointer of message recipient
+ * @fp: file pointer of message recipient
  *
  * Return: 0 on success, <0 on failure.
  */
-static int mei_amthif_read_start(struct mei_cl *cl, const struct file *file)
+static int mei_amthif_read_start(struct mei_cl *cl, const struct file *fp)
 {
        struct mei_device *dev = cl->dev;
        struct mei_cl_cb *cb;
-       int rets;
-
-       cb = mei_io_cb_init(cl, MEI_FOP_READ, file);
-       if (!cb) {
-               rets = -ENOMEM;
-               goto err;
-       }
 
-       rets = mei_io_cb_alloc_buf(cb, mei_cl_mtu(cl));
-       if (rets)
-               goto err;
+       cb = mei_cl_enqueue_ctrl_wr_cb(cl, mei_cl_mtu(cl), MEI_FOP_READ, fp);
+       if (!cb)
+               return -ENOMEM;
 
-       list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
+       cl->rx_flow_ctrl_creds++;
 
        dev->iamthif_state = MEI_IAMTHIF_READING;
-       dev->iamthif_fp = cb->fp;
-       dev->iamthif_current_cb = cb;
-
-       return 0;
-err:
-       mei_io_cb_free(cb);
-       return rets;
-}
-
-/**
- * mei_amthif_send_cmd - send amthif command to the ME
- *
- * @cl: the host client
- * @cb: mei call back struct
- *
- * Return: 0 on success, <0 on failure.
- */
-static int mei_amthif_send_cmd(struct mei_cl *cl, struct mei_cl_cb *cb)
-{
-       struct mei_device *dev;
-       int ret;
-
-       if (!cl->dev || !cb)
-               return -ENODEV;
-
-       dev = cl->dev;
-
-       dev->iamthif_state = MEI_IAMTHIF_WRITING;
-       dev->iamthif_current_cb = cb;
-       dev->iamthif_fp = cb->fp;
-       dev->iamthif_canceled = false;
-
-       ret = mei_cl_write(cl, cb, false);
-       if (ret < 0)
-               return ret;
-
-       if (cb->completed)
-               cb->status = mei_amthif_read_start(cl, cb->fp);
+       cl->fp = cb->fp;
 
        return 0;
 }
@@ -265,20 +126,32 @@ int mei_amthif_run_next_cmd(struct mei_device *dev)
 {
        struct mei_cl *cl = &dev->iamthif_cl;
        struct mei_cl_cb *cb;
+       int ret;
 
        dev->iamthif_canceled = false;
-       dev->iamthif_state = MEI_IAMTHIF_IDLE;
-       dev->iamthif_fp = NULL;
 
        dev_dbg(dev->dev, "complete amthif cmd_list cb.\n");
 
        cb = list_first_entry_or_null(&dev->amthif_cmd_list.list,
                                        typeof(*cb), list);
-       if (!cb)
+       if (!cb) {
+               dev->iamthif_state = MEI_IAMTHIF_IDLE;
+               cl->fp = NULL;
                return 0;
+       }
 
        list_del_init(&cb->list);
-       return mei_amthif_send_cmd(cl, cb);
+       dev->iamthif_state = MEI_IAMTHIF_WRITING;
+       cl->fp = cb->fp;
+
+       ret = mei_cl_write(cl, cb, false);
+       if (ret < 0)
+               return ret;
+
+       if (cb->completed)
+               cb->status = mei_amthif_read_start(cl, cb->fp);
+
+       return 0;
 }
 
 /**
@@ -299,8 +172,7 @@ int mei_amthif_write(struct mei_cl *cl, struct mei_cl_cb *cb)
        /*
         * The previous request is still in processing, queue this one.
         */
-       if (dev->iamthif_state > MEI_IAMTHIF_IDLE &&
-           dev->iamthif_state < MEI_IAMTHIF_READ_COMPLETE)
+       if (dev->iamthif_state != MEI_IAMTHIF_IDLE)
                return 0;
 
        return mei_amthif_run_next_cmd(dev);
@@ -309,7 +181,6 @@ int mei_amthif_write(struct mei_cl *cl, struct mei_cl_cb *cb)
 /**
  * mei_amthif_poll - the amthif poll function
  *
- * @dev: the device structure
  * @file: pointer to file structure
  * @wait: pointer to poll_table structure
  *
@@ -317,26 +188,19 @@ int mei_amthif_write(struct mei_cl *cl, struct mei_cl_cb *cb)
  *
  * Locking: called under "dev->device_lock" lock
  */
-
-unsigned int mei_amthif_poll(struct mei_device *dev,
-               struct file *file, poll_table *wait)
+unsigned int mei_amthif_poll(struct file *file, poll_table *wait)
 {
+       struct mei_cl *cl = file->private_data;
+       struct mei_cl_cb *cb = mei_cl_read_cb(cl, file);
        unsigned int mask = 0;
 
-       poll_wait(file, &dev->iamthif_cl.rx_wait, wait);
-
-       if (dev->iamthif_state == MEI_IAMTHIF_READ_COMPLETE &&
-           dev->iamthif_fp == file) {
-
+       poll_wait(file, &cl->rx_wait, wait);
+       if (cb)
                mask |= POLLIN | POLLRDNORM;
-               mei_amthif_run_next_cmd(dev);
-       }
 
        return mask;
 }
 
-
-
 /**
  * mei_amthif_irq_write - write iamthif command in irq thread context.
  *
@@ -393,7 +257,6 @@ int mei_amthif_irq_read_msg(struct mei_cl *cl,
                return 0;
 
        dev_dbg(dev->dev, "completed amthif read.\n ");
-       dev->iamthif_current_cb = NULL;
        dev->iamthif_stall_timer = 0;
 
        return 0;
@@ -409,115 +272,62 @@ void mei_amthif_complete(struct mei_cl *cl, struct mei_cl_cb *cb)
 {
        struct mei_device *dev = cl->dev;
 
-       if (cb->fop_type == MEI_FOP_WRITE) {
+       dev_dbg(dev->dev, "completing amthif call back.\n");
+       switch (cb->fop_type) {
+       case MEI_FOP_WRITE:
                if (!cb->status) {
                        dev->iamthif_stall_timer = MEI_IAMTHIF_STALL_TIMER;
                        mei_io_cb_free(cb);
                        return;
                }
-               /*
-                * in case of error enqueue the write cb to complete read list
-                * so it can be propagated to the reader
-                */
-               list_add_tail(&cb->list, &cl->rd_completed);
-               wake_up_interruptible(&cl->rx_wait);
-               return;
-       }
+               dev->iamthif_state = MEI_IAMTHIF_IDLE;
+               cl->fp = NULL;
+               if (!dev->iamthif_canceled) {
+                       /*
+                        * in case of error enqueue the write cb to complete
+                        * read list so it can be propagated to the reader
+                        */
+                       list_add_tail(&cb->list, &cl->rd_completed);
+                       wake_up_interruptible(&cl->rx_wait);
+               } else {
+                       mei_io_cb_free(cb);
+               }
+               break;
+       case MEI_FOP_READ:
+               if (!dev->iamthif_canceled) {
+                       list_add_tail(&cb->list, &cl->rd_completed);
+                       dev_dbg(dev->dev, "amthif read completed\n");
+                       wake_up_interruptible(&cl->rx_wait);
+               } else {
+                       mei_io_cb_free(cb);
+               }
 
-       if (!dev->iamthif_canceled) {
-               dev->iamthif_state = MEI_IAMTHIF_READ_COMPLETE;
                dev->iamthif_stall_timer = 0;
-               list_add_tail(&cb->list, &cl->rd_completed);
-               dev_dbg(dev->dev, "amthif read completed\n");
-       } else {
                mei_amthif_run_next_cmd(dev);
+               break;
+       default:
+               WARN_ON(1);
        }
-
-       dev_dbg(dev->dev, "completing amthif call back.\n");
-       wake_up_interruptible(&cl->rx_wait);
 }
 
 /**
  * mei_clear_list - removes all callbacks associated with file
  *             from mei_cb_list
  *
- * @dev: device structure.
  * @file: file structure
  * @mei_cb_list: callbacks list
  *
  * mei_clear_list is called to clear resources associated with file
  * when application calls close function or Ctrl-C was pressed
- *
- * Return: true if callback removed from the list, false otherwise
  */
-static bool mei_clear_list(struct mei_device *dev,
-               const struct file *file, struct list_head *mei_cb_list)
+static void mei_clear_list(const struct file *file,
+                          struct list_head *mei_cb_list)
 {
-       struct mei_cl *cl = &dev->iamthif_cl;
        struct mei_cl_cb *cb, *next;
-       bool removed = false;
-
-       /* list all list member */
-       list_for_each_entry_safe(cb, next, mei_cb_list, list) {
-               /* check if list member associated with a file */
-               if (file == cb->fp) {
-                       /* check if cb equal to current iamthif cb */
-                       if (dev->iamthif_current_cb == cb) {
-                               dev->iamthif_current_cb = NULL;
-                               /* send flow control to iamthif client */
-                               mei_hbm_cl_flow_control_req(dev, cl);
-                       }
-                       /* free all allocated buffers */
-                       mei_io_cb_free(cb);
-                       removed = true;
-               }
-       }
-       return removed;
-}
 
-/**
- * mei_clear_lists - removes all callbacks associated with file
- *
- * @dev: device structure
- * @file: file structure
- *
- * mei_clear_lists is called to clear resources associated with file
- * when application calls close function or Ctrl-C was pressed
- *
- * Return: true if callback removed from the list, false otherwise
- */
-static bool mei_clear_lists(struct mei_device *dev, const struct file *file)
-{
-       bool removed = false;
-       struct mei_cl *cl = &dev->iamthif_cl;
-
-       /* remove callbacks associated with a file */
-       mei_clear_list(dev, file, &dev->amthif_cmd_list.list);
-       if (mei_clear_list(dev, file, &cl->rd_completed))
-               removed = true;
-
-       mei_clear_list(dev, file, &dev->ctrl_rd_list.list);
-
-       if (mei_clear_list(dev, file, &dev->ctrl_wr_list.list))
-               removed = true;
-
-       if (mei_clear_list(dev, file, &dev->write_waiting_list.list))
-               removed = true;
-
-       if (mei_clear_list(dev, file, &dev->write_list.list))
-               removed = true;
-
-       /* check if iamthif_current_cb not NULL */
-       if (dev->iamthif_current_cb && !removed) {
-               /* check file and iamthif current cb association */
-               if (dev->iamthif_current_cb->fp == file) {
-                       /* remove cb */
-                       mei_io_cb_free(dev->iamthif_current_cb);
-                       dev->iamthif_current_cb = NULL;
-                       removed = true;
-               }
-       }
-       return removed;
+       list_for_each_entry_safe(cb, next, mei_cb_list, list)
+               if (file == cb->fp)
+                       mei_io_cb_free(cb);
 }
 
 /**
@@ -530,23 +340,21 @@ static bool mei_clear_lists(struct mei_device *dev, const struct file *file)
 */
 int mei_amthif_release(struct mei_device *dev, struct file *file)
 {
+       struct mei_cl *cl = file->private_data;
+
        if (dev->iamthif_open_count > 0)
                dev->iamthif_open_count--;
 
-       if (dev->iamthif_fp == file &&
-           dev->iamthif_state != MEI_IAMTHIF_IDLE) {
+       if (cl->fp == file && dev->iamthif_state != MEI_IAMTHIF_IDLE) {
 
                dev_dbg(dev->dev, "amthif canceled iamthif state %d\n",
                    dev->iamthif_state);
                dev->iamthif_canceled = true;
-               if (dev->iamthif_state == MEI_IAMTHIF_READ_COMPLETE) {
-                       dev_dbg(dev->dev, "run next amthif iamthif cb\n");
-                       mei_amthif_run_next_cmd(dev);
-               }
        }
 
-       if (mei_clear_lists(dev, file))
-               dev->iamthif_state = MEI_IAMTHIF_IDLE;
+       mei_clear_list(file, &dev->amthif_cmd_list.list);
+       mei_clear_list(file, &cl->rd_completed);
+       mei_clear_list(file, &dev->ctrl_rd_list.list);
 
        return 0;
 }
index 1f33fea9299f61a4b8ceeb127a638ccbf09c312e..8cac7ef9ad0d98789c3f910dced1b61bc2b3ab62 100644 (file)
@@ -126,7 +126,8 @@ ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length)
                goto out;
 
        /* wait on event only if there is no other waiter */
-       if (list_empty(&cl->rd_completed) && !waitqueue_active(&cl->rx_wait)) {
+       /* synchronized under device mutex */
+       if (!waitqueue_active(&cl->rx_wait)) {
 
                mutex_unlock(&bus->device_lock);
 
@@ -142,7 +143,7 @@ ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length)
                mutex_lock(&bus->device_lock);
 
                if (!mei_cl_is_connected(cl)) {
-                       rets = -EBUSY;
+                       rets = -ENODEV;
                        goto out;
                }
        }
@@ -234,7 +235,7 @@ static void mei_cl_bus_event_work(struct work_struct *work)
        /* Prepare for the next read */
        if (cldev->events_mask & BIT(MEI_CL_EVENT_RX)) {
                mutex_lock(&bus->device_lock);
-               mei_cl_read_start(cldev->cl, 0, NULL);
+               mei_cl_read_start(cldev->cl, mei_cl_mtu(cldev->cl), NULL);
                mutex_unlock(&bus->device_lock);
        }
 }
@@ -324,7 +325,7 @@ int mei_cldev_register_event_cb(struct mei_cl_device *cldev,
 
        if (cldev->events_mask & BIT(MEI_CL_EVENT_RX)) {
                mutex_lock(&bus->device_lock);
-               ret = mei_cl_read_start(cldev->cl, 0, NULL);
+               ret = mei_cl_read_start(cldev->cl, mei_cl_mtu(cldev->cl), NULL);
                mutex_unlock(&bus->device_lock);
                if (ret && ret != -EBUSY)
                        return ret;
@@ -983,12 +984,10 @@ void mei_cl_bus_rescan_work(struct work_struct *work)
                container_of(work, struct mei_device, bus_rescan_work);
        struct mei_me_client *me_cl;
 
-       mutex_lock(&bus->device_lock);
        me_cl = mei_me_cl_by_uuid(bus, &mei_amthif_guid);
        if (me_cl)
                mei_amthif_host_init(bus, me_cl);
        mei_me_cl_put(me_cl);
-       mutex_unlock(&bus->device_lock);
 
        mei_cl_bus_rescan(bus);
 }
index 641c1a5666879b9715f5ee0924db447411a2e653..45a7652820cfd5928f2dc39db1398597158dc81d 100644 (file)
@@ -358,8 +358,9 @@ void mei_io_cb_free(struct mei_cl_cb *cb)
  *
  * Return: mei_cl_cb pointer or NULL;
  */
-struct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl, enum mei_cb_file_ops type,
-                                const struct file *fp)
+static struct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl,
+                                       enum mei_cb_file_ops type,
+                                       const struct file *fp)
 {
        struct mei_cl_cb *cb;
 
@@ -420,32 +421,41 @@ static inline void mei_io_list_free(struct mei_cl_cb *list, struct mei_cl *cl)
 }
 
 /**
- * mei_io_cb_alloc_buf - allocate callback buffer
+ * mei_cl_alloc_cb - a convenient wrapper for allocating read cb
  *
- * @cb: io callback structure
+ * @cl: host client
  * @length: size of the buffer
+ * @type: operation type
+ * @fp: associated file pointer (might be NULL)
  *
- * Return: 0 on success
- *         -EINVAL if cb is NULL
- *         -ENOMEM if allocation failed
+ * Return: cb on success and NULL on failure
  */
-int mei_io_cb_alloc_buf(struct mei_cl_cb *cb, size_t length)
+struct mei_cl_cb *mei_cl_alloc_cb(struct mei_cl *cl, size_t length,
+                                 enum mei_cb_file_ops fop_type,
+                                 const struct file *fp)
 {
+       struct mei_cl_cb *cb;
+
+       cb = mei_io_cb_init(cl, fop_type, fp);
        if (!cb)
-               return -EINVAL;
+               return NULL;
 
        if (length == 0)
-               return 0;
+               return cb;
 
        cb->buf.data = kmalloc(length, GFP_KERNEL);
-       if (!cb->buf.data)
-               return -ENOMEM;
+       if (!cb->buf.data) {
+               mei_io_cb_free(cb);
+               return NULL;
+       }
        cb->buf.size = length;
-       return 0;
+
+       return cb;
 }
 
 /**
- * mei_cl_alloc_cb - a convenient wrapper for allocating read cb
+ * mei_cl_enqueue_ctrl_wr_cb - a convenient wrapper for allocating
+ *     and enqueuing of the control commands cb
  *
  * @cl: host client
  * @length: size of the buffer
@@ -453,22 +463,23 @@ int mei_io_cb_alloc_buf(struct mei_cl_cb *cb, size_t length)
  * @fp: associated file pointer (might be NULL)
  *
  * Return: cb on success and NULL on failure
+ * Locking: called under "dev->device_lock" lock
  */
-struct mei_cl_cb *mei_cl_alloc_cb(struct mei_cl *cl, size_t length,
-                                 enum mei_cb_file_ops type,
-                                 const struct file *fp)
+struct mei_cl_cb *mei_cl_enqueue_ctrl_wr_cb(struct mei_cl *cl, size_t length,
+                                           enum mei_cb_file_ops fop_type,
+                                           const struct file *fp)
 {
        struct mei_cl_cb *cb;
 
-       cb = mei_io_cb_init(cl, type, fp);
-       if (!cb)
-               return NULL;
+       /* for RX always allocate at least client's mtu */
+       if (length)
+               length = max_t(size_t, length, mei_cl_mtu(cl));
 
-       if (mei_io_cb_alloc_buf(cb, length)) {
-               mei_io_cb_free(cb);
+       cb = mei_cl_alloc_cb(cl, length, fop_type, fp);
+       if (!cb)
                return NULL;
-       }
 
+       list_add_tail(&cb->list, &cl->dev->ctrl_wr_list.list);
        return cb;
 }
 
@@ -754,7 +765,8 @@ void mei_cl_set_disconnected(struct mei_cl *cl)
        mei_io_list_flush(&dev->ctrl_rd_list, cl);
        mei_io_list_flush(&dev->ctrl_wr_list, cl);
        mei_cl_wake_all(cl);
-       cl->mei_flow_ctrl_creds = 0;
+       cl->rx_flow_ctrl_creds = 0;
+       cl->tx_flow_ctrl_creds = 0;
        cl->timer_count = 0;
 
        if (!cl->me_cl)
@@ -764,7 +776,7 @@ void mei_cl_set_disconnected(struct mei_cl *cl)
                cl->me_cl->connect_count--;
 
        if (cl->me_cl->connect_count == 0)
-               cl->me_cl->mei_flow_ctrl_creds = 0;
+               cl->me_cl->tx_flow_ctrl_creds = 0;
 
        mei_me_cl_put(cl->me_cl);
        cl->me_cl = NULL;
@@ -867,13 +879,11 @@ static int __mei_cl_disconnect(struct mei_cl *cl)
 
        cl->state = MEI_FILE_DISCONNECTING;
 
-       cb = mei_io_cb_init(cl, MEI_FOP_DISCONNECT, NULL);
-       rets = cb ? 0 : -ENOMEM;
-       if (rets)
+       cb = mei_cl_enqueue_ctrl_wr_cb(cl, 0, MEI_FOP_DISCONNECT, NULL);
+       if (!cb) {
+               rets = -ENOMEM;
                goto out;
-
-       cl_dbg(dev, cl, "add disconnect cb to control write list\n");
-       list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
+       }
 
        if (mei_hbuf_acquire(dev)) {
                rets = mei_cl_send_disconnect(cl, cb);
@@ -1042,14 +1052,14 @@ int mei_cl_irq_connect(struct mei_cl *cl, struct mei_cl_cb *cb,
  *
  * @cl: host client
  * @me_cl: me client
- * @file: pointer to file structure
+ * @fp: pointer to file structure
  *
  * Locking: called under "dev->device_lock" lock
  *
  * Return: 0 on success, <0 on failure.
  */
 int mei_cl_connect(struct mei_cl *cl, struct mei_me_client *me_cl,
-                 const struct file *file)
+                  const struct file *fp)
 {
        struct mei_device *dev;
        struct mei_cl_cb *cb;
@@ -1076,12 +1086,11 @@ int mei_cl_connect(struct mei_cl *cl, struct mei_me_client *me_cl,
                goto nortpm;
        }
 
-       cb = mei_io_cb_init(cl, MEI_FOP_CONNECT, file);
-       rets = cb ? 0 : -ENOMEM;
-       if (rets)
+       cb = mei_cl_enqueue_ctrl_wr_cb(cl, 0, MEI_FOP_CONNECT, fp);
+       if (!cb) {
+               rets = -ENOMEM;
                goto out;
-
-       list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
+       }
 
        /* run hbuf acquire last so we don't have to undo */
        if (!mei_cl_is_other_connecting(cl) && mei_hbuf_acquire(dev)) {
@@ -1159,50 +1168,42 @@ err:
        return ERR_PTR(ret);
 }
 
-
-
 /**
- * mei_cl_flow_ctrl_creds - checks flow_control credits for cl.
+ * mei_cl_tx_flow_ctrl_creds - checks flow_control credits for cl.
  *
  * @cl: host client
- * @fp: the file pointer associated with the pointer
  *
- * Return: 1 if mei_flow_ctrl_creds >0, 0 - otherwise.
+ * Return: 1 if tx_flow_ctrl_creds >0, 0 - otherwise.
  */
-static int mei_cl_flow_ctrl_creds(struct mei_cl *cl, const struct file *fp)
+static int mei_cl_tx_flow_ctrl_creds(struct mei_cl *cl)
 {
-       int rets;
-
        if (WARN_ON(!cl || !cl->me_cl))
                return -EINVAL;
 
-       if (cl->mei_flow_ctrl_creds > 0)
+       if (cl->tx_flow_ctrl_creds > 0)
                return 1;
 
-       if (mei_cl_is_fixed_address(cl)) {
-               rets = mei_cl_read_start(cl, mei_cl_mtu(cl), fp);
-               if (rets && rets != -EBUSY)
-                       return rets;
+       if (mei_cl_is_fixed_address(cl))
                return 1;
-       }
 
        if (mei_cl_is_single_recv_buf(cl)) {
-               if (cl->me_cl->mei_flow_ctrl_creds > 0)
+               if (cl->me_cl->tx_flow_ctrl_creds > 0)
                        return 1;
        }
        return 0;
 }
 
 /**
- * mei_cl_flow_ctrl_reduce - reduces flow_control.
+ * mei_cl_tx_flow_ctrl_creds_reduce - reduces transmit flow control credits
+ *   for a client
  *
- * @cl: private data of the file object
+ * @cl: host client
  *
  * Return:
  *     0 on success
  *     -EINVAL when ctrl credits are <= 0
  */
-static int mei_cl_flow_ctrl_reduce(struct mei_cl *cl)
+static int mei_cl_tx_flow_ctrl_creds_reduce(struct mei_cl *cl)
 {
        if (WARN_ON(!cl || !cl->me_cl))
                return -EINVAL;
@@ -1211,13 +1212,13 @@ static int mei_cl_flow_ctrl_reduce(struct mei_cl *cl)
                return 0;
 
        if (mei_cl_is_single_recv_buf(cl)) {
-               if (WARN_ON(cl->me_cl->mei_flow_ctrl_creds <= 0))
+               if (WARN_ON(cl->me_cl->tx_flow_ctrl_creds <= 0))
                        return -EINVAL;
-               cl->me_cl->mei_flow_ctrl_creds--;
+               cl->me_cl->tx_flow_ctrl_creds--;
        } else {
-               if (WARN_ON(cl->mei_flow_ctrl_creds <= 0))
+               if (WARN_ON(cl->tx_flow_ctrl_creds <= 0))
                        return -EINVAL;
-               cl->mei_flow_ctrl_creds--;
+               cl->tx_flow_ctrl_creds--;
        }
        return 0;
 }
@@ -1292,7 +1293,7 @@ int mei_cl_irq_notify(struct mei_cl *cl, struct mei_cl_cb *cb,
  * mei_cl_notify_request - send notification stop/start request
  *
  * @cl: host client
- * @file: associate request with file
+ * @fp: associate request with file
  * @request: 1 for start or 0 for stop
  *
  * Locking: called under "dev->device_lock" lock
@@ -1300,7 +1301,7 @@ int mei_cl_irq_notify(struct mei_cl *cl, struct mei_cl_cb *cb,
  * Return: 0 on such and error otherwise.
  */
 int mei_cl_notify_request(struct mei_cl *cl,
-                         const struct file *file, u8 request)
+                         const struct file *fp, u8 request)
 {
        struct mei_device *dev;
        struct mei_cl_cb *cb;
@@ -1325,7 +1326,7 @@ int mei_cl_notify_request(struct mei_cl *cl,
        }
 
        fop_type = mei_cl_notify_req2fop(request);
-       cb = mei_io_cb_init(cl, fop_type, file);
+       cb = mei_cl_enqueue_ctrl_wr_cb(cl, 0, fop_type, fp);
        if (!cb) {
                rets = -ENOMEM;
                goto out;
@@ -1336,9 +1337,7 @@ int mei_cl_notify_request(struct mei_cl *cl,
                        rets = -ENODEV;
                        goto out;
                }
-               list_add_tail(&cb->list, &dev->ctrl_rd_list.list);
-       } else {
-               list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
+               list_move_tail(&cb->list, &dev->ctrl_rd_list.list);
        }
 
        mutex_unlock(&dev->device_lock);
@@ -1435,25 +1434,6 @@ out:
        return 0;
 }
 
-/**
- * mei_cl_is_read_fc_cb - check if read cb is waiting for flow control
- *                        for given host client
- *
- * @cl: host client
- *
- * Return: true, if found at least one cb.
- */
-static bool mei_cl_is_read_fc_cb(struct mei_cl *cl)
-{
-       struct mei_device *dev = cl->dev;
-       struct mei_cl_cb *cb;
-
-       list_for_each_entry(cb, &dev->ctrl_wr_list.list, list)
-               if (cb->fop_type == MEI_FOP_READ && cb->cl == cl)
-                       return true;
-       return false;
-}
-
 /**
  * mei_cl_read_start - the start read client message function.
  *
@@ -1477,26 +1457,22 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length, const struct file *fp)
        if (!mei_cl_is_connected(cl))
                return -ENODEV;
 
-       /* HW currently supports only one pending read */
-       if (!list_empty(&cl->rd_pending) || mei_cl_is_read_fc_cb(cl))
-               return -EBUSY;
-
        if (!mei_me_cl_is_active(cl->me_cl)) {
                cl_err(dev, cl, "no such me client\n");
                return  -ENOTTY;
        }
 
-       /* always allocate at least client max message */
-       length = max_t(size_t, length, mei_cl_mtu(cl));
-       cb = mei_cl_alloc_cb(cl, length, MEI_FOP_READ, fp);
+       if (mei_cl_is_fixed_address(cl) || cl == &dev->iamthif_cl)
+               return 0;
+
+       /* HW currently supports only one pending read */
+       if (cl->rx_flow_ctrl_creds)
+               return -EBUSY;
+
+       cb = mei_cl_enqueue_ctrl_wr_cb(cl, length, MEI_FOP_READ, fp);
        if (!cb)
                return -ENOMEM;
 
-       if (mei_cl_is_fixed_address(cl)) {
-               list_add_tail(&cb->list, &cl->rd_pending);
-               return 0;
-       }
-
        rets = pm_runtime_get(dev->dev);
        if (rets < 0 && rets != -EINPROGRESS) {
                pm_runtime_put_noidle(dev->dev);
@@ -1504,16 +1480,15 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length, const struct file *fp)
                goto nortpm;
        }
 
+       rets = 0;
        if (mei_hbuf_acquire(dev)) {
                rets = mei_hbm_cl_flow_control_req(dev, cl);
                if (rets < 0)
                        goto out;
 
-               list_add_tail(&cb->list, &cl->rd_pending);
-       } else {
-               rets = 0;
-               list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
+               list_move_tail(&cb->list, &cl->rd_pending);
        }
+       cl->rx_flow_ctrl_creds++;
 
 out:
        cl_dbg(dev, cl, "rpm: autosuspend\n");
@@ -1557,7 +1532,7 @@ int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
 
        first_chunk = cb->buf_idx == 0;
 
-       rets = first_chunk ? mei_cl_flow_ctrl_creds(cl, cb->fp) : 1;
+       rets = first_chunk ? mei_cl_tx_flow_ctrl_creds(cl) : 1;
        if (rets < 0)
                return rets;
 
@@ -1605,7 +1580,7 @@ int mei_cl_irq_write(struct mei_cl *cl, struct mei_cl_cb *cb,
        cb->completed = mei_hdr.msg_complete == 1;
 
        if (first_chunk) {
-               if (mei_cl_flow_ctrl_reduce(cl))
+               if (mei_cl_tx_flow_ctrl_creds_reduce(cl))
                        return -EIO;
        }
 
@@ -1663,7 +1638,7 @@ int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking)
        mei_hdr.msg_complete = 0;
        mei_hdr.internal = cb->internal;
 
-       rets = mei_cl_flow_ctrl_creds(cl, cb->fp);
+       rets = mei_cl_tx_flow_ctrl_creds(cl);
        if (rets < 0)
                goto err;
 
@@ -1691,7 +1666,7 @@ int mei_cl_write(struct mei_cl *cl, struct mei_cl_cb *cb, bool blocking)
        if (rets)
                goto err;
 
-       rets = mei_cl_flow_ctrl_reduce(cl);
+       rets = mei_cl_tx_flow_ctrl_creds_reduce(cl);
        if (rets)
                goto err;
 
@@ -1761,6 +1736,9 @@ void mei_cl_complete(struct mei_cl *cl, struct mei_cl_cb *cb)
 
        case MEI_FOP_READ:
                list_add_tail(&cb->list, &cl->rd_completed);
+               if (!mei_cl_is_fixed_address(cl) &&
+                   !WARN_ON(!cl->rx_flow_ctrl_creds))
+                       cl->rx_flow_ctrl_creds--;
                if (!mei_cl_bus_rx_event(cl))
                        wake_up_interruptible(&cl->rx_wait);
                break;
index 0d7a3a1fef7891ca19eb4d2bfb98d54abede69cc..d2bfabecd882c1d963f14f504914857ba06f1a98 100644 (file)
@@ -82,11 +82,7 @@ static inline u8 mei_me_cl_ver(const struct mei_me_client *me_cl)
 /*
  * MEI IO Functions
  */
-struct mei_cl_cb *mei_io_cb_init(struct mei_cl *cl, enum mei_cb_file_ops type,
-                                const struct file *fp);
 void mei_io_cb_free(struct mei_cl_cb *priv_cb);
-int mei_io_cb_alloc_buf(struct mei_cl_cb *cb, size_t length);
-
 
 /**
  * mei_io_list_init - Sets up a queue list.
@@ -118,6 +114,9 @@ void mei_cl_read_cb_flush(const struct mei_cl *cl, const struct file *fp);
 struct mei_cl_cb *mei_cl_alloc_cb(struct mei_cl *cl, size_t length,
                                  enum mei_cb_file_ops type,
                                  const struct file *fp);
+struct mei_cl_cb *mei_cl_enqueue_ctrl_wr_cb(struct mei_cl *cl, size_t length,
+                                           enum mei_cb_file_ops type,
+                                           const struct file *fp);
 int mei_cl_flush_queues(struct mei_cl *cl, const struct file *fp);
 
 /*
index 085f3aafe6fa92f6ec749f7d5ed457edb1b31348..4b9495f0394c90e8cc10adae6342315427551e62 100644 (file)
@@ -161,6 +161,7 @@ void mei_hbm_cl_hdr(struct mei_cl *cl, u8 hbm_cmd, void *buf, size_t len)
  * @dev: the device structure
  * @cl: client
  * @hbm_cmd: host bus message command
+ * @buf: message buffer
  * @len: buffer length
  *
  * Return: 0 on success, <0 on failure.
@@ -339,7 +340,7 @@ static int mei_hbm_me_cl_add(struct mei_device *dev,
 
        me_cl->props = res->client_properties;
        me_cl->client_id = res->me_addr;
-       me_cl->mei_flow_ctrl_creds = 0;
+       me_cl->tx_flow_ctrl_creds = 0;
 
        mei_me_cl_add(dev, me_cl);
 
@@ -636,23 +637,22 @@ int mei_hbm_cl_flow_control_req(struct mei_device *dev, struct mei_cl *cl)
 }
 
 /**
- * mei_hbm_add_single_flow_creds - adds single buffer credentials.
+ * mei_hbm_add_single_tx_flow_ctrl_creds - adds single buffer credentials.
  *
  * @dev: the device structure
- * @flow: flow control.
+ * @fctrl: flow control response bus message
  *
  * Return: 0 on success, < 0 otherwise
  */
-static int mei_hbm_add_single_flow_creds(struct mei_device *dev,
-                                 struct hbm_flow_control *flow)
+static int mei_hbm_add_single_tx_flow_ctrl_creds(struct mei_device *dev,
+                                                struct hbm_flow_control *fctrl)
 {
        struct mei_me_client *me_cl;
        int rets;
 
-       me_cl = mei_me_cl_by_id(dev, flow->me_addr);
+       me_cl = mei_me_cl_by_id(dev, fctrl->me_addr);
        if (!me_cl) {
-               dev_err(dev->dev, "no such me client %d\n",
-                       flow->me_addr);
+               dev_err(dev->dev, "no such me client %d\n", fctrl->me_addr);
                return -ENOENT;
        }
 
@@ -661,9 +661,9 @@ static int mei_hbm_add_single_flow_creds(struct mei_device *dev,
                goto out;
        }
 
-       me_cl->mei_flow_ctrl_creds++;
+       me_cl->tx_flow_ctrl_creds++;
        dev_dbg(dev->dev, "recv flow ctrl msg ME %d (single) creds = %d.\n",
-           flow->me_addr, me_cl->mei_flow_ctrl_creds);
+               fctrl->me_addr, me_cl->tx_flow_ctrl_creds);
 
        rets = 0;
 out:
@@ -675,24 +675,24 @@ out:
  * mei_hbm_cl_flow_control_res - flow control response from me
  *
  * @dev: the device structure
- * @flow_control: flow control response bus message
+ * @fctrl: flow control response bus message
  */
-static void mei_hbm_cl_flow_control_res(struct mei_device *dev,
-                                       struct hbm_flow_control *flow_control)
+static void mei_hbm_cl_tx_flow_ctrl_creds_res(struct mei_device *dev,
+                                              struct hbm_flow_control *fctrl)
 {
        struct mei_cl *cl;
 
-       if (!flow_control->host_addr) {
+       if (!fctrl->host_addr) {
                /* single receive buffer */
-               mei_hbm_add_single_flow_creds(dev, flow_control);
+               mei_hbm_add_single_tx_flow_ctrl_creds(dev, fctrl);
                return;
        }
 
-       cl = mei_hbm_cl_find_by_cmd(dev, flow_control);
+       cl = mei_hbm_cl_find_by_cmd(dev, fctrl);
        if (cl) {
-               cl->mei_flow_ctrl_creds++;
+               cl->tx_flow_ctrl_creds++;
                cl_dbg(dev, cl, "flow control creds = %d.\n",
-                               cl->mei_flow_ctrl_creds);
+                               cl->tx_flow_ctrl_creds);
        }
 }
 
@@ -871,10 +871,10 @@ static int mei_hbm_fw_disconnect_req(struct mei_device *dev,
                cl->state = MEI_FILE_DISCONNECTING;
                cl->timer_count = 0;
 
-               cb = mei_io_cb_init(cl, MEI_FOP_DISCONNECT_RSP, NULL);
+               cb = mei_cl_enqueue_ctrl_wr_cb(cl, 0, MEI_FOP_DISCONNECT_RSP,
+                                              NULL);
                if (!cb)
                        return -ENOMEM;
-               list_add_tail(&cb->list, &dev->ctrl_wr_list.list);
        }
        return 0;
 }
@@ -1022,7 +1022,7 @@ int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr)
 
        struct mei_hbm_cl_cmd *cl_cmd;
        struct hbm_client_connect_request *disconnect_req;
-       struct hbm_flow_control *flow_control;
+       struct hbm_flow_control *fctrl;
 
        /* read the message to our buffer */
        BUG_ON(hdr->length >= sizeof(dev->rd_msg_buf));
@@ -1102,8 +1102,8 @@ int mei_hbm_dispatch(struct mei_device *dev, struct mei_msg_hdr *hdr)
        case MEI_FLOW_CONTROL_CMD:
                dev_dbg(dev->dev, "hbm: client flow control response: message received.\n");
 
-               flow_control = (struct hbm_flow_control *) mei_msg;
-               mei_hbm_cl_flow_control_res(dev, flow_control);
+               fctrl = (struct hbm_flow_control *)mei_msg;
+               mei_hbm_cl_tx_flow_ctrl_creds_res(dev, fctrl);
                break;
 
        case MEI_PG_ISOLATION_ENTRY_RES_CMD:
index 0dcb854b4bfcdd38f80bdce7b5302e71d5101a11..7ad15d678878cf5e4f5bba819bda3ceba75560c6 100644 (file)
 #define MEI_DEV_ID_BXT_M      0x1A9A  /* Broxton M */
 #define MEI_DEV_ID_APL_I      0x5A9A  /* Apollo Lake I */
 
+#define MEI_DEV_ID_KBP        0xA2BA  /* Kaby Point */
+#define MEI_DEV_ID_KBP_2      0xA2BB  /* Kaby Point 2 */
+
 /*
  * MEI HW Section
  */
index dc3a854e02d39d1b73f95ff1ed8e203088955cb6..56c2101e80adb2033ed90ab54dbac2a2a36ee886 100644 (file)
@@ -18,6 +18,7 @@
 
 #include <linux/kthread.h>
 #include <linux/interrupt.h>
+#include <linux/pm_runtime.h>
 
 #include "mei_dev.h"
 #include "hbm.h"
@@ -1063,6 +1064,8 @@ static int mei_me_hw_reset(struct mei_device *dev, bool intr_enable)
                }
        }
 
+       pm_runtime_set_active(dev->dev);
+
        hcsr = mei_hcsr_read(dev);
        /* H_RST may be found lit before reset is started,
         * for example if preceding reset flow hasn't completed.
index 4a6c1b85f11e71d5cb09e0568527a0b4d494cbed..e6e5e55a12ed45f09577899198e7a8735ae7a0e8 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/delay.h>
 #include <linux/kthread.h>
 #include <linux/irqreturn.h>
+#include <linux/pm_runtime.h>
 
 #include <linux/mei.h>
 
@@ -935,6 +936,8 @@ static int mei_txe_hw_start(struct mei_device *dev)
                return ret;
        }
 
+       pm_runtime_set_active(dev->dev);
+
        /* enable input ready interrupts:
         * SEC_IPC_HOST_INT_MASK.IPC_INPUT_READY_INT_MASK
         */
index 3831a7ba2531c2c32c164e8cd987ad8590ef99e4..bf745e03f21e5a44a7d543f9df9de03c0cc3f28b 100644 (file)
@@ -102,26 +102,25 @@ int mei_cl_irq_read_msg(struct mei_cl *cl,
 {
        struct mei_device *dev = cl->dev;
        struct mei_cl_cb *cb;
-       unsigned char *buffer = NULL;
        size_t buf_sz;
 
        cb = list_first_entry_or_null(&cl->rd_pending, struct mei_cl_cb, list);
        if (!cb) {
-               cl_err(dev, cl, "pending read cb not found\n");
-               goto out;
+               if (!mei_cl_is_fixed_address(cl)) {
+                       cl_err(dev, cl, "pending read cb not found\n");
+                       goto discard;
+               }
+               cb = mei_cl_alloc_cb(cl, mei_cl_mtu(cl), MEI_FOP_READ, cl->fp);
+               if (!cb)
+                       goto discard;
+               list_add_tail(&cb->list, &cl->rd_pending);
        }
 
        if (!mei_cl_is_connected(cl)) {
                cl_dbg(dev, cl, "not connected\n");
-               cb->status = -ENODEV;
-               goto out;
-       }
-
-       if (cb->buf.size == 0 || cb->buf.data == NULL) {
-               cl_err(dev, cl, "response buffer is not allocated.\n");
                list_move_tail(&cb->list, &complete_list->list);
-               cb->status = -ENOMEM;
-               goto out;
+               cb->status = -ENODEV;
+               goto discard;
        }
 
        buf_sz = mei_hdr->length + cb->buf_idx;
@@ -132,25 +131,19 @@ int mei_cl_irq_read_msg(struct mei_cl *cl,
 
                list_move_tail(&cb->list, &complete_list->list);
                cb->status = -EMSGSIZE;
-               goto out;
+               goto discard;
        }
 
        if (cb->buf.size < buf_sz) {
                cl_dbg(dev, cl, "message overflow. size %zu len %d idx %zu\n",
                        cb->buf.size, mei_hdr->length, cb->buf_idx);
-               buffer = krealloc(cb->buf.data, buf_sz, GFP_KERNEL);
 
-               if (!buffer) {
-                       cb->status = -ENOMEM;
-                       list_move_tail(&cb->list, &complete_list->list);
-                       goto out;
-               }
-               cb->buf.data = buffer;
-               cb->buf.size = buf_sz;
+               list_move_tail(&cb->list, &complete_list->list);
+               cb->status = -EMSGSIZE;
+               goto discard;
        }
 
-       buffer = cb->buf.data + cb->buf_idx;
-       mei_read_slots(dev, buffer, mei_hdr->length);
+       mei_read_slots(dev, cb->buf.data + cb->buf_idx, mei_hdr->length);
 
        cb->buf_idx += mei_hdr->length;
 
@@ -162,10 +155,10 @@ int mei_cl_irq_read_msg(struct mei_cl *cl,
                pm_request_autosuspend(dev->dev);
        }
 
-out:
-       if (!buffer)
-               mei_irq_discard_msg(dev, mei_hdr);
+       return 0;
 
+discard:
+       mei_irq_discard_msg(dev, mei_hdr);
        return 0;
 }
 
@@ -216,6 +209,9 @@ static int mei_cl_irq_read(struct mei_cl *cl, struct mei_cl_cb *cb,
        int slots;
        int ret;
 
+       if (!list_empty(&cl->rd_pending))
+               return 0;
+
        msg_slots = mei_data2slots(sizeof(struct hbm_flow_control));
        slots = mei_hbuf_empty_slots(dev);
 
@@ -514,13 +510,7 @@ void mei_timer(struct work_struct *work)
                if (--dev->iamthif_stall_timer == 0) {
                        dev_err(dev->dev, "timer: amthif  hanged.\n");
                        mei_reset(dev);
-                       dev->iamthif_canceled = false;
-                       dev->iamthif_state = MEI_IAMTHIF_IDLE;
-
-                       mei_io_cb_free(dev->iamthif_current_cb);
-                       dev->iamthif_current_cb = NULL;
 
-                       dev->iamthif_fp = NULL;
                        mei_amthif_run_next_cmd(dev);
                }
        }
index 52635b063873ac1289b22c8987a5e115c37dc4cc..fa50635512e88985328849e216923785316ef79e 100644 (file)
@@ -71,6 +71,7 @@ static int mei_open(struct inode *inode, struct file *file)
                goto err_unlock;
        }
 
+       cl->fp = file;
        file->private_data = cl;
 
        mutex_unlock(&dev->device_lock);
@@ -138,9 +139,8 @@ static ssize_t mei_read(struct file *file, char __user *ubuf,
        struct mei_cl *cl = file->private_data;
        struct mei_device *dev;
        struct mei_cl_cb *cb = NULL;
+       bool nonblock = !!(file->f_flags & O_NONBLOCK);
        int rets;
-       int err;
-
 
        if (WARN_ON(!cl || !cl->dev))
                return -ENODEV;
@@ -164,11 +164,6 @@ static ssize_t mei_read(struct file *file, char __user *ubuf,
                goto out;
        }
 
-       if (cl == &dev->iamthif_cl) {
-               rets = mei_amthif_read(dev, file, ubuf, length, offset);
-               goto out;
-       }
-
        cb = mei_cl_read_cb(cl, file);
        if (cb)
                goto copy_buffer;
@@ -176,24 +171,29 @@ static ssize_t mei_read(struct file *file, char __user *ubuf,
        if (*offset > 0)
                *offset = 0;
 
-       err = mei_cl_read_start(cl, length, file);
-       if (err && err != -EBUSY) {
-               cl_dbg(dev, cl, "mei start read failure status = %d\n", err);
-               rets = err;
+       rets = mei_cl_read_start(cl, length, file);
+       if (rets && rets != -EBUSY) {
+               cl_dbg(dev, cl, "mei start read failure status = %d\n", rets);
                goto out;
        }
 
-       if (list_empty(&cl->rd_completed) && !waitqueue_active(&cl->rx_wait)) {
-               if (file->f_flags & O_NONBLOCK) {
-                       rets = -EAGAIN;
-                       goto out;
-               }
+       if (nonblock) {
+               rets = -EAGAIN;
+               goto out;
+       }
 
+       if (rets == -EBUSY &&
+           !mei_cl_enqueue_ctrl_wr_cb(cl, length, MEI_FOP_READ, file)) {
+               rets = -ENOMEM;
+               goto out;
+       }
+
+       do {
                mutex_unlock(&dev->device_lock);
 
                if (wait_event_interruptible(cl->rx_wait,
-                               (!list_empty(&cl->rd_completed)) ||
-                               (!mei_cl_is_connected(cl)))) {
+                                            (!list_empty(&cl->rd_completed)) ||
+                                            (!mei_cl_is_connected(cl)))) {
 
                        if (signal_pending(current))
                                return -EINTR;
@@ -202,16 +202,12 @@ static ssize_t mei_read(struct file *file, char __user *ubuf,
 
                mutex_lock(&dev->device_lock);
                if (!mei_cl_is_connected(cl)) {
-                       rets = -EBUSY;
+                       rets = -ENODEV;
                        goto out;
                }
-       }
 
-       cb = mei_cl_read_cb(cl, file);
-       if (!cb) {
-               rets = 0;
-               goto out;
-       }
+               cb = mei_cl_read_cb(cl, file);
+       } while (!cb);
 
 copy_buffer:
        /* now copy the data to user space */
@@ -609,24 +605,24 @@ static unsigned int mei_poll(struct file *file, poll_table *wait)
                goto out;
        }
 
-       if (cl == &dev->iamthif_cl) {
-               mask = mei_amthif_poll(dev, file, wait);
-               goto out;
-       }
-
        if (notify_en) {
                poll_wait(file, &cl->ev_wait, wait);
                if (cl->notify_ev)
                        mask |= POLLPRI;
        }
 
+       if (cl == &dev->iamthif_cl) {
+               mask |= mei_amthif_poll(file, wait);
+               goto out;
+       }
+
        if (req_events & (POLLIN | POLLRDNORM)) {
                poll_wait(file, &cl->rx_wait, wait);
 
                if (!list_empty(&cl->rd_completed))
                        mask |= POLLIN | POLLRDNORM;
                else
-                       mei_cl_read_start(cl, 0, file);
+                       mei_cl_read_start(cl, mei_cl_mtu(cl), file);
        }
 
 out:
index e5e32503d4bc44d9e03283f45910b271ba836a68..397ae2b45c9e62ad548292e13432782a95bb246d 100644 (file)
@@ -80,18 +80,13 @@ const char *mei_dev_state_str(int state);
 enum iamthif_states {
        MEI_IAMTHIF_IDLE,
        MEI_IAMTHIF_WRITING,
-       MEI_IAMTHIF_FLOW_CONTROL,
        MEI_IAMTHIF_READING,
-       MEI_IAMTHIF_READ_COMPLETE
 };
 
 enum mei_file_transaction_states {
        MEI_IDLE,
        MEI_WRITING,
        MEI_WRITE_COMPLETE,
-       MEI_FLOW_CONTROL,
-       MEI_READING,
-       MEI_READ_COMPLETE
 };
 
 /**
@@ -146,7 +141,7 @@ struct mei_fw_status {
  * @refcnt: struct reference count
  * @props: client properties
  * @client_id: me client id
- * @mei_flow_ctrl_creds: flow control credits
+ * @tx_flow_ctrl_creds: flow control credits
  * @connect_count: number connections to this client
  * @bus_added: added to bus
  */
@@ -155,7 +150,7 @@ struct mei_me_client {
        struct kref refcnt;
        struct mei_client_properties props;
        u8 client_id;
-       u8 mei_flow_ctrl_creds;
+       u8 tx_flow_ctrl_creds;
        u8 connect_count;
        u8 bus_added;
 };
@@ -202,10 +197,11 @@ struct mei_cl_cb {
  * @ev_async: event async notification
  * @status: connection status
  * @me_cl: fw client connected
+ * @fp: file associated with client
  * @host_client_id: host id
- * @mei_flow_ctrl_creds: transmit flow credentials
+ * @tx_flow_ctrl_creds: transmit flow credentials
+ * @rx_flow_ctrl_creds: receive flow credentials
  * @timer_count:  watchdog timer for operation completion
- * @reserved: reserved for alignment
  * @notify_en: notification - enabled/disabled
  * @notify_ev: pending notification event
  * @writing_state: state of the tx
@@ -225,10 +221,11 @@ struct mei_cl {
        struct fasync_struct *ev_async;
        int status;
        struct mei_me_client *me_cl;
+       const struct file *fp;
        u8 host_client_id;
-       u8 mei_flow_ctrl_creds;
+       u8 tx_flow_ctrl_creds;
+       u8 rx_flow_ctrl_creds;
        u8 timer_count;
-       u8 reserved;
        u8 notify_en;
        u8 notify_ev;
        enum mei_file_transaction_states writing_state;
@@ -400,9 +397,7 @@ const char *mei_pg_state_str(enum mei_pg_state state);
  * @override_fixed_address: force allow fixed address behavior
  *
  * @amthif_cmd_list : amthif list for cmd waiting
- * @iamthif_fp : file for current amthif operation
  * @iamthif_cl  : amthif host client
- * @iamthif_current_cb : amthif current operation callback
  * @iamthif_open_count : number of opened amthif connections
  * @iamthif_stall_timer : timer to detect amthif hang
  * @iamthif_state : amthif processor state
@@ -484,10 +479,7 @@ struct mei_device {
 
        /* amthif list for cmd waiting */
        struct mei_cl_cb amthif_cmd_list;
-       /* driver managed amthif list for reading completed amthif cmd data */
-       const struct file *iamthif_fp;
        struct mei_cl iamthif_cl;
-       struct mei_cl_cb *iamthif_current_cb;
        long iamthif_open_count;
        u32 iamthif_stall_timer;
        enum iamthif_states iamthif_state;
@@ -569,11 +561,7 @@ void mei_amthif_reset_params(struct mei_device *dev);
 
 int mei_amthif_host_init(struct mei_device *dev, struct mei_me_client *me_cl);
 
-int mei_amthif_read(struct mei_device *dev, struct file *file,
-               char __user *ubuf, size_t length, loff_t *offset);
-
-unsigned int mei_amthif_poll(struct mei_device *dev,
-               struct file *file, poll_table *wait);
+unsigned int mei_amthif_poll(struct file *file, poll_table *wait);
 
 int mei_amthif_release(struct mei_device *dev, struct file *file);
 
index 71cea9b296b2f72c1763d335024ff24379e137b7..e85bb371c87db3f3a27f8fbaa6eb7a98ea905240 100644 (file)
@@ -91,6 +91,9 @@ static const struct pci_device_id mei_me_pci_tbl[] = {
        {MEI_PCI_DEVICE(MEI_DEV_ID_BXT_M, mei_me_pch8_cfg)},
        {MEI_PCI_DEVICE(MEI_DEV_ID_APL_I, mei_me_pch8_cfg)},
 
+       {MEI_PCI_DEVICE(MEI_DEV_ID_KBP, mei_me_pch8_cfg)},
+       {MEI_PCI_DEVICE(MEI_DEV_ID_KBP_2, mei_me_pch8_cfg)},
+
        /* required last entry */
        {0, }
 };
@@ -400,6 +403,9 @@ static int mei_me_pm_runtime_suspend(struct device *device)
 
        dev_dbg(&pdev->dev, "rpm: me: runtime suspend ret=%d\n", ret);
 
+       if (ret && ret != -EAGAIN)
+               schedule_work(&dev->reset_work);
+
        return ret;
 }
 
@@ -423,6 +429,9 @@ static int mei_me_pm_runtime_resume(struct device *device)
 
        dev_dbg(&pdev->dev, "rpm: me: runtime resume ret = %d\n", ret);
 
+       if (ret)
+               schedule_work(&dev->reset_work);
+
        return ret;
 }
 
index 30cc30683c07186e7ff33d6395f6e8a64d2cf3c0..58ffd30dcc91822393cad09a96caeccab25620e1 100644 (file)
@@ -347,6 +347,10 @@ static int mei_txe_pm_runtime_suspend(struct device *device)
        dev_dbg(&pdev->dev, "rpm: txe: runtime suspend ret=%d\n", ret);
 
        mutex_unlock(&dev->device_lock);
+
+       if (ret && ret != -EAGAIN)
+               schedule_work(&dev->reset_work);
+
        return ret;
 }
 
@@ -372,6 +376,9 @@ static int mei_txe_pm_runtime_resume(struct device *device)
 
        dev_dbg(&pdev->dev, "rpm: txe: runtime resume ret = %d\n", ret);
 
+       if (ret)
+               schedule_work(&dev->reset_work);
+
        return ret;
 }
 
index cd01a0efda6b9a4f8710ab3ad94a24f060a9fba1..64d5760d069ab3887682e5358f009c9a4767b374 100644 (file)
@@ -115,7 +115,6 @@ int scif_reserve_dma_chan(struct scif_endpt *ep)
  */
 static
 void __scif_rma_destroy_tcw(struct scif_mmu_notif *mmn,
-                           struct scif_endpt *ep,
                            u64 start, u64 len)
 {
        struct list_head *item, *tmp;
@@ -128,7 +127,6 @@ void __scif_rma_destroy_tcw(struct scif_mmu_notif *mmn,
 
        list_for_each_safe(item, tmp, &mmn->tc_reg_list) {
                window = list_entry(item, struct scif_window, list);
-               ep = (struct scif_endpt *)window->ep;
                if (!len)
                        break;
                start_va = window->va_for_temp;
@@ -146,7 +144,7 @@ static void scif_rma_destroy_tcw(struct scif_mmu_notif *mmn, u64 start, u64 len)
        struct scif_endpt *ep = mmn->ep;
 
        spin_lock(&ep->rma_info.tc_lock);
-       __scif_rma_destroy_tcw(mmn, ep, start, len);
+       __scif_rma_destroy_tcw(mmn, start, len);
        spin_unlock(&ep->rma_info.tc_lock);
 }
 
@@ -169,7 +167,7 @@ static void __scif_rma_destroy_tcw_ep(struct scif_endpt *ep)
        spin_lock(&ep->rma_info.tc_lock);
        list_for_each_safe(item, tmp, &ep->rma_info.mmn_list) {
                mmn = list_entry(item, struct scif_mmu_notif, list);
-               __scif_rma_destroy_tcw(mmn, ep, 0, ULONG_MAX);
+               __scif_rma_destroy_tcw(mmn, 0, ULONG_MAX);
        }
        spin_unlock(&ep->rma_info.tc_lock);
 }
index 49cb8f7b46727b302f5a74aae79eac0ebfcedca4..92821167707927891bca4d336d8d9133e8c47c1d 100644 (file)
@@ -552,7 +552,7 @@ static void scif_munmap(struct vm_area_struct *vma)
 {
        struct scif_endpt *ep;
        struct vma_pvt *vmapvt = vma->vm_private_data;
-       int nr_pages = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
+       int nr_pages = vma_pages(vma);
        s64 offset;
        struct scif_rma_req req;
        struct scif_window *window = NULL;
@@ -614,7 +614,7 @@ int scif_mmap(struct vm_area_struct *vma, scif_epd_t epd)
        struct scif_window *window = NULL;
        struct scif_endpt *ep = (struct scif_endpt *)epd;
        s64 start_offset = vma->vm_pgoff << PAGE_SHIFT;
-       int nr_pages = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
+       int nr_pages = vma_pages(vma);
        int err;
        struct vma_pvt *vmapvt;
 
index 4810e039bbeced8bd7bb337ddd6404c95b3bfdd6..e42bdc90fa27a64ac7ab58e92628b956ff06e8b1 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/if_ether.h>
 #include <linux/ctype.h>
 #include <linux/dmi.h>
+#include <linux/of.h>
 
 #define PHUB_STATUS 0x00               /* Status Register offset */
 #define PHUB_CONTROL 0x04              /* Control Register offset */
@@ -57,6 +58,7 @@
 
 /* CM-iTC */
 #define CLKCFG_UART_48MHZ                      (1 << 16)
+#define CLKCFG_UART_25MHZ                      (2 << 16)
 #define CLKCFG_BAUDDIV                         (2 << 20)
 #define CLKCFG_PLL2VCO                         (8 << 9)
 #define CLKCFG_UARTCLKSEL                      (1 << 18)
@@ -711,6 +713,12 @@ static int pch_phub_probe(struct pci_dev *pdev,
 
        if (id->driver_data == 1) { /* EG20T PCH */
                const char *board_name;
+               unsigned int prefetch = 0x000affaa;
+
+               if (pdev->dev.of_node)
+                       of_property_read_u32(pdev->dev.of_node,
+                                                 "intel,eg20t-prefetch",
+                                                 &prefetch);
 
                ret = sysfs_create_file(&pdev->dev.kobj,
                                        &dev_attr_pch_mac.attr);
@@ -736,11 +744,21 @@ static int pch_phub_probe(struct pci_dev *pdev,
                                                CLKCFG_UART_MASK);
 
                /* set the prefech value */
-               iowrite32(0x000affaa, chip->pch_phub_base_address + 0x14);
+               iowrite32(prefetch, chip->pch_phub_base_address + 0x14);
                /* set the interrupt delay value */
                iowrite32(0x25, chip->pch_phub_base_address + 0x44);
                chip->pch_opt_rom_start_address = PCH_PHUB_ROM_START_ADDR_EG20T;
                chip->pch_mac_start_address = PCH_PHUB_MAC_START_ADDR_EG20T;
+
+               /* quirk for MIPS Boston platform */
+               if (pdev->dev.of_node) {
+                       if (of_machine_is_compatible("img,boston")) {
+                               pch_phub_read_modify_write_reg(chip,
+                                       (unsigned int)CLKCFG_REG_OFFSET,
+                                       CLKCFG_UART_25MHZ,
+                                       CLKCFG_UART_MASK);
+                       }
+               }
        } else if (id->driver_data == 2) { /* ML7213 IOH */
                ret = sysfs_create_bin_file(&pdev->dev.kobj, &pch_bin_attr);
                if (ret)
index 9ec262a526564134a0a61b4fa442549ea0ea2c57..ec090105eb4be7f9a8a3fbc2fd09168d011cca6c 100644 (file)
@@ -381,18 +381,12 @@ static int vmci_host_do_send_datagram(struct vmci_host_dev *vmci_host_dev,
                return -EINVAL;
        }
 
-       dg = kmalloc(send_info.len, GFP_KERNEL);
-       if (!dg) {
+       dg = memdup_user((void __user *)(uintptr_t)send_info.addr,
+                        send_info.len);
+       if (IS_ERR(dg)) {
                vmci_ioctl_err(
                        "cannot allocate memory to dispatch datagram\n");
-               return -ENOMEM;
-       }
-
-       if (copy_from_user(dg, (void __user *)(uintptr_t)send_info.addr,
-                          send_info.len)) {
-               vmci_ioctl_err("error getting datagram\n");
-               kfree(dg);
-               return -EFAULT;
+               return PTR_ERR(dg);
        }
 
        if (VMCI_DG_SIZE(dg) != send_info.len) {
index 4d3f391f0a0bb21f09a514cfa07d9c517a89b6f5..423907bdd259fd21b01095dd7aa813790d770618 100644 (file)
 #include <linux/nvmem-provider.h>
 #include <linux/slab.h>
 #include <linux/of.h>
+#include <linux/of_platform.h>
 #include <linux/platform_device.h>
 
-#define EFUSE_A_SHIFT                  6
-#define EFUSE_A_MASK                   0x3ff
-#define EFUSE_PGENB                    BIT(3)
-#define EFUSE_LOAD                     BIT(2)
-#define EFUSE_STROBE                   BIT(1)
-#define EFUSE_CSB                      BIT(0)
-
-#define REG_EFUSE_CTRL                 0x0000
-#define REG_EFUSE_DOUT                 0x0004
+#define RK3288_A_SHIFT         6
+#define RK3288_A_MASK          0x3ff
+#define RK3288_PGENB           BIT(3)
+#define RK3288_LOAD            BIT(2)
+#define RK3288_STROBE          BIT(1)
+#define RK3288_CSB             BIT(0)
+
+#define RK3399_A_SHIFT         16
+#define RK3399_A_MASK          0x3ff
+#define RK3399_NBYTES          4
+#define RK3399_STROBSFTSEL     BIT(9)
+#define RK3399_RSB             BIT(7)
+#define RK3399_PD              BIT(5)
+#define RK3399_PGENB           BIT(3)
+#define RK3399_LOAD            BIT(2)
+#define RK3399_STROBE          BIT(1)
+#define RK3399_CSB             BIT(0)
+
+#define REG_EFUSE_CTRL         0x0000
+#define REG_EFUSE_DOUT         0x0004
 
 struct rockchip_efuse_chip {
        struct device *dev;
@@ -40,8 +52,8 @@ struct rockchip_efuse_chip {
        struct clk *clk;
 };
 
-static int rockchip_efuse_read(void *context, unsigned int offset,
-                              void *val, size_t bytes)
+static int rockchip_rk3288_efuse_read(void *context, unsigned int offset,
+                                     void *val, size_t bytes)
 {
        struct rockchip_efuse_chip *efuse = context;
        u8 *buf = val;
@@ -53,27 +65,82 @@ static int rockchip_efuse_read(void *context, unsigned int offset,
                return ret;
        }
 
-       writel(EFUSE_LOAD | EFUSE_PGENB, efuse->base + REG_EFUSE_CTRL);
+       writel(RK3288_LOAD | RK3288_PGENB, efuse->base + REG_EFUSE_CTRL);
        udelay(1);
        while (bytes--) {
                writel(readl(efuse->base + REG_EFUSE_CTRL) &
-                            (~(EFUSE_A_MASK << EFUSE_A_SHIFT)),
+                            (~(RK3288_A_MASK << RK3288_A_SHIFT)),
                             efuse->base + REG_EFUSE_CTRL);
                writel(readl(efuse->base + REG_EFUSE_CTRL) |
-                            ((offset++ & EFUSE_A_MASK) << EFUSE_A_SHIFT),
+                            ((offset++ & RK3288_A_MASK) << RK3288_A_SHIFT),
                             efuse->base + REG_EFUSE_CTRL);
                udelay(1);
                writel(readl(efuse->base + REG_EFUSE_CTRL) |
-                            EFUSE_STROBE, efuse->base + REG_EFUSE_CTRL);
+                            RK3288_STROBE, efuse->base + REG_EFUSE_CTRL);
                udelay(1);
                *buf++ = readb(efuse->base + REG_EFUSE_DOUT);
                writel(readl(efuse->base + REG_EFUSE_CTRL) &
-                    (~EFUSE_STROBE), efuse->base + REG_EFUSE_CTRL);
+                      (~RK3288_STROBE), efuse->base + REG_EFUSE_CTRL);
+               udelay(1);
+       }
+
+       /* Switch to standby mode */
+       writel(RK3288_PGENB | RK3288_CSB, efuse->base + REG_EFUSE_CTRL);
+
+       clk_disable_unprepare(efuse->clk);
+
+       return 0;
+}
+
+static int rockchip_rk3399_efuse_read(void *context, unsigned int offset,
+                                     void *val, size_t bytes)
+{
+       struct rockchip_efuse_chip *efuse = context;
+       unsigned int addr_start, addr_end, addr_offset, addr_len;
+       u32 out_value;
+       u8 *buf;
+       int ret, i = 0;
+
+       ret = clk_prepare_enable(efuse->clk);
+       if (ret < 0) {
+               dev_err(efuse->dev, "failed to prepare/enable efuse clk\n");
+               return ret;
+       }
+
+       addr_start = rounddown(offset, RK3399_NBYTES) / RK3399_NBYTES;
+       addr_end = roundup(offset + bytes, RK3399_NBYTES) / RK3399_NBYTES;
+       addr_offset = offset % RK3399_NBYTES;
+       addr_len = addr_end - addr_start;
+
+       buf = kzalloc(sizeof(*buf) * addr_len * RK3399_NBYTES, GFP_KERNEL);
+       if (!buf) {
+               clk_disable_unprepare(efuse->clk);
+               return -ENOMEM;
+       }
+
+       writel(RK3399_LOAD | RK3399_PGENB | RK3399_STROBSFTSEL | RK3399_RSB,
+              efuse->base + REG_EFUSE_CTRL);
+       udelay(1);
+       while (addr_len--) {
+               writel(readl(efuse->base + REG_EFUSE_CTRL) | RK3399_STROBE |
+                      ((addr_start++ & RK3399_A_MASK) << RK3399_A_SHIFT),
+                      efuse->base + REG_EFUSE_CTRL);
                udelay(1);
+               out_value = readl(efuse->base + REG_EFUSE_DOUT);
+               writel(readl(efuse->base + REG_EFUSE_CTRL) & (~RK3399_STROBE),
+                      efuse->base + REG_EFUSE_CTRL);
+               udelay(1);
+
+               memcpy(&buf[i], &out_value, RK3399_NBYTES);
+               i += RK3399_NBYTES;
        }
 
        /* Switch to standby mode */
-       writel(EFUSE_PGENB | EFUSE_CSB, efuse->base + REG_EFUSE_CTRL);
+       writel(RK3399_PD | RK3399_CSB, efuse->base + REG_EFUSE_CTRL);
+
+       memcpy(val, buf + addr_offset, bytes);
+
+       kfree(buf);
 
        clk_disable_unprepare(efuse->clk);
 
@@ -89,7 +156,27 @@ static struct nvmem_config econfig = {
 };
 
 static const struct of_device_id rockchip_efuse_match[] = {
-       { .compatible = "rockchip,rockchip-efuse", },
+       /* deprecated but kept around for dts binding compatibility */
+       {
+               .compatible = "rockchip,rockchip-efuse",
+               .data = (void *)&rockchip_rk3288_efuse_read,
+       },
+       {
+               .compatible = "rockchip,rk3066a-efuse",
+               .data = (void *)&rockchip_rk3288_efuse_read,
+       },
+       {
+               .compatible = "rockchip,rk3188-efuse",
+               .data = (void *)&rockchip_rk3288_efuse_read,
+       },
+       {
+               .compatible = "rockchip,rk3288-efuse",
+               .data = (void *)&rockchip_rk3288_efuse_read,
+       },
+       {
+               .compatible = "rockchip,rk3399-efuse",
+               .data = (void *)&rockchip_rk3399_efuse_read,
+       },
        { /* sentinel */},
 };
 MODULE_DEVICE_TABLE(of, rockchip_efuse_match);
@@ -99,6 +186,14 @@ static int rockchip_efuse_probe(struct platform_device *pdev)
        struct resource *res;
        struct nvmem_device *nvmem;
        struct rockchip_efuse_chip *efuse;
+       const struct of_device_id *match;
+       struct device *dev = &pdev->dev;
+
+       match = of_match_device(dev->driver->of_match_table, dev);
+       if (!match || !match->data) {
+               dev_err(dev, "failed to get match data\n");
+               return -EINVAL;
+       }
 
        efuse = devm_kzalloc(&pdev->dev, sizeof(struct rockchip_efuse_chip),
                             GFP_KERNEL);
@@ -116,7 +211,7 @@ static int rockchip_efuse_probe(struct platform_device *pdev)
 
        efuse->dev = &pdev->dev;
        econfig.size = resource_size(res);
-       econfig.reg_read = rockchip_efuse_read;
+       econfig.reg_read = match->data;
        econfig.priv = efuse;
        econfig.dev = efuse->dev;
        nvmem = nvmem_register(&econfig);
index ea607a4a1bddaf3e41165aebed1fd787b87d754e..554eaa1e347de5125cc4c52d7cb1f24abb4e706a 100644 (file)
@@ -126,21 +126,4 @@ static struct miscdevice sclp_ctl_device = {
        .name = "sclp",
        .fops = &sclp_ctl_fops,
 };
-
-/*
- * Register sclp_ctl misc device
- */
-static int __init sclp_ctl_init(void)
-{
-       return misc_register(&sclp_ctl_device);
-}
-module_init(sclp_ctl_init);
-
-/*
- * Deregister sclp_ctl misc device
- */
-static void __exit sclp_ctl_exit(void)
-{
-       misc_deregister(&sclp_ctl_device);
-}
-module_exit(sclp_ctl_exit);
+module_misc_device(sclp_ctl_device);
index 518db24a5b36df38e03161d251d68f949453ee05..c7831407a882d2bb19be29153926d156a2a10a93 100644 (file)
@@ -1380,7 +1380,7 @@ config SERIAL_IFX6X60
 
 config SERIAL_PCH_UART
        tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) UART"
-       depends on PCI && (X86_32 || COMPILE_TEST)
+       depends on PCI && (X86_32 || MIPS ||  COMPILE_TEST)
        select SERIAL_CORE
        help
          This driver is for PCH(Platform controller Hub) UART of Intel EG20T
index b5874d1e26b61f54df2197200168963d4c3807df..d391650b82e7be9bb63ac7df85a9de3e4fe0bed8 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/dmi.h>
 #include <linux/nmi.h>
 #include <linux/delay.h>
+#include <linux/of.h>
 
 #include <linux/debugfs.h>
 #include <linux/dmaengine.h>
@@ -1826,6 +1827,10 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev,
        priv->trigger_level = 1;
        priv->fcr = 0;
 
+       if (pdev->dev.of_node)
+               of_property_read_u32(pdev->dev.of_node, "clock-frequency"
+                                        , &user_uartclk);
+
 #ifdef CONFIG_SERIAL_PCH_UART_CONSOLE
        pch_uart_ports[board->line_no] = priv;
 #endif
index 915facbf552e207c68b4b7555b9520d70746853f..e1134a4d97f3fd0005e30dc29e9acf9da77e0e46 100644 (file)
@@ -229,7 +229,7 @@ static int uio_dmem_genirq_probe(struct platform_device *pdev)
                ++uiomem;
        }
 
-       priv->dmem_region_start = i;
+       priv->dmem_region_start = uiomem - &uioinfo->mem[0];
        priv->num_dmem_regions = pdata->num_dynamic_regions;
 
        for (i = 0; i < pdata->num_dynamic_regions; ++i) {
index 97fb2f8fa93041a5a6854e580907854e283d80a8..3cc98c07dcd39365d6a379ed2290074f56683bd0 100644 (file)
@@ -322,18 +322,7 @@ static struct miscdevice vhost_test_misc = {
        "vhost-test",
        &vhost_test_fops,
 };
-
-static int vhost_test_init(void)
-{
-       return misc_register(&vhost_test_misc);
-}
-module_init(vhost_test_init);
-
-static void vhost_test_exit(void)
-{
-       misc_deregister(&vhost_test_misc);
-}
-module_exit(vhost_test_exit);
+module_misc_device(vhost_test_misc);
 
 MODULE_VERSION("0.0.1");
 MODULE_LICENSE("GPL v2");
index f6d854584906a9c079afe585965677c0bbc2a40c..f6ddc371540163ae28136e3da4b7c6f82903d092 100644 (file)
@@ -13,3 +13,11 @@ config VME_TSI148
        help
         If you say Y here you get support for the Tundra TSI148 VME bridge
         chip.
+
+config VME_FAKE
+       tristate "Fake"
+       help
+        If you say Y here you get support for the fake VME bridge. This
+        provides a virtualised VME Bus for devices with no VME bridge. This
+        is mainly useful for VME development (in the absence of VME
+        hardware).
index 59638afcd5021f0eb8b01d1c719f737df5144437..b074542495c55b4407626da7def60032ba3fe098 100644 (file)
@@ -1,2 +1,3 @@
 obj-$(CONFIG_VME_CA91CX42)     += vme_ca91cx42.o
 obj-$(CONFIG_VME_TSI148)       += vme_tsi148.o
+obj-$(CONFIG_VME_FAKE)         += vme_fake.o
index 9f2c834e43e002bdaab5344c4d16e980f057692d..6b5ee896af6318e9b50c384fcf3e062d24d89c47 100644 (file)
@@ -47,6 +47,8 @@ static const struct pci_device_id ca91cx42_ids[] = {
        { },
 };
 
+MODULE_DEVICE_TABLE(pci, ca91cx42_ids);
+
 static struct pci_driver ca91cx42_driver = {
        .name = driver_name,
        .id_table = ca91cx42_ids,
@@ -69,7 +71,7 @@ static u32 ca91cx42_LM_irqhandler(struct ca91cx42_driver *bridge, u32 stat)
        for (i = 0; i < 4; i++) {
                if (stat & CA91CX42_LINT_LM[i]) {
                        /* We only enable interrupts if the callback is set */
-                       bridge->lm_callback[i](i);
+                       bridge->lm_callback[i](bridge->lm_data[i]);
                        serviced |= CA91CX42_LINT_LM[i];
                }
        }
@@ -1410,7 +1412,7 @@ static int ca91cx42_lm_get(struct vme_lm_resource *lm,
  * Callback will be passed the monitor triggered.
  */
 static int ca91cx42_lm_attach(struct vme_lm_resource *lm, int monitor,
-       void (*callback)(int))
+       void (*callback)(void *), void *data)
 {
        u32 lm_ctl, tmp;
        struct ca91cx42_driver *bridge;
@@ -1438,6 +1440,7 @@ static int ca91cx42_lm_attach(struct vme_lm_resource *lm, int monitor,
 
        /* Attach callback */
        bridge->lm_callback[monitor] = callback;
+       bridge->lm_data[monitor] = data;
 
        /* Enable Location Monitor interrupt */
        tmp = ioread32(bridge->base + LINT_EN);
@@ -1477,6 +1480,7 @@ static int ca91cx42_lm_detach(struct vme_lm_resource *lm, int monitor)
 
        /* Detach callback */
        bridge->lm_callback[monitor] = NULL;
+       bridge->lm_data[monitor] = NULL;
 
        /* If all location monitors disabled, disable global Location Monitor */
        if ((tmp & (CA91CX42_LINT_LM0 | CA91CX42_LINT_LM1 | CA91CX42_LINT_LM2 |
index d54119e59d5513fdd81edd682becac5d071130ae..f35c9f5348a9d64d400a52b09e1225c3328b5a91 100644 (file)
@@ -43,7 +43,8 @@ struct ca91cx42_driver {
        wait_queue_head_t dma_queue;
        wait_queue_head_t iack_queue;
        wait_queue_head_t mbox_queue;
-       void (*lm_callback[4])(int);    /* Called in interrupt handler */
+       void (*lm_callback[4])(void *); /* Called in interrupt handler */
+       void *lm_data[4];
        void *crcsr_kernel;
        dma_addr_t crcsr_bus;
        struct mutex vme_rmw;           /* Only one RMW cycle at a time */
diff --git a/drivers/vme/bridges/vme_fake.c b/drivers/vme/bridges/vme_fake.c
new file mode 100644 (file)
index 0000000..7ef298b
--- /dev/null
@@ -0,0 +1,1299 @@
+/*
+ * Fake VME bridge support.
+ *
+ * This drive provides a fake VME bridge chip, this enables debugging of the
+ * VME framework in the absence of a VME system.
+ *
+ * This driver has to do a number of things in software that would be driven
+ * by hardware if it was available, it will also result in extra overhead at
+ * times when compared with driving actual hardware.
+ *
+ * Author: Martyn Welch <martyn@welches.me.uk>
+ * Copyright (c) 2014 Martyn Welch
+ *
+ * Based on vme_tsi148.c:
+ *
+ * Author: Martyn Welch <martyn.welch@ge.com>
+ * Copyright 2008 GE Intelligent Platforms Embedded Systems, Inc.
+ *
+ * Based on work by Tom Armistead and Ajit Prem
+ * Copyright 2004 Motorola Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+#include <linux/vme.h>
+
+#include "../vme_bridge.h"
+
+/*
+ *  Define the number of each that the fake driver supports.
+ */
+#define FAKE_MAX_MASTER                8       /* Max Master Windows */
+#define FAKE_MAX_SLAVE         8       /* Max Slave Windows */
+
+/* Structures to hold information normally held in device registers */
+struct fake_slave_window {
+       int enabled;
+       unsigned long long vme_base;
+       unsigned long long size;
+       dma_addr_t buf_base;
+       u32 aspace;
+       u32 cycle;
+};
+
+struct fake_master_window {
+       int enabled;
+       unsigned long long vme_base;
+       unsigned long long size;
+       u32 aspace;
+       u32 cycle;
+       u32 dwidth;
+};
+
+/* Structure used to hold driver specific information */
+struct fake_driver {
+       struct vme_bridge *parent;
+       struct fake_slave_window slaves[FAKE_MAX_SLAVE];
+       struct fake_master_window masters[FAKE_MAX_MASTER];
+       u32 lm_enabled;
+       unsigned long long lm_base;
+       u32 lm_aspace;
+       u32 lm_cycle;
+       void (*lm_callback[4])(void *);
+       void *lm_data[4];
+       struct tasklet_struct int_tasklet;
+       int int_level;
+       int int_statid;
+       void *crcsr_kernel;
+       dma_addr_t crcsr_bus;
+       /* Only one VME interrupt can be generated at a time, provide locking */
+       struct mutex vme_int;
+};
+
+/* Module parameter */
+static int geoid;
+
+static const char driver_name[] = "vme_fake";
+
+static struct vme_bridge *exit_pointer;
+
+static struct device *vme_root;
+
+/*
+ * Calling VME bus interrupt callback if provided.
+ */
+static void fake_VIRQ_tasklet(unsigned long data)
+{
+       struct vme_bridge *fake_bridge;
+       struct fake_driver *bridge;
+
+       fake_bridge = (struct vme_bridge *) data;
+       bridge = fake_bridge->driver_priv;
+
+       vme_irq_handler(fake_bridge, bridge->int_level, bridge->int_statid);
+}
+
+/*
+ * Configure VME interrupt
+ */
+static void fake_irq_set(struct vme_bridge *fake_bridge, int level,
+               int state, int sync)
+{
+       /* Nothing to do */
+}
+
+/*
+ * Generate a VME bus interrupt at the requested level & vector. Wait for
+ * interrupt to be acked.
+ */
+static int fake_irq_generate(struct vme_bridge *fake_bridge, int level,
+               int statid)
+{
+       struct fake_driver *bridge;
+
+       bridge = fake_bridge->driver_priv;
+
+       mutex_lock(&bridge->vme_int);
+
+       bridge->int_level = level;
+
+       bridge->int_statid = statid;
+
+       /*
+        * Schedule tasklet to run VME handler to emulate normal VME interrupt
+        * handler behaviour.
+        */
+       tasklet_schedule(&bridge->int_tasklet);
+
+       mutex_unlock(&bridge->vme_int);
+
+       return 0;
+}
+
+/*
+ * Initialize a slave window with the requested attributes.
+ */
+static int fake_slave_set(struct vme_slave_resource *image, int enabled,
+               unsigned long long vme_base, unsigned long long size,
+               dma_addr_t buf_base, u32 aspace, u32 cycle)
+{
+       unsigned int i, granularity = 0;
+       unsigned long long vme_bound;
+       struct vme_bridge *fake_bridge;
+       struct fake_driver *bridge;
+
+       fake_bridge = image->parent;
+       bridge = fake_bridge->driver_priv;
+
+       i = image->number;
+
+       switch (aspace) {
+       case VME_A16:
+               granularity = 0x10;
+               break;
+       case VME_A24:
+               granularity = 0x1000;
+               break;
+       case VME_A32:
+               granularity = 0x10000;
+               break;
+       case VME_A64:
+               granularity = 0x10000;
+               break;
+       case VME_CRCSR:
+       case VME_USER1:
+       case VME_USER2:
+       case VME_USER3:
+       case VME_USER4:
+       default:
+               pr_err("Invalid address space\n");
+               return -EINVAL;
+       }
+
+       /*
+        * Bound address is a valid address for the window, adjust
+        * accordingly
+        */
+       vme_bound = vme_base + size - granularity;
+
+       if (vme_base & (granularity - 1)) {
+               pr_err("Invalid VME base alignment\n");
+               return -EINVAL;
+       }
+       if (vme_bound & (granularity - 1)) {
+               pr_err("Invalid VME bound alignment\n");
+               return -EINVAL;
+       }
+
+       mutex_lock(&image->mtx);
+
+       bridge->slaves[i].enabled = enabled;
+       bridge->slaves[i].vme_base = vme_base;
+       bridge->slaves[i].size = size;
+       bridge->slaves[i].buf_base = buf_base;
+       bridge->slaves[i].aspace = aspace;
+       bridge->slaves[i].cycle = cycle;
+
+       mutex_unlock(&image->mtx);
+
+       return 0;
+}
+
+/*
+ * Get slave window configuration.
+ */
+static int fake_slave_get(struct vme_slave_resource *image, int *enabled,
+               unsigned long long *vme_base, unsigned long long *size,
+               dma_addr_t *buf_base, u32 *aspace, u32 *cycle)
+{
+       unsigned int i;
+       struct fake_driver *bridge;
+
+       bridge = image->parent->driver_priv;
+
+       i = image->number;
+
+       mutex_lock(&image->mtx);
+
+       *enabled = bridge->slaves[i].enabled;
+       *vme_base = bridge->slaves[i].vme_base;
+       *size = bridge->slaves[i].size;
+       *buf_base = bridge->slaves[i].buf_base;
+       *aspace = bridge->slaves[i].aspace;
+       *cycle = bridge->slaves[i].cycle;
+
+       mutex_unlock(&image->mtx);
+
+       return 0;
+}
+
+/*
+ * Set the attributes of an outbound window.
+ */
+static int fake_master_set(struct vme_master_resource *image, int enabled,
+               unsigned long long vme_base, unsigned long long size,
+               u32 aspace, u32 cycle, u32 dwidth)
+{
+       int retval = 0;
+       unsigned int i;
+       struct vme_bridge *fake_bridge;
+       struct fake_driver *bridge;
+
+       fake_bridge = image->parent;
+
+       bridge = fake_bridge->driver_priv;
+
+       /* Verify input data */
+       if (vme_base & 0xFFFF) {
+               pr_err("Invalid VME Window alignment\n");
+               retval = -EINVAL;
+               goto err_window;
+       }
+
+       if (size & 0xFFFF) {
+               spin_unlock(&image->lock);
+               pr_err("Invalid size alignment\n");
+               retval = -EINVAL;
+               goto err_window;
+       }
+
+       if ((size == 0) && (enabled != 0)) {
+               pr_err("Size must be non-zero for enabled windows\n");
+               retval = -EINVAL;
+               goto err_window;
+       }
+
+       /* Setup data width */
+       switch (dwidth) {
+       case VME_D8:
+       case VME_D16:
+       case VME_D32:
+               break;
+       default:
+               spin_unlock(&image->lock);
+               pr_err("Invalid data width\n");
+               retval = -EINVAL;
+               goto err_dwidth;
+       }
+
+       /* Setup address space */
+       switch (aspace) {
+       case VME_A16:
+       case VME_A24:
+       case VME_A32:
+       case VME_A64:
+       case VME_CRCSR:
+       case VME_USER1:
+       case VME_USER2:
+       case VME_USER3:
+       case VME_USER4:
+               break;
+       default:
+               spin_unlock(&image->lock);
+               pr_err("Invalid address space\n");
+               retval = -EINVAL;
+               goto err_aspace;
+       }
+
+       spin_lock(&image->lock);
+
+       i = image->number;
+
+       bridge->masters[i].enabled = enabled;
+       bridge->masters[i].vme_base = vme_base;
+       bridge->masters[i].size = size;
+       bridge->masters[i].aspace = aspace;
+       bridge->masters[i].cycle = cycle;
+       bridge->masters[i].dwidth = dwidth;
+
+       spin_unlock(&image->lock);
+
+       return 0;
+
+err_aspace:
+err_dwidth:
+err_window:
+       return retval;
+
+}
+
+/*
+ * Set the attributes of an outbound window.
+ */
+static int __fake_master_get(struct vme_master_resource *image, int *enabled,
+               unsigned long long *vme_base, unsigned long long *size,
+               u32 *aspace, u32 *cycle, u32 *dwidth)
+{
+       unsigned int i;
+       struct fake_driver *bridge;
+
+       bridge = image->parent->driver_priv;
+
+       i = image->number;
+
+       *enabled = bridge->masters[i].enabled;
+       *vme_base = bridge->masters[i].vme_base;
+       *size = bridge->masters[i].size;
+       *aspace = bridge->masters[i].aspace;
+       *cycle = bridge->masters[i].cycle;
+       *dwidth = bridge->masters[i].dwidth;
+
+       return 0;
+}
+
+
+static int fake_master_get(struct vme_master_resource *image, int *enabled,
+               unsigned long long *vme_base, unsigned long long *size,
+               u32 *aspace, u32 *cycle, u32 *dwidth)
+{
+       int retval;
+
+       spin_lock(&image->lock);
+
+       retval = __fake_master_get(image, enabled, vme_base, size, aspace,
+                       cycle, dwidth);
+
+       spin_unlock(&image->lock);
+
+       return retval;
+}
+
+
+void fake_lm_check(struct fake_driver *bridge, unsigned long long addr,
+               u32 aspace, u32 cycle)
+{
+       struct vme_bridge *fake_bridge;
+       unsigned long long lm_base;
+       u32 lm_aspace, lm_cycle;
+       int i;
+       struct vme_lm_resource *lm;
+       struct list_head *pos = NULL, *n;
+
+       /* Get vme_bridge */
+       fake_bridge = bridge->parent;
+
+       /* Loop through each location monitor resource */
+       list_for_each_safe(pos, n, &fake_bridge->lm_resources) {
+               lm = list_entry(pos, struct vme_lm_resource, list);
+
+               /* If disabled, we're done */
+               if (bridge->lm_enabled == 0)
+                       return;
+
+               lm_base = bridge->lm_base;
+               lm_aspace = bridge->lm_aspace;
+               lm_cycle = bridge->lm_cycle;
+
+               /* First make sure that the cycle and address space match */
+               if ((lm_aspace == aspace) && (lm_cycle == cycle)) {
+                       for (i = 0; i < lm->monitors; i++) {
+                               /* Each location monitor covers 8 bytes */
+                               if (((lm_base + (8 * i)) <= addr) &&
+                                   ((lm_base + (8 * i) + 8) > addr)) {
+                                       if (bridge->lm_callback[i] != NULL)
+                                               bridge->lm_callback[i](
+                                                       bridge->lm_data[i]);
+                               }
+                       }
+               }
+       }
+}
+
+static u8 fake_vmeread8(struct fake_driver *bridge, unsigned long long addr,
+               u32 aspace, u32 cycle)
+{
+       u8 retval = 0xff;
+       int i;
+       unsigned long long start, end, offset;
+       u8 *loc;
+
+       for (i = 0; i < FAKE_MAX_SLAVE; i++) {
+               start = bridge->slaves[i].vme_base;
+               end = bridge->slaves[i].vme_base + bridge->slaves[i].size;
+
+               if (aspace != bridge->slaves[i].aspace)
+                       continue;
+
+               if (cycle != bridge->slaves[i].cycle)
+                       continue;
+
+               if ((addr >= start) && (addr < end)) {
+                       offset = addr - bridge->slaves[i].vme_base;
+                       loc = (u8 *)((void *)bridge->slaves[i].buf_base + offset);
+                       retval = *loc;
+
+                       break;
+               }
+       }
+
+       fake_lm_check(bridge, addr, aspace, cycle);
+
+       return retval;
+}
+
+static u16 fake_vmeread16(struct fake_driver *bridge, unsigned long long addr,
+               u32 aspace, u32 cycle)
+{
+       u16 retval = 0xffff;
+       int i;
+       unsigned long long start, end, offset;
+       u16 *loc;
+
+       for (i = 0; i < FAKE_MAX_SLAVE; i++) {
+               if (aspace != bridge->slaves[i].aspace)
+                       continue;
+
+               if (cycle != bridge->slaves[i].cycle)
+                       continue;
+
+               start = bridge->slaves[i].vme_base;
+               end = bridge->slaves[i].vme_base + bridge->slaves[i].size;
+
+               if ((addr >= start) && ((addr + 1) < end)) {
+                       offset = addr - bridge->slaves[i].vme_base;
+                       loc = (u16 *)((void *)bridge->slaves[i].buf_base + offset);
+                       retval = *loc;
+
+                       break;
+               }
+       }
+
+       fake_lm_check(bridge, addr, aspace, cycle);
+
+       return retval;
+}
+
+static u32 fake_vmeread32(struct fake_driver *bridge, unsigned long long addr,
+               u32 aspace, u32 cycle)
+{
+       u32 retval = 0xffffffff;
+       int i;
+       unsigned long long start, end, offset;
+       u32 *loc;
+
+       for (i = 0; i < FAKE_MAX_SLAVE; i++) {
+               if (aspace != bridge->slaves[i].aspace)
+                       continue;
+
+               if (cycle != bridge->slaves[i].cycle)
+                       continue;
+
+               start = bridge->slaves[i].vme_base;
+               end = bridge->slaves[i].vme_base + bridge->slaves[i].size;
+
+               if ((addr >= start) && ((addr + 3) < end)) {
+                       offset = addr - bridge->slaves[i].vme_base;
+                       loc = (u32 *)((void *)bridge->slaves[i].buf_base + offset);
+                       retval = *loc;
+
+                       break;
+               }
+       }
+
+       fake_lm_check(bridge, addr, aspace, cycle);
+
+       return retval;
+}
+
+static ssize_t fake_master_read(struct vme_master_resource *image, void *buf,
+               size_t count, loff_t offset)
+{
+       int retval;
+       u32 aspace, cycle, dwidth;
+       struct vme_bridge *fake_bridge;
+       struct fake_driver *priv;
+       int i;
+       unsigned long long addr;
+       unsigned int done = 0;
+       unsigned int count32;
+
+       fake_bridge = image->parent;
+
+       priv = fake_bridge->driver_priv;
+
+       i = image->number;
+
+       addr = (unsigned long long)priv->masters[i].vme_base + offset;
+       aspace = priv->masters[i].aspace;
+       cycle = priv->masters[i].cycle;
+       dwidth = priv->masters[i].dwidth;
+
+       spin_lock(&image->lock);
+
+       /* The following code handles VME address alignment. We cannot use
+        * memcpy_xxx here because it may cut data transfers in to 8-bit
+        * cycles when D16 or D32 cycles are required on the VME bus.
+        * On the other hand, the bridge itself assures that the maximum data
+        * cycle configured for the transfer is used and splits it
+        * automatically for non-aligned addresses, so we don't want the
+        * overhead of needlessly forcing small transfers for the entire cycle.
+        */
+       if (addr & 0x1) {
+               *(u8 *)buf = fake_vmeread8(priv, addr, aspace, cycle);
+               done += 1;
+               if (done == count)
+                       goto out;
+       }
+       if ((dwidth == VME_D16) || (dwidth == VME_D32)) {
+               if ((addr + done) & 0x2) {
+                       if ((count - done) < 2) {
+                               *(u8 *)(buf + done) = fake_vmeread8(priv,
+                                               addr + done, aspace, cycle);
+                               done += 1;
+                               goto out;
+                       } else {
+                               *(u16 *)(buf + done) = fake_vmeread16(priv,
+                                               addr + done, aspace, cycle);
+                               done += 2;
+                       }
+               }
+       }
+
+       if (dwidth == VME_D32) {
+               count32 = (count - done) & ~0x3;
+               while (done < count32) {
+                       *(u32 *)(buf + done) = fake_vmeread32(priv, addr + done,
+                                       aspace, cycle);
+                       done += 4;
+               }
+       } else if (dwidth == VME_D16) {
+               count32 = (count - done) & ~0x3;
+               while (done < count32) {
+                       *(u16 *)(buf + done) = fake_vmeread16(priv, addr + done,
+                                       aspace, cycle);
+                       done += 2;
+               }
+       } else if (dwidth == VME_D8) {
+               count32 = (count - done);
+               while (done < count32) {
+                       *(u8 *)(buf + done) = fake_vmeread8(priv, addr + done,
+                                       aspace, cycle);
+                       done += 1;
+               }
+
+       }
+
+       if ((dwidth == VME_D16) || (dwidth == VME_D32)) {
+               if ((count - done) & 0x2) {
+                       *(u16 *)(buf + done) = fake_vmeread16(priv, addr + done,
+                                       aspace, cycle);
+                       done += 2;
+               }
+       }
+       if ((count - done) & 0x1) {
+               *(u8 *)(buf + done) = fake_vmeread8(priv, addr + done, aspace,
+                               cycle);
+               done += 1;
+       }
+
+out:
+       retval = count;
+
+       spin_unlock(&image->lock);
+
+       return retval;
+}
+
+void fake_vmewrite8(struct fake_driver *bridge, u8 *buf,
+                unsigned long long addr, u32 aspace, u32 cycle)
+{
+       int i;
+       unsigned long long start, end, offset;
+       u8 *loc;
+
+       for (i = 0; i < FAKE_MAX_SLAVE; i++) {
+               if (aspace != bridge->slaves[i].aspace)
+                       continue;
+
+               if (cycle != bridge->slaves[i].cycle)
+                       continue;
+
+               start = bridge->slaves[i].vme_base;
+               end = bridge->slaves[i].vme_base + bridge->slaves[i].size;
+
+               if ((addr >= start) && (addr < end)) {
+                       offset = addr - bridge->slaves[i].vme_base;
+                       loc = (u8 *)((void *)bridge->slaves[i].buf_base + offset);
+                       *loc = *buf;
+
+                       break;
+               }
+       }
+
+       fake_lm_check(bridge, addr, aspace, cycle);
+
+}
+
+void fake_vmewrite16(struct fake_driver *bridge, u16 *buf,
+               unsigned long long addr, u32 aspace, u32 cycle)
+{
+       int i;
+       unsigned long long start, end, offset;
+       u16 *loc;
+
+       for (i = 0; i < FAKE_MAX_SLAVE; i++) {
+               if (aspace != bridge->slaves[i].aspace)
+                       continue;
+
+               if (cycle != bridge->slaves[i].cycle)
+                       continue;
+
+               start = bridge->slaves[i].vme_base;
+               end = bridge->slaves[i].vme_base + bridge->slaves[i].size;
+
+               if ((addr >= start) && ((addr + 1) < end)) {
+                       offset = addr - bridge->slaves[i].vme_base;
+                       loc = (u16 *)((void *)bridge->slaves[i].buf_base + offset);
+                       *loc = *buf;
+
+                       break;
+               }
+       }
+
+       fake_lm_check(bridge, addr, aspace, cycle);
+
+}
+
+void fake_vmewrite32(struct fake_driver *bridge, u32 *buf,
+               unsigned long long addr, u32 aspace, u32 cycle)
+{
+       int i;
+       unsigned long long start, end, offset;
+       u32 *loc;
+
+       for (i = 0; i < FAKE_MAX_SLAVE; i++) {
+               if (aspace != bridge->slaves[i].aspace)
+                       continue;
+
+               if (cycle != bridge->slaves[i].cycle)
+                       continue;
+
+               start = bridge->slaves[i].vme_base;
+               end = bridge->slaves[i].vme_base + bridge->slaves[i].size;
+
+               if ((addr >= start) && ((addr + 3) < end)) {
+                       offset = addr - bridge->slaves[i].vme_base;
+                       loc = (u32 *)((void *)bridge->slaves[i].buf_base + offset);
+                       *loc = *buf;
+
+                       break;
+               }
+       }
+
+       fake_lm_check(bridge, addr, aspace, cycle);
+
+}
+
+static ssize_t fake_master_write(struct vme_master_resource *image, void *buf,
+               size_t count, loff_t offset)
+{
+       int retval = 0;
+       u32 aspace, cycle, dwidth;
+       unsigned long long addr;
+       int i;
+       unsigned int done = 0;
+       unsigned int count32;
+
+       struct vme_bridge *fake_bridge;
+       struct fake_driver *bridge;
+
+       fake_bridge = image->parent;
+
+       bridge = fake_bridge->driver_priv;
+
+       i = image->number;
+
+       addr = bridge->masters[i].vme_base + offset;
+       aspace = bridge->masters[i].aspace;
+       cycle = bridge->masters[i].cycle;
+       dwidth = bridge->masters[i].dwidth;
+
+       spin_lock(&image->lock);
+
+       /* Here we apply for the same strategy we do in master_read
+        * function in order to assure the correct cycles.
+        */
+       if (addr & 0x1) {
+               fake_vmewrite8(bridge, (u8 *)buf, addr, aspace, cycle);
+               done += 1;
+               if (done == count)
+                       goto out;
+       }
+
+       if ((dwidth == VME_D16) || (dwidth == VME_D32)) {
+               if ((addr + done) & 0x2) {
+                       if ((count - done) < 2) {
+                               fake_vmewrite8(bridge, (u8 *)(buf + done),
+                                               addr + done, aspace, cycle);
+                               done += 1;
+                               goto out;
+                       } else {
+                               fake_vmewrite16(bridge, (u16 *)(buf + done),
+                                               addr + done, aspace, cycle);
+                               done += 2;
+                       }
+               }
+       }
+
+       if (dwidth == VME_D32) {
+               count32 = (count - done) & ~0x3;
+               while (done < count32) {
+                       fake_vmewrite32(bridge, (u32 *)(buf + done),
+                                       addr + done, aspace, cycle);
+                       done += 4;
+               }
+       } else if (dwidth == VME_D16) {
+               count32 = (count - done) & ~0x3;
+               while (done < count32) {
+                       fake_vmewrite16(bridge, (u16 *)(buf + done),
+                                       addr + done, aspace, cycle);
+                       done += 2;
+               }
+       } else if (dwidth == VME_D8) {
+               count32 = (count - done);
+               while (done < count32) {
+                       fake_vmewrite8(bridge, (u8 *)(buf + done), addr + done,
+                                       aspace, cycle);
+                       done += 1;
+               }
+
+       }
+
+       if ((dwidth == VME_D16) || (dwidth == VME_D32)) {
+               if ((count - done) & 0x2) {
+                       fake_vmewrite16(bridge, (u16 *)(buf + done),
+                                       addr + done, aspace, cycle);
+                       done += 2;
+               }
+       }
+
+       if ((count - done) & 0x1) {
+               fake_vmewrite8(bridge, (u8 *)(buf + done), addr + done, aspace,
+                               cycle);
+               done += 1;
+       }
+
+out:
+       retval = count;
+
+       spin_unlock(&image->lock);
+
+       return retval;
+}
+
+/*
+ * Perform an RMW cycle on the VME bus.
+ *
+ * Requires a previously configured master window, returns final value.
+ */
+static unsigned int fake_master_rmw(struct vme_master_resource *image,
+               unsigned int mask, unsigned int compare, unsigned int swap,
+               loff_t offset)
+{
+       u32 tmp, base;
+       u32 aspace, cycle;
+       int i;
+       struct fake_driver *bridge;
+
+       bridge = image->parent->driver_priv;
+
+       /* Find the PCI address that maps to the desired VME address */
+       i = image->number;
+
+       base = bridge->masters[i].vme_base;
+       aspace = bridge->masters[i].aspace;
+       cycle = bridge->masters[i].cycle;
+
+       /* Lock image */
+       spin_lock(&image->lock);
+
+       /* Read existing value */
+       tmp = fake_vmeread32(bridge, base + offset, aspace, cycle);
+
+       /* Perform check */
+       if ((tmp && mask) == (compare && mask)) {
+               tmp = tmp | (mask | swap);
+               tmp = tmp & (~mask | swap);
+
+               /* Write back */
+               fake_vmewrite32(bridge, &tmp, base + offset, aspace, cycle);
+       }
+
+       /* Unlock image */
+       spin_unlock(&image->lock);
+
+       return tmp;
+}
+
+/*
+ * All 4 location monitors reside at the same base - this is therefore a
+ * system wide configuration.
+ *
+ * This does not enable the LM monitor - that should be done when the first
+ * callback is attached and disabled when the last callback is removed.
+ */
+static int fake_lm_set(struct vme_lm_resource *lm, unsigned long long lm_base,
+               u32 aspace, u32 cycle)
+{
+       int i;
+       struct vme_bridge *fake_bridge;
+       struct fake_driver *bridge;
+
+       fake_bridge = lm->parent;
+
+       bridge = fake_bridge->driver_priv;
+
+       mutex_lock(&lm->mtx);
+
+       /* If we already have a callback attached, we can't move it! */
+       for (i = 0; i < lm->monitors; i++) {
+               if (bridge->lm_callback[i] != NULL) {
+                       mutex_unlock(&lm->mtx);
+                       pr_err("Location monitor callback attached, can't reset\n");
+                       return -EBUSY;
+               }
+       }
+
+       switch (aspace) {
+       case VME_A16:
+       case VME_A24:
+       case VME_A32:
+       case VME_A64:
+               break;
+       default:
+               mutex_unlock(&lm->mtx);
+               pr_err("Invalid address space\n");
+               return -EINVAL;
+       }
+
+       bridge->lm_base = lm_base;
+       bridge->lm_aspace = aspace;
+       bridge->lm_cycle = cycle;
+
+       mutex_unlock(&lm->mtx);
+
+       return 0;
+}
+
+/* Get configuration of the callback monitor and return whether it is enabled
+ * or disabled.
+ */
+static int fake_lm_get(struct vme_lm_resource *lm,
+               unsigned long long *lm_base, u32 *aspace, u32 *cycle)
+{
+       struct fake_driver *bridge;
+
+       bridge = lm->parent->driver_priv;
+
+       mutex_lock(&lm->mtx);
+
+       *lm_base = bridge->lm_base;
+       *aspace = bridge->lm_aspace;
+       *cycle = bridge->lm_cycle;
+
+       mutex_unlock(&lm->mtx);
+
+       return bridge->lm_enabled;
+}
+
+/*
+ * Attach a callback to a specific location monitor.
+ *
+ * Callback will be passed the monitor triggered.
+ */
+static int fake_lm_attach(struct vme_lm_resource *lm, int monitor,
+               void (*callback)(void *), void *data)
+{
+       struct vme_bridge *fake_bridge;
+       struct fake_driver *bridge;
+
+       fake_bridge = lm->parent;
+
+       bridge = fake_bridge->driver_priv;
+
+       mutex_lock(&lm->mtx);
+
+       /* Ensure that the location monitor is configured - need PGM or DATA */
+       if (bridge->lm_cycle == 0) {
+               mutex_unlock(&lm->mtx);
+               pr_err("Location monitor not properly configured\n");
+               return -EINVAL;
+       }
+
+       /* Check that a callback isn't already attached */
+       if (bridge->lm_callback[monitor] != NULL) {
+               mutex_unlock(&lm->mtx);
+               pr_err("Existing callback attached\n");
+               return -EBUSY;
+       }
+
+       /* Attach callback */
+       bridge->lm_callback[monitor] = callback;
+       bridge->lm_data[monitor] = data;
+
+       /* Ensure that global Location Monitor Enable set */
+       bridge->lm_enabled = 1;
+
+       mutex_unlock(&lm->mtx);
+
+       return 0;
+}
+
+/*
+ * Detach a callback function forn a specific location monitor.
+ */
+static int fake_lm_detach(struct vme_lm_resource *lm, int monitor)
+{
+       u32 tmp;
+       int i;
+       struct fake_driver *bridge;
+
+       bridge = lm->parent->driver_priv;
+
+       mutex_lock(&lm->mtx);
+
+       /* Detach callback */
+       bridge->lm_callback[monitor] = NULL;
+       bridge->lm_data[monitor] = NULL;
+
+       /* If all location monitors disabled, disable global Location Monitor */
+       tmp = 0;
+       for (i = 0; i < lm->monitors; i++) {
+               if (bridge->lm_callback[i] != NULL)
+                       tmp = 1;
+       }
+
+       if (tmp == 0)
+               bridge->lm_enabled = 0;
+
+       mutex_unlock(&lm->mtx);
+
+       return 0;
+}
+
+/*
+ * Determine Geographical Addressing
+ */
+static int fake_slot_get(struct vme_bridge *fake_bridge)
+{
+       return geoid;
+}
+
+static void *fake_alloc_consistent(struct device *parent, size_t size,
+               dma_addr_t *dma)
+{
+       void *alloc = kmalloc(size, GFP_KERNEL);
+
+       if (alloc != NULL)
+               *dma = (dma_addr_t)(unsigned long)alloc;
+
+       return alloc;
+}
+
+static void fake_free_consistent(struct device *parent, size_t size,
+               void *vaddr, dma_addr_t dma)
+{
+       kfree(vaddr);
+/*
+       dma_free_coherent(parent, size, vaddr, dma);
+*/
+}
+
+/*
+ * Configure CR/CSR space
+ *
+ * Access to the CR/CSR can be configured at power-up. The location of the
+ * CR/CSR registers in the CR/CSR address space is determined by the boards
+ * Geographic address.
+ *
+ * Each board has a 512kB window, with the highest 4kB being used for the
+ * boards registers, this means there is a fix length 508kB window which must
+ * be mapped onto PCI memory.
+ */
+static int fake_crcsr_init(struct vme_bridge *fake_bridge)
+{
+       u32 vstat;
+       struct fake_driver *bridge;
+
+       bridge = fake_bridge->driver_priv;
+
+       /* Allocate mem for CR/CSR image */
+       bridge->crcsr_kernel = kzalloc(VME_CRCSR_BUF_SIZE, GFP_KERNEL);
+       bridge->crcsr_bus = (dma_addr_t)bridge->crcsr_kernel;
+       if (bridge->crcsr_kernel == NULL)
+               return -ENOMEM;
+
+       vstat = fake_slot_get(fake_bridge);
+
+       pr_info("CR/CSR Offset: %d\n", vstat);
+
+       return 0;
+}
+
+static void fake_crcsr_exit(struct vme_bridge *fake_bridge)
+{
+       struct fake_driver *bridge;
+
+       bridge = fake_bridge->driver_priv;
+
+       kfree(bridge->crcsr_kernel);
+}
+
+
+static int __init fake_init(void)
+{
+       int retval, i;
+       struct list_head *pos = NULL, *n;
+       struct vme_bridge *fake_bridge;
+       struct fake_driver *fake_device;
+       struct vme_master_resource *master_image;
+       struct vme_slave_resource *slave_image;
+       struct vme_lm_resource *lm;
+
+       /* We need a fake parent device */
+       vme_root = __root_device_register("vme", THIS_MODULE);
+
+       /* If we want to support more than one bridge at some point, we need to
+        * dynamically allocate this so we get one per device.
+        */
+       fake_bridge = kzalloc(sizeof(struct vme_bridge), GFP_KERNEL);
+       if (fake_bridge == NULL) {
+               retval = -ENOMEM;
+               goto err_struct;
+       }
+
+       fake_device = kzalloc(sizeof(struct fake_driver), GFP_KERNEL);
+       if (fake_device == NULL) {
+               retval = -ENOMEM;
+               goto err_driver;
+       }
+
+       fake_bridge->driver_priv = fake_device;
+
+       fake_bridge->parent = vme_root;
+
+       fake_device->parent = fake_bridge;
+
+       /* Initialize wait queues & mutual exclusion flags */
+       mutex_init(&fake_device->vme_int);
+       mutex_init(&fake_bridge->irq_mtx);
+       tasklet_init(&fake_device->int_tasklet, fake_VIRQ_tasklet,
+                       (unsigned long) fake_bridge);
+
+       strcpy(fake_bridge->name, driver_name);
+
+       /* Add master windows to list */
+       INIT_LIST_HEAD(&fake_bridge->master_resources);
+       for (i = 0; i < FAKE_MAX_MASTER; i++) {
+               master_image = kmalloc(sizeof(struct vme_master_resource),
+                               GFP_KERNEL);
+               if (master_image == NULL) {
+                       retval = -ENOMEM;
+                       goto err_master;
+               }
+               master_image->parent = fake_bridge;
+               spin_lock_init(&master_image->lock);
+               master_image->locked = 0;
+               master_image->number = i;
+               master_image->address_attr = VME_A16 | VME_A24 | VME_A32 |
+                       VME_A64;
+               master_image->cycle_attr = VME_SCT | VME_BLT | VME_MBLT |
+                       VME_2eVME | VME_2eSST | VME_2eSSTB | VME_2eSST160 |
+                       VME_2eSST267 | VME_2eSST320 | VME_SUPER | VME_USER |
+                       VME_PROG | VME_DATA;
+               master_image->width_attr = VME_D16 | VME_D32;
+               memset(&master_image->bus_resource, 0,
+                               sizeof(struct resource));
+               master_image->kern_base  = NULL;
+               list_add_tail(&master_image->list,
+                               &fake_bridge->master_resources);
+       }
+
+       /* Add slave windows to list */
+       INIT_LIST_HEAD(&fake_bridge->slave_resources);
+       for (i = 0; i < FAKE_MAX_SLAVE; i++) {
+               slave_image = kmalloc(sizeof(struct vme_slave_resource),
+                               GFP_KERNEL);
+               if (slave_image == NULL) {
+                       retval = -ENOMEM;
+                       goto err_slave;
+               }
+               slave_image->parent = fake_bridge;
+               mutex_init(&slave_image->mtx);
+               slave_image->locked = 0;
+               slave_image->number = i;
+               slave_image->address_attr = VME_A16 | VME_A24 | VME_A32 |
+                       VME_A64 | VME_CRCSR | VME_USER1 | VME_USER2 |
+                       VME_USER3 | VME_USER4;
+               slave_image->cycle_attr = VME_SCT | VME_BLT | VME_MBLT |
+                       VME_2eVME | VME_2eSST | VME_2eSSTB | VME_2eSST160 |
+                       VME_2eSST267 | VME_2eSST320 | VME_SUPER | VME_USER |
+                       VME_PROG | VME_DATA;
+               list_add_tail(&slave_image->list,
+                               &fake_bridge->slave_resources);
+       }
+
+       /* Add location monitor to list */
+       INIT_LIST_HEAD(&fake_bridge->lm_resources);
+       lm = kmalloc(sizeof(struct vme_lm_resource), GFP_KERNEL);
+       if (lm == NULL) {
+               pr_err("Failed to allocate memory for location monitor resource structure\n");
+               retval = -ENOMEM;
+               goto err_lm;
+       }
+       lm->parent = fake_bridge;
+       mutex_init(&lm->mtx);
+       lm->locked = 0;
+       lm->number = 1;
+       lm->monitors = 4;
+       list_add_tail(&lm->list, &fake_bridge->lm_resources);
+
+       fake_bridge->slave_get = fake_slave_get;
+       fake_bridge->slave_set = fake_slave_set;
+       fake_bridge->master_get = fake_master_get;
+       fake_bridge->master_set = fake_master_set;
+       fake_bridge->master_read = fake_master_read;
+       fake_bridge->master_write = fake_master_write;
+       fake_bridge->master_rmw = fake_master_rmw;
+       fake_bridge->irq_set = fake_irq_set;
+       fake_bridge->irq_generate = fake_irq_generate;
+       fake_bridge->lm_set = fake_lm_set;
+       fake_bridge->lm_get = fake_lm_get;
+       fake_bridge->lm_attach = fake_lm_attach;
+       fake_bridge->lm_detach = fake_lm_detach;
+       fake_bridge->slot_get = fake_slot_get;
+       fake_bridge->alloc_consistent = fake_alloc_consistent;
+       fake_bridge->free_consistent = fake_free_consistent;
+
+       pr_info("Board is%s the VME system controller\n",
+                       (geoid == 1) ? "" : " not");
+
+       pr_info("VME geographical address is set to %d\n", geoid);
+
+       retval = fake_crcsr_init(fake_bridge);
+       if (retval) {
+               pr_err("CR/CSR configuration failed.\n");
+               goto err_crcsr;
+       }
+
+       retval = vme_register_bridge(fake_bridge);
+       if (retval != 0) {
+               pr_err("Chip Registration failed.\n");
+               goto err_reg;
+       }
+
+       exit_pointer = fake_bridge;
+
+       return 0;
+
+err_reg:
+       fake_crcsr_exit(fake_bridge);
+err_crcsr:
+err_lm:
+       /* resources are stored in link list */
+       list_for_each_safe(pos, n, &fake_bridge->lm_resources) {
+               lm = list_entry(pos, struct vme_lm_resource, list);
+               list_del(pos);
+               kfree(lm);
+       }
+err_slave:
+       /* resources are stored in link list */
+       list_for_each_safe(pos, n, &fake_bridge->slave_resources) {
+               slave_image = list_entry(pos, struct vme_slave_resource, list);
+               list_del(pos);
+               kfree(slave_image);
+       }
+err_master:
+       /* resources are stored in link list */
+       list_for_each_safe(pos, n, &fake_bridge->master_resources) {
+               master_image = list_entry(pos, struct vme_master_resource,
+                               list);
+               list_del(pos);
+               kfree(master_image);
+       }
+
+       kfree(fake_device);
+err_driver:
+       kfree(fake_bridge);
+err_struct:
+       return retval;
+
+}
+
+
+static void __exit fake_exit(void)
+{
+       struct list_head *pos = NULL;
+       struct list_head *tmplist;
+       struct vme_master_resource *master_image;
+       struct vme_slave_resource *slave_image;
+       int i;
+       struct vme_bridge *fake_bridge;
+       struct fake_driver *bridge;
+
+       fake_bridge = exit_pointer;
+
+       bridge = fake_bridge->driver_priv;
+
+       pr_debug("Driver is being unloaded.\n");
+
+       /*
+        *  Shutdown all inbound and outbound windows.
+        */
+       for (i = 0; i < FAKE_MAX_MASTER; i++)
+               bridge->masters[i].enabled = 0;
+
+       for (i = 0; i < FAKE_MAX_SLAVE; i++)
+               bridge->slaves[i].enabled = 0;
+
+       /*
+        *  Shutdown Location monitor.
+        */
+       bridge->lm_enabled = 0;
+
+       vme_unregister_bridge(fake_bridge);
+
+       fake_crcsr_exit(fake_bridge);
+       /* resources are stored in link list */
+       list_for_each_safe(pos, tmplist, &fake_bridge->slave_resources) {
+               slave_image = list_entry(pos, struct vme_slave_resource, list);
+               list_del(pos);
+               kfree(slave_image);
+       }
+
+       /* resources are stored in link list */
+       list_for_each_safe(pos, tmplist, &fake_bridge->master_resources) {
+               master_image = list_entry(pos, struct vme_master_resource,
+                               list);
+               list_del(pos);
+               kfree(master_image);
+       }
+
+       kfree(fake_bridge->driver_priv);
+
+       kfree(fake_bridge);
+
+       root_device_unregister(vme_root);
+}
+
+
+MODULE_PARM_DESC(geoid, "Set geographical addressing");
+module_param(geoid, int, 0);
+
+MODULE_DESCRIPTION("Fake VME bridge driver");
+MODULE_LICENSE("GPL");
+
+module_init(fake_init);
+module_exit(fake_exit);
index 4bc5d451ec6c001f446e1df444ab59c606fe116c..fc1b634b969a999c780e11caea23b3c84b08b8d0 100644 (file)
@@ -50,6 +50,8 @@ static const struct pci_device_id tsi148_ids[] = {
        { },
 };
 
+MODULE_DEVICE_TABLE(pci, tsi148_ids);
+
 static struct pci_driver tsi148_driver = {
        .name = driver_name,
        .id_table = tsi148_ids,
@@ -102,7 +104,7 @@ static u32 tsi148_LM_irqhandler(struct tsi148_driver *bridge, u32 stat)
        for (i = 0; i < 4; i++) {
                if (stat & TSI148_LCSR_INTS_LMS[i]) {
                        /* We only enable interrupts if the callback is set */
-                       bridge->lm_callback[i](i);
+                       bridge->lm_callback[i](bridge->lm_data[i]);
                        serviced |= TSI148_LCSR_INTC_LMC[i];
                }
        }
@@ -2047,7 +2049,7 @@ static int tsi148_lm_get(struct vme_lm_resource *lm,
  * Callback will be passed the monitor triggered.
  */
 static int tsi148_lm_attach(struct vme_lm_resource *lm, int monitor,
-       void (*callback)(int))
+       void (*callback)(void *), void *data)
 {
        u32 lm_ctl, tmp;
        struct vme_bridge *tsi148_bridge;
@@ -2077,6 +2079,7 @@ static int tsi148_lm_attach(struct vme_lm_resource *lm, int monitor,
 
        /* Attach callback */
        bridge->lm_callback[monitor] = callback;
+       bridge->lm_data[monitor] = data;
 
        /* Enable Location Monitor interrupt */
        tmp = ioread32be(bridge->base + TSI148_LCSR_INTEN);
@@ -2124,6 +2127,7 @@ static int tsi148_lm_detach(struct vme_lm_resource *lm, int monitor)
 
        /* Detach callback */
        bridge->lm_callback[monitor] = NULL;
+       bridge->lm_data[monitor] = NULL;
 
        /* If all location monitors disabled, disable global Location Monitor */
        if ((lm_en & (TSI148_LCSR_INTS_LM0S | TSI148_LCSR_INTS_LM1S |
index f5ed14382a8de69aaa7dd76525dd173d65a56ec9..0935d85d32ec2ad3a47a7f4085e05c497eed2229 100644 (file)
@@ -38,7 +38,8 @@ struct tsi148_driver {
        void __iomem *base;     /* Base Address of device registers */
        wait_queue_head_t dma_queue[2];
        wait_queue_head_t iack_queue;
-       void (*lm_callback[4])(int);    /* Called in interrupt handler */
+       void (*lm_callback[4])(void *); /* Called in interrupt handler */
+       void *lm_data[4];
        void *crcsr_kernel;
        dma_addr_t crcsr_bus;
        struct vme_master_resource *flush_image;
index 37ac0a58e59a8cd56013ebdb33ddb7fee643d3ba..15b64076bc26257abffd02a60de7b2fe4b22c4e0 100644 (file)
@@ -13,8 +13,8 @@
  * option) any later version.
  */
 
-#include <linux/module.h>
-#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/export.h>
 #include <linux/mm.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
@@ -39,7 +39,6 @@ static unsigned int vme_bus_numbers;
 static LIST_HEAD(vme_bus_list);
 static DEFINE_MUTEX(vme_buses_lock);
 
-static void __exit vme_exit(void);
 static int __init vme_init(void);
 
 static struct vme_dev *dev_to_vme_dev(struct device *dev)
@@ -1321,7 +1320,7 @@ int vme_lm_get(struct vme_resource *resource, unsigned long long *lm_base,
 EXPORT_SYMBOL(vme_lm_get);
 
 int vme_lm_attach(struct vme_resource *resource, int monitor,
-       void (*callback)(int))
+       void (*callback)(void *), void *data)
 {
        struct vme_bridge *bridge = find_bridge(resource);
        struct vme_lm_resource *lm;
@@ -1338,7 +1337,7 @@ int vme_lm_attach(struct vme_resource *resource, int monitor,
                return -EINVAL;
        }
 
-       return bridge->lm_attach(lm, monitor, callback);
+       return bridge->lm_attach(lm, monitor, callback, data);
 }
 EXPORT_SYMBOL(vme_lm_attach);
 
@@ -1622,25 +1621,10 @@ static int vme_bus_probe(struct device *dev)
        return retval;
 }
 
-static int vme_bus_remove(struct device *dev)
-{
-       int retval = -ENODEV;
-       struct vme_driver *driver;
-       struct vme_dev *vdev = dev_to_vme_dev(dev);
-
-       driver = dev->platform_data;
-
-       if (driver->remove != NULL)
-               retval = driver->remove(vdev);
-
-       return retval;
-}
-
 struct bus_type vme_bus_type = {
        .name = "vme",
        .match = vme_bus_match,
        .probe = vme_bus_probe,
-       .remove = vme_bus_remove,
 };
 EXPORT_SYMBOL(vme_bus_type);
 
@@ -1648,11 +1632,4 @@ static int __init vme_init(void)
 {
        return bus_register(&vme_bus_type);
 }
-
-static void __exit vme_exit(void)
-{
-       bus_unregister(&vme_bus_type);
-}
-
 subsys_initcall(vme_init);
-module_exit(vme_exit);
index cb8246fd97beb4dbeeae2649196b59481e3a2dc4..2662e916b96af86892ec71315cc660702ba852a3 100644 (file)
@@ -160,7 +160,8 @@ struct vme_bridge {
        int (*lm_set) (struct vme_lm_resource *, unsigned long long, u32, u32);
        int (*lm_get) (struct vme_lm_resource *, unsigned long long *, u32 *,
                u32 *);
-       int (*lm_attach) (struct vme_lm_resource *, int, void (*callback)(int));
+       int (*lm_attach)(struct vme_lm_resource *, int,
+                        void (*callback)(void *), void *);
        int (*lm_detach) (struct vme_lm_resource *, int);
 
        /* CR/CSR space functions */
index 581a300fd6cda40265c5bdde527ced6157c56e06..82611f197b0a06a741c67bc756b1ce82da4f1275 100644 (file)
@@ -66,7 +66,7 @@ struct w1_therm_family_data {
 
 /* return the address of the refcnt in the family data */
 #define THERM_REFCNT(family_data) \
-       (&((struct w1_therm_family_data*)family_data)->refcnt)
+       (&((struct w1_therm_family_data *)family_data)->refcnt)
 
 static int w1_therm_add_slave(struct w1_slave *sl)
 {
@@ -81,7 +81,8 @@ static int w1_therm_add_slave(struct w1_slave *sl)
 static void w1_therm_remove_slave(struct w1_slave *sl)
 {
        int refcnt = atomic_sub_return(1, THERM_REFCNT(sl->family_data));
-       while(refcnt) {
+
+       while (refcnt) {
                msleep(1000);
                refcnt = atomic_read(THERM_REFCNT(sl->family_data));
        }
@@ -151,8 +152,7 @@ static struct w1_family w1_therm_family_DS1825 = {
        .fops = &w1_therm_fops,
 };
 
-struct w1_therm_family_converter
-{
+struct w1_therm_family_converter {
        u8                      broken;
        u16                     reserved;
        struct w1_family        *f;
@@ -293,7 +293,7 @@ static inline int w1_DS18B20_precision(struct device *device, int val)
        uint8_t precision_bits;
        uint8_t mask = 0x60;
 
-       if(val > 12 || val < 9) {
+       if (val > 12 || val < 9) {
                pr_warn("Unsupported precision\n");
                return -1;
        }
@@ -336,7 +336,8 @@ static inline int w1_DS18B20_precision(struct device *device, int val)
 
                        /* read values to only alter precision bits */
                        w1_write_8(dev, W1_READ_SCRATCHPAD);
-                       if ((count = w1_read_block(dev, rom, 9)) != 9)
+                       count = w1_read_block(dev, rom, 9);
+                       if (count != 9)
                                dev_warn(device, "w1_read_block() returned %u instead of 9.\n", count);
 
                        crc = w1_calc_crc8(rom, 8);
@@ -366,6 +367,7 @@ post_unlock:
 static inline int w1_DS18B20_convert_temp(u8 rom[9])
 {
        s16 t = le16_to_cpup((__le16 *)rom);
+
        return t*1000/16;
 }
 
@@ -415,7 +417,7 @@ static ssize_t w1_slave_store(struct device *device,
        for (i = 0; i < ARRAY_SIZE(w1_therm_families); ++i) {
                if (w1_therm_families[i].f->fid == sl->family->fid) {
                        /* zero value indicates to write current configuration to eeprom */
-                       if (0 == val)
+                       if (val == 0)
                                ret = w1_therm_families[i].eeprom(device);
                        else
                                ret = w1_therm_families[i].precision(device, val);
@@ -439,8 +441,7 @@ static ssize_t w1_slave_show(struct device *device,
        if (ret != 0)
                goto post_unlock;
 
-       if(!sl->family_data)
-       {
+       if (!sl->family_data) {
                ret = -ENODEV;
                goto pre_unlock;
        }
@@ -495,7 +496,8 @@ static ssize_t w1_slave_show(struct device *device,
                        if (!w1_reset_select_slave(sl)) {
 
                                w1_write_8(dev, W1_READ_SCRATCHPAD);
-                               if ((count = w1_read_block(dev, rom, 9)) != 9) {
+                               count = w1_read_block(dev, rom, 9);
+                               if (count != 9) {
                                        dev_warn(device, "w1_read_block() "
                                                "returned %u instead of 9.\n",
                                                count);
index bb34362e930a2a1b3a6723e2b1e1274258fc98cc..e213c678bbfe0cee97afe47a6f082ca4b7ed9f2f 100644 (file)
@@ -53,8 +53,8 @@ int w1_max_slave_ttl = 10;
 module_param_named(timeout, w1_timeout, int, 0);
 MODULE_PARM_DESC(timeout, "time in seconds between automatic slave searches");
 module_param_named(timeout_us, w1_timeout_us, int, 0);
-MODULE_PARM_DESC(timeout, "time in microseconds between automatic slave"
-                         " searches");
+MODULE_PARM_DESC(timeout_us,
+                "time in microseconds between automatic slave searches");
 /* A search stops when w1_max_slave_count devices have been found in that
  * search.  The next search will start over and detect the same set of devices
  * on a static 1-wire bus.  Memory is not allocated based on this number, just
index 385d62e64abb00218d5f52f32bd1875dde5b7b43..2a5982c37dfb660d344777c79dcde044ca304f1c 100644 (file)
@@ -232,8 +232,9 @@ struct coresight_ops_source {
        int (*cpu_id)(struct coresight_device *csdev);
        int (*trace_id)(struct coresight_device *csdev);
        int (*enable)(struct coresight_device *csdev,
-                     struct perf_event_attr *attr,  u32 mode);
-       void (*disable)(struct coresight_device *csdev);
+                     struct perf_event *event,  u32 mode);
+       void (*disable)(struct coresight_device *csdev,
+                       struct perf_event *event);
 };
 
 struct coresight_ops {
index 5df444b1ac1845787a3bc77f4cccd0365838b1a4..4068d0bae8e5118590bde16fa91a0f658d99f87b 100644 (file)
@@ -674,6 +674,11 @@ enum hv_signal_policy {
        HV_SIGNAL_POLICY_EXPLICIT,
 };
 
+enum hv_numa_policy {
+       HV_BALANCED = 0,
+       HV_LOCALIZED,
+};
+
 enum vmbus_device_type {
        HV_IDE = 0,
        HV_SCSI,
@@ -850,6 +855,43 @@ struct vmbus_channel {
         * ring lock to preserve the current behavior.
         */
        bool acquire_ring_lock;
+       /*
+        * For performance critical channels (storage, networking
+        * etc,), Hyper-V has a mechanism to enhance the throughput
+        * at the expense of latency:
+        * When the host is to be signaled, we just set a bit in a shared page
+        * and this bit will be inspected by the hypervisor within a certain
+        * window and if the bit is set, the host will be signaled. The window
+        * of time is the monitor latency - currently around 100 usecs. This
+        * mechanism improves throughput by:
+        *
+        * A) Making the host more efficient - each time it wakes up,
+        *    potentially it will process morev number of packets. The
+        *    monitor latency allows a batch to build up.
+        * B) By deferring the hypercall to signal, we will also minimize
+        *    the interrupts.
+        *
+        * Clearly, these optimizations improve throughput at the expense of
+        * latency. Furthermore, since the channel is shared for both
+        * control and data messages, control messages currently suffer
+        * unnecessary latency adversley impacting performance and boot
+        * time. To fix this issue, permit tagging the channel as being
+        * in "low latency" mode. In this mode, we will bypass the monitor
+        * mechanism.
+        */
+       bool low_latency;
+
+       /*
+        * NUMA distribution policy:
+        * We support teo policies:
+        * 1) Balanced: Here all performance critical channels are
+        *    distributed evenly amongst all the NUMA nodes.
+        *    This policy will be the default policy.
+        * 2) Localized: All channels of a given instance of a
+        *    performance critical service will be assigned CPUs
+        *    within a selected NUMA node.
+        */
+       enum hv_numa_policy affinity_policy;
 
 };
 
@@ -870,6 +912,12 @@ static inline void set_channel_signal_state(struct vmbus_channel *c,
        c->signal_policy = policy;
 }
 
+static inline void set_channel_affinity_state(struct vmbus_channel *c,
+                                             enum hv_numa_policy policy)
+{
+       c->affinity_policy = policy;
+}
+
 static inline void set_channel_read_state(struct vmbus_channel *c, bool state)
 {
        c->batched_reading = state;
@@ -891,6 +939,16 @@ static inline void set_channel_pending_send_size(struct vmbus_channel *c,
        c->outbound.ring_buffer->pending_send_sz = size;
 }
 
+static inline void set_low_latency_mode(struct vmbus_channel *c)
+{
+       c->low_latency = true;
+}
+
+static inline void clear_low_latency_mode(struct vmbus_channel *c)
+{
+       c->low_latency = false;
+}
+
 void vmbus_onmessage(void *context);
 
 int vmbus_request_offers(void);
@@ -1263,6 +1321,27 @@ u64 hv_do_hypercall(u64 control, void *input, void *output);
        .guid = UUID_LE(0x44c4f61d, 0x4444, 0x4400, 0x9d, 0x52, \
                        0x80, 0x2e, 0x27, 0xed, 0xe1, 0x9f)
 
+/*
+ * Linux doesn't support the 3 devices: the first two are for
+ * Automatic Virtual Machine Activation, and the third is for
+ * Remote Desktop Virtualization.
+ * {f8e65716-3cb3-4a06-9a60-1889c5cccab5}
+ * {3375baf4-9e15-4b30-b765-67acb10d607b}
+ * {276aacf4-ac15-426c-98dd-7521ad3f01fe}
+ */
+
+#define HV_AVMA1_GUID \
+       .guid = UUID_LE(0xf8e65716, 0x3cb3, 0x4a06, 0x9a, 0x60, \
+                       0x18, 0x89, 0xc5, 0xcc, 0xca, 0xb5)
+
+#define HV_AVMA2_GUID \
+       .guid = UUID_LE(0x3375baf4, 0x9e15, 0x4b30, 0xb7, 0x65, \
+                       0x67, 0xac, 0xb1, 0x0d, 0x60, 0x7b)
+
+#define HV_RDV_GUID \
+       .guid = UUID_LE(0x276aacf4, 0xac15, 0x426c, 0x98, 0xdd, \
+                       0x75, 0x21, 0xad, 0x3f, 0x01, 0xfe)
+
 /*
  * Common header for Hyper-V ICs
  */
@@ -1351,6 +1430,15 @@ struct ictimesync_data {
        u8 flags;
 } __packed;
 
+struct ictimesync_ref_data {
+       u64 parenttime;
+       u64 vmreferencetime;
+       u8 flags;
+       char leapflags;
+       char stratum;
+       u8 reserved[3];
+} __packed;
+
 struct hyperv_service_callback {
        u8 msg_type;
        char *log_msg;
@@ -1364,6 +1452,9 @@ extern bool vmbus_prep_negotiate_resp(struct icmsg_hdr *,
                                        struct icmsg_negotiate *, u8 *, int,
                                        int);
 
+void hv_event_tasklet_disable(struct vmbus_channel *channel);
+void hv_event_tasklet_enable(struct vmbus_channel *channel);
+
 void hv_process_channel_removal(struct vmbus_channel *channel, u32 relid);
 
 /*
index ead13d233a97e60392110d0b8bba43c3b7fa5e5a..ee5200d660b0ad2d47f7ebf80c5e752f7b95873b 100644 (file)
@@ -41,15 +41,17 @@ struct mcb_bus {
        char name[CHAMELEON_FILENAME_LEN + 1];
        int (*get_irq)(struct mcb_device *dev);
 };
-#define to_mcb_bus(b) container_of((b), struct mcb_bus, dev)
+
+static inline struct mcb_bus *to_mcb_bus(struct device *dev)
+{
+       return container_of(dev, struct mcb_bus, dev);
+}
 
 /**
  * struct mcb_device - MEN Chameleon Bus device
  *
- * @bus_list: internal list handling for bus code
  * @dev: device in kernel representation
  * @bus: mcb bus the device is plugged to
- * @subordinate: subordinate MCBus in case of bridge
  * @is_added: flag to check if device is added to bus
  * @driver: associated mcb_driver
  * @id: mcb device id
@@ -62,10 +64,8 @@ struct mcb_bus {
  * @memory: memory resource
  */
 struct mcb_device {
-       struct list_head bus_list;
        struct device dev;
        struct mcb_bus *bus;
-       struct mcb_bus *subordinate;
        bool is_added;
        struct mcb_driver *driver;
        u16 id;
@@ -77,7 +77,11 @@ struct mcb_device {
        struct resource irq;
        struct resource mem;
 };
-#define to_mcb_device(x) container_of((x), struct mcb_device, dev)
+
+static inline struct mcb_device *to_mcb_device(struct device *dev)
+{
+       return container_of(dev, struct mcb_device, dev);
+}
 
 /**
  * struct mcb_driver - MEN Chameleon Bus device driver
@@ -95,7 +99,11 @@ struct mcb_driver {
        void (*remove)(struct mcb_device *mdev);
        void (*shutdown)(struct mcb_device *mdev);
 };
-#define to_mcb_driver(x) container_of((x), struct mcb_driver, driver)
+
+static inline struct mcb_driver *to_mcb_driver(struct device_driver *drv)
+{
+       return container_of(drv, struct mcb_driver, driver);
+}
 
 static inline void *mcb_get_drvdata(struct mcb_device *dev)
 {
index 5430374659734ae74ea27e8fb28a126976482b26..722698a43d79c906f933513c201e369be339c2b8 100644 (file)
@@ -3,6 +3,7 @@
 #include <linux/major.h>
 #include <linux/list.h>
 #include <linux/types.h>
+#include <linux/device.h>
 
 /*
  *     These allocations are managed by device@lanana.org. If you use an
@@ -70,6 +71,13 @@ struct miscdevice  {
 extern int misc_register(struct miscdevice *misc);
 extern void misc_deregister(struct miscdevice *misc);
 
+/*
+ * Helper macro for drivers that don't do anything special in module init / exit
+ * call. This helps in eleminating of boilerplate code.
+ */
+#define module_misc_device(__misc_device) \
+       module_driver(__misc_device, misc_register, misc_deregister)
+
 #define MODULE_ALIAS_MISCDEV(minor)                            \
        MODULE_ALIAS("char-major-" __stringify(MISC_MAJOR)      \
        "-" __stringify(minor))
index 71e4a6dec5ac77a4cfdaf1483ae2c8866e7fd032..ea6095deba2078fcde296b9043c7b55f717cab4b 100644 (file)
@@ -166,7 +166,7 @@ struct vme_resource *vme_lm_request(struct vme_dev *);
 int vme_lm_count(struct vme_resource *);
 int vme_lm_set(struct vme_resource *, unsigned long long, u32, u32);
 int vme_lm_get(struct vme_resource *, unsigned long long *, u32 *, u32 *);
-int vme_lm_attach(struct vme_resource *, int, void (*callback)(int));
+int vme_lm_attach(struct vme_resource *, int, void (*callback)(void *), void *);
 int vme_lm_detach(struct vme_resource *, int);
 void vme_lm_free(struct vme_resource *);
 
index df643f60bb41a47561d39e08d24f34b532dfc715..a32e4da4c11708dbbffd97a1467ff978b336ddd0 100755 (executable)
@@ -1,98 +1,99 @@
-#!/usr/bin/env python2
+#!/usr/bin/env python3
 
 """Find Kconfig symbols that are referenced but not defined."""
 
-# (c) 2014-2015 Valentin Rothberg <valentinrothberg@gmail.com>
+# (c) 2014-2016 Valentin Rothberg <valentinrothberg@gmail.com>
 # (c) 2014 Stefan Hengelein <stefan.hengelein@fau.de>
 #
 # Licensed under the terms of the GNU GPL License version 2
 
 
+import argparse
 import difflib
 import os
 import re
 import signal
+import subprocess
 import sys
 from multiprocessing import Pool, cpu_count
-from optparse import OptionParser
-from subprocess import Popen, PIPE, STDOUT
 
 
 # regex expressions
 OPERATORS = r"&|\(|\)|\||\!"
-FEATURE = r"(?:\w*[A-Z0-9]\w*){2,}"
-DEF = r"^\s*(?:menu){,1}config\s+(" + FEATURE + r")\s*"
-EXPR = r"(?:" + OPERATORS + r"|\s|" + FEATURE + r")+"
+SYMBOL = r"(?:\w*[A-Z0-9]\w*){2,}"
+DEF = r"^\s*(?:menu){,1}config\s+(" + SYMBOL + r")\s*"
+EXPR = r"(?:" + OPERATORS + r"|\s|" + SYMBOL + r")+"
 DEFAULT = r"default\s+.*?(?:if\s.+){,1}"
 STMT = r"^\s*(?:if|select|depends\s+on|(?:" + DEFAULT + r"))\s+" + EXPR
-SOURCE_FEATURE = r"(?:\W|\b)+[D]{,1}CONFIG_(" + FEATURE + r")"
+SOURCE_SYMBOL = r"(?:\W|\b)+[D]{,1}CONFIG_(" + SYMBOL + r")"
 
 # regex objects
 REGEX_FILE_KCONFIG = re.compile(r".*Kconfig[\.\w+\-]*$")
-REGEX_FEATURE = re.compile(r'(?!\B)' + FEATURE + r'(?!\B)')
-REGEX_SOURCE_FEATURE = re.compile(SOURCE_FEATURE)
+REGEX_SYMBOL = re.compile(r'(?!\B)' + SYMBOL + r'(?!\B)')
+REGEX_SOURCE_SYMBOL = re.compile(SOURCE_SYMBOL)
 REGEX_KCONFIG_DEF = re.compile(DEF)
 REGEX_KCONFIG_EXPR = re.compile(EXPR)
 REGEX_KCONFIG_STMT = re.compile(STMT)
 REGEX_KCONFIG_HELP = re.compile(r"^\s+(help|---help---)\s*$")
-REGEX_FILTER_FEATURES = re.compile(r"[A-Za-z0-9]$")
+REGEX_FILTER_SYMBOLS = re.compile(r"[A-Za-z0-9]$")
 REGEX_NUMERIC = re.compile(r"0[xX][0-9a-fA-F]+|[0-9]+")
 REGEX_QUOTES = re.compile("(\"(.*?)\")")
 
 
 def parse_options():
     """The user interface of this module."""
-    usage = "%prog [options]\n\n"                                              \
-            "Run this tool to detect Kconfig symbols that are referenced but " \
-            "not defined in\nKconfig.  The output of this tool has the "       \
-            "format \'Undefined symbol\\tFile list\'\n\n"                      \
-            "If no option is specified, %prog will default to check your\n"    \
-            "current tree.  Please note that specifying commits will "         \
-            "\'git reset --hard\'\nyour current tree!  You may save "          \
-            "uncommitted changes to avoid losing data."
-
-    parser = OptionParser(usage=usage)
-
-    parser.add_option('-c', '--commit', dest='commit', action='store',
-                      default="",
-                      help="Check if the specified commit (hash) introduces "
-                           "undefined Kconfig symbols.")
-
-    parser.add_option('-d', '--diff', dest='diff', action='store',
-                      default="",
-                      help="Diff undefined symbols between two commits.  The "
-                           "input format bases on Git log's "
-                           "\'commmit1..commit2\'.")
-
-    parser.add_option('-f', '--find', dest='find', action='store_true',
-                      default=False,
-                      help="Find and show commits that may cause symbols to be "
-                           "missing.  Required to run with --diff.")
-
-    parser.add_option('-i', '--ignore', dest='ignore', action='store',
-                      default="",
-                      help="Ignore files matching this pattern.  Note that "
-                           "the pattern needs to be a Python regex.  To "
-                           "ignore defconfigs, specify -i '.*defconfig'.")
-
-    parser.add_option('-s', '--sim', dest='sim', action='store', default="",
-                      help="Print a list of maximum 10 string-similar symbols.")
-
-    parser.add_option('', '--force', dest='force', action='store_true',
-                      default=False,
-                      help="Reset current Git tree even when it's dirty.")
-
-    (opts, _) = parser.parse_args()
-
-    if opts.commit and opts.diff:
+    usage = "Run this tool to detect Kconfig symbols that are referenced but " \
+            "not defined in Kconfig.  If no option is specified, "             \
+            "checkkconfigsymbols defaults to check your current tree.  "       \
+            "Please note that specifying commits will 'git reset --hard\' "    \
+            "your current tree!  You may save uncommitted changes to avoid "   \
+            "losing data."
+
+    parser = argparse.ArgumentParser(description=usage)
+
+    parser.add_argument('-c', '--commit', dest='commit', action='store',
+                        default="",
+                        help="check if the specified commit (hash) introduces "
+                             "undefined Kconfig symbols")
+
+    parser.add_argument('-d', '--diff', dest='diff', action='store',
+                        default="",
+                        help="diff undefined symbols between two commits "
+                             "(e.g., -d commmit1..commit2)")
+
+    parser.add_argument('-f', '--find', dest='find', action='store_true',
+                        default=False,
+                        help="find and show commits that may cause symbols to be "
+                             "missing (required to run with --diff)")
+
+    parser.add_argument('-i', '--ignore', dest='ignore', action='store',
+                        default="",
+                        help="ignore files matching this Python regex "
+                             "(e.g., -i '.*defconfig')")
+
+    parser.add_argument('-s', '--sim', dest='sim', action='store', default="",
+                        help="print a list of max. 10 string-similar symbols")
+
+    parser.add_argument('--force', dest='force', action='store_true',
+                        default=False,
+                        help="reset current Git tree even when it's dirty")
+
+    parser.add_argument('--no-color', dest='color', action='store_false',
+                        default=True,
+                        help="don't print colored output (default when not "
+                             "outputting to a terminal)")
+
+    args = parser.parse_args()
+
+    if args.commit and args.diff:
         sys.exit("Please specify only one option at once.")
 
-    if opts.diff and not re.match(r"^[\w\-\.]+\.\.[\w\-\.]+$", opts.diff):
+    if args.diff and not re.match(r"^[\w\-\.]+\.\.[\w\-\.]+$", args.diff):
         sys.exit("Please specify valid input in the following format: "
                  "\'commit1..commit2\'")
 
-    if opts.commit or opts.diff:
-        if not opts.force and tree_is_dirty():
+    if args.commit or args.diff:
+        if not args.force and tree_is_dirty():
             sys.exit("The current Git tree is dirty (see 'git status').  "
                      "Running this script may\ndelete important data since it "
                      "calls 'git reset --hard' for some performance\nreasons. "
@@ -100,138 +101,148 @@ def parse_options():
                      "'--force' if you\nwant to ignore this warning and "
                      "continue.")
 
-    if opts.commit:
-        opts.find = False
+    if args.commit:
+        args.find = False
 
-    if opts.ignore:
+    if args.ignore:
         try:
-            re.match(opts.ignore, "this/is/just/a/test.c")
+            re.match(args.ignore, "this/is/just/a/test.c")
         except:
             sys.exit("Please specify a valid Python regex.")
 
-    return opts
+    return args
 
 
 def main():
     """Main function of this module."""
-    opts = parse_options()
+    args = parse_options()
 
-    if opts.sim and not opts.commit and not opts.diff:
-        sims = find_sims(opts.sim, opts.ignore)
+    global COLOR
+    COLOR = args.color and sys.stdout.isatty()
+
+    if args.sim and not args.commit and not args.diff:
+        sims = find_sims(args.sim, args.ignore)
         if sims:
-            print "%s: %s" % (yel("Similar symbols"), ', '.join(sims))
+            print("%s: %s" % (yel("Similar symbols"), ', '.join(sims)))
         else:
-            print "%s: no similar symbols found" % yel("Similar symbols")
+            print("%s: no similar symbols found" % yel("Similar symbols"))
         sys.exit(0)
 
     # dictionary of (un)defined symbols
     defined = {}
     undefined = {}
 
-    if opts.commit or opts.diff:
+    if args.commit or args.diff:
         head = get_head()
 
         # get commit range
         commit_a = None
         commit_b = None
-        if opts.commit:
-            commit_a = opts.commit + "~"
-            commit_b = opts.commit
-        elif opts.diff:
-            split = opts.diff.split("..")
+        if args.commit:
+            commit_a = args.commit + "~"
+            commit_b = args.commit
+        elif args.diff:
+            split = args.diff.split("..")
             commit_a = split[0]
             commit_b = split[1]
             undefined_a = {}
             undefined_b = {}
 
         # get undefined items before the commit
-        execute("git reset --hard %s" % commit_a)
-        undefined_a, _ = check_symbols(opts.ignore)
+        reset(commit_a)
+        undefined_a, _ = check_symbols(args.ignore)
 
         # get undefined items for the commit
-        execute("git reset --hard %s" % commit_b)
-        undefined_b, defined = check_symbols(opts.ignore)
+        reset(commit_b)
+        undefined_b, defined = check_symbols(args.ignore)
 
         # report cases that are present for the commit but not before
-        for feature in sorted(undefined_b):
-            # feature has not been undefined before
-            if not feature in undefined_a:
-                files = sorted(undefined_b.get(feature))
-                undefined[feature] = files
-            # check if there are new files that reference the undefined feature
+        for symbol in sorted(undefined_b):
+            # symbol has not been undefined before
+            if symbol not in undefined_a:
+                files = sorted(undefined_b.get(symbol))
+                undefined[symbol] = files
+            # check if there are new files that reference the undefined symbol
             else:
-                files = sorted(undefined_b.get(feature) -
-                               undefined_a.get(feature))
+                files = sorted(undefined_b.get(symbol) -
+                               undefined_a.get(symbol))
                 if files:
-                    undefined[feature] = files
+                    undefined[symbol] = files
 
         # reset to head
-        execute("git reset --hard %s" % head)
+        reset(head)
 
     # default to check the entire tree
     else:
-        undefined, defined = check_symbols(opts.ignore)
+        undefined, defined = check_symbols(args.ignore)
 
     # now print the output
-    for feature in sorted(undefined):
-        print red(feature)
+    for symbol in sorted(undefined):
+        print(red(symbol))
 
-        files = sorted(undefined.get(feature))
-        print "%s: %s" % (yel("Referencing files"), ", ".join(files))
+        files = sorted(undefined.get(symbol))
+        print("%s: %s" % (yel("Referencing files"), ", ".join(files)))
 
-        sims = find_sims(feature, opts.ignore, defined)
+        sims = find_sims(symbol, args.ignore, defined)
         sims_out = yel("Similar symbols")
         if sims:
-            print "%s: %s" % (sims_out, ', '.join(sims))
+            print("%s: %s" % (sims_out, ', '.join(sims)))
         else:
-            print "%s: %s" % (sims_out, "no similar symbols found")
+            print("%s: %s" % (sims_out, "no similar symbols found"))
 
-        if opts.find:
-            print "%s:" % yel("Commits changing symbol")
-            commits = find_commits(feature, opts.diff)
+        if args.find:
+            print("%s:" % yel("Commits changing symbol"))
+            commits = find_commits(symbol, args.diff)
             if commits:
                 for commit in commits:
                     commit = commit.split(" ", 1)
-                    print "\t- %s (\"%s\")" % (yel(commit[0]), commit[1])
+                    print("\t- %s (\"%s\")" % (yel(commit[0]), commit[1]))
             else:
-                print "\t- no commit found"
-        print  #  new line
+                print("\t- no commit found")
+        print()  # new line
+
+
+def reset(commit):
+    """Reset current git tree to %commit."""
+    execute(["git", "reset", "--hard", commit])
 
 
 def yel(string):
     """
     Color %string yellow.
     """
-    return "\033[33m%s\033[0m" % string
+    return "\033[33m%s\033[0m" % string if COLOR else string
 
 
 def red(string):
     """
     Color %string red.
     """
-    return "\033[31m%s\033[0m" % string
+    return "\033[31m%s\033[0m" % string if COLOR else string
 
 
 def execute(cmd):
     """Execute %cmd and return stdout.  Exit in case of error."""
-    pop = Popen(cmd, stdout=PIPE, stderr=STDOUT, shell=True)
-    (stdout, _) = pop.communicate()  # wait until finished
-    if pop.returncode != 0:
-        sys.exit(stdout)
+    try:
+        stdout = subprocess.check_output(cmd, stderr=subprocess.STDOUT, shell=False)
+        stdout = stdout.decode(errors='replace')
+    except subprocess.CalledProcessError as fail:
+        exit(fail)
     return stdout
 
 
 def find_commits(symbol, diff):
     """Find commits changing %symbol in the given range of %diff."""
-    commits = execute("git log --pretty=oneline --abbrev-commit -G %s %s"
-                      % (symbol, diff))
+    commits = execute(["git", "log", "--pretty=oneline",
+                       "--abbrev-commit", "-G",
+                       symbol, diff])
     return [x for x in commits.split("\n") if x]
 
 
 def tree_is_dirty():
     """Return true if the current working tree is dirty (i.e., if any file has
     been added, deleted, modified, renamed or copied but not committed)."""
-    stdout = execute("git status --porcelain")
+    stdout = execute(["git", "status", "--porcelain"])
     for line in stdout:
         if re.findall(r"[URMADC]{1}", line[:2]):
             return True
@@ -240,13 +251,13 @@ def tree_is_dirty():
 
 def get_head():
     """Return commit hash of current HEAD."""
-    stdout = execute("git rev-parse HEAD")
+    stdout = execute(["git", "rev-parse", "HEAD"])
     return stdout.strip('\n')
 
 
 def partition(lst, size):
     """Partition list @lst into eveni-sized lists of size @size."""
-    return [lst[i::size] for i in xrange(size)]
+    return [lst[i::size] for i in range(size)]
 
 
 def init_worker():
@@ -254,7 +265,7 @@ def init_worker():
     signal.signal(signal.SIGINT, signal.SIG_IGN)
 
 
-def find_sims(symbol, ignore, defined = []):
+def find_sims(symbol, ignore, defined=[]):
     """Return a list of max. ten Kconfig symbols that are string-similar to
     @symbol."""
     if defined:
@@ -279,7 +290,7 @@ def find_sims(symbol, ignore, defined = []):
 def get_files():
     """Return a list of all files in the current git directory."""
     # use 'git ls-files' to get the worklist
-    stdout = execute("git ls-files")
+    stdout = execute(["git", "ls-files"])
     if len(stdout) > 0 and stdout[-1] == "\n":
         stdout = stdout[:-1]
 
@@ -311,8 +322,8 @@ def check_symbols_helper(pool, ignore):
     check_symbols() in order to properly terminate running worker processes."""
     source_files = []
     kconfig_files = []
-    defined_features = []
-    referenced_features = dict()  # {file: [features]}
+    defined_symbols = []
+    referenced_symbols = dict()  # {file: [symbols]}
 
     for gitfile in get_files():
         if REGEX_FILE_KCONFIG.match(gitfile):
@@ -326,76 +337,75 @@ def check_symbols_helper(pool, ignore):
     # parse source files
     arglist = partition(source_files, cpu_count())
     for res in pool.map(parse_source_files, arglist):
-        referenced_features.update(res)
-
+        referenced_symbols.update(res)
 
     # parse kconfig files
     arglist = []
     for part in partition(kconfig_files, cpu_count()):
         arglist.append((part, ignore))
     for res in pool.map(parse_kconfig_files, arglist):
-        defined_features.extend(res[0])
-        referenced_features.update(res[1])
-    defined_features = set(defined_features)
+        defined_symbols.extend(res[0])
+        referenced_symbols.update(res[1])
+    defined_symbols = set(defined_symbols)
 
-    # inverse mapping of referenced_features to dict(feature: [files])
+    # inverse mapping of referenced_symbols to dict(symbol: [files])
     inv_map = dict()
-    for _file, features in referenced_features.iteritems():
-        for feature in features:
-            inv_map[feature] = inv_map.get(feature, set())
-            inv_map[feature].add(_file)
-    referenced_features = inv_map
-
-    undefined = {}  # {feature: [files]}
-    for feature in sorted(referenced_features):
+    for _file, symbols in referenced_symbols.items():
+        for symbol in symbols:
+            inv_map[symbol] = inv_map.get(symbol, set())
+            inv_map[symbol].add(_file)
+    referenced_symbols = inv_map
+
+    undefined = {}  # {symbol: [files]}
+    for symbol in sorted(referenced_symbols):
         # filter some false positives
-        if feature == "FOO" or feature == "BAR" or \
-                feature == "FOO_BAR" or feature == "XXX":
+        if symbol == "FOO" or symbol == "BAR" or \
+                symbol == "FOO_BAR" or symbol == "XXX":
             continue
-        if feature not in defined_features:
-            if feature.endswith("_MODULE"):
+        if symbol not in defined_symbols:
+            if symbol.endswith("_MODULE"):
                 # avoid false positives for kernel modules
-                if feature[:-len("_MODULE")] in defined_features:
+                if symbol[:-len("_MODULE")] in defined_symbols:
                     continue
-            undefined[feature] = referenced_features.get(feature)
-    return undefined, defined_features
+            undefined[symbol] = referenced_symbols.get(symbol)
+    return undefined, defined_symbols
 
 
 def parse_source_files(source_files):
     """Parse each source file in @source_files and return dictionary with source
     files as keys and lists of references Kconfig symbols as values."""
-    referenced_features = dict()
+    referenced_symbols = dict()
     for sfile in source_files:
-        referenced_features[sfile] = parse_source_file(sfile)
-    return referenced_features
+        referenced_symbols[sfile] = parse_source_file(sfile)
+    return referenced_symbols
 
 
 def parse_source_file(sfile):
-    """Parse @sfile and return a list of referenced Kconfig features."""
+    """Parse @sfile and return a list of referenced Kconfig symbols."""
     lines = []
     references = []
 
     if not os.path.exists(sfile):
         return references
 
-    with open(sfile, "r") as stream:
+    with open(sfile, "r", encoding='utf-8', errors='replace') as stream:
         lines = stream.readlines()
 
     for line in lines:
-        if not "CONFIG_" in line:
+        if "CONFIG_" not in line:
             continue
-        features = REGEX_SOURCE_FEATURE.findall(line)
-        for feature in features:
-            if not REGEX_FILTER_FEATURES.search(feature):
+        symbols = REGEX_SOURCE_SYMBOL.findall(line)
+        for symbol in symbols:
+            if not REGEX_FILTER_SYMBOLS.search(symbol):
                 continue
-            references.append(feature)
+            references.append(symbol)
 
     return references
 
 
-def get_features_in_line(line):
-    """Return mentioned Kconfig features in @line."""
-    return REGEX_FEATURE.findall(line)
+def get_symbols_in_line(line):
+    """Return mentioned Kconfig symbols in @line."""
+    return REGEX_SYMBOL.findall(line)
 
 
 def parse_kconfig_files(args):
@@ -404,21 +414,21 @@ def parse_kconfig_files(args):
     pattern."""
     kconfig_files = args[0]
     ignore = args[1]
-    defined_features = []
-    referenced_features = dict()
+    defined_symbols = []
+    referenced_symbols = dict()
 
     for kfile in kconfig_files:
         defined, references = parse_kconfig_file(kfile)
-        defined_features.extend(defined)
+        defined_symbols.extend(defined)
         if ignore and re.match(ignore, kfile):
             # do not collect references for files that match the ignore pattern
             continue
-        referenced_features[kfile] = references
-    return (defined_features, referenced_features)
+        referenced_symbols[kfile] = references
+    return (defined_symbols, referenced_symbols)
 
 
 def parse_kconfig_file(kfile):
-    """Parse @kfile and update feature definitions and references."""
+    """Parse @kfile and update symbol definitions and references."""
     lines = []
     defined = []
     references = []
@@ -427,7 +437,7 @@ def parse_kconfig_file(kfile):
     if not os.path.exists(kfile):
         return defined, references
 
-    with open(kfile, "r") as stream:
+    with open(kfile, "r", encoding='utf-8', errors='replace') as stream:
         lines = stream.readlines()
 
     for i in range(len(lines)):
@@ -436,8 +446,8 @@ def parse_kconfig_file(kfile):
         line = line.split("#")[0]  # ignore comments
 
         if REGEX_KCONFIG_DEF.match(line):
-            feature_def = REGEX_KCONFIG_DEF.findall(line)
-            defined.append(feature_def[0])
+            symbol_def = REGEX_KCONFIG_DEF.findall(line)
+            defined.append(symbol_def[0])
             skip = False
         elif REGEX_KCONFIG_HELP.match(line):
             skip = True
@@ -446,18 +456,18 @@ def parse_kconfig_file(kfile):
             pass
         elif REGEX_KCONFIG_STMT.match(line):
             line = REGEX_QUOTES.sub("", line)
-            features = get_features_in_line(line)
+            symbols = get_symbols_in_line(line)
             # multi-line statements
             while line.endswith("\\"):
                 i += 1
                 line = lines[i]
                 line = line.strip('\n')
-                features.extend(get_features_in_line(line))
-            for feature in set(features):
-                if REGEX_NUMERIC.match(feature):
+                symbols.extend(get_symbols_in_line(line))
+            for symbol in set(symbols):
+                if REGEX_NUMERIC.match(symbol):
                     # ignore numeric values
                     continue
-                references.append(feature)
+                references.append(symbol)
 
     return defined, references
 
index 0d8bd29b1bd6fe5cfc61dc7c245ecee70420458a..430b201f3e254ad852d5b712529d62bf24b1e8e1 100755 (executable)
-#!/bin/sh
+#!/bin/awk -f
 # Before running this script please ensure that your PATH is
 # typical as you use for compilation/installation. I use
 # /bin /sbin /usr/bin /usr/sbin /usr/local/bin, but it may
 # differ on your system.
-#
-echo 'If some fields are empty or look unusual you may have an old version.'
-echo 'Compare to the current minimal requirements in Documentation/Changes.'
-echo ' '
 
-uname -a
-echo ' '
-
-gcc -dumpversion 2>&1 |
-awk '/[0-9]+([.]?[0-9]+)+/ && !/not found$/{
-       match($0, /[0-9]+([.]?[0-9]+)+/)
-       printf("GNU C\t\t\t%s\n",
-       substr($0,RSTART,RLENGTH))
-}'
-
-make --version 2>&1 |
-awk '/GNU Make/{
-       match($0, /[0-9]+([.]?[0-9]+)+/)
-       printf("GNU Make\t\t%s\n",
-       substr($0,RSTART,RLENGTH))
-}'
-
-ld -v 2>&1 |
-awk '/[0-9]+([.]?[0-9]+)+/ && !/not found$/{
-       match($0, /[0-9]+([.]?[0-9]+)+/)
-       printf("Binutils\t\t%s\n",
-       substr($0,RSTART,RLENGTH))
-}'
-
-mount --version 2>&1 |
-awk '/[0-9]+([.]?[0-9]+)+/ && !/not found$/{
-       match($0, /[0-9]+([.]?[0-9]+)+/)
-       $0 = substr($0,RSTART,RLENGTH)
-       printf("Util-linux\t\t%s\nMount\t\t\t%s\n",$0,$0)
-}'
-
-depmod -V  2>&1 |
-awk '/[0-9]+([.]?[0-9]+)+/ && !/not found$/{
-       match($0, /[0-9]+([.]?[0-9]+)+/)
-       printf("Module-init-tools\t%s\n",
-       substr($0,RSTART,RLENGTH))
-}'
-
-tune2fs 2>&1 |
-awk '/^tune2fs/{
-       match($0, /[0-9]+([.]?[0-9]+)+/)
-       printf("E2fsprogs\t\t%s\n",
-       substr($0,RSTART,RLENGTH))
-}'
-
-fsck.jfs -V 2>&1 |
-awk '/version/{
-       match($0, /[0-9]+([.]?[0-9]+)+/)
-       printf("Jfsutils\t\t%s\n",
-       substr($0,RSTART,RLENGTH))
-}'
-
-reiserfsck -V 2>&1 |
-awk '/^reiserfsck/{
-       match($0, /[0-9]+([.]?[0-9]+)+/)
-       printf("Reiserfsprogs\t\t%s\n",
-       substr($0,RSTART,RLENGTH))
-}'
-
-fsck.reiser4 -V 2>&1 | grep ^fsck.reiser4 | awk \
-'NR==1{print "reiser4progs          ", $2}'
-
-xfs_db -V 2>&1 |
-awk '/version/{
-       match($0, /[0-9]+([.]?[0-9]+)+/)
-       printf("Xfsprogs\t\t%s\n",
-       substr($0,RSTART,RLENGTH))
-}'
-
-pccardctl -V 2>&1 |
-awk '/pcmciautils/{
-       match($0, /[0-9]+([.]?[0-9]+)+/)
-       printf("Pcmciautils\t\t%s\n",
-       substr($0,RSTART,RLENGTH))
-}'
-
-cardmgr -V 2>&1| grep version | awk \
-'NR==1{print "pcmcia-cs             ", $3}'
-
-quota -V 2>&1 |
-awk '/version/{
-       match($0, /[0-9]+([.]?[0-9]+)+/)
-       printf("Quota-tools\t\t%s\n",
-       substr($0,RSTART,RLENGTH))
-}'
-
-pppd --version 2>&1 |
-awk '/version/{
-       match($0, /[0-9]+([.]?[0-9]+)+/)
-       printf("PPP\t\t\t%s\n",
-       substr($0,RSTART,RLENGTH))
-}'
-
-isdnctrl 2>&1 | grep version | awk \
-'NR==1{print "isdn4k-utils          ", $NF}'
-
-showmount --version 2>&1 | grep nfs-utils | awk \
-'NR==1{print "nfs-utils             ", $NF}'
-
-test -r /proc/self/maps &&
-sed '
-       /.*libc-\(.*\)\.so$/!d
-       s//Linux C Library\t\t\1/
-       q
-' /proc/self/maps
-
-ldd --version 2>&1 |
-awk '/^ldd/{
-       match($0, /[0-9]+([.]?[0-9]+)+/)
-       printf("Dynamic linker (ldd)\t%s\n",
-       substr($0,RSTART,RLENGTH))
-}'
-
-libcpp=`ldconfig -p 2>/dev/null |
-       awk '/(libg|stdc)[+]+\.so/ {
-       print $NF
-       exit
+BEGIN {
+       usage = "If some fields are empty or look unusual you may have an old version.\n"
+       usage = usage "Compare to the current minimal requirements in Documentation/Changes.\n"
+       print usage
+
+       system("uname -a")
+       printf("\n")
+
+       printversion("GNU C", version("gcc -dumpversion 2>&1"))
+       printversion("GNU Make", version("make --version 2>&1"))
+       printversion("Binutils", version("ld -v 2>&1"))
+       printversion("Util-linux", version("mount --version 2>&1"))
+       printversion("Mount", version("mount --version 2>&1"))
+       printversion("Module-init-tools", version("depmod -V  2>&1"))
+       printversion("E2fsprogs", version("tune2fs 2>&1"))
+       printversion("Jfsutils", version("fsck.jfs -V 2>&1"))
+       printversion("Reiserfsprogs", version("reiserfsck -V 2>&1"))
+       printversion("Reiser4fsprogs", version("fsck.reiser4 -V 2>&1"))
+       printversion("Xfsprogs", version("xfs_db -V 2>&1"))
+       printversion("Pcmciautils", version("pccardctl -V 2>&1"))
+       printversion("Pcmcia-cs", version("cardmgr -V 2>&1"))
+       printversion("Quota-tools", version("quota -V 2>&1"))
+       printversion("PPP", version("pppd --version 2>&1"))
+       printversion("Isdn4k-utils", version("isdnctrl 2>&1"))
+       printversion("Nfs-utils", version("showmount --version 2>&1"))
+
+       if (system("test -r /proc/self/maps") == 0) {
+               while (getline <"/proc/self/maps" > 0) {
+                       n = split($0, procmaps, "/")
+                       if (/libc.*so$/ && match(procmaps[n], /[0-9]+([.]?[0-9]+)+/)) {
+                               ver = substr(procmaps[n], RSTART, RLENGTH)
+                               printversion("Linux C Library", ver)
+                               break
+                       }
+               }
        }
-'`
-test -r "$libcpp" &&
-ls -l $libcpp |
-sed '
-       s!.*so\.!!
-       s!^!Linux C++ Library\t!
-'
-ps --version 2>&1 |
-awk '/version/{
-       match($0, /[0-9]+([.]?[0-9]+)+/)
-       printf("Procps\t\t\t%s\n",
-       substr($0,RSTART,RLENGTH))
-}'
-
-ifconfig --version 2>&1 |
-awk '/tools/{
-       match($0, /[0-9]+([.]?[0-9]+)+/)
-       printf("Net-tools\t\t%s\n",
-       substr($0,RSTART,RLENGTH))
-}'
-
-loadkeys -V 2>&1 |
-awk '/[0-9]+([.]?[0-9]+)+/ && !/not found$/{
-       match($0, /[0-9]+([.]?[0-9]+)+/)
-       $0 = substr($0,RSTART,RLENGTH)
-       printf("Kbd\t\t\t%s\nConsole-tools\t\t%s\n",$0,$0)
-}'
 
-oprofiled --version 2>&1 | awk \
-'(NR==1 && ($2 == "oprofile")) {print "oprofile              ", $3}'
+       printversion("Dynamic linker (ldd)", version("ldd --version 2>&1"))
 
-expr --v 2>&1 |
-awk '/^expr/{
-       match($0, /[0-9]+([.]?[0-9]+)+/)
-       printf("Sh-utils\t\t%s\n",
-       substr($0,RSTART,RLENGTH))
-}'
-
-udevadm --version 2>&1 |
-awk '/[0-9]+([.]?[0-9]+)+/ && !/not found$/{
-       match($0, /[0-9]+([.]?[0-9]+)+/)
-       printf("Udev\t\t\t%s\n",
-       substr($0,RSTART,RLENGTH))
-}'
+       while ("ldconfig -p 2>/dev/null" | getline > 0) {
+               if (/(libg|stdc)[+]+\.so/) {
+                       libcpp = $NF
+                       break
+               }
+       }
+       if (system("test -r " libcpp) == 0)
+               printversion("Linux C++ Library", version("readlink " libcpp))
+
+       printversion("Procps", version("ps --version 2>&1"))
+       printversion("Net-tools", version("ifconfig --version 2>&1"))
+       printversion("Kbd", version("loadkeys -V 2>&1"))
+       printversion("Console-tools", version("loadkeys -V 2>&1"))
+       printversion("Oprofile", version("oprofiled --version 2>&1"))
+       printversion("Sh-utils", version("expr --v 2>&1"))
+       printversion("Udev", version("udevadm --version 2>&1"))
+       printversion("Wireless-tools", version("iwconfig --version 2>&1"))
+
+       if (system("test -r /proc/modules") == 0) {
+               while ("sort /proc/modules" | getline > 0) {
+                       mods = mods sep $1
+                       sep = " "
+               }
+               printversion("Modules Loaded", mods)
+       }
+}
 
-iwconfig --version 2>&1 |
-awk '/version/{
-       match($0, /[0-9]+([.]?[0-9]+)+/)
-       printf("Wireless-tools\t\t%s\n",
-       substr($0,RSTART,RLENGTH))
-}'
+function version(cmd,    ver) {
+       while (cmd | getline > 0) {
+               if (!/ver_linux/ && match($0, /[0-9]+([.]?[0-9]+)+/)) {
+                       ver = substr($0, RSTART, RLENGTH)
+                       break
+               }
+       }
+       close(cmd)
+       return ver
+}
 
-test -e /proc/modules &&
-sort /proc/modules |
-sed '
-       s/ .*//
-       H
-${
-       g
-       s/^\n/Modules Loaded\t\t/
-       y/\n/ /
-       q
+function printversion(name, value,  ofmt) {
+       if (value != "") {
+               ofmt = "%-20s\t%s\n"
+               printf(ofmt, name, value)
+       }
 }
-       d
-'
index 0d9f48ec42bbb66366d1b35dab04af94eb152901..bc7adb84e679cdd237b60646255b425819c5f5b0 100644 (file)
@@ -1433,7 +1433,7 @@ int main(int argc, char *argv[])
        openlog("KVP", 0, LOG_USER);
        syslog(LOG_INFO, "KVP starting; pid is:%d", getpid());
 
-       kvp_fd = open("/dev/vmbus/hv_kvp", O_RDWR);
+       kvp_fd = open("/dev/vmbus/hv_kvp", O_RDWR | O_CLOEXEC);
 
        if (kvp_fd < 0) {
                syslog(LOG_ERR, "open /dev/vmbus/hv_kvp failed; error: %d %s",
index 5d51d6ff08e6a603173ad071b7651cc0fbce241d..e0829809c897064554ca4ad342e4dd22c6c1c024 100644 (file)
@@ -250,6 +250,9 @@ int main(int argc, char *argv[])
                                syslog(LOG_ERR, "/etc/fstab and /proc/mounts");
                        }
                        break;
+               case VSS_OP_HOT_BACKUP:
+                       syslog(LOG_INFO, "VSS: op=CHECK HOT BACKUP\n");
+                       break;
                default:
                        syslog(LOG_ERR, "Illegal op:%d\n", op);
                }
This page took 0.203986 seconds and 5 git commands to generate.