Char/Misc driver patches for 5.9-rc1

Here is the large set of char and misc and other driver subsystem
 patches for 5.9-rc1.  Lots of new driver submissions in here, and
 cleanups and features for existing drivers.
 
 Highlights are:
 	- habanalabs driver updates
 	- coresight driver updates
 	- nvmem driver updates
 	- huge number of "W=1" build warning cleanups from Lee Jones
 	- dyndbg updates
 	- virtbox driver fixes and updates
 	- soundwire driver updates
 	- mei driver updates
 	- phy driver updates
 	- fpga driver updates
 	- lots of smaller individual misc/char driver cleanups and fixes
 
 Full details are in the shortlog.
 
 All of these have been in linux-next with no reported issues.
 
 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 -----BEGIN PGP SIGNATURE-----
 
 iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCXylccQ8cZ3JlZ0Brcm9h
 aC5jb20ACgkQMUfUDdst+ymofgCfZ1CxNWd0ZVM0YIn8cY9gO6ON7MsAnRq48hvn
 Vjf4rKM73GC11bVF4Gyy
 =Xq1R
 -----END PGP SIGNATURE-----

Merge tag 'char-misc-5.9-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 large set of char and misc and other driver subsystem
  patches for 5.9-rc1. Lots of new driver submissions in here, and
  cleanups and features for existing drivers.

  Highlights are:
   - habanalabs driver updates
   - coresight driver updates
   - nvmem driver updates
   - huge number of "W=1" build warning cleanups from Lee Jones
   - dyndbg updates
   - virtbox driver fixes and updates
   - soundwire driver updates
   - mei driver updates
   - phy driver updates
   - fpga driver updates
   - lots of smaller individual misc/char driver cleanups and fixes

  Full details are in the shortlog.

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

* tag 'char-misc-5.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc: (322 commits)
  habanalabs: remove unused but set variable 'ctx_asid'
  nvmem: qcom-spmi-sdam: Enable multiple devices
  dt-bindings: nvmem: SID: add binding for A100's SID controller
  nvmem: update Kconfig description
  nvmem: qfprom: Add fuse blowing support
  dt-bindings: nvmem: Add properties needed for blowing fuses
  dt-bindings: nvmem: qfprom: Convert to yaml
  nvmem: qfprom: use NVMEM_DEVID_AUTO for multiple instances
  nvmem: core: add support to auto devid
  nvmem: core: Add nvmem_cell_read_u8()
  nvmem: core: Grammar fixes for help text
  nvmem: sc27xx: add sc2730 efuse support
  nvmem: Enforce nvmem stride in the sysfs interface
  MAINTAINERS: Add git tree for NVMEM FRAMEWORK
  nvmem: sprd: Fix return value of sprd_efuse_probe()
  drivers: android: Fix the SPDX comment style
  drivers: android: Fix a variable declaration coding style issue
  drivers: android: Remove braces for a single statement if-else block
  drivers: android: Remove the use of else after return
  drivers: android: Fix a variable declaration coding style issue
  ...
This commit is contained in:
Linus Torvalds 2020-08-05 11:43:47 -07:00
commit 1785d11612
291 changed files with 10379 additions and 4138 deletions

View File

@ -90,3 +90,16 @@ Description: Display trc status register content
The ME FW writes Glitch Detection HW (TRC)
status information into trc status register
for BIOS and OS to monitor fw health.
What: /sys/class/mei/meiN/kind
Date: Jul 2020
KernelVersion: 5.8
Contact: Tomas Winkler <tomas.winkler@intel.com>
Description: Display kind of the device
Generic devices are marked as "mei"
while special purpose have their own
names.
Available options:
- mei: generic mei device.
- itouch: itouch (ipts) mei device.

View File

@ -126,3 +126,39 @@ Description:
1 no action
0 firmware record the notify code defined
in b[15:0].
What: /sys/devices/platform/stratix10-rsu.0/dcmf0
Date: June 2020
KernelVersion: 5.8
Contact: Richard Gong <richard.gong@linux.intel.com>
Description:
(RO) Decision firmware copy 0 version information.
What: /sys/devices/platform/stratix10-rsu.0/dcmf1
Date: June 2020
KernelVersion: 5.8
Contact: Richard Gong <richard.gong@linux.intel.com>
Description:
(RO) Decision firmware copy 1 version information.
What: /sys/devices/platform/stratix10-rsu.0/dcmf2
Date: June 2020
KernelVersion: 5.8
Contact: Richard Gong <richard.gong@linux.intel.com>
Description:
(RO) Decision firmware copy 2 version information.
What: /sys/devices/platform/stratix10-rsu.0/dcmf3
Date: June 2020
KernelVersion: 5.8
Contact: Richard Gong <richard.gong@linux.intel.com>
Description:
(RO) Decision firmware copy 3 version information.
What: /sys/devices/platform/stratix10-rsu.0/max_retry
Date: June 2020
KernelVersion: 5.8
Contact: Richard Gong <richard.gong@linux.intel.com>
Description:
(RO) max retry parameter is stored in the firmware
decision IO section, as a byte located at offset 0x18c.

View File

@ -70,10 +70,10 @@ statements via::
nullarbor:~ # cat <debugfs>/dynamic_debug/control
# filename:lineno [module]function flags format
/usr/src/packages/BUILD/sgi-enhancednfs-1.4/default/net/sunrpc/svc_rdma.c:323 [svcxprt_rdma]svc_rdma_cleanup =_ "SVCRDMA Module Removed, deregister RPC RDMA transport\012"
/usr/src/packages/BUILD/sgi-enhancednfs-1.4/default/net/sunrpc/svc_rdma.c:341 [svcxprt_rdma]svc_rdma_init =_ "\011max_inline : %d\012"
/usr/src/packages/BUILD/sgi-enhancednfs-1.4/default/net/sunrpc/svc_rdma.c:340 [svcxprt_rdma]svc_rdma_init =_ "\011sq_depth : %d\012"
/usr/src/packages/BUILD/sgi-enhancednfs-1.4/default/net/sunrpc/svc_rdma.c:338 [svcxprt_rdma]svc_rdma_init =_ "\011max_requests : %d\012"
net/sunrpc/svc_rdma.c:323 [svcxprt_rdma]svc_rdma_cleanup =_ "SVCRDMA Module Removed, deregister RPC RDMA transport\012"
net/sunrpc/svc_rdma.c:341 [svcxprt_rdma]svc_rdma_init =_ "\011max_inline : %d\012"
net/sunrpc/svc_rdma.c:340 [svcxprt_rdma]svc_rdma_init =_ "\011sq_depth : %d\012"
net/sunrpc/svc_rdma.c:338 [svcxprt_rdma]svc_rdma_init =_ "\011max_requests : %d\012"
...
@ -93,7 +93,7 @@ the debug statement callsites with any non-default flags::
nullarbor:~ # awk '$3 != "=_"' <debugfs>/dynamic_debug/control
# filename:lineno [module]function flags format
/usr/src/packages/BUILD/sgi-enhancednfs-1.4/default/net/sunrpc/svcsock.c:1603 [sunrpc]svc_send p "svc_process: st_sendto returned %d\012"
net/sunrpc/svcsock.c:1603 [sunrpc]svc_send p "svc_process: st_sendto returned %d\012"
Command Language Reference
==========================
@ -156,6 +156,7 @@ against. Possible keywords are:::
``line-range`` cannot contain space, e.g.
"1-30" is valid range but "1 - 30" is not.
``module=foo`` combined keyword=value form is interchangably accepted
The meanings of each keyword are:
@ -164,15 +165,18 @@ func
of each callsite. Example::
func svc_tcp_accept
func *recv* # in rfcomm, bluetooth, ping, tcp
file
The given string is compared against either the full pathname, the
src-root relative pathname, or the basename of the source file of
each callsite. Examples::
The given string is compared against either the src-root relative
pathname, or the basename of the source file of each callsite.
Examples::
file svcsock.c
file kernel/freezer.c
file /usr/src/packages/BUILD/sgi-enhancednfs-1.4/default/net/sunrpc/svcsock.c
file kernel/freezer.c # ie column 1 of control file
file drivers/usb/* # all callsites under it
file inode.c:start_* # parse :tail as a func (above)
file inode.c:1-100 # parse :tail as a line-range (above)
module
The given string is compared against the module name
@ -182,6 +186,7 @@ module
module sunrpc
module nfsd
module drm* # both drm, drm_kms_helper
format
The given string is searched for in the dynamic debug format
@ -251,8 +256,8 @@ the syntax described above, but must not exceed 1023 characters. Your
bootloader may impose lower limits.
These ``dyndbg`` params are processed just after the ddebug tables are
processed, as part of the arch_initcall. Thus you can enable debug
messages in all code run after this arch_initcall via this boot
processed, as part of the early_initcall. Thus you can enable debug
messages in all code run after this early_initcall via this boot
parameter.
On an x86 system for example ACPI enablement is a subsys_initcall and::

View File

@ -108,6 +108,13 @@ its hardware characteristcs.
* arm,cp14: must be present if the system accesses ETM/PTM management
registers via co-processor 14.
* qcom,skip-power-up: boolean. Indicates that an implementation can
skip powering up the trace unit. TRCPDCR.PU does not have to be set
on Qualcomm Technologies Inc. systems since ETMs are in the same power
domain as their CPU cores. This property is required to identify such
systems with hardware errata where the CPU watchdog counter is stopped
when TRCPDCR.PU is set.
* Optional property for TMC:
* arm,buffer-size: size of contiguous buffer space for TMC ETR
@ -121,6 +128,12 @@ its hardware characteristcs.
* interrupts : Exactly one SPI may be listed for reporting the address
error
* Optional property for configurable replicators:
* qcom,replicator-loses-context: boolean. Indicates that the replicator
will lose register context when AMBA clock is removed which is observed
in some replicator designs.
Graph bindings for Coresight
-------------------------------

View File

@ -1,11 +1,14 @@
Xilinx Slave Serial SPI FPGA Manager
Xilinx Spartan-6 FPGAs support a method of loading the bitstream over
what is referred to as "slave serial" interface.
Xilinx Spartan-6 and 7 Series FPGAs support a method of loading the
bitstream over what is referred to as "slave serial" interface.
The slave serial link is not technically SPI, and might require extra
circuits in order to play nicely with other SPI slaves on the same bus.
See https://www.xilinx.com/support/documentation/user_guides/ug380.pdf
See:
- https://www.xilinx.com/support/documentation/user_guides/ug380.pdf
- https://www.xilinx.com/support/documentation/user_guides/ug470_7Series_Config.pdf
- https://www.xilinx.com/support/documentation/application_notes/xapp583-fpga-configuration.pdf
Required properties:
- compatible: should contain "xlnx,fpga-slave-serial"
@ -13,6 +16,10 @@ Required properties:
- prog_b-gpios: config pin (referred to as PROGRAM_B in the manual)
- done-gpios: config status pin (referred to as DONE in the manual)
Optional properties:
- init-b-gpios: initialization status and configuration error pin
(referred to as INIT_B in the manual)
Example for full FPGA configuration:
fpga-region0 {
@ -37,7 +44,8 @@ Example for full FPGA configuration:
spi-max-frequency = <60000000>;
spi-cpha;
reg = <0>;
done-gpios = <&gpio0 9 GPIO_ACTIVE_HIGH>;
prog_b-gpios = <&gpio0 29 GPIO_ACTIVE_LOW>;
init-b-gpios = <&gpio0 28 GPIO_ACTIVE_LOW>;
done-gpios = <&gpio0 9 GPIO_ACTIVE_HIGH>;
};
};

View File

@ -15,14 +15,17 @@ allOf:
properties:
compatible:
enum:
- allwinner,sun4i-a10-sid
- allwinner,sun7i-a20-sid
- allwinner,sun8i-a83t-sid
- allwinner,sun8i-h3-sid
- allwinner,sun50i-a64-sid
- allwinner,sun50i-h5-sid
- allwinner,sun50i-h6-sid
oneOf:
- const: allwinner,sun4i-a10-sid
- const: allwinner,sun7i-a20-sid
- const: allwinner,sun8i-a83t-sid
- const: allwinner,sun8i-h3-sid
- const: allwinner,sun50i-a64-sid
- items:
- const: allwinner,sun50i-a100-sid
- const: allwinner,sun50i-a64-sid
- const: allwinner,sun50i-h5-sid
- const: allwinner,sun50i-h6-sid
reg:
maxItems: 1

View File

@ -0,0 +1,96 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/nvmem/qcom,qfprom.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm Technologies Inc, QFPROM Efuse bindings
maintainers:
- Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
allOf:
- $ref: "nvmem.yaml#"
properties:
compatible:
const: qcom,qfprom
reg:
# If the QFPROM is read-only OS image then only the corrected region
# needs to be provided. If the QFPROM is writable then all 4 regions
# must be provided.
oneOf:
- items:
- description: The corrected region.
- items:
- description: The corrected region.
- description: The raw region.
- description: The config region.
- description: The security control region.
# Clock must be provided if QFPROM is writable from the OS image.
clocks:
maxItems: 1
clock-names:
const: core
# Supply reference must be provided if QFPROM is writable from the OS image.
vcc-supply:
description: Our power supply.
# Needed if any child nodes are present.
"#address-cells":
const: 1
"#size-cells":
const: 1
required:
- compatible
- reg
examples:
- |
#include <dt-bindings/clock/qcom,gcc-sc7180.h>
soc {
#address-cells = <2>;
#size-cells = <2>;
efuse@784000 {
compatible = "qcom,qfprom";
reg = <0 0x00784000 0 0x8ff>,
<0 0x00780000 0 0x7a0>,
<0 0x00782000 0 0x100>,
<0 0x00786000 0 0x1fff>;
clocks = <&gcc GCC_SEC_CTRL_CLK_SRC>;
clock-names = "core";
#address-cells = <1>;
#size-cells = <1>;
vcc-supply = <&vreg_l11a_1p8>;
hstx-trim-primary@25b {
reg = <0x25b 0x1>;
bits = <1 3>;
};
};
};
- |
soc {
#address-cells = <2>;
#size-cells = <2>;
efuse@784000 {
compatible = "qcom,qfprom";
reg = <0 0x00784000 0 0x8ff>;
#address-cells = <1>;
#size-cells = <1>;
hstx-trim-primary@1eb {
reg = <0x1eb 0x1>;
bits = <1 4>;
};
};
};

View File

@ -1,35 +0,0 @@
= Qualcomm QFPROM device tree bindings =
This binding is intended to represent QFPROM which is found in most QCOM SOCs.
Required properties:
- compatible: should be "qcom,qfprom"
- reg: Should contain registers location and length
= Data cells =
Are child nodes of qfprom, bindings of which as described in
bindings/nvmem/nvmem.txt
Example:
qfprom: qfprom@700000 {
compatible = "qcom,qfprom";
reg = <0x00700000 0x8000>;
...
/* Data cells */
tsens_calibration: calib@404 {
reg = <0x4404 0x10>;
};
};
= Data consumers =
Are device nodes which consume nvmem data cells.
For example:
tsens {
...
nvmem-cells = <&tsens_calibration>;
nvmem-cell-names = "calibration";
};

View File

@ -0,0 +1,79 @@
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
%YAML 1.2
---
$id: "http://devicetree.org/schemas/phy/brcm,bcm63xx-usbh-phy.yaml#"
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
title: BCM63xx USBH PHY
maintainers:
- Álvaro Fernández Rojas <noltari@gmail.com>
properties:
compatible:
enum:
- brcm,bcm6318-usbh-phy
- brcm,bcm6328-usbh-phy
- brcm,bcm6358-usbh-phy
- brcm,bcm6362-usbh-phy
- brcm,bcm6368-usbh-phy
- brcm,bcm63268-usbh-phy
reg:
maxItems: 1
clocks:
minItems: 1
maxItems: 2
clock-names:
minItems: 1
maxItems: 2
items:
- const: usbh
- const: usb_ref
resets:
maxItems: 1
"#phy-cells":
const: 1
additionalProperties: false
required:
- compatible
- reg
- clocks
- clock-names
- resets
- "#phy-cells"
if:
properties:
compatible:
enum:
- brcm,bcm6318-usbh-phy
- brcm,bcm6328-usbh-phy
- brcm,bcm6362-usbh-phy
- brcm,bcm63268-usbh-phy
then:
properties:
power-domains:
maxItems: 1
required:
- power-domains
else:
properties:
power-domains: false
examples:
- |
usbh: usb-phy@10001700 {
compatible = "brcm,bcm6368-usbh-phy";
reg = <0x10001700 0x38>;
clocks = <&periph_clk 15>;
clock-names = "usbh";
resets = <&periph_rst 12>;
#phy-cells = <1>;
};

View File

@ -12,6 +12,13 @@ Required properties:
- #address-cells: should be 1.
- #size-cells: should be 0.
Optional properties:
- reg-names: must be "comphy" as the first name, and "conf".
- reg: must contain the comphy register location and length as the first
pair, followed by an optional configuration register address and
length pair.
A sub-node is required for each comphy lane provided by the comphy.
Required properties (child nodes):
@ -24,7 +31,8 @@ Example:
comphy: phy@18300 {
compatible = "marvell,armada-380-comphy";
reg = <0x18300 0x100>;
reg-names = "comphy", "conf";
reg = <0x18300 0x100>, <0x18460 4>;
#address-cells = <1>;
#size-cells = <0>;

View File

@ -0,0 +1,55 @@
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/phy/qcom,ipq806x-usb-phy-hs.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm ipq806x usb DWC3 HS PHY CONTROLLER
maintainers:
- Ansuel Smith <ansuelsmth@gmail.com>
description:
DWC3 PHY nodes are defined to describe on-chip Synopsis Physical layer
controllers used in ipq806x. Each DWC3 PHY controller should have its
own node.
properties:
compatible:
const: qcom,ipq806x-usb-phy-hs
"#phy-cells":
const: 0
reg:
maxItems: 1
clocks:
minItems: 1
maxItems: 2
clock-names:
minItems: 1
maxItems: 2
items:
- const: ref
- const: xo
required:
- compatible
- "#phy-cells"
- reg
- clocks
- clock-names
examples:
- |
#include <dt-bindings/clock/qcom,gcc-ipq806x.h>
hs_phy_0: phy@110f8800 {
compatible = "qcom,ipq806x-usb-phy-hs";
reg = <0x110f8800 0x30>;
clocks = <&gcc USB30_0_UTMI_CLK>;
clock-names = "ref";
#phy-cells = <0>;
};

View File

@ -0,0 +1,73 @@
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/phy/qcom,ipq806x-usb-phy-ss.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm ipq806x usb DWC3 SS PHY CONTROLLER
maintainers:
- Ansuel Smith <ansuelsmth@gmail.com>
description:
DWC3 PHY nodes are defined to describe on-chip Synopsis Physical layer
controllers used in ipq806x. Each DWC3 PHY controller should have its
own node.
properties:
compatible:
const: qcom,ipq806x-usb-phy-ss
"#phy-cells":
const: 0
reg:
maxItems: 1
clocks:
minItems: 1
maxItems: 2
clock-names:
minItems: 1
maxItems: 2
items:
- const: ref
- const: xo
qcom,rx-eq:
$ref: /schemas/types.yaml#/definitions/uint32
description: Override value for rx_eq.
default: 4
maximum: 7
qcom,tx-deamp-3_5db:
$ref: /schemas/types.yaml#/definitions/uint32
description: Override value for transmit preemphasis.
default: 23
maximum: 63
qcom,mpll:
$ref: /schemas/types.yaml#/definitions/uint32
description: Override value for mpll.
default: 0
maximum: 7
required:
- compatible
- "#phy-cells"
- reg
- clocks
- clock-names
examples:
- |
#include <dt-bindings/clock/qcom,gcc-ipq806x.h>
ss_phy_0: phy@110f8830 {
compatible = "qcom,ipq806x-usb-phy-ss";
reg = <0x110f8830 0x30>;
clocks = <&gcc USB30_0_MASTER_CLK>;
clock-names = "ref";
#phy-cells = <0>;
};

View File

@ -18,6 +18,7 @@ properties:
compatible:
enum:
- qcom,ipq8074-qmp-pcie-phy
- qcom,ipq8074-qmp-usb3-phy
- qcom,msm8996-qmp-pcie-phy
- qcom,msm8996-qmp-ufs-phy
- qcom,msm8996-qmp-usb3-phy
@ -161,6 +162,7 @@ allOf:
compatible:
contains:
enum:
- qcom,ipq8074-qmp-usb3-phy
- qcom,msm8996-qmp-usb3-phy
- qcom,msm8998-qmp-pcie-phy
- qcom,msm8998-qmp-usb3-phy

View File

@ -18,6 +18,7 @@ properties:
oneOf:
- items:
- enum:
- qcom,ipq8074-qusb2-phy
- qcom,msm8996-qusb2-phy
- qcom,msm8998-qusb2-phy
- items:

View File

@ -21,6 +21,7 @@ properties:
- renesas,usb2-phy-r8a774a1 # RZ/G2M
- renesas,usb2-phy-r8a774b1 # RZ/G2N
- renesas,usb2-phy-r8a774c0 # RZ/G2E
- renesas,usb2-phy-r8a774e1 # RZ/G2H
- renesas,usb2-phy-r8a7795 # R-Car H3
- renesas,usb2-phy-r8a7796 # R-Car M3-W
- renesas,usb2-phy-r8a77961 # R-Car M3-W+

View File

@ -15,6 +15,7 @@ properties:
- enum:
- renesas,r8a774a1-usb3-phy # RZ/G2M
- renesas,r8a774b1-usb3-phy # RZ/G2N
- renesas,r8a774e1-usb3-phy # RZ/G2H
- renesas,r8a7795-usb3-phy # R-Car H3
- renesas,r8a7796-usb3-phy # R-Car M3-W
- renesas,r8a77961-usb3-phy # R-Car M3-W+

View File

@ -0,0 +1,75 @@
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/phy/samsung,ufs-phy.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Samsung SoC series UFS PHY Device Tree Bindings
maintainers:
- Alim Akhtar <alim.akhtar@samsung.com>
properties:
"#phy-cells":
const: 0
compatible:
enum:
- samsung,exynos7-ufs-phy
reg:
maxItems: 1
reg-names:
items:
- const: phy-pma
clocks:
items:
- description: PLL reference clock
- description: symbol clock for input symbol ( rx0-ch0 symbol clock)
- description: symbol clock for input symbol ( rx1-ch1 symbol clock)
- description: symbol clock for output symbol ( tx0 symbol clock)
clock-names:
items:
- const: ref_clk
- const: rx1_symbol_clk
- const: rx0_symbol_clk
- const: tx0_symbol_clk
samsung,pmu-syscon:
$ref: '/schemas/types.yaml#/definitions/phandle'
description: phandle for PMU system controller interface, used to
control pmu registers bits for ufs m-phy
required:
- "#phy-cells"
- compatible
- reg
- reg-names
- clocks
- clock-names
- samsung,pmu-syscon
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/exynos7-clk.h>
ufs_phy: ufs-phy@15571800 {
compatible = "samsung,exynos7-ufs-phy";
reg = <0x15571800 0x240>;
reg-names = "phy-pma";
samsung,pmu-syscon = <&pmu_system_controller>;
#phy-cells = <0>;
clocks = <&clock_fsys1 SCLK_COMBO_PHY_EMBEDDED_26M>,
<&clock_fsys1 PHYCLK_UFS20_RX1_SYMBOL_USER>,
<&clock_fsys1 PHYCLK_UFS20_RX0_SYMBOL_USER>,
<&clock_fsys1 PHYCLK_UFS20_TX0_SYMBOL_USER>;
clock-names = "ref_clk", "rx1_symbol_clk",
"rx0_symbol_clk", "tx0_symbol_clk";
};
...

View File

@ -31,12 +31,16 @@ properties:
clocks:
minItems: 1
maxItems: 2
maxItems: 3
clock-names:
oneOf:
- const: link # for PXs2
- items: # for PXs3
- items: # for PXs3 with phy-ext
- const: link
- const: phy
- const: phy-ext
- items: # for others
- const: link
- const: phy

View File

@ -0,0 +1,105 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/phy/xlnx,zynqmp-psgtr.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Xilinx ZynqMP Gigabit Transceiver PHY Device Tree Bindings
maintainers:
- Laurent Pinchart <laurent.pinchart@ideasonboard.com>
description: |
This binding describes the Xilinx ZynqMP Gigabit Transceiver (GTR) PHY. The
GTR provides four lanes and is used by USB, SATA, PCIE, Display port and
Ethernet SGMII controllers.
properties:
"#phy-cells":
const: 4
description: |
The cells contain the following arguments.
- description: The GTR lane
minimum: 0
maximum: 3
- description: The PHY type
enum:
- PHY_TYPE_DP
- PHY_TYPE_PCIE
- PHY_TYPE_SATA
- PHY_TYPE_SGMII
- PHY_TYPE_USB
- description: The PHY instance
minimum: 0
maximum: 1 # for DP, SATA or USB
maximum: 3 # for PCIE or SGMII
- description: The reference clock number
minimum: 0
maximum: 3
compatible:
enum:
- xlnx,zynqmp-psgtr-v1.1
- xlnx,zynqmp-psgtr
clocks:
minItems: 1
maxItems: 4
description: |
Clock for each PS_MGTREFCLK[0-3] reference clock input. Unconnected
inputs shall not have an entry.
clock-names:
minItems: 1
maxItems: 4
items:
pattern: "^ref[0-3]$"
reg:
items:
- description: SERDES registers block
- description: SIOU registers block
reg-names:
items:
- const: serdes
- const: siou
xlnx,tx-termination-fix:
description: |
Include this for fixing functional issue with the TX termination
resistance in GT, which can be out of spec for the XCZU9EG silicon
version.
type: boolean
required:
- "#phy-cells"
- compatible
- reg
- reg-names
if:
properties:
compatible:
const: xlnx,zynqmp-psgtr-v1.1
then:
properties:
xlnx,tx-termination-fix: false
additionalProperties: false
examples:
- |
phy: phy@fd400000 {
compatible = "xlnx,zynqmp-psgtr-v1.1";
reg = <0xfd400000 0x40000>,
<0xfd3d0000 0x1000>;
reg-names = "serdes", "siou";
clocks = <&refclks 3>, <&refclks 2>, <&refclks 0>;
clock-names = "ref1", "ref2", "ref3";
#phy-cells = <4>;
};
...

View File

@ -28,6 +28,6 @@ able to make use of built-in firmware:
* Some firmware files may be really large in size. The remote-proc subsystem
is an example subsystem which deals with these sorts of firmware
* The firmware may need to be scraped out from some device specific location
dynamically, an example is calibration data for for some WiFi chipsets. This
dynamically, an example is calibration data for some WiFi chipsets. This
calibration data can be unique per sold device.

View File

@ -24,7 +24,7 @@ available. Stuffing the firmware into initramfs resolves this race issue,
however note that using initrd does not suffice to address the same race.
There are circumstances that justify not wanting to include firmware into
initramfs, such as dealing with large firmware firmware files for the
initramfs, such as dealing with large firmware files for the
remote-proc subsystem. For such cases using a userspace fallback mechanism
is currently the only viable solution as only userspace can know for sure
when the real rootfs is ready and mounted.

View File

@ -27,7 +27,7 @@ Some implementation details about the firmware cache setup:
uses all synchronous call except :c:func:`request_firmware_into_buf`.
* If an asynchronous call is used the firmware cache is only set up for a
device if if the second argument (uevent) to request_firmware_nowait() is
device if the second argument (uevent) to request_firmware_nowait() is
true. When uevent is true it requests that a kobject uevent be sent to
userspace for the firmware request through the sysfs fallback mechanism
if the firmware file is not found.

View File

@ -76,5 +76,5 @@ firmware. For example if you used request_firmware() and it returns,
the driver has the firmware image accessible in fw_entry->{data,size}.
If something went wrong request_firmware() returns non-zero and fw_entry
is set to NULL. Once your driver is done with processing the firmware it
can call call release_firmware(fw_entry) to release the firmware image
can call release_firmware(fw_entry) to release the firmware image
and any related resource.

View File

@ -293,6 +293,10 @@ per stream. From ASoC DPCM framework, this stream state maybe linked to
int sdw_alloc_stream(char * stream_name);
The SoundWire core provides a sdw_startup_stream() helper function,
typically called during a dailink .startup() callback, which performs
stream allocation and sets the stream pointer for all DAIs
connected to a stream.
SDW_STREAM_CONFIGURED
~~~~~~~~~~~~~~~~~~~~~
@ -509,7 +513,12 @@ In .shutdown() the data structure maintaining stream state are freed up.
void sdw_release_stream(struct sdw_stream_runtime * stream);
Not Supported
The SoundWire core provides a sdw_shutdown_stream() helper function,
typically called during a dailink .shutdown() callback, which clears
the stream pointer for all DAIS connected to a stream and releases the
memory allocated for the stream.
Not Supported
=============
1. A single port with multiple channels supported cannot be used between two

View File

@ -274,7 +274,7 @@ fields of ``struct uio_mem``:
region, it will show up in the corresponding sysfs node.
- ``int memtype``: Required if the mapping is used. Set this to
``UIO_MEM_PHYS`` if you you have physical memory on your card to be
``UIO_MEM_PHYS`` if you have physical memory on your card to be
mapped. Use ``UIO_MEM_LOGICAL`` for logical memory (e.g. allocated
with :c:func:`__get_free_pages()` but not kmalloc()). There's also
``UIO_MEM_VIRTUAL`` for virtual memory.

View File

@ -273,7 +273,7 @@ buffer is full, the FPGA informs the host about that (appending a
XILLYMSG_OPCODE_RELEASEBUF message channel 0 and sending an interrupt if
necessary). The host responds by making the data available for reading through
the character device. When all data has been read, the host writes on the
the FPGA's buffer control register, allowing the buffer's overwriting. Flow
FPGA's buffer control register, allowing the buffer's overwriting. Flow
control mechanisms exist on both sides to prevent underflows and overflows.
This is not good enough for creating a TCP/IP-like stream: If the data flow

View File

@ -89,6 +89,8 @@ The following functions are exposed through ioctls:
- Program bitstream (DFL_FPGA_FME_PORT_PR)
- Assign port to PF (DFL_FPGA_FME_PORT_ASSIGN)
- Release port from PF (DFL_FPGA_FME_PORT_RELEASE)
- Get number of irqs of FME global error (DFL_FPGA_FME_ERR_GET_IRQ_NUM)
- Set interrupt trigger for FME error (DFL_FPGA_FME_ERR_SET_IRQ)
More functions are exposed through sysfs
(/sys/class/fpga_region/regionX/dfl-fme.n/):
@ -149,6 +151,10 @@ The following functions are exposed through ioctls:
- Map DMA buffer (DFL_FPGA_PORT_DMA_MAP)
- Unmap DMA buffer (DFL_FPGA_PORT_DMA_UNMAP)
- Reset AFU (DFL_FPGA_PORT_RESET)
- Get number of irqs of port error (DFL_FPGA_PORT_ERR_GET_IRQ_NUM)
- Set interrupt trigger for port error (DFL_FPGA_PORT_ERR_SET_IRQ)
- Get number of irqs of UINT (DFL_FPGA_PORT_UINT_GET_IRQ_NUM)
- Set interrupt trigger for UINT (DFL_FPGA_PORT_UINT_SET_IRQ)
DFL_FPGA_PORT_RESET:
reset the FPGA Port and its AFU. Userspace can do Port
@ -462,6 +468,19 @@ since they are system-wide counters on FPGA device.
The current driver does not support sampling. So "perf record" is unsupported.
Interrupt support
=================
Some FME and AFU private features are able to generate interrupts. As mentioned
above, users could call ioctl (DFL_FPGA_*_GET_IRQ_NUM) to know whether or how
many interrupts are supported for this private feature. Drivers also implement
an eventfd based interrupt handling mechanism for users to get notified when
interrupt happens. Users could set eventfds to driver via
ioctl (DFL_FPGA_*_SET_IRQ), and then poll/select on these eventfds waiting for
notification.
In Current DFL, 3 sub features (Port error, FME global error and AFU interrupt)
support interrupts.
Add new FIUs support
====================
It's possible that developers made some new function blocks (FIUs) under this

View File

@ -1179,6 +1179,8 @@ M: Todd Kjos <tkjos@android.com>
M: Martijn Coenen <maco@android.com>
M: Joel Fernandes <joel@joelfernandes.org>
M: Christian Brauner <christian@brauner.io>
M: Hridya Valsaraju <hridya@google.com>
M: Suren Baghdasaryan <surenb@google.com>
L: devel@driverdev.osuosl.org
S: Supported
T: git git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git
@ -8833,7 +8835,7 @@ M: Tomas Winkler <tomas.winkler@intel.com>
L: linux-kernel@vger.kernel.org
S: Supported
F: Documentation/driver-api/mei/*
F: drivers/misc/mei/*
F: drivers/misc/mei/
F: drivers/watchdog/mei_wdt.c
F: include/linux/mei_cl_bus.h
F: include/uapi/linux/mei.h
@ -12329,6 +12331,7 @@ F: drivers/nvme/target/
NVMEM FRAMEWORK
M: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
S: Maintained
T: git git://git.kernel.org/pub/scm/linux/kernel/git/srini/nvmem.git
F: Documentation/ABI/stable/sysfs-bus-nvmem
F: Documentation/devicetree/bindings/nvmem/
F: drivers/nvmem/
@ -16082,8 +16085,9 @@ F: sound/soc/sof/
SOUNDWIRE SUBSYSTEM
M: Vinod Koul <vkoul@kernel.org>
M: Sanyog Kale <sanyog.r.kale@intel.com>
M: Bard Liao <yung-chuan.liao@linux.intel.com>
R: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
R: Sanyog Kale <sanyog.r.kale@intel.com>
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
S: Supported
F: Documentation/driver-api/soundwire/
@ -18922,6 +18926,15 @@ F: Documentation/devicetree/bindings/media/xilinx/
F: drivers/media/platform/xilinx/
F: include/uapi/linux/xilinx-v4l2-controls.h
XILINX ZYNQMP PSGTR PHY DRIVER
M: Anurag Kumar Vulisha <anurag.kumar.vulisha@xilinx.com>
M: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
L: linux-kernel@vger.kernel.org
S: Supported
T: git https://github.com/Xilinx/linux-xlnx.git
F: Documentation/devicetree/bindings/phy/xlnx,zynqmp-psgtr.yaml
F: drivers/phy/xilinx/phy-zynqmp.c
XILLYBUS DRIVER
M: Eli Billauer <eli.billauer@gmail.com>
L: linux-kernel@vger.kernel.org

View File

@ -1969,9 +1969,8 @@ static void binder_send_failed_reply(struct binder_transaction *t,
binder_thread_dec_tmpref(target_thread);
binder_free_transaction(t);
return;
} else {
__release(&target_thread->proc->inner_lock);
}
__release(&target_thread->proc->inner_lock);
next = t->from_parent;
binder_debug(BINDER_DEBUG_FAILED_TRANSACTION,
@ -2760,11 +2759,10 @@ static bool binder_proc_transaction(struct binder_transaction *t,
binder_node_lock(node);
if (oneway) {
BUG_ON(thread);
if (node->has_async_transaction) {
if (node->has_async_transaction)
pending_async = true;
} else {
else
node->has_async_transaction = true;
}
}
binder_inner_proc_lock(proc);
@ -2982,6 +2980,12 @@ static void binder_transaction(struct binder_proc *proc,
goto err_dead_binder;
}
e->to_node = target_node->debug_id;
if (WARN_ON(proc == target_proc)) {
return_error = BR_FAILED_REPLY;
return_error_param = -EINVAL;
return_error_line = __LINE__;
goto err_invalid_target_handle;
}
if (security_binder_transaction(proc->tsk,
target_proc->tsk) < 0) {
return_error = BR_FAILED_REPLY;
@ -3635,10 +3639,17 @@ static int binder_thread_write(struct binder_proc *proc,
struct binder_node *ctx_mgr_node;
mutex_lock(&context->context_mgr_node_lock);
ctx_mgr_node = context->binder_context_mgr_node;
if (ctx_mgr_node)
if (ctx_mgr_node) {
if (ctx_mgr_node->proc == proc) {
binder_user_error("%d:%d context manager tried to acquire desc 0\n",
proc->pid, thread->pid);
mutex_unlock(&context->context_mgr_node_lock);
return -EINVAL;
}
ret = binder_inc_ref_for_node(
proc, ctx_mgr_node,
strong, NULL, &rdata);
}
mutex_unlock(&context->context_mgr_node_lock);
}
if (ret)

View File

@ -547,6 +547,7 @@ static void binder_delete_free_buffer(struct binder_alloc *alloc,
{
struct binder_buffer *prev, *next = NULL;
bool to_free = true;
BUG_ON(alloc->buffers.next == &buffer->entry);
prev = binder_buffer_prev(buffer);
BUG_ON(!prev->free);

View File

@ -1,4 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0 */
// SPDX-License-Identifier: GPL-2.0
#include <linux/compiler_types.h>
#include <linux/errno.h>
@ -351,6 +351,7 @@ static const struct super_operations binderfs_super_ops = {
static inline bool is_binderfs_control_device(const struct dentry *dentry)
{
struct binderfs_info *info = dentry->d_sb->s_fs_info;
return info->control_dentry == dentry;
}

View File

@ -27,7 +27,16 @@ static bool fsl_mc_device_match(struct fsl_mc_device *mc_dev,
{
return mc_dev->obj_desc.id == obj_desc->id &&
strcmp(mc_dev->obj_desc.type, obj_desc->type) == 0;
}
static bool fsl_mc_obj_desc_is_allocatable(struct fsl_mc_obj_desc *obj)
{
if (strcmp(obj->type, "dpmcp") == 0 ||
strcmp(obj->type, "dpcon") == 0 ||
strcmp(obj->type, "dpbp") == 0)
return true;
else
return false;
}
static int __fsl_mc_device_remove_if_not_in_mc(struct device *dev, void *data)
@ -150,6 +159,27 @@ static void check_plugged_state_change(struct fsl_mc_device *mc_dev,
}
}
static void fsl_mc_obj_device_add(struct fsl_mc_device *mc_bus_dev,
struct fsl_mc_obj_desc *obj_desc)
{
int error;
struct fsl_mc_device *child_dev;
/*
* Check if device is already known to Linux:
*/
child_dev = fsl_mc_device_lookup(obj_desc, mc_bus_dev);
if (child_dev) {
check_plugged_state_change(child_dev, obj_desc);
put_device(&child_dev->dev);
} else {
error = fsl_mc_device_add(obj_desc, NULL, &mc_bus_dev->dev,
&child_dev);
if (error < 0)
return;
}
}
/**
* dprc_add_new_devices - Adds devices to the logical bus for a DPRC
*
@ -166,30 +196,23 @@ static void dprc_add_new_devices(struct fsl_mc_device *mc_bus_dev,
struct fsl_mc_obj_desc *obj_desc_array,
int num_child_objects_in_mc)
{
int error;
int i;
/* probe the allocable objects first */
for (i = 0; i < num_child_objects_in_mc; i++) {
struct fsl_mc_device *child_dev;
struct fsl_mc_obj_desc *obj_desc = &obj_desc_array[i];
if (strlen(obj_desc->type) == 0)
continue;
if (strlen(obj_desc->type) > 0 &&
fsl_mc_obj_desc_is_allocatable(obj_desc))
fsl_mc_obj_device_add(mc_bus_dev, obj_desc);
}
/*
* Check if device is already known to Linux:
*/
child_dev = fsl_mc_device_lookup(obj_desc, mc_bus_dev);
if (child_dev) {
check_plugged_state_change(child_dev, obj_desc);
put_device(&child_dev->dev);
continue;
}
for (i = 0; i < num_child_objects_in_mc; i++) {
struct fsl_mc_obj_desc *obj_desc = &obj_desc_array[i];
error = fsl_mc_device_add(obj_desc, NULL, &mc_bus_dev->dev,
&child_dev);
if (error < 0)
continue;
if (strlen(obj_desc->type) > 0 &&
!fsl_mc_obj_desc_is_allocatable(obj_desc))
fsl_mc_obj_device_add(mc_bus_dev, obj_desc);
}
}

View File

@ -213,6 +213,31 @@ struct device_type fsl_mc_bus_dpseci_type = {
};
EXPORT_SYMBOL_GPL(fsl_mc_bus_dpseci_type);
struct device_type fsl_mc_bus_dpdmux_type = {
.name = "fsl_mc_bus_dpdmux"
};
EXPORT_SYMBOL_GPL(fsl_mc_bus_dpdmux_type);
struct device_type fsl_mc_bus_dpdcei_type = {
.name = "fsl_mc_bus_dpdcei"
};
EXPORT_SYMBOL_GPL(fsl_mc_bus_dpdcei_type);
struct device_type fsl_mc_bus_dpaiop_type = {
.name = "fsl_mc_bus_dpaiop"
};
EXPORT_SYMBOL_GPL(fsl_mc_bus_dpaiop_type);
struct device_type fsl_mc_bus_dpci_type = {
.name = "fsl_mc_bus_dpci"
};
EXPORT_SYMBOL_GPL(fsl_mc_bus_dpci_type);
struct device_type fsl_mc_bus_dpdmai_type = {
.name = "fsl_mc_bus_dpdmai"
};
EXPORT_SYMBOL_GPL(fsl_mc_bus_dpdmai_type);
static struct device_type *fsl_mc_get_device_type(const char *type)
{
static const struct {
@ -229,6 +254,11 @@ static struct device_type *fsl_mc_get_device_type(const char *type)
{ &fsl_mc_bus_dpmac_type, "dpmac" },
{ &fsl_mc_bus_dprtc_type, "dprtc" },
{ &fsl_mc_bus_dpseci_type, "dpseci" },
{ &fsl_mc_bus_dpdmux_type, "dpdmux" },
{ &fsl_mc_bus_dpdcei_type, "dpdcei" },
{ &fsl_mc_bus_dpaiop_type, "dpaiop" },
{ &fsl_mc_bus_dpci_type, "dpci" },
{ &fsl_mc_bus_dpdmai_type, "dpdmai" },
{ NULL, NULL }
};
int i;

View File

@ -82,7 +82,7 @@ int __must_check fsl_create_mc_io(struct device *dev,
mc_io->portal_phys_addr = mc_portal_phys_addr;
mc_io->portal_size = mc_portal_size;
if (flags & FSL_MC_IO_ATOMIC_CONTEXT_PORTAL)
spin_lock_init(&mc_io->spinlock);
raw_spin_lock_init(&mc_io->spinlock);
else
mutex_init(&mc_io->mutex);

View File

@ -251,7 +251,7 @@ int mc_send_command(struct fsl_mc_io *mc_io, struct fsl_mc_command *cmd)
return -EINVAL;
if (mc_io->flags & FSL_MC_IO_ATOMIC_CONTEXT_PORTAL)
spin_lock_irqsave(&mc_io->spinlock, irq_flags);
raw_spin_lock_irqsave(&mc_io->spinlock, irq_flags);
else
mutex_lock(&mc_io->mutex);
@ -287,7 +287,7 @@ int mc_send_command(struct fsl_mc_io *mc_io, struct fsl_mc_command *cmd)
error = 0;
common_exit:
if (mc_io->flags & FSL_MC_IO_ATOMIC_CONTEXT_PORTAL)
spin_unlock_irqrestore(&mc_io->spinlock, irq_flags);
raw_spin_unlock_irqrestore(&mc_io->spinlock, irq_flags);
else
mutex_unlock(&mc_io->mutex);

View File

@ -38,7 +38,7 @@ config PRINTER
box (as opposed to using a serial printer; if the connector at the
printer has 9 or 25 holes ["female"], then it's serial), say Y.
Also read the Printing-HOWTO, available from
<http://www.tldp.org/docs.html#howto>.
<https://www.tldp.org/docs.html#howto>.
It is possible to share one parallel port among several devices
(e.g. printer and ZIP drive) and it is safe to compile the
@ -201,7 +201,7 @@ config DTLK
depends on ISA
help
This driver is for the DoubleTalk PC, a speech synthesizer
manufactured by RC Systems (<http://www.rcsys.com/>). It is also
manufactured by RC Systems (<https://www.rcsys.com/>). It is also
called the `internal DoubleTalk'.
To compile this driver as a module, choose M here: the
@ -237,7 +237,7 @@ config APPLICOM
This driver provides the kernel-side support for the intelligent
fieldbus cards made by Applicom International. More information
about these cards can be found on the WWW at the address
<http://www.applicom-int.com/>, or by email from David Woodhouse
<https://www.applicom-int.com/>, or by email from David Woodhouse
<dwmw2@infradead.org>.
To compile this driver as a module, choose M here: the

View File

@ -126,7 +126,7 @@ static int smapi_request(unsigned short inBX, unsigned short inCX,
int smapi_query_DSP_cfg(SMAPI_DSP_SETTINGS * pSettings)
{
int bRC = -EIO;
int bRC;
unsigned short usAX, usBX, usCX, usDX, usDI, usSI;
static const unsigned short ausDspBases[] = {
0x0030, 0x4E30, 0x8E30, 0xCE30,
@ -497,7 +497,7 @@ exit_smapi_request_error:
int smapi_set_DSP_power_state(bool bOn)
{
int bRC = -EIO;
int bRC;
unsigned short usAX, usBX, usCX, usDX, usDI, usSI;
unsigned short usPowerFunction;

View File

@ -37,7 +37,7 @@ static struct raw_device_data *raw_devices;
static DEFINE_MUTEX(raw_mutex);
static const struct file_operations raw_ctl_fops; /* forward declaration */
static int max_raw_minors = MAX_RAW_MINORS;
static int max_raw_minors = CONFIG_MAX_RAW_DEVS;
module_param(max_raw_minors, int, 0);
MODULE_PARM_DESC(max_raw_minors, "Maximum number of raw devices (1-65536)");
@ -317,9 +317,9 @@ static int __init raw_init(void)
int ret;
if (max_raw_minors < 1 || max_raw_minors > 65536) {
printk(KERN_WARNING "raw: invalid max_raw_minors (must be"
" between 1 and 65536), using %d\n", MAX_RAW_MINORS);
max_raw_minors = MAX_RAW_MINORS;
pr_warn("raw: invalid max_raw_minors (must be between 1 and 65536), using %d\n",
CONFIG_MAX_RAW_DEVS);
max_raw_minors = CONFIG_MAX_RAW_DEVS;
}
raw_devices = vzalloc(array_size(max_raw_minors,

View File

@ -172,7 +172,7 @@ static struct tty_driver *ttyprintk_driver;
static int __init ttyprintk_init(void)
{
int ret = -ENOMEM;
int ret;
spin_lock_init(&tpk_port.spinlock);

View File

@ -2112,18 +2112,18 @@ fail:
return err;
}
static struct virtio_device_id id_table[] = {
static const struct virtio_device_id id_table[] = {
{ VIRTIO_ID_CONSOLE, VIRTIO_DEV_ANY_ID },
{ 0 },
};
MODULE_DEVICE_TABLE(virtio, id_table);
static unsigned int features[] = {
static const unsigned int features[] = {
VIRTIO_CONSOLE_F_SIZE,
VIRTIO_CONSOLE_F_MULTIPORT,
};
static struct virtio_device_id rproc_serial_id_table[] = {
static const struct virtio_device_id rproc_serial_id_table[] = {
#if IS_ENABLED(CONFIG_REMOTEPROC)
{ VIRTIO_ID_RPROC_SERIAL, VIRTIO_DEV_ANY_ID },
#endif
@ -2131,7 +2131,7 @@ static struct virtio_device_id rproc_serial_id_table[] = {
};
MODULE_DEVICE_TABLE(virtio, rproc_serial_id_table);
static unsigned int rproc_serial_features[] = {
static const unsigned int rproc_serial_features[] = {
};
#ifdef CONFIG_PM_SLEEP

View File

@ -20,10 +20,16 @@
#define RSU_VERSION_MASK GENMASK_ULL(63, 32)
#define RSU_ERROR_LOCATION_MASK GENMASK_ULL(31, 0)
#define RSU_ERROR_DETAIL_MASK GENMASK_ULL(63, 32)
#define RSU_DCMF0_MASK GENMASK_ULL(31, 0)
#define RSU_DCMF1_MASK GENMASK_ULL(63, 32)
#define RSU_DCMF2_MASK GENMASK_ULL(31, 0)
#define RSU_DCMF3_MASK GENMASK_ULL(63, 32)
#define RSU_TIMEOUT (msecs_to_jiffies(SVC_RSU_REQUEST_TIMEOUT_MS))
#define INVALID_RETRY_COUNTER 0xFFFFFFFF
#define INVALID_RETRY_COUNTER 0xFF
#define INVALID_DCMF_VERSION 0xFF
typedef void (*rsu_callback)(struct stratix10_svc_client *client,
struct stratix10_svc_cb_data *data);
@ -35,11 +41,16 @@ typedef void (*rsu_callback)(struct stratix10_svc_client *client,
* @lock: a mutex to protect callback completion state
* @status.current_image: address of image currently running in flash
* @status.fail_image: address of failed image in flash
* @status.version: the version number of RSU firmware
* @status.version: the interface version number of RSU firmware
* @status.state: the state of RSU system
* @status.error_details: error code
* @status.error_location: the error offset inside the image that failed
* @dcmf_version.dcmf0: Quartus dcmf0 version
* @dcmf_version.dcmf1: Quartus dcmf1 version
* @dcmf_version.dcmf2: Quartus dcmf2 version
* @dcmf_version.dcmf3: Quartus dcmf3 version
* @retry_counter: the current image's retry counter
* @max_retry: the preset max retry value
*/
struct stratix10_rsu_priv {
struct stratix10_svc_chan *chan;
@ -54,7 +65,16 @@ struct stratix10_rsu_priv {
unsigned int error_details;
unsigned int error_location;
} status;
struct {
unsigned int dcmf0;
unsigned int dcmf1;
unsigned int dcmf2;
unsigned int dcmf3;
} dcmf_version;
unsigned int retry_counter;
unsigned int max_retry;
};
/**
@ -109,7 +129,7 @@ static void rsu_command_callback(struct stratix10_svc_client *client,
struct stratix10_rsu_priv *priv = client->priv;
if (data->status == BIT(SVC_STATUS_NO_SUPPORT))
dev_warn(client->dev, "Secure FW doesn't support notify\n");
dev_warn(client->dev, "FW doesn't support notify\n");
else if (data->status == BIT(SVC_STATUS_ERROR))
dev_err(client->dev, "Failure, returned status is %lu\n",
BIT(data->status));
@ -119,7 +139,7 @@ static void rsu_command_callback(struct stratix10_svc_client *client,
/**
* rsu_retry_callback() - Callback from Intel service layer for getting
* the current image's retry counter from firmware
* the current image's retry counter from the firmware
* @client: pointer to client
* @data: pointer to callback data structure
*
@ -136,7 +156,7 @@ static void rsu_retry_callback(struct stratix10_svc_client *client,
if (data->status == BIT(SVC_STATUS_OK))
priv->retry_counter = *counter;
else if (data->status == BIT(SVC_STATUS_NO_SUPPORT))
dev_warn(client->dev, "Secure FW doesn't support retry\n");
dev_warn(client->dev, "FW doesn't support retry\n");
else
dev_err(client->dev, "Failed to get retry counter %lu\n",
BIT(data->status));
@ -144,6 +164,57 @@ static void rsu_retry_callback(struct stratix10_svc_client *client,
complete(&priv->completion);
}
/**
* rsu_max_retry_callback() - Callback from Intel service layer for getting
* the max retry value from the firmware
* @client: pointer to client
* @data: pointer to callback data structure
*
* Callback from Intel service layer for max retry.
*/
static void rsu_max_retry_callback(struct stratix10_svc_client *client,
struct stratix10_svc_cb_data *data)
{
struct stratix10_rsu_priv *priv = client->priv;
unsigned int *max_retry = (unsigned int *)data->kaddr1;
if (data->status == BIT(SVC_STATUS_OK))
priv->max_retry = *max_retry;
else if (data->status == BIT(SVC_STATUS_NO_SUPPORT))
dev_warn(client->dev, "FW doesn't support max retry\n");
else
dev_err(client->dev, "Failed to get max retry %lu\n",
BIT(data->status));
complete(&priv->completion);
}
/**
* rsu_dcmf_version_callback() - Callback from Intel service layer for getting
* the DCMF version
* @client: pointer to client
* @data: pointer to callback data structure
*
* Callback from Intel service layer for DCMF version number
*/
static void rsu_dcmf_version_callback(struct stratix10_svc_client *client,
struct stratix10_svc_cb_data *data)
{
struct stratix10_rsu_priv *priv = client->priv;
unsigned long long *value1 = (unsigned long long *)data->kaddr1;
unsigned long long *value2 = (unsigned long long *)data->kaddr2;
if (data->status == BIT(SVC_STATUS_OK)) {
priv->dcmf_version.dcmf0 = FIELD_GET(RSU_DCMF0_MASK, *value1);
priv->dcmf_version.dcmf1 = FIELD_GET(RSU_DCMF1_MASK, *value1);
priv->dcmf_version.dcmf2 = FIELD_GET(RSU_DCMF2_MASK, *value2);
priv->dcmf_version.dcmf3 = FIELD_GET(RSU_DCMF3_MASK, *value2);
} else
dev_err(client->dev, "failed to get DCMF version\n");
complete(&priv->completion);
}
/**
* rsu_send_msg() - send a message to Intel service layer
* @priv: pointer to rsu private data
@ -282,6 +353,61 @@ static ssize_t retry_counter_show(struct device *dev,
return sprintf(buf, "0x%08x\n", priv->retry_counter);
}
static ssize_t max_retry_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct stratix10_rsu_priv *priv = dev_get_drvdata(dev);
if (!priv)
return -ENODEV;
return sprintf(buf, "0x%08x\n", priv->max_retry);
}
static ssize_t dcmf0_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct stratix10_rsu_priv *priv = dev_get_drvdata(dev);
if (!priv)
return -ENODEV;
return sprintf(buf, "0x%08x\n", priv->dcmf_version.dcmf0);
}
static ssize_t dcmf1_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct stratix10_rsu_priv *priv = dev_get_drvdata(dev);
if (!priv)
return -ENODEV;
return sprintf(buf, "0x%08x\n", priv->dcmf_version.dcmf1);
}
static ssize_t dcmf2_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct stratix10_rsu_priv *priv = dev_get_drvdata(dev);
if (!priv)
return -ENODEV;
return sprintf(buf, "0x%08x\n", priv->dcmf_version.dcmf2);
}
static ssize_t dcmf3_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct stratix10_rsu_priv *priv = dev_get_drvdata(dev);
if (!priv)
return -ENODEV;
return sprintf(buf, "0x%08x\n", priv->dcmf_version.dcmf3);
}
static ssize_t reboot_image_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
@ -290,7 +416,7 @@ static ssize_t reboot_image_store(struct device *dev,
unsigned long address;
int ret;
if (priv == 0)
if (!priv)
return -ENODEV;
ret = kstrtoul(buf, 0, &address);
@ -315,7 +441,7 @@ static ssize_t notify_store(struct device *dev,
unsigned long status;
int ret;
if (priv == 0)
if (!priv)
return -ENODEV;
ret = kstrtoul(buf, 0, &status);
@ -353,6 +479,11 @@ static DEVICE_ATTR_RO(version);
static DEVICE_ATTR_RO(error_location);
static DEVICE_ATTR_RO(error_details);
static DEVICE_ATTR_RO(retry_counter);
static DEVICE_ATTR_RO(max_retry);
static DEVICE_ATTR_RO(dcmf0);
static DEVICE_ATTR_RO(dcmf1);
static DEVICE_ATTR_RO(dcmf2);
static DEVICE_ATTR_RO(dcmf3);
static DEVICE_ATTR_WO(reboot_image);
static DEVICE_ATTR_WO(notify);
@ -364,6 +495,11 @@ static struct attribute *rsu_attrs[] = {
&dev_attr_error_location.attr,
&dev_attr_error_details.attr,
&dev_attr_retry_counter.attr,
&dev_attr_max_retry.attr,
&dev_attr_dcmf0.attr,
&dev_attr_dcmf1.attr,
&dev_attr_dcmf2.attr,
&dev_attr_dcmf3.attr,
&dev_attr_reboot_image.attr,
&dev_attr_notify.attr,
NULL
@ -391,6 +527,11 @@ static int stratix10_rsu_probe(struct platform_device *pdev)
priv->status.version = 0;
priv->status.state = 0;
priv->retry_counter = INVALID_RETRY_COUNTER;
priv->dcmf_version.dcmf0 = INVALID_DCMF_VERSION;
priv->dcmf_version.dcmf1 = INVALID_DCMF_VERSION;
priv->dcmf_version.dcmf2 = INVALID_DCMF_VERSION;
priv->dcmf_version.dcmf3 = INVALID_DCMF_VERSION;
priv->max_retry = INVALID_RETRY_COUNTER;
mutex_init(&priv->lock);
priv->chan = stratix10_svc_request_channel_byname(&priv->client,
@ -412,12 +553,27 @@ static int stratix10_rsu_probe(struct platform_device *pdev)
stratix10_svc_free_channel(priv->chan);
}
/* get DCMF version from firmware */
ret = rsu_send_msg(priv, COMMAND_RSU_DCMF_VERSION,
0, rsu_dcmf_version_callback);
if (ret) {
dev_err(dev, "Error, getting DCMF version %i\n", ret);
stratix10_svc_free_channel(priv->chan);
}
ret = rsu_send_msg(priv, COMMAND_RSU_RETRY, 0, rsu_retry_callback);
if (ret) {
dev_err(dev, "Error, getting RSU retry %i\n", ret);
stratix10_svc_free_channel(priv->chan);
}
ret = rsu_send_msg(priv, COMMAND_RSU_MAX_RETRY, 0,
rsu_max_retry_callback);
if (ret) {
dev_err(dev, "Error, getting RSU max retry %i\n", ret);
stratix10_svc_free_channel(priv->chan);
}
return ret;
}

View File

@ -305,9 +305,15 @@ static void svc_thread_recv_status_ok(struct stratix10_svc_data *p_data,
cb_data->status = BIT(SVC_STATUS_COMPLETED);
break;
case COMMAND_RSU_RETRY:
case COMMAND_RSU_MAX_RETRY:
cb_data->status = BIT(SVC_STATUS_OK);
cb_data->kaddr1 = &res.a1;
break;
case COMMAND_RSU_DCMF_VERSION:
cb_data->status = BIT(SVC_STATUS_OK);
cb_data->kaddr1 = &res.a1;
cb_data->kaddr2 = &res.a2;
break;
default:
pr_warn("it shouldn't happen\n");
break;
@ -406,6 +412,16 @@ static int svc_normal_to_secure_thread(void *data)
a1 = 0;
a2 = 0;
break;
case COMMAND_RSU_MAX_RETRY:
a0 = INTEL_SIP_SMC_RSU_MAX_RETRY;
a1 = 0;
a2 = 0;
break;
case COMMAND_RSU_DCMF_VERSION:
a0 = INTEL_SIP_SMC_RSU_DCMF_VERSION;
a1 = 0;
a2 = 0;
break;
default:
pr_warn("it shouldn't happen\n");
break;
@ -474,6 +490,7 @@ static int svc_normal_to_secure_thread(void *data)
* doesn't support RSU notify or retry
*/
if ((pdata->command == COMMAND_RSU_RETRY) ||
(pdata->command == COMMAND_RSU_MAX_RETRY) ||
(pdata->command == COMMAND_RSU_NOTIFY)) {
cbdata->status =
BIT(SVC_STATUS_NO_SUPPORT);

View File

@ -16,15 +16,6 @@
#include "dfl-afu.h"
static void put_all_pages(struct page **pages, int npages)
{
int i;
for (i = 0; i < npages; i++)
if (pages[i])
put_page(pages[i]);
}
void afu_dma_region_init(struct dfl_feature_platform_data *pdata)
{
struct dfl_afu *afu = dfl_fpga_pdata_get_private(pdata);
@ -57,22 +48,22 @@ static int afu_dma_pin_pages(struct dfl_feature_platform_data *pdata,
goto unlock_vm;
}
pinned = get_user_pages_fast(region->user_addr, npages, FOLL_WRITE,
pinned = pin_user_pages_fast(region->user_addr, npages, FOLL_WRITE,
region->pages);
if (pinned < 0) {
ret = pinned;
goto free_pages;
} else if (pinned != npages) {
ret = -EFAULT;
goto put_pages;
goto unpin_pages;
}
dev_dbg(dev, "%d pages pinned\n", pinned);
return 0;
put_pages:
put_all_pages(region->pages, pinned);
unpin_pages:
unpin_user_pages(region->pages, pinned);
free_pages:
kfree(region->pages);
unlock_vm:
@ -94,7 +85,7 @@ static void afu_dma_unpin_pages(struct dfl_feature_platform_data *pdata,
long npages = region->length >> PAGE_SHIFT;
struct device *dev = &pdata->dev->dev;
put_all_pages(region->pages, npages);
unpin_user_pages(region->pages, npages);
kfree(region->pages);
account_locked_vm(current->mm, npages, false);

View File

@ -14,6 +14,7 @@
* Mitchel Henry <henry.mitchel@intel.com>
*/
#include <linux/fpga-dfl.h>
#include <linux/uaccess.h>
#include "dfl-afu.h"
@ -219,6 +220,21 @@ static void port_err_uinit(struct platform_device *pdev,
afu_port_err_mask(&pdev->dev, true);
}
static long
port_err_ioctl(struct platform_device *pdev, struct dfl_feature *feature,
unsigned int cmd, unsigned long arg)
{
switch (cmd) {
case DFL_FPGA_PORT_ERR_GET_IRQ_NUM:
return dfl_feature_ioctl_get_num_irqs(pdev, feature, arg);
case DFL_FPGA_PORT_ERR_SET_IRQ:
return dfl_feature_ioctl_set_irq(pdev, feature, arg);
default:
dev_dbg(&pdev->dev, "%x cmd not handled", cmd);
return -ENODEV;
}
}
const struct dfl_feature_id port_err_id_table[] = {
{.id = PORT_FEATURE_ID_ERROR,},
{0,}
@ -227,4 +243,5 @@ const struct dfl_feature_id port_err_id_table[] = {
const struct dfl_feature_ops port_err_ops = {
.init = port_err_init,
.uinit = port_err_uinit,
.ioctl = port_err_ioctl,
};

View File

@ -530,6 +530,30 @@ static const struct dfl_feature_ops port_stp_ops = {
.init = port_stp_init,
};
static long
port_uint_ioctl(struct platform_device *pdev, struct dfl_feature *feature,
unsigned int cmd, unsigned long arg)
{
switch (cmd) {
case DFL_FPGA_PORT_UINT_GET_IRQ_NUM:
return dfl_feature_ioctl_get_num_irqs(pdev, feature, arg);
case DFL_FPGA_PORT_UINT_SET_IRQ:
return dfl_feature_ioctl_set_irq(pdev, feature, arg);
default:
dev_dbg(&pdev->dev, "%x cmd not handled", cmd);
return -ENODEV;
}
}
static const struct dfl_feature_id port_uint_id_table[] = {
{.id = PORT_FEATURE_ID_UINT,},
{0,}
};
static const struct dfl_feature_ops port_uint_ops = {
.ioctl = port_uint_ioctl,
};
static struct dfl_feature_driver port_feature_drvs[] = {
{
.id_table = port_hdr_id_table,
@ -547,6 +571,10 @@ static struct dfl_feature_driver port_feature_drvs[] = {
.id_table = port_stp_id_table,
.ops = &port_stp_ops,
},
{
.id_table = port_uint_id_table,
.ops = &port_uint_ops,
},
{
.ops = NULL,
}
@ -578,6 +606,7 @@ static int afu_release(struct inode *inode, struct file *filp)
{
struct platform_device *pdev = filp->private_data;
struct dfl_feature_platform_data *pdata;
struct dfl_feature *feature;
dev_dbg(&pdev->dev, "Device File Release\n");
@ -587,6 +616,9 @@ static int afu_release(struct inode *inode, struct file *filp)
dfl_feature_dev_use_end(pdata);
if (!dfl_feature_dev_use_count(pdata)) {
dfl_fpga_dev_for_each_feature(pdata, feature)
dfl_fpga_set_irq_triggers(feature, 0,
feature->nr_irqs, NULL);
__port_reset(pdev);
afu_dma_region_destroy(pdata);
}

View File

@ -15,6 +15,7 @@
* Mitchel, Henry <henry.mitchel@intel.com>
*/
#include <linux/fpga-dfl.h>
#include <linux/uaccess.h>
#include "dfl.h"
@ -348,6 +349,22 @@ static void fme_global_err_uinit(struct platform_device *pdev,
fme_err_mask(&pdev->dev, true);
}
static long
fme_global_error_ioctl(struct platform_device *pdev,
struct dfl_feature *feature,
unsigned int cmd, unsigned long arg)
{
switch (cmd) {
case DFL_FPGA_FME_ERR_GET_IRQ_NUM:
return dfl_feature_ioctl_get_num_irqs(pdev, feature, arg);
case DFL_FPGA_FME_ERR_SET_IRQ:
return dfl_feature_ioctl_set_irq(pdev, feature, arg);
default:
dev_dbg(&pdev->dev, "%x cmd not handled", cmd);
return -ENODEV;
}
}
const struct dfl_feature_id fme_global_err_id_table[] = {
{.id = FME_FEATURE_ID_GLOBAL_ERR,},
{0,}
@ -356,4 +373,5 @@ const struct dfl_feature_id fme_global_err_id_table[] = {
const struct dfl_feature_ops fme_global_err_ops = {
.init = fme_global_err_init,
.uinit = fme_global_err_uinit,
.ioctl = fme_global_error_ioctl,
};

View File

@ -620,11 +620,17 @@ static int fme_release(struct inode *inode, struct file *filp)
{
struct dfl_feature_platform_data *pdata = filp->private_data;
struct platform_device *pdev = pdata->dev;
struct dfl_feature *feature;
dev_dbg(&pdev->dev, "Device File Release\n");
mutex_lock(&pdata->lock);
dfl_feature_dev_use_end(pdata);
if (!dfl_feature_dev_use_count(pdata))
dfl_fpga_dev_for_each_feature(pdata, feature)
dfl_fpga_set_irq_triggers(feature, 0,
feature->nr_irqs, NULL);
mutex_unlock(&pdata->lock);
return 0;

View File

@ -39,10 +39,32 @@ static void __iomem *cci_pci_ioremap_bar(struct pci_dev *pcidev, int bar)
return pcim_iomap_table(pcidev)[bar];
}
static int cci_pci_alloc_irq(struct pci_dev *pcidev)
{
int ret, nvec = pci_msix_vec_count(pcidev);
if (nvec <= 0) {
dev_dbg(&pcidev->dev, "fpga interrupt not supported\n");
return 0;
}
ret = pci_alloc_irq_vectors(pcidev, nvec, nvec, PCI_IRQ_MSIX);
if (ret < 0)
return ret;
return nvec;
}
static void cci_pci_free_irq(struct pci_dev *pcidev)
{
pci_free_irq_vectors(pcidev);
}
/* PCI Device ID */
#define PCIE_DEVICE_ID_PF_INT_5_X 0xBCBD
#define PCIE_DEVICE_ID_PF_INT_6_X 0xBCC0
#define PCIE_DEVICE_ID_PF_DSC_1_X 0x09C4
#define PCIE_DEVICE_ID_INTEL_PAC_N3000 0x0B30
/* VF Device */
#define PCIE_DEVICE_ID_VF_INT_5_X 0xBCBF
#define PCIE_DEVICE_ID_VF_INT_6_X 0xBCC1
@ -55,6 +77,7 @@ static struct pci_device_id cci_pcie_id_tbl[] = {
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_VF_INT_6_X),},
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_PF_DSC_1_X),},
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_VF_DSC_1_X),},
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCIE_DEVICE_ID_INTEL_PAC_N3000),},
{0,}
};
MODULE_DEVICE_TABLE(pci, cci_pcie_id_tbl);
@ -78,17 +101,34 @@ static void cci_remove_feature_devs(struct pci_dev *pcidev)
/* remove all children feature devices */
dfl_fpga_feature_devs_remove(drvdata->cdev);
cci_pci_free_irq(pcidev);
}
static int *cci_pci_create_irq_table(struct pci_dev *pcidev, unsigned int nvec)
{
unsigned int i;
int *table;
table = kcalloc(nvec, sizeof(int), GFP_KERNEL);
if (!table)
return table;
for (i = 0; i < nvec; i++)
table[i] = pci_irq_vector(pcidev, i);
return table;
}
/* enumerate feature devices under pci device */
static int cci_enumerate_feature_devs(struct pci_dev *pcidev)
{
struct cci_drvdata *drvdata = pci_get_drvdata(pcidev);
int port_num, bar, i, nvec, ret = 0;
struct dfl_fpga_enum_info *info;
struct dfl_fpga_cdev *cdev;
resource_size_t start, len;
int port_num, bar, i, ret = 0;
void __iomem *base;
int *irq_table;
u32 offset;
u64 v;
@ -97,11 +137,30 @@ static int cci_enumerate_feature_devs(struct pci_dev *pcidev)
if (!info)
return -ENOMEM;
/* add irq info for enumeration if the device support irq */
nvec = cci_pci_alloc_irq(pcidev);
if (nvec < 0) {
dev_err(&pcidev->dev, "Fail to alloc irq %d.\n", nvec);
ret = nvec;
goto enum_info_free_exit;
} else if (nvec) {
irq_table = cci_pci_create_irq_table(pcidev, nvec);
if (!irq_table) {
ret = -ENOMEM;
goto irq_free_exit;
}
ret = dfl_fpga_enum_info_add_irq(info, nvec, irq_table);
kfree(irq_table);
if (ret)
goto irq_free_exit;
}
/* start to find Device Feature List from Bar 0 */
base = cci_pci_ioremap_bar(pcidev, 0);
if (!base) {
ret = -ENOMEM;
goto enum_info_free_exit;
goto irq_free_exit;
}
/*
@ -154,7 +213,7 @@ static int cci_enumerate_feature_devs(struct pci_dev *pcidev)
dfl_fpga_enum_info_add_dfl(info, start, len, base);
} else {
ret = -ENODEV;
goto enum_info_free_exit;
goto irq_free_exit;
}
/* start enumeration with prepared enumeration information */
@ -162,11 +221,14 @@ static int cci_enumerate_feature_devs(struct pci_dev *pcidev)
if (IS_ERR(cdev)) {
dev_err(&pcidev->dev, "Enumeration failure\n");
ret = PTR_ERR(cdev);
goto enum_info_free_exit;
goto irq_free_exit;
}
drvdata->cdev = cdev;
irq_free_exit:
if (ret)
cci_pci_free_irq(pcidev);
enum_info_free_exit:
dfl_fpga_enum_info_free(info);
@ -211,12 +273,10 @@ int cci_pci_probe(struct pci_dev *pcidev, const struct pci_device_id *pcidevid)
}
ret = cci_enumerate_feature_devs(pcidev);
if (ret) {
dev_err(&pcidev->dev, "enumeration failure %d.\n", ret);
goto disable_error_report_exit;
}
if (!ret)
return ret;
return ret;
dev_err(&pcidev->dev, "enumeration failure %d.\n", ret);
disable_error_report_exit:
pci_disable_pcie_error_reporting(pcidev);

View File

@ -10,7 +10,9 @@
* Wu Hao <hao.wu@intel.com>
* Xiao Guangrong <guangrong.xiao@linux.intel.com>
*/
#include <linux/fpga-dfl.h>
#include <linux/module.h>
#include <linux/uaccess.h>
#include "dfl.h"
@ -421,6 +423,9 @@ EXPORT_SYMBOL_GPL(dfl_fpga_dev_ops_unregister);
*
* @dev: device to enumerate.
* @cdev: the container device for all feature devices.
* @nr_irqs: number of irqs for all feature devices.
* @irq_table: Linux IRQ numbers for all irqs, indexed by local irq index of
* this device.
* @feature_dev: current feature device.
* @ioaddr: header register region address of feature device in enumeration.
* @sub_features: a sub features linked list for feature device in enumeration.
@ -429,6 +434,9 @@ EXPORT_SYMBOL_GPL(dfl_fpga_dev_ops_unregister);
struct build_feature_devs_info {
struct device *dev;
struct dfl_fpga_cdev *cdev;
unsigned int nr_irqs;
int *irq_table;
struct platform_device *feature_dev;
void __iomem *ioaddr;
struct list_head sub_features;
@ -442,12 +450,16 @@ struct build_feature_devs_info {
* @mmio_res: mmio resource of this sub feature.
* @ioaddr: mapped base address of mmio resource.
* @node: node in sub_features linked list.
* @irq_base: start of irq index in this sub feature.
* @nr_irqs: number of irqs of this sub feature.
*/
struct dfl_feature_info {
u64 fid;
struct resource mmio_res;
void __iomem *ioaddr;
struct list_head node;
unsigned int irq_base;
unsigned int nr_irqs;
};
static void dfl_fpga_cdev_add_port_dev(struct dfl_fpga_cdev *cdev,
@ -487,8 +499,7 @@ static int build_info_commit_dev(struct build_feature_devs_info *binfo)
* it will be automatically freed by device's release() callback,
* platform_device_release().
*/
pdata = kzalloc(dfl_feature_platform_data_size(binfo->feature_num),
GFP_KERNEL);
pdata = kzalloc(struct_size(pdata, features, binfo->feature_num), GFP_KERNEL);
if (!pdata)
return -ENOMEM;
@ -520,13 +531,30 @@ static int build_info_commit_dev(struct build_feature_devs_info *binfo)
/* fill features and resource information for feature dev */
list_for_each_entry_safe(finfo, p, &binfo->sub_features, node) {
struct dfl_feature *feature = &pdata->features[index];
struct dfl_feature_irq_ctx *ctx;
unsigned int i;
/* save resource information for each feature */
feature->dev = fdev;
feature->id = finfo->fid;
feature->resource_index = index;
feature->ioaddr = finfo->ioaddr;
fdev->resource[index++] = finfo->mmio_res;
if (finfo->nr_irqs) {
ctx = devm_kcalloc(binfo->dev, finfo->nr_irqs,
sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return -ENOMEM;
for (i = 0; i < finfo->nr_irqs; i++)
ctx[i].irq =
binfo->irq_table[finfo->irq_base + i];
feature->irq_ctx = ctx;
feature->nr_irqs = finfo->nr_irqs;
}
list_del(&finfo->node);
kfree(finfo);
}
@ -638,6 +666,78 @@ static u64 feature_id(void __iomem *start)
return 0;
}
static int parse_feature_irqs(struct build_feature_devs_info *binfo,
resource_size_t ofst, u64 fid,
unsigned int *irq_base, unsigned int *nr_irqs)
{
void __iomem *base = binfo->ioaddr + ofst;
unsigned int i, ibase, inr = 0;
int virq;
u64 v;
/*
* Ideally DFL framework should only read info from DFL header, but
* current version DFL only provides mmio resources information for
* each feature in DFL Header, no field for interrupt resources.
* Interrupt resource information is provided by specific mmio
* registers of each private feature which supports interrupt. So in
* order to parse and assign irq resources, DFL framework has to look
* into specific capability registers of these private features.
*
* Once future DFL version supports generic interrupt resource
* information in common DFL headers, the generic interrupt parsing
* code will be added. But in order to be compatible to old version
* DFL, the driver may still fall back to these quirks.
*/
switch (fid) {
case PORT_FEATURE_ID_UINT:
v = readq(base + PORT_UINT_CAP);
ibase = FIELD_GET(PORT_UINT_CAP_FST_VECT, v);
inr = FIELD_GET(PORT_UINT_CAP_INT_NUM, v);
break;
case PORT_FEATURE_ID_ERROR:
v = readq(base + PORT_ERROR_CAP);
ibase = FIELD_GET(PORT_ERROR_CAP_INT_VECT, v);
inr = FIELD_GET(PORT_ERROR_CAP_SUPP_INT, v);
break;
case FME_FEATURE_ID_GLOBAL_ERR:
v = readq(base + FME_ERROR_CAP);
ibase = FIELD_GET(FME_ERROR_CAP_INT_VECT, v);
inr = FIELD_GET(FME_ERROR_CAP_SUPP_INT, v);
break;
}
if (!inr) {
*irq_base = 0;
*nr_irqs = 0;
return 0;
}
dev_dbg(binfo->dev, "feature: 0x%llx, irq_base: %u, nr_irqs: %u\n",
fid, ibase, inr);
if (ibase + inr > binfo->nr_irqs) {
dev_err(binfo->dev,
"Invalid interrupt number in feature 0x%llx\n", fid);
return -EINVAL;
}
for (i = 0; i < inr; i++) {
virq = binfo->irq_table[ibase + i];
if (virq < 0 || virq > NR_IRQS) {
dev_err(binfo->dev,
"Invalid irq table entry for feature 0x%llx\n",
fid);
return -EINVAL;
}
}
*irq_base = ibase;
*nr_irqs = inr;
return 0;
}
/*
* when create sub feature instances, for private features, it doesn't need
* to provide resource size and feature id as they could be read from DFH
@ -650,7 +750,9 @@ create_feature_instance(struct build_feature_devs_info *binfo,
struct dfl_fpga_enum_dfl *dfl, resource_size_t ofst,
resource_size_t size, u64 fid)
{
unsigned int irq_base, nr_irqs;
struct dfl_feature_info *finfo;
int ret;
/* read feature size and id if inputs are invalid */
size = size ? size : feature_size(dfl->ioaddr + ofst);
@ -659,6 +761,10 @@ create_feature_instance(struct build_feature_devs_info *binfo,
if (dfl->len - ofst < size)
return -EINVAL;
ret = parse_feature_irqs(binfo, ofst, fid, &irq_base, &nr_irqs);
if (ret)
return ret;
finfo = kzalloc(sizeof(*finfo), GFP_KERNEL);
if (!finfo)
return -ENOMEM;
@ -667,6 +773,8 @@ create_feature_instance(struct build_feature_devs_info *binfo,
finfo->mmio_res.start = dfl->start + ofst;
finfo->mmio_res.end = finfo->mmio_res.start + size - 1;
finfo->mmio_res.flags = IORESOURCE_MEM;
finfo->irq_base = irq_base;
finfo->nr_irqs = nr_irqs;
finfo->ioaddr = dfl->ioaddr + ofst;
list_add_tail(&finfo->node, &binfo->sub_features);
@ -853,6 +961,10 @@ void dfl_fpga_enum_info_free(struct dfl_fpga_enum_info *info)
devm_kfree(dev, dfl);
}
/* remove irq table */
if (info->irq_table)
devm_kfree(dev, info->irq_table);
devm_kfree(dev, info);
put_device(dev);
}
@ -892,6 +1004,45 @@ int dfl_fpga_enum_info_add_dfl(struct dfl_fpga_enum_info *info,
}
EXPORT_SYMBOL_GPL(dfl_fpga_enum_info_add_dfl);
/**
* dfl_fpga_enum_info_add_irq - add irq table to enum info
*
* @info: ptr to dfl_fpga_enum_info
* @nr_irqs: number of irqs of the DFL fpga device to be enumerated.
* @irq_table: Linux IRQ numbers for all irqs, indexed by local irq index of
* this device.
*
* One FPGA device may have several interrupts. This function adds irq
* information of the DFL fpga device to enum info for next step enumeration.
* This function should be called before dfl_fpga_feature_devs_enumerate().
* As we only support one irq domain for all DFLs in the same enum info, adding
* irq table a second time for the same enum info will return error.
*
* If we need to enumerate DFLs which belong to different irq domains, we
* should fill more enum info and enumerate them one by one.
*
* Return: 0 on success, negative error code otherwise.
*/
int dfl_fpga_enum_info_add_irq(struct dfl_fpga_enum_info *info,
unsigned int nr_irqs, int *irq_table)
{
if (!nr_irqs || !irq_table)
return -EINVAL;
if (info->irq_table)
return -EEXIST;
info->irq_table = devm_kmemdup(info->dev, irq_table,
sizeof(int) * nr_irqs, GFP_KERNEL);
if (!info->irq_table)
return -ENOMEM;
info->nr_irqs = nr_irqs;
return 0;
}
EXPORT_SYMBOL_GPL(dfl_fpga_enum_info_add_irq);
static int remove_feature_dev(struct device *dev, void *data)
{
struct platform_device *pdev = to_platform_device(dev);
@ -959,6 +1110,10 @@ dfl_fpga_feature_devs_enumerate(struct dfl_fpga_enum_info *info)
binfo->dev = info->dev;
binfo->cdev = cdev;
binfo->nr_irqs = info->nr_irqs;
if (info->nr_irqs)
binfo->irq_table = info->irq_table;
/*
* start enumeration for all feature devices based on Device Feature
* Lists.
@ -1241,6 +1396,160 @@ done:
}
EXPORT_SYMBOL_GPL(dfl_fpga_cdev_config_ports_vf);
static irqreturn_t dfl_irq_handler(int irq, void *arg)
{
struct eventfd_ctx *trigger = arg;
eventfd_signal(trigger, 1);
return IRQ_HANDLED;
}
static int do_set_irq_trigger(struct dfl_feature *feature, unsigned int idx,
int fd)
{
struct platform_device *pdev = feature->dev;
struct eventfd_ctx *trigger;
int irq, ret;
irq = feature->irq_ctx[idx].irq;
if (feature->irq_ctx[idx].trigger) {
free_irq(irq, feature->irq_ctx[idx].trigger);
kfree(feature->irq_ctx[idx].name);
eventfd_ctx_put(feature->irq_ctx[idx].trigger);
feature->irq_ctx[idx].trigger = NULL;
}
if (fd < 0)
return 0;
feature->irq_ctx[idx].name =
kasprintf(GFP_KERNEL, "fpga-irq[%u](%s-%llx)", idx,
dev_name(&pdev->dev), feature->id);
if (!feature->irq_ctx[idx].name)
return -ENOMEM;
trigger = eventfd_ctx_fdget(fd);
if (IS_ERR(trigger)) {
ret = PTR_ERR(trigger);
goto free_name;
}
ret = request_irq(irq, dfl_irq_handler, 0,
feature->irq_ctx[idx].name, trigger);
if (!ret) {
feature->irq_ctx[idx].trigger = trigger;
return ret;
}
eventfd_ctx_put(trigger);
free_name:
kfree(feature->irq_ctx[idx].name);
return ret;
}
/**
* dfl_fpga_set_irq_triggers - set eventfd triggers for dfl feature interrupts
*
* @feature: dfl sub feature.
* @start: start of irq index in this dfl sub feature.
* @count: number of irqs.
* @fds: eventfds to bind with irqs. unbind related irq if fds[n] is negative.
* unbind "count" specified number of irqs if fds ptr is NULL.
*
* Bind given eventfds with irqs in this dfl sub feature. Unbind related irq if
* fds[n] is negative. Unbind "count" specified number of irqs if fds ptr is
* NULL.
*
* Return: 0 on success, negative error code otherwise.
*/
int dfl_fpga_set_irq_triggers(struct dfl_feature *feature, unsigned int start,
unsigned int count, int32_t *fds)
{
unsigned int i;
int ret = 0;
/* overflow */
if (unlikely(start + count < start))
return -EINVAL;
/* exceeds nr_irqs */
if (start + count > feature->nr_irqs)
return -EINVAL;
for (i = 0; i < count; i++) {
int fd = fds ? fds[i] : -1;
ret = do_set_irq_trigger(feature, start + i, fd);
if (ret) {
while (i--)
do_set_irq_trigger(feature, start + i, -1);
break;
}
}
return ret;
}
EXPORT_SYMBOL_GPL(dfl_fpga_set_irq_triggers);
/**
* dfl_feature_ioctl_get_num_irqs - dfl feature _GET_IRQ_NUM ioctl interface.
* @pdev: the feature device which has the sub feature
* @feature: the dfl sub feature
* @arg: ioctl argument
*
* Return: 0 on success, negative error code otherwise.
*/
long dfl_feature_ioctl_get_num_irqs(struct platform_device *pdev,
struct dfl_feature *feature,
unsigned long arg)
{
return put_user(feature->nr_irqs, (__u32 __user *)arg);
}
EXPORT_SYMBOL_GPL(dfl_feature_ioctl_get_num_irqs);
/**
* dfl_feature_ioctl_set_irq - dfl feature _SET_IRQ ioctl interface.
* @pdev: the feature device which has the sub feature
* @feature: the dfl sub feature
* @arg: ioctl argument
*
* Return: 0 on success, negative error code otherwise.
*/
long dfl_feature_ioctl_set_irq(struct platform_device *pdev,
struct dfl_feature *feature,
unsigned long arg)
{
struct dfl_feature_platform_data *pdata = dev_get_platdata(&pdev->dev);
struct dfl_fpga_irq_set hdr;
s32 *fds;
long ret;
if (!feature->nr_irqs)
return -ENOENT;
if (copy_from_user(&hdr, (void __user *)arg, sizeof(hdr)))
return -EFAULT;
if (!hdr.count || (hdr.start + hdr.count > feature->nr_irqs) ||
(hdr.start + hdr.count < hdr.start))
return -EINVAL;
fds = memdup_user((void __user *)(arg + sizeof(hdr)),
hdr.count * sizeof(s32));
if (IS_ERR(fds))
return PTR_ERR(fds);
mutex_lock(&pdata->lock);
ret = dfl_fpga_set_irq_triggers(feature, hdr.start, hdr.count, fds);
mutex_unlock(&pdata->lock);
kfree(fds);
return ret;
}
EXPORT_SYMBOL_GPL(dfl_feature_ioctl_set_irq);
static void __exit dfl_fpga_exit(void)
{
dfl_chardev_uinit();

View File

@ -17,7 +17,9 @@
#include <linux/bitfield.h>
#include <linux/cdev.h>
#include <linux/delay.h>
#include <linux/eventfd.h>
#include <linux/fs.h>
#include <linux/interrupt.h>
#include <linux/iopoll.h>
#include <linux/io-64-nonatomic-lo-hi.h>
#include <linux/platform_device.h>
@ -112,6 +114,13 @@
#define FME_PORT_OFST_ACC_VF 1
#define FME_PORT_OFST_IMP BIT_ULL(60)
/* FME Error Capability Register */
#define FME_ERROR_CAP 0x70
/* FME Error Capability Register Bitfield */
#define FME_ERROR_CAP_SUPP_INT BIT_ULL(0) /* Interrupt Support */
#define FME_ERROR_CAP_INT_VECT GENMASK_ULL(12, 1) /* Interrupt vector */
/* PORT Header Register Set */
#define PORT_HDR_DFH DFH
#define PORT_HDR_GUID_L GUID_L
@ -145,6 +154,20 @@
#define PORT_STS_PWR_STATE_AP2 2 /* 90% throttling */
#define PORT_STS_PWR_STATE_AP6 6 /* 100% throttling */
/* Port Error Capability Register */
#define PORT_ERROR_CAP 0x38
/* Port Error Capability Register Bitfield */
#define PORT_ERROR_CAP_SUPP_INT BIT_ULL(0) /* Interrupt Support */
#define PORT_ERROR_CAP_INT_VECT GENMASK_ULL(12, 1) /* Interrupt vector */
/* Port Uint Capability Register */
#define PORT_UINT_CAP 0x8
/* Port Uint Capability Register Bitfield */
#define PORT_UINT_CAP_INT_NUM GENMASK_ULL(11, 0) /* Interrupts num */
#define PORT_UINT_CAP_FST_VECT GENMASK_ULL(23, 12) /* First Vector */
/**
* struct dfl_fpga_port_ops - port ops
*
@ -188,21 +211,40 @@ struct dfl_feature_driver {
const struct dfl_feature_ops *ops;
};
/**
* struct dfl_feature_irq_ctx - dfl private feature interrupt context
*
* @irq: Linux IRQ number of this interrupt.
* @trigger: eventfd context to signal when interrupt happens.
* @name: irq name needed when requesting irq.
*/
struct dfl_feature_irq_ctx {
int irq;
struct eventfd_ctx *trigger;
char *name;
};
/**
* struct dfl_feature - sub feature of the feature devices
*
* @dev: ptr to pdev of the feature device which has the sub feature.
* @id: sub feature id.
* @resource_index: each sub feature has one mmio resource for its registers.
* this index is used to find its mmio resource from the
* feature dev (platform device)'s reources.
* @ioaddr: mapped mmio resource address.
* @irq_ctx: interrupt context list.
* @nr_irqs: number of interrupt contexts.
* @ops: ops of this sub feature.
* @priv: priv data of this feature.
*/
struct dfl_feature {
struct platform_device *dev;
u64 id;
int resource_index;
void __iomem *ioaddr;
struct dfl_feature_irq_ctx *irq_ctx;
unsigned int nr_irqs;
const struct dfl_feature_ops *ops;
void *priv;
};
@ -299,12 +341,6 @@ struct dfl_feature_ops {
#define DFL_FPGA_FEATURE_DEV_FME "dfl-fme"
#define DFL_FPGA_FEATURE_DEV_PORT "dfl-port"
static inline int dfl_feature_platform_data_size(const int num)
{
return sizeof(struct dfl_feature_platform_data) +
num * sizeof(struct dfl_feature);
}
void dfl_fpga_dev_feature_uinit(struct platform_device *pdev);
int dfl_fpga_dev_feature_init(struct platform_device *pdev,
struct dfl_feature_driver *feature_drvs);
@ -390,10 +426,14 @@ static inline u8 dfl_feature_revision(void __iomem *base)
*
* @dev: parent device.
* @dfls: list of device feature lists.
* @nr_irqs: number of irqs for all feature devices.
* @irq_table: Linux IRQ numbers for all irqs, indexed by hw irq numbers.
*/
struct dfl_fpga_enum_info {
struct device *dev;
struct list_head dfls;
unsigned int nr_irqs;
int *irq_table;
};
/**
@ -417,6 +457,8 @@ struct dfl_fpga_enum_info *dfl_fpga_enum_info_alloc(struct device *dev);
int dfl_fpga_enum_info_add_dfl(struct dfl_fpga_enum_info *info,
resource_size_t start, resource_size_t len,
void __iomem *ioaddr);
int dfl_fpga_enum_info_add_irq(struct dfl_fpga_enum_info *info,
unsigned int nr_irqs, int *irq_table);
void dfl_fpga_enum_info_free(struct dfl_fpga_enum_info *info);
/**
@ -468,4 +510,13 @@ int dfl_fpga_cdev_release_port(struct dfl_fpga_cdev *cdev, int port_id);
int dfl_fpga_cdev_assign_port(struct dfl_fpga_cdev *cdev, int port_id);
void dfl_fpga_cdev_config_ports_pf(struct dfl_fpga_cdev *cdev);
int dfl_fpga_cdev_config_ports_vf(struct dfl_fpga_cdev *cdev, int num_vf);
int dfl_fpga_set_irq_triggers(struct dfl_feature *feature, unsigned int start,
unsigned int count, int32_t *fds);
long dfl_feature_ioctl_get_num_irqs(struct platform_device *pdev,
struct dfl_feature *feature,
unsigned long arg);
long dfl_feature_ioctl_set_irq(struct platform_device *pdev,
struct dfl_feature *feature,
unsigned long arg);
#endif /* __FPGA_DFL_H */

View File

@ -328,7 +328,7 @@ struct fpga_bridge *fpga_bridge_create(struct device *dev, const char *name,
void *priv)
{
struct fpga_bridge *bridge;
int id, ret = 0;
int id, ret;
if (!name || !strlen(name)) {
dev_err(dev, "Attempt to register with no name!\n");
@ -340,10 +340,8 @@ struct fpga_bridge *fpga_bridge_create(struct device *dev, const char *name,
return NULL;
id = ida_simple_get(&fpga_bridge_ida, 0, 0, GFP_KERNEL);
if (id < 0) {
ret = id;
if (id < 0)
goto error_kfree;
}
mutex_init(&bridge->mutex);
INIT_LIST_HEAD(&bridge->node);

View File

@ -581,10 +581,8 @@ struct fpga_manager *fpga_mgr_create(struct device *dev, const char *name,
return NULL;
id = ida_simple_get(&fpga_mgr_ida, 0, 0, GFP_KERNEL);
if (id < 0) {
ret = id;
if (id < 0)
goto error_kfree;
}
mutex_init(&mgr->ref_mutex);

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Xilinx Spartan6 Slave Serial SPI Driver
* Xilinx Spartan6 and 7 Series Slave Serial SPI Driver
*
* Copyright (C) 2017 DENX Software Engineering
*
@ -23,6 +23,7 @@
struct xilinx_spi_conf {
struct spi_device *spi;
struct gpio_desc *prog_b;
struct gpio_desc *init_b;
struct gpio_desc *done;
};
@ -36,13 +37,45 @@ static enum fpga_mgr_states xilinx_spi_state(struct fpga_manager *mgr)
return FPGA_MGR_STATE_UNKNOWN;
}
/**
* wait_for_init_b - wait for the INIT_B pin to have a given state, or wait
* a given delay if the pin is unavailable
*
* @mgr: The FPGA manager object
* @value: Value INIT_B to wait for (1 = asserted = low)
* @alt_udelay: Delay to wait if the INIT_B GPIO is not available
*
* Returns 0 when the INIT_B GPIO reached the given state or -ETIMEDOUT if
* too much time passed waiting for that. If no INIT_B GPIO is available
* then always return 0.
*/
static int wait_for_init_b(struct fpga_manager *mgr, int value,
unsigned long alt_udelay)
{
struct xilinx_spi_conf *conf = mgr->priv;
unsigned long timeout = jiffies + msecs_to_jiffies(1000);
if (conf->init_b) {
while (time_before(jiffies, timeout)) {
/* dump_state(conf, "wait for init_d .."); */
if (gpiod_get_value(conf->init_b) == value)
return 0;
usleep_range(100, 400);
}
return -ETIMEDOUT;
}
udelay(alt_udelay);
return 0;
}
static int xilinx_spi_write_init(struct fpga_manager *mgr,
struct fpga_image_info *info,
const char *buf, size_t count)
{
struct xilinx_spi_conf *conf = mgr->priv;
const size_t prog_latency_7500us = 7500;
const size_t prog_pulse_1us = 1;
int err;
if (info->flags & FPGA_MGR_PARTIAL_RECONFIG) {
dev_err(&mgr->dev, "Partial reconfiguration not supported.\n");
@ -51,17 +84,28 @@ static int xilinx_spi_write_init(struct fpga_manager *mgr,
gpiod_set_value(conf->prog_b, 1);
udelay(prog_pulse_1us); /* min is 500 ns */
err = wait_for_init_b(mgr, 1, 1); /* min is 500 ns */
if (err) {
dev_err(&mgr->dev, "INIT_B pin did not go low\n");
gpiod_set_value(conf->prog_b, 0);
return err;
}
gpiod_set_value(conf->prog_b, 0);
err = wait_for_init_b(mgr, 0, 0);
if (err) {
dev_err(&mgr->dev, "INIT_B pin did not go high\n");
return err;
}
if (gpiod_get_value(conf->done)) {
dev_err(&mgr->dev, "Unexpected DONE pin state...\n");
return -EIO;
}
/* program latency */
usleep_range(prog_latency_7500us, prog_latency_7500us + 100);
usleep_range(7500, 7600);
return 0;
}
@ -156,6 +200,13 @@ static int xilinx_spi_probe(struct spi_device *spi)
return PTR_ERR(conf->prog_b);
}
conf->init_b = devm_gpiod_get_optional(&spi->dev, "init-b", GPIOD_IN);
if (IS_ERR(conf->init_b)) {
dev_err(&spi->dev, "Failed to get INIT_B gpio: %ld\n",
PTR_ERR(conf->init_b));
return PTR_ERR(conf->init_b);
}
conf->done = devm_gpiod_get(&spi->dev, "done", GPIOD_IN);
if (IS_ERR(conf->done)) {
dev_err(&spi->dev, "Failed to get DONE gpio: %ld\n",

View File

@ -759,7 +759,7 @@ static int check_urb_status(struct urb *urb)
case -EOVERFLOW:
dev_err(dev, "%s: overflow actual length is %d\n",
__func__, urb->actual_length);
/* fall through */
fallthrough;
case -ECONNRESET:
case -ENOENT:
case -ESHUTDOWN:

View File

@ -1233,7 +1233,7 @@ int gb_interface_add(struct gb_interface *intf)
case GB_INTERFACE_TYPE_GREYBUS:
dev_info(&intf->dev, "GMP VID=0x%08x, PID=0x%08x\n",
intf->vendor_id, intf->product_id);
/* fall-through */
fallthrough;
case GB_INTERFACE_TYPE_UNIPRO:
dev_info(&intf->dev, "DDBL1 Manufacturer=0x%08x, Product=0x%08x\n",
intf->ddbl1_manufacturer_id,

View File

@ -568,10 +568,7 @@ out:
}
static struct amba_id catu_ids[] = {
{
.id = 0x000bb9ee,
.mask = 0x000fffff,
},
CS_AMBA_ID(0x000bb9ee),
{},
};

View File

@ -226,9 +226,6 @@ static void *etm_setup_aux(struct perf_event *event, void **pages,
sink = coresight_get_enabled_sink(true);
}
if (!sink)
goto err;
mask = &event_data->mask;
/*
@ -253,6 +250,16 @@ static void *etm_setup_aux(struct perf_event *event, void **pages,
continue;
}
/*
* No sink provided - look for a default sink for one of the
* devices. At present we only support topology where all CPUs
* use the same sink [N:1], so only need to find one sink. The
* coresight_build_path later will remove any CPU that does not
* attach to the sink, or if we have not found a sink.
*/
if (!sink)
sink = coresight_find_default_sink(csdev);
/*
* Building a path doesn't enable it, it simply builds a
* list of devices from source to sink that can be
@ -267,6 +274,10 @@ static void *etm_setup_aux(struct perf_event *event, void **pages,
*etm_event_cpu_path_ptr(event_data, cpu) = path;
}
/* no sink found for any CPU - cannot trace */
if (!sink)
goto err;
/* If we don't have any CPUs ready for tracing, abort */
cpu = cpumask_first(mask);
if (cpu >= nr_cpu_ids)

View File

@ -196,12 +196,14 @@ static int etm4_enable_hw(struct etmv4_drvdata *drvdata)
writel_relaxed(config->vmid_mask0, drvdata->base + TRCVMIDCCTLR0);
writel_relaxed(config->vmid_mask1, drvdata->base + TRCVMIDCCTLR1);
/*
* Request to keep the trace unit powered and also
* emulation of powerdown
*/
writel_relaxed(readl_relaxed(drvdata->base + TRCPDCR) | TRCPDCR_PU,
drvdata->base + TRCPDCR);
if (!drvdata->skip_power_up) {
/*
* Request to keep the trace unit powered and also
* emulation of powerdown
*/
writel_relaxed(readl_relaxed(drvdata->base + TRCPDCR) |
TRCPDCR_PU, drvdata->base + TRCPDCR);
}
/* Enable the trace unit */
writel_relaxed(1, drvdata->base + TRCPRGCTLR);
@ -476,10 +478,12 @@ static void etm4_disable_hw(void *info)
CS_UNLOCK(drvdata->base);
/* power can be removed from the trace unit now */
control = readl_relaxed(drvdata->base + TRCPDCR);
control &= ~TRCPDCR_PU;
writel_relaxed(control, drvdata->base + TRCPDCR);
if (!drvdata->skip_power_up) {
/* power can be removed from the trace unit now */
control = readl_relaxed(drvdata->base + TRCPDCR);
control &= ~TRCPDCR_PU;
writel_relaxed(control, drvdata->base + TRCPDCR);
}
control = readl_relaxed(drvdata->base + TRCPRGCTLR);
@ -507,6 +511,12 @@ static void etm4_disable_hw(void *info)
readl_relaxed(drvdata->base + TRCSSCSRn(i));
}
/* read back the current counter values */
for (i = 0; i < drvdata->nr_cntr; i++) {
config->cntr_val[i] =
readl_relaxed(drvdata->base + TRCCNTVRn(i));
}
coresight_disclaim_device_unlocked(drvdata->base);
CS_LOCK(drvdata->base);
@ -1196,8 +1206,8 @@ static int etm4_cpu_save(struct etmv4_drvdata *drvdata)
}
for (i = 0; i < drvdata->nr_addr_cmp * 2; i++) {
state->trcacvr[i] = readl(drvdata->base + TRCACVRn(i));
state->trcacatr[i] = readl(drvdata->base + TRCACATRn(i));
state->trcacvr[i] = readq(drvdata->base + TRCACVRn(i));
state->trcacatr[i] = readq(drvdata->base + TRCACATRn(i));
}
/*
@ -1208,10 +1218,10 @@ static int etm4_cpu_save(struct etmv4_drvdata *drvdata)
*/
for (i = 0; i < drvdata->numcidc; i++)
state->trccidcvr[i] = readl(drvdata->base + TRCCIDCVRn(i));
state->trccidcvr[i] = readq(drvdata->base + TRCCIDCVRn(i));
for (i = 0; i < drvdata->numvmidc; i++)
state->trcvmidcvr[i] = readl(drvdata->base + TRCVMIDCVRn(i));
state->trcvmidcvr[i] = readq(drvdata->base + TRCVMIDCVRn(i));
state->trccidcctlr0 = readl(drvdata->base + TRCCIDCCTLR0);
state->trccidcctlr1 = readl(drvdata->base + TRCCIDCCTLR1);
@ -1309,18 +1319,18 @@ static void etm4_cpu_restore(struct etmv4_drvdata *drvdata)
}
for (i = 0; i < drvdata->nr_addr_cmp * 2; i++) {
writel_relaxed(state->trcacvr[i],
writeq_relaxed(state->trcacvr[i],
drvdata->base + TRCACVRn(i));
writel_relaxed(state->trcacatr[i],
writeq_relaxed(state->trcacatr[i],
drvdata->base + TRCACATRn(i));
}
for (i = 0; i < drvdata->numcidc; i++)
writel_relaxed(state->trccidcvr[i],
writeq_relaxed(state->trccidcvr[i],
drvdata->base + TRCCIDCVRn(i));
for (i = 0; i < drvdata->numvmidc; i++)
writel_relaxed(state->trcvmidcvr[i],
writeq_relaxed(state->trcvmidcvr[i],
drvdata->base + TRCVMIDCVRn(i));
writel_relaxed(state->trccidcctlr0, drvdata->base + TRCCIDCCTLR0);
@ -1468,6 +1478,9 @@ static int etm4_probe(struct amba_device *adev, const struct amba_id *id)
return -ENOMEM;
}
if (fwnode_property_present(dev_fwnode(dev), "qcom,skip-power-up"))
drvdata->skip_power_up = true;
/* Validity for the resource is already checked by the AMBA core */
base = devm_ioremap_resource(dev, res);
if (IS_ERR(base))

View File

@ -133,7 +133,7 @@
#define ETMv4_MAX_CTXID_CMP 8
#define ETM_MAX_VMID_CMP 8
#define ETM_MAX_PE_CMP 8
#define ETM_MAX_RES_SEL 16
#define ETM_MAX_RES_SEL 32
#define ETM_MAX_SS_CMP 8
#define ETM_ARCH_V4 0x40
@ -325,7 +325,7 @@ struct etmv4_save_state {
u32 trccntctlr[ETMv4_MAX_CNTR];
u32 trccntvr[ETMv4_MAX_CNTR];
u32 trcrsctlr[ETM_MAX_RES_SEL * 2];
u32 trcrsctlr[ETM_MAX_RES_SEL];
u32 trcssccr[ETM_MAX_SS_CMP];
u32 trcsscsr[ETM_MAX_SS_CMP];
@ -334,7 +334,7 @@ struct etmv4_save_state {
u64 trcacvr[ETM_MAX_SINGLE_ADDR_CMP];
u64 trcacatr[ETM_MAX_SINGLE_ADDR_CMP];
u64 trccidcvr[ETMv4_MAX_CTXID_CMP];
u32 trcvmidcvr[ETM_MAX_VMID_CMP];
u64 trcvmidcvr[ETM_MAX_VMID_CMP];
u32 trccidcctlr0;
u32 trccidcctlr1;
u32 trcvmidcctlr0;
@ -407,6 +407,8 @@ struct etmv4_save_state {
* @config: structure holding configuration parameters.
* @save_state: State to be preserved across power loss
* @state_needs_restore: True when there is context to restore after PM exit
* @skip_power_up: Indicates if an implementation can skip powering up
* the trace unit.
*/
struct etmv4_drvdata {
void __iomem *base;
@ -454,6 +456,7 @@ struct etmv4_drvdata {
struct etmv4_config config;
struct etmv4_save_state *save_state;
bool state_needs_restore;
bool skip_power_up;
};
/* Address comparator access types */

View File

@ -27,9 +27,8 @@ static int coresight_alloc_conns(struct device *dev,
struct coresight_platform_data *pdata)
{
if (pdata->nr_outport) {
pdata->conns = devm_kzalloc(dev, pdata->nr_outport *
sizeof(*pdata->conns),
GFP_KERNEL);
pdata->conns = devm_kcalloc(dev, pdata->nr_outport,
sizeof(*pdata->conns), GFP_KERNEL);
if (!pdata->conns)
return -ENOMEM;
}

View File

@ -150,6 +150,8 @@ int coresight_enable_path(struct list_head *path, u32 mode, void *sink_data);
struct coresight_device *coresight_get_sink(struct list_head *path);
struct coresight_device *coresight_get_enabled_sink(bool reset);
struct coresight_device *coresight_get_sink_by_id(u32 id);
struct coresight_device *
coresight_find_default_sink(struct coresight_device *csdev);
struct list_head *coresight_build_path(struct coresight_device *csdev,
struct coresight_device *sink);
void coresight_release_path(struct list_head *path);

View File

@ -14,6 +14,7 @@
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/pm_runtime.h>
#include <linux/property.h>
#include <linux/clk.h>
#include <linux/of.h>
#include <linux/coresight.h>
@ -32,12 +33,14 @@ DEFINE_CORESIGHT_DEVLIST(replicator_devs, "replicator");
* @atclk: optional clock for the core parts of the replicator.
* @csdev: component vitals needed by the framework
* @spinlock: serialize enable/disable operations.
* @check_idfilter_val: check if the context is lost upon clock removal.
*/
struct replicator_drvdata {
void __iomem *base;
struct clk *atclk;
struct coresight_device *csdev;
spinlock_t spinlock;
bool check_idfilter_val;
};
static void dynamic_replicator_reset(struct replicator_drvdata *drvdata)
@ -66,29 +69,43 @@ static int dynamic_replicator_enable(struct replicator_drvdata *drvdata,
int inport, int outport)
{
int rc = 0;
u32 reg;
switch (outport) {
case 0:
reg = REPLICATOR_IDFILTER0;
break;
case 1:
reg = REPLICATOR_IDFILTER1;
break;
default:
WARN_ON(1);
return -EINVAL;
}
u32 id0val, id1val;
CS_UNLOCK(drvdata->base);
if ((readl_relaxed(drvdata->base + REPLICATOR_IDFILTER0) == 0xff) &&
(readl_relaxed(drvdata->base + REPLICATOR_IDFILTER1) == 0xff))
id0val = readl_relaxed(drvdata->base + REPLICATOR_IDFILTER0);
id1val = readl_relaxed(drvdata->base + REPLICATOR_IDFILTER1);
/*
* Some replicator designs lose context when AMBA clocks are removed,
* so have a check for this.
*/
if (drvdata->check_idfilter_val && id0val == 0x0 && id1val == 0x0)
id0val = id1val = 0xff;
if (id0val == 0xff && id1val == 0xff)
rc = coresight_claim_device_unlocked(drvdata->base);
if (!rc) {
switch (outport) {
case 0:
id0val = 0x0;
break;
case 1:
id1val = 0x0;
break;
default:
WARN_ON(1);
rc = -EINVAL;
}
}
/* Ensure that the outport is enabled. */
if (!rc)
writel_relaxed(0x00, drvdata->base + reg);
if (!rc) {
writel_relaxed(id0val, drvdata->base + REPLICATOR_IDFILTER0);
writel_relaxed(id1val, drvdata->base + REPLICATOR_IDFILTER1);
}
CS_LOCK(drvdata->base);
return rc;
@ -239,6 +256,10 @@ static int replicator_probe(struct device *dev, struct resource *res)
desc.groups = replicator_groups;
}
if (fwnode_property_present(dev_fwnode(dev),
"qcom,replicator-loses-context"))
drvdata->check_idfilter_val = true;
dev_set_drvdata(dev, drvdata);
pdata = coresight_get_platform_data(dev);
@ -348,16 +369,9 @@ static int dynamic_replicator_probe(struct amba_device *adev,
}
static const struct amba_id dynamic_replicator_ids[] = {
{
.id = 0x000bb909,
.mask = 0x000fffff,
},
{
/* Coresight SoC-600 */
.id = 0x000bb9ec,
.mask = 0x000fffff,
},
{ 0, 0 },
CS_AMBA_ID(0x000bb909),
CS_AMBA_ID(0x000bb9ec), /* Coresight SoC-600 */
{},
};
static struct amba_driver dynamic_replicator_driver = {

View File

@ -727,8 +727,6 @@ static int acpi_stm_get_stimulus_area(struct device *dev, struct resource *res)
struct acpi_device *adev = ACPI_COMPANION(dev);
if (!adev)
return -ENODEV;
rc = acpi_dev_get_resources(adev, &res_list, NULL, NULL);
if (rc < 0)
return rc;

View File

@ -639,15 +639,14 @@ int tmc_read_unprepare_etb(struct tmc_drvdata *drvdata)
spin_lock_irqsave(&drvdata->spinlock, flags);
/* There is no point in reading a TMC in HW FIFO mode */
mode = readl_relaxed(drvdata->base + TMC_MODE);
if (mode != TMC_MODE_CIRCULAR_BUFFER) {
spin_unlock_irqrestore(&drvdata->spinlock, flags);
return -EINVAL;
}
/* Re-enable the TMC if need be */
if (drvdata->mode == CS_MODE_SYSFS) {
/* There is no point in reading a TMC in HW FIFO mode */
mode = readl_relaxed(drvdata->base + TMC_MODE);
if (mode != TMC_MODE_CIRCULAR_BUFFER) {
spin_unlock_irqrestore(&drvdata->spinlock, flags);
return -EINVAL;
}
/*
* The trace run will continue with the same allocated trace
* buffer. As such zero-out the buffer so that we don't end

View File

@ -1110,7 +1110,7 @@ static void __tmc_etr_disable_hw(struct tmc_drvdata *drvdata)
}
static void tmc_etr_disable_hw(struct tmc_drvdata *drvdata)
void tmc_etr_disable_hw(struct tmc_drvdata *drvdata)
{
__tmc_etr_disable_hw(drvdata);
/* Disable CATU device if this ETR is connected to one */

View File

@ -484,7 +484,7 @@ static int tmc_probe(struct amba_device *adev, const struct amba_id *id)
break;
case TMC_CONFIG_TYPE_ETR:
desc.type = CORESIGHT_DEV_TYPE_SINK;
desc.subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_BUFFER;
desc.subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_SYSMEM;
desc.ops = &tmc_etr_cs_ops;
ret = tmc_etr_setup_caps(dev, devid,
coresight_get_uci_data(id));
@ -496,6 +496,7 @@ static int tmc_probe(struct amba_device *adev, const struct amba_id *id)
break;
case TMC_CONFIG_TYPE_ETF:
desc.type = CORESIGHT_DEV_TYPE_LINKSINK;
desc.subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_SINK_BUFFER;
desc.subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_FIFO;
desc.ops = &tmc_etf_cs_ops;
dev_list = &etf_devs;
@ -538,6 +539,28 @@ out:
return ret;
}
static void tmc_shutdown(struct amba_device *adev)
{
unsigned long flags;
struct tmc_drvdata *drvdata = amba_get_drvdata(adev);
spin_lock_irqsave(&drvdata->spinlock, flags);
if (drvdata->mode == CS_MODE_DISABLED)
goto out;
if (drvdata->config_type == TMC_CONFIG_TYPE_ETR)
tmc_etr_disable_hw(drvdata);
/*
* We do not care about coresight unregister here unlike remove
* callback which is required for making coresight modular since
* the system is going down after this.
*/
out:
spin_unlock_irqrestore(&drvdata->spinlock, flags);
}
static const struct amba_id tmc_ids[] = {
CS_AMBA_ID(0x000bb961),
/* Coresight SoC 600 TMC-ETR/ETS */
@ -556,6 +579,7 @@ static struct amba_driver tmc_driver = {
.suppress_bind_attrs = true,
},
.probe = tmc_probe,
.shutdown = tmc_shutdown,
.id_table = tmc_ids,
};
builtin_amba_driver(tmc_driver);

View File

@ -268,6 +268,7 @@ ssize_t tmc_etb_get_sysfs_trace(struct tmc_drvdata *drvdata,
/* ETR functions */
int tmc_read_prepare_etr(struct tmc_drvdata *drvdata);
int tmc_read_unprepare_etr(struct tmc_drvdata *drvdata);
void tmc_etr_disable_hw(struct tmc_drvdata *drvdata);
extern const struct coresight_ops tmc_etr_cs_ops;
ssize_t tmc_etr_get_sysfs_trace(struct tmc_drvdata *drvdata,
loff_t pos, size_t len, char **bufpp);

View File

@ -769,6 +769,171 @@ void coresight_release_path(struct list_head *path)
path = NULL;
}
/* return true if the device is a suitable type for a default sink */
static inline bool coresight_is_def_sink_type(struct coresight_device *csdev)
{
/* sink & correct subtype */
if (((csdev->type == CORESIGHT_DEV_TYPE_SINK) ||
(csdev->type == CORESIGHT_DEV_TYPE_LINKSINK)) &&
(csdev->subtype.sink_subtype >= CORESIGHT_DEV_SUBTYPE_SINK_BUFFER))
return true;
return false;
}
/**
* coresight_select_best_sink - return the best sink for use as default from
* the two provided.
*
* @sink: current best sink.
* @depth: search depth where current sink was found.
* @new_sink: new sink for comparison with current sink.
* @new_depth: search depth where new sink was found.
*
* Sinks prioritised according to coresight_dev_subtype_sink, with only
* subtypes CORESIGHT_DEV_SUBTYPE_SINK_BUFFER or higher being used.
*
* Where two sinks of equal priority are found, the sink closest to the
* source is used (smallest search depth).
*
* return @new_sink & update @depth if better than @sink, else return @sink.
*/
static struct coresight_device *
coresight_select_best_sink(struct coresight_device *sink, int *depth,
struct coresight_device *new_sink, int new_depth)
{
bool update = false;
if (!sink) {
/* first found at this level */
update = true;
} else if (new_sink->subtype.sink_subtype >
sink->subtype.sink_subtype) {
/* found better sink */
update = true;
} else if ((new_sink->subtype.sink_subtype ==
sink->subtype.sink_subtype) &&
(*depth > new_depth)) {
/* found same but closer sink */
update = true;
}
if (update)
*depth = new_depth;
return update ? new_sink : sink;
}
/**
* coresight_find_sink - recursive function to walk trace connections from
* source to find a suitable default sink.
*
* @csdev: source / current device to check.
* @depth: [in] search depth of calling dev, [out] depth of found sink.
*
* This will walk the connection path from a source (ETM) till a suitable
* sink is encountered and return that sink to the original caller.
*
* If current device is a plain sink return that & depth, otherwise recursively
* call child connections looking for a sink. Select best possible using
* coresight_select_best_sink.
*
* return best sink found, or NULL if not found at this node or child nodes.
*/
static struct coresight_device *
coresight_find_sink(struct coresight_device *csdev, int *depth)
{
int i, curr_depth = *depth + 1, found_depth = 0;
struct coresight_device *found_sink = NULL;
if (coresight_is_def_sink_type(csdev)) {
found_depth = curr_depth;
found_sink = csdev;
if (csdev->type == CORESIGHT_DEV_TYPE_SINK)
goto return_def_sink;
/* look past LINKSINK for something better */
}
/*
* Not a sink we want - or possible child sink may be better.
* recursively explore each port found on this element.
*/
for (i = 0; i < csdev->pdata->nr_outport; i++) {
struct coresight_device *child_dev, *sink = NULL;
int child_depth = curr_depth;
child_dev = csdev->pdata->conns[i].child_dev;
if (child_dev)
sink = coresight_find_sink(child_dev, &child_depth);
if (sink)
found_sink = coresight_select_best_sink(found_sink,
&found_depth,
sink,
child_depth);
}
return_def_sink:
/* return found sink and depth */
if (found_sink)
*depth = found_depth;
return found_sink;
}
/**
* coresight_find_default_sink: Find a sink suitable for use as a
* default sink.
*
* @csdev: starting source to find a connected sink.
*
* Walks connections graph looking for a suitable sink to enable for the
* supplied source. Uses CoreSight device subtypes and distance from source
* to select the best sink.
*
* If a sink is found, then the default sink for this device is set and
* will be automatically used in future.
*
* Used in cases where the CoreSight user (perf / sysfs) has not selected a
* sink.
*/
struct coresight_device *
coresight_find_default_sink(struct coresight_device *csdev)
{
int depth = 0;
/* look for a default sink if we have not found for this device */
if (!csdev->def_sink)
csdev->def_sink = coresight_find_sink(csdev, &depth);
return csdev->def_sink;
}
static int coresight_remove_sink_ref(struct device *dev, void *data)
{
struct coresight_device *sink = data;
struct coresight_device *source = to_coresight_device(dev);
if (source->def_sink == sink)
source->def_sink = NULL;
return 0;
}
/**
* coresight_clear_default_sink: Remove all default sink references to the
* supplied sink.
*
* If supplied device is a sink, then check all the bus devices and clear
* out all the references to this sink from the coresight_device def_sink
* parameter.
*
* @csdev: coresight sink - remove references to this from all sources.
*/
static void coresight_clear_default_sink(struct coresight_device *csdev)
{
if ((csdev->type == CORESIGHT_DEV_TYPE_SINK) ||
(csdev->type == CORESIGHT_DEV_TYPE_LINKSINK)) {
bus_for_each_dev(&coresight_bustype, NULL, csdev,
coresight_remove_sink_ref);
}
}
/** coresight_validate_source - make sure a source has the right credentials
* @csdev: the device structure for a source.
* @function: the function this was called from.
@ -1358,6 +1523,7 @@ void coresight_unregister(struct coresight_device *csdev)
etm_perf_del_symlink_sink(csdev);
/* Remove references of that device in the topology */
coresight_remove_conns(csdev);
coresight_clear_default_sink(csdev);
coresight_release_platform_data(csdev, csdev->pdata);
device_unregister(&csdev->dev);
}

View File

@ -269,23 +269,22 @@ static int aggregate_requests(struct icc_node *node)
static int apply_constraints(struct icc_path *path)
{
struct icc_node *next, *prev = NULL;
struct icc_provider *p;
int ret = -EINVAL;
int i;
for (i = 0; i < path->num_nodes; i++) {
next = path->reqs[i].node;
p = next->provider;
/*
* Both endpoints should be valid master-slave pairs of the
* same interconnect provider that will be configured.
*/
if (!prev || next->provider != prev->provider) {
/* both endpoints should be valid master-slave pairs */
if (!prev || (p != prev->provider && !p->inter_set)) {
prev = next;
continue;
}
/* set the constraints */
ret = next->provider->set(prev, next);
ret = p->set(prev, next);
if (ret)
goto out;
@ -340,12 +339,12 @@ EXPORT_SYMBOL_GPL(of_icc_xlate_onecell);
* Returns a valid pointer to struct icc_node on success or ERR_PTR()
* on failure.
*/
static struct icc_node *of_icc_get_from_provider(struct of_phandle_args *spec)
struct icc_node *of_icc_get_from_provider(struct of_phandle_args *spec)
{
struct icc_node *node = ERR_PTR(-EPROBE_DEFER);
struct icc_provider *provider;
if (!spec || spec->args_count != 1)
if (!spec)
return ERR_PTR(-EINVAL);
mutex_lock(&icc_lock);
@ -359,6 +358,7 @@ static struct icc_node *of_icc_get_from_provider(struct of_phandle_args *spec)
return node;
}
EXPORT_SYMBOL_GPL(of_icc_get_from_provider);
static void devm_icc_release(struct device *dev, void *res)
{

View File

@ -83,7 +83,7 @@ config IBM_ASM
WARNING: This software may not be supported or function
correctly on your IBM server. Please consult the IBM ServerProven
website <http://www-03.ibm.com/systems/info/x86servers/serverproven/compat/us/>
website <https://www-03.ibm.com/systems/info/x86servers/serverproven/compat/us/>
for information on the specific driver level and support statement
for your IBM server.

View File

@ -923,7 +923,7 @@ struct c2port_device *c2port_device_register(char *name,
}
dev_set_drvdata(c2dev->dev, c2dev);
strncpy(c2dev->name, name, C2PORT_NAME_LEN);
strncpy(c2dev->name, name, C2PORT_NAME_LEN - 1);
c2dev->ops = ops;
mutex_init(&c2dev->mutex);

View File

@ -1,5 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_MISC_ALCOR_PCI) += alcor_pci.o
obj-$(CONFIG_MISC_RTSX_PCI) += rtsx_pci.o
rtsx_pci-objs := rtsx_pcr.o rts5209.o rts5229.o rtl8411.o rts5227.o rts5249.o rts5260.o rts5261.o
rtsx_pci-objs := rtsx_pcr.o rts5209.o rts5229.o rtl8411.o rts5227.o rts5249.o rts5260.o rts5261.o rts5228.o
obj-$(CONFIG_MISC_RTSX_USB) += rtsx_usb.o

View File

@ -37,10 +37,11 @@ static int rtl8411b_is_qfn48(struct rtsx_pcr *pcr)
static void rtl8411_fetch_vendor_settings(struct rtsx_pcr *pcr)
{
struct pci_dev *pdev = pcr->pci;
u32 reg1 = 0;
u8 reg3 = 0;
rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG1, &reg1);
pci_read_config_dword(pdev, PCR_SETTING_REG1, &reg1);
pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG1, reg1);
if (!rtsx_vendor_setting_valid(reg1))
@ -52,16 +53,17 @@ static void rtl8411_fetch_vendor_settings(struct rtsx_pcr *pcr)
pcr->card_drive_sel &= 0x3F;
pcr->card_drive_sel |= rtsx_reg_to_card_drive_sel(reg1);
rtsx_pci_read_config_byte(pcr, PCR_SETTING_REG3, &reg3);
pci_read_config_byte(pdev, PCR_SETTING_REG3, &reg3);
pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG3, reg3);
pcr->sd30_drive_sel_3v3 = rtl8411_reg_to_sd30_drive_sel_3v3(reg3);
}
static void rtl8411b_fetch_vendor_settings(struct rtsx_pcr *pcr)
{
struct pci_dev *pdev = pcr->pci;
u32 reg = 0;
rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG1, &reg);
pci_read_config_dword(pdev, PCR_SETTING_REG1, &reg);
pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG1, reg);
if (!rtsx_vendor_setting_valid(reg))

View File

@ -23,9 +23,10 @@ static u8 rts5209_get_ic_version(struct rtsx_pcr *pcr)
static void rts5209_fetch_vendor_settings(struct rtsx_pcr *pcr)
{
struct pci_dev *pdev = pcr->pci;
u32 reg;
rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG1, &reg);
pci_read_config_dword(pdev, PCR_SETTING_REG1, &reg);
pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG1, reg);
if (rts5209_vendor_setting1_valid(reg)) {
@ -34,7 +35,7 @@ static void rts5209_fetch_vendor_settings(struct rtsx_pcr *pcr)
pcr->aspm_en = rts5209_reg_to_aspm(reg);
}
rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG2, &reg);
pci_read_config_dword(pdev, PCR_SETTING_REG2, &reg);
pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG2, reg);
if (rts5209_vendor_setting2_valid(reg)) {

View File

@ -56,9 +56,10 @@ static void rts5227_fill_driving(struct rtsx_pcr *pcr, u8 voltage)
static void rts5227_fetch_vendor_settings(struct rtsx_pcr *pcr)
{
struct pci_dev *pdev = pcr->pci;
u32 reg;
rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG1, &reg);
pci_read_config_dword(pdev, PCR_SETTING_REG1, &reg);
pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG1, reg);
if (!rtsx_vendor_setting_valid(reg))
@ -69,7 +70,7 @@ static void rts5227_fetch_vendor_settings(struct rtsx_pcr *pcr)
pcr->card_drive_sel &= 0x3F;
pcr->card_drive_sel |= rtsx_reg_to_card_drive_sel(reg);
rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG2, &reg);
pci_read_config_dword(pdev, PCR_SETTING_REG2, &reg);
pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG2, reg);
pcr->sd30_drive_sel_3v3 = rtsx_reg_to_sd30_drive_sel_3v3(reg);
if (rtsx_reg_check_reverse_socket(reg))

View File

@ -0,0 +1,747 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/* Driver for Realtek PCI-Express card reader
*
* Copyright(c) 2018-2019 Realtek Semiconductor Corp. All rights reserved.
*
* Author:
* Ricky WU <ricky_wu@realtek.com>
* Rui FENG <rui_feng@realsil.com.cn>
* Wei WANG <wei_wang@realsil.com.cn>
*/
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/rtsx_pci.h>
#include "rts5228.h"
#include "rtsx_pcr.h"
static u8 rts5228_get_ic_version(struct rtsx_pcr *pcr)
{
u8 val;
rtsx_pci_read_register(pcr, DUMMY_REG_RESET_0, &val);
return val & IC_VERSION_MASK;
}
static void rts5228_fill_driving(struct rtsx_pcr *pcr, u8 voltage)
{
u8 driving_3v3[4][3] = {
{0x13, 0x13, 0x13},
{0x96, 0x96, 0x96},
{0x7F, 0x7F, 0x7F},
{0x96, 0x96, 0x96},
};
u8 driving_1v8[4][3] = {
{0x99, 0x99, 0x99},
{0xB5, 0xB5, 0xB5},
{0xE6, 0x7E, 0xFE},
{0x6B, 0x6B, 0x6B},
};
u8 (*driving)[3], drive_sel;
if (voltage == OUTPUT_3V3) {
driving = driving_3v3;
drive_sel = pcr->sd30_drive_sel_3v3;
} else {
driving = driving_1v8;
drive_sel = pcr->sd30_drive_sel_1v8;
}
rtsx_pci_write_register(pcr, SD30_CLK_DRIVE_SEL,
0xFF, driving[drive_sel][0]);
rtsx_pci_write_register(pcr, SD30_CMD_DRIVE_SEL,
0xFF, driving[drive_sel][1]);
rtsx_pci_write_register(pcr, SD30_DAT_DRIVE_SEL,
0xFF, driving[drive_sel][2]);
}
static void rtsx5228_fetch_vendor_settings(struct rtsx_pcr *pcr)
{
struct pci_dev *pdev = pcr->pci;
u32 reg;
/* 0x724~0x727 */
pci_read_config_dword(pdev, PCR_SETTING_REG1, &reg);
pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG1, reg);
if (!rtsx_vendor_setting_valid(reg)) {
pcr_dbg(pcr, "skip fetch vendor setting\n");
return;
}
pcr->sd30_drive_sel_1v8 = rtsx_reg_to_sd30_drive_sel_1v8(reg);
pcr->aspm_en = rtsx_reg_to_aspm(reg);
/* 0x814~0x817 */
pci_read_config_dword(pdev, PCR_SETTING_REG2, &reg);
pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG2, reg);
pcr->rtd3_en = rtsx_reg_to_rtd3(reg);
if (rtsx_check_mmc_support(reg))
pcr->extra_caps |= EXTRA_CAPS_NO_MMC;
pcr->sd30_drive_sel_3v3 = rtsx_reg_to_sd30_drive_sel_3v3(reg);
if (rtsx_reg_check_reverse_socket(reg))
pcr->flags |= PCR_REVERSE_SOCKET;
}
static int rts5228_optimize_phy(struct rtsx_pcr *pcr)
{
return rtsx_pci_write_phy_register(pcr, 0x07, 0x8F40);
}
static void rts5228_force_power_down(struct rtsx_pcr *pcr, u8 pm_state)
{
/* Set relink_time to 0 */
rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 1, MASK_8_BIT_DEF, 0);
rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 2, MASK_8_BIT_DEF, 0);
rtsx_pci_write_register(pcr, AUTOLOAD_CFG_BASE + 3,
RELINK_TIME_MASK, 0);
if (pm_state == HOST_ENTER_S3)
rtsx_pci_write_register(pcr, pcr->reg_pm_ctrl3,
D3_DELINK_MODE_EN, D3_DELINK_MODE_EN);
rtsx_pci_write_register(pcr, FPDCTL,
SSC_POWER_DOWN, SSC_POWER_DOWN);
}
static int rts5228_enable_auto_blink(struct rtsx_pcr *pcr)
{
return rtsx_pci_write_register(pcr, OLT_LED_CTL,
LED_SHINE_MASK, LED_SHINE_EN);
}
static int rts5228_disable_auto_blink(struct rtsx_pcr *pcr)
{
return rtsx_pci_write_register(pcr, OLT_LED_CTL,
LED_SHINE_MASK, LED_SHINE_DISABLE);
}
static int rts5228_turn_on_led(struct rtsx_pcr *pcr)
{
return rtsx_pci_write_register(pcr, GPIO_CTL,
0x02, 0x02);
}
static int rts5228_turn_off_led(struct rtsx_pcr *pcr)
{
return rtsx_pci_write_register(pcr, GPIO_CTL,
0x02, 0x00);
}
/* SD Pull Control Enable:
* SD_DAT[3:0] ==> pull up
* SD_CD ==> pull up
* SD_WP ==> pull up
* SD_CMD ==> pull up
* SD_CLK ==> pull down
*/
static const u32 rts5228_sd_pull_ctl_enable_tbl[] = {
RTSX_REG_PAIR(CARD_PULL_CTL2, 0xAA),
RTSX_REG_PAIR(CARD_PULL_CTL3, 0xE9),
0,
};
/* SD Pull Control Disable:
* SD_DAT[3:0] ==> pull down
* SD_CD ==> pull up
* SD_WP ==> pull down
* SD_CMD ==> pull down
* SD_CLK ==> pull down
*/
static const u32 rts5228_sd_pull_ctl_disable_tbl[] = {
RTSX_REG_PAIR(CARD_PULL_CTL2, 0x55),
RTSX_REG_PAIR(CARD_PULL_CTL3, 0xD5),
0,
};
static int rts5228_sd_set_sample_push_timing_sd30(struct rtsx_pcr *pcr)
{
rtsx_pci_write_register(pcr, SD_CFG1, SD_MODE_SELECT_MASK
| SD_ASYNC_FIFO_NOT_RST, SD_30_MODE | SD_ASYNC_FIFO_NOT_RST);
rtsx_pci_write_register(pcr, CLK_CTL, CLK_LOW_FREQ, CLK_LOW_FREQ);
rtsx_pci_write_register(pcr, CARD_CLK_SOURCE, 0xFF,
CRC_VAR_CLK0 | SD30_FIX_CLK | SAMPLE_VAR_CLK1);
rtsx_pci_write_register(pcr, CLK_CTL, CLK_LOW_FREQ, 0);
return 0;
}
static int rts5228_card_power_on(struct rtsx_pcr *pcr, int card)
{
struct rtsx_cr_option *option = &pcr->option;
if (option->ocp_en)
rtsx_pci_enable_ocp(pcr);
rtsx_pci_write_register(pcr, REG_CRC_DUMMY_0,
CFG_SD_POW_AUTO_PD, CFG_SD_POW_AUTO_PD);
rtsx_pci_write_register(pcr, RTS5228_LDO1_CFG1,
RTS5228_LDO1_TUNE_MASK, RTS5228_LDO1_33);
rtsx_pci_write_register(pcr, RTS5228_LDO1233318_POW_CTL,
RTS5228_LDO1_POWERON_MASK, RTS5228_LDO1_SOFTSTART);
mdelay(2);
rtsx_pci_write_register(pcr, RTS5228_LDO1233318_POW_CTL,
RTS5228_LDO1_POWERON_MASK, RTS5228_LDO1_FULLON);
rtsx_pci_write_register(pcr, RTS5228_LDO1233318_POW_CTL,
RTS5228_LDO3318_POWERON, RTS5228_LDO3318_POWERON);
msleep(20);
rtsx_pci_write_register(pcr, CARD_OE, SD_OUTPUT_EN, SD_OUTPUT_EN);
/* Initialize SD_CFG1 register */
rtsx_pci_write_register(pcr, SD_CFG1, 0xFF,
SD_CLK_DIVIDE_128 | SD_20_MODE | SD_BUS_WIDTH_1BIT);
rtsx_pci_write_register(pcr, SD_SAMPLE_POINT_CTL,
0xFF, SD20_RX_POS_EDGE);
rtsx_pci_write_register(pcr, SD_PUSH_POINT_CTL, 0xFF, 0);
rtsx_pci_write_register(pcr, CARD_STOP, SD_STOP | SD_CLR_ERR,
SD_STOP | SD_CLR_ERR);
/* Reset SD_CFG3 register */
rtsx_pci_write_register(pcr, SD_CFG3, SD30_CLK_END_EN, 0);
rtsx_pci_write_register(pcr, REG_SD_STOP_SDCLK_CFG,
SD30_CLK_STOP_CFG_EN | SD30_CLK_STOP_CFG1 |
SD30_CLK_STOP_CFG0, 0);
if (pcr->extra_caps & EXTRA_CAPS_SD_SDR50 ||
pcr->extra_caps & EXTRA_CAPS_SD_SDR104)
rts5228_sd_set_sample_push_timing_sd30(pcr);
return 0;
}
static int rts5228_switch_output_voltage(struct rtsx_pcr *pcr, u8 voltage)
{
int err;
u16 val = 0;
rtsx_pci_write_register(pcr, RTS5228_CARD_PWR_CTL,
RTS5228_PUPDC, RTS5228_PUPDC);
switch (voltage) {
case OUTPUT_3V3:
rtsx_pci_read_phy_register(pcr, PHY_TUNE, &val);
val |= PHY_TUNE_SDBUS_33;
err = rtsx_pci_write_phy_register(pcr, PHY_TUNE, val);
if (err < 0)
return err;
rtsx_pci_write_register(pcr, RTS5228_DV3318_CFG,
RTS5228_DV3318_TUNE_MASK, RTS5228_DV3318_33);
rtsx_pci_write_register(pcr, SD_PAD_CTL,
SD_IO_USING_1V8, 0);
break;
case OUTPUT_1V8:
rtsx_pci_read_phy_register(pcr, PHY_TUNE, &val);
val &= ~PHY_TUNE_SDBUS_33;
err = rtsx_pci_write_phy_register(pcr, PHY_TUNE, val);
if (err < 0)
return err;
rtsx_pci_write_register(pcr, RTS5228_DV3318_CFG,
RTS5228_DV3318_TUNE_MASK, RTS5228_DV3318_18);
rtsx_pci_write_register(pcr, SD_PAD_CTL,
SD_IO_USING_1V8, SD_IO_USING_1V8);
break;
default:
return -EINVAL;
}
/* set pad drive */
rts5228_fill_driving(pcr, voltage);
return 0;
}
static void rts5228_stop_cmd(struct rtsx_pcr *pcr)
{
rtsx_pci_writel(pcr, RTSX_HCBCTLR, STOP_CMD);
rtsx_pci_writel(pcr, RTSX_HDBCTLR, STOP_DMA);
rtsx_pci_write_register(pcr, RTS5260_DMA_RST_CTL_0,
RTS5260_DMA_RST | RTS5260_ADMA3_RST,
RTS5260_DMA_RST | RTS5260_ADMA3_RST);
rtsx_pci_write_register(pcr, RBCTL, RB_FLUSH, RB_FLUSH);
}
static void rts5228_card_before_power_off(struct rtsx_pcr *pcr)
{
rts5228_stop_cmd(pcr);
rts5228_switch_output_voltage(pcr, OUTPUT_3V3);
}
static void rts5228_enable_ocp(struct rtsx_pcr *pcr)
{
u8 val = 0;
val = SD_OCP_INT_EN | SD_DETECT_EN;
rtsx_pci_write_register(pcr, REG_OCPCTL, 0xFF, val);
rtsx_pci_write_register(pcr, RTS5228_LDO1_CFG0,
RTS5228_LDO1_OCP_EN | RTS5228_LDO1_OCP_LMT_EN,
RTS5228_LDO1_OCP_EN | RTS5228_LDO1_OCP_LMT_EN);
}
static void rts5228_disable_ocp(struct rtsx_pcr *pcr)
{
u8 mask = 0;
mask = SD_OCP_INT_EN | SD_DETECT_EN;
rtsx_pci_write_register(pcr, REG_OCPCTL, mask, 0);
rtsx_pci_write_register(pcr, RTS5228_LDO1_CFG0,
RTS5228_LDO1_OCP_EN | RTS5228_LDO1_OCP_LMT_EN, 0);
}
static int rts5228_card_power_off(struct rtsx_pcr *pcr, int card)
{
int err = 0;
rts5228_card_before_power_off(pcr);
err = rtsx_pci_write_register(pcr, RTS5228_LDO1233318_POW_CTL,
RTS5228_LDO_POWERON_MASK, 0);
rtsx_pci_write_register(pcr, REG_CRC_DUMMY_0, CFG_SD_POW_AUTO_PD, 0);
if (pcr->option.ocp_en)
rtsx_pci_disable_ocp(pcr);
return err;
}
static void rts5228_init_ocp(struct rtsx_pcr *pcr)
{
struct rtsx_cr_option *option = &pcr->option;
if (option->ocp_en) {
u8 mask, val;
rtsx_pci_write_register(pcr, RTS5228_LDO1_CFG0,
RTS5228_LDO1_OCP_EN | RTS5228_LDO1_OCP_LMT_EN,
RTS5228_LDO1_OCP_EN | RTS5228_LDO1_OCP_LMT_EN);
rtsx_pci_write_register(pcr, RTS5228_LDO1_CFG0,
RTS5228_LDO1_OCP_THD_MASK, option->sd_800mA_ocp_thd);
rtsx_pci_write_register(pcr, RTS5228_LDO1_CFG0,
RTS5228_LDO1_OCP_LMT_THD_MASK,
RTS5228_LDO1_LMT_THD_1500);
rtsx_pci_read_register(pcr, RTS5228_LDO1_CFG0, &val);
mask = SD_OCP_GLITCH_MASK;
val = pcr->hw_param.ocp_glitch;
rtsx_pci_write_register(pcr, REG_OCPGLITCH, mask, val);
rts5228_enable_ocp(pcr);
} else {
rtsx_pci_write_register(pcr, RTS5228_LDO1_CFG0,
RTS5228_LDO1_OCP_EN | RTS5228_LDO1_OCP_LMT_EN, 0);
}
}
static void rts5228_clear_ocpstat(struct rtsx_pcr *pcr)
{
u8 mask = 0;
u8 val = 0;
mask = SD_OCP_INT_CLR | SD_OC_CLR;
val = SD_OCP_INT_CLR | SD_OC_CLR;
rtsx_pci_write_register(pcr, REG_OCPCTL, mask, val);
udelay(1000);
rtsx_pci_write_register(pcr, REG_OCPCTL, mask, 0);
}
static void rts5228_process_ocp(struct rtsx_pcr *pcr)
{
if (!pcr->option.ocp_en)
return;
rtsx_pci_get_ocpstat(pcr, &pcr->ocp_stat);
if (pcr->ocp_stat & (SD_OC_NOW | SD_OC_EVER)) {
rts5228_clear_ocpstat(pcr);
rts5228_card_power_off(pcr, RTSX_SD_CARD);
rtsx_pci_write_register(pcr, CARD_OE, SD_OUTPUT_EN, 0);
pcr->ocp_stat = 0;
}
}
static void rts5228_init_from_cfg(struct rtsx_pcr *pcr)
{
struct pci_dev *pdev = pcr->pci;
int l1ss;
u32 lval;
struct rtsx_cr_option *option = &pcr->option;
l1ss = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_L1SS);
if (!l1ss)
return;
pci_read_config_dword(pdev, l1ss + PCI_L1SS_CTL1, &lval);
if (0 == (lval & 0x0F))
rtsx_pci_enable_oobs_polling(pcr);
else
rtsx_pci_disable_oobs_polling(pcr);
if (lval & PCI_L1SS_CTL1_ASPM_L1_1)
rtsx_set_dev_flag(pcr, ASPM_L1_1_EN);
else
rtsx_clear_dev_flag(pcr, ASPM_L1_1_EN);
if (lval & PCI_L1SS_CTL1_ASPM_L1_2)
rtsx_set_dev_flag(pcr, ASPM_L1_2_EN);
else
rtsx_clear_dev_flag(pcr, ASPM_L1_2_EN);
if (lval & PCI_L1SS_CTL1_PCIPM_L1_1)
rtsx_set_dev_flag(pcr, PM_L1_1_EN);
else
rtsx_clear_dev_flag(pcr, PM_L1_1_EN);
if (lval & PCI_L1SS_CTL1_PCIPM_L1_2)
rtsx_set_dev_flag(pcr, PM_L1_2_EN);
else
rtsx_clear_dev_flag(pcr, PM_L1_2_EN);
rtsx_pci_write_register(pcr, ASPM_FORCE_CTL, 0xFF, 0);
if (option->ltr_en) {
u16 val;
pcie_capability_read_word(pcr->pci, PCI_EXP_DEVCTL2, &val);
if (val & PCI_EXP_DEVCTL2_LTR_EN) {
option->ltr_enabled = true;
option->ltr_active = true;
rtsx_set_ltr_latency(pcr, option->ltr_active_latency);
} else {
option->ltr_enabled = false;
}
}
if (rtsx_check_dev_flag(pcr, ASPM_L1_1_EN | ASPM_L1_2_EN
| PM_L1_1_EN | PM_L1_2_EN))
option->force_clkreq_0 = false;
else
option->force_clkreq_0 = true;
}
static int rts5228_extra_init_hw(struct rtsx_pcr *pcr)
{
struct rtsx_cr_option *option = &pcr->option;
rtsx_pci_write_register(pcr, RTS5228_AUTOLOAD_CFG1,
CD_RESUME_EN_MASK, CD_RESUME_EN_MASK);
rts5228_init_from_cfg(pcr);
rtsx_pci_write_register(pcr, L1SUB_CONFIG1,
AUX_CLK_ACTIVE_SEL_MASK, MAC_CKSW_DONE);
rtsx_pci_write_register(pcr, L1SUB_CONFIG3, 0xFF, 0);
rtsx_pci_write_register(pcr, FUNC_FORCE_CTL,
FUNC_FORCE_UPME_XMT_DBG, FUNC_FORCE_UPME_XMT_DBG);
rtsx_pci_write_register(pcr, PCLK_CTL,
PCLK_MODE_SEL, PCLK_MODE_SEL);
rtsx_pci_write_register(pcr, PM_EVENT_DEBUG, PME_DEBUG_0, PME_DEBUG_0);
rtsx_pci_write_register(pcr, PM_CLK_FORCE_CTL, CLK_PM_EN, CLK_PM_EN);
/* LED shine disabled, set initial shine cycle period */
rtsx_pci_write_register(pcr, OLT_LED_CTL, 0x0F, 0x02);
/* Configure driving */
rts5228_fill_driving(pcr, OUTPUT_3V3);
if (pcr->flags & PCR_REVERSE_SOCKET)
rtsx_pci_write_register(pcr, PETXCFG, 0x30, 0x30);
else
rtsx_pci_write_register(pcr, PETXCFG, 0x30, 0x00);
/*
* If u_force_clkreq_0 is enabled, CLKREQ# PIN will be forced
* to drive low, and we forcibly request clock.
*/
if (option->force_clkreq_0)
rtsx_pci_write_register(pcr, PETXCFG,
FORCE_CLKREQ_DELINK_MASK, FORCE_CLKREQ_LOW);
else
rtsx_pci_write_register(pcr, PETXCFG,
FORCE_CLKREQ_DELINK_MASK, FORCE_CLKREQ_HIGH);
rtsx_pci_write_register(pcr, PWD_SUSPEND_EN, 0xFF, 0xFB);
rtsx_pci_write_register(pcr, pcr->reg_pm_ctrl3, 0x10, 0x00);
rtsx_pci_write_register(pcr, RTS5228_REG_PME_FORCE_CTL,
FORCE_PM_CONTROL | FORCE_PM_VALUE, FORCE_PM_CONTROL);
return 0;
}
static void rts5228_enable_aspm(struct rtsx_pcr *pcr, bool enable)
{
u8 mask, val;
if (pcr->aspm_enabled == enable)
return;
mask = FORCE_ASPM_VAL_MASK | FORCE_ASPM_CTL0 | FORCE_ASPM_CTL1;
val = FORCE_ASPM_CTL0 | FORCE_ASPM_CTL1;
val |= (pcr->aspm_en & 0x02);
rtsx_pci_write_register(pcr, ASPM_FORCE_CTL, mask, val);
pcie_capability_clear_and_set_word(pcr->pci, PCI_EXP_LNKCTL,
PCI_EXP_LNKCTL_ASPMC, pcr->aspm_en);
pcr->aspm_enabled = enable;
}
static void rts5228_disable_aspm(struct rtsx_pcr *pcr, bool enable)
{
u8 mask, val;
if (pcr->aspm_enabled == enable)
return;
pcie_capability_clear_and_set_word(pcr->pci, PCI_EXP_LNKCTL,
PCI_EXP_LNKCTL_ASPMC, 0);
mask = FORCE_ASPM_VAL_MASK | FORCE_ASPM_CTL0 | FORCE_ASPM_CTL1;
val = FORCE_ASPM_CTL0 | FORCE_ASPM_CTL1;
rtsx_pci_write_register(pcr, ASPM_FORCE_CTL, mask, val);
rtsx_pci_write_register(pcr, SD_CFG1, SD_ASYNC_FIFO_NOT_RST, 0);
mdelay(10);
pcr->aspm_enabled = enable;
}
static void rts5228_set_aspm(struct rtsx_pcr *pcr, bool enable)
{
if (enable)
rts5228_enable_aspm(pcr, true);
else
rts5228_disable_aspm(pcr, false);
}
static void rts5228_set_l1off_cfg_sub_d0(struct rtsx_pcr *pcr, int active)
{
struct rtsx_cr_option *option = &pcr->option;
int aspm_L1_1, aspm_L1_2;
u8 val = 0;
aspm_L1_1 = rtsx_check_dev_flag(pcr, ASPM_L1_1_EN);
aspm_L1_2 = rtsx_check_dev_flag(pcr, ASPM_L1_2_EN);
if (active) {
/* run, latency: 60us */
if (aspm_L1_1)
val = option->ltr_l1off_snooze_sspwrgate;
} else {
/* l1off, latency: 300us */
if (aspm_L1_2)
val = option->ltr_l1off_sspwrgate;
}
rtsx_set_l1off_sub(pcr, val);
}
static const struct pcr_ops rts5228_pcr_ops = {
.fetch_vendor_settings = rtsx5228_fetch_vendor_settings,
.turn_on_led = rts5228_turn_on_led,
.turn_off_led = rts5228_turn_off_led,
.extra_init_hw = rts5228_extra_init_hw,
.enable_auto_blink = rts5228_enable_auto_blink,
.disable_auto_blink = rts5228_disable_auto_blink,
.card_power_on = rts5228_card_power_on,
.card_power_off = rts5228_card_power_off,
.switch_output_voltage = rts5228_switch_output_voltage,
.force_power_down = rts5228_force_power_down,
.stop_cmd = rts5228_stop_cmd,
.set_aspm = rts5228_set_aspm,
.set_l1off_cfg_sub_d0 = rts5228_set_l1off_cfg_sub_d0,
.enable_ocp = rts5228_enable_ocp,
.disable_ocp = rts5228_disable_ocp,
.init_ocp = rts5228_init_ocp,
.process_ocp = rts5228_process_ocp,
.clear_ocpstat = rts5228_clear_ocpstat,
.optimize_phy = rts5228_optimize_phy,
};
static inline u8 double_ssc_depth(u8 depth)
{
return ((depth > 1) ? (depth - 1) : depth);
}
int rts5228_pci_switch_clock(struct rtsx_pcr *pcr, unsigned int card_clock,
u8 ssc_depth, bool initial_mode, bool double_clk, bool vpclk)
{
int err, clk;
u16 n;
u8 clk_divider, mcu_cnt, div;
static const u8 depth[] = {
[RTSX_SSC_DEPTH_4M] = RTS5228_SSC_DEPTH_4M,
[RTSX_SSC_DEPTH_2M] = RTS5228_SSC_DEPTH_2M,
[RTSX_SSC_DEPTH_1M] = RTS5228_SSC_DEPTH_1M,
[RTSX_SSC_DEPTH_500K] = RTS5228_SSC_DEPTH_512K,
};
if (initial_mode) {
/* We use 250k(around) here, in initial stage */
clk_divider = SD_CLK_DIVIDE_128;
card_clock = 30000000;
} else {
clk_divider = SD_CLK_DIVIDE_0;
}
err = rtsx_pci_write_register(pcr, SD_CFG1,
SD_CLK_DIVIDE_MASK, clk_divider);
if (err < 0)
return err;
card_clock /= 1000000;
pcr_dbg(pcr, "Switch card clock to %dMHz\n", card_clock);
clk = card_clock;
if (!initial_mode && double_clk)
clk = card_clock * 2;
pcr_dbg(pcr, "Internal SSC clock: %dMHz (cur_clock = %d)\n",
clk, pcr->cur_clock);
if (clk == pcr->cur_clock)
return 0;
if (pcr->ops->conv_clk_and_div_n)
n = pcr->ops->conv_clk_and_div_n(clk, CLK_TO_DIV_N);
else
n = clk - 4;
if ((clk <= 4) || (n > 396))
return -EINVAL;
mcu_cnt = 125/clk + 3;
if (mcu_cnt > 15)
mcu_cnt = 15;
div = CLK_DIV_1;
while ((n < MIN_DIV_N_PCR - 4) && (div < CLK_DIV_8)) {
if (pcr->ops->conv_clk_and_div_n) {
int dbl_clk = pcr->ops->conv_clk_and_div_n(n,
DIV_N_TO_CLK) * 2;
n = pcr->ops->conv_clk_and_div_n(dbl_clk,
CLK_TO_DIV_N);
} else {
n = (n + 4) * 2 - 4;
}
div++;
}
n = (n / 2) - 1;
pcr_dbg(pcr, "n = %d, div = %d\n", n, div);
ssc_depth = depth[ssc_depth];
if (double_clk)
ssc_depth = double_ssc_depth(ssc_depth);
if (ssc_depth) {
if (div == CLK_DIV_2) {
if (ssc_depth > 1)
ssc_depth -= 1;
else
ssc_depth = RTS5228_SSC_DEPTH_8M;
} else if (div == CLK_DIV_4) {
if (ssc_depth > 2)
ssc_depth -= 2;
else
ssc_depth = RTS5228_SSC_DEPTH_8M;
} else if (div == CLK_DIV_8) {
if (ssc_depth > 3)
ssc_depth -= 3;
else
ssc_depth = RTS5228_SSC_DEPTH_8M;
}
} else {
ssc_depth = 0;
}
pcr_dbg(pcr, "ssc_depth = %d\n", ssc_depth);
rtsx_pci_init_cmd(pcr);
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_CTL,
CLK_LOW_FREQ, CLK_LOW_FREQ);
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_DIV,
0xFF, (div << 4) | mcu_cnt);
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_CTL1, SSC_RSTB, 0);
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_CTL2,
SSC_DEPTH_MASK, ssc_depth);
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_DIV_N_0, 0xFF, n);
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_CTL1, SSC_RSTB, SSC_RSTB);
if (vpclk) {
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_VPCLK0_CTL,
PHASE_NOT_RESET, 0);
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_VPCLK1_CTL,
PHASE_NOT_RESET, 0);
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_VPCLK0_CTL,
PHASE_NOT_RESET, PHASE_NOT_RESET);
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_VPCLK1_CTL,
PHASE_NOT_RESET, PHASE_NOT_RESET);
}
err = rtsx_pci_send_cmd(pcr, 2000);
if (err < 0)
return err;
/* Wait SSC clock stable */
udelay(SSC_CLOCK_STABLE_WAIT);
err = rtsx_pci_write_register(pcr, CLK_CTL, CLK_LOW_FREQ, 0);
if (err < 0)
return err;
pcr->cur_clock = clk;
return 0;
}
void rts5228_init_params(struct rtsx_pcr *pcr)
{
struct rtsx_cr_option *option = &pcr->option;
struct rtsx_hw_param *hw_param = &pcr->hw_param;
pcr->extra_caps = EXTRA_CAPS_SD_SDR50 | EXTRA_CAPS_SD_SDR104;
pcr->num_slots = 1;
pcr->ops = &rts5228_pcr_ops;
pcr->flags = 0;
pcr->card_drive_sel = RTSX_CARD_DRIVE_DEFAULT;
pcr->sd30_drive_sel_1v8 = CFG_DRIVER_TYPE_B;
pcr->sd30_drive_sel_3v3 = CFG_DRIVER_TYPE_B;
pcr->aspm_en = ASPM_L1_EN;
pcr->tx_initial_phase = SET_CLOCK_PHASE(28, 27, 11);
pcr->rx_initial_phase = SET_CLOCK_PHASE(24, 6, 5);
pcr->ic_version = rts5228_get_ic_version(pcr);
pcr->sd_pull_ctl_enable_tbl = rts5228_sd_pull_ctl_enable_tbl;
pcr->sd_pull_ctl_disable_tbl = rts5228_sd_pull_ctl_disable_tbl;
pcr->reg_pm_ctrl3 = RTS5228_AUTOLOAD_CFG3;
option->dev_flags = (LTR_L1SS_PWR_GATE_CHECK_CARD_EN
| LTR_L1SS_PWR_GATE_EN);
option->ltr_en = true;
/* init latency of active, idle, L1OFF to 60us, 300us, 3ms */
option->ltr_active_latency = LTR_ACTIVE_LATENCY_DEF;
option->ltr_idle_latency = LTR_IDLE_LATENCY_DEF;
option->ltr_l1off_latency = LTR_L1OFF_LATENCY_DEF;
option->l1_snooze_delay = L1_SNOOZE_DELAY_DEF;
option->ltr_l1off_sspwrgate = 0x7F;
option->ltr_l1off_snooze_sspwrgate = 0x78;
option->ocp_en = 1;
hw_param->interrupt_en |= SD_OC_INT_EN;
hw_param->ocp_glitch = SD_OCP_GLITCH_800U;
option->sd_800mA_ocp_thd = RTS5228_LDO1_OCP_THD_930;
}

View File

@ -0,0 +1,168 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* Driver for Realtek PCI-Express card reader
*
* Copyright(c) 2018-2019 Realtek Semiconductor Corp. All rights reserved.
*
* Author:
* Ricky WU <ricky_wu@realtek.com>
* Rui FENG <rui_feng@realsil.com.cn>
* Wei WANG <wei_wang@realsil.com.cn>
*/
#ifndef RTS5228_H
#define RTS5228_H
#define RTS5228_AUTOLOAD_CFG0 0xFF7B
#define RTS5228_AUTOLOAD_CFG1 0xFF7C
#define RTS5228_AUTOLOAD_CFG2 0xFF7D
#define RTS5228_AUTOLOAD_CFG3 0xFF7E
#define RTS5228_AUTOLOAD_CFG4 0xFF7F
#define RTS5228_REG_VREF 0xFE97
#define RTS5228_PWD_SUSPND_EN (1 << 4)
#define RTS5228_PAD_H3L1 0xFF79
#define PAD_GPIO_H3L1 (1 << 3)
/* SSC_CTL2 0xFC12 */
#define RTS5228_SSC_DEPTH_MASK 0x07
#define RTS5228_SSC_DEPTH_DISALBE 0x00
#define RTS5228_SSC_DEPTH_8M 0x01
#define RTS5228_SSC_DEPTH_4M 0x02
#define RTS5228_SSC_DEPTH_2M 0x03
#define RTS5228_SSC_DEPTH_1M 0x04
#define RTS5228_SSC_DEPTH_512K 0x05
#define RTS5228_SSC_DEPTH_256K 0x06
#define RTS5228_SSC_DEPTH_128K 0x07
/* DMACTL 0xFE2C */
#define RTS5228_DMA_PACK_SIZE_MASK 0xF0
#define RTS5228_REG_LDO12_CFG 0xFF6E
#define RTS5228_LDO12_VO_TUNE_MASK (0x07<<1)
#define RTS5228_LDO12_100 (0x00<<1)
#define RTS5228_LDO12_105 (0x01<<1)
#define RTS5228_LDO12_110 (0x02<<1)
#define RTS5228_LDO12_115 (0x03<<1)
#define RTS5228_LDO12_120 (0x04<<1)
#define RTS5228_LDO12_125 (0x05<<1)
#define RTS5228_LDO12_130 (0x06<<1)
#define RTS5228_LDO12_135 (0x07<<1)
#define RTS5228_REG_PWD_LDO12 (0x01<<0)
#define RTS5228_REG_LDO12_L12 0xFF6F
#define RTS5228_LDO12_L12_MASK (0x07<<4)
#define RTS5228_LDO12_L12_120 (0x04<<4)
/* LDO control register */
#define RTS5228_CARD_PWR_CTL 0xFD50
#define RTS5228_PUPDC (0x01<<5)
#define RTS5228_LDO1233318_POW_CTL 0xFF70
#define RTS5228_LDO3318_POWERON (0x01<<3)
#define RTS5228_LDO1_POWEROFF (0x00<<0)
#define RTS5228_LDO1_SOFTSTART (0x01<<0)
#define RTS5228_LDO1_FULLON (0x03<<0)
#define RTS5228_LDO1_POWERON_MASK (0x03<<0)
#define RTS5228_LDO_POWERON_MASK (0x0F<<0)
#define RTS5228_DV3318_CFG 0xFF71
#define RTS5228_DV3318_TUNE_MASK (0x07<<4)
#define RTS5228_DV3318_17 (0x00<<4)
#define RTS5228_DV3318_1V75 (0x01<<4)
#define RTS5228_DV3318_18 (0x02<<4)
#define RTS5228_DV3318_1V85 (0x03<<4)
#define RTS5228_DV3318_19 (0x04<<4)
#define RTS5228_DV3318_33 (0x07<<4)
#define RTS5228_DV3318_SR_MASK (0x03<<2)
#define RTS5228_DV3318_SR_0 (0x00<<2)
#define RTS5228_DV3318_SR_250 (0x01<<2)
#define RTS5228_DV3318_SR_500 (0x02<<2)
#define RTS5228_DV3318_SR_1000 (0x03<<2)
#define RTS5228_LDO1_CFG0 0xFF72
#define RTS5228_LDO1_OCP_THD_MASK (0x07<<5)
#define RTS5228_LDO1_OCP_EN (0x01<<4)
#define RTS5228_LDO1_OCP_LMT_THD_MASK (0x03<<2)
#define RTS5228_LDO1_OCP_LMT_EN (0x01<<1)
#define RTS5228_LDO1_OCP_THD_730 (0x00<<5)
#define RTS5228_LDO1_OCP_THD_780 (0x01<<5)
#define RTS5228_LDO1_OCP_THD_860 (0x02<<5)
#define RTS5228_LDO1_OCP_THD_930 (0x03<<5)
#define RTS5228_LDO1_OCP_THD_1000 (0x04<<5)
#define RTS5228_LDO1_OCP_THD_1070 (0x05<<5)
#define RTS5228_LDO1_OCP_THD_1140 (0x06<<5)
#define RTS5228_LDO1_OCP_THD_1220 (0x07<<5)
#define RTS5228_LDO1_LMT_THD_450 (0x00<<2)
#define RTS5228_LDO1_LMT_THD_1000 (0x01<<2)
#define RTS5228_LDO1_LMT_THD_1500 (0x02<<2)
#define RTS5228_LDO1_LMT_THD_2000 (0x03<<2)
#define RTS5228_LDO1_CFG1 0xFF73
#define RTS5228_LDO1_SR_TIME_MASK (0x03<<6)
#define RTS5228_LDO1_SR_0_0 (0x00<<6)
#define RTS5228_LDO1_SR_0_25 (0x01<<6)
#define RTS5228_LDO1_SR_0_5 (0x02<<6)
#define RTS5228_LDO1_SR_1_0 (0x03<<6)
#define RTS5228_LDO1_TUNE_MASK (0x07<<1)
#define RTS5228_LDO1_18 (0x05<<1)
#define RTS5228_LDO1_33 (0x07<<1)
#define RTS5228_LDO1_PWD_MASK (0x01<<0)
#define RTS5228_AUXCLK_GAT_CTL 0xFF74
#define RTS5228_REG_RREF_CTL_0 0xFF75
#define RTS5228_FORCE_RREF_EXTL (0x01<<7)
#define RTS5228_REG_BG33_MASK (0x07<<0)
#define RTS5228_RREF_12_1V (0x04<<0)
#define RTS5228_RREF_12_3V (0x05<<0)
#define RTS5228_REG_RREF_CTL_1 0xFF76
#define RTS5228_REG_RREF_CTL_2 0xFF77
#define RTS5228_TEST_INTL_RREF (0x01<<7)
#define RTS5228_DGLCH_TIME_MASK (0x03<<5)
#define RTS5228_DGLCH_TIME_50 (0x00<<5)
#define RTS5228_DGLCH_TIME_75 (0x01<<5)
#define RTS5228_DGLCH_TIME_100 (0x02<<5)
#define RTS5228_DGLCH_TIME_125 (0x03<<5)
#define RTS5228_REG_REXT_TUNE_MASK (0x1F<<0)
#define RTS5228_REG_PME_FORCE_CTL 0xFF78
#define FORCE_PM_CONTROL 0x20
#define FORCE_PM_VALUE 0x10
/* Single LUN, support SD */
#define DEFAULT_SINGLE 0
#define SD_LUN 1
/* For Change_FPGA_SSCClock Function */
#define MULTIPLY_BY_1 0x00
#define MULTIPLY_BY_2 0x01
#define MULTIPLY_BY_3 0x02
#define MULTIPLY_BY_4 0x03
#define MULTIPLY_BY_5 0x04
#define MULTIPLY_BY_6 0x05
#define MULTIPLY_BY_7 0x06
#define MULTIPLY_BY_8 0x07
#define MULTIPLY_BY_9 0x08
#define MULTIPLY_BY_10 0x09
#define DIVIDE_BY_2 0x01
#define DIVIDE_BY_3 0x02
#define DIVIDE_BY_4 0x03
#define DIVIDE_BY_5 0x04
#define DIVIDE_BY_6 0x05
#define DIVIDE_BY_7 0x06
#define DIVIDE_BY_8 0x07
#define DIVIDE_BY_9 0x08
#define DIVIDE_BY_10 0x09
int rts5228_pci_switch_clock(struct rtsx_pcr *pcr, unsigned int card_clock,
u8 ssc_depth, bool initial_mode, bool double_clk, bool vpclk);
#endif /* RTS5228_H */

View File

@ -23,9 +23,10 @@ static u8 rts5229_get_ic_version(struct rtsx_pcr *pcr)
static void rts5229_fetch_vendor_settings(struct rtsx_pcr *pcr)
{
struct pci_dev *pdev = pcr->pci;
u32 reg;
rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG1, &reg);
pci_read_config_dword(pdev, PCR_SETTING_REG1, &reg);
pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG1, reg);
if (!rtsx_vendor_setting_valid(reg))
@ -37,7 +38,7 @@ static void rts5229_fetch_vendor_settings(struct rtsx_pcr *pcr)
pcr->card_drive_sel &= 0x3F;
pcr->card_drive_sel |= rtsx_reg_to_card_drive_sel(reg);
rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG2, &reg);
pci_read_config_dword(pdev, PCR_SETTING_REG2, &reg);
pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG2, reg);
pcr->sd30_drive_sel_3v3 =
map_sd_drive(rtsx_reg_to_sd30_drive_sel_3v3(reg));

View File

@ -55,9 +55,10 @@ static void rts5249_fill_driving(struct rtsx_pcr *pcr, u8 voltage)
static void rtsx_base_fetch_vendor_settings(struct rtsx_pcr *pcr)
{
struct pci_dev *pdev = pcr->pci;
u32 reg;
rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG1, &reg);
pci_read_config_dword(pdev, PCR_SETTING_REG1, &reg);
pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG1, reg);
if (!rtsx_vendor_setting_valid(reg)) {
@ -70,7 +71,7 @@ static void rtsx_base_fetch_vendor_settings(struct rtsx_pcr *pcr)
pcr->card_drive_sel &= 0x3F;
pcr->card_drive_sel |= rtsx_reg_to_card_drive_sel(reg);
rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG2, &reg);
pci_read_config_dword(pdev, PCR_SETTING_REG2, &reg);
pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG2, reg);
pcr->sd30_drive_sel_3v3 = rtsx_reg_to_sd30_drive_sel_3v3(reg);
if (rtsx_reg_check_reverse_socket(reg))
@ -93,32 +94,33 @@ static void rtsx_base_force_power_down(struct rtsx_pcr *pcr, u8 pm_state)
static void rts5249_init_from_cfg(struct rtsx_pcr *pcr)
{
struct pci_dev *pdev = pcr->pci;
int l1ss;
struct rtsx_cr_option *option = &(pcr->option);
u32 lval;
if (CHK_PCI_PID(pcr, PID_524A))
rtsx_pci_read_config_dword(pcr,
PCR_ASPM_SETTING_REG1, &lval);
else
rtsx_pci_read_config_dword(pcr,
PCR_ASPM_SETTING_REG2, &lval);
l1ss = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_L1SS);
if (!l1ss)
return;
if (lval & ASPM_L1_1_EN_MASK)
pci_read_config_dword(pdev, l1ss + PCI_L1SS_CTL1, &lval);
if (lval & PCI_L1SS_CTL1_ASPM_L1_1)
rtsx_set_dev_flag(pcr, ASPM_L1_1_EN);
if (lval & ASPM_L1_2_EN_MASK)
if (lval & PCI_L1SS_CTL1_ASPM_L1_2)
rtsx_set_dev_flag(pcr, ASPM_L1_2_EN);
if (lval & PM_L1_1_EN_MASK)
if (lval & PCI_L1SS_CTL1_PCIPM_L1_1)
rtsx_set_dev_flag(pcr, PM_L1_1_EN);
if (lval & PM_L1_2_EN_MASK)
if (lval & PCI_L1SS_CTL1_PCIPM_L1_2)
rtsx_set_dev_flag(pcr, PM_L1_2_EN);
if (option->ltr_en) {
u16 val;
pcie_capability_read_word(pcr->pci, PCI_EXP_DEVCTL2, &val);
pcie_capability_read_word(pdev, PCI_EXP_DEVCTL2, &val);
if (val & PCI_EXP_DEVCTL2_LTR_EN) {
option->ltr_enabled = true;
option->ltr_active = true;

View File

@ -64,9 +64,10 @@ static void rts5260_fill_driving(struct rtsx_pcr *pcr, u8 voltage)
static void rtsx_base_fetch_vendor_settings(struct rtsx_pcr *pcr)
{
struct pci_dev *pdev = pcr->pci;
u32 reg;
rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG1, &reg);
pci_read_config_dword(pdev, PCR_SETTING_REG1, &reg);
pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG1, reg);
if (!rtsx_vendor_setting_valid(reg)) {
@ -79,7 +80,7 @@ static void rtsx_base_fetch_vendor_settings(struct rtsx_pcr *pcr)
pcr->card_drive_sel &= 0x3F;
pcr->card_drive_sel |= rtsx_reg_to_card_drive_sel(reg);
rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG2, &reg);
pci_read_config_dword(pdev, PCR_SETTING_REG2, &reg);
pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG2, reg);
pcr->sd30_drive_sel_3v3 = rtsx_reg_to_sd30_drive_sel_3v3(reg);
if (rtsx_reg_check_reverse_socket(reg))
@ -496,21 +497,27 @@ static void rts5260_pwr_saving_setting(struct rtsx_pcr *pcr)
static void rts5260_init_from_cfg(struct rtsx_pcr *pcr)
{
struct pci_dev *pdev = pcr->pci;
int l1ss;
struct rtsx_cr_option *option = &pcr->option;
u32 lval;
rtsx_pci_read_config_dword(pcr, PCR_ASPM_SETTING_5260, &lval);
l1ss = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_L1SS);
if (!l1ss)
return;
if (lval & ASPM_L1_1_EN_MASK)
pci_read_config_dword(pdev, l1ss + PCI_L1SS_CTL1, &lval);
if (lval & PCI_L1SS_CTL1_ASPM_L1_1)
rtsx_set_dev_flag(pcr, ASPM_L1_1_EN);
if (lval & ASPM_L1_2_EN_MASK)
if (lval & PCI_L1SS_CTL1_ASPM_L1_2)
rtsx_set_dev_flag(pcr, ASPM_L1_2_EN);
if (lval & PM_L1_1_EN_MASK)
if (lval & PCI_L1SS_CTL1_PCIPM_L1_1)
rtsx_set_dev_flag(pcr, PM_L1_1_EN);
if (lval & PM_L1_2_EN_MASK)
if (lval & PCI_L1SS_CTL1_PCIPM_L1_2)
rtsx_set_dev_flag(pcr, PM_L1_2_EN);
rts5260_pwr_saving_setting(pcr);
@ -518,7 +525,7 @@ static void rts5260_init_from_cfg(struct rtsx_pcr *pcr)
if (option->ltr_en) {
u16 val;
pcie_capability_read_word(pcr->pci, PCI_EXP_DEVCTL2, &val);
pcie_capability_read_word(pdev, PCI_EXP_DEVCTL2, &val);
if (val & PCI_EXP_DEVCTL2_LTR_EN) {
option->ltr_enabled = true;
option->ltr_active = true;

View File

@ -59,9 +59,11 @@ static void rts5261_fill_driving(struct rtsx_pcr *pcr, u8 voltage)
static void rtsx5261_fetch_vendor_settings(struct rtsx_pcr *pcr)
{
struct pci_dev *pdev = pcr->pci;
u32 reg;
/* 0x814~0x817 */
rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG2, &reg);
pci_read_config_dword(pdev, PCR_SETTING_REG2, &reg);
pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG2, reg);
if (!rts5261_vendor_setting_valid(reg)) {
@ -76,7 +78,7 @@ static void rtsx5261_fetch_vendor_settings(struct rtsx_pcr *pcr)
pcr->flags |= PCR_REVERSE_SOCKET;
/* 0x724~0x727 */
rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG1, &reg);
pci_read_config_dword(pdev, PCR_SETTING_REG1, &reg);
pcr_dbg(pcr, "Cfg 0x%x: 0x%x\n", PCR_SETTING_REG1, reg);
pcr->aspm_en = rts5261_reg_to_aspm(reg);
@ -361,6 +363,7 @@ static void rts5261_process_ocp(struct rtsx_pcr *pcr)
static int rts5261_init_from_hw(struct rtsx_pcr *pcr)
{
struct pci_dev *pdev = pcr->pci;
int retval;
u32 lval, i;
u8 valid, efuse_valid, tmp;
@ -386,8 +389,7 @@ static int rts5261_init_from_hw(struct rtsx_pcr *pcr)
pcr_dbg(pcr, "Load efuse valid: 0x%x\n", efuse_valid);
if (efuse_valid == 0) {
retval = rtsx_pci_read_config_dword(pcr,
PCR_SETTING_REG2, &lval);
retval = pci_read_config_dword(pdev, PCR_SETTING_REG2, &lval);
if (retval != 0)
pcr_dbg(pcr, "read 0x814 DW fail\n");
pcr_dbg(pcr, "DW from 0x814: 0x%x\n", lval);
@ -399,9 +401,9 @@ static int rts5261_init_from_hw(struct rtsx_pcr *pcr)
REG_EFUSE_POR, 0);
pcr_dbg(pcr, "Disable efuse por!\n");
rtsx_pci_read_config_dword(pcr, PCR_SETTING_REG2, &lval);
pci_read_config_dword(pdev, PCR_SETTING_REG2, &lval);
lval = lval & 0x00FFFFFF;
retval = rtsx_pci_write_config_dword(pcr, PCR_SETTING_REG2, lval);
retval = pci_write_config_dword(pdev, PCR_SETTING_REG2, lval);
if (retval != 0)
pcr_dbg(pcr, "write config fail\n");
@ -410,27 +412,33 @@ static int rts5261_init_from_hw(struct rtsx_pcr *pcr)
static void rts5261_init_from_cfg(struct rtsx_pcr *pcr)
{
struct pci_dev *pdev = pcr->pci;
int l1ss;
u32 lval;
struct rtsx_cr_option *option = &pcr->option;
rtsx_pci_read_config_dword(pcr, PCR_ASPM_SETTING_REG1, &lval);
l1ss = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_L1SS);
if (!l1ss)
return;
if (lval & ASPM_L1_1_EN_MASK)
pci_read_config_dword(pdev, l1ss + PCI_L1SS_CTL1, &lval);
if (lval & PCI_L1SS_CTL1_ASPM_L1_1)
rtsx_set_dev_flag(pcr, ASPM_L1_1_EN);
else
rtsx_clear_dev_flag(pcr, ASPM_L1_1_EN);
if (lval & ASPM_L1_2_EN_MASK)
if (lval & PCI_L1SS_CTL1_ASPM_L1_2)
rtsx_set_dev_flag(pcr, ASPM_L1_2_EN);
else
rtsx_clear_dev_flag(pcr, ASPM_L1_2_EN);
if (lval & PM_L1_1_EN_MASK)
if (lval & PCI_L1SS_CTL1_PCIPM_L1_1)
rtsx_set_dev_flag(pcr, PM_L1_1_EN);
else
rtsx_clear_dev_flag(pcr, PM_L1_1_EN);
if (lval & PM_L1_2_EN_MASK)
if (lval & PCI_L1SS_CTL1_PCIPM_L1_2)
rtsx_set_dev_flag(pcr, PM_L1_2_EN);
else
rtsx_clear_dev_flag(pcr, PM_L1_2_EN);
@ -439,7 +447,7 @@ static void rts5261_init_from_cfg(struct rtsx_pcr *pcr)
if (option->ltr_en) {
u16 val;
pcie_capability_read_word(pcr->pci, PCI_EXP_DEVCTL2, &val);
pcie_capability_read_word(pdev, PCI_EXP_DEVCTL2, &val);
if (val & PCI_EXP_DEVCTL2_LTR_EN) {
option->ltr_enabled = true;
option->ltr_active = true;

View File

@ -23,6 +23,7 @@
#include "rtsx_pcr.h"
#include "rts5261.h"
#include "rts5228.h"
static bool msi_en = true;
module_param(msi_en, bool, S_IRUGO | S_IWUSR);
@ -50,6 +51,7 @@ static const struct pci_device_id rtsx_pci_ids[] = {
{ PCI_DEVICE(0x10EC, 0x525A), PCI_CLASS_OTHERS << 16, 0xFF0000 },
{ PCI_DEVICE(0x10EC, 0x5260), PCI_CLASS_OTHERS << 16, 0xFF0000 },
{ PCI_DEVICE(0x10EC, 0x5261), PCI_CLASS_OTHERS << 16, 0xFF0000 },
{ PCI_DEVICE(0x10EC, 0x5228), PCI_CLASS_OTHERS << 16, 0xFF0000 },
{ 0, }
};
@ -206,16 +208,10 @@ int __rtsx_pci_write_phy_register(struct rtsx_pcr *pcr, u8 addr, u16 val)
int err, i, finished = 0;
u8 tmp;
rtsx_pci_init_cmd(pcr);
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PHYDATA0, 0xFF, (u8)val);
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PHYDATA1, 0xFF, (u8)(val >> 8));
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PHYADDR, 0xFF, addr);
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PHYRWCTL, 0xFF, 0x81);
err = rtsx_pci_send_cmd(pcr, 100);
if (err < 0)
return err;
rtsx_pci_write_register(pcr, PHYDATA0, 0xFF, (u8)val);
rtsx_pci_write_register(pcr, PHYDATA1, 0xFF, (u8)(val >> 8));
rtsx_pci_write_register(pcr, PHYADDR, 0xFF, addr);
rtsx_pci_write_register(pcr, PHYRWCTL, 0xFF, 0x81);
for (i = 0; i < 100000; i++) {
err = rtsx_pci_read_register(pcr, PHYRWCTL, &tmp);
@ -247,16 +243,10 @@ int __rtsx_pci_read_phy_register(struct rtsx_pcr *pcr, u8 addr, u16 *val)
{
int err, i, finished = 0;
u16 data;
u8 *ptr, tmp;
u8 tmp, val1, val2;
rtsx_pci_init_cmd(pcr);
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PHYADDR, 0xFF, addr);
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PHYRWCTL, 0xFF, 0x80);
err = rtsx_pci_send_cmd(pcr, 100);
if (err < 0)
return err;
rtsx_pci_write_register(pcr, PHYADDR, 0xFF, addr);
rtsx_pci_write_register(pcr, PHYRWCTL, 0xFF, 0x80);
for (i = 0; i < 100000; i++) {
err = rtsx_pci_read_register(pcr, PHYRWCTL, &tmp);
@ -272,17 +262,9 @@ int __rtsx_pci_read_phy_register(struct rtsx_pcr *pcr, u8 addr, u16 *val)
if (!finished)
return -ETIMEDOUT;
rtsx_pci_init_cmd(pcr);
rtsx_pci_add_cmd(pcr, READ_REG_CMD, PHYDATA0, 0, 0);
rtsx_pci_add_cmd(pcr, READ_REG_CMD, PHYDATA1, 0, 0);
err = rtsx_pci_send_cmd(pcr, 100);
if (err < 0)
return err;
ptr = rtsx_pci_get_cmd_data(pcr);
data = ((u16)ptr[1] << 8) | ptr[0];
rtsx_pci_read_register(pcr, PHYDATA0, &val1);
rtsx_pci_read_register(pcr, PHYDATA1, &val2);
data = val1 | (val2 << 8);
if (val)
*val = data;
@ -417,7 +399,7 @@ static void rtsx_pci_add_sg_tbl(struct rtsx_pcr *pcr,
if (end)
option |= RTSX_SG_END;
if (PCI_PID(pcr) == PID_5261) {
if ((PCI_PID(pcr) == PID_5261) || (PCI_PID(pcr) == PID_5228)) {
if (len > 0xFFFF)
val = ((u64)addr << 32) | (((u64)len & 0xFFFF) << 16)
| (((u64)len >> 16) << 6) | option;
@ -723,6 +705,9 @@ int rtsx_pci_switch_clock(struct rtsx_pcr *pcr, unsigned int card_clock,
if (PCI_PID(pcr) == PID_5261)
return rts5261_pci_switch_clock(pcr, card_clock,
ssc_depth, initial_mode, double_clk, vpclk);
if (PCI_PID(pcr) == PID_5228)
return rts5228_pci_switch_clock(pcr, card_clock,
ssc_depth, initial_mode, double_clk, vpclk);
if (initial_mode) {
/* We use 250k(around) here, in initial stage */
@ -1111,8 +1096,7 @@ static void rtsx_pci_idle_work(struct work_struct *work)
mutex_unlock(&pcr->pcr_mutex);
}
#ifdef CONFIG_PM
static void rtsx_pci_power_off(struct rtsx_pcr *pcr, u8 pm_state)
static void __maybe_unused rtsx_pci_power_off(struct rtsx_pcr *pcr, u8 pm_state)
{
if (pcr->ops->turn_off_led)
pcr->ops->turn_off_led(pcr);
@ -1126,7 +1110,6 @@ static void rtsx_pci_power_off(struct rtsx_pcr *pcr, u8 pm_state)
if (pcr->ops->force_power_down)
pcr->ops->force_power_down(pcr, pm_state);
}
#endif
void rtsx_pci_enable_ocp(struct rtsx_pcr *pcr)
{
@ -1202,6 +1185,36 @@ void rtsx_pci_clear_ocpstat(struct rtsx_pcr *pcr)
}
}
void rtsx_pci_enable_oobs_polling(struct rtsx_pcr *pcr)
{
u16 val;
if ((PCI_PID(pcr) != PID_525A) && (PCI_PID(pcr) != PID_5260)) {
rtsx_pci_read_phy_register(pcr, 0x01, &val);
val |= 1<<9;
rtsx_pci_write_phy_register(pcr, 0x01, val);
}
rtsx_pci_write_register(pcr, REG_CFG_OOBS_OFF_TIMER, 0xFF, 0x32);
rtsx_pci_write_register(pcr, REG_CFG_OOBS_ON_TIMER, 0xFF, 0x05);
rtsx_pci_write_register(pcr, REG_CFG_VCM_ON_TIMER, 0xFF, 0x83);
rtsx_pci_write_register(pcr, REG_CFG_OOBS_POLLING, 0xFF, 0xDE);
}
void rtsx_pci_disable_oobs_polling(struct rtsx_pcr *pcr)
{
u16 val;
if ((PCI_PID(pcr) != PID_525A) && (PCI_PID(pcr) != PID_5260)) {
rtsx_pci_read_phy_register(pcr, 0x01, &val);
val &= ~(1<<9);
rtsx_pci_write_phy_register(pcr, 0x01, val);
}
rtsx_pci_write_register(pcr, REG_CFG_VCM_ON_TIMER, 0xFF, 0x03);
rtsx_pci_write_register(pcr, REG_CFG_OOBS_POLLING, 0xFF, 0x00);
}
int rtsx_sd_power_off_card3v3(struct rtsx_pcr *pcr)
{
rtsx_pci_write_register(pcr, CARD_CLK_EN, SD_CLK_EN |
@ -1231,9 +1244,13 @@ int rtsx_ms_power_off_card3v3(struct rtsx_pcr *pcr)
static int rtsx_pci_init_hw(struct rtsx_pcr *pcr)
{
struct pci_dev *pdev = pcr->pci;
int err;
pcr->pcie_cap = pci_find_capability(pcr->pci, PCI_CAP_ID_EXP);
if (PCI_PID(pcr) == PID_5228)
rtsx_pci_write_register(pcr, RTS5228_LDO1_CFG1, RTS5228_LDO1_SR_TIME_MASK,
RTS5228_LDO1_SR_0_5);
rtsx_pci_writel(pcr, RTSX_HCBAR, pcr->host_cmds_addr);
rtsx_pci_enable_bus_int(pcr);
@ -1280,6 +1297,9 @@ static int rtsx_pci_init_hw(struct rtsx_pcr *pcr)
if (PCI_PID(pcr) == PID_5261)
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_CTL2, 0xFF,
RTS5261_SSC_DEPTH_2M);
else if (PCI_PID(pcr) == PID_5228)
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_CTL2, 0xFF,
RTS5228_SSC_DEPTH_2M);
else
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SSC_CTL2, 0xFF, 0x12);
@ -1314,6 +1334,7 @@ static int rtsx_pci_init_hw(struct rtsx_pcr *pcr)
case PID_525A:
case PID_5260:
case PID_5261:
case PID_5228:
rtsx_pci_write_register(pcr, PM_CLK_FORCE_CTL, 1, 1);
break;
default:
@ -1324,9 +1345,10 @@ static int rtsx_pci_init_hw(struct rtsx_pcr *pcr)
rtsx_pci_init_ocp(pcr);
/* Enable clk_request_n to enable clock power management */
rtsx_pci_write_config_byte(pcr, pcr->pcie_cap + PCI_EXP_LNKCTL + 1, 1);
pcie_capability_write_word(pdev, PCI_EXP_LNKCTL,
PCI_EXP_LNKCTL_CLKREQ_EN);
/* Enter L1 when host tx idle */
rtsx_pci_write_config_byte(pcr, 0x70F, 0x5B);
pci_write_config_byte(pdev, 0x70F, 0x5B);
if (pcr->ops->extra_init_hw) {
err = pcr->ops->extra_init_hw(pcr);
@ -1401,6 +1423,10 @@ static int rtsx_pci_init_chip(struct rtsx_pcr *pcr)
case 0x5261:
rts5261_init_params(pcr);
break;
case 0x5228:
rts5228_init_params(pcr);
break;
}
pcr_dbg(pcr, "PID: 0x%04x, IC version: 0x%02x\n",
@ -1604,10 +1630,9 @@ static void rtsx_pci_remove(struct pci_dev *pcidev)
pci_name(pcidev), (int)pcidev->vendor, (int)pcidev->device);
}
#ifdef CONFIG_PM
static int rtsx_pci_suspend(struct pci_dev *pcidev, pm_message_t state)
static int __maybe_unused rtsx_pci_suspend(struct device *dev_d)
{
struct pci_dev *pcidev = to_pci_dev(dev_d);
struct pcr_handle *handle;
struct rtsx_pcr *pcr;
@ -1623,17 +1648,15 @@ static int rtsx_pci_suspend(struct pci_dev *pcidev, pm_message_t state)
rtsx_pci_power_off(pcr, HOST_ENTER_S3);
pci_save_state(pcidev);
pci_enable_wake(pcidev, pci_choose_state(pcidev, state), 0);
pci_disable_device(pcidev);
pci_set_power_state(pcidev, pci_choose_state(pcidev, state));
device_wakeup_disable(dev_d);
mutex_unlock(&pcr->pcr_mutex);
return 0;
}
static int rtsx_pci_resume(struct pci_dev *pcidev)
static int __maybe_unused rtsx_pci_resume(struct device *dev_d)
{
struct pci_dev *pcidev = to_pci_dev(dev_d);
struct pcr_handle *handle;
struct rtsx_pcr *pcr;
int ret = 0;
@ -1645,13 +1668,6 @@ static int rtsx_pci_resume(struct pci_dev *pcidev)
mutex_lock(&pcr->pcr_mutex);
pci_set_power_state(pcidev, PCI_D0);
pci_restore_state(pcidev);
ret = pci_enable_device(pcidev);
if (ret)
goto out;
pci_set_master(pcidev);
ret = rtsx_pci_write_register(pcr, HOST_SLEEP_STATE, 0x03, 0x00);
if (ret)
goto out;
@ -1667,6 +1683,8 @@ out:
return ret;
}
#ifdef CONFIG_PM
static void rtsx_pci_shutdown(struct pci_dev *pcidev)
{
struct pcr_handle *handle;
@ -1686,19 +1704,18 @@ static void rtsx_pci_shutdown(struct pci_dev *pcidev)
#else /* CONFIG_PM */
#define rtsx_pci_suspend NULL
#define rtsx_pci_resume NULL
#define rtsx_pci_shutdown NULL
#endif /* CONFIG_PM */
static SIMPLE_DEV_PM_OPS(rtsx_pci_pm_ops, rtsx_pci_suspend, rtsx_pci_resume);
static struct pci_driver rtsx_pci_driver = {
.name = DRV_NAME_RTSX_PCI,
.id_table = rtsx_pci_ids,
.probe = rtsx_pci_probe,
.remove = rtsx_pci_remove,
.suspend = rtsx_pci_suspend,
.resume = rtsx_pci_resume,
.driver.pm = &rtsx_pci_pm_ops,
.shutdown = rtsx_pci_shutdown,
};
module_pci_driver(rtsx_pci_driver);

View File

@ -53,6 +53,7 @@ void rts525a_init_params(struct rtsx_pcr *pcr);
void rtl8411b_init_params(struct rtsx_pcr *pcr);
void rts5260_init_params(struct rtsx_pcr *pcr);
void rts5261_init_params(struct rtsx_pcr *pcr);
void rts5228_init_params(struct rtsx_pcr *pcr);
static inline u8 map_sd_drive(int idx)
{
@ -70,6 +71,8 @@ static inline u8 map_sd_drive(int idx)
#define rts5209_vendor_setting1_valid(reg) (!((reg) & 0x80))
#define rts5209_vendor_setting2_valid(reg) ((reg) & 0x80)
#define rtsx_check_mmc_support(reg) ((reg) & 0x10)
#define rtsx_reg_to_rtd3(reg) ((reg) & 0x02)
#define rtsx_reg_to_aspm(reg) (((reg) >> 28) & 0x03)
#define rtsx_reg_to_sd30_drive_sel_1v8(reg) (((reg) >> 26) & 0x03)
#define rtsx_reg_to_sd30_drive_sel_3v3(reg) (((reg) >> 5) & 0x03)
@ -100,6 +103,8 @@ void rtsx_pci_disable_ocp(struct rtsx_pcr *pcr);
void rtsx_pci_enable_ocp(struct rtsx_pcr *pcr);
int rtsx_pci_get_ocpstat(struct rtsx_pcr *pcr, u8 *val);
void rtsx_pci_clear_ocpstat(struct rtsx_pcr *pcr);
void rtsx_pci_enable_oobs_polling(struct rtsx_pcr *pcr);
void rtsx_pci_disable_oobs_polling(struct rtsx_pcr *pcr);
int rtsx_sd_power_off_card3v3(struct rtsx_pcr *pcr);
int rtsx_ms_power_off_card3v3(struct rtsx_pcr *pcr);

View File

@ -759,7 +759,7 @@ static int rtsx_usb_post_reset(struct usb_interface *intf)
return 0;
}
static struct usb_device_id rtsx_usb_usb_ids[] = {
static const struct usb_device_id rtsx_usb_usb_ids[] = {
{ USB_DEVICE(0x0BDA, 0x0129) },
{ USB_DEVICE(0x0BDA, 0x0139) },
{ USB_DEVICE(0x0BDA, 0x0140) },

View File

@ -166,37 +166,24 @@ void cb710_set_irq_handler(struct cb710_slot *slot,
}
EXPORT_SYMBOL_GPL(cb710_set_irq_handler);
#ifdef CONFIG_PM
static int cb710_suspend(struct pci_dev *pdev, pm_message_t state)
static int __maybe_unused cb710_suspend(struct device *dev_d)
{
struct pci_dev *pdev = to_pci_dev(dev_d);
struct cb710_chip *chip = pci_get_drvdata(pdev);
devm_free_irq(&pdev->dev, pdev->irq, chip);
pci_save_state(pdev);
pci_disable_device(pdev);
if (state.event & PM_EVENT_SLEEP)
pci_set_power_state(pdev, PCI_D3hot);
return 0;
}
static int cb710_resume(struct pci_dev *pdev)
static int __maybe_unused cb710_resume(struct device *dev_d)
{
struct pci_dev *pdev = to_pci_dev(dev_d);
struct cb710_chip *chip = pci_get_drvdata(pdev);
int err;
pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
err = pcim_enable_device(pdev);
if (err)
return err;
return devm_request_irq(&pdev->dev, pdev->irq,
cb710_irq_handler, IRQF_SHARED, KBUILD_MODNAME, chip);
}
#endif /* CONFIG_PM */
static int cb710_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
@ -312,15 +299,14 @@ static const struct pci_device_id cb710_pci_tbl[] = {
{ 0, }
};
static SIMPLE_DEV_PM_OPS(cb710_pm_ops, cb710_suspend, cb710_resume);
static struct pci_driver cb710_driver = {
.name = KBUILD_MODNAME,
.id_table = cb710_pci_tbl,
.probe = cb710_probe,
.remove = cb710_remove_one,
#ifdef CONFIG_PM
.suspend = cb710_suspend,
.resume = cb710_resume,
#endif
.driver.pm = &cb710_pm_ops,
};
static int __init cb710_init_module(void)

View File

@ -117,6 +117,7 @@ static void sg_dwiter_write_slow(struct sg_mapping_iter *miter, uint32_t data)
/**
* cb710_sg_dwiter_write_next_block() - write next 32-bit word to sg buffer
* @miter: sg mapping iterator used for writing
* @data: data to write to sg buffer
*
* Description:
* Writes 32-bit word starting at byte pointed to by @miter@

View File

@ -175,7 +175,7 @@ static int update_devicetree(struct cxl *adapter, s32 scope)
struct update_nodes_workarea *unwa;
u32 action, node_count;
int token, rc, i;
__be32 *data, drc_index, phandle;
__be32 *data, phandle;
char *buf;
token = rtas_token("ibm,update-nodes");
@ -213,7 +213,7 @@ static int update_devicetree(struct cxl *adapter, s32 scope)
break;
case OPCODE_ADD:
/* nothing to do, just move pointer */
drc_index = *data++;
data++;
break;
}
}

View File

@ -167,7 +167,7 @@ long cxl_h_attach_process(u64 unit_address,
}
}
/**
/*
* cxl_h_detach_process - Detach a process element from a coherent
* platform function.
*/
@ -197,7 +197,7 @@ long cxl_h_detach_process(u64 unit_address, u64 process_token)
}
}
/**
/*
* cxl_h_control_function - This H_CONTROL_CA_FUNCTION hypervisor call allows
* the partition to manipulate or query
* certain coherent platform function behaviors.
@ -238,7 +238,7 @@ static long cxl_h_control_function(u64 unit_address, u64 op,
}
}
/**
/*
* cxl_h_reset_afu - Perform a reset to the coherent platform function.
*/
long cxl_h_reset_afu(u64 unit_address)
@ -249,7 +249,7 @@ long cxl_h_reset_afu(u64 unit_address)
NULL);
}
/**
/*
* cxl_h_suspend_process - Suspend a process from being executed
* Parameter1 = process-token as returned from H_ATTACH_CA_PROCESS when
* process was attached.
@ -262,7 +262,7 @@ long cxl_h_suspend_process(u64 unit_address, u64 process_token)
NULL);
}
/**
/*
* cxl_h_resume_process - Resume a process to be executed
* Parameter1 = process-token as returned from H_ATTACH_CA_PROCESS when
* process was attached.
@ -275,7 +275,7 @@ long cxl_h_resume_process(u64 unit_address, u64 process_token)
NULL);
}
/**
/*
* cxl_h_read_error_state - Checks the error state of the coherent
* platform function.
* R4 contains the error state
@ -288,7 +288,7 @@ long cxl_h_read_error_state(u64 unit_address, u64 *state)
state);
}
/**
/*
* cxl_h_get_afu_err - collect the AFU error buffer
* Parameter1 = byte offset into error buffer to retrieve, valid values
* are between 0 and (ibm,error-buffer-size - 1)
@ -304,7 +304,7 @@ long cxl_h_get_afu_err(u64 unit_address, u64 offset,
NULL);
}
/**
/*
* cxl_h_get_config - collect configuration record for the
* coherent platform function
* Parameter1 = # of configuration record to retrieve, valid values are
@ -324,7 +324,7 @@ long cxl_h_get_config(u64 unit_address, u64 cr_num, u64 offset,
NULL);
}
/**
/*
* cxl_h_terminate_process - Terminate the process before completion
* Parameter1 = process-token as returned from H_ATTACH_CA_PROCESS when
* process was attached.
@ -337,7 +337,7 @@ long cxl_h_terminate_process(u64 unit_address, u64 process_token)
NULL);
}
/**
/*
* cxl_h_collect_vpd - Collect VPD for the coherent platform function.
* Parameter1 = # of VPD record to retrieve, valid values are between 0
* and (ibm,#config-records - 1).
@ -355,7 +355,7 @@ long cxl_h_collect_vpd(u64 unit_address, u64 record, u64 list_address,
out);
}
/**
/*
* cxl_h_get_fn_error_interrupt - Read the function-wide error data based on an interrupt
*/
long cxl_h_get_fn_error_interrupt(u64 unit_address, u64 *reg)
@ -365,7 +365,7 @@ long cxl_h_get_fn_error_interrupt(u64 unit_address, u64 *reg)
0, 0, 0, 0, reg);
}
/**
/*
* cxl_h_ack_fn_error_interrupt - Acknowledge function-wide error data
* based on an interrupt
* Parameter1 = value to write to the function-wide error interrupt register
@ -378,7 +378,7 @@ long cxl_h_ack_fn_error_interrupt(u64 unit_address, u64 value)
NULL);
}
/**
/*
* cxl_h_get_error_log - Retrieve the Platform Log ID (PLID) of
* an error log
*/
@ -390,7 +390,7 @@ long cxl_h_get_error_log(u64 unit_address, u64 value)
NULL);
}
/**
/*
* cxl_h_collect_int_info - Collect interrupt info about a coherent
* platform function after an interrupt occurred.
*/
@ -425,7 +425,7 @@ long cxl_h_collect_int_info(u64 unit_address, u64 process_token,
}
}
/**
/*
* cxl_h_control_faults - Control the operation of a coherent platform
* function after a fault occurs.
*
@ -470,7 +470,7 @@ long cxl_h_control_faults(u64 unit_address, u64 process_token,
}
}
/**
/*
* cxl_h_control_facility - This H_CONTROL_CA_FACILITY hypervisor call
* allows the partition to manipulate or query
* certain coherent platform facility behaviors.
@ -509,7 +509,7 @@ static long cxl_h_control_facility(u64 unit_address, u64 op,
}
}
/**
/*
* cxl_h_reset_adapter - Perform a reset to the coherent platform facility.
*/
long cxl_h_reset_adapter(u64 unit_address)
@ -520,7 +520,7 @@ long cxl_h_reset_adapter(u64 unit_address)
NULL);
}
/**
/*
* cxl_h_collect_vpd - Collect VPD for the coherent platform function.
* Parameter1 = 4K naturally aligned real buffer containing block
* list entries
@ -536,7 +536,7 @@ long cxl_h_collect_vpd_adapter(u64 unit_address, u64 list_address,
out);
}
/**
/*
* cxl_h_download_facility - This H_DOWNLOAD_CA_FACILITY
* hypervisor call provide platform support for
* downloading a base adapter image to the coherent
@ -616,7 +616,7 @@ static long cxl_h_download_facility(u64 unit_address, u64 op,
}
}
/**
/*
* cxl_h_download_adapter_image - Download the base image to the coherent
* platform facility.
*/
@ -629,7 +629,7 @@ long cxl_h_download_adapter_image(u64 unit_address,
list_address, num, out);
}
/**
/*
* cxl_h_validate_adapter_image - Validate the base image in the coherent
* platform facility.
*/

View File

@ -624,7 +624,7 @@ static struct afu_config_record *cxl_sysfs_afu_new_cr(struct cxl_afu *afu, int c
rc = kobject_init_and_add(&cr->kobj, &afu_config_record_type,
&afu->dev.kobj, "cr%i", cr->cr);
if (rc)
goto err;
goto err1;
rc = sysfs_create_bin_file(&cr->kobj, &cr->config_attr);
if (rc)

View File

@ -150,7 +150,7 @@ static int cxl_pcie_read_config(struct pci_bus *bus, unsigned int devfn,
out:
cxl_afu_configured_put(afu);
return rc ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL;
return rc ? PCIBIOS_DEVICE_NOT_FOUND : 0;
}
static int cxl_pcie_write_config(struct pci_bus *bus, unsigned int devfn,
@ -184,7 +184,7 @@ static int cxl_pcie_write_config(struct pci_bus *bus, unsigned int devfn,
out:
cxl_afu_configured_put(afu);
return rc ? PCIBIOS_SET_FAILED : PCIBIOS_SUCCESSFUL;
return rc ? PCIBIOS_SET_FAILED : 0;
}
static struct pci_ops cxl_pcie_pci_ops =

View File

@ -66,13 +66,13 @@
Path Models", IEEE Transactions on communications, COM-25,
No. 6, June
1977.
http://www.rowetel.com/images/echo/dual_path_paper.pdf
https://www.rowetel.com/images/echo/dual_path_paper.pdf
[2] The classic, very useful paper that tells you how to
actually build a real world echo canceller:
Messerschmitt, Hedberg, Cole, Haoui, Winship, "Digital Voice
Echo Canceller with a TMS320020,
http://www.rowetel.com/images/echo/spra129.pdf
https://www.rowetel.com/images/echo/spra129.pdf
[3] I have written a series of blog posts on this work, here is
Part 1: http://www.rowetel.com/blog/?p=18
@ -80,7 +80,7 @@
[4] The source code http://svn.rowetel.com/software/oslec/
[5] A nice reference on LMS filters:
http://en.wikipedia.org/wiki/Least_mean_squares_filter
https://en.wikipedia.org/wiki/Least_mean_squares_filter
Credits:

View File

@ -225,7 +225,7 @@ static const struct of_device_id at24_of_match[] = {
};
MODULE_DEVICE_TABLE(of, at24_of_match);
static const struct acpi_device_id at24_acpi_ids[] = {
static const struct acpi_device_id __maybe_unused at24_acpi_ids[] = {
{ "INT3499", (kernel_ulong_t)&at24_data_INT3499 },
{ "TPF0001", (kernel_ulong_t)&at24_data_24c1024 },
{ /* END OF LIST */ }

View File

@ -228,7 +228,7 @@ EXPORT_SYMBOL_GPL(eeprom_93cx6_multiread);
/**
* eeprom_93cx6_readb - Read a byte from eeprom
* @eeprom: Pointer to eeprom structure
* @word: Byte index from where we should start reading
* @byte: Byte index from where we should start reading
* @data: target pointer where the information will have to be stored
*
* This function will read a byte of the eeprom data
@ -270,7 +270,7 @@ EXPORT_SYMBOL_GPL(eeprom_93cx6_readb);
* @eeprom: Pointer to eeprom structure
* @byte: Index from where we should start reading
* @data: target pointer where the information will have to be stored
* @words: Number of bytes that should be read.
* @bytes: Number of bytes that should be read.
*
* This function will read all requested bytes from the eeprom,
* this is done by calling eeprom_93cx6_readb() multiple times.

View File

@ -103,7 +103,9 @@ EXPORT_SYMBOL_GPL(enclosure_for_each_device);
* enclosure_register - register device as an enclosure
*
* @dev: device containing the enclosure
* @name: chosen device name
* @components: number of components in the enclosure
* @cb: platform call-backs
*
* This sets up the device for being an enclosure. Note that @dev does
* not have to be a dedicated enclosure device. It may be some other type
@ -266,7 +268,7 @@ static const struct attribute_group *enclosure_component_groups[];
/**
* enclosure_component_alloc - prepare a new enclosure component
* @edev: the enclosure to add the component
* @num: the device number
* @number: the device number
* @type: the type of component being added
* @name: an optional name to appear in sysfs (leave NULL if none)
*
@ -347,7 +349,7 @@ EXPORT_SYMBOL_GPL(enclosure_component_register);
/**
* enclosure_add_device - add a device as being part of an enclosure
* @edev: the enclosure device being added to.
* @num: the number of the component
* @component: the number of the component
* @dev: the device being added
*
* Declares a real device to reside in slot (or identifier) @num of an
@ -389,7 +391,7 @@ EXPORT_SYMBOL_GPL(enclosure_add_device);
/**
* enclosure_remove_device - remove a device from an enclosure
* @edev: the enclosure device
* @num: the number of the component to remove
* @dev: device to remove/put
*
* Returns zero on success or an error.
*

View File

@ -165,6 +165,7 @@ static void genwqe_dev_free(struct genwqe_dev *cd)
/**
* genwqe_bus_reset() - Card recovery
* @cd: GenWQE device information
*
* pci_reset_function() will recover the device and ensure that the
* registers are accessible again when it completes with success. If
@ -262,6 +263,7 @@ static void genwqe_tweak_hardware(struct genwqe_dev *cd)
/**
* genwqe_recovery_on_fatal_gfir_required() - Version depended actions
* @cd: GenWQE device information
*
* Bitstreams older than 2013-02-17 have a bug where fatal GFIRs must
* be ignored. This is e.g. true for the bitstream we gave to the card
@ -280,6 +282,7 @@ int genwqe_flash_readback_fails(struct genwqe_dev *cd)
/**
* genwqe_T_psec() - Calculate PF/VF timeout register content
* @cd: GenWQE device information
*
* Note: From a design perspective it turned out to be a bad idea to
* use codes here to specifiy the frequency/speed values. An old
@ -303,6 +306,7 @@ static int genwqe_T_psec(struct genwqe_dev *cd)
/**
* genwqe_setup_pf_jtimer() - Setup PF hardware timeouts for DDCB execution
* @cd: GenWQE device information
*
* Do this _after_ card_reset() is called. Otherwise the values will
* vanish. The settings need to be done when the queues are inactive.
@ -329,6 +333,7 @@ static bool genwqe_setup_pf_jtimer(struct genwqe_dev *cd)
/**
* genwqe_setup_vf_jtimer() - Setup VF hardware timeouts for DDCB execution
* @cd: GenWQE device information
*/
static bool genwqe_setup_vf_jtimer(struct genwqe_dev *cd)
{
@ -543,6 +548,7 @@ static int genwqe_start(struct genwqe_dev *cd)
/**
* genwqe_stop() - Stop card operation
* @cd: GenWQE device information
*
* Recovery notes:
* As long as genwqe_thread runs we might access registers during
@ -569,6 +575,8 @@ static int genwqe_stop(struct genwqe_dev *cd)
/**
* genwqe_recover_card() - Try to recover the card if it is possible
* @cd: GenWQE device information
* @fatal_err: Indicate whether to attempt soft reset
*
* If fatal_err is set no register access is possible anymore. It is
* likely that genwqe_start fails in that situation. Proper error
@ -618,6 +626,7 @@ static int genwqe_health_check_cond(struct genwqe_dev *cd, u64 *gfir)
/**
* genwqe_fir_checking() - Check the fault isolation registers of the card
* @cd: GenWQE device information
*
* If this code works ok, can be tried out with help of the genwqe_poke tool:
* sudo ./tools/genwqe_poke 0x8 0xfefefefefef
@ -762,6 +771,7 @@ static u64 genwqe_fir_checking(struct genwqe_dev *cd)
/**
* genwqe_pci_fundamental_reset() - trigger a PCIe fundamental reset on the slot
* @pci_dev: PCI device information struct
*
* Note: pci_set_pcie_reset_state() is not implemented on all archs, so this
* reset method will not work in all cases.
@ -826,8 +836,9 @@ static int genwqe_platform_recovery(struct genwqe_dev *cd)
return rc;
}
/*
/**
* genwqe_reload_bistream() - reload card bitstream
* @cd: GenWQE device information
*
* Set the appropriate register and call fundamental reset to reaload the card
* bitstream.
@ -880,6 +891,7 @@ static int genwqe_reload_bistream(struct genwqe_dev *cd)
/**
* genwqe_health_thread() - Health checking thread
* @data: GenWQE device information
*
* This thread is only started for the PF of the card.
*
@ -1043,18 +1055,17 @@ static int genwqe_health_thread_running(struct genwqe_dev *cd)
static int genwqe_health_check_stop(struct genwqe_dev *cd)
{
int rc;
if (!genwqe_health_thread_running(cd))
return -EIO;
rc = kthread_stop(cd->health_thread);
kthread_stop(cd->health_thread);
cd->health_thread = NULL;
return 0;
}
/**
* genwqe_pci_setup() - Allocate PCIe related resources for our card
* @cd: GenWQE device information
*/
static int genwqe_pci_setup(struct genwqe_dev *cd)
{
@ -1140,6 +1151,7 @@ static int genwqe_pci_setup(struct genwqe_dev *cd)
/**
* genwqe_pci_remove() - Free PCIe related resources for our card
* @cd: GenWQE device information
*/
static void genwqe_pci_remove(struct genwqe_dev *cd)
{
@ -1154,7 +1166,8 @@ static void genwqe_pci_remove(struct genwqe_dev *cd)
/**
* genwqe_probe() - Device initialization
* @pdev: PCI device information struct
* @pci_dev: PCI device information struct
* @id: PCI device ID
*
* Callable for multiple cards. This function is called on bind.
*
@ -1214,6 +1227,7 @@ static int genwqe_probe(struct pci_dev *pci_dev,
/**
* genwqe_remove() - Called when device is removed (hot-plugable)
* @pci_dev: PCI device information struct
*
* Or when driver is unloaded respecitively when unbind is done.
*/
@ -1233,8 +1247,10 @@ static void genwqe_remove(struct pci_dev *pci_dev)
genwqe_dev_free(cd);
}
/*
/**
* genwqe_err_error_detected() - Error detection callback
* @pci_dev: PCI device information struct
* @state: PCI channel state
*
* This callback is called by the PCI subsystem whenever a PCI bus
* error is detected.
@ -1324,7 +1340,7 @@ static int genwqe_sriov_configure(struct pci_dev *dev, int numvfs)
return 0;
}
static struct pci_error_handlers genwqe_err_handler = {
static const struct pci_error_handlers genwqe_err_handler = {
.error_detected = genwqe_err_error_detected,
.mmio_enabled = genwqe_err_result_none,
.slot_reset = genwqe_err_slot_reset,
@ -1342,6 +1358,8 @@ static struct pci_driver genwqe_driver = {
/**
* genwqe_devnode() - Set default access mode for genwqe devices.
* @dev: Pointer to device (unused)
* @mode: Carrier to pass-back given mode (permissions)
*
* Default mode should be rw for everybody. Do not change default
* device name.

View File

@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
/**
/*
* IBM Accelerator Family 'GenWQE'
*
* (C) Copyright IBM Corp. 2013
@ -244,10 +244,13 @@ static int ddcb_requ_finished(struct genwqe_dev *cd, struct ddcb_requ *req)
(cd->card_state != GENWQE_CARD_USED);
}
#define RET_DDCB_APPENDED 1
#define RET_DDCB_TAPPED 2
/**
* enqueue_ddcb() - Enqueue a DDCB
* @cd: pointer to genwqe device descriptor
* @queue: queue this operation should be done on
* @pddcb: pointer to ddcb structure
* @ddcb_no: pointer to ddcb number being tapped
*
* Start execution of DDCB by tapping or append to queue via NEXT
@ -259,9 +262,6 @@ static int ddcb_requ_finished(struct genwqe_dev *cd, struct ddcb_requ *req)
* Return: 1 if new DDCB is appended to previous
* 2 if DDCB queue is tapped via register/simulation
*/
#define RET_DDCB_APPENDED 1
#define RET_DDCB_TAPPED 2
static int enqueue_ddcb(struct genwqe_dev *cd, struct ddcb_queue *queue,
struct ddcb *pddcb, int ddcb_no)
{
@ -316,6 +316,8 @@ static int enqueue_ddcb(struct genwqe_dev *cd, struct ddcb_queue *queue,
/**
* copy_ddcb_results() - Copy output state from real DDCB to request
* @req: pointer to requsted DDCB parameters
* @ddcb_no: pointer to ddcb number being tapped
*
* Copy DDCB ASV to request struct. There is no endian
* conversion made, since data structure in ASV is still
@ -356,6 +358,7 @@ static void copy_ddcb_results(struct ddcb_requ *req, int ddcb_no)
/**
* genwqe_check_ddcb_queue() - Checks DDCB queue for completed work equests.
* @cd: pointer to genwqe device descriptor
* @queue: queue to be checked
*
* Return: Number of DDCBs which were finished
*/
@ -553,6 +556,8 @@ int __genwqe_wait_ddcb(struct genwqe_dev *cd, struct ddcb_requ *req)
/**
* get_next_ddcb() - Get next available DDCB
* @cd: pointer to genwqe device descriptor
* @queue: DDCB queue
* @num: internal DDCB number
*
* DDCB's content is completely cleared but presets for PRE and
* SEQNUM. This function must only be called when ddcb_lock is held.
@ -900,7 +905,7 @@ int __genwqe_enqueue_ddcb(struct genwqe_dev *cd, struct ddcb_requ *req,
/**
* __genwqe_execute_raw_ddcb() - Setup and execute DDCB
* @cd: pointer to genwqe device descriptor
* @req: user provided DDCB request
* @cmd: user provided DDCB command
* @f_flags: file mode: blocking, non-blocking
*/
int __genwqe_execute_raw_ddcb(struct genwqe_dev *cd,
@ -965,6 +970,7 @@ int __genwqe_execute_raw_ddcb(struct genwqe_dev *cd,
/**
* genwqe_next_ddcb_ready() - Figure out if the next DDCB is already finished
* @cd: pointer to genwqe device descriptor
*
* We use this as condition for our wait-queue code.
*/
@ -993,6 +999,7 @@ static int genwqe_next_ddcb_ready(struct genwqe_dev *cd)
/**
* genwqe_ddcbs_in_flight() - Check how many DDCBs are in flight
* @cd: pointer to genwqe device descriptor
*
* Keep track on the number of DDCBs which ware currently in the
* queue. This is needed for statistics as well as conditon if we want
@ -1171,6 +1178,7 @@ static irqreturn_t genwqe_vf_isr(int irq, void *dev_id)
/**
* genwqe_card_thread() - Work thread for the DDCB queue
* @data: pointer to genwqe device descriptor
*
* The idea is to check if there are DDCBs in processing. If there are
* some finished DDCBs, we process them and wakeup the
@ -1299,6 +1307,7 @@ int genwqe_setup_service_layer(struct genwqe_dev *cd)
/**
* queue_wake_up_all() - Handles fatal error case
* @cd: pointer to genwqe device descriptor
*
* The PCI device got unusable and we have to stop all pending
* requests as fast as we can. The code after this must purge the
@ -1323,6 +1332,7 @@ static int queue_wake_up_all(struct genwqe_dev *cd)
/**
* genwqe_finish_queue() - Remove any genwqe devices and user-interfaces
* @cd: pointer to genwqe device descriptor
*
* Relies on the pre-condition that there are no users of the card
* device anymore e.g. with open file-descriptors.

View File

@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
/**
/*
* IBM Accelerator Family 'GenWQE'
*
* (C) Copyright IBM Corp. 2013

View File

@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
/**
/*
* IBM Accelerator Family 'GenWQE'
*
* (C) Copyright IBM Corp. 2013
@ -87,7 +87,7 @@ static int genwqe_del_pin(struct genwqe_file *cfile, struct dma_mapping *m)
* @cfile: Descriptor of opened file
* @u_addr: User virtual address
* @size: Size of buffer
* @dma_addr: DMA address to be updated
* @virt_addr: Virtual address to be updated
*
* Return: Pointer to the corresponding mapping NULL if not found
*/
@ -144,6 +144,7 @@ static void __genwqe_del_mapping(struct genwqe_file *cfile,
* @u_addr: user virtual address
* @size: size of buffer
* @dma_addr: DMA address to be updated
* @virt_addr: Virtual address to be updated
* Return: Pointer to the corresponding mapping NULL if not found
*/
static struct dma_mapping *__genwqe_search_mapping(struct genwqe_file *cfile,
@ -249,6 +250,8 @@ static void genwqe_remove_pinnings(struct genwqe_file *cfile)
/**
* genwqe_kill_fasync() - Send signal to all processes with open GenWQE files
* @cd: GenWQE device information
* @sig: Signal to send out
*
* E.g. genwqe_send_signal(cd, SIGIO);
*/
@ -380,6 +383,7 @@ static void genwqe_vma_open(struct vm_area_struct *vma)
/**
* genwqe_vma_close() - Called each time when vma is unmapped
* @vma: VMA area to close
*
* Free memory which got allocated by GenWQE mmap().
*/
@ -416,6 +420,8 @@ static const struct vm_operations_struct genwqe_vma_ops = {
/**
* genwqe_mmap() - Provide contignous buffers to userspace
* @filp: File pointer (unused)
* @vma: VMA area to map
*
* We use mmap() to allocate contignous buffers used for DMA
* transfers. After the buffer is allocated we remap it to user-space
@ -484,16 +490,15 @@ static int genwqe_mmap(struct file *filp, struct vm_area_struct *vma)
return rc;
}
#define FLASH_BLOCK 0x40000 /* we use 256k blocks */
/**
* do_flash_update() - Excute flash update (write image or CVPD)
* @cd: genwqe device
* @cfile: Descriptor of opened file
* @load: details about image load
*
* Return: 0 if successful
*/
#define FLASH_BLOCK 0x40000 /* we use 256k blocks */
static int do_flash_update(struct genwqe_file *cfile,
struct genwqe_bitstream *load)
{
@ -820,6 +825,8 @@ static int genwqe_unpin_mem(struct genwqe_file *cfile, struct genwqe_mem *m)
/**
* ddcb_cmd_cleanup() - Remove dynamically created fixup entries
* @cfile: Descriptor of opened file
* @req: DDCB work request
*
* Only if there are any. Pinnings are not removed.
*/
@ -844,6 +851,8 @@ static int ddcb_cmd_cleanup(struct genwqe_file *cfile, struct ddcb_requ *req)
/**
* ddcb_cmd_fixups() - Establish DMA fixups/sglists for user memory references
* @cfile: Descriptor of opened file
* @req: DDCB work request
*
* Before the DDCB gets executed we need to handle the fixups. We
* replace the user-space addresses with DMA addresses or do
@ -974,6 +983,8 @@ static int ddcb_cmd_fixups(struct genwqe_file *cfile, struct ddcb_requ *req)
/**
* genwqe_execute_ddcb() - Execute DDCB using userspace address fixups
* @cfile: Descriptor of opened file
* @cmd: Command identifier (passed from user)
*
* The code will build up the translation tables or lookup the
* contignous memory allocation table to find the right translations
@ -1339,6 +1350,7 @@ static int genwqe_inform_and_stop_processes(struct genwqe_dev *cd)
/**
* genwqe_device_remove() - Remove genwqe's char device
* @cd: GenWQE device information
*
* This function must be called after the client devices are removed
* because it will free the major/minor number range for the genwqe

View File

@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
/**
/*
* IBM Accelerator Family 'GenWQE'
*
* (C) Copyright IBM Corp. 2013
@ -129,7 +129,7 @@ static ssize_t base_clock_show(struct device *dev,
}
static DEVICE_ATTR_RO(base_clock);
/**
/*
* curr_bitstream_show() - Show the current bitstream id
*
* There is a bug in some old versions of the CPLD which selects the
@ -156,7 +156,7 @@ static ssize_t curr_bitstream_show(struct device *dev,
}
static DEVICE_ATTR_RO(curr_bitstream);
/**
/*
* next_bitstream_show() - Show the next activated bitstream
*
* IO_SLC_CFGREG_SOFTRESET: This register can only be accessed by the PF.
@ -260,7 +260,7 @@ static struct attribute *genwqe_normal_attributes[] = {
NULL,
};
/**
/*
* genwqe_is_visible() - Determine if sysfs attribute should be visible or not
*
* VFs have restricted mmio capabilities, so not all sysfs entries

View File

@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
/**
/*
* IBM Accelerator Family 'GenWQE'
*
* (C) Copyright IBM Corp. 2013
@ -129,6 +129,9 @@ u32 __genwqe_readl(struct genwqe_dev *cd, u64 byte_offs)
/**
* genwqe_read_app_id() - Extract app_id
* @cd: genwqe device descriptor
* @app_name: carrier used to pass-back name
* @len: length of data for name
*
* app_unitcfg need to be filled with valid data first
*/
@ -183,7 +186,7 @@ void genwqe_init_crc32(void)
* @init: initial crc (0xffffffff at start)
*
* polynomial = x^32 * + x^29 + x^18 + x^14 + x^3 + 1 (0x20044009)
*
* Example: 4 bytes 0x01 0x02 0x03 0x04 with init=0xffffffff should
* result in a crc32 of 0xf33cb7d3.
*
@ -277,7 +280,7 @@ static int genwqe_sgl_size(int num_pages)
return roundup(len, PAGE_SIZE);
}
/**
/*
* genwqe_alloc_sync_sgl() - Allocate memory for sgl and overlapping pages
*
* Allocates memory for sgl and overlapping pages. Pages which might
@ -460,6 +463,8 @@ int genwqe_setup_sgl(struct genwqe_dev *cd, struct genwqe_sgl *sgl,
/**
* genwqe_free_sync_sgl() - Free memory for sgl and overlapping pages
* @cd: genwqe device descriptor
* @sgl: scatter gather list describing user-space memory
*
* After the DMA transfer has been completed we free the memory for
* the sgl and the cached pages. Data is being transferred from cached
@ -710,6 +715,7 @@ int genwqe_read_softreset(struct genwqe_dev *cd)
/**
* genwqe_set_interrupt_capability() - Configure MSI capability structure
* @cd: pointer to the device
* @count: number of vectors to allocate
* Return: 0 if no error
*/
int genwqe_set_interrupt_capability(struct genwqe_dev *cd, int count)
@ -738,7 +744,7 @@ void genwqe_reset_interrupt_capability(struct genwqe_dev *cd)
* @i: index to desired entry
* @m: maximum possible entries
* @addr: addr which is read
* @index: index in debug array
* @idx: index in debug array
* @val: read value
*/
static int set_reg_idx(struct genwqe_dev *cd, struct genwqe_reg *r,
@ -818,6 +824,8 @@ int genwqe_read_ffdc_regs(struct genwqe_dev *cd, struct genwqe_reg *regs,
/**
* genwqe_ffdc_buff_size() - Calculates the number of dump registers
* @cd: genwqe device descriptor
* @uid: unit ID
*/
int genwqe_ffdc_buff_size(struct genwqe_dev *cd, int uid)
{
@ -871,6 +879,10 @@ int genwqe_ffdc_buff_size(struct genwqe_dev *cd, int uid)
/**
* genwqe_ffdc_buff_read() - Implements LogoutExtendedErrorRegisters procedure
* @cd: genwqe device descriptor
* @uid: unit ID
* @regs: register information
* @max_regs: number of register entries
*/
int genwqe_ffdc_buff_read(struct genwqe_dev *cd, int uid,
struct genwqe_reg *regs, unsigned int max_regs)
@ -956,6 +968,10 @@ int genwqe_ffdc_buff_read(struct genwqe_dev *cd, int uid,
/**
* genwqe_write_vreg() - Write register in virtual window
* @cd: genwqe device descriptor
* @reg: register (byte) offset within BAR
* @val: value to write
* @func: PCI virtual function
*
* Note, these registers are only accessible to the PF through the
* VF-window. It is not intended for the VF to access.
@ -969,6 +985,9 @@ int genwqe_write_vreg(struct genwqe_dev *cd, u32 reg, u64 val, int func)
/**
* genwqe_read_vreg() - Read register in virtual window
* @cd: genwqe device descriptor
* @reg: register (byte) offset within BAR
* @func: PCI virtual function
*
* Note, these registers are only accessible to the PF through the
* VF-window. It is not intended for the VF to access.
@ -981,6 +1000,7 @@ u64 genwqe_read_vreg(struct genwqe_dev *cd, u32 reg, int func)
/**
* genwqe_base_clock_frequency() - Deteremine base clock frequency of the card
* @cd: genwqe device descriptor
*
* Note: From a design perspective it turned out to be a bad idea to
* use codes here to specifiy the frequency/speed values. An old
@ -1005,6 +1025,7 @@ int genwqe_base_clock_frequency(struct genwqe_dev *cd)
/**
* genwqe_stop_traps() - Stop traps
* @cd: genwqe device descriptor
*
* Before reading out the analysis data, we need to stop the traps.
*/
@ -1015,6 +1036,7 @@ void genwqe_stop_traps(struct genwqe_dev *cd)
/**
* genwqe_start_traps() - Start traps
* @cd: genwqe device descriptor
*
* After having read the data, we can/must enable the traps again.
*/

Some files were not shown because too many files have changed in this diff Show More