Commit b78b499a authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'char-misc-4.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc

Pull char/misc driver updates from Greg KH:
 "Here's the big char/misc driver patches for 4.10-rc1. Lots of tiny
  changes over lots of "minor" driver subsystems, the largest being some
  new FPGA drivers. Other than that, a few other new drivers, but no new
  driver subsystems added for this kernel cycle, a nice change.

  All of these have been in linux-next with no reported issues"

* tag 'char-misc-4.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc: (107 commits)
  uio-hv-generic: store physical addresses instead of virtual
  Tools: hv: kvp: configurable external scripts path
  uio-hv-generic: new userspace i/o driver for VMBus
  vmbus: add support for dynamic device id's
  hv: change clockevents unbind tactics
  hv: acquire vmbus_connection.channel_mutex in vmbus_free_channels()
  hyperv: Fix spelling of HV_UNKOWN
  mei: bus: enable non-blocking RX
  mei: fix the back to back interrupt handling
  mei: synchronize irq before initiating a reset.
  VME: Remove shutdown entry from vme_driver
  auxdisplay: ht16k33: select framebuffer helper modules
  MAINTAINERS: add git url for fpga
  fpga: Clarify how write_init works streaming modes
  fpga zynq: Fix incorrect ISR state on bootup
  fpga zynq: Remove priv->dev
  fpga zynq: Add missing \n to messages
  fpga: Add COMPILE_TEST to all drivers
  uio: pruss: add clk_disable()
  char/pcmcia: add some error checking in scr24x_read()
  ...
parents 098c3055 190cc65e
What: /sys/class/fpga_bridge/<bridge>/name
Date: January 2016
KernelVersion: 4.5
Contact: Alan Tull <atull@opensource.altera.com>
Description: Name of low level FPGA bridge driver.
What: /sys/class/fpga_bridge/<bridge>/state
Date: January 2016
KernelVersion: 4.5
Contact: Alan Tull <atull@opensource.altera.com>
Description: Show bridge state as "enabled" or "disabled"
......@@ -29,3 +29,19 @@ Description: Display fw status registers content
Also number of registers varies between 1 and 6
depending on generation.
What: /sys/class/mei/meiN/hbm_ver
Date: Aug 2016
KernelVersion: 4.9
Contact: Tomas Winkler <tomas.winkler@intel.com>
Description: Display the negotiated HBM protocol version.
The HBM protocol version negotiated
between the driver and the device.
What: /sys/class/mei/meiN/hbm_ver_drv
Date: Aug 2016
KernelVersion: 4.9
Contact: Tomas Winkler <tomas.winkler@intel.com>
Description: Display the driver HBM protocol version.
The HBM protocol version supported by the driver.
Holtek ht16k33 RAM mapping 16*8 LED controller driver with keyscan
-------------------------------------------------------------------------------
Required properties:
- compatible: "holtek,ht16k33"
- reg: I2C slave address of the chip.
- interrupt-parent: A phandle pointing to the interrupt controller
serving the interrupt for this chip.
- interrupts: Interrupt specification for the key pressed interrupt.
- refresh-rate-hz: Display update interval in HZ.
- debounce-delay-ms: Debouncing interval time in milliseconds.
- linux,keymap: The keymap for keys as described in the binding
document (devicetree/bindings/input/matrix-keymap.txt).
Optional properties:
- linux,no-autorepeat: Disable keyrepeat.
- default-brightness-level: Initial brightness level [0-15] (default: 15).
Example:
&i2c1 {
ht16k33: ht16k33@70 {
compatible = "holtek,ht16k33";
reg = <0x70>;
refresh-rate-hz = <20>;
debounce-delay-ms = <50>;
interrupt-parent = <&gpio4>;
interrupts = <5 (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_EDGE_RISING)>;
linux,keymap = <
MATRIX_KEY(2, 0, KEY_F6)
MATRIX_KEY(3, 0, KEY_F8)
MATRIX_KEY(4, 0, KEY_F10)
MATRIX_KEY(5, 0, KEY_F4)
MATRIX_KEY(6, 0, KEY_F2)
MATRIX_KEY(2, 1, KEY_F5)
MATRIX_KEY(3, 1, KEY_F7)
MATRIX_KEY(4, 1, KEY_F9)
MATRIX_KEY(5, 1, KEY_F3)
MATRIX_KEY(6, 1, KEY_F1)
>;
};
};
This diff is collapsed.
Broadcom OTP memory controller
Required Properties:
- compatible: "brcm,ocotp" for the first generation Broadcom OTPC which is used
in Cygnus and supports 32 bit read/write. Use "brcm,ocotp-v2" for the second
generation Broadcom OTPC which is used in SoC's such as Stingray and supports
64-bit read/write.
- reg: Base address of the OTP controller.
- brcm,ocotp-size: Amount of memory available, in 32 bit words
Example:
otp: otp@0301c800 {
compatible = "brcm,ocotp";
reg = <0x0301c800 0x2c>;
brcm,ocotp-size = <2048>;
};
* NXP LPC18xx OTP memory
Internal OTP (One Time Programmable) memory for NXP LPC18xx/43xx devices.
Required properties:
- compatible: Should be "nxp,lpc1850-otp"
- reg: Must contain an entry with the physical base address and length
for each entry in reg-names.
- address-cells: must be set to 1.
- size-cells: must be set to 1.
See nvmem.txt for more information.
Example:
otp: otp@40045000 {
compatible = "nxp,lpc1850-otp";
reg = <0x40045000 0x1000>;
#address-cells = <1>;
#size-cells = <1>;
};
......@@ -127,6 +127,7 @@ hitex Hitex Development Tools
holt Holt Integrated Circuits, Inc.
honeywell Honeywell
hp Hewlett Packard
holtek Holtek Semiconductor, Inc.
i2se I2SE GmbH
ibm International Business Machines (IBM)
idt Integrated Device Technologies, Inc.
......
......@@ -18,31 +18,37 @@ API Functions:
To program the FPGA from a file or from a buffer:
-------------------------------------------------
int fpga_mgr_buf_load(struct fpga_manager *mgr, u32 flags,
int fpga_mgr_buf_load(struct fpga_manager *mgr,
struct fpga_image_info *info,
const char *buf, size_t count);
Load the FPGA from an image which exists as a buffer in memory.
int fpga_mgr_firmware_load(struct fpga_manager *mgr, u32 flags,
int fpga_mgr_firmware_load(struct fpga_manager *mgr,
struct fpga_image_info *info,
const char *image_name);
Load the FPGA from an image which exists as a file. The image file must be on
the firmware search path (see the firmware class documentation).
For both these functions, flags == 0 for normal full reconfiguration or
FPGA_MGR_PARTIAL_RECONFIG for partial reconfiguration. If successful, the FPGA
ends up in operating mode. Return 0 on success or a negative error code.
the firmware search path (see the firmware class documentation). If successful,
the FPGA ends up in operating mode. Return 0 on success or a negative error
code.
A FPGA design contained in a FPGA image file will likely have particulars that
affect how the image is programmed to the FPGA. These are contained in struct
fpga_image_info. Currently the only such particular is a single flag bit
indicating whether the image is for full or partial reconfiguration.
To get/put a reference to a FPGA manager:
-----------------------------------------
struct fpga_manager *of_fpga_mgr_get(struct device_node *node);
struct fpga_manager *fpga_mgr_get(struct device *dev);
Given a DT node or device, get an exclusive reference to a FPGA manager.
void fpga_mgr_put(struct fpga_manager *mgr);
Given a DT node, get an exclusive reference to a FPGA manager or release
the reference.
Release the reference.
To register or unregister the low level FPGA-specific driver:
......@@ -70,8 +76,11 @@ struct device_node *mgr_node = ...
char *buf = ...
int count = ...
/* struct with information about the FPGA image to program. */
struct fpga_image_info info;
/* flags indicates whether to do full or partial reconfiguration */
int flags = 0;
info.flags = 0;
int ret;
......@@ -79,7 +88,7 @@ int ret;
struct fpga_manager *mgr = of_fpga_mgr_get(mgr_node);
/* Load the buffer to the FPGA */
ret = fpga_mgr_buf_load(mgr, flags, buf, count);
ret = fpga_mgr_buf_load(mgr, &info, buf, count);
/* Release the FPGA manager */
fpga_mgr_put(mgr);
......@@ -96,8 +105,11 @@ struct device_node *mgr_node = ...
/* FPGA image is in this file which is in the firmware search path */
const char *path = "fpga-image-9.rbf"
/* struct with information about the FPGA image to program. */
struct fpga_image_info info;
/* flags indicates whether to do full or partial reconfiguration */
int flags = 0;
info.flags = 0;
int ret;
......@@ -105,7 +117,7 @@ int ret;
struct fpga_manager *mgr = of_fpga_mgr_get(mgr_node);
/* Get the firmware image (path) and load it to the FPGA */
ret = fpga_mgr_firmware_load(mgr, flags, path);
ret = fpga_mgr_firmware_load(mgr, &info, path);
/* Release the FPGA manager */
fpga_mgr_put(mgr);
......@@ -157,7 +169,10 @@ The programming sequence is:
2. .write (may be called once or multiple times)
3. .write_complete
The .write_init function will prepare the FPGA to receive the image data.
The .write_init function will prepare the FPGA to receive the image data. The
buffer passed into .write_init will be atmost .initial_header_size bytes long,
if the whole bitstream is not immediately available then the core code will
buffer up at least this much before starting.
The .write function writes a buffer to the FPGA. The buffer may be contain the
whole FPGA image or may be a smaller chunk of an FPGA image. In the latter
......
......@@ -97,3 +97,25 @@ $ echo 0 > /sys/bus/intel_th/devices/0-msc0/active
# and now you can collect the trace from the device node:
$ cat /dev/intel_th0/msc0 > my_stp_trace
Host Debugger Mode
==================
It is possible to configure the Trace Hub and control its trace
capture from a remote debug host, which should be connected via one of
the hardware debugging interfaces, which will then be used to both
control Intel Trace Hub and transfer its trace data to the debug host.
The driver needs to be told that such an arrangement is taking place
so that it does not touch any capture/port configuration and avoids
conflicting with the debug host's configuration accesses. The only
activity that the driver will perform in this mode is collecting
software traces to the Software Trace Hub (an stm class device). The
user is still responsible for setting up adequate master/channel
mappings that the decoder on the receiving end would recognize.
In order to enable the host mode, set the 'host_mode' parameter of the
'intel_th' kernel module to 'y'. None of the virtual output devices
will show up on the intel_th bus. Also, trace configuration and
capture controlling attribute groups of the 'gth' device will not be
exposed. The 'sth' device will operate as usual.
......@@ -69,12 +69,43 @@ stm device's channel mmio region is 64 bytes and hardware page size is
width==64, you should be able to mmap() one page on this file
descriptor and obtain direct access to an mmio region for 64 channels.
Examples of STM devices are Intel(R) Trace Hub [1] and Coresight STM
[2].
stm_source
==========
For kernel-based trace sources, there is "stm_source" device
class. Devices of this class can be connected and disconnected to/from
stm devices at runtime via a sysfs attribute.
stm devices at runtime via a sysfs attribute called "stm_source_link"
by writing the name of the desired stm device there, for example:
Examples of STM devices are Intel(R) Trace Hub [1] and Coresight STM
[2].
$ echo dummy_stm.0 > /sys/class/stm_source/console/stm_source_link
For examples on how to use stm_source interface in the kernel, refer
to stm_console or stm_heartbeat drivers.
Each stm_source device will need to assume a master and a range of
channels, depending on how many channels it requires. These are
allocated for the device according to the policy configuration. If
there's a node in the root of the policy directory that matches the
stm_source device's name (for example, "console"), this node will be
used to allocate master and channel numbers. If there's no such policy
node, the stm core will pick the first contiguous chunk of channels
within the first available master. Note that the node must exist
before the stm_source device is connected to its stm device.
stm_console
===========
One implementation of this interface also used in the example above is
the "stm_console" driver, which basically provides a one-way console
for kernel messages over an stm device.
To configure the master/channel pair that will be assigned to this
console in the STP stream, create a "console" policy entry (see the
beginning of this text on how to do that). When initialized, it will
consume one channel.
[1] https://software.intel.com/sites/default/files/managed/d3/3c/intel-th-developer-manual.pdf
[2] http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0444b/index.html
......@@ -3067,6 +3067,12 @@ F: drivers/usb/host/whci/
F: drivers/usb/wusbcore/
F: include/linux/usb/wusb*
HT16K33 LED CONTROLLER DRIVER
M: Robin van der Gracht <robin@protonic.nl>
S: Maintained
F: drivers/auxdisplay/ht16k33.c
F: Documentation/devicetree/bindings/display/ht16k33.txt
CFAG12864B LCD DRIVER
M: Miguel Ojeda Sandonis <miguel.ojeda.sandonis@gmail.com>
W: http://miguelojeda.es/auxdisplay.htm
......@@ -5043,7 +5049,9 @@ K: fmc_d.*register
FPGA MANAGER FRAMEWORK
M: Alan Tull <atull@opensource.altera.com>
R: Moritz Fischer <moritz.fischer@ettus.com>
L: linux-fpga@vger.kernel.org
S: Maintained
T: git git://git.kernel.org/pub/scm/linux/kernel/git/atull/linux-fpga.git
F: drivers/fpga/
F: include/linux/fpga/fpga-mgr.h
W: http://www.rocketboards.org
......@@ -5940,6 +5948,7 @@ F: drivers/input/serio/hyperv-keyboard.c
F: drivers/pci/host/pci-hyperv.c
F: drivers/net/hyperv/
F: drivers/scsi/storvsc_drv.c
F: drivers/uio/uio_hv_generic.c
F: drivers/video/fbdev/hyperv_fb.c
F: include/linux/hyperv.h
F: tools/hv/
......@@ -9231,7 +9240,7 @@ F: drivers/misc/panel.c
PARALLEL PORT SUBSYSTEM
M: Sudip Mukherjee <sudipm.mukherjee@gmail.com>
M: Sudip Mukherjee <sudip@vectorindia.org>
M: Sudip Mukherjee <sudip.mukherjee@codethink.co.uk>
L: linux-parport@lists.infradead.org (subscribers-only)
S: Maintained
F: drivers/parport/
......@@ -10841,6 +10850,11 @@ W: http://www.sunplus.com
S: Supported
F: arch/score/
SCR24X CHIP CARD INTERFACE DRIVER
M: Lubomir Rintel <lkundrak@v3.sk>
S: Supported
F: drivers/char/pcmcia/scr24x_cs.c
SYSTEM CONTROL & POWER INTERFACE (SCPI) Message Protocol drivers
M: Sudeep Holla <sudeep.holla@arm.com>
L: linux-arm-kernel@lists.infradead.org
......@@ -11244,7 +11258,7 @@ F: include/media/i2c/ov2659.h
SILICON MOTION SM712 FRAME BUFFER DRIVER
M: Sudip Mukherjee <sudipm.mukherjee@gmail.com>
M: Teddy Wang <teddy.wang@siliconmotion.com>
M: Sudip Mukherjee <sudip@vectorindia.org>
M: Sudip Mukherjee <sudip.mukherjee@codethink.co.uk>
L: linux-fbdev@vger.kernel.org
S: Maintained
F: drivers/video/fbdev/sm712*
......@@ -11672,7 +11686,7 @@ F: drivers/staging/rtl8712/
STAGING - SILICON MOTION SM750 FRAME BUFFER DRIVER
M: Sudip Mukherjee <sudipm.mukherjee@gmail.com>
M: Teddy Wang <teddy.wang@siliconmotion.com>
M: Sudip Mukherjee <sudip@vectorindia.org>
M: Sudip Mukherjee <sudip.mukherjee@codethink.co.uk>
L: linux-fbdev@vger.kernel.org
S: Maintained
F: drivers/staging/sm750fb/
......
/* Load firmware into Core B on a BF561
*
* Author: Bas Vermeulen <bvermeul@blackstar.xs4all.nl>
*
* Copyright 2004-2009 Analog Devices Inc.
* Licensed under the GPL-2 or later.
......@@ -14,9 +16,9 @@
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/miscdevice.h>
#include <linux/module.h>
#define CMD_COREB_START _IO('b', 0)
#define CMD_COREB_STOP _IO('b', 1)
......@@ -59,8 +61,4 @@ static struct miscdevice coreb_dev = {
.name = "coreb",
.fops = &coreb_fops,
};
module_misc_device(coreb_dev);
MODULE_AUTHOR("Bas Vermeulen <bvermeul@blackstar.xs4all.nl>");
MODULE_DESCRIPTION("BF561 Core B Support");
MODULE_LICENSE("GPL");
builtin_misc_device(coreb_dev);
......@@ -128,4 +128,17 @@ config IMG_ASCII_LCD
development boards such as the MIPS Boston, MIPS Malta & MIPS SEAD3
from Imagination Technologies.
config HT16K33
tristate "Holtek Ht16K33 LED controller with keyscan"
depends on FB && OF && I2C && INPUT
select FB_SYS_FOPS
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
select INPUT_MATRIXKMAP
select FB_BACKLIGHT
help
Say yes here to add support for Holtek HT16K33, RAM mapping 16*8
LED controller driver with keyscan.
endif # AUXDISPLAY
......@@ -5,3 +5,4 @@
obj-$(CONFIG_KS0108) += ks0108.o
obj-$(CONFIG_CFAG12864B) += cfag12864b.o cfag12864bfb.o
obj-$(CONFIG_IMG_ASCII_LCD) += img-ascii-lcd.o
obj-$(CONFIG_HT16K33) += ht16k33.o
This diff is collapsed.
......@@ -17,7 +17,6 @@ config DEVMEM
config DEVKMEM
bool "/dev/kmem virtual device support"
default y
help
Say Y here if you want to support the /dev/kmem device. The
/dev/kmem device is rarely used, but can be used for certain
......@@ -579,7 +578,7 @@ config DEVPORT
source "drivers/s390/char/Kconfig"
config TILE_SROM
bool "Character-device access via hypervisor to the Tilera SPI ROM"
tristate "Character-device access via hypervisor to the Tilera SPI ROM"
depends on TILE
default y
---help---
......
......@@ -43,6 +43,17 @@ config CARDMAN_4040
(http://www.omnikey.com/), or a current development version of OpenCT
(http://www.opensc-project.org/opensc).
config SCR24X
tristate "SCR24x Chip Card Interface support"
depends on PCMCIA
help
Enable support for the SCR24x PCMCIA Chip Card Interface.
To compile this driver as a module, choose M here.
The module will be called scr24x_cs..
If unsure say N.
config IPWIRELESS
tristate "IPWireless 3G UMTS PCMCIA card support"
depends on PCMCIA && NETDEVICES && TTY
......
......@@ -7,3 +7,4 @@
obj-$(CONFIG_SYNCLINK_CS) += synclink_cs.o
obj-$(CONFIG_CARDMAN_4000) += cm4000_cs.o
obj-$(CONFIG_CARDMAN_4040) += cm4040_cs.o
obj-$(CONFIG_SCR24X) += scr24x_cs.o
/*
* SCR24x PCMCIA Smart Card Reader Driver
*
* Copyright (C) 2005-2006 TL Sudheendran
* Copyright (C) 2016 Lubomir Rintel
*
* Derived from "scr24x_v4.2.6_Release.tar.gz" driver by TL Sudheendran.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/device.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/io.h>
#include <linux/uaccess.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/ds.h>
#define CCID_HEADER_SIZE 10
#define CCID_LENGTH_OFFSET 1
#define CCID_MAX_LEN 271
#define SCR24X_DATA(n) (1 + n)
#define SCR24X_CMD_STATUS 7
#define CMD_START 0x40
#define CMD_WRITE_BYTE 0x41
#define CMD_READ_BYTE 0x42
#define STATUS_BUSY 0x80
struct scr24x_dev {
struct device *dev;
struct cdev c_dev;
unsigned char buf[CCID_MAX_LEN];
int devno;
struct mutex lock;
struct kref refcnt;
u8 __iomem *regs;
};
#define SCR24X_DEVS 8
static DECLARE_BITMAP(scr24x_minors, SCR24X_DEVS);
static struct class *scr24x_class;
static dev_t scr24x_devt;
static void scr24x_delete(struct kref *kref)
{
struct scr24x_dev *dev = container_of(kref, struct scr24x_dev,
refcnt);
kfree(dev);
}
static int scr24x_wait_ready(struct scr24x_dev *dev)
{
u_char status;
int timeout = 100;
do {
status = ioread8(dev->regs + SCR24X_CMD_STATUS);
if (!(status & STATUS_BUSY))
return 0;
msleep(20);
} while (--timeout);
return -EIO;
}
static int scr24x_open(struct inode *inode, struct file *filp)
{
struct scr24x_dev *dev = container_of(inode->i_cdev,
struct scr24x_dev, c_dev);
kref_get(&dev->refcnt);
filp->private_data = dev;
return nonseekable_open(inode, filp);
}
static int scr24x_release(struct inode *inode, struct file *filp)
{
struct scr24x_dev *dev = filp->private_data;
/* We must not take the dev->lock here as scr24x_delete()
* might be called to remove the dev structure altogether.
* We don't need the lock anyway, since after the reference
* acquired in probe() is released in remove() the chrdev
* is already unregistered and noone can possibly acquire
* a reference via open() anymore. */
kref_put(&dev->refcnt, scr24x_delete);
return 0;
}
static int read_chunk(struct scr24x_dev *dev, size_t offset, size_t limit)
{
size_t i, y;
int ret;
for (i = offset; i < limit; i += 5) {
iowrite8(CMD_READ_BYTE, dev->regs + SCR24X_CMD_STATUS);
ret = scr24x_wait_ready(dev);
if (ret < 0)
return ret;
for (y = 0; y < 5 && i + y < limit; y++)
dev->buf[i + y] = ioread8(dev->regs + SCR24X_DATA(y));
}
return 0;
}
static ssize_t scr24x_read(struct file *filp, char __user *buf, size_t count,
loff_t *ppos)
{
struct scr24x_dev *dev = filp->private_data;
int ret;
int len;
if (count < CCID_HEADER_SIZE)
return -EINVAL;
if (mutex_lock_interruptible(&dev->lock))
return -ERESTARTSYS;
if (!dev->dev) {
ret = -ENODEV;
goto out;
}
ret = scr24x_wait_ready(dev);
if (ret < 0)
goto out;
len = CCID_HEADER_SIZE;
ret = read_chunk(dev, 0, len);
if (ret < 0)
goto out;
len += le32_to_cpu(*(__le32 *)(&dev->buf[CCID_LENGTH_OFFSET]));
if (len > sizeof(dev->buf)) {
ret = -EIO;
goto out;
}
ret = read_chunk(dev, CCID_HEADER_SIZE, len);
if (ret < 0)
goto out;
if (len < count)
count = len;
if (copy_to_user(buf, dev->buf, count)) {
ret = -EFAULT;
goto out;
}
ret = count;
out:
mutex_unlock(&dev->lock);
return ret;
}
static ssize_t scr24x_write(struct file *filp, const char __user *buf,
size_t count, loff_t *ppos)
{
struct scr24x_dev *dev = filp->private_data;
size_t i, y;
int ret;
if (mutex_lock_interruptible(&dev->lock))
return -ERESTARTSYS;
if (!dev->dev) {
ret = -ENODEV;
goto out;
}
if (count > sizeof(dev->buf)) {
ret = -EINVAL;
goto out;
}
if (copy_from_user(dev->buf, buf, count)) {
ret = -EFAULT;
goto out;
}
ret = scr24x_wait_ready(dev);
if (ret < 0)
goto out;
iowrite8(CMD_START, dev->regs + SCR24X_CMD_STATUS);
ret = scr24x_wait_ready(dev);
if (ret < 0)
goto out;
for (i = 0; i < count; i += 5) {
for (y = 0; y < 5 && i + y < count; y++)
iowrite8(dev->buf[i + y], dev->regs + SCR24X_DATA(y));
iowrite8(CMD_WRITE_BYTE, dev->regs + SCR24X_CMD_STATUS);
ret = scr24x_wait_ready(dev);
if (ret < 0)
goto out;
}
ret = count;
out:
mutex_unlock(&dev->lock);
return ret;
}
static const struct file_operations scr24x_fops = {
.owner = THIS_MODULE,
.read = scr24x_read,
.write = scr24x_write,
.open = scr24x_open,
.release = scr24x_release,
.llseek = no_llseek,
};
static int scr24x_config_check(struct pcmcia_device *link, void *priv_data)
{
if (resource_size(link->resource[PCMCIA_IOPORT_0]) != 0x11)
return -ENODEV;
return pcmcia_request_io(link);
}
static int scr24x_probe(struct pcmcia_device *link)
{
struct scr24x_dev *dev;
int ret;
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (!dev)
return -ENOMEM;
dev->devno = find_first_zero_bit(scr24x_minors, SCR24X_DEVS);
if (dev->devno >= SCR24X_DEVS) {
ret = -EBUSY;
goto err;
}
mutex_init(&dev->lock);
kref_init(&dev->refcnt);
link->priv = dev;
link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
ret = pcmcia_loop_config(link, scr24x_config_check, NULL);
if (ret < 0)
goto err;
dev->dev = &link->dev;
dev->regs = devm_ioport_map(&link->dev,
link->resource[PCMCIA_IOPORT_0]->start,
resource_size(link->resource[PCMCIA_IOPORT_0]));
if (!dev->regs) {
ret = -EIO;
goto err;
}
cdev_init(&dev->c_dev, &scr24x_fops);
dev->c_dev.owner = THIS_MODULE;
dev->c_dev.ops = &scr24x_fops;
ret = cdev_add(&dev->c_dev, MKDEV(MAJOR(scr24x_devt), dev->devno), 1);
if (ret < 0)
goto err;
ret = pcmcia_enable_device(link);
if (ret < 0) {
pcmcia_disable_device(link);
goto err;
}
device_create(scr24x_class, NULL, MKDEV(MAJOR(scr24x_devt), dev->devno),
NULL, "scr24x%d", dev->devno);
dev_info(&link->dev, "SCR24x Chip Card Interface\n");
return 0;
err:
if (dev->devno < SCR24X_DEVS)
clear_bit(dev->devno, scr24x_minors);
kfree (dev);
return ret;
}
static void scr24x_remove(struct pcmcia_device *link)
{
struct scr24x_dev *dev = (struct scr24x_dev *)link->priv;
device_destroy(scr24x_class, MKDEV(MAJOR(scr24x_devt), dev->devno));
mutex_lock(&dev->lock);
pcmcia_disable_device(link);
cdev_del(&dev->c_dev);
clear_bit(dev->devno, scr24x_minors);
dev->dev = NULL;
mutex_unlock(&dev->lock);
kref_put(&dev->refcnt, scr24x_delete);
}
static const struct pcmcia_device_id scr24x_ids[] = {
PCMCIA_DEVICE_PROD_ID12("HP", "PC Card Smart Card Reader",
0x53cb94f9, 0xbfdf89a5),
PCMCIA_DEVICE_PROD_ID1("SCR241 PCMCIA", 0x6271efa3),
PCMCIA_DEVICE_PROD_ID1("SCR243 PCMCIA", 0x2054e8de),
PCMCIA_DEVICE_PROD_ID1("SCR24x PCMCIA", 0x54a33665),
PCMCIA_DEVICE_NULL
};
MODULE_DEVICE_TABLE(pcmcia, scr24x_ids);
static struct pcmcia_driver scr24x_driver = {
.owner = THIS_MODULE,
.name = "scr24x_cs",
.probe = scr24x_probe,
.remove = scr24x_remove,
.id_table = scr24x_ids,
};
static int __init scr24x_init(void)
{
int ret;
scr24x_class = class_create(THIS_MODULE, "scr24x");
if (IS_ERR(scr24x_class))
return PTR_ERR(scr24x_class);
ret = alloc_chrdev_region(&scr24x_devt, 0, SCR24X_DEVS, "scr24x");
if (ret < 0) {
class_destroy(scr24x_class);
return ret;
}
ret = pcmcia_register_driver(&scr24x_driver);
if (ret < 0) {
unregister_chrdev_region(scr24x_devt, SCR24X_DEVS);
class_destroy(scr24x_class);
}
return ret;
}
static void __exit scr24x_exit(void)
{
pcmcia_unregister_driver(&scr24x_driver);
unregister_chrdev_region(scr24x_devt, SCR24X_DEVS);
class_destroy(scr24x_class);
}
module_init(scr24x_init);
module_exit(scr24x_exit);
MODULE_AUTHOR("Lubomir Rintel");
MODULE_DESCRIPTION("SCR24x PCMCIA Smart Card Reader Driver");
MODULE_LICENSE("GPL");
......@@ -86,6 +86,9 @@ struct pp_struct {
long default_inactivity;
};
/* should we use PARDEVICE_MAX here? */
static struct device *devices[PARPORT_MAX];
/* pp_struct.flags bitfields */
#define PP_CLAIMED (1<<0)
#define PP_EXCL (1<<1)
......@@ -294,7 +297,7 @@ static int register_device(int minor, struct pp_struct *pp)
port = parport_find_number(minor);
if (!port) {
printk(KERN_WARNING "%s: no associated port!\n", name);
pr_warn("%s: no associated port!\n", name);
kfree(name);
return -ENXIO;
}
......@@ -305,10 +308,10 @@ static int register_device(int minor, struct pp_struct *pp)
ppdev_cb.private = pp;
pdev = parport_register_dev_model(port, name, &ppdev_cb, minor);
parport_put_port(port);
kfree(name);
if (!pdev) {
printk(KERN_WARNING "%s: failed to register device!\n", name);
kfree(name);
pr_warn("%s: failed to register device!\n", name);
return -ENXIO;
}
......@@ -789,13 +792,29 @@ static const struct file_operations pp_fops = {
static void pp_attach(struct parport *port)
{
device_create(ppdev_class, port->dev, MKDEV(PP_MAJOR, port->number),
NULL, "parport%d", port->number);
struct device *ret;
if (devices[port->number])
return;
ret = device_create(ppdev_class, port->dev,
MKDEV(PP_MAJOR, port->number), NULL,
"parport%d", port->number);
if (IS_ERR(ret)) {
pr_err("Failed to create device parport%d\n",
port->number);
return;
}
devices[port->number] = ret;
}
static void pp_detach(struct parport *port)
{
if (!devices[port->number])
return;
device_destroy(ppdev_class, MKDEV(PP_MAJOR, port->number));
devices[port->number] = NULL;
}
static int pp_probe(struct pardevice *par_dev)
......@@ -822,8 +841,7 @@ static int __init ppdev_init(void)
int err = 0;
if (register_chrdev(PP_MAJOR, CHRDEV, &pp_fops)) {
printk(KERN_WARNING CHRDEV ": unable to get major %d\n",
PP_MAJOR);
pr_warn(CHRDEV ": unable to get major %d\n", PP_MAJOR);
return -EIO;
}
ppdev_class = class_create(THIS_MODULE, CHRDEV);
......@@ -833,11 +851,11 @@ static int __init ppdev_init(void)
}
err = parport_register_driver(&pp_driver);
if (err < 0) {
printk(KERN_WARNING CHRDEV ": unable to register with parport\n");
pr_warn(CHRDEV ": unable to register with parport\n");
goto out_class;
}
printk(KERN_INFO PP_VERSION "\n");
pr_info(PP_VERSION "\n");
goto out;
out_class:
......
......@@ -285,7 +285,7 @@ scdrv_write(struct file *file, const char __user *buf,
DECLARE_WAITQUEUE(wait, current);
if (file->f_flags & O_NONBLOCK) {
spin_unlock(&sd->sd_wlock);
spin_unlock_irqrestore(&sd->sd_wlock, flags);
up(&sd->sd_wbs);
return -EAGAIN;
}
......
......@@ -312,7 +312,8 @@ ATTRIBUTE_GROUPS(srom_dev);
static char *srom_devnode(struct device *dev, umode_t *mode)
{
*mode = S_IRUGO | S_IWUSR;
if (mode)
*mode = 0644;
return kasprintf(GFP_KERNEL, "srom/%s", dev_name(dev));
}
......
......@@ -13,12 +13,26 @@ config FPGA
if FPGA
config FPGA_REGION
tristate "FPGA Region"
depends on OF && FPGA_BRIDGE
help
FPGA Regions allow loading FPGA images under control of
the Device Tree.
config FPGA_MGR_SOCFPGA
tristate "Altera SOCFPGA FPGA Manager"
depends on ARCH_SOCFPGA
depends on ARCH_SOCFPGA || COMPILE_TEST
help
FPGA manager driver support for Altera SOCFPGA.
config FPGA_MGR_SOCFPGA_A10
tristate "Altera SoCFPGA Arria10"
depends on ARCH_SOCFPGA || COMPILE_TEST
select REGMAP_MMIO
help
FPGA manager driver support for Altera Arria10 SoCFPGA.
config FPGA_MGR_ZYNQ_FPGA
tristate "Xilinx Zynq FPGA"
depends on ARCH_ZYNQ || COMPILE_TEST
......@@ -26,6 +40,29 @@ config FPGA_MGR_ZYNQ_FPGA
help
FPGA manager driver support for Xilinx Zynq FPGAs.
config FPGA_BRIDGE
tristate "FPGA Bridge Framework"
depends on OF
help
Say Y here if you want to support bridges connected between host
processors and FPGAs or between FPGAs.
config SOCFPGA_FPGA_BRIDGE
tristate "Altera SoCFPGA FPGA Bridges"
depends on ARCH_SOCFPGA && FPGA_BRIDGE
help
Say Y to enable drivers for FPGA bridges for Altera SOCFPGA
devices.
config ALTERA_FREEZE_BRIDGE
tristate "Altera FPGA Freeze Bridge"
depends on ARCH_SOCFPGA && FPGA_BRIDGE
help
Say Y to enable drivers for Altera FPGA Freeze bridges. A
freeze bridge is a bridge that exists in the FPGA fabric to
isolate one region of the FPGA from the busses while that
region is being reprogrammed.
endif # FPGA
endmenu
......@@ -7,4 +7,13 @@ obj-$(CONFIG_FPGA) += fpga-mgr.o
# FPGA Manager Drivers
obj-$(CONFIG_FPGA_MGR_SOCFPGA) += socfpga.o
obj-$(CONFIG_FPGA_MGR_SOCFPGA_A10) += socfpga-a10.o
obj-$(CONFIG_FPGA_MGR_ZYNQ_FPGA) += zynq-fpga.o
# FPGA Bridge Drivers
obj-$(CONFIG_FPGA_BRIDGE) += fpga-bridge.o
obj-$(CONFIG_SOCFPGA_FPGA_BRIDGE) += altera-hps2fpga.o altera-fpga2sdram.o
obj-$(CONFIG_ALTERA_FREEZE_BRIDGE) += altera-freeze-bridge.o
# High Level Interfaces
obj-$(CONFIG_FPGA_REGION) += fpga-region.o
/*
* FPGA to SDRAM Bridge Driver for Altera SoCFPGA Devices
*
* Copyright (C) 2013-2016 Altera Corporation, All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* This driver manages a bridge between an FPGA and the SDRAM used by the ARM
* host processor system (HPS).
*
* The bridge contains 4 read ports, 4 write ports, and 6 command ports.
* Reconfiguring these ports requires that no SDRAM transactions occur during
* reconfiguration. The code reconfiguring the ports cannot run out of SDRAM
* nor can the FPGA access the SDRAM during reconfiguration. This driver does
* not support reconfiguring the ports. The ports are configured by code
* running out of on chip ram before Linux is started and the configuration
* is passed in a handoff register in the system manager.
*
* This driver supports enabling and disabling of the configured ports, which
* allows for safe reprogramming of the FPGA, assuming that the new FPGA image
* uses the same port configuration. Bridges must be disabled before
* reprogramming the FPGA and re-enabled after the FPGA has been programmed.
*/
#include <linux/fpga/fpga-bridge.h>
#include <linux/kernel.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of_platform.h>
#include <linux/regmap.h>
#define ALT_SDR_CTL_FPGAPORTRST_OFST 0x80
#define ALT_SDR_CTL_FPGAPORTRST_PORTRSTN_MSK 0x00003fff
#define ALT_SDR_CTL_FPGAPORTRST_RD_SHIFT 0
#define ALT_SDR_CTL_FPGAPORTRST_WR_SHIFT 4
#define ALT_SDR_CTL_FPGAPORTRST_CTRL_SHIFT 8
/*
* From the Cyclone V HPS Memory Map document:
* These registers are used to store handoff information between the
* preloader and the OS. These 8 registers can be used to store any
* information. The contents of these registers have no impact on
* the state of the HPS hardware.
*/
#define SYSMGR_ISWGRP_HANDOFF3 (0x8C)
#define F2S_BRIDGE_NAME "fpga2sdram"
struct alt_fpga2sdram_data {
struct device *dev;
struct regmap *sdrctl;
int mask;
};
static int alt_fpga2sdram_enable_show(struct fpga_bridge *bridge)
{
struct alt_fpga2sdram_data *priv = bridge->priv;
int value;
regmap_read(priv->sdrctl, ALT_SDR_CTL_FPGAPORTRST_OFST, &value);
return (value & priv->mask) == priv->mask;
}
static inline int _alt_fpga2sdram_enable_set(struct alt_fpga2sdram_data *priv,
bool enable)
{
return regmap_update_bits(priv->sdrctl, ALT_SDR_CTL_FPGAPORTRST_OFST,
priv->mask, enable ? priv->mask : 0);
}
static int alt_fpga2sdram_enable_set(struct fpga_bridge *bridge, bool enable)
{
return _alt_fpga2sdram_enable_set(bridge->priv, enable);
}
struct prop_map {
char *prop_name;
u32 *prop_value;
u32 prop_max;
};
static const struct fpga_bridge_ops altera_fpga2sdram_br_ops = {
.enable_set = alt_fpga2sdram_enable_set,
.enable_show = alt_fpga2sdram_enable_show,
};
static const struct of_device_id altera_fpga_of_match[] = {
{ .compatible = "altr,socfpga-fpga2sdram-bridge" },
{},
};
static int alt_fpga_bridge_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct alt_fpga2sdram_data *priv;
u32 enable;
struct regmap *sysmgr;
int ret = 0;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->dev = dev;
priv->sdrctl = syscon_regmap_lookup_by_compatible("altr,sdr-ctl");
if (IS_ERR(priv->sdrctl)) {
dev_err(dev, "regmap for altr,sdr-ctl lookup failed.\n");
return PTR_ERR(priv->sdrctl);
}
sysmgr = syscon_regmap_lookup_by_compatible("altr,sys-mgr");
if (IS_ERR(sysmgr)) {
dev_err(dev, "regmap for altr,sys-mgr lookup failed.\n");
return PTR_ERR(sysmgr);
}
/* Get f2s bridge configuration saved in handoff register */
regmap_read(sysmgr, SYSMGR_ISWGRP_HANDOFF3, &priv->mask);
ret = fpga_bridge_register(dev, F2S_BRIDGE_NAME,
&altera_fpga2sdram_br_ops, priv);
if (ret)
return ret;
dev_info(dev, "driver initialized with handoff %08x\n", priv->mask);
if (!of_property_read_u32(dev->of_node, "bridge-enable", &enable)) {
if (enable > 1) {
dev_warn(dev, "invalid bridge-enable %u > 1\n", enable);
} else {
dev_info(dev, "%s bridge\n",
(enable ? "enabling" : "disabling"));
ret = _alt_fpga2sdram_enable_set(priv, enable);
if (ret) {
fpga_bridge_unregister(&pdev->dev);
return ret;
}
}
}
return ret;
}
static int alt_fpga_bridge_remove(struct platform_device *pdev)
{
fpga_bridge_unregister(&pdev->dev);
return 0;
}
MODULE_DEVICE_TABLE(of, altera_fpga_of_match);
static struct platform_driver altera_fpga_driver = {
.probe = alt_fpga_bridge_probe,
.remove = alt_fpga_bridge_remove,
.driver = {
.name = "altera_fpga2sdram_bridge",
.of_match_table = of_match_ptr(altera_fpga_of_match),
},
};
module_platform_driver(altera_fpga_driver);
MODULE_DESCRIPTION("Altera SoCFPGA FPGA to SDRAM Bridge");
MODULE_AUTHOR("Alan Tull <atull@opensource.altera.com>");
MODULE_LICENSE("GPL v2");
/*
* FPGA Freeze Bridge Controller
*
* Copyright (C) 2016 Altera Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/of_device.h>
#include <linux/module.h>
#include <linux/fpga/fpga-bridge.h>
#define FREEZE_CSR_STATUS_OFFSET 0
#define FREEZE_CSR_CTRL_OFFSET 4
#define FREEZE_CSR_ILLEGAL_REQ_OFFSET 8
#define FREEZE_CSR_REG_VERSION 12
#define FREEZE_CSR_SUPPORTED_VERSION 2
#define FREEZE_CSR_STATUS_FREEZE_REQ_DONE BIT(0)
#define FREEZE_CSR_STATUS_UNFREEZE_REQ_DONE BIT(1)
#define FREEZE_CSR_CTRL_FREEZE_REQ BIT(0)
#define FREEZE_CSR_CTRL_RESET_REQ BIT(1)
#define FREEZE_CSR_CTRL_UNFREEZE_REQ BIT(2)
#define FREEZE_BRIDGE_NAME "freeze"
struct altera_freeze_br_data {
struct device *dev;
void __iomem *base_addr;
bool enable;
};
/*
* Poll status until status bit is set or we have a timeout.
*/
static int altera_freeze_br_req_ack(struct altera_freeze_br_data *priv,
u32 timeout, u32 req_ack)
{
struct device *dev = priv->dev;
void __iomem *csr_illegal_req_addr = priv->base_addr +
FREEZE_CSR_ILLEGAL_REQ_OFFSET;
u32 status, illegal, ctrl;
int ret = -ETIMEDOUT;
do {
illegal = readl(csr_illegal_req_addr);
if (illegal) {
dev_err(dev, "illegal request detected 0x%x", illegal);
writel(1, csr_illegal_req_addr);
illegal = readl(csr_illegal_req_addr);
if (illegal)
dev_err(dev, "illegal request not cleared 0x%x",
illegal);
ret = -EINVAL;
break;
}
status = readl(priv->base_addr + FREEZE_CSR_STATUS_OFFSET);
dev_dbg(dev, "%s %x %x\n", __func__, status, req_ack);
status &= req_ack;
if (status) {
ctrl = readl(priv->base_addr + FREEZE_CSR_CTRL_OFFSET);
dev_dbg(dev, "%s request %x acknowledged %x %x\n",
__func__, req_ack, status, ctrl);
ret = 0;
break;
}
udelay(1);
} while (timeout--);
if (ret == -ETIMEDOUT)
dev_err(dev, "%s timeout waiting for 0x%x\n",
__func__, req_ack);
return ret;
}
static int altera_freeze_br_do_freeze(struct altera_freeze_br_data *priv,
u32 timeout)
{
struct device *dev = priv->dev;
void __iomem *csr_ctrl_addr = priv->base_addr +
FREEZE_CSR_CTRL_OFFSET;
u32 status;
int ret;
status = readl(priv->base_addr + FREEZE_CSR_STATUS_OFFSET);
dev_dbg(dev, "%s %d %d\n", __func__, status, readl(csr_ctrl_addr));
if (status & FREEZE_CSR_STATUS_FREEZE_REQ_DONE) {
dev_dbg(dev, "%s bridge already disabled %d\n",
__func__, status);
return 0;
} else if (!(status & FREEZE_CSR_STATUS_UNFREEZE_REQ_DONE)) {
dev_err(dev, "%s bridge not enabled %d\n", __func__, status);
return -EINVAL;
}
writel(FREEZE_CSR_CTRL_FREEZE_REQ, csr_ctrl_addr);
ret = altera_freeze_br_req_ack(priv, timeout,
FREEZE_CSR_STATUS_FREEZE_REQ_DONE);
if (ret)
writel(0, csr_ctrl_addr);
else
writel(FREEZE_CSR_CTRL_RESET_REQ, csr_ctrl_addr);
return ret;
}
static int altera_freeze_br_do_unfreeze(struct altera_freeze_br_data *priv,
u32 timeout)
{
struct device *dev = priv->dev;
void __iomem *csr_ctrl_addr = priv->base_addr +
FREEZE_CSR_CTRL_OFFSET;
u32 status;
int ret;
writel(0, csr_ctrl_addr);
status = readl(priv->base_addr + FREEZE_CSR_STATUS_OFFSET);
dev_dbg(dev, "%s %d %d\n", __func__, status, readl(csr_ctrl_addr));
if (status & FREEZE_CSR_STATUS_UNFREEZE_REQ_DONE) {
dev_dbg(dev, "%s bridge already enabled %d\n",
__func__, status);
return 0;
} else if (!(status & FREEZE_CSR_STATUS_FREEZE_REQ_DONE)) {
dev_err(dev, "%s bridge not frozen %d\n", __func__, status);
return -EINVAL;
}
writel(FREEZE_CSR_CTRL_UNFREEZE_REQ, csr_ctrl_addr);
ret = altera_freeze_br_req_ack(priv, timeout,
FREEZE_CSR_STATUS_UNFREEZE_REQ_DONE);
status = readl(priv->base_addr + FREEZE_CSR_STATUS_OFFSET);
dev_dbg(dev, "%s %d %d\n", __func__, status, readl(csr_ctrl_addr));
writel(0, csr_ctrl_addr);
return ret;
}
/*
* enable = 1 : allow traffic through the bridge
* enable = 0 : disable traffic through the bridge
*/
static int altera_freeze_br_enable_set(struct fpga_bridge *bridge,
bool enable)
{
struct altera_freeze_br_data *priv = bridge->priv;
struct fpga_image_info *info = bridge->info;
u32 timeout = 0;
int ret;
if (enable) {
if (info)
timeout = info->enable_timeout_us;
ret = altera_freeze_br_do_unfreeze(bridge->priv, timeout);
} else {
if (info)
timeout = info->disable_timeout_us;
ret = altera_freeze_br_do_freeze(bridge->priv, timeout);
}
if (!ret)
priv->enable = enable;
return ret;
}
static int altera_freeze_br_enable_show(struct fpga_bridge *bridge)
{
struct altera_freeze_br_data *priv = bridge->priv;
return priv->enable;
}
static struct fpga_bridge_ops altera_freeze_br_br_ops = {
.enable_set = altera_freeze_br_enable_set,
.enable_show = altera_freeze_br_enable_show,
};
static const struct of_device_id altera_freeze_br_of_match[] = {
{ .compatible = "altr,freeze-bridge-controller", },
{},
};
MODULE_DEVICE_TABLE(of, altera_freeze_br_of_match);
static int altera_freeze_br_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *np = pdev->dev.of_node;
struct altera_freeze_br_data *priv;
struct resource *res;
u32 status, revision;
if (!np)
return -ENODEV;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->dev = dev;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
priv->base_addr = devm_ioremap_resource(dev, res);
if (IS_ERR(priv->base_addr))
return PTR_ERR(priv->base_addr);
status = readl(priv->base_addr + FREEZE_CSR_STATUS_OFFSET);
if (status & FREEZE_CSR_STATUS_UNFREEZE_REQ_DONE)
priv->enable = 1;
revision = readl(priv->base_addr + FREEZE_CSR_REG_VERSION);
if (revision != FREEZE_CSR_SUPPORTED_VERSION)
dev_warn(dev,
"%s Freeze Controller unexpected revision %d != %d\n",
__func__, revision, FREEZE_CSR_SUPPORTED_VERSION);
return fpga_bridge_register(dev, FREEZE_BRIDGE_NAME,
&altera_freeze_br_br_ops, priv);
}
static int altera_freeze_br_remove(struct platform_device *pdev)
{
fpga_bridge_unregister(&pdev->dev);
return 0;
}
static struct platform_driver altera_freeze_br_driver = {
.probe = altera_freeze_br_probe,
.remove = altera_freeze_br_remove,
.driver = {
.name = "altera_freeze_br",
.of_match_table = of_match_ptr(altera_freeze_br_of_match),
},
};
module_platform_driver(altera_freeze_br_driver);
MODULE_DESCRIPTION("Altera Freeze Bridge");
MODULE_AUTHOR("Alan Tull <atull@opensource.altera.com>");
MODULE_LICENSE("GPL v2");
/*
* FPGA to/from HPS Bridge Driver for Altera SoCFPGA Devices
*
* Copyright (C) 2013-2016 Altera Corporation, All Rights Reserved.
*
* Includes this patch from the mailing list:
* fpga: altera-hps2fpga: fix HPS2FPGA bridge visibility to L3 masters
* Signed-off-by: Anatolij Gustschin <agust@denx.de>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* This driver manages bridges on a Altera SOCFPGA between the ARM host
* processor system (HPS) and the embedded FPGA.
*
* This driver supports enabling and disabling of the configured ports, which
* allows for safe reprogramming of the FPGA, assuming that the new FPGA image
* uses the same port configuration. Bridges must be disabled before
* reprogramming the FPGA and re-enabled after the FPGA has been programmed.
*/
#include <linux/clk.h>
#include <linux/fpga/fpga-bridge.h>
#include <linux/kernel.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of_platform.h>
#include <linux/regmap.h>
#include <linux/reset.h>
#include <linux/spinlock.h>
#define ALT_L3_REMAP_OFST 0x0
#define ALT_L3_REMAP_MPUZERO_MSK 0x00000001
#define ALT_L3_REMAP_H2F_MSK 0x00000008
#define ALT_L3_REMAP_LWH2F_MSK 0x00000010
#define HPS2FPGA_BRIDGE_NAME "hps2fpga"
#define LWHPS2FPGA_BRIDGE_NAME "lwhps2fpga"
#define FPGA2HPS_BRIDGE_NAME "fpga2hps"
struct altera_hps2fpga_data {
const char *name;
struct reset_control *bridge_reset;
struct regmap *l3reg;
unsigned int remap_mask;
struct clk *clk;
};
static int alt_hps2fpga_enable_show(struct fpga_bridge *bridge)
{
struct altera_hps2fpga_data *priv = bridge->priv;
return reset_control_status(priv->bridge_reset);
}
/* The L3 REMAP register is write only, so keep a cached value. */
static unsigned int l3_remap_shadow;
static spinlock_t l3_remap_lock;
static int _alt_hps2fpga_enable_set(struct altera_hps2fpga_data *priv,
bool enable)
{
unsigned long flags;
int ret;
/* bring bridge out of reset */
if (enable)
ret = reset_control_deassert(priv->bridge_reset);
else
ret = reset_control_assert(priv->bridge_reset);
if (ret)
return ret;
/* Allow bridge to be visible to L3 masters or not */
if (priv->remap_mask) {
spin_lock_irqsave(&l3_remap_lock, flags);
l3_remap_shadow |= ALT_L3_REMAP_MPUZERO_MSK;
if (enable)
l3_remap_shadow |= priv->remap_mask;
else
l3_remap_shadow &= ~priv->remap_mask;
ret = regmap_write(priv->l3reg, ALT_L3_REMAP_OFST,
l3_remap_shadow);
spin_unlock_irqrestore(&l3_remap_lock, flags);
}
return ret;
}
static int alt_hps2fpga_enable_set(struct fpga_bridge *bridge, bool enable)
{
return _alt_hps2fpga_enable_set(bridge->priv, enable);
}
static const struct fpga_bridge_ops altera_hps2fpga_br_ops = {
.enable_set = alt_hps2fpga_enable_set,
.enable_show = alt_hps2fpga_enable_show,
};
static struct altera_hps2fpga_data hps2fpga_data = {
.name = HPS2FPGA_BRIDGE_NAME,
.remap_mask = ALT_L3_REMAP_H2F_MSK,
};
static struct altera_hps2fpga_data lwhps2fpga_data = {
.name = LWHPS2FPGA_BRIDGE_NAME,
.remap_mask = ALT_L3_REMAP_LWH2F_MSK,
};
static struct altera_hps2fpga_data fpga2hps_data = {
.name = FPGA2HPS_BRIDGE_NAME,
};
static const struct of_device_id altera_fpga_of_match[] = {
{ .compatible = "altr,socfpga-hps2fpga-bridge",
.data = &hps2fpga_data },
{ .compatible = "altr,socfpga-lwhps2fpga-bridge",
.data = &lwhps2fpga_data },
{ .compatible = "altr,socfpga-fpga2hps-bridge",
.data = &fpga2hps_data },
{},
};
static int alt_fpga_bridge_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct altera_hps2fpga_data *priv;
const struct of_device_id *of_id;
u32 enable;
int ret;
of_id = of_match_device(altera_fpga_of_match, dev);
priv = (struct altera_hps2fpga_data *)of_id->data;
priv->bridge_reset = of_reset_control_get_by_index(dev->of_node, 0);
if (IS_ERR(priv->bridge_reset)) {
dev_err(dev, "Could not get %s reset control\n", priv->name);
return PTR_ERR(priv->bridge_reset);
}
if (priv->remap_mask) {
priv->l3reg = syscon_regmap_lookup_by_compatible("altr,l3regs");
if (IS_ERR(priv->l3reg)) {
dev_err(dev, "regmap for altr,l3regs lookup failed\n");
return PTR_ERR(priv->l3reg);
}
}
priv->clk = devm_clk_get(dev, NULL);
if (IS_ERR(priv->clk)) {
dev_err(dev, "no clock specified\n");
return PTR_ERR(priv->clk);
}
ret = clk_prepare_enable(priv->clk);
if (ret) {
dev_err(dev, "could not enable clock\n");
return -EBUSY;
}
spin_lock_init(&l3_remap_lock);
if (!of_property_read_u32(dev->of_node, "bridge-enable", &enable)) {
if (enable > 1) {
dev_warn(dev, "invalid bridge-enable %u > 1\n", enable);
} else {
dev_info(dev, "%s bridge\n",
(enable ? "enabling" : "disabling"));
ret = _alt_hps2fpga_enable_set(priv, enable);
if (ret) {
fpga_bridge_unregister(&pdev->dev);
return ret;
}
}
}
return fpga_bridge_register(dev, priv->name, &altera_hps2fpga_br_ops,
priv);
}
static int alt_fpga_bridge_remove(struct platform_device *pdev)
{
struct fpga_bridge *bridge = platform_get_drvdata(pdev);
struct altera_hps2fpga_data *priv = bridge->priv;
fpga_bridge_unregister(&pdev->dev);
clk_disable_unprepare(priv->clk);
return 0;
}
MODULE_DEVICE_TABLE(of, altera_fpga_of_match);
static struct platform_driver alt_fpga_bridge_driver = {
.probe = alt_fpga_bridge_probe,
.remove = alt_fpga_bridge_remove,
.driver = {
.name = "altera_hps2fpga_bridge",
.of_match_table = of_match_ptr(altera_fpga_of_match),
},
};
module_platform_driver(alt_fpga_bridge_driver);
MODULE_DESCRIPTION("Altera SoCFPGA HPS to FPGA Bridge");
MODULE_AUTHOR("Alan Tull <atull@opensource.altera.com>");
MODULE_LICENSE("GPL v2");
/*
* FPGA Bridge Framework Driver
*
* Copyright (C) 2013-2016 Altera Corporation, All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/fpga/fpga-bridge.h>
#include <linux/idr.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_platform.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
static DEFINE_IDA(fpga_bridge_ida);
static struct class *fpga_bridge_class;
/* Lock for adding/removing bridges to linked lists*/
spinlock_t bridge_list_lock;
static int fpga_bridge_of_node_match(struct device *dev, const void *data)
{
return dev->of_node == data;
}
/**
* fpga_bridge_enable - Enable transactions on the bridge
*
* @bridge: FPGA bridge
*
* Return: 0 for success, error code otherwise.
*/
int fpga_bridge_enable(struct fpga_bridge *bridge)
{
dev_dbg(&bridge->dev, "enable\n");
if (bridge->br_ops && bridge->br_ops->enable_set)
return bridge->br_ops->enable_set(bridge, 1);
return 0;
}
EXPORT_SYMBOL_GPL(fpga_bridge_enable);
/**
* fpga_bridge_disable - Disable transactions on the bridge
*
* @bridge: FPGA bridge
*
* Return: 0 for success, error code otherwise.
*/
int fpga_bridge_disable(struct fpga_bridge *bridge)
{
dev_dbg(&bridge->dev, "disable\n");
if (bridge->br_ops && bridge->br_ops->enable_set)
return bridge->br_ops->enable_set(bridge, 0);
return 0;
}
EXPORT_SYMBOL_GPL(fpga_bridge_disable);
/**
* of_fpga_bridge_get - get an exclusive reference to a fpga bridge
*
* @np: node pointer of a FPGA bridge
* @info: fpga image specific information
*
* Return fpga_bridge struct if successful.
* Return -EBUSY if someone already has a reference to the bridge.
* Return -ENODEV if @np is not a FPGA Bridge.
*/
struct fpga_bridge *of_fpga_bridge_get(struct device_node *np,
struct fpga_image_info *info)
{
struct device *dev;
struct fpga_bridge *bridge;
int ret = -ENODEV;
dev = class_find_device(fpga_bridge_class, NULL, np,
fpga_bridge_of_node_match);
if (!dev)
goto err_dev;
bridge = to_fpga_bridge(dev);
if (!bridge)
goto err_dev;
bridge->info = info;
if (!mutex_trylock(&bridge->mutex)) {
ret = -EBUSY;
goto err_dev;
}
if (!try_module_get(dev->parent->driver->owner))
goto err_ll_mod;
dev_dbg(&bridge->dev, "get\n");
return bridge;
err_ll_mod:
mutex_unlock(&bridge->mutex);
err_dev:
put_device(dev);
return ERR_PTR(ret);
}
EXPORT_SYMBOL_GPL(of_fpga_bridge_get);
/**
* fpga_bridge_put - release a reference to a bridge
*
* @bridge: FPGA bridge
*/
void fpga_bridge_put(struct fpga_bridge *bridge)
{
dev_dbg(&bridge->dev, "put\n");
bridge->info = NULL;
module_put(bridge->dev.parent->driver->owner);
mutex_unlock(&bridge->mutex);
put_device(&bridge->dev);
}
EXPORT_SYMBOL_GPL(fpga_bridge_put);
/**
* fpga_bridges_enable - enable bridges in a list
* @bridge_list: list of FPGA bridges
*
* Enable each bridge in the list. If list is empty, do nothing.
*
* Return 0 for success or empty bridge list; return error code otherwise.
*/
int fpga_bridges_enable(struct list_head *bridge_list)
{
struct fpga_bridge *bridge;
struct list_head *node;
int ret;
list_for_each(node, bridge_list) {
bridge = list_entry(node, struct fpga_bridge, node);
ret = fpga_bridge_enable(bridge);
if (ret)
return ret;
}
return 0;
}
EXPORT_SYMBOL_GPL(fpga_bridges_enable);
/**
* fpga_bridges_disable - disable bridges in a list
*
* @bridge_list: list of FPGA bridges
*
* Disable each bridge in the list. If list is empty, do nothing.
*
* Return 0 for success or empty bridge list; return error code otherwise.
*/
int fpga_bridges_disable(struct list_head *bridge_list)
{
struct fpga_bridge *bridge;
struct list_head *node;
int ret;
list_for_each(node, bridge_list) {
bridge = list_entry(node, struct fpga_bridge, node);
ret = fpga_bridge_disable(bridge);
if (ret)
return ret;
}
return 0;
}
EXPORT_SYMBOL_GPL(fpga_bridges_disable);
/**
* fpga_bridges_put - put bridges
*
* @bridge_list: list of FPGA bridges
*
* For each bridge in the list, put the bridge and remove it from the list.
* If list is empty, do nothing.
*/
void fpga_bridges_put(struct list_head *bridge_list)
{
struct fpga_bridge *bridge;
struct list_head *node, *next;
unsigned long flags;
list_for_each_safe(node, next, bridge_list) {
bridge = list_entry(node, struct fpga_bridge, node);
fpga_bridge_put(bridge);
spin_lock_irqsave(&bridge_list_lock, flags);
list_del(&bridge->node);
spin_unlock_irqrestore(&bridge_list_lock, flags);
}
}
EXPORT_SYMBOL_GPL(fpga_bridges_put);
/**
* fpga_bridges_get_to_list - get a bridge, add it to a list
*
* @np: node pointer of a FPGA bridge
* @info: fpga image specific information
* @bridge_list: list of FPGA bridges
*
* Get an exclusive reference to the bridge and and it to the list.
*
* Return 0 for success, error code from of_fpga_bridge_get() othewise.
*/
int fpga_bridge_get_to_list(struct device_node *np,
struct fpga_image_info *info,
struct list_head *bridge_list)
{
struct fpga_bridge *bridge;
unsigned long flags;
bridge = of_fpga_bridge_get(np, info);
if (IS_ERR(bridge))
return PTR_ERR(bridge);
spin_lock_irqsave(&bridge_list_lock, flags);
list_add(&bridge->node, bridge_list);
spin_unlock_irqrestore(&bridge_list_lock, flags);
return 0;
}
EXPORT_SYMBOL_GPL(fpga_bridge_get_to_list);
static ssize_t name_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct fpga_bridge *bridge = to_fpga_bridge(dev);
return sprintf(buf, "%s\n", bridge->name);
}
static ssize_t state_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct fpga_bridge *bridge = to_fpga_bridge(dev);
int enable = 1;
if (bridge->br_ops && bridge->br_ops->enable_show)
enable = bridge->br_ops->enable_show(bridge);
return sprintf(buf, "%s\n", enable ? "enabled" : "disabled");
}
static DEVICE_ATTR_RO(name);
static DEVICE_ATTR_RO(state);
static struct attribute *fpga_bridge_attrs[] = {
&dev_attr_name.attr,
&dev_attr_state.attr,
NULL,
};
ATTRIBUTE_GROUPS(fpga_bridge);
/**
* fpga_bridge_register - register a fpga bridge driver
* @dev: FPGA bridge device from pdev
* @name: FPGA bridge name
* @br_ops: pointer to structure of fpga bridge ops
* @priv: FPGA bridge private data
*
* Return: 0 for success, error code otherwise.
*/
int fpga_bridge_register(struct device *dev, const char *name,
const struct fpga_bridge_ops *br_ops, void *priv)
{
struct fpga_bridge *bridge;
int id, ret = 0;
if (!name || !strlen(name)) {
dev_err(dev, "Attempt to register with no name!\n");
return -EINVAL;
}
bridge = kzalloc(sizeof(*bridge), GFP_KERNEL);
if (!bridge)
return -ENOMEM;
id = ida_simple_get(&fpga_bridge_ida, 0, 0, GFP_KERNEL);
if (id < 0) {
ret = id;
goto error_kfree;
}
mutex_init(&bridge->mutex);
INIT_LIST_HEAD(&bridge->node);
bridge->name = name;
bridge->br_ops = br_ops;
bridge->priv = priv;
device_initialize(&bridge->dev);
bridge->dev.class = fpga_bridge_class;
bridge->dev.parent = dev;
bridge->dev.of_node = dev->of_node;
bridge->dev.id = id;
dev_set_drvdata(dev, bridge);
ret = dev_set_name(&bridge->dev, "br%d", id);
if (ret)
goto error_device;
ret = device_add(&bridge->dev);
if (ret)
goto error_device;
of_platform_populate(dev->of_node, NULL, NULL, dev);
dev_info(bridge->dev.parent, "fpga bridge [%s] registered\n",
bridge->name);
return 0;
error_device:
ida_simple_remove(&fpga_bridge_ida, id);
error_kfree:
kfree(bridge);
return ret;
}
EXPORT_SYMBOL_GPL(fpga_bridge_register);
/**
* fpga_bridge_unregister - unregister a fpga bridge driver
* @dev: FPGA bridge device from pdev
*/
void fpga_bridge_unregister(struct device *dev)
{
struct fpga_bridge *bridge = dev_get_drvdata(dev);
/*
* If the low level driver provides a method for putting bridge into
* a desired state upon unregister, do it.
*/
if (bridge->br_ops && bridge->br_ops->fpga_bridge_remove)
bridge->br_ops->fpga_bridge_remove(bridge);
device_unregister(&bridge->dev);
}
EXPORT_SYMBOL_GPL(fpga_bridge_unregister);
static void fpga_bridge_dev_release(struct device *dev)
{
struct fpga_bridge *bridge = to_fpga_bridge(dev);
ida_simple_remove(&fpga_bridge_ida, bridge->dev.id);
kfree(bridge);
}
static int __init fpga_bridge_dev_init(void)
{
spin_lock_init(&bridge_list_lock);
fpga_bridge_class = class_create(THIS_MODULE, "fpga_bridge");
if (IS_ERR(fpga_bridge_class))
return PTR_ERR(fpga_bridge_class);
fpga_bridge_class->dev_groups = fpga_bridge_groups;
fpga_bridge_class->dev_release = fpga_bridge_dev_release;
return 0;
}
static void __exit fpga_bridge_dev_exit(void)
{
class_destroy(fpga_bridge_class);
ida_destroy(&fpga_bridge_ida);
}
MODULE_DESCRIPTION("FPGA Bridge Driver");
MODULE_AUTHOR("Alan Tull <atull@opensource.altera.com>");
MODULE_LICENSE("GPL v2");
subsys_initcall(fpga_bridge_dev_init);
module_exit(fpga_bridge_dev_exit);
......@@ -32,19 +32,20 @@ static struct class *fpga_mgr_class;
/**
* fpga_mgr_buf_load - load fpga from image in buffer
* @mgr: fpga manager
* @flags: flags setting fpga confuration modes
* @info: fpga image specific information
* @buf: buffer contain fpga image
* @count: byte count of buf
*
* Step the low level fpga manager through the device-specific steps of getting
* an FPGA ready to be configured, writing the image to it, then doing whatever
* post-configuration steps necessary. This code assumes the caller got the
* mgr pointer from of_fpga_mgr_get() and checked that it is not an error code.
* mgr pointer from of_fpga_mgr_get() or fpga_mgr_get() and checked that it is
* not an error code.
*
* Return: 0 on success, negative error code otherwise.
*/
int fpga_mgr_buf_load(struct fpga_manager *mgr, u32 flags, const char *buf,
size_t count)
int fpga_mgr_buf_load(struct fpga_manager *mgr, struct fpga_image_info *info,
const char *buf, size_t count)
{
struct device *dev = &mgr->dev;
int ret;
......@@ -52,10 +53,12 @@ int fpga_mgr_buf_load(struct fpga_manager *mgr, u32 flags, const char *buf,
/*
* Call the low level driver's write_init function. This will do the
* device-specific things to get the FPGA into the state where it is
* ready to receive an FPGA image.
* ready to receive an FPGA image. The low level driver only gets to
* see the first initial_header_size bytes in the buffer.
*/
mgr->state = FPGA_MGR_STATE_WRITE_INIT;
ret = mgr->mops->write_init(mgr, flags, buf, count);
ret = mgr->mops->write_init(mgr, info, buf,
min(mgr->mops->initial_header_size, count));
if (ret) {
dev_err(dev, "Error preparing FPGA for writing\n");
mgr->state = FPGA_MGR_STATE_WRITE_INIT_ERR;
......@@ -78,7 +81,7 @@ int fpga_mgr_buf_load(struct fpga_manager *mgr, u32 flags, const char *buf,
* steps to finish and set the FPGA into operating mode.
*/
mgr->state = FPGA_MGR_STATE_WRITE_COMPLETE;
ret = mgr->mops->write_complete(mgr, flags);
ret = mgr->mops->write_complete(mgr, info);
if (ret) {
dev_err(dev, "Error after writing image data to FPGA\n");
mgr->state = FPGA_MGR_STATE_WRITE_COMPLETE_ERR;
......@@ -93,17 +96,19 @@ EXPORT_SYMBOL_GPL(fpga_mgr_buf_load);
/**
* fpga_mgr_firmware_load - request firmware and load to fpga
* @mgr: fpga manager
* @flags: flags setting fpga confuration modes
* @info: fpga image specific information
* @image_name: name of image file on the firmware search path
*
* Request an FPGA image using the firmware class, then write out to the FPGA.
* Update the state before each step to provide info on what step failed if
* there is a failure. This code assumes the caller got the mgr pointer
* from of_fpga_mgr_get() and checked that it is not an error code.
* from of_fpga_mgr_get() or fpga_mgr_get() and checked that it is not an error
* code.
*
* Return: 0 on success, negative error code otherwise.
*/
int fpga_mgr_firmware_load(struct fpga_manager *mgr, u32 flags,
int fpga_mgr_firmware_load(struct fpga_manager *mgr,
struct fpga_image_info *info,
const char *image_name)
{
struct device *dev = &mgr->dev;
......@@ -121,7 +126,7 @@ int fpga_mgr_firmware_load(struct fpga_manager *mgr, u32 flags,
return ret;
}
ret = fpga_mgr_buf_load(mgr, flags, fw->data, fw->size);
ret = fpga_mgr_buf_load(mgr, info, fw->data, fw->size);
release_firmware(fw);
......@@ -181,30 +186,11 @@ static struct attribute *fpga_mgr_attrs[] = {
};
ATTRIBUTE_GROUPS(fpga_mgr);
static int fpga_mgr_of_node_match(struct device *dev, const void *data)
{
return dev->of_node == data;
}
/**
* of_fpga_mgr_get - get an exclusive reference to a fpga mgr
* @node: device node
*
* Given a device node, get an exclusive reference to a fpga mgr.
*
* Return: fpga manager struct or IS_ERR() condition containing error code.
*/
struct fpga_manager *of_fpga_mgr_get(struct device_node *node)
struct fpga_manager *__fpga_mgr_get(struct device *dev)
{
struct fpga_manager *mgr;
struct device *dev;
int ret = -ENODEV;
dev = class_find_device(fpga_mgr_class, NULL, node,
fpga_mgr_of_node_match);
if (!dev)
return ERR_PTR(-ENODEV);
mgr = to_fpga_manager(dev);
if (!mgr)
goto err_dev;
......@@ -226,6 +212,55 @@ struct fpga_manager *of_fpga_mgr_get(struct device_node *node)
put_device(dev);
return ERR_PTR(ret);
}
static int fpga_mgr_dev_match(struct device *dev, const void *data)
{
return dev->parent == data;
}
/**
* fpga_mgr_get - get an exclusive reference to a fpga mgr
* @dev: parent device that fpga mgr was registered with
*
* Given a device, get an exclusive reference to a fpga mgr.
*
* Return: fpga manager struct or IS_ERR() condition containing error code.
*/
struct fpga_manager *fpga_mgr_get(struct device *dev)
{
struct device *mgr_dev = class_find_device(fpga_mgr_class, NULL, dev,
fpga_mgr_dev_match);
if (!mgr_dev)
return ERR_PTR(-ENODEV);
return __fpga_mgr_get(mgr_dev);
}
EXPORT_SYMBOL_GPL(fpga_mgr_get);
static int fpga_mgr_of_node_match(struct device *dev, const void *data)
{
return dev->of_node == data;
}
/**
* of_fpga_mgr_get - get an exclusive reference to a fpga mgr
* @node: device node
*
* Given a device node, get an exclusive reference to a fpga mgr.
*
* Return: fpga manager struct or IS_ERR() condition containing error code.
*/
struct fpga_manager *of_fpga_mgr_get(struct device_node *node)
{
struct device *dev;
dev = class_find_device(fpga_mgr_class, NULL, node,
fpga_mgr_of_node_match);
if (!dev)
return ERR_PTR(-ENODEV);
return __fpga_mgr_get(dev);
}
EXPORT_SYMBOL_GPL(of_fpga_mgr_get);
/**
......
This diff is collapsed.
This diff is collapsed.
......@@ -407,13 +407,14 @@ static int socfpga_fpga_reset(struct fpga_manager *mgr)
/*
* Prepare the FPGA to receive the configuration data.
*/
static int socfpga_fpga_ops_configure_init(struct fpga_manager *mgr, u32 flags,
static int socfpga_fpga_ops_configure_init(struct fpga_manager *mgr,
struct fpga_image_info *info,
const char *buf, size_t count)
{
struct socfpga_fpga_priv *priv = mgr->priv;
int ret;
if (flags & FPGA_MGR_PARTIAL_RECONFIG) {
if (info->flags & FPGA_MGR_PARTIAL_RECONFIG) {
dev_err(&mgr->dev, "Partial reconfiguration not supported.\n");
return -EINVAL;
}
......@@ -478,7 +479,7 @@ static int socfpga_fpga_ops_configure_write(struct fpga_manager *mgr,
}
static int socfpga_fpga_ops_configure_complete(struct fpga_manager *mgr,
u32 flags)
struct fpga_image_info *info)
{
struct socfpga_fpga_priv *priv = mgr->priv;
u32 status;
......
......@@ -118,7 +118,6 @@
#define FPGA_RST_NONE_MASK 0x0
struct zynq_fpga_priv {
struct device *dev;
int irq;
struct clk *clk;
......@@ -175,7 +174,8 @@ static irqreturn_t zynq_fpga_isr(int irq, void *data)
return IRQ_HANDLED;
}
static int zynq_fpga_ops_write_init(struct fpga_manager *mgr, u32 flags,
static int zynq_fpga_ops_write_init(struct fpga_manager *mgr,
struct fpga_image_info *info,
const char *buf, size_t count)
{
struct zynq_fpga_priv *priv;
......@@ -189,7 +189,7 @@ static int zynq_fpga_ops_write_init(struct fpga_manager *mgr, u32 flags,
return err;
/* don't globally reset PL if we're doing partial reconfig */
if (!(flags & FPGA_MGR_PARTIAL_RECONFIG)) {
if (!(info->flags & FPGA_MGR_PARTIAL_RECONFIG)) {
/* assert AXI interface resets */
regmap_write(priv->slcr, SLCR_FPGA_RST_CTRL_OFFSET,
FPGA_RST_ALL_MASK);
......@@ -217,7 +217,7 @@ static int zynq_fpga_ops_write_init(struct fpga_manager *mgr, u32 flags,
INIT_POLL_DELAY,
INIT_POLL_TIMEOUT);
if (err) {
dev_err(priv->dev, "Timeout waiting for PCFG_INIT");
dev_err(&mgr->dev, "Timeout waiting for PCFG_INIT\n");
goto out_err;
}
......@@ -231,7 +231,7 @@ static int zynq_fpga_ops_write_init(struct fpga_manager *mgr, u32 flags,
INIT_POLL_DELAY,
INIT_POLL_TIMEOUT);
if (err) {
dev_err(priv->dev, "Timeout waiting for !PCFG_INIT");
dev_err(&mgr->dev, "Timeout waiting for !PCFG_INIT\n");
goto out_err;
}
......@@ -245,7 +245,7 @@ static int zynq_fpga_ops_write_init(struct fpga_manager *mgr, u32 flags,
INIT_POLL_DELAY,
INIT_POLL_TIMEOUT);
if (err) {
dev_err(priv->dev, "Timeout waiting for PCFG_INIT");
dev_err(&mgr->dev, "Timeout waiting for PCFG_INIT\n");
goto out_err;
}
}
......@@ -262,7 +262,7 @@ static int zynq_fpga_ops_write_init(struct fpga_manager *mgr, u32 flags,
/* check that we have room in the command queue */
status = zynq_fpga_read(priv, STATUS_OFFSET);
if (status & STATUS_DMA_Q_F) {
dev_err(priv->dev, "DMA command queue full");
dev_err(&mgr->dev, "DMA command queue full\n");
err = -EBUSY;
goto out_err;
}
......@@ -295,7 +295,8 @@ static int zynq_fpga_ops_write(struct fpga_manager *mgr,
in_count = count;
priv = mgr->priv;
kbuf = dma_alloc_coherent(priv->dev, count, &dma_addr, GFP_KERNEL);
kbuf =
dma_alloc_coherent(mgr->dev.parent, count, &dma_addr, GFP_KERNEL);
if (!kbuf)
return -ENOMEM;
......@@ -331,19 +332,19 @@ static int zynq_fpga_ops_write(struct fpga_manager *mgr,
zynq_fpga_write(priv, INT_STS_OFFSET, intr_status);
if (!((intr_status & IXR_D_P_DONE_MASK) == IXR_D_P_DONE_MASK)) {
dev_err(priv->dev, "Error configuring FPGA");
dev_err(&mgr->dev, "Error configuring FPGA\n");
err = -EFAULT;
}
clk_disable(priv->clk);
out_free:
dma_free_coherent(priv->dev, in_count, kbuf, dma_addr);
dma_free_coherent(mgr->dev.parent, count, kbuf, dma_addr);
return err;
}
static int zynq_fpga_ops_write_complete(struct fpga_manager *mgr, u32 flags)
static int zynq_fpga_ops_write_complete(struct fpga_manager *mgr,
struct fpga_image_info *info)
{
struct zynq_fpga_priv *priv = mgr->priv;
int err;
......@@ -364,7 +365,7 @@ static int zynq_fpga_ops_write_complete(struct fpga_manager *mgr, u32 flags)
return err;
/* for the partial reconfig case we didn't touch the level shifters */
if (!(flags & FPGA_MGR_PARTIAL_RECONFIG)) {
if (!(info->flags & FPGA_MGR_PARTIAL_RECONFIG)) {
/* enable level shifters from PL to PS */
regmap_write(priv->slcr, SLCR_LVL_SHFTR_EN_OFFSET,
LVL_SHFTR_ENABLE_PL_TO_PS);
......@@ -416,8 +417,6 @@ static int zynq_fpga_probe(struct platform_device *pdev)
if (!priv)
return -ENOMEM;
priv->dev = dev;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
priv->io_base = devm_ioremap_resource(dev, res);
if (IS_ERR(priv->io_base))
......@@ -426,7 +425,7 @@ static int zynq_fpga_probe(struct platform_device *pdev)
priv->slcr = syscon_regmap_lookup_by_phandle(dev->of_node,
"syscon");
if (IS_ERR(priv->slcr)) {
dev_err(dev, "unable to get zynq-slcr regmap");
dev_err(dev, "unable to get zynq-slcr regmap\n");
return PTR_ERR(priv->slcr);
}
......@@ -434,38 +433,41 @@ static int zynq_fpga_probe(struct platform_device *pdev)
priv->irq = platform_get_irq(pdev, 0);
if (priv->irq < 0) {
dev_err(dev, "No IRQ available");
dev_err(dev, "No IRQ available\n");
return priv->irq;
}
err = devm_request_irq(dev, priv->irq, zynq_fpga_isr, 0,
dev_name(dev), priv);
if (err) {
dev_err(dev, "unable to request IRQ");
return err;
}
priv->clk = devm_clk_get(dev, "ref_clk");
if (IS_ERR(priv->clk)) {
dev_err(dev, "input clock not found");
dev_err(dev, "input clock not found\n");
return PTR_ERR(priv->clk);
}
err = clk_prepare_enable(priv->clk);
if (err) {
dev_err(dev, "unable to enable clock");
dev_err(dev, "unable to enable clock\n");
return err;
}
/* unlock the device */
zynq_fpga_write(priv, UNLOCK_OFFSET, UNLOCK_MASK);
zynq_fpga_write(priv, INT_MASK_OFFSET, 0xFFFFFFFF);
zynq_fpga_write(priv, INT_STS_OFFSET, IXR_ALL_MASK);
err = devm_request_irq(dev, priv->irq, zynq_fpga_isr, 0, dev_name(dev),
priv);
if (err) {
dev_err(dev, "unable to request IRQ\n");
clk_disable_unprepare(priv->clk);
return err;
}
clk_disable(priv->clk);
err = fpga_mgr_register(dev, "Xilinx Zynq FPGA Manager",
&zynq_fpga_ops, priv);
if (err) {
dev_err(dev, "unable to register FPGA manager");
dev_err(dev, "unable to register FPGA manager\n");
clk_unprepare(priv->clk);
return err;
}
......
......@@ -39,7 +39,7 @@
* vmbus_setevent- Trigger an event notification on the specified
* channel.
*/
static void vmbus_setevent(struct vmbus_channel *channel)
void vmbus_setevent(struct vmbus_channel *channel)
{
struct hv_monitor_page *monitorpage;
......@@ -65,6 +65,7 @@ static void vmbus_setevent(struct vmbus_channel *channel)
vmbus_set_event(channel);
}
}
EXPORT_SYMBOL_GPL(vmbus_setevent);
/*
* vmbus_open - Open the specified channel.
......@@ -635,8 +636,6 @@ int vmbus_sendpacket_ctl(struct vmbus_channel *channel, void *buffer,
u32 packetlen_aligned = ALIGN(packetlen, sizeof(u64));
struct kvec bufferlist[3];
u64 aligned_data = 0;
int ret;
bool signal = false;
bool lock = channel->acquire_ring_lock;
int num_vecs = ((bufferlen != 0) ? 3 : 1);
......@@ -656,33 +655,9 @@ int vmbus_sendpacket_ctl(struct vmbus_channel *channel, void *buffer,
bufferlist[2].iov_base = &aligned_data;
bufferlist[2].iov_len = (packetlen_aligned - packetlen);
ret = hv_ringbuffer_write(&channel->outbound, bufferlist, num_vecs,
&signal, lock, channel->signal_policy);
/*
* Signalling the host is conditional on many factors:
* 1. The ring state changed from being empty to non-empty.
* This is tracked by the variable "signal".
* 2. The variable kick_q tracks if more data will be placed
* on the ring. We will not signal if more data is
* to be placed.
*
* Based on the channel signal state, we will decide
* which signaling policy will be applied.
*
* If we cannot write to the ring-buffer; signal the host
* even if we may not have written anything. This is a rare
* enough condition that it should not matter.
* NOTE: in this case, the hvsock channel is an exception, because
* it looks the host side's hvsock implementation has a throttling
* mechanism which can hurt the performance otherwise.
*/
if (((ret == 0) && kick_q && signal) ||
(ret && !is_hvsock_channel(channel)))
vmbus_setevent(channel);
return hv_ringbuffer_write(channel, bufferlist, num_vecs,
lock, kick_q);
return ret;
}
EXPORT_SYMBOL(vmbus_sendpacket_ctl);
......@@ -723,7 +698,6 @@ int vmbus_sendpacket_pagebuffer_ctl(struct vmbus_channel *channel,
u32 flags,
bool kick_q)
{
int ret;
int i;
struct vmbus_channel_packet_page_buffer desc;
u32 descsize;
......@@ -731,7 +705,6 @@ int vmbus_sendpacket_pagebuffer_ctl(struct vmbus_channel *channel,
u32 packetlen_aligned;
struct kvec bufferlist[3];
u64 aligned_data = 0;
bool signal = false;
bool lock = channel->acquire_ring_lock;
if (pagecount > MAX_PAGE_BUFFER_COUNT)
......@@ -769,29 +742,8 @@ int vmbus_sendpacket_pagebuffer_ctl(struct vmbus_channel *channel,
bufferlist[2].iov_base = &aligned_data;
bufferlist[2].iov_len = (packetlen_aligned - packetlen);
ret = hv_ringbuffer_write(&channel->outbound, bufferlist, 3,
&signal, lock, channel->signal_policy);
/*
* Signalling the host is conditional on many factors:
* 1. The ring state changed from being empty to non-empty.
* This is tracked by the variable "signal".
* 2. The variable kick_q tracks if more data will be placed
* on the ring. We will not signal if more data is
* to be placed.
*
* Based on the channel signal state, we will decide
* which signaling policy will be applied.
*
* If we cannot write to the ring-buffer; signal the host
* even if we may not have written anything. This is a rare
* enough condition that it should not matter.
*/
if (((ret == 0) && kick_q && signal) || (ret))
vmbus_setevent(channel);
return ret;
return hv_ringbuffer_write(channel, bufferlist, 3,
lock, kick_q);
}
EXPORT_SYMBOL_GPL(vmbus_sendpacket_pagebuffer_ctl);
......@@ -822,12 +774,10 @@ int vmbus_sendpacket_mpb_desc(struct vmbus_channel *channel,
u32 desc_size,
void *buffer, u32 bufferlen, u64 requestid)
{
int ret;
u32 packetlen;
u32 packetlen_aligned;
struct kvec bufferlist[3];
u64 aligned_data = 0;
bool signal = false;
bool lock = channel->acquire_ring_lock;
packetlen = desc_size + bufferlen;
......@@ -848,13 +798,8 @@ int vmbus_sendpacket_mpb_desc(struct vmbus_channel *channel,
bufferlist[2].iov_base = &aligned_data;
bufferlist[2].iov_len = (packetlen_aligned - packetlen);
ret = hv_ringbuffer_write(&channel->outbound, bufferlist, 3,
&signal, lock, channel->signal_policy);
if (ret == 0 && signal)
vmbus_setevent(channel);
return ret;
return hv_ringbuffer_write(channel, bufferlist, 3,
lock, true);
}
EXPORT_SYMBOL_GPL(vmbus_sendpacket_mpb_desc);
......@@ -866,14 +811,12 @@ int vmbus_sendpacket_multipagebuffer(struct vmbus_channel *channel,
struct hv_multipage_buffer *multi_pagebuffer,
void *buffer, u32 bufferlen, u64 requestid)
{
int ret;
struct vmbus_channel_packet_multipage_buffer desc;
u32 descsize;
u32 packetlen;
u32 packetlen_aligned;
struct kvec bufferlist[3];
u64 aligned_data = 0;
bool signal = false;
bool lock = channel->acquire_ring_lock;
u32 pfncount = NUM_PAGES_SPANNED(multi_pagebuffer->offset,
multi_pagebuffer->len);
......@@ -913,13 +856,8 @@ int vmbus_sendpacket_multipagebuffer(struct vmbus_channel *channel,
bufferlist[2].iov_base = &aligned_data;
bufferlist[2].iov_len = (packetlen_aligned - packetlen);
ret = hv_ringbuffer_write(&channel->outbound, bufferlist, 3,
&signal, lock, channel->signal_policy);
if (ret == 0 && signal)
vmbus_setevent(channel);
return ret;
return hv_ringbuffer_write(channel, bufferlist, 3,
lock, true);
}
EXPORT_SYMBOL_GPL(vmbus_sendpacket_multipagebuffer);
......@@ -941,16 +879,9 @@ __vmbus_recvpacket(struct vmbus_channel *channel, void *buffer,
u32 bufferlen, u32 *buffer_actual_len, u64 *requestid,
bool raw)
{
int ret;
bool signal = false;
return hv_ringbuffer_read(channel, buffer, bufferlen,
buffer_actual_len, requestid, raw);
ret = hv_ringbuffer_read(&channel->inbound, buffer, bufferlen,
buffer_actual_len, requestid, &signal, raw);
if (signal)
vmbus_setevent(channel);
return ret;
}
int vmbus_recvpacket(struct vmbus_channel *channel, void *buffer,
......
......@@ -134,7 +134,7 @@ static const struct vmbus_device vmbus_devs[] = {
},
/* Unknown GUID */
{ .dev_type = HV_UNKOWN,
{ .dev_type = HV_UNKNOWN,
.perf_device = false,
},
};
......@@ -163,9 +163,9 @@ static u16 hv_get_dev_type(const struct vmbus_channel *channel)
u16 i;
if (is_hvsock_channel(channel) || is_unsupported_vmbus_devs(guid))
return HV_UNKOWN;
return HV_UNKNOWN;
for (i = HV_IDE; i < HV_UNKOWN; i++) {
for (i = HV_IDE; i < HV_UNKNOWN; i++) {
if (!uuid_le_cmp(*guid, vmbus_devs[i].guid))
return i;
}
......@@ -389,6 +389,7 @@ void vmbus_free_channels(void)
{
struct vmbus_channel *channel, *tmp;
mutex_lock(&vmbus_connection.channel_mutex);
list_for_each_entry_safe(channel, tmp, &vmbus_connection.chn_list,
listentry) {
/* hv_process_channel_removal() needs this */
......@@ -396,6 +397,7 @@ void vmbus_free_channels(void)
vmbus_device_unregister(channel->device_obj);
}
mutex_unlock(&vmbus_connection.channel_mutex);
}
/*
......@@ -447,8 +449,6 @@ static void vmbus_process_offer(struct vmbus_channel *newchannel)
}
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);
......
......@@ -39,6 +39,7 @@ struct vmbus_connection vmbus_connection = {
.conn_state = DISCONNECTED,
.next_gpadl_handle = ATOMIC_INIT(0xE1E10),
};
EXPORT_SYMBOL_GPL(vmbus_connection);
/*
* Negotiated protocol version with the host.
......
......@@ -575,7 +575,7 @@ void hv_synic_clockevents_cleanup(void)
if (!(ms_hyperv.features & HV_X64_MSR_SYNTIMER_AVAILABLE))
return;
for_each_online_cpu(cpu)
for_each_present_cpu(cpu)
clockevents_unbind_device(hv_context.clk_evt[cpu], cpu);
}
......@@ -594,8 +594,10 @@ void hv_synic_cleanup(void *arg)
return;
/* Turn off clockevent device */
if (ms_hyperv.features & HV_X64_MSR_SYNTIMER_AVAILABLE)
if (ms_hyperv.features & HV_X64_MSR_SYNTIMER_AVAILABLE) {
clockevents_unbind_device(hv_context.clk_evt[cpu], cpu);
hv_ce_shutdown(hv_context.clk_evt[cpu]);
}
rdmsrl(HV_X64_MSR_SINT0 + VMBUS_MESSAGE_SINT, shared_sint.as_uint64);
......
......@@ -564,6 +564,11 @@ struct hv_dynmem_device {
* next version to try.
*/
__u32 next_version;
/*
* The negotiated version agreed by host.
*/
__u32 version;
};
static struct hv_dynmem_device dm_device;
......@@ -645,6 +650,7 @@ static void hv_bring_pgs_online(struct hv_hotadd_state *has,
{
int i;
pr_debug("Online %lu pages starting at pfn 0x%lx\n", size, start_pfn);
for (i = 0; i < size; i++)
hv_page_online_one(has, pfn_to_page(start_pfn + i));
}
......@@ -685,7 +691,7 @@ static void hv_mem_hot_add(unsigned long start, unsigned long size,
(HA_CHUNK << PAGE_SHIFT));
if (ret) {
pr_info("hot_add memory failed error is %d\n", ret);
pr_warn("hot_add memory failed error is %d\n", ret);
if (ret == -EEXIST) {
/*
* This error indicates that the error
......@@ -814,6 +820,9 @@ static unsigned long handle_pg_range(unsigned long pg_start,
unsigned long old_covered_state;
unsigned long res = 0, flags;
pr_debug("Hot adding %lu pages starting at pfn 0x%lx.\n", pg_count,
pg_start);
spin_lock_irqsave(&dm_device.ha_lock, flags);
list_for_each_entry(has, &dm_device.ha_region_list, list) {
/*
......@@ -1025,8 +1034,13 @@ static void process_info(struct hv_dynmem_device *dm, struct dm_info_msg *msg)
switch (info_hdr->type) {
case INFO_TYPE_MAX_PAGE_CNT:
pr_info("Received INFO_TYPE_MAX_PAGE_CNT\n");
pr_info("Data Size is %d\n", info_hdr->data_size);
if (info_hdr->data_size == sizeof(__u64)) {
__u64 *max_page_count = (__u64 *)&info_hdr[1];
pr_info("INFO_TYPE_MAX_PAGE_CNT = %llu\n",
*max_page_count);
}
break;
default:
pr_info("Received Unknown type: %d\n", info_hdr->type);
......@@ -1196,8 +1210,6 @@ static unsigned int alloc_balloon_pages(struct hv_dynmem_device *dm,
return num_pages;
}
static void balloon_up(struct work_struct *dummy)
{
unsigned int num_pages = dm_device.balloon_wrk.num_pages;
......@@ -1224,6 +1236,10 @@ static void balloon_up(struct work_struct *dummy)
/* Refuse to balloon below the floor, keep the 2M granularity. */
if (avail_pages < num_pages || avail_pages - num_pages < floor) {
pr_warn("Balloon request will be partially fulfilled. %s\n",
avail_pages < num_pages ? "Not enough memory." :
"Balloon floor reached.");
num_pages = avail_pages > floor ? (avail_pages - floor) : 0;
num_pages -= num_pages % PAGES_IN_2M;
}
......@@ -1245,6 +1261,9 @@ static void balloon_up(struct work_struct *dummy)
}
if (num_ballooned == 0 || num_ballooned == num_pages) {
pr_debug("Ballooned %u out of %u requested pages.\n",
num_pages, dm_device.balloon_wrk.num_pages);
bl_resp->more_pages = 0;
done = true;
dm_device.state = DM_INITIALIZED;
......@@ -1292,12 +1311,16 @@ static void balloon_down(struct hv_dynmem_device *dm,
int range_count = req->range_count;
struct dm_unballoon_response resp;
int i;
unsigned int prev_pages_ballooned = dm->num_pages_ballooned;
for (i = 0; i < range_count; i++) {
free_balloon_pages(dm, &range_array[i]);
complete(&dm_device.config_event);
}
pr_debug("Freed %u ballooned pages.\n",
prev_pages_ballooned - dm->num_pages_ballooned);
if (req->more_pages == 1)
return;
......@@ -1365,6 +1388,7 @@ static void version_resp(struct hv_dynmem_device *dm,
version_req.hdr.size = sizeof(struct dm_version_request);
version_req.hdr.trans_id = atomic_inc_return(&trans_id);
version_req.version.version = dm->next_version;
dm->version = version_req.version.version;
/*
* Set the next version to try in case current version fails.
......@@ -1501,7 +1525,11 @@ static int balloon_probe(struct hv_device *dev,
struct dm_version_request version_req;
struct dm_capabilities cap_msg;
#ifdef CONFIG_MEMORY_HOTPLUG
do_hot_add = hot_add;
#else
do_hot_add = false;
#endif
/*
* First allocate a send buffer.
......@@ -1553,6 +1581,7 @@ static int balloon_probe(struct hv_device *dev,
version_req.hdr.trans_id = atomic_inc_return(&trans_id);
version_req.version.version = DYNMEM_PROTOCOL_VERSION_WIN10;
version_req.is_last_attempt = 0;
dm_device.version = version_req.version.version;
ret = vmbus_sendpacket(dev->channel, &version_req,
sizeof(struct dm_version_request),
......@@ -1575,6 +1604,11 @@ static int balloon_probe(struct hv_device *dev,
ret = -ETIMEDOUT;
goto probe_error2;
}
pr_info("Using Dynamic Memory protocol version %u.%u\n",
DYNMEM_MAJOR_VERSION(dm_device.version),
DYNMEM_MINOR_VERSION(dm_device.version));
/*
* Now submit our capabilities to the host.
*/
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -164,6 +164,16 @@ static ssize_t mode_store(struct device *dev,
else
config->ctrl &= ~ETMCR_CTXID_SIZE;
if (config->mode & ETM_MODE_BBROAD)
config->ctrl |= ETMCR_BRANCH_BROADCAST;
else
config->ctrl &= ~ETMCR_BRANCH_BROADCAST;
if (config->mode & ETM_MODE_RET_STACK)
config->ctrl |= ETMCR_RETURN_STACK;
else
config->ctrl &= ~ETMCR_RETURN_STACK;
if (config->mode & (ETM_MODE_EXCL_KERN | ETM_MODE_EXCL_USER))
etm_config_trace_mode(config);
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -9,3 +9,4 @@ obj-$(CONFIG_UIO_NETX) += uio_netx.o
obj-$(CONFIG_UIO_PRUSS) += uio_pruss.o
obj-$(CONFIG_UIO_MF624) += uio_mf624.o
obj-$(CONFIG_UIO_FSL_ELBC_GPCM) += uio_fsl_elbc_gpcm.o
obj-$(CONFIG_UIO_HV_GENERIC) += uio_hv_generic.o
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment