Commit abf7dba7 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull char/misc driver updates from Greg KH:
 "Here is the "big" char and misc driver patches for 4.18-rc1.

  It's not a lot of stuff here, but there are some highlights:

   - coreboot driver updates

   - soundwire driver updates

   - android binder updates

   - fpga big sync, mostly documentation

   - lots of minor driver updates

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

* tag 'char-misc-4.18-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc: (81 commits)
  vmw_balloon: fixing double free when batching mode is off
  MAINTAINERS: Add driver-api/fpga path
  fpga: clarify that unregister functions also free
  documentation: fpga: move fpga-region.txt to driver-api
  documentation: fpga: add bridge document to driver-api
  documentation: fpga: move fpga-mgr.txt to driver-api
  Documentation: fpga: move fpga overview to driver-api
  fpga: region: kernel-doc fixes
  fpga: bridge: kernel-doc fixes
  fpga: mgr: kernel-doc fixes
  fpga: use SPDX
  fpga: region: change api, add fpga_region_create/free
  fpga: bridge: change api, don't use drvdata
  fpga: manager: change api, don't use drvdata
  fpga: region: don't use drvdata in common fpga code
  Drivers: hv: vmbus: Removed an unnecessary cast from void *
  ver_linux: Drop redundant calls to system() to test if file is readable
  ver_linux: Move stderr redirection from function parameter to function body
  misc: IBM Virtual Management Channel Driver (VMC)
  rpmsg: Correct support for MODULE_DEVICE_TABLE()
  ...
parents 07c4dd34 b23220fe
What: /sys/bus/vmbus/devices/vmbus_*/id
What: /sys/bus/vmbus/devices/<UUID>/id
Date: Jul 2009
KernelVersion: 2.6.31
Contact: K. Y. Srinivasan <kys@microsoft.com>
Description: The VMBus child_relid of the device's primary channel
Users: tools/hv/lsvmbus
What: /sys/bus/vmbus/devices/vmbus_*/class_id
What: /sys/bus/vmbus/devices/<UUID>/class_id
Date: Jul 2009
KernelVersion: 2.6.31
Contact: K. Y. Srinivasan <kys@microsoft.com>
Description: The VMBus interface type GUID of the device
Users: tools/hv/lsvmbus
What: /sys/bus/vmbus/devices/vmbus_*/device_id
What: /sys/bus/vmbus/devices/<UUID>/device_id
Date: Jul 2009
KernelVersion: 2.6.31
Contact: K. Y. Srinivasan <kys@microsoft.com>
Description: The VMBus interface instance GUID of the device
Users: tools/hv/lsvmbus
What: /sys/bus/vmbus/devices/vmbus_*/channel_vp_mapping
What: /sys/bus/vmbus/devices/<UUID>/channel_vp_mapping
Date: Jul 2015
KernelVersion: 4.2.0
Contact: K. Y. Srinivasan <kys@microsoft.com>
......@@ -28,112 +28,112 @@ Description: The mapping of which primary/sub channels are bound to which
Format: <channel's child_relid:the bound cpu's number>
Users: tools/hv/lsvmbus
What: /sys/bus/vmbus/devices/vmbus_*/device
What: /sys/bus/vmbus/devices/<UUID>/device
Date: Dec. 2015
KernelVersion: 4.5
Contact: K. Y. Srinivasan <kys@microsoft.com>
Description: The 16 bit device ID of the device
Users: tools/hv/lsvmbus and user level RDMA libraries
What: /sys/bus/vmbus/devices/vmbus_*/vendor
What: /sys/bus/vmbus/devices/<UUID>/vendor
Date: Dec. 2015
KernelVersion: 4.5
Contact: K. Y. Srinivasan <kys@microsoft.com>
Description: The 16 bit vendor ID of the device
Users: tools/hv/lsvmbus and user level RDMA libraries
What: /sys/bus/vmbus/devices/vmbus_*/channels/NN
What: /sys/bus/vmbus/devices/<UUID>/channels/<N>
Date: September. 2017
KernelVersion: 4.14
Contact: Stephen Hemminger <sthemmin@microsoft.com>
Description: Directory for per-channel information
NN is the VMBUS relid associtated with the channel.
What: /sys/bus/vmbus/devices/vmbus_*/channels/NN/cpu
What: /sys/bus/vmbus/devices/<UUID>/channels/<N>/cpu
Date: September. 2017
KernelVersion: 4.14
Contact: Stephen Hemminger <sthemmin@microsoft.com>
Description: VCPU (sub)channel is affinitized to
Users: tools/hv/lsvmbus and other debugging tools
What: /sys/bus/vmbus/devices/vmbus_*/channels/NN/cpu
What: /sys/bus/vmbus/devices/<UUID>/channels/<N>/cpu
Date: September. 2017
KernelVersion: 4.14
Contact: Stephen Hemminger <sthemmin@microsoft.com>
Description: VCPU (sub)channel is affinitized to
Users: tools/hv/lsvmbus and other debugging tools
What: /sys/bus/vmbus/devices/vmbus_*/channels/NN/in_mask
What: /sys/bus/vmbus/devices/<UUID>/channels/<N>/in_mask
Date: September. 2017
KernelVersion: 4.14
Contact: Stephen Hemminger <sthemmin@microsoft.com>
Description: Host to guest channel interrupt mask
Users: Debugging tools
What: /sys/bus/vmbus/devices/vmbus_*/channels/NN/latency
What: /sys/bus/vmbus/devices/<UUID>/channels/<N>/latency
Date: September. 2017
KernelVersion: 4.14
Contact: Stephen Hemminger <sthemmin@microsoft.com>
Description: Channel signaling latency
Users: Debugging tools
What: /sys/bus/vmbus/devices/vmbus_*/channels/NN/out_mask
What: /sys/bus/vmbus/devices/<UUID>/channels/<N>/out_mask
Date: September. 2017
KernelVersion: 4.14
Contact: Stephen Hemminger <sthemmin@microsoft.com>
Description: Guest to host channel interrupt mask
Users: Debugging tools
What: /sys/bus/vmbus/devices/vmbus_*/channels/NN/pending
What: /sys/bus/vmbus/devices/<UUID>/channels/<N>/pending
Date: September. 2017
KernelVersion: 4.14
Contact: Stephen Hemminger <sthemmin@microsoft.com>
Description: Channel interrupt pending state
Users: Debugging tools
What: /sys/bus/vmbus/devices/vmbus_*/channels/NN/read_avail
What: /sys/bus/vmbus/devices/<UUID>/channels/<N>/read_avail
Date: September. 2017
KernelVersion: 4.14
Contact: Stephen Hemminger <sthemmin@microsoft.com>
Description: Bytes available to read
Users: Debugging tools
What: /sys/bus/vmbus/devices/vmbus_*/channels/NN/write_avail
What: /sys/bus/vmbus/devices/<UUID>/channels/<N>/write_avail
Date: September. 2017
KernelVersion: 4.14
Contact: Stephen Hemminger <sthemmin@microsoft.com>
Description: Bytes available to write
Users: Debugging tools
What: /sys/bus/vmbus/devices/vmbus_*/channels/NN/events
What: /sys/bus/vmbus/devices/<UUID>/channels/<N>/events
Date: September. 2017
KernelVersion: 4.14
Contact: Stephen Hemminger <sthemmin@microsoft.com>
Description: Number of times we have signaled the host
Users: Debugging tools
What: /sys/bus/vmbus/devices/vmbus_*/channels/NN/interrupts
What: /sys/bus/vmbus/devices/<UUID>/channels/<N>/interrupts
Date: September. 2017
KernelVersion: 4.14
Contact: Stephen Hemminger <sthemmin@microsoft.com>
Description: Number of times we have taken an interrupt (incoming)
Users: Debugging tools
What: /sys/bus/vmbus/devices/vmbus_*/channels/NN/subchannel_id
What: /sys/bus/vmbus/devices/<UUID>/channels/<N>/subchannel_id
Date: January. 2018
KernelVersion: 4.16
Contact: Stephen Hemminger <sthemmin@microsoft.com>
Description: Subchannel ID associated with VMBUS channel
Users: Debugging tools and userspace drivers
What: /sys/bus/vmbus/devices/vmbus_*/channels/NN/monitor_id
What: /sys/bus/vmbus/devices/<UUID>/channels/<N>/monitor_id
Date: January. 2018
KernelVersion: 4.16
Contact: Stephen Hemminger <sthemmin@microsoft.com>
Description: Monitor bit associated with channel
Users: Debugging tools and userspace drivers
What: /sys/bus/vmbus/devices/vmbus_*/channels/NN/ring
What: /sys/bus/vmbus/devices/<UUID>/channels/<N>/ring
Date: January. 2018
KernelVersion: 4.16
Contact: Stephen Hemminger <sthemmin@microsoft.com>
......
Lattice MachXO2 Slave SPI FPGA Manager
Lattice MachXO2 FPGAs support a method of loading the bitstream over
'slave SPI' interface.
See 'MachXO2ProgrammingandConfigurationUsageGuide.pdf' on www.latticesemi.com
Required properties:
- compatible: should contain "lattice,machxo2-slave-spi"
- reg: spi chip select of the FPGA
Example for full FPGA configuration:
fpga-region0 {
compatible = "fpga-region";
fpga-mgr = <&fpga_mgr_spi>;
#address-cells = <0x1>;
#size-cells = <0x1>;
};
spi1: spi@2000 {
...
fpga_mgr_spi: fpga-mgr@0 {
compatible = "lattice,machxo2-slave-spi";
spi-max-frequency = <8000000>;
reg = <0>;
};
};
Zodiac Inflight Innovations RAVE EEPROM Bindings
RAVE SP EEPROM device is a "MFD cell" device exposing physical EEPROM
attached to RAVE Supervisory Processor. It is expected that its Device
Tree node is specified as a child of the node corresponding to the
parent RAVE SP device (as documented in
Documentation/devicetree/bindings/mfd/zii,rave-sp.txt)
Required properties:
- compatible: Should be "zii,rave-sp-eeprom"
Optional properties:
- zii,eeprom-name: Unique EEPROM identifier describing its function in the
system. Will be used as created NVMEM deivce's name.
Data cells:
Data cells are child nodes of eerpom node, bindings for which are
documented in Documentation/bindings/nvmem/nvmem.txt
Example:
rave-sp {
compatible = "zii,rave-sp-rdu1";
current-speed = <38400>;
eeprom@a4 {
compatible = "zii,rave-sp-eeprom";
reg = <0xa4 0x4000>;
#address-cells = <1>;
#size-cells = <1>;
zii,eeprom-name = "main-eeprom";
wdt_timeout: wdt-timeout@81 {
reg = <0x81 2>;
};
};
}
FPGA Bridge
===========
API to implement a new FPGA bridge
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. kernel-doc:: include/linux/fpga/fpga-bridge.h
:functions: fpga_bridge
.. kernel-doc:: include/linux/fpga/fpga-bridge.h
:functions: fpga_bridge_ops
.. kernel-doc:: drivers/fpga/fpga-bridge.c
:functions: fpga_bridge_create
.. kernel-doc:: drivers/fpga/fpga-bridge.c
:functions: fpga_bridge_free
.. kernel-doc:: drivers/fpga/fpga-bridge.c
:functions: fpga_bridge_register
.. kernel-doc:: drivers/fpga/fpga-bridge.c
:functions: fpga_bridge_unregister
API to control an FPGA bridge
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
You probably won't need these directly. FPGA regions should handle this.
.. kernel-doc:: drivers/fpga/fpga-bridge.c
:functions: of_fpga_bridge_get
.. kernel-doc:: drivers/fpga/fpga-bridge.c
:functions: fpga_bridge_get
.. kernel-doc:: drivers/fpga/fpga-bridge.c
:functions: fpga_bridge_put
.. kernel-doc:: drivers/fpga/fpga-bridge.c
:functions: fpga_bridge_get_to_list
.. kernel-doc:: drivers/fpga/fpga-bridge.c
:functions: of_fpga_bridge_get_to_list
.. kernel-doc:: drivers/fpga/fpga-bridge.c
:functions: fpga_bridge_enable
.. kernel-doc:: drivers/fpga/fpga-bridge.c
:functions: fpga_bridge_disable
FPGA Regions
FPGA Region
===========
Alan Tull 2017
CONTENTS
- Introduction
- The FPGA region API
- Usage example
Introduction
============
Overview
--------
This document is meant to be an brief overview of the FPGA region API usage. A
more conceptual look at regions can be found in [1].
more conceptual look at regions can be found in the Device Tree binding
document [#f1]_.
For the purposes of this API document, let's just say that a region associates
an FPGA Manager and a bridge (or bridges) with a reprogrammable region of an
......@@ -19,43 +14,51 @@ FPGA or the whole FPGA. The API provides a way to register a region and to
program a region.
Currently the only layer above fpga-region.c in the kernel is the Device Tree
support (of-fpga-region.c) described in [1]. The DT support layer uses regions
support (of-fpga-region.c) described in [#f1]_. The DT support layer uses regions
to program the FPGA and then DT to handle enumeration. The common region code
is intended to be used by other schemes that have other ways of accomplishing
enumeration after programming.
An fpga-region can be set up to know the following things:
* which FPGA manager to use to do the programming
* which bridges to disable before programming and enable afterwards.
* which FPGA manager to use to do the programming
* which bridges to disable before programming and enable afterwards.
Additional info needed to program the FPGA image is passed in the struct
fpga_image_info [2] including:
* pointers to the image as either a scatter-gather buffer, a contiguous
buffer, or the name of firmware file
* flags indicating specifics such as whether the image if for partial
reconfiguration.
fpga_image_info including:
===================
The FPGA region API
===================
* pointers to the image as either a scatter-gather buffer, a contiguous
buffer, or the name of firmware file
To register or unregister a region:
-----------------------------------
* flags indicating specifics such as whether the image if for partial
reconfiguration.
int fpga_region_register(struct device *dev,
struct fpga_region *region);
int fpga_region_unregister(struct fpga_region *region);
How to program a FPGA using a region
------------------------------------
An example of usage can be seen in the probe function of [3]
First, allocate the info struct::
To program an FPGA:
-------------------
int fpga_region_program_fpga(struct fpga_region *region);
info = fpga_image_info_alloc(dev);
if (!info)
return -ENOMEM;
Set flags as needed, i.e.::
info->flags |= FPGA_MGR_PARTIAL_RECONFIG;
Point to your FPGA image, such as::
info->sgt = &sgt;
This function operates on info passed in the fpga_image_info
(region->info).
Add info to region and do the programming::
region->info = info;
ret = fpga_region_program_fpga(region);
:c:func:`fpga_region_program_fpga()` operates on info passed in the
fpga_image_info (region->info). This function will attempt to:
This function will attempt to:
* lock the region's mutex
* lock the region's FPGA manager
* build a list of FPGA bridges if a method has been specified to do so
......@@ -64,32 +67,36 @@ This function will attempt to:
* re-enable the bridges
* release the locks
=============
Usage example
=============
Then you will want to enumerate whatever hardware has appeared in the FPGA.
First, allocate the info struct:
How to add a new FPGA region
----------------------------
info = fpga_image_info_alloc(dev);
if (!info)
return -ENOMEM;
An example of usage can be seen in the probe function of [#f2]_.
Set flags as needed, i.e.
.. [#f1] ../devicetree/bindings/fpga/fpga-region.txt
.. [#f2] ../../drivers/fpga/of-fpga-region.c
info->flags |= FPGA_MGR_PARTIAL_RECONFIG;
API to program a FGPA
---------------------
Point to your FPGA image, such as:
.. kernel-doc:: drivers/fpga/fpga-region.c
:functions: fpga_region_program_fpga
info->sgt = &sgt;
API to add a new FPGA region
----------------------------
Add info to region and do the programming:
.. kernel-doc:: include/linux/fpga/fpga-region.h
:functions: fpga_region
region->info = info;
ret = fpga_region_program_fpga(region);
.. kernel-doc:: drivers/fpga/fpga-region.c
:functions: fpga_region_create
.. kernel-doc:: drivers/fpga/fpga-region.c
:functions: fpga_region_free
Then enumerate whatever hardware has appeared in the FPGA.
.. kernel-doc:: drivers/fpga/fpga-region.c
:functions: fpga_region_register
--
[1] ../devicetree/bindings/fpga/fpga-region.txt
[2] ./fpga-mgr.txt
[3] ../../drivers/fpga/of-fpga-region.c
.. kernel-doc:: drivers/fpga/fpga-region.c
:functions: fpga_region_unregister
==============
FPGA Subsystem
==============
:Author: Alan Tull
.. toctree::
:maxdepth: 2
intro
fpga-mgr
fpga-bridge
fpga-region
Introduction
============
The FPGA subsystem supports reprogramming FPGAs dynamically under
Linux. Some of the core intentions of the FPGA subsystems are:
* The FPGA subsystem is vendor agnostic.
* The FPGA subsystem separates upper layers (userspace interfaces and
enumeration) from lower layers that know how to program a specific
FPGA.
* Code should not be shared between upper and lower layers. This
should go without saying. If that seems necessary, there's probably
framework functionality that that can be added that will benefit
other users. Write the linux-fpga mailing list and maintainers and
seek out a solution that expands the framework for broad reuse.
* Generally, when adding code, think of the future. Plan for re-use.
The framework in the kernel is divided into:
FPGA Manager
------------
If you are adding a new FPGA or a new method of programming a FPGA,
this is the subsystem for you. Low level FPGA manager drivers contain
the knowledge of how to program a specific device. This subsystem
includes the framework in fpga-mgr.c and the low level drivers that
are registered with it.
FPGA Bridge
-----------
FPGA Bridges prevent spurious signals from going out of a FPGA or a
region of a FPGA during programming. They are disabled before
programming begins and re-enabled afterwards. An FPGA bridge may be
actual hard hardware that gates a bus to a cpu or a soft ("freeze")
bridge in FPGA fabric that surrounds a partial reconfiguration region
of an FPGA. This subsystem includes fpga-bridge.c and the low level
drivers that are registered with it.
FPGA Region
-----------
If you are adding a new interface to the FPGA framework, add it on top
of a FPGA region to allow the most reuse of your interface.
The FPGA Region framework (fpga-region.c) associates managers and
bridges as reconfigurable regions. A region may refer to the whole
FPGA in full reconfiguration or to a partial reconfiguration region.
The Device Tree FPGA Region support (of-fpga-region.c) handles
reprogramming FPGAs when device tree overlays are applied.
......@@ -51,6 +51,7 @@ available subsections can be seen below.
dmaengine/index
slimbus
soundwire/index
fpga/index
.. only:: subproject and html
......
========================
SoundWire Error Handling
========================
The SoundWire PHY was designed with care and errors on the bus are going to
be very unlikely, and if they happen it should be limited to single bit
errors. Examples of this design can be found in the synchronization
mechanism (sync loss after two errors) and short CRCs used for the Bulk
Register Access.
The errors can be detected with multiple mechanisms:
1. Bus clash or parity errors: This mechanism relies on low-level detectors
that are independent of the payload and usages, and they cover both control
and audio data. The current implementation only logs such errors.
Improvements could be invalidating an entire programming sequence and
restarting from a known position. In the case of such errors outside of a
control/command sequence, there is no concealment or recovery for audio
data enabled by the SoundWire protocol, the location of the error will also
impact its audibility (most-significant bits will be more impacted in PCM),
and after a number of such errors are detected the bus might be reset. Note
that bus clashes due to programming errors (two streams using the same bit
slots) or electrical issues during the transmit/receive transition cannot
be distinguished, although a recurring bus clash when audio is enabled is a
indication of a bus allocation issue. The interrupt mechanism can also help
identify Slaves which detected a Bus Clash or a Parity Error, but they may
not be responsible for the errors so resetting them individually is not a
viable recovery strategy.
2. Command status: Each command is associated with a status, which only
covers transmission of the data between devices. The ACK status indicates
that the command was received and will be executed by the end of the
current frame. A NAK indicates that the command was in error and will not
be applied. In case of a bad programming (command sent to non-existent
Slave or to a non-implemented register) or electrical issue, no response
signals the command was ignored. Some Master implementations allow for a
command to be retransmitted several times. If the retransmission fails,
backtracking and restarting the entire programming sequence might be a
solution. Alternatively some implementations might directly issue a bus
reset and re-enumerate all devices.
3. Timeouts: In a number of cases such as ChannelPrepare or
ClockStopPrepare, the bus driver is supposed to poll a register field until
it transitions to a NotFinished value of zero. The MIPI SoundWire spec 1.1
does not define timeouts but the MIPI SoundWire DisCo document adds
recommendation on timeouts. If such configurations do not complete, the
driver will return a -ETIMEOUT. Such timeouts are symptoms of a faulty
Slave device and are likely impossible to recover from.
Errors during global reconfiguration sequences are extremely difficult to
handle:
1. BankSwitch: An error during the last command issuing a BankSwitch is
difficult to backtrack from. Retransmitting the Bank Switch command may be
possible in a single segment setup, but this can lead to synchronization
problems when enabling multiple bus segments (a command with side effects
such as frame reconfiguration would be handled at different times). A global
hard-reset might be the best solution.
Note that SoundWire does not provide a mechanism to detect illegal values
written in valid registers. In a number of cases the standard even mentions
that the Slave might behave in implementation-defined ways. The bus
implementation does not provide a recovery mechanism for such errors, Slave
or Master driver implementers are responsible for writing valid values in
valid registers and implement additional range checking if needed.
......@@ -6,6 +6,9 @@ SoundWire Documentation
:maxdepth: 1
summary
stream
error_handling
locking
.. only:: subproject
......
=================
SoundWire Locking
=================
This document explains locking mechanism of the SoundWire Bus. Bus uses
following locks in order to avoid race conditions in Bus operations on
shared resources.
- Bus lock
- Message lock
Bus lock
========
SoundWire Bus lock is a mutex and is part of Bus data structure
(sdw_bus) which is used for every Bus instance. This lock is used to
serialize each of the following operations(s) within SoundWire Bus instance.
- Addition and removal of Slave(s), changing Slave status.
- Prepare, Enable, Disable and De-prepare stream operations.
- Access of Stream data structure.
Message lock
============
SoundWire message transfer lock. This mutex is part of
Bus data structure (sdw_bus). This lock is used to serialize the message
transfers (read/write) within a SoundWire Bus instance.
Below examples show how locks are acquired.
Example 1
---------
Message transfer.
1. For every message transfer
a. Acquire Message lock.
b. Transfer message (Read/Write) to Slave1 or broadcast message on
Bus in case of bank switch.
c. Release Message lock ::
+----------+ +---------+
| | | |
| Bus | | Master |
| | | Driver |
| | | |
+----+-----+ +----+----+
| |
| bus->ops->xfer_msg() |
<-------------------------------+ a. Acquire Message lock
| | b. Transfer message
| |
+-------------------------------> c. Release Message lock
| return success/error | d. Return success/error
| |
+ +
Example 2
---------
Prepare operation.
1. Acquire lock for Bus instance associated with Master 1.
2. For every message transfer in Prepare operation
a. Acquire Message lock.
b. Transfer message (Read/Write) to Slave1 or broadcast message on
Bus in case of bank switch.
c. Release Message lock.
3. Release lock for Bus instance associated with Master 1 ::
+----------+ +---------+
| | | |
| Bus | | Master |
| | | Driver |
| | | |
+----+-----+ +----+----+
| |
| sdw_prepare_stream() |
<-------------------------------+ 1. Acquire bus lock
| | 2. Perform stream prepare
| |
| |
| bus->ops->xfer_msg() |
<-------------------------------+ a. Acquire Message lock
| | b. Transfer message
| |
+-------------------------------> c. Release Message lock
| return success/error | d. Return success/error
| |
| |
| return success/error | 3. Release bus lock
+-------------------------------> 4. Return success/error
| |
+ +
This diff is collapsed.
Linux kernel FPGA support
Alan Tull 2017
The main point of this project has been to separate the out the upper layers
that know when to reprogram a FPGA from the lower layers that know how to
reprogram a specific FPGA device. The intention is to make this manufacturer
agnostic, understanding that of course the FPGA images are very device specific
themselves.
The framework in the kernel includes:
* low level FPGA manager drivers that know how to program a specific device
* the fpga-mgr framework they are registered with
* low level FPGA bridge drivers for hard/soft bridges which are intended to
be disable during FPGA programming
* the fpga-bridge framework they are registered with
* the fpga-region framework which associates and controls managers and bridges
as reconfigurable regions
* the of-fpga-region support for reprogramming FPGAs when device tree overlays
are applied.
I would encourage you the user to add code that creates FPGA regions rather
that trying to control managers and bridges separately.
......@@ -328,6 +328,7 @@ Code Seq#(hex) Include File Comments
0xCA 80-BF uapi/scsi/cxlflash_ioctl.h
0xCB 00-1F CBM serial IEC bus in development:
<mailto:michael.klein@puffin.lb.shuttle.de>
0xCC 00-0F drivers/misc/ibmvmc.h pseries VMC driver
0xCD 01 linux/reiserfs_fs.h
0xCF 02 fs/cifs/ioctl.c
0xDB 00-0F drivers/char/mwave/mwavepub.h
......
This diff is collapsed.
......@@ -177,11 +177,11 @@ Here is an example of the debugging output format:
ARM external debug module:
coresight-cpu-debug 850000.debug: CPU[0]:
coresight-cpu-debug 850000.debug: EDPRSR: 00000001 (Power:On DLK:Unlock)
coresight-cpu-debug 850000.debug: EDPCSR: [<ffff00000808e9bc>] handle_IPI+0x174/0x1d8
coresight-cpu-debug 850000.debug: EDPCSR: handle_IPI+0x174/0x1d8
coresight-cpu-debug 850000.debug: EDCIDSR: 00000000
coresight-cpu-debug 850000.debug: EDVIDSR: 90000000 (State:Non-secure Mode:EL1/0 Width:64bits VMID:0)
coresight-cpu-debug 852000.debug: CPU[1]:
coresight-cpu-debug 852000.debug: EDPRSR: 00000001 (Power:On DLK:Unlock)
coresight-cpu-debug 852000.debug: EDPCSR: [<ffff0000087fab34>] debug_notifier_call+0x23c/0x358
coresight-cpu-debug 852000.debug: EDPCSR: debug_notifier_call+0x23c/0x358
coresight-cpu-debug 852000.debug: EDCIDSR: 00000000
coresight-cpu-debug 852000.debug: EDVIDSR: 90000000 (State:Non-secure Mode:EL1/0 Width:64bits VMID:0)
......@@ -5586,6 +5586,7 @@ S: Maintained
T: git git://git.kernel.org/pub/scm/linux/kernel/git/atull/linux-fpga.git
Q: http://patchwork.kernel.org/project/linux-fpga/list/
F: Documentation/fpga/
F: Documentation/driver-api/fpga/
F: Documentation/devicetree/bindings/fpga/
F: drivers/fpga/
F: include/linux/fpga/
......@@ -6773,6 +6774,12 @@ L: linux-scsi@vger.kernel.org
S: Supported
F: drivers/scsi/ibmvscsi/ibmvfc*
IBM Power Virtual Management Channel Driver
M: Bryant G. Ly <bryantly@linux.vnet.ibm.com>
M: Steven Royer <seroyer@linux.vnet.ibm.com>
S: Supported
F: drivers/misc/ibmvmc.*
IBM Power Virtual SCSI Device Drivers
M: Tyrel Datwyler <tyreld@linux.vnet.ibm.com>
L: linux-scsi@vger.kernel.org
......@@ -13136,7 +13143,7 @@ F: include/uapi/sound/
F: sound/
SOUND - COMPRESSED AUDIO
M: Vinod Koul <vinod.koul@intel.com>
M: Vinod Koul <vkoul@kernel.org>
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
T: git git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git
S: Supported
......
......@@ -279,6 +279,7 @@
#define H_GET_MPP_X 0x314
#define H_SET_MODE 0x31C
#define H_CLEAR_HPT 0x358
#define H_REQUEST_VMC 0x360
#define H_RESIZE_HPT_PREPARE 0x36C
#define H_RESIZE_HPT_COMMIT 0x370
#define H_REGISTER_PROC_TBL 0x37C
......
......@@ -102,8 +102,8 @@ static ssize_t driver_override_store(struct device *_dev,
if (strlen(driver_override)) {
dev->driver_override = driver_override;
} else {
kfree(driver_override);
dev->driver_override = NULL;
kfree(driver_override);
dev->driver_override = NULL;
}
device_unlock(_dev);
......
......@@ -10,7 +10,7 @@ if ANDROID
config ANDROID_BINDER_IPC
bool "Android Binder IPC Driver"
depends on MMU
depends on MMU && !M68K
default n
---help---
Binder is used in Android for both communication between processes,
......@@ -32,19 +32,6 @@ config ANDROID_BINDER_DEVICES
created. Each binder device has its own context manager, and is
therefore logically separated from the other devices.
config ANDROID_BINDER_IPC_32BIT
bool "Use old (Android 4.4 and earlier) 32-bit binder API"
depends on !64BIT && ANDROID_BINDER_IPC
default y
---help---
The Binder API has been changed to support both 32 and 64bit
applications in a mixed environment.
Enable this to support an old 32-bit Android user-space (v4.4 and
earlier).
Note that enabling this will break newer Android user-space.
config ANDROID_BINDER_IPC_SELFTEST
bool "Android Binder IPC Driver Selftest"
depends on ANDROID_BINDER_IPC
......
......@@ -72,10 +72,6 @@
#include <linux/security.h>
#include <linux/spinlock.h>
#ifdef CONFIG_ANDROID_BINDER_IPC_32BIT
#define BINDER_IPC_32BIT 1
#endif
#include <uapi/linux/android/binder.h>
#include "binder_alloc.h"
#include "binder_trace.h"
......@@ -2058,8 +2054,8 @@ static size_t binder_validate_object(struct binder_buffer *buffer, u64 offset)
struct binder_object_header *hdr;
size_t object_size = 0;
if (offset > buffer->data_size - sizeof(*hdr) ||
buffer->data_size < sizeof(*hdr) ||
if (buffer->data_size < sizeof(*hdr) ||
offset > buffer->data_size - sizeof(*hdr) ||
!IS_ALIGNED(offset, sizeof(u32)))
return 0;
......@@ -3925,10 +3921,11 @@ static int binder_thread_read(struct binder_proc *proc,
binder_inner_proc_unlock(proc);
if (put_user(e->cmd, (uint32_t __user *)ptr))
return -EFAULT;
cmd = e->cmd;
e->cmd = BR_OK;
ptr += sizeof(uint32_t);
binder_stat_br(proc, thread, e->cmd);
binder_stat_br(proc, thread, cmd);
} break;
case BINDER_WORK_TRANSACTION_COMPLETE: {
binder_inner_proc_unlock(proc);
......@@ -4696,7 +4693,7 @@ static void binder_vma_close(struct vm_area_struct *vma)
binder_defer_work(proc, BINDER_DEFERRED_PUT_FILES);
}
static int binder_vm_fault(struct vm_fault *vmf)
static vm_fault_t binder_vm_fault(struct vm_fault *vmf)
{
return VM_FAULT_SIGBUS;
}
......@@ -4730,7 +4727,9 @@ static int binder_mmap(struct file *filp, struct vm_area_struct *vma)
failure_string = "bad vm_flags";
goto err_bad_arg;
}
vma->vm_flags = (vma->vm_flags | VM_DONTCOPY) & ~VM_MAYWRITE;
vma->vm_flags |= VM_DONTCOPY | VM_MIXEDMAP;
vma->vm_flags &= ~VM_MAYWRITE;
vma->vm_ops = &binder_vm_ops;
vma->vm_private_data = proc;
......
......@@ -219,7 +219,7 @@ static int binder_update_page_range(struct binder_alloc *alloc, int allocate,
mm = alloc->vma_vm_mm;
if (mm) {
down_write(&mm->mmap_sem);
down_read(&mm->mmap_sem);
vma = alloc->vma;
}
......@@ -288,7 +288,7 @@ static int binder_update_page_range(struct binder_alloc *alloc, int allocate,
/* vm_insert_page does not seem to increment the refcount */
}
if (mm) {
up_write(&mm->mmap_sem);
up_read(&mm->mmap_sem);
mmput(mm);
}
return 0;
......@@ -321,7 +321,7 @@ static int binder_update_page_range(struct binder_alloc *alloc, int allocate,
}
err_no_vma:
if (mm) {
up_write(&mm->mmap_sem);
up_read(&mm->mmap_sem);
mmput(mm);
}
return vma ? -ENOMEM : -ESRCH;
......
......@@ -191,7 +191,7 @@ mspec_close(struct vm_area_struct *vma)
*
* Creates a mspec page and maps it to user space.
*/
static int
static vm_fault_t
mspec_fault(struct vm_fault *vmf)
{
unsigned long paddr, maddr;
......@@ -223,14 +223,7 @@ mspec_fault(struct vm_fault *vmf)
pfn = paddr >> PAGE_SHIFT;
/*
* vm_insert_pfn can fail with -EBUSY, but in that case it will
* be because another thread has installed the pte first, so it
* is no problem.
*/
vm_insert_pfn(vmf->vma, vmf->address, pfn);
return VM_FAULT_NOPAGE;
return vmf_insert_pfn(vmf->vma, vmf->address, pfn);
}
static const struct vm_operations_struct mspec_vm_ops = {
......
......@@ -55,6 +55,14 @@ config GOOGLE_MEMCONSOLE_X86_LEGACY
the EBDA on Google servers. If found, this log is exported to
userland in the file /sys/firmware/log.
config GOOGLE_FRAMEBUFFER_COREBOOT
tristate "Coreboot Framebuffer"
depends on FB_SIMPLE
depends on GOOGLE_COREBOOT_TABLE
help
This option enables the kernel to search for a framebuffer in
the coreboot table. If found, it is registered with simplefb.
config GOOGLE_MEMCONSOLE_COREBOOT
tristate "Firmware Memory Console"
depends on GOOGLE_COREBOOT_TABLE
......
......@@ -4,6 +4,7 @@ obj-$(CONFIG_GOOGLE_SMI) += gsmi.o
obj-$(CONFIG_GOOGLE_COREBOOT_TABLE) += coreboot_table.o
obj-$(CONFIG_GOOGLE_COREBOOT_TABLE_ACPI) += coreboot_table-acpi.o
obj-$(CONFIG_GOOGLE_COREBOOT_TABLE_OF) += coreboot_table-of.o
obj-$(CONFIG_GOOGLE_FRAMEBUFFER_COREBOOT) += framebuffer-coreboot.o
obj-$(CONFIG_GOOGLE_MEMCONSOLE) += memconsole.o
obj-$(CONFIG_GOOGLE_MEMCONSOLE_COREBOOT) += memconsole-coreboot.o
obj-$(CONFIG_GOOGLE_MEMCONSOLE_X86_LEGACY) += memconsole-x86-legacy.o
......
......@@ -53,7 +53,7 @@ static int coreboot_table_acpi_probe(struct platform_device *pdev)
if (!ptr)
return -ENOMEM;
return coreboot_table_init(ptr);
return coreboot_table_init(&pdev->dev, ptr);
}
static int coreboot_table_acpi_remove(struct platform_device *pdev)
......
......@@ -34,7 +34,7 @@ static int coreboot_table_of_probe(struct platform_device *pdev)
if (!ptr)
return -ENOMEM;
return coreboot_table_init(ptr);
return coreboot_table_init(&pdev->dev, ptr);
}
static int coreboot_table_of_remove(struct platform_device *pdev)
......
......@@ -4,6 +4,7 @@
* Module providing coreboot table access.
*
* Copyright 2017 Google Inc.
* Copyright 2017 Samuel Holland <samuel@sholland.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License v2.0 as published by
......@@ -15,37 +16,96 @@
* GNU General Public License for more details.
*/
#include <linux/device.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include "coreboot_table.h"
struct coreboot_table_entry {
u32 tag;
u32 size;
};
#define CB_DEV(d) container_of(d, struct coreboot_device, dev)
#define CB_DRV(d) container_of(d, struct coreboot_driver, drv)
static struct coreboot_table_header __iomem *ptr_header;
/*
* This function parses the coreboot table for an entry that contains the base
* address of the given entry tag. The coreboot table consists of a header
* directly followed by a number of small, variable-sized entries, which each
* contain an identifying tag and their length as the first two fields.
*/
int coreboot_table_find(int tag, void *data, size_t data_size)
static int coreboot_bus_match(struct device *dev, struct device_driver *drv)
{
struct coreboot_table_header header;
struct coreboot_table_entry entry;
void *ptr_entry;
int i;
struct coreboot_device *device = CB_DEV(dev);
struct coreboot_driver *driver = CB_DRV(drv);
if (!ptr_header)
return -EPROBE_DEFER;
return device->entry.tag == driver->tag;
}
static int coreboot_bus_probe(struct device *dev)
{
int ret = -ENODEV;
struct coreboot_device *device = CB_DEV(dev);
struct coreboot_driver *driver = CB_DRV(dev->driver);
if (driver->probe)
ret = driver->probe(device);
return ret;
}
static int coreboot_bus_remove(struct device *dev)
{
int ret = 0;
struct coreboot_device *device = CB_DEV(dev);
struct coreboot_driver *driver = CB_DRV(dev->driver);
if (driver->remove)
ret = driver->remove(device);
return ret;
}
static struct bus_type coreboot_bus_type = {
.name = "coreboot",
.match = coreboot_bus_match,
.probe = coreboot_bus_probe,
.remove = coreboot_bus_remove,
};
static int __init coreboot_bus_init(void)
{
return bus_register(&coreboot_bus_type);
}
module_init(coreboot_bus_init);
static void coreboot_device_release(struct device *dev)
{
struct coreboot_device *device = CB_DEV(dev);
kfree(device);
}
int coreboot_driver_register(struct coreboot_driver *driver)
{
driver->drv.bus = &coreboot_bus_type;
return driver_register(&driver->drv);
}
EXPORT_SYMBOL(coreboot_driver_register);
void coreboot_driver_unregister(struct coreboot_driver *driver)
{
driver_unregister(&driver->drv);
}
EXPORT_SYMBOL(coreboot_driver_unregister);
int coreboot_table_init(struct device *dev, void __iomem *ptr)
{
int i, ret;
void *ptr_entry;
struct coreboot_device *device;
struct coreboot_table_entry entry;
struct coreboot_table_header header;
ptr_header = ptr;
memcpy_fromio(&header, ptr_header, sizeof(header));
if (strncmp(header.signature, "LBIO", sizeof(header.signature))) {
......@@ -54,37 +114,41 @@ int coreboot_table_find(int tag, void *data, size_t data_size)
}
ptr_entry = (void *)ptr_header + header.header_bytes;
for (i = 0; i < header.table_entries; i++) {
memcpy_fromio(&entry, ptr_entry, sizeof(entry));
if (entry.tag == tag) {
if (data_size < entry.size)
return -EINVAL;
memcpy_fromio(data, ptr_entry, entry.size);
device = kzalloc(sizeof(struct device) + entry.size, GFP_KERNEL);
if (!device) {
ret = -ENOMEM;
break;
}
dev_set_name(&device->dev, "coreboot%d", i);
device->dev.parent = dev;
device->dev.bus = &coreboot_bus_type;
device->dev.release = coreboot_device_release;
memcpy_fromio(&device->entry, ptr_entry, entry.size);
return 0;
ret = device_register(&device->dev);
if (ret) {
put_device(&device->dev);
break;
}
ptr_entry += entry.size;
}
return -ENOENT;
}
EXPORT_SYMBOL(coreboot_table_find);
int coreboot_table_init(void __iomem *ptr)
{
ptr_header = ptr;
return 0;
return ret;
}
EXPORT_SYMBOL(coreboot_table_init);
int coreboot_table_exit(void)
{
if (ptr_header)
if (ptr_header) {
bus_unregister(&coreboot_bus_type);
iounmap(ptr_header);
ptr_header = NULL;
}
return 0;
}
......
......@@ -3,7 +3,9 @@
*
* Internal header for coreboot table access.
*
* Copyright 2014 Gerd Hoffmann <kraxel@redhat.com>
* Copyright 2017 Google Inc.
* Copyright 2017 Samuel Holland <samuel@sholland.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License v2.0 as published by
......@@ -20,14 +22,6 @@
#include <linux/io.h>
/* List of coreboot entry structures that is used */
struct lb_cbmem_ref {
uint32_t tag;
uint32_t size;
uint64_t cbmem_addr;
};
/* Coreboot table header structure */
struct coreboot_table_header {
char signature[4];
......@@ -38,11 +32,67 @@ struct coreboot_table_header {
u32 table_entries;
};
/* Retrieve coreboot table entry with tag *tag* and copy it to data */
int coreboot_table_find(int tag, void *data, size_t data_size);
/* List of coreboot entry structures that is used */
/* Generic */
struct coreboot_table_entry {
u32 tag;
u32 size;
};
/* Points to a CBMEM entry */
struct lb_cbmem_ref {
u32 tag;
u32 size;
u64 cbmem_addr;
};
/* Describes framebuffer setup by coreboot */
struct lb_framebuffer {
u32 tag;
u32 size;
u64 physical_address;
u32 x_resolution;
u32 y_resolution;
u32 bytes_per_line;
u8 bits_per_pixel;
u8 red_mask_pos;
u8 red_mask_size;
u8 green_mask_pos;
u8 green_mask_size;
u8 blue_mask_pos;
u8 blue_mask_size;
u8 reserved_mask_pos;
u8 reserved_mask_size;
};
/* A device, additionally with information from coreboot. */
struct coreboot_device {
struct device dev;
union {
struct coreboot_table_entry entry;
struct lb_cbmem_ref cbmem_ref;
struct lb_framebuffer framebuffer;
};
};
/* A driver for handling devices described in coreboot tables. */
struct coreboot_driver {
int (*probe)(struct coreboot_device *);
int (*remove)(struct coreboot_device *);
struct device_driver drv;
u32 tag;
};
/* Register a driver that uses the data from a coreboot table. */
int coreboot_driver_register(struct coreboot_driver *driver);
/* Unregister a driver that uses the data from a coreboot table. */
void coreboot_driver_unregister(struct coreboot_driver *driver);
/* Initialize coreboot table module given a pointer to iomem */
int coreboot_table_init(void __iomem *ptr);
int coreboot_table_init(struct device *dev, void __iomem *ptr);
/* Cleanup coreboot table module */
int coreboot_table_exit(void);
......
/*
* framebuffer-coreboot.c
*
* Memory based framebuffer accessed through coreboot table.
*
* Copyright 2012-2013 David Herrmann <dh.herrmann@gmail.com>
* Copyright 2017 Google Inc.
* Copyright 2017 Samuel Holland <samuel@sholland.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License v2.0 as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/platform_data/simplefb.h>
#include <linux/platform_device.h>
#include "coreboot_table.h"
#define CB_TAG_FRAMEBUFFER 0x12
static const struct simplefb_format formats[] = SIMPLEFB_FORMATS;
static int framebuffer_probe(struct coreboot_device *dev)
{
int i;
u32 length;
struct lb_framebuffer *fb = &dev->framebuffer;
struct platform_device *pdev;
struct resource res;
struct simplefb_platform_data pdata = {
.width = fb->x_resolution,
.height = fb->y_resolution,
.stride = fb->bytes_per_line,
.format = NULL,
};
for (i = 0; i < ARRAY_SIZE(formats); ++i) {
if (fb->bits_per_pixel == formats[i].bits_per_pixel &&
fb->red_mask_pos == formats[i].red.offset &&
fb->red_mask_size == formats[i].red.length &&
fb->green_mask_pos == formats[i].green.offset &&
fb->green_mask_size == formats[i].green.length &&
fb->blue_mask_pos == formats[i].blue.offset &&
fb->blue_mask_size == formats[i].blue.length &&
fb->reserved_mask_pos == formats[i].transp.offset &&
fb->reserved_mask_size == formats[i].transp.length)
pdata.format = formats[i].name;
}
if (!pdata.format)
return -ENODEV;
memset(&res, 0, sizeof(res));
res.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
res.name = "Coreboot Framebuffer";
res.start = fb->physical_address;
length = PAGE_ALIGN(fb->y_resolution * fb->bytes_per_line);
res.end = res.start + length - 1;
if (res.end <= res.start)
return -EINVAL;
pdev = platform_device_register_resndata(&dev->dev,
"simple-framebuffer", 0,
&res, 1, &pdata,
sizeof(pdata));
if (IS_ERR(pdev))
pr_warn("coreboot: could not register framebuffer\n");
else
dev_set_drvdata(&dev->dev, pdev);
return PTR_ERR_OR_ZERO(pdev);
}
static int framebuffer_remove(struct coreboot_device *dev)
{
struct platform_device *pdev = dev_get_drvdata(&dev->dev);
platform_device_unregister(pdev);
return 0;
}
static struct coreboot_driver framebuffer_driver = {
.probe = framebuffer_probe,
.remove = framebuffer_remove,
.drv = {
.name = "framebuffer",
},
.tag = CB_TAG_FRAMEBUFFER,
};
static int __init coreboot_framebuffer_init(void)
{
return coreboot_driver_register(&framebuffer_driver);
}
static void coreboot_framebuffer_exit(void)
{
coreboot_driver_unregister(&framebuffer_driver);
}
module_init(coreboot_framebuffer_init);
module_exit(coreboot_framebuffer_exit);
MODULE_AUTHOR("Samuel Holland <samuel@sholland.org>");
MODULE_LICENSE("GPL");
......@@ -15,9 +15,9 @@
* GNU General Public License for more details.
*/
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include "memconsole.h"
#include "coreboot_table.h"
......@@ -73,18 +73,19 @@ static ssize_t memconsole_coreboot_read(char *buf, loff_t pos, size_t count)
return done;
}
static int memconsole_coreboot_init(phys_addr_t physaddr)
static int memconsole_probe(struct coreboot_device *dev)
{
struct cbmem_cons __iomem *tmp_cbmc;
tmp_cbmc = memremap(physaddr, sizeof(*tmp_cbmc), MEMREMAP_WB);
tmp_cbmc = memremap(dev->cbmem_ref.cbmem_addr,
sizeof(*tmp_cbmc), MEMREMAP_WB);
if (!tmp_cbmc)
return -ENOMEM;
/* Read size only once to prevent overrun attack through /dev/mem. */
cbmem_console_size = tmp_cbmc->size_dont_access_after_boot;
cbmem_console = memremap(physaddr,
cbmem_console = memremap(dev->cbmem_ref.cbmem_addr,
cbmem_console_size + sizeof(*cbmem_console),
MEMREMAP_WB);
memunmap(tmp_cbmc);
......@@ -93,26 +94,11 @@ static int memconsole_coreboot_init(phys_addr_t physaddr)
return -ENOMEM;
memconsole_setup(memconsole_coreboot_read);
return 0;
}
static int memconsole_probe(struct platform_device *pdev)
{
int ret;
struct lb_cbmem_ref entry;
ret = coreboot_table_find(CB_TAG_CBMEM_CONSOLE, &entry, sizeof(entry));
if (ret)
return ret;
ret = memconsole_coreboot_init(entry.cbmem_addr);
if (ret)
return ret;
return memconsole_sysfs_init();
}
static int memconsole_remove(struct platform_device *pdev)
static int memconsole_remove(struct coreboot_device *dev)
{
memconsole_exit();
......@@ -122,28 +108,27 @@ static int memconsole_remove(struct platform_device *pdev)
return 0;
}
static struct platform_driver memconsole_driver = {
static struct coreboot_driver memconsole_driver = {
.probe = memconsole_probe,
.remove = memconsole_remove,
.driver = {
.drv = {
.name = "memconsole",
},
.tag = CB_TAG_CBMEM_CONSOLE,
};
static int __init platform_memconsole_init(void)
static void coreboot_memconsole_exit(void)
{
struct platform_device *pdev;
pdev = platform_device_register_simple("memconsole", -1, NULL, 0);
if (IS_ERR(pdev))
return PTR_ERR(pdev);
platform_driver_register(&memconsole_driver);
coreboot_driver_unregister(&memconsole_driver);
}
return 0;
static int __init coreboot_memconsole_init(void)
{
return coreboot_driver_register(&memconsole_driver);
}
module_init(platform_memconsole_init);
module_exit(coreboot_memconsole_exit);
module_init(coreboot_memconsole_init);
MODULE_AUTHOR("Google, Inc.");
MODULE_LICENSE("GPL");
......@@ -286,20 +286,15 @@ static int vpd_sections_init(phys_addr_t physaddr)
return 0;
}
static int vpd_probe(struct platform_device *pdev)
static int vpd_probe(struct coreboot_device *dev)
{
int ret;
struct lb_cbmem_ref entry;
ret = coreboot_table_find(CB_TAG_VPD, &entry, sizeof(entry));
if (ret)
return ret;
vpd_kobj = kobject_create_and_add("vpd", firmware_kobj);
if (!vpd_kobj)
return -ENOMEM;
ret = vpd_sections_init(entry.cbmem_addr);
ret = vpd_sections_init(dev->cbmem_ref.cbmem_addr);
if (ret) {
kobject_put(vpd_kobj);
return ret;
......@@ -308,7 +303,7 @@ static int vpd_probe(struct platform_device *pdev)
return 0;
}
static int vpd_remove(struct platform_device *pdev)
static int vpd_remove(struct coreboot_device *dev)
{
vpd_section_destroy(&ro_vpd);
vpd_section_destroy(&rw_vpd);
......@@ -318,41 +313,27 @@ static int vpd_remove(struct platform_device *pdev)
return 0;
}
static struct platform_driver vpd_driver = {
static struct coreboot_driver vpd_driver = {
.probe = vpd_probe,
.remove = vpd_remove,
.driver = {
.drv = {
.name = "vpd",
},
.tag = CB_TAG_VPD,
};
static struct platform_device *vpd_pdev;
static int __init vpd_platform_init(void)
static int __init coreboot_vpd_init(void)
{
int ret;
ret = platform_driver_register(&vpd_driver);
if (ret)
return ret;
vpd_pdev = platform_device_register_simple("vpd", -1, NULL, 0);
if (IS_ERR(vpd_pdev)) {
platform_driver_unregister(&vpd_driver);
return PTR_ERR(vpd_pdev);
}
return 0;
return coreboot_driver_register(&vpd_driver);
}
static void __exit vpd_platform_exit(void)
static void __exit coreboot_vpd_exit(void)
{
platform_device_unregister(vpd_pdev);
platform_driver_unregister(&vpd_driver);
coreboot_driver_unregister(&vpd_driver);
}
module_init(vpd_platform_init);
module_exit(vpd_platform_exit);
module_init(coreboot_vpd_init);
module_exit(coreboot_vpd_exit);
MODULE_AUTHOR("Google, Inc.");
MODULE_LICENSE("GPL");
......@@ -53,7 +53,6 @@ config FPGA_MGR_ALTERA_CVP
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.
......@@ -70,6 +69,13 @@ config FPGA_MGR_ICE40_SPI
help
FPGA manager driver support for Lattice iCE40 FPGAs over SPI.
config FPGA_MGR_MACHXO2_SPI
tristate "Lattice MachXO2 SPI"
depends on SPI
help
FPGA manager driver support for Lattice MachXO2 configuration
over slave SPI interface.
config FPGA_MGR_TS73XX
tristate "Technologic Systems TS-73xx SBC FPGA Manager"
depends on ARCH_EP93XX && MACH_TS72XX
......
......@@ -10,6 +10,7 @@ obj-$(CONFIG_FPGA) += fpga-mgr.o
obj-$(CONFIG_FPGA_MGR_ALTERA_CVP) += altera-cvp.o
obj-$(CONFIG_FPGA_MGR_ALTERA_PS_SPI) += altera-ps-spi.o
obj-$(CONFIG_FPGA_MGR_ICE40_SPI) += ice40-spi.o
obj-$(CONFIG_FPGA_MGR_MACHXO2_SPI) += machxo2-spi.o
obj-$(CONFIG_FPGA_MGR_SOCFPGA) += socfpga.o
obj-$(CONFIG_FPGA_MGR_SOCFPGA_A10) += socfpga-a10.o
obj-$(CONFIG_FPGA_MGR_TS73XX) += ts73xx-fpga.o
......
......@@ -401,6 +401,7 @@ static int altera_cvp_probe(struct pci_dev *pdev,
const struct pci_device_id *dev_id)
{
struct altera_cvp_conf *conf;
struct fpga_manager *mgr;
u16 cmd, val;
int ret;
......@@ -452,16 +453,24 @@ static int altera_cvp_probe(struct pci_dev *pdev,
snprintf(conf->mgr_name, sizeof(conf->mgr_name), "%s @%s",
ALTERA_CVP_MGR_NAME, pci_name(pdev));
ret = fpga_mgr_register(&pdev->dev, conf->mgr_name,
&altera_cvp_ops, conf);
if (ret)
mgr = fpga_mgr_create(&pdev->dev, conf->mgr_name,
&altera_cvp_ops, conf);
if (!mgr)
return -ENOMEM;
pci_set_drvdata(pdev, mgr);
ret = fpga_mgr_register(mgr);
if (ret) {
fpga_mgr_free(mgr);
goto err_unmap;
}
ret = driver_create_file(&altera_cvp_driver.driver,
&driver_attr_chkcfg);
if (ret) {
dev_err(&pdev->dev, "Can't create sysfs chkcfg file\n");
fpga_mgr_unregister(&pdev->dev);
fpga_mgr_unregister(mgr);
goto err_unmap;
}
......@@ -483,7 +492,7 @@ static void altera_cvp_remove(struct pci_dev *pdev)
u16 cmd;
driver_remove_file(&altera_cvp_driver.driver, &driver_attr_chkcfg);
fpga_mgr_unregister(&pdev->dev);
fpga_mgr_unregister(mgr);
pci_iounmap(pdev, conf->map);
pci_release_region(pdev, CVP_BAR);
pci_read_config_word(pdev, PCI_COMMAND, &cmd);
......
// SPDX-License-Identifier: GPL-2.0
/*
* 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/>.
*/
/*
......@@ -106,6 +95,7 @@ static int alt_fpga_bridge_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct alt_fpga2sdram_data *priv;
struct fpga_bridge *br;
u32 enable;
struct regmap *sysmgr;
int ret = 0;
......@@ -131,10 +121,18 @@ static int alt_fpga_bridge_probe(struct platform_device *pdev)
/* 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)
br = fpga_bridge_create(dev, F2S_BRIDGE_NAME,
&altera_fpga2sdram_br_ops, priv);
if (!br)
return -ENOMEM;
platform_set_drvdata(pdev, br);
ret = fpga_bridge_register(br);
if (ret) {
fpga_bridge_free(br);
return ret;
}
dev_info(dev, "driver initialized with handoff %08x\n", priv->mask);
......@@ -146,7 +144,7 @@ static int alt_fpga_bridge_probe(struct platform_device *pdev)
(enable ? "enabling" : "disabling"));
ret = _alt_fpga2sdram_enable_set(priv, enable);
if (ret) {
fpga_bridge_unregister(&pdev->dev);
fpga_bridge_unregister(br);
return ret;
}
}
......@@ -157,7 +155,9 @@ static int alt_fpga_bridge_probe(struct platform_device *pdev)
static int alt_fpga_bridge_remove(struct platform_device *pdev)
{
fpga_bridge_unregister(&pdev->dev);
struct fpga_bridge *br = platform_get_drvdata(pdev);
fpga_bridge_unregister(br);
return 0;
}
......
// SPDX-License-Identifier: GPL-2.0
/*
* 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>
......@@ -221,8 +210,10 @@ static int altera_freeze_br_probe(struct platform_device *pdev)
struct device_node *np = pdev->dev.of_node;
void __iomem *base_addr;
struct altera_freeze_br_data *priv;
struct fpga_bridge *br;
struct resource *res;
u32 status, revision;
int ret;
if (!np)
return -ENODEV;
......@@ -254,13 +245,27 @@ static int altera_freeze_br_probe(struct platform_device *pdev)
priv->base_addr = base_addr;
return fpga_bridge_register(dev, FREEZE_BRIDGE_NAME,
&altera_freeze_br_br_ops, priv);
br = fpga_bridge_create(dev, FREEZE_BRIDGE_NAME,
&altera_freeze_br_br_ops, priv);
if (!br)
return -ENOMEM;
platform_set_drvdata(pdev, br);
ret = fpga_bridge_register(br);
if (ret) {
fpga_bridge_free(br);
return ret;
}
return 0;
}
static int altera_freeze_br_remove(struct platform_device *pdev)
{
fpga_bridge_unregister(&pdev->dev);
struct fpga_bridge *br = platform_get_drvdata(pdev);
fpga_bridge_unregister(br);
return 0;
}
......
// SPDX-License-Identifier: GPL-2.0
/*
* FPGA to/from HPS Bridge Driver for Altera SoCFPGA Devices
*
......@@ -6,18 +7,6 @@
* 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/>.
*/
/*
......@@ -139,6 +128,7 @@ 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;
struct fpga_bridge *br;
u32 enable;
int ret;
......@@ -190,11 +180,24 @@ static int alt_fpga_bridge_probe(struct platform_device *pdev)
}
}
ret = fpga_bridge_register(dev, priv->name, &altera_hps2fpga_br_ops,
priv);
err:
br = fpga_bridge_create(dev, priv->name, &altera_hps2fpga_br_ops, priv);
if (!br) {
ret = -ENOMEM;
goto err;
}
platform_set_drvdata(pdev, br);
ret = fpga_bridge_register(br);
if (ret)
clk_disable_unprepare(priv->clk);
goto err_free;
return 0;
err_free:
fpga_bridge_free(br);
err:
clk_disable_unprepare(priv->clk);
return ret;
}
......@@ -204,7 +207,7 @@ 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);
fpga_bridge_unregister(bridge);
clk_disable_unprepare(priv->clk);
......
// SPDX-License-Identifier: GPL-2.0
/*
* Driver for Altera Partial Reconfiguration IP Core
*
......@@ -5,18 +6,6 @@
*
* Based on socfpga-a10.c Copyright (C) 2015-2016 Altera Corporation
* by Alan Tull <atull@opensource.altera.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* 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/altera-pr-ip-core.h>
#include <linux/module.h>
......
// SPDX-License-Identifier: GPL-2.0
/*
* Driver for Altera Partial Reconfiguration IP Core
*
......@@ -5,18 +6,6 @@
*
* Based on socfpga-a10.c Copyright (C) 2015-2016 Altera Corporation
* by Alan Tull <atull@opensource.altera.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* 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/fpga/altera-pr-ip-core.h>
......@@ -187,6 +176,8 @@ static const struct fpga_manager_ops alt_pr_ops = {
int alt_pr_register(struct device *dev, void __iomem *reg_base)
{
struct alt_pr_priv *priv;
struct fpga_manager *mgr;
int ret;
u32 val;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
......@@ -201,15 +192,27 @@ int alt_pr_register(struct device *dev, void __iomem *reg_base)
(val & ALT_PR_CSR_STATUS_MSK) >> ALT_PR_CSR_STATUS_SFT,
(int)(val & ALT_PR_CSR_PR_START));
return fpga_mgr_register(dev, dev_name(dev), &alt_pr_ops, priv);
mgr = fpga_mgr_create(dev, dev_name(dev), &alt_pr_ops, priv);
if (!mgr)
return -ENOMEM;
dev_set_drvdata(dev, mgr);
ret = fpga_mgr_register(mgr);
if (ret)
fpga_mgr_free(mgr);
return ret;
}
EXPORT_SYMBOL_GPL(alt_pr_register);
int alt_pr_unregister(struct device *dev)
{
struct fpga_manager *mgr = dev_get_drvdata(dev);
dev_dbg(dev, "%s\n", __func__);
fpga_mgr_unregister(dev);
fpga_mgr_unregister(mgr);
return 0;
}
......
......@@ -238,6 +238,8 @@ static int altera_ps_probe(struct spi_device *spi)
{
struct altera_ps_conf *conf;
const struct of_device_id *of_id;
struct fpga_manager *mgr;
int ret;
conf = devm_kzalloc(&spi->dev, sizeof(*conf), GFP_KERNEL);
if (!conf)
......@@ -273,13 +275,25 @@ static int altera_ps_probe(struct spi_device *spi)
snprintf(conf->mgr_name, sizeof(conf->mgr_name), "%s %s",
dev_driver_string(&spi->dev), dev_name(&spi->dev));
return fpga_mgr_register(&spi->dev, conf->mgr_name,
&altera_ps_ops, conf);
mgr = fpga_mgr_create(&spi->dev, conf->mgr_name,
&altera_ps_ops, conf);
if (!mgr)
return -ENOMEM;
spi_set_drvdata(spi, mgr);
ret = fpga_mgr_register(mgr);
if (ret)
fpga_mgr_free(mgr);
return ret;
}
static int altera_ps_remove(struct spi_device *spi)
{
fpga_mgr_unregister(&spi->dev);
struct fpga_manager *mgr = spi_get_drvdata(spi);
fpga_mgr_unregister(mgr);
return 0;
}
......
// SPDX-License-Identifier: GPL-2.0
/*
* FPGA Bridge Framework Driver
*
* Copyright (C) 2013-2016 Altera Corporation, All Rights Reserved.
* Copyright (C) 2017 Intel Corporation
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/fpga/fpga-bridge.h>
#include <linux/idr.h>
......@@ -132,6 +121,7 @@ static int fpga_bridge_dev_match(struct device *dev, const void *data)
/**
* fpga_bridge_get - get an exclusive reference to a fpga bridge
* @dev: parent device that fpga bridge was registered with
* @info: fpga manager info
*
* Given a device, get an exclusive reference to a fpga bridge.
*
......@@ -328,28 +318,29 @@ static struct attribute *fpga_bridge_attrs[] = {
ATTRIBUTE_GROUPS(fpga_bridge);
/**
* fpga_bridge_register - register a fpga bridge driver
* fpga_bridge_create - create and initialize a struct fpga_bridge
* @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.
* Return: struct fpga_bridge or NULL
*/
int fpga_bridge_register(struct device *dev, const char *name,
const struct fpga_bridge_ops *br_ops, void *priv)
struct fpga_bridge *fpga_bridge_create(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;
return NULL;
}
bridge = kzalloc(sizeof(*bridge), GFP_KERNEL);
if (!bridge)
return -ENOMEM;
return NULL;
id = ida_simple_get(&fpga_bridge_ida, 0, 0, GFP_KERNEL);
if (id < 0) {
......@@ -370,40 +361,62 @@ int fpga_bridge_register(struct device *dev, const char *name,
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;
return bridge;
error_device:
ida_simple_remove(&fpga_bridge_ida, id);
error_kfree:
kfree(bridge);
return ret;
return NULL;
}
EXPORT_SYMBOL_GPL(fpga_bridge_register);
EXPORT_SYMBOL_GPL(fpga_bridge_create);
/**
* fpga_bridge_unregister - unregister a fpga bridge driver
* @dev: FPGA bridge device from pdev
* fpga_bridge_free - free a fpga bridge and its id
* @bridge: FPGA bridge struct created by fpga_bridge_create
*/
void fpga_bridge_unregister(struct device *dev)
void fpga_bridge_free(struct fpga_bridge *bridge)
{
struct fpga_bridge *bridge = dev_get_drvdata(dev);
ida_simple_remove(&fpga_bridge_ida, bridge->dev.id);
kfree(bridge);
}
EXPORT_SYMBOL_GPL(fpga_bridge_free);
/**
* fpga_bridge_register - register a fpga bridge
* @bridge: FPGA bridge struct created by fpga_bridge_create
*
* Return: 0 for success, error code otherwise.
*/
int fpga_bridge_register(struct fpga_bridge *bridge)
{
struct device *dev = &bridge->dev;
int ret;
ret = device_add(dev);
if (ret)
return ret;
of_platform_populate(dev->of_node, NULL, NULL, dev);
dev_info(dev->parent, "fpga bridge [%s] registered\n", bridge->name);
return 0;
}
EXPORT_SYMBOL_GPL(fpga_bridge_register);
/**
* fpga_bridge_unregister - unregister and free a fpga bridge
* @bridge: FPGA bridge struct created by fpga_bridge_create
*/
void fpga_bridge_unregister(struct fpga_bridge *bridge)
{
/*
* If the low level driver provides a method for putting bridge into
* a desired state upon unregister, do it.
......@@ -419,8 +432,7 @@ 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);
fpga_bridge_free(bridge);
}
static int __init fpga_bridge_dev_init(void)
......
// SPDX-License-Identifier: GPL-2.0
/*
* FPGA Manager Core
*
......@@ -6,18 +7,6 @@
*
* With code from the mailing list:
* Copyright (C) 2013 Xilinx, Inc.
*
* 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/firmware.h>
#include <linux/fpga/fpga-mgr.h>
......@@ -32,6 +21,12 @@
static DEFINE_IDA(fpga_mgr_ida);
static struct class *fpga_mgr_class;
/**
* fpga_image_info_alloc - Allocate a FPGA image info struct
* @dev: owning device
*
* Return: struct fpga_image_info or NULL
*/
struct fpga_image_info *fpga_image_info_alloc(struct device *dev)
{
struct fpga_image_info *info;
......@@ -50,6 +45,10 @@ struct fpga_image_info *fpga_image_info_alloc(struct device *dev)
}
EXPORT_SYMBOL_GPL(fpga_image_info_alloc);
/**
* fpga_image_info_free - Free a FPGA image info struct
* @info: FPGA image info struct to free
*/
void fpga_image_info_free(struct fpga_image_info *info)
{
struct device *dev;
......@@ -234,7 +233,7 @@ static int fpga_mgr_buf_load_mapped(struct fpga_manager *mgr,
/**
* fpga_mgr_buf_load - load fpga from image in buffer
* @mgr: fpga manager
* @flags: flags setting fpga confuration modes
* @info: fpga image info
* @buf: buffer contain fpga image
* @count: byte count of buf
*
......@@ -343,6 +342,16 @@ static int fpga_mgr_firmware_load(struct fpga_manager *mgr,
return ret;
}
/**
* fpga_mgr_load - load FPGA from scatter/gather table, buffer, or firmware
* @mgr: fpga manager
* @info: fpga image information.
*
* Load the FPGA from an image which is indicated in @info. If successful, the
* FPGA ends up in operating mode.
*
* Return: 0 on success, negative error code otherwise.
*/
int fpga_mgr_load(struct fpga_manager *mgr, struct fpga_image_info *info)
{
if (info->sgt)
......@@ -429,11 +438,9 @@ static int fpga_mgr_dev_match(struct device *dev, const void *data)
}
/**
* fpga_mgr_get - get a reference to a fpga mgr
* fpga_mgr_get - Given a device, get a reference to a fpga mgr.
* @dev: parent device that fpga mgr was registered with
*
* Given a device, get a 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)
......@@ -453,10 +460,9 @@ static int fpga_mgr_of_node_match(struct device *dev, const void *data)
}
/**
* of_fpga_mgr_get - get a reference to a fpga mgr
* @node: device node
* of_fpga_mgr_get - Given a device node, get a reference to a fpga mgr.
*
* Given a device node, get a reference to a fpga mgr.
* @node: device node
*
* Return: fpga manager struct or IS_ERR() condition containing error code.
*/
......@@ -489,7 +495,10 @@ EXPORT_SYMBOL_GPL(fpga_mgr_put);
* @mgr: fpga manager
*
* Given a pointer to FPGA Manager (from fpga_mgr_get() or
* of_fpga_mgr_put()) attempt to get the mutex.
* of_fpga_mgr_put()) attempt to get the mutex. The user should call
* fpga_mgr_lock() and verify that it returns 0 before attempting to
* program the FPGA. Likewise, the user should call fpga_mgr_unlock
* when done programming the FPGA.
*
* Return: 0 for success or -EBUSY
*/
......@@ -505,7 +514,7 @@ int fpga_mgr_lock(struct fpga_manager *mgr)
EXPORT_SYMBOL_GPL(fpga_mgr_lock);
/**
* fpga_mgr_unlock - Unlock FPGA manager
* fpga_mgr_unlock - Unlock FPGA manager after done programming
* @mgr: fpga manager
*/
void fpga_mgr_unlock(struct fpga_manager *mgr)
......@@ -515,17 +524,17 @@ void fpga_mgr_unlock(struct fpga_manager *mgr)
EXPORT_SYMBOL_GPL(fpga_mgr_unlock);
/**
* fpga_mgr_register - register a low level fpga manager driver
* fpga_mgr_create - create and initialize a FPGA manager struct
* @dev: fpga manager device from pdev
* @name: fpga manager name
* @mops: pointer to structure of fpga manager ops
* @priv: fpga manager private data
*
* Return: 0 on success, negative error code otherwise.
* Return: pointer to struct fpga_manager or NULL
*/
int fpga_mgr_register(struct device *dev, const char *name,
const struct fpga_manager_ops *mops,
void *priv)
struct fpga_manager *fpga_mgr_create(struct device *dev, const char *name,
const struct fpga_manager_ops *mops,
void *priv)
{
struct fpga_manager *mgr;
int id, ret;
......@@ -534,17 +543,17 @@ int fpga_mgr_register(struct device *dev, const char *name,
!mops->write_init || (!mops->write && !mops->write_sg) ||
(mops->write && mops->write_sg)) {
dev_err(dev, "Attempt to register without fpga_manager_ops\n");
return -EINVAL;
return NULL;
}
if (!name || !strlen(name)) {
dev_err(dev, "Attempt to register with no name!\n");
return -EINVAL;
return NULL;
}
mgr = kzalloc(sizeof(*mgr), GFP_KERNEL);
if (!mgr)
return -ENOMEM;
return NULL;
id = ida_simple_get(&fpga_mgr_ida, 0, 0, GFP_KERNEL);
if (id < 0) {
......@@ -558,25 +567,56 @@ int fpga_mgr_register(struct device *dev, const char *name,
mgr->mops = mops;
mgr->priv = priv;
/*
* Initialize framework state by requesting low level driver read state
* from device. FPGA may be in reset mode or may have been programmed
* by bootloader or EEPROM.
*/
mgr->state = mgr->mops->state(mgr);
device_initialize(&mgr->dev);
mgr->dev.class = fpga_mgr_class;
mgr->dev.groups = mops->groups;
mgr->dev.parent = dev;
mgr->dev.of_node = dev->of_node;
mgr->dev.id = id;
dev_set_drvdata(dev, mgr);
ret = dev_set_name(&mgr->dev, "fpga%d", id);
if (ret)
goto error_device;
return mgr;
error_device:
ida_simple_remove(&fpga_mgr_ida, id);
error_kfree:
kfree(mgr);
return NULL;
}
EXPORT_SYMBOL_GPL(fpga_mgr_create);
/**
* fpga_mgr_free - deallocate a FPGA manager
* @mgr: fpga manager struct created by fpga_mgr_create
*/
void fpga_mgr_free(struct fpga_manager *mgr)
{
ida_simple_remove(&fpga_mgr_ida, mgr->dev.id);
kfree(mgr);
}
EXPORT_SYMBOL_GPL(fpga_mgr_free);
/**
* fpga_mgr_register - register a FPGA manager
* @mgr: fpga manager struct created by fpga_mgr_create
*
* Return: 0 on success, negative error code otherwise.
*/
int fpga_mgr_register(struct fpga_manager *mgr)
{
int ret;
/*
* Initialize framework state by requesting low level driver read state
* from device. FPGA may be in reset mode or may have been programmed
* by bootloader or EEPROM.
*/
mgr->state = mgr->mops->state(mgr);
ret = device_add(&mgr->dev);
if (ret)
goto error_device;
......@@ -586,22 +626,18 @@ int fpga_mgr_register(struct device *dev, const char *name,
return 0;
error_device:
ida_simple_remove(&fpga_mgr_ida, id);
error_kfree:
kfree(mgr);
ida_simple_remove(&fpga_mgr_ida, mgr->dev.id);
return ret;
}
EXPORT_SYMBOL_GPL(fpga_mgr_register);
/**
* fpga_mgr_unregister - unregister a low level fpga manager driver
* @dev: fpga manager device from pdev
* fpga_mgr_unregister - unregister and free a FPGA manager
* @mgr: fpga manager struct
*/
void fpga_mgr_unregister(struct device *dev)
void fpga_mgr_unregister(struct fpga_manager *mgr)
{
struct fpga_manager *mgr = dev_get_drvdata(dev);
dev_info(&mgr->dev, "%s %s\n", __func__, mgr->name);
/*
......@@ -619,8 +655,7 @@ static void fpga_mgr_dev_release(struct device *dev)
{
struct fpga_manager *mgr = to_fpga_manager(dev);
ida_simple_remove(&fpga_mgr_ida, mgr->dev.id);
kfree(mgr);
fpga_mgr_free(mgr);
}
static int __init fpga_mgr_class_init(void)
......
// SPDX-License-Identifier: GPL-2.0
/*
* FPGA Region - Device Tree support for FPGA programming under Linux
*
* Copyright (C) 2013-2016 Altera Corporation
* Copyright (C) 2017 Intel Corporation
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/fpga/fpga-bridge.h>
#include <linux/fpga/fpga-mgr.h>
#include <linux/fpga/fpga-region.h>
......@@ -93,8 +81,16 @@ static void fpga_region_put(struct fpga_region *region)
/**
* fpga_region_program_fpga - program FPGA
*
* @region: FPGA region
*
* Program an FPGA using fpga image info (region->info).
* If the region has a get_bridges function, the exclusive reference for the
* bridges will be held if programming succeeds. This is intended to prevent
* reprogramming the region until the caller considers it safe to do so.
* The caller will need to call fpga_bridges_put() before attempting to
* reprogram the region.
*
* Return 0 for success or negative error code.
*/
int fpga_region_program_fpga(struct fpga_region *region)
......@@ -162,45 +158,86 @@ int fpga_region_program_fpga(struct fpga_region *region)
}
EXPORT_SYMBOL_GPL(fpga_region_program_fpga);
int fpga_region_register(struct device *dev, struct fpga_region *region)
/**
* fpga_region_create - alloc and init a struct fpga_region
* @dev: device parent
* @mgr: manager that programs this region
* @get_bridges: optional function to get bridges to a list
*
* Return: struct fpga_region or NULL
*/
struct fpga_region
*fpga_region_create(struct device *dev,
struct fpga_manager *mgr,
int (*get_bridges)(struct fpga_region *))
{
struct fpga_region *region;
int id, ret = 0;
region = kzalloc(sizeof(*region), GFP_KERNEL);
if (!region)
return NULL;
id = ida_simple_get(&fpga_region_ida, 0, 0, GFP_KERNEL);
if (id < 0)
return id;
goto err_free;
region->mgr = mgr;
region->get_bridges = get_bridges;
mutex_init(&region->mutex);
INIT_LIST_HEAD(&region->bridge_list);
device_initialize(&region->dev);
region->dev.groups = region->groups;
region->dev.class = fpga_region_class;
region->dev.parent = dev;
region->dev.of_node = dev->of_node;
region->dev.id = id;
dev_set_drvdata(dev, region);
ret = dev_set_name(&region->dev, "region%d", id);
if (ret)
goto err_remove;
ret = device_add(&region->dev);
if (ret)
goto err_remove;
return 0;
return region;
err_remove:
ida_simple_remove(&fpga_region_ida, id);
return ret;
err_free:
kfree(region);
return NULL;
}
EXPORT_SYMBOL_GPL(fpga_region_create);
/**
* fpga_region_free - free a struct fpga_region
* @region: FPGA region created by fpga_region_create
*/
void fpga_region_free(struct fpga_region *region)
{
ida_simple_remove(&fpga_region_ida, region->dev.id);
kfree(region);
}
EXPORT_SYMBOL_GPL(fpga_region_free);
/**
* fpga_region_register - register a FPGA region
* @region: FPGA region created by fpga_region_create
* Return: 0 or -errno
*/
int fpga_region_register(struct fpga_region *region)
{
return device_add(&region->dev);
}
EXPORT_SYMBOL_GPL(fpga_region_register);
int fpga_region_unregister(struct fpga_region *region)
/**
* fpga_region_unregister - unregister and free a FPGA region
* @region: FPGA region
*/
void fpga_region_unregister(struct fpga_region *region)
{
device_unregister(&region->dev);
return 0;
}
EXPORT_SYMBOL_GPL(fpga_region_unregister);
......@@ -208,7 +245,7 @@ static void fpga_region_dev_release(struct device *dev)
{
struct fpga_region *region = to_fpga_region(dev);
ida_simple_remove(&fpga_region_ida, region->dev.id);
fpga_region_free(region);
}
/**
......
......@@ -133,6 +133,7 @@ static int ice40_fpga_probe(struct spi_device *spi)
{
struct device *dev = &spi->dev;
struct ice40_fpga_priv *priv;
struct fpga_manager *mgr;
int ret;
priv = devm_kzalloc(&spi->dev, sizeof(*priv), GFP_KERNEL);
......@@ -174,14 +175,26 @@ static int ice40_fpga_probe(struct spi_device *spi)
return ret;
}
/* Register with the FPGA manager */
return fpga_mgr_register(dev, "Lattice iCE40 FPGA Manager",
&ice40_fpga_ops, priv);
mgr = fpga_mgr_create(dev, "Lattice iCE40 FPGA Manager",
&ice40_fpga_ops, priv);
if (!mgr)
return -ENOMEM;
spi_set_drvdata(spi, mgr);
ret = fpga_mgr_register(mgr);
if (ret)
fpga_mgr_free(mgr);
return ret;
}
static int ice40_fpga_remove(struct spi_device *spi)
{
fpga_mgr_unregister(&spi->dev);
struct fpga_manager *mgr = spi_get_drvdata(spi);
fpga_mgr_unregister(mgr);
return 0;
}
......
// SPDX-License-Identifier: GPL-2.0
/*
* Lattice MachXO2 Slave SPI Driver
*
* Manage Lattice FPGA firmware that is loaded over SPI using
* the slave serial configuration interface.
*
* Copyright (C) 2018 Paolo Pisati <p.pisati@gmail.com>
*/
#include <linux/delay.h>
#include <linux/fpga/fpga-mgr.h>
#include <linux/gpio/consumer.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/spi/spi.h>
/* MachXO2 Programming Guide - sysCONFIG Programming Commands */
#define IDCODE_PUB {0xe0, 0x00, 0x00, 0x00}
#define ISC_ENABLE {0xc6, 0x08, 0x00, 0x00}
#define ISC_ERASE {0x0e, 0x04, 0x00, 0x00}
#define ISC_PROGRAMDONE {0x5e, 0x00, 0x00, 0x00}
#define LSC_INITADDRESS {0x46, 0x00, 0x00, 0x00}
#define LSC_PROGINCRNV {0x70, 0x00, 0x00, 0x01}
#define LSC_READ_STATUS {0x3c, 0x00, 0x00, 0x00}
#define LSC_REFRESH {0x79, 0x00, 0x00, 0x00}
/*
* Max CCLK in Slave SPI mode according to 'MachXO2 Family Data
* Sheet' sysCONFIG Port Timing Specifications (3-36)
*/
#define MACHXO2_MAX_SPEED 66000000
#define MACHXO2_LOW_DELAY_USEC 5
#define MACHXO2_HIGH_DELAY_USEC 200
#define MACHXO2_REFRESH_USEC 4800
#define MACHXO2_MAX_BUSY_LOOP 128
#define MACHXO2_MAX_REFRESH_LOOP 16
#define MACHXO2_PAGE_SIZE 16
#define MACHXO2_BUF_SIZE (MACHXO2_PAGE_SIZE + 4)
/* Status register bits, errors and error mask */
#define BUSY 12
#define DONE 8
#define DVER 27
#define ENAB 9
#define ERRBITS 23
#define ERRMASK 7
#define FAIL 13
#define ENOERR 0 /* no error */
#define EID 1
#define ECMD 2
#define ECRC 3
#define EPREAM 4 /* preamble error */
#define EABRT 5 /* abort error */
#define EOVERFL 6 /* overflow error */
#define ESDMEOF 7 /* SDM EOF */
static inline u8 get_err(unsigned long *status)
{
return (*status >> ERRBITS) & ERRMASK;
}
static int get_status(struct spi_device *spi, unsigned long *status)
{
struct spi_message msg;
struct spi_transfer rx, tx;
static const u8 cmd[] = LSC_READ_STATUS;
int ret;
memset(&rx, 0, sizeof(rx));
memset(&tx, 0, sizeof(tx));
tx.tx_buf = cmd;
tx.len = sizeof(cmd);
rx.rx_buf = status;
rx.len = 4;
spi_message_init(&msg);
spi_message_add_tail(&tx, &msg);
spi_message_add_tail(&rx, &msg);
ret = spi_sync(spi, &msg);
if (ret)
return ret;
*status = be32_to_cpu(*status);
return 0;
}
#ifdef DEBUG
static const char *get_err_string(u8 err)
{
switch (err) {
case ENOERR: return "No Error";
case EID: return "ID ERR";
case ECMD: return "CMD ERR";
case ECRC: return "CRC ERR";
case EPREAM: return "Preamble ERR";
case EABRT: return "Abort ERR";
case EOVERFL: return "Overflow ERR";
case ESDMEOF: return "SDM EOF";
}
return "Default switch case";
}
#endif
static void dump_status_reg(unsigned long *status)
{
#ifdef DEBUG
pr_debug("machxo2 status: 0x%08lX - done=%d, cfgena=%d, busy=%d, fail=%d, devver=%d, err=%s\n",
*status, test_bit(DONE, status), test_bit(ENAB, status),
test_bit(BUSY, status), test_bit(FAIL, status),
test_bit(DVER, status), get_err_string(get_err(status)));
#endif
}
static int wait_until_not_busy(struct spi_device *spi)
{
unsigned long status;
int ret, loop = 0;
do {
ret = get_status(spi, &status);
if (ret)
return ret;
if (++loop >= MACHXO2_MAX_BUSY_LOOP)
return -EBUSY;
} while (test_bit(BUSY, &status));
return 0;
}
static int machxo2_cleanup(struct fpga_manager *mgr)
{
struct spi_device *spi = mgr->priv;
struct spi_message msg;
struct spi_transfer tx[2];
static const u8 erase[] = ISC_ERASE;
static const u8 refresh[] = LSC_REFRESH;
int ret;
memset(tx, 0, sizeof(tx));
spi_message_init(&msg);
tx[0].tx_buf = &erase;
tx[0].len = sizeof(erase);
spi_message_add_tail(&tx[0], &msg);
ret = spi_sync(spi, &msg);
if (ret)
goto fail;
ret = wait_until_not_busy(spi);
if (ret)
goto fail;
spi_message_init(&msg);
tx[1].tx_buf = &refresh;
tx[1].len = sizeof(refresh);
tx[1].delay_usecs = MACHXO2_REFRESH_USEC;
spi_message_add_tail(&tx[1], &msg);
ret = spi_sync(spi, &msg);
if (ret)
goto fail;
return 0;
fail:
dev_err(&mgr->dev, "Cleanup failed\n");
return ret;
}
static enum fpga_mgr_states machxo2_spi_state(struct fpga_manager *mgr)
{
struct spi_device *spi = mgr->priv;
unsigned long status;
get_status(spi, &status);
if (!test_bit(BUSY, &status) && test_bit(DONE, &status) &&
get_err(&status) == ENOERR)
return FPGA_MGR_STATE_OPERATING;
return FPGA_MGR_STATE_UNKNOWN;
}
static int machxo2_write_init(struct fpga_manager *mgr,
struct fpga_image_info *info,
const char *buf, size_t count)
{
struct spi_device *spi = mgr->priv;
struct spi_message msg;
struct spi_transfer tx[3];
static const u8 enable[] = ISC_ENABLE;
static const u8 erase[] = ISC_ERASE;
static const u8 initaddr[] = LSC_INITADDRESS;
unsigned long status;
int ret;
if ((info->flags & FPGA_MGR_PARTIAL_RECONFIG)) {
dev_err(&mgr->dev,
"Partial reconfiguration is not supported\n");
return -ENOTSUPP;
}
get_status(spi, &status);
dump_status_reg(&status);
memset(tx, 0, sizeof(tx));
spi_message_init(&msg);
tx[0].tx_buf = &enable;
tx[0].len = sizeof(enable);
tx[0].delay_usecs = MACHXO2_LOW_DELAY_USEC;
spi_message_add_tail(&tx[0], &msg);
tx[1].tx_buf = &erase;
tx[1].len = sizeof(erase);
spi_message_add_tail(&tx[1], &msg);
ret = spi_sync(spi, &msg);
if (ret)
goto fail;
ret = wait_until_not_busy(spi);
if (ret)
goto fail;
get_status(spi, &status);
if (test_bit(FAIL, &status))
goto fail;
dump_status_reg(&status);
spi_message_init(&msg);
tx[2].tx_buf = &initaddr;
tx[2].len = sizeof(initaddr);
spi_message_add_tail(&tx[2], &msg);
ret = spi_sync(spi, &msg);
if (ret)
goto fail;
get_status(spi, &status);
dump_status_reg(&status);
return 0;
fail:
dev_err(&mgr->dev, "Error during FPGA init.\n");
return ret;
}
static int machxo2_write(struct fpga_manager *mgr, const char *buf,
size_t count)
{
struct spi_device *spi = mgr->priv;
struct spi_message msg;
struct spi_transfer tx;
static const u8 progincr[] = LSC_PROGINCRNV;
u8 payload[MACHXO2_BUF_SIZE];
unsigned long status;
int i, ret;
if (count % MACHXO2_PAGE_SIZE != 0) {
dev_err(&mgr->dev, "Malformed payload.\n");
return -EINVAL;
}
get_status(spi, &status);
dump_status_reg(&status);
memcpy(payload, &progincr, sizeof(progincr));
for (i = 0; i < count; i += MACHXO2_PAGE_SIZE) {
memcpy(&payload[sizeof(progincr)], &buf[i], MACHXO2_PAGE_SIZE);
memset(&tx, 0, sizeof(tx));
spi_message_init(&msg);
tx.tx_buf = payload;
tx.len = MACHXO2_BUF_SIZE;
tx.delay_usecs = MACHXO2_HIGH_DELAY_USEC;
spi_message_add_tail(&tx, &msg);
ret = spi_sync(spi, &msg);
if (ret) {
dev_err(&mgr->dev, "Error loading the bitstream.\n");
return ret;
}
}
get_status(spi, &status);
dump_status_reg(&status);
return 0;
}
static int machxo2_write_complete(struct fpga_manager *mgr,
struct fpga_image_info *info)
{
struct spi_device *spi = mgr->priv;
struct spi_message msg;
struct spi_transfer tx[2];
static const u8 progdone[] = ISC_PROGRAMDONE;
static const u8 refresh[] = LSC_REFRESH;
unsigned long status;
int ret, refreshloop = 0;
memset(tx, 0, sizeof(tx));
spi_message_init(&msg);
tx[0].tx_buf = &progdone;
tx[0].len = sizeof(progdone);
spi_message_add_tail(&tx[0], &msg);
ret = spi_sync(spi, &msg);
if (ret)
goto fail;
ret = wait_until_not_busy(spi);
if (ret)
goto fail;
get_status(spi, &status);
dump_status_reg(&status);
if (!test_bit(DONE, &status)) {
machxo2_cleanup(mgr);
goto fail;
}
do {
spi_message_init(&msg);
tx[1].tx_buf = &refresh;
tx[1].len = sizeof(refresh);
tx[1].delay_usecs = MACHXO2_REFRESH_USEC;
spi_message_add_tail(&tx[1], &msg);
ret = spi_sync(spi, &msg);
if (ret)
goto fail;
/* check refresh status */
get_status(spi, &status);
dump_status_reg(&status);
if (!test_bit(BUSY, &status) && test_bit(DONE, &status) &&
get_err(&status) == ENOERR)
break;
if (++refreshloop == MACHXO2_MAX_REFRESH_LOOP) {
machxo2_cleanup(mgr);
goto fail;
}
} while (1);
get_status(spi, &status);
dump_status_reg(&status);
return 0;
fail:
dev_err(&mgr->dev, "Refresh failed.\n");
return ret;
}
static const struct fpga_manager_ops machxo2_ops = {
.state = machxo2_spi_state,
.write_init = machxo2_write_init,
.write = machxo2_write,
.write_complete = machxo2_write_complete,
};
static int machxo2_spi_probe(struct spi_device *spi)
{
struct device *dev = &spi->dev;
struct fpga_manager *mgr;
int ret;
if (spi->max_speed_hz > MACHXO2_MAX_SPEED) {
dev_err(dev, "Speed is too high\n");
return -EINVAL;
}
mgr = fpga_mgr_create(dev, "Lattice MachXO2 SPI FPGA Manager",
&machxo2_ops, spi);
if (!mgr)
return -ENOMEM;
spi_set_drvdata(spi, mgr);
ret = fpga_mgr_register(mgr);
if (ret)
fpga_mgr_free(mgr);
return ret;
}
static int machxo2_spi_remove(struct spi_device *spi)
{
struct fpga_manager *mgr = spi_get_drvdata(spi);
fpga_mgr_unregister(mgr);
return 0;
}
static const struct of_device_id of_match[] = {
{ .compatible = "lattice,machxo2-slave-spi", },
{}
};
MODULE_DEVICE_TABLE(of, of_match);
static const struct spi_device_id lattice_ids[] = {
{ "machxo2-slave-spi", 0 },
{ },
};
MODULE_DEVICE_TABLE(spi, lattice_ids);
static struct spi_driver machxo2_spi_driver = {
.driver = {
.name = "machxo2-slave-spi",
.of_match_table = of_match_ptr(of_match),
},
.probe = machxo2_spi_probe,
.remove = machxo2_spi_remove,
.id_table = lattice_ids,
};
module_spi_driver(machxo2_spi_driver)
MODULE_AUTHOR("Paolo Pisati <p.pisati@gmail.com>");
MODULE_DESCRIPTION("Load Lattice FPGA firmware over SPI");
MODULE_LICENSE("GPL v2");
// SPDX-License-Identifier: GPL-2.0
/*
* FPGA Region - Device Tree support for FPGA programming under Linux
*
* Copyright (C) 2013-2016 Altera Corporation
* Copyright (C) 2017 Intel Corporation
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/fpga/fpga-bridge.h>
#include <linux/fpga/fpga-mgr.h>
#include <linux/fpga/fpga-region.h>
......@@ -422,27 +410,25 @@ static int of_fpga_region_probe(struct platform_device *pdev)
if (IS_ERR(mgr))
return -EPROBE_DEFER;
region = devm_kzalloc(dev, sizeof(*region), GFP_KERNEL);
region = fpga_region_create(dev, mgr, of_fpga_region_get_bridges);
if (!region) {
ret = -ENOMEM;
goto eprobe_mgr_put;
}
region->mgr = mgr;
/* Specify how to get bridges for this type of region. */
region->get_bridges = of_fpga_region_get_bridges;
ret = fpga_region_register(dev, region);
ret = fpga_region_register(region);
if (ret)
goto eprobe_mgr_put;
goto eprobe_free;
of_platform_populate(np, fpga_region_of_match, NULL, &region->dev);
dev_set_drvdata(dev, region);
dev_info(dev, "FPGA Region probed\n");
return 0;
eprobe_free:
fpga_region_free(region);
eprobe_mgr_put:
fpga_mgr_put(mgr);
return ret;
......
// SPDX-License-Identifier: GPL-2.0
/*
* FPGA Manager Driver for Altera Arria10 SoCFPGA
*
* Copyright (C) 2015-2016 Altera Corporation
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/delay.h>
......@@ -482,6 +470,7 @@ static int socfpga_a10_fpga_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct a10_fpga_priv *priv;
void __iomem *reg_base;
struct fpga_manager *mgr;
struct resource *res;
int ret;
......@@ -519,9 +508,16 @@ static int socfpga_a10_fpga_probe(struct platform_device *pdev)
return -EBUSY;
}
ret = fpga_mgr_register(dev, "SoCFPGA Arria10 FPGA Manager",
&socfpga_a10_fpga_mgr_ops, priv);
mgr = fpga_mgr_create(dev, "SoCFPGA Arria10 FPGA Manager",
&socfpga_a10_fpga_mgr_ops, priv);
if (!mgr)
return -ENOMEM;
platform_set_drvdata(pdev, mgr);
ret = fpga_mgr_register(mgr);
if (ret) {
fpga_mgr_free(mgr);
clk_disable_unprepare(priv->clk);
return ret;
}
......@@ -534,7 +530,7 @@ static int socfpga_a10_fpga_remove(struct platform_device *pdev)
struct fpga_manager *mgr = platform_get_drvdata(pdev);
struct a10_fpga_priv *priv = mgr->priv;
fpga_mgr_unregister(&pdev->dev);
fpga_mgr_unregister(mgr);
clk_disable_unprepare(priv->clk);
return 0;
......
// SPDX-License-Identifier: GPL-2.0
/*
* FPGA Manager Driver for Altera SOCFPGA
*
* Copyright (C) 2013-2015 Altera Corporation
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/completion.h>
#include <linux/delay.h>
......@@ -555,6 +544,7 @@ static int socfpga_fpga_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct socfpga_fpga_priv *priv;
struct fpga_manager *mgr;
struct resource *res;
int ret;
......@@ -581,13 +571,25 @@ static int socfpga_fpga_probe(struct platform_device *pdev)
if (ret)
return ret;
return fpga_mgr_register(dev, "Altera SOCFPGA FPGA Manager",
&socfpga_fpga_ops, priv);
mgr = fpga_mgr_create(dev, "Altera SOCFPGA FPGA Manager",
&socfpga_fpga_ops, priv);
if (!mgr)
return -ENOMEM;
platform_set_drvdata(pdev, mgr);
ret = fpga_mgr_register(mgr);
if (ret)
fpga_mgr_free(mgr);
return ret;
}
static int socfpga_fpga_remove(struct platform_device *pdev)
{
fpga_mgr_unregister(&pdev->dev);
struct fpga_manager *mgr = platform_get_drvdata(pdev);
fpga_mgr_unregister(mgr);
return 0;
}
......
......@@ -116,7 +116,9 @@ static int ts73xx_fpga_probe(struct platform_device *pdev)
{
struct device *kdev = &pdev->dev;
struct ts73xx_fpga_priv *priv;
struct fpga_manager *mgr;
struct resource *res;
int ret;
priv = devm_kzalloc(kdev, sizeof(*priv), GFP_KERNEL);
if (!priv)
......@@ -131,13 +133,25 @@ static int ts73xx_fpga_probe(struct platform_device *pdev)
return PTR_ERR(priv->io_base);
}
return fpga_mgr_register(kdev, "TS-73xx FPGA Manager",
&ts73xx_fpga_ops, priv);
mgr = fpga_mgr_create(kdev, "TS-73xx FPGA Manager",
&ts73xx_fpga_ops, priv);
if (!mgr)
return -ENOMEM;
platform_set_drvdata(pdev, mgr);
ret = fpga_mgr_register(mgr);
if (ret)
fpga_mgr_free(mgr);
return ret;
}
static int ts73xx_fpga_remove(struct platform_device *pdev)
{
fpga_mgr_unregister(&pdev->dev);
struct fpga_manager *mgr = platform_get_drvdata(pdev);
fpga_mgr_unregister(mgr);
return 0;
}
......
......@@ -94,6 +94,7 @@ MODULE_DEVICE_TABLE(of, xlnx_pr_decoupler_of_match);
static int xlnx_pr_decoupler_probe(struct platform_device *pdev)
{
struct xlnx_pr_decoupler_data *priv;
struct fpga_bridge *br;
int err;
struct resource *res;
......@@ -120,16 +121,27 @@ static int xlnx_pr_decoupler_probe(struct platform_device *pdev)
clk_disable(priv->clk);
err = fpga_bridge_register(&pdev->dev, "Xilinx PR Decoupler",
&xlnx_pr_decoupler_br_ops, priv);
br = fpga_bridge_create(&pdev->dev, "Xilinx PR Decoupler",
&xlnx_pr_decoupler_br_ops, priv);
if (!br) {
err = -ENOMEM;
goto err_clk;
}
platform_set_drvdata(pdev, br);
err = fpga_bridge_register(br);
if (err) {
dev_err(&pdev->dev, "unable to register Xilinx PR Decoupler");
clk_unprepare(priv->clk);
return err;
goto err_clk;
}
return 0;
err_clk:
clk_unprepare(priv->clk);
return err;
}
static int xlnx_pr_decoupler_remove(struct platform_device *pdev)
......@@ -137,7 +149,7 @@ static int xlnx_pr_decoupler_remove(struct platform_device *pdev)
struct fpga_bridge *bridge = platform_get_drvdata(pdev);
struct xlnx_pr_decoupler_data *p = bridge->priv;
fpga_bridge_unregister(&pdev->dev);
fpga_bridge_unregister(bridge);
clk_unprepare(p->clk);
......
......@@ -143,6 +143,8 @@ static const struct fpga_manager_ops xilinx_spi_ops = {
static int xilinx_spi_probe(struct spi_device *spi)
{
struct xilinx_spi_conf *conf;
struct fpga_manager *mgr;
int ret;
conf = devm_kzalloc(&spi->dev, sizeof(*conf), GFP_KERNEL);
if (!conf)
......@@ -165,13 +167,25 @@ static int xilinx_spi_probe(struct spi_device *spi)
return PTR_ERR(conf->done);
}
return fpga_mgr_register(&spi->dev, "Xilinx Slave Serial FPGA Manager",
&xilinx_spi_ops, conf);
mgr = fpga_mgr_create(&spi->dev, "Xilinx Slave Serial FPGA Manager",
&xilinx_spi_ops, conf);
if (!mgr)
return -ENOMEM;
spi_set_drvdata(spi, mgr);
ret = fpga_mgr_register(mgr);
if (ret)
fpga_mgr_free(mgr);
return ret;
}
static int xilinx_spi_remove(struct spi_device *spi)
{
fpga_mgr_unregister(&spi->dev);
struct fpga_manager *mgr = spi_get_drvdata(spi);
fpga_mgr_unregister(mgr);
return 0;
}
......
......@@ -558,6 +558,7 @@ static int zynq_fpga_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct zynq_fpga_priv *priv;
struct fpga_manager *mgr;
struct resource *res;
int err;
......@@ -613,10 +614,17 @@ static int zynq_fpga_probe(struct platform_device *pdev)
clk_disable(priv->clk);
err = fpga_mgr_register(dev, "Xilinx Zynq FPGA Manager",
&zynq_fpga_ops, priv);
mgr = fpga_mgr_create(dev, "Xilinx Zynq FPGA Manager",
&zynq_fpga_ops, priv);
if (!mgr)
return -ENOMEM;
platform_set_drvdata(pdev, mgr);
err = fpga_mgr_register(mgr);
if (err) {
dev_err(dev, "unable to register FPGA manager\n");
fpga_mgr_free(mgr);
clk_unprepare(priv->clk);
return err;
}
......@@ -632,7 +640,7 @@ static int zynq_fpga_remove(struct platform_device *pdev)
mgr = platform_get_drvdata(pdev);
priv = mgr->priv;
fpga_mgr_unregister(&pdev->dev);
fpga_mgr_unregister(mgr);
clk_unprepare(priv->clk);
......
......@@ -63,6 +63,9 @@ static __u32 vmbus_get_next_version(__u32 current_version)
case (VERSION_WIN10):
return VERSION_WIN8_1;
case (VERSION_WIN10_V5):
return VERSION_WIN10;
case (VERSION_WS2008):
default:
return VERSION_INVAL;
......@@ -80,9 +83,29 @@ static int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo,
msg = (struct vmbus_channel_initiate_contact *)msginfo->msg;
memset(msg, 0, sizeof(*msg));
msg->header.msgtype = CHANNELMSG_INITIATE_CONTACT;
msg->vmbus_version_requested = version;
msg->interrupt_page = virt_to_phys(vmbus_connection.int_page);
/*
* VMBus protocol 5.0 (VERSION_WIN10_V5) requires that we must use
* VMBUS_MESSAGE_CONNECTION_ID_4 for the Initiate Contact Message,
* and for subsequent messages, we must use the Message Connection ID
* field in the host-returned Version Response Message. And, with
* VERSION_WIN10_V5, we don't use msg->interrupt_page, but we tell
* the host explicitly that we still use VMBUS_MESSAGE_SINT(2) for
* compatibility.
*
* On old hosts, we should always use VMBUS_MESSAGE_CONNECTION_ID (1).
*/
if (version >= VERSION_WIN10_V5) {
msg->msg_sint = VMBUS_MESSAGE_SINT;
vmbus_connection.msg_conn_id = VMBUS_MESSAGE_CONNECTION_ID_4;
} else {
msg->interrupt_page = virt_to_phys(vmbus_connection.int_page);
vmbus_connection.msg_conn_id = VMBUS_MESSAGE_CONNECTION_ID;
}
msg->monitor_page1 = virt_to_phys(vmbus_connection.monitor_pages[0]);
msg->monitor_page2 = virt_to_phys(vmbus_connection.monitor_pages[1]);
/*
......@@ -137,6 +160,10 @@ static int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo,
/* Check if successful */
if (msginfo->response.version_response.version_supported) {
vmbus_connection.conn_state = CONNECTED;
if (version >= VERSION_WIN10_V5)
vmbus_connection.msg_conn_id =
msginfo->response.version_response.msg_conn_id;
} else {
return -ECONNREFUSED;
}
......@@ -354,13 +381,14 @@ void vmbus_on_event(unsigned long data)
*/
int vmbus_post_msg(void *buffer, size_t buflen, bool can_sleep)
{
struct vmbus_channel_message_header *hdr;
union hv_connection_id conn_id;
int ret = 0;
int retries = 0;
u32 usec = 1;
conn_id.asu32 = 0;
conn_id.u.id = VMBUS_MESSAGE_CONNECTION_ID;
conn_id.u.id = vmbus_connection.msg_conn_id;
/*
* hv_post_message() can have transient failures because of
......@@ -372,6 +400,18 @@ int vmbus_post_msg(void *buffer, size_t buflen, bool can_sleep)
switch (ret) {
case HV_STATUS_INVALID_CONNECTION_ID:
/*
* See vmbus_negotiate_version(): VMBus protocol 5.0
* requires that we must use
* VMBUS_MESSAGE_CONNECTION_ID_4 for the Initiate
* Contact message, but on old hosts that only
* support VMBus protocol 4.0 or lower, here we get
* HV_STATUS_INVALID_CONNECTION_ID and we should
* return an error immediately without retrying.
*/
hdr = buffer;
if (hdr->msgtype == CHANNELMSG_INITIATE_CONTACT)
return -EINVAL;
/*
* We could get this if we send messages too
* frequently.
......
......@@ -187,6 +187,7 @@ struct hv_input_post_message {
enum {
VMBUS_MESSAGE_CONNECTION_ID = 1,
VMBUS_MESSAGE_CONNECTION_ID_4 = 4,
VMBUS_MESSAGE_PORT_ID = 1,
VMBUS_EVENT_CONNECTION_ID = 2,
VMBUS_EVENT_PORT_ID = 2,
......@@ -302,6 +303,8 @@ struct vmbus_connection {
*/
int connect_cpu;
u32 msg_conn_id;
atomic_t offer_in_progress;
enum vmbus_connect_state conn_state;
......
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2017 Linaro Limited. All rights reserved.
*
* Author: Leo Yan <leo.yan@linaro.org>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* 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/amba/bus.h>
#include <linux/coresight.h>
......@@ -315,7 +303,7 @@ static void debug_dump_regs(struct debug_drvdata *drvdata)
}
pc = debug_adjust_pc(drvdata);
dev_emerg(dev, " EDPCSR: [<%px>] %pS\n", (void *)pc, (void *)pc);
dev_emerg(dev, " EDPCSR: %pS\n", (void *)pc);
if (drvdata->edcidsr_present)
dev_emerg(dev, " EDCIDSR: %08x\n", drvdata->edcidsr);
......
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2011-2015, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/amba/bus.h>
......
/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
*
* Description: CoreSight Embedded Trace Buffer driver
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <asm/local.h>
......
/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2012, The Linux Foundation. All rights reserved.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
......
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright(C) 2015 Linaro Limited. All rights reserved.
* Author: Mathieu Poirier <mathieu.poirier@linaro.org>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* 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/coresight.h>
......
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright(C) 2015 Linaro Limited. All rights reserved.
* Author: Mathieu Poirier <mathieu.poirier@linaro.org>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _CORESIGHT_ETM_PERF_H
......
/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
*/
#ifndef _CORESIGHT_CORESIGHT_ETM_H
......
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright(C) 2015 Linaro Limited. All rights reserved.
* Author: Mathieu Poirier <mathieu.poirier@linaro.org>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* 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/pm_runtime.h>
......
/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
*
* Description: CoreSight Program Flow Trace driver
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/kernel.h>
......
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright(C) 2015 Linaro Limited. All rights reserved.
* Author: Mathieu Poirier <mathieu.poirier@linaro.org>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* 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/pm_runtime.h>
......
/* Copyright (c) 2014, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2014, The Linux Foundation. All rights reserved.
*/
#include <linux/kernel.h>
......
/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
*/
#ifndef _CORESIGHT_CORESIGHT_ETM_H
......
/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
*
* Description: CoreSight Funnel driver
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/kernel.h>
......
/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
*/
#ifndef _CORESIGHT_PRIV_H
......
/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
*
* Description: CoreSight Replicator driver
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/kernel.h>
......
/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
*
* Description: CoreSight System Trace Macrocell driver
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* Initial implementation by Pratik Patel
* (C) 2014-2015 Pratik Patel <pratikp@codeaurora.org>
*
......
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright(C) 2016 Linaro Limited. All rights reserved.
* Author: Mathieu Poirier <mathieu.poirier@linaro.org>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* 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/circ_buf.h>
......
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright(C) 2016 Linaro Limited. All rights reserved.
* Author: Mathieu Poirier <mathieu.poirier@linaro.org>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* 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/coresight.h>
......@@ -124,10 +113,9 @@ static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev)
bool used = false;
unsigned long flags;
void __iomem *vaddr = NULL;
dma_addr_t paddr;
dma_addr_t paddr = 0;
struct tmc_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
/*
* If we don't have a buffer release the lock and allocate memory.
* Otherwise keep the lock and move along.
......@@ -164,11 +152,11 @@ static int tmc_enable_etr_sink_sysfs(struct coresight_device *csdev)
goto out;
/*
* If drvdata::buf == NULL, use the memory allocated above.
* If drvdata::vaddr == NULL, use the memory allocated above.
* Otherwise a buffer still exists from a previous session, so
* simply use that.
*/
if (drvdata->buf == NULL) {
if (drvdata->vaddr == NULL) {
used = true;
drvdata->vaddr = vaddr;
drvdata->paddr = paddr;
......
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
*
* Description: CoreSight Trace Memory Controller driver
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/kernel.h>
......
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright(C) 2015 Linaro Limited. All rights reserved.
* Author: Mathieu Poirier <mathieu.poirier@linaro.org>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _CORESIGHT_TMC_H
......
/* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
*
* Description: CoreSight Trace Port Interface Unit driver
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/kernel.h>
......
/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2012, The Linux Foundation. All rights reserved.
*/
#include <linux/kernel.h>
......@@ -1026,8 +1019,10 @@ struct coresight_device *coresight_register(struct coresight_desc *desc)
dev_set_name(&csdev->dev, "%s", desc->pdata->name);
ret = device_register(&csdev->dev);
if (ret)
goto err_device_register;
if (ret) {
put_device(&csdev->dev);
goto err_kzalloc_csdev;
}
mutex_lock(&coresight_mutex);
......@@ -1038,8 +1033,6 @@ struct coresight_device *coresight_register(struct coresight_desc *desc)
return csdev;
err_device_register:
kfree(conns);
err_kzalloc_conns:
kfree(refcnts);
err_kzalloc_refcnts:
......
/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2012, The Linux Foundation. All rights reserved.
*/
#include <linux/types.h>
......
// SPDX-License-Identifier: GPL-2.0
/*
* Simple kernel driver to link kernel Ftrace and an STM device
* Copyright (c) 2016, Linaro Ltd.
*
* 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.
*
* STM Ftrace will be registered as a trace_export.
*/
......
......@@ -113,6 +113,20 @@ config IBM_ASM
for information on the specific driver level and support statement
for your IBM server.
config IBMVMC
tristate "IBM Virtual Management Channel support"
depends on PPC_PSERIES
help
This is the IBM POWER Virtual Management Channel
This driver is to be used for the POWER Virtual
Management Channel virtual adapter on the PowerVM
platform. It provides both request/response and
async message support through the /dev/ibmvmc node.
To compile this driver as a module, choose M here: the
module will be called ibmvmc.
config PHANTOM
tristate "Sensable PHANToM (PCI)"
depends on PCI
......
......@@ -4,6 +4,7 @@
#
obj-$(CONFIG_IBM_ASM) += ibmasm/
obj-$(CONFIG_IBMVMC) += ibmvmc.o
obj-$(CONFIG_AD525X_DPOT) += ad525x_dpot.o
obj-$(CONFIG_AD525X_DPOT_I2C) += ad525x_dpot-i2c.o
obj-$(CONFIG_AD525X_DPOT_SPI) += ad525x_dpot-spi.o
......
......@@ -128,11 +128,12 @@ void cxl_context_set_mapping(struct cxl_context *ctx,
mutex_unlock(&ctx->mapping_lock);
}
static int cxl_mmap_fault(struct vm_fault *vmf)
static vm_fault_t cxl_mmap_fault(struct vm_fault *vmf)
{
struct vm_area_struct *vma = vmf->vma;
struct cxl_context *ctx = vma->vm_file->private_data;
u64 area, offset;
vm_fault_t ret;
offset = vmf->pgoff << PAGE_SHIFT;
......@@ -169,11 +170,11 @@ static int cxl_mmap_fault(struct vm_fault *vmf)
return VM_FAULT_SIGBUS;
}
vm_insert_pfn(vma, vmf->address, (area + offset) >> PAGE_SHIFT);
ret = vmf_insert_pfn(vma, vmf->address, (area + offset) >> PAGE_SHIFT);
mutex_unlock(&ctx->status_mutex);
return VM_FAULT_NOPAGE;
return ret;
}
static const struct vm_operations_struct cxl_mmap_vmops = {
......
This diff is collapsed.
/* SPDX-License-Identifier: GPL-2.0+
*
* linux/drivers/misc/ibmvmc.h
*
* IBM Power Systems Virtual Management Channel Support.
*
* Copyright (c) 2004, 2018 IBM Corp.
* Dave Engebretsen engebret@us.ibm.com
* Steven Royer seroyer@linux.vnet.ibm.com
* Adam Reznechek adreznec@linux.vnet.ibm.com
* Bryant G. Ly <bryantly@linux.vnet.ibm.com>
*/
#ifndef IBMVMC_H
#define IBMVMC_H
#include <linux/types.h>
#include <linux/cdev.h>
#include <asm/vio.h>
#define IBMVMC_PROTOCOL_VERSION 0x0101
#define MIN_BUF_POOL_SIZE 16
#define MIN_HMCS 1
#define MIN_MTU 4096
#define MAX_BUF_POOL_SIZE 64
#define MAX_HMCS 2
#define MAX_MTU (4 * 4096)
#define DEFAULT_BUF_POOL_SIZE 32
#define DEFAULT_HMCS 1
#define DEFAULT_MTU 4096
#define HMC_ID_LEN 32
#define VMC_INVALID_BUFFER_ID 0xFFFF
/* ioctl numbers */
#define VMC_BASE 0xCC
#define VMC_IOCTL_SETHMCID _IOW(VMC_BASE, 0x00, unsigned char *)
#define VMC_IOCTL_QUERY _IOR(VMC_BASE, 0x01, struct ibmvmc_query_struct)
#define VMC_IOCTL_REQUESTVMC _IOR(VMC_BASE, 0x02, u32)
#define VMC_MSG_CAP 0x01
#define VMC_MSG_CAP_RESP 0x81
#define VMC_MSG_OPEN 0x02
#define VMC_MSG_OPEN_RESP 0x82
#define VMC_MSG_CLOSE 0x03
#define VMC_MSG_CLOSE_RESP 0x83
#define VMC_MSG_ADD_BUF 0x04
#define VMC_MSG_ADD_BUF_RESP 0x84
#define VMC_MSG_REM_BUF 0x05
#define VMC_MSG_REM_BUF_RESP 0x85
#define VMC_MSG_SIGNAL 0x06
#define VMC_MSG_SUCCESS 0
#define VMC_MSG_INVALID_HMC_INDEX 1
#define VMC_MSG_INVALID_BUFFER_ID 2
#define VMC_MSG_CLOSED_HMC 3
#define VMC_MSG_INTERFACE_FAILURE 4
#define VMC_MSG_NO_BUFFER 5
#define VMC_BUF_OWNER_ALPHA 0
#define VMC_BUF_OWNER_HV 1
enum ibmvmc_states {
ibmvmc_state_sched_reset = -1,
ibmvmc_state_initial = 0,
ibmvmc_state_crqinit = 1,
ibmvmc_state_capabilities = 2,
ibmvmc_state_ready = 3,
ibmvmc_state_failed = 4,
};
enum ibmhmc_states {
/* HMC connection not established */
ibmhmc_state_free = 0,
/* HMC connection established (open called) */
ibmhmc_state_initial = 1,
/* open msg sent to HV, due to ioctl(1) call */
ibmhmc_state_opening = 2,
/* HMC connection ready, open resp msg from HV */
ibmhmc_state_ready = 3,
/* HMC connection failure */
ibmhmc_state_failed = 4,
};
struct ibmvmc_buffer {
u8 valid; /* 1 when DMA storage allocated to buffer */
u8 free; /* 1 when buffer available for the Alpha Partition */
u8 owner;
u16 id;
u32 size;
u32 msg_len;
dma_addr_t dma_addr_local;
dma_addr_t dma_addr_remote;
void *real_addr_local;
};
struct ibmvmc_admin_crq_msg {
u8 valid; /* RPA Defined */
u8 type; /* ibmvmc msg type */
u8 status; /* Response msg status. Zero is success and on failure,
* either 1 - General Failure, or 2 - Invalid Version is
* returned.
*/
u8 rsvd[2];
u8 max_hmc; /* Max # of independent HMC connections supported */
__be16 pool_size; /* Maximum number of buffers supported per HMC
* connection
*/
__be32 max_mtu; /* Maximum message size supported (bytes) */
__be16 crq_size; /* # of entries available in the CRQ for the
* source partition. The target partition must
* limit the number of outstanding messages to
* one half or less.
*/
__be16 version; /* Indicates the code level of the management partition
* or the hypervisor with the high-order byte
* indicating a major version and the low-order byte
* indicating a minor version.
*/
};
struct ibmvmc_crq_msg {
u8 valid; /* RPA Defined */
u8 type; /* ibmvmc msg type */
u8 status; /* Response msg status */
union {
u8 rsvd; /* Reserved */
u8 owner;
} var1;
u8 hmc_session; /* Session Identifier for the current VMC connection */
u8 hmc_index; /* A unique HMC Idx would be used if multiple management
* applications running concurrently were desired
*/
union {
__be16 rsvd;
__be16 buffer_id;
} var2;
__be32 rsvd;
union {
__be32 rsvd;
__be32 lioba;
__be32 msg_len;
} var3;
};
/* an RPA command/response transport queue */
struct crq_queue {
struct ibmvmc_crq_msg *msgs;
int size, cur;
dma_addr_t msg_token;
spinlock_t lock;
};
/* VMC server adapter settings */
struct crq_server_adapter {
struct device *dev;
struct crq_queue queue;
u32 liobn;
u32 riobn;
struct tasklet_struct work_task;
wait_queue_head_t reset_wait_queue;
struct task_struct *reset_task;
};
/* Driver wide settings */
struct ibmvmc_struct {
u32 state;
u32 max_mtu;
u32 max_buffer_pool_size;
u32 max_hmc_index;
struct crq_server_adapter *adapter;
struct cdev cdev;
u32 vmc_drc_index;
};
struct ibmvmc_file_session;
/* Connection specific settings */
struct ibmvmc_hmc {
u8 session;
u8 index;
u32 state;
struct crq_server_adapter *adapter;
spinlock_t lock;
unsigned char hmc_id[HMC_ID_LEN];
struct ibmvmc_buffer buffer[MAX_BUF_POOL_SIZE];
unsigned short queue_outbound_msgs[MAX_BUF_POOL_SIZE];
int queue_head, queue_tail;
struct ibmvmc_file_session *file_session;
};
struct ibmvmc_file_session {
struct file *file;
struct ibmvmc_hmc *hmc;
bool valid;
};
struct ibmvmc_query_struct {
int have_vmc;
int state;
int vmc_drc_index;
};
#endif /* __IBMVMC_H */
......@@ -926,7 +926,7 @@ struct gru_state *gru_assign_gru_context(struct gru_thread_state *gts)
*
* Note: gru segments alway mmaped on GRU_GSEG_PAGESIZE boundaries.
*/
int gru_fault(struct vm_fault *vmf)
vm_fault_t gru_fault(struct vm_fault *vmf)
{
struct vm_area_struct *vma = vmf->vma;
struct gru_thread_state *gts;
......
......@@ -147,6 +147,7 @@
#include <linux/mutex.h>
#include <linux/wait.h>
#include <linux/mmu_notifier.h>
#include <linux/mm_types.h>
#include "gru.h"
#include "grulib.h"
#include "gruhandles.h"
......@@ -665,7 +666,7 @@ extern unsigned long gru_reserve_cb_resources(struct gru_state *gru,
int cbr_au_count, char *cbmap);
extern unsigned long gru_reserve_ds_resources(struct gru_state *gru,
int dsr_au_count, char *dsmap);
extern int gru_fault(struct vm_fault *vmf);
extern vm_fault_t gru_fault(struct vm_fault *vmf);
extern struct gru_mm_struct *gru_register_mmu_notifier(void);
extern void gru_drop_mmu_notifier(struct gru_mm_struct *gms);
......
......@@ -407,7 +407,7 @@ xpnet_send(struct sk_buff *skb, struct xpnet_pending_msg *queued_msg,
* destination partid. If the destination partid octets are 0xffff,
* this packet is to be broadcast to all connected partitions.
*/
static int
static netdev_tx_t
xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct xpnet_pending_msg *queued_msg;
......
......@@ -735,7 +735,7 @@ static int kim_probe(struct platform_device *pdev)
st_kim_devices[0] = pdev;
}
kim_gdata = kzalloc(sizeof(struct kim_data_s), GFP_ATOMIC);
kim_gdata = kzalloc(sizeof(struct kim_data_s), GFP_KERNEL);
if (!kim_gdata) {
pr_err("no mem to allocate");
return -ENOMEM;
......
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.
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