soc: fixes for 7.1, part 2
Following the previous set of fixes, this addresses another significant
number of small issues found in firmware drivers (tee, optee, qcomtee,
qcom ice, exynos acpm) drivers through various tools. This is about
error handling, resource leaks, concurrency and a use-after-free bug.
The fixes for the Qualcomm ICE driver also introduce interface changes
in the UFS and MMC drivers using it.
Outside of firmware drivers, there are a few fixes across the tree:
- Minor driver code mistakes in the Atmel EBI memory controller,
the i.MX soc ID driver and socfpga boot logic
- A defconfig change to avoid a boot time regression on multiple
qualcomm boards
- Device tree fixes for qualcomm, at91 and gemini, addressing
mostly minor configuration mistakes
-----BEGIN PGP SIGNATURE-----
iQIzBAABCgAdFiEEo6/YBQwIrVS28WGKmmx57+YAGNkFAmofFFQACgkQmmx57+YA
GNkoZxAAjEoE6xgVJjQBQug02+puOll3DSjYjYahg434nUoIpfY4bU4247eUtvxi
QU5kSRQbMaYBpBM5pqgqdG0P0KiP8UsrDWgGr1CbHhCtO2H2cJ6ICUFAXmgpZ+n3
P7R4hROu+EoRb6urgRG6koL6LYId1nRSKOvWsPEz8cXcVE/nwdaYgU6GB9aS2B0v
zAcLGMtACNU9iiDZNW+pt97CkMr38pjEkcmWxfQBSqcjck0JsujHCuCWLwPALKAo
V1aSKPgg1YUMs3+2LeXyhv5rFrBmXfRJ1v7unLKXAvJ9k+DZb63D5AIFT6xjD7Qh
nF/IgPmiFPaYKVskTWS7UHWVLZY7mBstb4gWei1fNE8deCXA35ntuNSg1YkIabvF
s/g5g2/EuiCTobZLO+xAGHJvfB/iVx2k2w6CzYpxXtOOf8CNzskWkRnerK3RF+TM
LIN1JhrZJzAnHL+Z8jv3z2+vo1sUOMuQax723xYoh/7LUUr1yp0hBJExkjJJ8s3q
5GOob3WnjH9n15OAsJvNXlKIWstIi/BPSXyATmca6tDsEnuv3KE9Sok4ZT/Gsjxk
2L/aIlnnu6qX4BlQ7Hrfl2+LDp7jX1RP7MFMGxHscD36ws7ZU9asoUc5MxPrnZno
Oay2HTyiA42YvsN+R6oI331VSTd/hXLemqvP9JpENvSbpuGm2So=
=uqVQ
-----END PGP SIGNATURE-----
Merge tag 'soc-fixes-7.1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc
Pull SoC fixes from Arnd Bergmann:
"Following the previous set of fixes, this addresses another
significant number of small issues found in firmware drivers (tee,
optee, qcomtee, qcom ice, exynos acpm) drivers through various tools.
This is about error handling, resource leaks, concurrency and a
use-after-free bug.
The fixes for the Qualcomm ICE driver also introduce interface changes
in the UFS and MMC drivers using it.
Outside of firmware drivers, there are a few fixes across the tree:
- Minor driver code mistakes in the Atmel EBI memory controller, the
i.MX soc ID driver and socfpga boot logic
- A defconfig change to avoid a boot time regression on multiple
qualcomm boards
- Device tree fixes for qualcomm, at91 and gemini, addressing mostly
minor configuration mistakes"
* tag 'soc-fixes-7.1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc: (28 commits)
firmware: samsung: acpm: Fix infinite loop on sequence number exhaustion
firmware: samsung: acpm: Fix missing LKMM barriers in sequence allocator
firmware: samsung: acpm: Fix false timeouts and Use-After-Free in polling
ARM: dts: gemini: Fix partition offsets
ARM: socfpga: Fix OF node refcount leak in SMP setup
soc: qcom: ice: Fix the error code when 'qcom,ice' property is not found
arm64: dts: qcom: eliza: Add power-domain and iface clk for ice node
arm64: dts: qcom: milos: Add power-domain and iface clk for ice node
tee: qcomtee: add missing va_end in early return qcomtee_object_user_init()
tee: fix params_from_user() error path in tee_ioctl_supp_recv
tee: shm: fix shm leak in register_shm_helper()
tee: fix tee_ioctl_object_invoke_arg padding
arm64: defconfig: Enable PCI M.2 power sequencing driver
scsi: ufs: ufs-qcom: Remove NULL check from devm_of_qcom_ice_get()
mmc: sdhci-msm: Remove NULL check from devm_of_qcom_ice_get()
soc: qcom: ice: Return proper error codes from devm_of_qcom_ice_get() instead of NULL
soc: qcom: ice: Return -ENODEV if the ICE platform device is not found
soc: qcom: ice: Fix race between qcom_ice_probe() and of_qcom_ice_get()
ARM: dts: microchip: sam9x7: fix GMAC clock configuration
firmware: samsung: acpm: Fix mailbox channel leak on probe error
...
master
commit
ba3e43a9e6
|
|
@ -30,6 +30,16 @@ properties:
|
||||||
maxItems: 1
|
maxItems: 1
|
||||||
|
|
||||||
clocks:
|
clocks:
|
||||||
|
minItems: 1
|
||||||
|
maxItems: 2
|
||||||
|
|
||||||
|
clock-names:
|
||||||
|
minItems: 1
|
||||||
|
items:
|
||||||
|
- const: core
|
||||||
|
- const: iface
|
||||||
|
|
||||||
|
power-domains:
|
||||||
maxItems: 1
|
maxItems: 1
|
||||||
|
|
||||||
operating-points-v2: true
|
operating-points-v2: true
|
||||||
|
|
@ -44,6 +54,25 @@ required:
|
||||||
|
|
||||||
additionalProperties: false
|
additionalProperties: false
|
||||||
|
|
||||||
|
allOf:
|
||||||
|
- if:
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
contains:
|
||||||
|
enum:
|
||||||
|
- qcom,eliza-inline-crypto-engine
|
||||||
|
- qcom,milos-inline-crypto-engine
|
||||||
|
|
||||||
|
then:
|
||||||
|
required:
|
||||||
|
- power-domains
|
||||||
|
- clock-names
|
||||||
|
properties:
|
||||||
|
clocks:
|
||||||
|
minItems: 2
|
||||||
|
clock-names:
|
||||||
|
minItems: 2
|
||||||
|
|
||||||
examples:
|
examples:
|
||||||
- |
|
- |
|
||||||
#include <dt-bindings/clock/qcom,sm8550-gcc.h>
|
#include <dt-bindings/clock/qcom,sm8550-gcc.h>
|
||||||
|
|
@ -52,7 +81,11 @@ examples:
|
||||||
compatible = "qcom,sm8550-inline-crypto-engine",
|
compatible = "qcom,sm8550-inline-crypto-engine",
|
||||||
"qcom,inline-crypto-engine";
|
"qcom,inline-crypto-engine";
|
||||||
reg = <0x01d88000 0x8000>;
|
reg = <0x01d88000 0x8000>;
|
||||||
clocks = <&gcc GCC_UFS_PHY_ICE_CORE_CLK>;
|
clocks = <&gcc GCC_UFS_PHY_ICE_CORE_CLK>,
|
||||||
|
<&gcc GCC_UFS_PHY_AHB_CLK>;
|
||||||
|
clock-names = "core",
|
||||||
|
"iface";
|
||||||
|
power-domains = <&gcc UFS_PHY_GDSC>;
|
||||||
|
|
||||||
operating-points-v2 = <&ice_opp_table>;
|
operating-points-v2 = <&ice_opp_table>;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -146,7 +146,7 @@
|
||||||
partitions {
|
partitions {
|
||||||
compatible = "redboot-fis";
|
compatible = "redboot-fis";
|
||||||
/* Eraseblock at 0xfe0000 */
|
/* Eraseblock at 0xfe0000 */
|
||||||
fis-index-block = <0x1fc>;
|
fis-index-block = <0x7f>;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -134,7 +134,7 @@
|
||||||
partitions {
|
partitions {
|
||||||
compatible = "redboot-fis";
|
compatible = "redboot-fis";
|
||||||
/* Eraseblock at 0xfe0000 */
|
/* Eraseblock at 0xfe0000 */
|
||||||
fis-index-block = <0x1fc>;
|
fis-index-block = <0x7f>;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -990,9 +990,9 @@
|
||||||
<62 IRQ_TYPE_LEVEL_HIGH 3>, /* Queue 3 */
|
<62 IRQ_TYPE_LEVEL_HIGH 3>, /* Queue 3 */
|
||||||
<63 IRQ_TYPE_LEVEL_HIGH 3>, /* Queue 4 */
|
<63 IRQ_TYPE_LEVEL_HIGH 3>, /* Queue 4 */
|
||||||
<64 IRQ_TYPE_LEVEL_HIGH 3>; /* Queue 5 */
|
<64 IRQ_TYPE_LEVEL_HIGH 3>; /* Queue 5 */
|
||||||
clocks = <&pmc PMC_TYPE_PERIPHERAL 24>, <&pmc PMC_TYPE_PERIPHERAL 24>, <&pmc PMC_TYPE_GCK 24>, <&pmc PMC_TYPE_GCK 67>;
|
clocks = <&pmc PMC_TYPE_PERIPHERAL 24>, <&pmc PMC_TYPE_PERIPHERAL 24>, <&pmc PMC_TYPE_GCK 24>;
|
||||||
clock-names = "hclk", "pclk", "tx_clk", "tsu_clk";
|
clock-names = "hclk", "pclk", "tsu_clk";
|
||||||
assigned-clocks = <&pmc PMC_TYPE_GCK 67>;
|
assigned-clocks = <&pmc PMC_TYPE_GCK 24>;
|
||||||
assigned-clock-rates = <266666666>;
|
assigned-clock-rates = <266666666>;
|
||||||
status = "disabled";
|
status = "disabled";
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -78,6 +78,7 @@ static void __init socfpga_smp_prepare_cpus(unsigned int max_cpus)
|
||||||
}
|
}
|
||||||
|
|
||||||
socfpga_scu_base_addr = of_iomap(np, 0);
|
socfpga_scu_base_addr = of_iomap(np, 0);
|
||||||
|
of_node_put(np);
|
||||||
if (!socfpga_scu_base_addr)
|
if (!socfpga_scu_base_addr)
|
||||||
return;
|
return;
|
||||||
scu_enable(socfpga_scu_base_addr);
|
scu_enable(socfpga_scu_base_addr);
|
||||||
|
|
|
||||||
|
|
@ -843,7 +843,11 @@
|
||||||
"qcom,inline-crypto-engine";
|
"qcom,inline-crypto-engine";
|
||||||
reg = <0x0 0x01d88000 0x0 0x18000>;
|
reg = <0x0 0x01d88000 0x0 0x18000>;
|
||||||
|
|
||||||
clocks = <&gcc GCC_UFS_PHY_ICE_CORE_CLK>;
|
clocks = <&gcc GCC_UFS_PHY_ICE_CORE_CLK>,
|
||||||
|
<&gcc GCC_UFS_PHY_AHB_CLK>;
|
||||||
|
clock-names = "core",
|
||||||
|
"iface";
|
||||||
|
power-domains = <&gcc GCC_UFS_PHY_GDSC>;
|
||||||
};
|
};
|
||||||
|
|
||||||
tcsr_mutex: hwlock@1f40000 {
|
tcsr_mutex: hwlock@1f40000 {
|
||||||
|
|
|
||||||
|
|
@ -2314,11 +2314,9 @@
|
||||||
|
|
||||||
clocks = <&gcc GCC_USB3_MP_PHY_AUX_CLK>,
|
clocks = <&gcc GCC_USB3_MP_PHY_AUX_CLK>,
|
||||||
<&tcsr TCSR_USB3_0_CLKREF_EN>,
|
<&tcsr TCSR_USB3_0_CLKREF_EN>,
|
||||||
<&rpmhcc RPMH_CXO_CLK>,
|
|
||||||
<&gcc GCC_USB3_MP_PHY_COM_AUX_CLK>,
|
<&gcc GCC_USB3_MP_PHY_COM_AUX_CLK>,
|
||||||
<&gcc GCC_USB3_MP_PHY_PIPE_0_CLK>;
|
<&gcc GCC_USB3_MP_PHY_PIPE_0_CLK>;
|
||||||
clock-names = "aux",
|
clock-names = "aux",
|
||||||
"clkref",
|
|
||||||
"ref",
|
"ref",
|
||||||
"com_aux",
|
"com_aux",
|
||||||
"pipe";
|
"pipe";
|
||||||
|
|
@ -2343,11 +2341,9 @@
|
||||||
|
|
||||||
clocks = <&gcc GCC_USB3_MP_PHY_AUX_CLK>,
|
clocks = <&gcc GCC_USB3_MP_PHY_AUX_CLK>,
|
||||||
<&tcsr TCSR_USB3_1_CLKREF_EN>,
|
<&tcsr TCSR_USB3_1_CLKREF_EN>,
|
||||||
<&rpmhcc RPMH_CXO_CLK>,
|
|
||||||
<&gcc GCC_USB3_MP_PHY_COM_AUX_CLK>,
|
<&gcc GCC_USB3_MP_PHY_COM_AUX_CLK>,
|
||||||
<&gcc GCC_USB3_MP_PHY_PIPE_1_CLK>;
|
<&gcc GCC_USB3_MP_PHY_PIPE_1_CLK>;
|
||||||
clock-names = "aux",
|
clock-names = "aux",
|
||||||
"clkref",
|
|
||||||
"ref",
|
"ref",
|
||||||
"com_aux",
|
"com_aux",
|
||||||
"pipe";
|
"pipe";
|
||||||
|
|
@ -2482,15 +2478,13 @@
|
||||||
reg = <0x0 0x00fde000 0x0 0x8000>;
|
reg = <0x0 0x00fde000 0x0 0x8000>;
|
||||||
|
|
||||||
clocks = <&gcc GCC_USB3_SEC_PHY_AUX_CLK>,
|
clocks = <&gcc GCC_USB3_SEC_PHY_AUX_CLK>,
|
||||||
<&rpmhcc RPMH_CXO_CLK>,
|
<&tcsr TCSR_USB4_1_CLKREF_EN>,
|
||||||
<&gcc GCC_USB3_SEC_PHY_COM_AUX_CLK>,
|
<&gcc GCC_USB3_SEC_PHY_COM_AUX_CLK>,
|
||||||
<&gcc GCC_USB3_SEC_PHY_PIPE_CLK>,
|
<&gcc GCC_USB3_SEC_PHY_PIPE_CLK>;
|
||||||
<&tcsr TCSR_USB4_1_CLKREF_EN>;
|
|
||||||
clock-names = "aux",
|
clock-names = "aux",
|
||||||
"ref",
|
"ref",
|
||||||
"com_aux",
|
"com_aux",
|
||||||
"usb3_pipe",
|
"usb3_pipe";
|
||||||
"clkref";
|
|
||||||
|
|
||||||
power-domains = <&gcc GCC_USB_1_PHY_GDSC>;
|
power-domains = <&gcc GCC_USB_1_PHY_GDSC>;
|
||||||
|
|
||||||
|
|
@ -3750,15 +3744,13 @@
|
||||||
reg = <0x0 0x088e1000 0x0 0x8000>;
|
reg = <0x0 0x088e1000 0x0 0x8000>;
|
||||||
|
|
||||||
clocks = <&gcc GCC_USB3_TERT_PHY_AUX_CLK>,
|
clocks = <&gcc GCC_USB3_TERT_PHY_AUX_CLK>,
|
||||||
<&rpmhcc RPMH_CXO_CLK>,
|
<&tcsr TCSR_USB4_2_CLKREF_EN>,
|
||||||
<&gcc GCC_USB3_TERT_PHY_COM_AUX_CLK>,
|
<&gcc GCC_USB3_TERT_PHY_COM_AUX_CLK>,
|
||||||
<&gcc GCC_USB3_TERT_PHY_PIPE_CLK>,
|
<&gcc GCC_USB3_TERT_PHY_PIPE_CLK>;
|
||||||
<&tcsr TCSR_USB4_2_CLKREF_EN>;
|
|
||||||
clock-names = "aux",
|
clock-names = "aux",
|
||||||
"ref",
|
"ref",
|
||||||
"com_aux",
|
"com_aux",
|
||||||
"usb3_pipe",
|
"usb3_pipe";
|
||||||
"clkref";
|
|
||||||
|
|
||||||
power-domains = <&gcc GCC_USB_2_PHY_GDSC>;
|
power-domains = <&gcc GCC_USB_2_PHY_GDSC>;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1275,7 +1275,11 @@
|
||||||
"qcom,inline-crypto-engine";
|
"qcom,inline-crypto-engine";
|
||||||
reg = <0x0 0x01d88000 0x0 0x18000>;
|
reg = <0x0 0x01d88000 0x0 0x18000>;
|
||||||
|
|
||||||
clocks = <&gcc GCC_UFS_PHY_ICE_CORE_CLK>;
|
clocks = <&gcc GCC_UFS_PHY_ICE_CORE_CLK>,
|
||||||
|
<&gcc GCC_UFS_PHY_AHB_CLK>;
|
||||||
|
clock-names = "core",
|
||||||
|
"iface";
|
||||||
|
power-domains = <&gcc UFS_PHY_GDSC>;
|
||||||
};
|
};
|
||||||
|
|
||||||
tcsr_mutex: hwlock@1f40000 {
|
tcsr_mutex: hwlock@1f40000 {
|
||||||
|
|
|
||||||
|
|
@ -982,12 +982,6 @@
|
||||||
status = "okay";
|
status = "okay";
|
||||||
};
|
};
|
||||||
|
|
||||||
&i2c20 {
|
|
||||||
clock-frequency = <400000>;
|
|
||||||
|
|
||||||
status = "okay";
|
|
||||||
};
|
|
||||||
|
|
||||||
&lpass_tlmm {
|
&lpass_tlmm {
|
||||||
spkr_01_sd_n_active: spkr-01-sd-n-active-state {
|
spkr_01_sd_n_active: spkr-01-sd-n-active-state {
|
||||||
pins = "gpio12";
|
pins = "gpio12";
|
||||||
|
|
@ -1308,6 +1302,7 @@
|
||||||
&tlmm {
|
&tlmm {
|
||||||
gpio-reserved-ranges = <44 4>, /* SPI11 (TPM) */
|
gpio-reserved-ranges = <44 4>, /* SPI11 (TPM) */
|
||||||
<76 4>, /* SPI19 (TZ Protected) */
|
<76 4>, /* SPI19 (TZ Protected) */
|
||||||
|
<80 2>, /* I2C20 (Battery SMBus) */
|
||||||
<238 1>; /* UFS Reset */
|
<238 1>; /* UFS Reset */
|
||||||
|
|
||||||
cam_rgb_default: cam-rgb-default-state {
|
cam_rgb_default: cam-rgb-default-state {
|
||||||
|
|
|
||||||
|
|
@ -260,6 +260,7 @@ CONFIG_PCI_ENDPOINT=y
|
||||||
CONFIG_PCI_ENDPOINT_CONFIGFS=y
|
CONFIG_PCI_ENDPOINT_CONFIGFS=y
|
||||||
CONFIG_PCI_EPF_TEST=m
|
CONFIG_PCI_EPF_TEST=m
|
||||||
CONFIG_PCI_PWRCTRL_GENERIC=m
|
CONFIG_PCI_PWRCTRL_GENERIC=m
|
||||||
|
CONFIG_POWER_SEQUENCING_PCIE_M2=m
|
||||||
CONFIG_DEVTMPFS=y
|
CONFIG_DEVTMPFS=y
|
||||||
CONFIG_DEVTMPFS_MOUNT=y
|
CONFIG_DEVTMPFS_MOUNT=y
|
||||||
CONFIG_FW_LOADER_USER_HELPER=y
|
CONFIG_FW_LOADER_USER_HELPER=y
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,9 @@ static void acpm_dvfs_set_xfer(struct acpm_xfer *xfer, u32 *cmd, size_t cmdlen,
|
||||||
if (response) {
|
if (response) {
|
||||||
xfer->rxcnt = cmdlen;
|
xfer->rxcnt = cmdlen;
|
||||||
xfer->rxd = cmd;
|
xfer->rxd = cmd;
|
||||||
|
} else {
|
||||||
|
xfer->rxcnt = 0;
|
||||||
|
xfer->rxd = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,11 +7,12 @@
|
||||||
|
|
||||||
#include <linux/bitfield.h>
|
#include <linux/bitfield.h>
|
||||||
#include <linux/bitmap.h>
|
#include <linux/bitmap.h>
|
||||||
#include <linux/bits.h>
|
#include <linux/bitops.h>
|
||||||
#include <linux/cleanup.h>
|
#include <linux/cleanup.h>
|
||||||
#include <linux/container_of.h>
|
#include <linux/container_of.h>
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
|
#include <linux/find.h>
|
||||||
#include <linux/firmware/samsung/exynos-acpm-protocol.h>
|
#include <linux/firmware/samsung/exynos-acpm-protocol.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
#include <linux/iopoll.h>
|
#include <linux/iopoll.h>
|
||||||
|
|
@ -104,12 +105,15 @@ struct acpm_queue {
|
||||||
*
|
*
|
||||||
* @cmd: pointer to where the data shall be saved.
|
* @cmd: pointer to where the data shall be saved.
|
||||||
* @n_cmd: number of 32-bit commands.
|
* @n_cmd: number of 32-bit commands.
|
||||||
* @response: true if the client expects the RX data.
|
* @rxcnt: expected length of the response in 32-bit words.
|
||||||
|
* @completed: flag indicating if the firmware response has been fully
|
||||||
|
* processed.
|
||||||
*/
|
*/
|
||||||
struct acpm_rx_data {
|
struct acpm_rx_data {
|
||||||
u32 *cmd;
|
u32 *cmd;
|
||||||
size_t n_cmd;
|
size_t n_cmd;
|
||||||
bool response;
|
size_t rxcnt;
|
||||||
|
bool completed;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define ACPM_SEQNUM_MAX 64
|
#define ACPM_SEQNUM_MAX 64
|
||||||
|
|
@ -199,31 +203,33 @@ static void acpm_get_saved_rx(struct acpm_chan *achan,
|
||||||
const struct acpm_rx_data *rx_data = &achan->rx_data[tx_seqnum - 1];
|
const struct acpm_rx_data *rx_data = &achan->rx_data[tx_seqnum - 1];
|
||||||
u32 rx_seqnum;
|
u32 rx_seqnum;
|
||||||
|
|
||||||
if (!rx_data->response)
|
if (!rx_data->rxcnt)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
rx_seqnum = FIELD_GET(ACPM_PROTOCOL_SEQNUM, rx_data->cmd[0]);
|
rx_seqnum = FIELD_GET(ACPM_PROTOCOL_SEQNUM, rx_data->cmd[0]);
|
||||||
|
|
||||||
if (rx_seqnum == tx_seqnum) {
|
if (rx_seqnum == tx_seqnum)
|
||||||
memcpy(xfer->rxd, rx_data->cmd, xfer->rxcnt * sizeof(*xfer->rxd));
|
memcpy(xfer->rxd, rx_data->cmd, xfer->rxcnt * sizeof(*xfer->rxd));
|
||||||
clear_bit(rx_seqnum - 1, achan->bitmap_seqnum);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* acpm_get_rx() - get response from RX queue.
|
* acpm_get_rx() - get response from RX queue.
|
||||||
* @achan: ACPM channel info.
|
* @achan: ACPM channel info.
|
||||||
* @xfer: reference to the transfer to get response for.
|
* @xfer: reference to the transfer to get response for.
|
||||||
|
* @native_match: pointer to a boolean set to true if the thread natively
|
||||||
|
* processed its own sequence number during this call.
|
||||||
*
|
*
|
||||||
* Return: 0 on success, -errno otherwise.
|
* Return: 0 on success, -errno otherwise.
|
||||||
*/
|
*/
|
||||||
static int acpm_get_rx(struct acpm_chan *achan, const struct acpm_xfer *xfer)
|
static int acpm_get_rx(struct acpm_chan *achan, const struct acpm_xfer *xfer,
|
||||||
|
bool *native_match)
|
||||||
{
|
{
|
||||||
u32 rx_front, rx_seqnum, tx_seqnum, seqnum;
|
u32 rx_front, rx_seqnum, tx_seqnum, seqnum;
|
||||||
const void __iomem *base, *addr;
|
const void __iomem *base, *addr;
|
||||||
struct acpm_rx_data *rx_data;
|
struct acpm_rx_data *rx_data;
|
||||||
u32 i, val, mlen;
|
u32 i, val, mlen;
|
||||||
bool rx_set = false;
|
|
||||||
|
*native_match = false;
|
||||||
|
|
||||||
guard(mutex)(&achan->rx_lock);
|
guard(mutex)(&achan->rx_lock);
|
||||||
|
|
||||||
|
|
@ -232,10 +238,8 @@ static int acpm_get_rx(struct acpm_chan *achan, const struct acpm_xfer *xfer)
|
||||||
|
|
||||||
tx_seqnum = FIELD_GET(ACPM_PROTOCOL_SEQNUM, xfer->txd[0]);
|
tx_seqnum = FIELD_GET(ACPM_PROTOCOL_SEQNUM, xfer->txd[0]);
|
||||||
|
|
||||||
if (i == rx_front) {
|
if (i == rx_front)
|
||||||
acpm_get_saved_rx(achan, xfer, tx_seqnum);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
|
|
||||||
base = achan->rx.base;
|
base = achan->rx.base;
|
||||||
mlen = achan->mlen;
|
mlen = achan->mlen;
|
||||||
|
|
@ -256,11 +260,16 @@ static int acpm_get_rx(struct acpm_chan *achan, const struct acpm_xfer *xfer)
|
||||||
seqnum = rx_seqnum - 1;
|
seqnum = rx_seqnum - 1;
|
||||||
rx_data = &achan->rx_data[seqnum];
|
rx_data = &achan->rx_data[seqnum];
|
||||||
|
|
||||||
if (rx_data->response) {
|
if (rx_data->rxcnt) {
|
||||||
if (rx_seqnum == tx_seqnum) {
|
if (rx_seqnum == tx_seqnum) {
|
||||||
__ioread32_copy(xfer->rxd, addr, xfer->rxcnt);
|
__ioread32_copy(xfer->rxd, addr, xfer->rxcnt);
|
||||||
rx_set = true;
|
/*
|
||||||
clear_bit(seqnum, achan->bitmap_seqnum);
|
* Signal completion to the polling thread.
|
||||||
|
* Pairs with smp_load_acquire() in polling
|
||||||
|
* loop.
|
||||||
|
*/
|
||||||
|
smp_store_release(&rx_data->completed, true);
|
||||||
|
*native_match = true;
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
* The RX data corresponds to another request.
|
* The RX data corresponds to another request.
|
||||||
|
|
@ -268,10 +277,23 @@ static int acpm_get_rx(struct acpm_chan *achan, const struct acpm_xfer *xfer)
|
||||||
* clear yet the bitmap. It will be cleared
|
* clear yet the bitmap. It will be cleared
|
||||||
* after the response is copied to the request.
|
* after the response is copied to the request.
|
||||||
*/
|
*/
|
||||||
__ioread32_copy(rx_data->cmd, addr, xfer->rxcnt);
|
__ioread32_copy(rx_data->cmd, addr,
|
||||||
|
rx_data->rxcnt);
|
||||||
|
/*
|
||||||
|
* Signal completion to the polling thread.
|
||||||
|
* Pairs with smp_load_acquire() in polling
|
||||||
|
* loop.
|
||||||
|
*/
|
||||||
|
smp_store_release(&rx_data->completed, true);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
clear_bit(seqnum, achan->bitmap_seqnum);
|
/*
|
||||||
|
* Signal completion to the polling thread.
|
||||||
|
* Pairs with smp_load_acquire() in polling loop.
|
||||||
|
*/
|
||||||
|
smp_store_release(&rx_data->completed, true);
|
||||||
|
if (rx_seqnum == tx_seqnum)
|
||||||
|
*native_match = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
i = (i + 1) % achan->qlen;
|
i = (i + 1) % achan->qlen;
|
||||||
|
|
@ -280,13 +302,6 @@ static int acpm_get_rx(struct acpm_chan *achan, const struct acpm_xfer *xfer)
|
||||||
/* We saved all responses, mark RX empty. */
|
/* We saved all responses, mark RX empty. */
|
||||||
writel(rx_front, achan->rx.rear);
|
writel(rx_front, achan->rx.rear);
|
||||||
|
|
||||||
/*
|
|
||||||
* If the response was not in this iteration of the queue, check if the
|
|
||||||
* RX data was previously saved.
|
|
||||||
*/
|
|
||||||
if (!rx_set)
|
|
||||||
acpm_get_saved_rx(achan, xfer, tx_seqnum);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -301,6 +316,7 @@ static int acpm_dequeue_by_polling(struct acpm_chan *achan,
|
||||||
const struct acpm_xfer *xfer)
|
const struct acpm_xfer *xfer)
|
||||||
{
|
{
|
||||||
struct device *dev = achan->acpm->dev;
|
struct device *dev = achan->acpm->dev;
|
||||||
|
bool native_match;
|
||||||
ktime_t timeout;
|
ktime_t timeout;
|
||||||
u32 seqnum;
|
u32 seqnum;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
@ -309,12 +325,25 @@ static int acpm_dequeue_by_polling(struct acpm_chan *achan,
|
||||||
|
|
||||||
timeout = ktime_add_us(ktime_get(), ACPM_POLL_TIMEOUT_US);
|
timeout = ktime_add_us(ktime_get(), ACPM_POLL_TIMEOUT_US);
|
||||||
do {
|
do {
|
||||||
ret = acpm_get_rx(achan, xfer);
|
ret = acpm_get_rx(achan, xfer, &native_match);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
if (!test_bit(seqnum - 1, achan->bitmap_seqnum))
|
/*
|
||||||
|
* Safely check if our specific transaction has been processed.
|
||||||
|
* smp_load_acquire prevents the CPU from speculatively
|
||||||
|
* executing subsequent instructions before the transaction is
|
||||||
|
* synchronized.
|
||||||
|
*/
|
||||||
|
if (smp_load_acquire(&achan->rx_data[seqnum - 1].completed)) {
|
||||||
|
/* Retrieve payload if another thread cached it for us */
|
||||||
|
if (!native_match)
|
||||||
|
acpm_get_saved_rx(achan, xfer, seqnum);
|
||||||
|
|
||||||
|
/* Relinquish ownership of the sequence slot */
|
||||||
|
clear_bit_unlock(seqnum - 1, achan->bitmap_seqnum);
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Determined experimentally. */
|
/* Determined experimentally. */
|
||||||
udelay(20);
|
udelay(20);
|
||||||
|
|
@ -362,29 +391,48 @@ static int acpm_wait_for_queue_slots(struct acpm_chan *achan, u32 next_tx_front)
|
||||||
* TX queue.
|
* TX queue.
|
||||||
* @achan: ACPM channel info.
|
* @achan: ACPM channel info.
|
||||||
* @xfer: reference to the transfer being prepared.
|
* @xfer: reference to the transfer being prepared.
|
||||||
|
*
|
||||||
|
* Return: 0 on success, -errno otherwise.
|
||||||
*/
|
*/
|
||||||
static void acpm_prepare_xfer(struct acpm_chan *achan,
|
static int acpm_prepare_xfer(struct acpm_chan *achan,
|
||||||
const struct acpm_xfer *xfer)
|
const struct acpm_xfer *xfer)
|
||||||
{
|
{
|
||||||
struct acpm_rx_data *rx_data;
|
struct acpm_rx_data *rx_data;
|
||||||
u32 *txd = (u32 *)xfer->txd;
|
u32 *txd = (u32 *)xfer->txd;
|
||||||
|
unsigned long size = ACPM_SEQNUM_MAX - 1;
|
||||||
|
unsigned long bit = achan->seqnum;
|
||||||
|
|
||||||
/* Prevent chan->seqnum from being re-used */
|
bit = find_next_zero_bit(achan->bitmap_seqnum, size, bit);
|
||||||
do {
|
if (bit >= size) {
|
||||||
if (++achan->seqnum == ACPM_SEQNUM_MAX)
|
bit = find_first_zero_bit(achan->bitmap_seqnum, size);
|
||||||
achan->seqnum = 1;
|
if (bit >= size) {
|
||||||
} while (test_bit(achan->seqnum - 1, achan->bitmap_seqnum));
|
dev_err_ratelimited(achan->acpm->dev,
|
||||||
|
"ACPM sequence number pool exhausted\n");
|
||||||
|
return -EBUSY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Execute the atomic set to formally claim the bit and establish
|
||||||
|
* LKMM Acquire semantics against the RX thread's clear_bit_unlock().
|
||||||
|
* A loop is unnecessary because allocations are strictly serialized
|
||||||
|
* by tx_lock.
|
||||||
|
*/
|
||||||
|
if (WARN_ON_ONCE(test_and_set_bit_lock(bit, achan->bitmap_seqnum)))
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
|
/* Flag the index based on seqnum. (seqnum: 1~63, bitmap: 0~62) */
|
||||||
|
achan->seqnum = bit + 1;
|
||||||
txd[0] |= FIELD_PREP(ACPM_PROTOCOL_SEQNUM, achan->seqnum);
|
txd[0] |= FIELD_PREP(ACPM_PROTOCOL_SEQNUM, achan->seqnum);
|
||||||
|
|
||||||
/* Clear data for upcoming responses */
|
/* Clear data for upcoming responses */
|
||||||
rx_data = &achan->rx_data[achan->seqnum - 1];
|
rx_data = &achan->rx_data[bit];
|
||||||
|
rx_data->completed = false;
|
||||||
memset(rx_data->cmd, 0, sizeof(*rx_data->cmd) * rx_data->n_cmd);
|
memset(rx_data->cmd, 0, sizeof(*rx_data->cmd) * rx_data->n_cmd);
|
||||||
if (xfer->rxd)
|
/* zero means no response expected */
|
||||||
rx_data->response = true;
|
rx_data->rxcnt = xfer->rxcnt;
|
||||||
|
|
||||||
/* Flag the index based on seqnum. (seqnum: 1~63, bitmap: 0~62) */
|
return 0;
|
||||||
set_bit(achan->seqnum - 1, achan->bitmap_seqnum);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -444,7 +492,9 @@ int acpm_do_xfer(struct acpm_handle *handle, const struct acpm_xfer *xfer)
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
acpm_prepare_xfer(achan, xfer);
|
ret = acpm_prepare_xfer(achan, xfer);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
/* Write TX command. */
|
/* Write TX command. */
|
||||||
__iowrite32_copy(achan->tx.base + achan->mlen * tx_front,
|
__iowrite32_copy(achan->tx.base + achan->mlen * tx_front,
|
||||||
|
|
@ -526,10 +576,11 @@ static int acpm_achan_alloc_cmds(struct acpm_chan *achan)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* acpm_free_mbox_chans() - free mailbox channels.
|
* acpm_free_mbox_chans() - free mailbox channels.
|
||||||
* @acpm: pointer to driver data.
|
* @data: pointer to driver data.
|
||||||
*/
|
*/
|
||||||
static void acpm_free_mbox_chans(struct acpm_info *acpm)
|
static void acpm_free_mbox_chans(void *data)
|
||||||
{
|
{
|
||||||
|
struct acpm_info *acpm = data;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < acpm->num_chans; i++)
|
for (i = 0; i < acpm->num_chans; i++)
|
||||||
|
|
@ -557,6 +608,10 @@ static int acpm_channels_init(struct acpm_info *acpm)
|
||||||
if (!acpm->chans)
|
if (!acpm->chans)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
ret = devm_add_action_or_reset(dev, acpm_free_mbox_chans, acpm);
|
||||||
|
if (ret)
|
||||||
|
return dev_err_probe(dev, ret, "Failed to add mbox free action.\n");
|
||||||
|
|
||||||
chans_shmem = acpm->sram_base + readl(&shmem->chans);
|
chans_shmem = acpm->sram_base + readl(&shmem->chans);
|
||||||
|
|
||||||
for (i = 0; i < acpm->num_chans; i++) {
|
for (i = 0; i < acpm->num_chans; i++) {
|
||||||
|
|
@ -578,10 +633,8 @@ static int acpm_channels_init(struct acpm_info *acpm)
|
||||||
cl->dev = dev;
|
cl->dev = dev;
|
||||||
|
|
||||||
achan->chan = mbox_request_channel(cl, 0);
|
achan->chan = mbox_request_channel(cl, 0);
|
||||||
if (IS_ERR(achan->chan)) {
|
if (IS_ERR(achan->chan))
|
||||||
acpm_free_mbox_chans(acpm);
|
|
||||||
return PTR_ERR(achan->chan);
|
return PTR_ERR(achan->chan);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
||||||
|
|
@ -628,10 +628,11 @@ static __maybe_unused int atmel_ebi_resume(struct device *dev)
|
||||||
static SIMPLE_DEV_PM_OPS(atmel_ebi_pm_ops, NULL, atmel_ebi_resume);
|
static SIMPLE_DEV_PM_OPS(atmel_ebi_pm_ops, NULL, atmel_ebi_resume);
|
||||||
|
|
||||||
static struct platform_driver atmel_ebi_driver = {
|
static struct platform_driver atmel_ebi_driver = {
|
||||||
|
.probe = atmel_ebi_probe,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "atmel-ebi",
|
.name = "atmel-ebi",
|
||||||
.of_match_table = atmel_ebi_id_table,
|
.of_match_table = atmel_ebi_id_table,
|
||||||
.pm = &atmel_ebi_pm_ops,
|
.pm = &atmel_ebi_pm_ops,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
builtin_platform_driver_probe(atmel_ebi_driver, atmel_ebi_probe);
|
builtin_platform_driver(atmel_ebi_driver);
|
||||||
|
|
|
||||||
|
|
@ -1918,13 +1918,13 @@ static int sdhci_msm_ice_init(struct sdhci_msm_host *msm_host,
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
ice = devm_of_qcom_ice_get(dev);
|
ice = devm_of_qcom_ice_get(dev);
|
||||||
if (ice == ERR_PTR(-EOPNOTSUPP)) {
|
if (IS_ERR(ice)) {
|
||||||
dev_warn(dev, "Disabling inline encryption support\n");
|
if (ice != ERR_PTR(-EOPNOTSUPP))
|
||||||
ice = NULL;
|
return PTR_ERR(ice);
|
||||||
}
|
|
||||||
|
|
||||||
if (IS_ERR_OR_NULL(ice))
|
dev_warn(dev, "Disabling inline encryption support\n");
|
||||||
return PTR_ERR_OR_ZERO(ice);
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
msm_host->ice = ice;
|
msm_host->ice = ice;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -247,7 +247,7 @@ static int imx8m_soc_probe(struct platform_device *pdev)
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
data = device_get_match_data(dev);
|
data = of_machine_get_match_data(imx8_soc_match);
|
||||||
if (data) {
|
if (data) {
|
||||||
soc_dev_attr->soc_id = data->name;
|
soc_dev_attr->soc_id = data->name;
|
||||||
ret = imx8m_soc_prepare(pdev, data->ocotp_compatible);
|
ret = imx8m_soc_prepare(pdev, data->ocotp_compatible);
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@
|
||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
#include <linux/of_platform.h>
|
#include <linux/of_platform.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/xarray.h>
|
||||||
|
|
||||||
#include <linux/firmware/qcom/qcom_scm.h>
|
#include <linux/firmware/qcom/qcom_scm.h>
|
||||||
|
|
||||||
|
|
@ -108,11 +109,15 @@ struct qcom_ice {
|
||||||
void __iomem *base;
|
void __iomem *base;
|
||||||
|
|
||||||
struct clk *core_clk;
|
struct clk *core_clk;
|
||||||
|
struct clk *iface_clk;
|
||||||
bool use_hwkm;
|
bool use_hwkm;
|
||||||
bool hwkm_init_complete;
|
bool hwkm_init_complete;
|
||||||
u8 hwkm_version;
|
u8 hwkm_version;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static DEFINE_XARRAY(ice_handles);
|
||||||
|
static DEFINE_MUTEX(ice_mutex);
|
||||||
|
|
||||||
static bool qcom_ice_check_supported(struct qcom_ice *ice)
|
static bool qcom_ice_check_supported(struct qcom_ice *ice)
|
||||||
{
|
{
|
||||||
u32 regval = qcom_ice_readl(ice, QCOM_ICE_REG_VERSION);
|
u32 regval = qcom_ice_readl(ice, QCOM_ICE_REG_VERSION);
|
||||||
|
|
@ -312,8 +317,13 @@ int qcom_ice_resume(struct qcom_ice *ice)
|
||||||
|
|
||||||
err = clk_prepare_enable(ice->core_clk);
|
err = clk_prepare_enable(ice->core_clk);
|
||||||
if (err) {
|
if (err) {
|
||||||
dev_err(dev, "failed to enable core clock (%d)\n",
|
dev_err(dev, "Failed to enable core clock: %d\n", err);
|
||||||
err);
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = clk_prepare_enable(ice->iface_clk);
|
||||||
|
if (err) {
|
||||||
|
dev_err(dev, "Failed to enable iface clock: %d\n", err);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
qcom_ice_hwkm_init(ice);
|
qcom_ice_hwkm_init(ice);
|
||||||
|
|
@ -323,6 +333,7 @@ EXPORT_SYMBOL_GPL(qcom_ice_resume);
|
||||||
|
|
||||||
int qcom_ice_suspend(struct qcom_ice *ice)
|
int qcom_ice_suspend(struct qcom_ice *ice)
|
||||||
{
|
{
|
||||||
|
clk_disable_unprepare(ice->iface_clk);
|
||||||
clk_disable_unprepare(ice->core_clk);
|
clk_disable_unprepare(ice->core_clk);
|
||||||
ice->hwkm_init_complete = false;
|
ice->hwkm_init_complete = false;
|
||||||
|
|
||||||
|
|
@ -559,7 +570,7 @@ static struct qcom_ice *qcom_ice_create(struct device *dev,
|
||||||
|
|
||||||
if (!qcom_scm_ice_available()) {
|
if (!qcom_scm_ice_available()) {
|
||||||
dev_warn(dev, "ICE SCM interface not found\n");
|
dev_warn(dev, "ICE SCM interface not found\n");
|
||||||
return NULL;
|
return ERR_PTR(-EOPNOTSUPP);
|
||||||
}
|
}
|
||||||
|
|
||||||
engine = devm_kzalloc(dev, sizeof(*engine), GFP_KERNEL);
|
engine = devm_kzalloc(dev, sizeof(*engine), GFP_KERNEL);
|
||||||
|
|
@ -579,11 +590,17 @@ static struct qcom_ice *qcom_ice_create(struct device *dev,
|
||||||
engine->core_clk = devm_clk_get_optional_enabled(dev, "ice_core_clk");
|
engine->core_clk = devm_clk_get_optional_enabled(dev, "ice_core_clk");
|
||||||
if (!engine->core_clk)
|
if (!engine->core_clk)
|
||||||
engine->core_clk = devm_clk_get_optional_enabled(dev, "ice");
|
engine->core_clk = devm_clk_get_optional_enabled(dev, "ice");
|
||||||
|
if (!engine->core_clk)
|
||||||
|
engine->core_clk = devm_clk_get_optional_enabled(dev, "core");
|
||||||
if (!engine->core_clk)
|
if (!engine->core_clk)
|
||||||
engine->core_clk = devm_clk_get_enabled(dev, NULL);
|
engine->core_clk = devm_clk_get_enabled(dev, NULL);
|
||||||
if (IS_ERR(engine->core_clk))
|
if (IS_ERR(engine->core_clk))
|
||||||
return ERR_CAST(engine->core_clk);
|
return ERR_CAST(engine->core_clk);
|
||||||
|
|
||||||
|
engine->iface_clk = devm_clk_get_optional_enabled(dev, "iface");
|
||||||
|
if (IS_ERR(engine->iface_clk))
|
||||||
|
return ERR_CAST(engine->iface_clk);
|
||||||
|
|
||||||
if (!qcom_ice_check_supported(engine))
|
if (!qcom_ice_check_supported(engine))
|
||||||
return ERR_PTR(-EOPNOTSUPP);
|
return ERR_PTR(-EOPNOTSUPP);
|
||||||
|
|
||||||
|
|
@ -631,6 +648,8 @@ static struct qcom_ice *of_qcom_ice_get(struct device *dev)
|
||||||
return qcom_ice_create(&pdev->dev, base);
|
return qcom_ice_create(&pdev->dev, base);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
guard(mutex)(&ice_mutex);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the consumer node does not provider an 'ice' reg range
|
* If the consumer node does not provider an 'ice' reg range
|
||||||
* (legacy DT binding), then it must at least provide a phandle
|
* (legacy DT binding), then it must at least provide a phandle
|
||||||
|
|
@ -639,20 +658,21 @@ static struct qcom_ice *of_qcom_ice_get(struct device *dev)
|
||||||
struct device_node *node __free(device_node) = of_parse_phandle(dev->of_node,
|
struct device_node *node __free(device_node) = of_parse_phandle(dev->of_node,
|
||||||
"qcom,ice", 0);
|
"qcom,ice", 0);
|
||||||
if (!node)
|
if (!node)
|
||||||
return NULL;
|
return ERR_PTR(-EOPNOTSUPP);
|
||||||
|
|
||||||
pdev = of_find_device_by_node(node);
|
pdev = of_find_device_by_node(node);
|
||||||
if (!pdev) {
|
if (!pdev) {
|
||||||
dev_err(dev, "Cannot find device node %s\n", node->name);
|
dev_err(dev, "Cannot find device node %s\n", node->name);
|
||||||
return ERR_PTR(-EPROBE_DEFER);
|
return ERR_PTR(-ENODEV);
|
||||||
}
|
}
|
||||||
|
|
||||||
ice = platform_get_drvdata(pdev);
|
ice = xa_load(&ice_handles, pdev->dev.of_node->phandle);
|
||||||
if (!ice) {
|
if (IS_ERR_OR_NULL(ice)) {
|
||||||
dev_err(dev, "Cannot get ice instance from %s\n",
|
|
||||||
dev_name(&pdev->dev));
|
|
||||||
platform_device_put(pdev);
|
platform_device_put(pdev);
|
||||||
return ERR_PTR(-EPROBE_DEFER);
|
if (!ice)
|
||||||
|
return ERR_PTR(-EPROBE_DEFER);
|
||||||
|
else
|
||||||
|
return ice;
|
||||||
}
|
}
|
||||||
|
|
||||||
link = device_link_add(dev, &pdev->dev, DL_FLAG_AUTOREMOVE_SUPPLIER);
|
link = device_link_add(dev, &pdev->dev, DL_FLAG_AUTOREMOVE_SUPPLIER);
|
||||||
|
|
@ -691,8 +711,7 @@ static void devm_of_qcom_ice_put(struct device *dev, void *res)
|
||||||
* phandle via 'qcom,ice' property to an ICE DT, the ICE instance will already
|
* phandle via 'qcom,ice' property to an ICE DT, the ICE instance will already
|
||||||
* be created and so this function will return that instead.
|
* be created and so this function will return that instead.
|
||||||
*
|
*
|
||||||
* Return: ICE pointer on success, NULL if there is no ICE data provided by the
|
* Return: ICE pointer on success, ERR_PTR() on error.
|
||||||
* consumer or ERR_PTR() on error.
|
|
||||||
*/
|
*/
|
||||||
struct qcom_ice *devm_of_qcom_ice_get(struct device *dev)
|
struct qcom_ice *devm_of_qcom_ice_get(struct device *dev)
|
||||||
{
|
{
|
||||||
|
|
@ -703,7 +722,7 @@ struct qcom_ice *devm_of_qcom_ice_get(struct device *dev)
|
||||||
return ERR_PTR(-ENOMEM);
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
ice = of_qcom_ice_get(dev);
|
ice = of_qcom_ice_get(dev);
|
||||||
if (!IS_ERR_OR_NULL(ice)) {
|
if (!IS_ERR(ice)) {
|
||||||
*dr = ice;
|
*dr = ice;
|
||||||
devres_add(dev, dr);
|
devres_add(dev, dr);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -716,24 +735,40 @@ EXPORT_SYMBOL_GPL(devm_of_qcom_ice_get);
|
||||||
|
|
||||||
static int qcom_ice_probe(struct platform_device *pdev)
|
static int qcom_ice_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
|
unsigned long phandle = pdev->dev.of_node->phandle;
|
||||||
struct qcom_ice *engine;
|
struct qcom_ice *engine;
|
||||||
void __iomem *base;
|
void __iomem *base;
|
||||||
|
|
||||||
|
guard(mutex)(&ice_mutex);
|
||||||
|
|
||||||
base = devm_platform_ioremap_resource(pdev, 0);
|
base = devm_platform_ioremap_resource(pdev, 0);
|
||||||
if (IS_ERR(base)) {
|
if (IS_ERR(base)) {
|
||||||
dev_warn(&pdev->dev, "ICE registers not found\n");
|
dev_warn(&pdev->dev, "ICE registers not found\n");
|
||||||
|
/* Store the error pointer for devm_of_qcom_ice_get() */
|
||||||
|
xa_store(&ice_handles, phandle, (__force void *)base, GFP_KERNEL);
|
||||||
return PTR_ERR(base);
|
return PTR_ERR(base);
|
||||||
}
|
}
|
||||||
|
|
||||||
engine = qcom_ice_create(&pdev->dev, base);
|
engine = qcom_ice_create(&pdev->dev, base);
|
||||||
if (IS_ERR(engine))
|
if (IS_ERR(engine)) {
|
||||||
|
/* Store the error pointer for devm_of_qcom_ice_get() */
|
||||||
|
xa_store(&ice_handles, phandle, engine, GFP_KERNEL);
|
||||||
return PTR_ERR(engine);
|
return PTR_ERR(engine);
|
||||||
|
}
|
||||||
|
|
||||||
platform_set_drvdata(pdev, engine);
|
xa_store(&ice_handles, phandle, engine, GFP_KERNEL);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void qcom_ice_remove(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
unsigned long phandle = pdev->dev.of_node->phandle;
|
||||||
|
|
||||||
|
guard(mutex)(&ice_mutex);
|
||||||
|
xa_store(&ice_handles, phandle, NULL, GFP_KERNEL);
|
||||||
|
}
|
||||||
|
|
||||||
static const struct of_device_id qcom_ice_of_match_table[] = {
|
static const struct of_device_id qcom_ice_of_match_table[] = {
|
||||||
{ .compatible = "qcom,inline-crypto-engine" },
|
{ .compatible = "qcom,inline-crypto-engine" },
|
||||||
{ },
|
{ },
|
||||||
|
|
@ -742,6 +777,7 @@ MODULE_DEVICE_TABLE(of, qcom_ice_of_match_table);
|
||||||
|
|
||||||
static struct platform_driver qcom_ice_driver = {
|
static struct platform_driver qcom_ice_driver = {
|
||||||
.probe = qcom_ice_probe,
|
.probe = qcom_ice_probe,
|
||||||
|
.remove = qcom_ice_remove,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "qcom-ice",
|
.name = "qcom-ice",
|
||||||
.of_match_table = qcom_ice_of_match_table,
|
.of_match_table = qcom_ice_of_match_table,
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,11 @@
|
||||||
struct optee_supp_req {
|
struct optee_supp_req {
|
||||||
struct list_head link;
|
struct list_head link;
|
||||||
|
|
||||||
|
int id;
|
||||||
|
|
||||||
bool in_queue;
|
bool in_queue;
|
||||||
|
bool processed;
|
||||||
|
|
||||||
u32 func;
|
u32 func;
|
||||||
u32 ret;
|
u32 ret;
|
||||||
size_t num_params;
|
size_t num_params;
|
||||||
|
|
@ -19,6 +23,9 @@ struct optee_supp_req {
|
||||||
struct completion c;
|
struct completion c;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* It is temporary request used for revoked pending request in supp->idr. */
|
||||||
|
#define INVALID_REQ_PTR ((struct optee_supp_req *)ERR_PTR(-EBADF))
|
||||||
|
|
||||||
void optee_supp_init(struct optee_supp *supp)
|
void optee_supp_init(struct optee_supp *supp)
|
||||||
{
|
{
|
||||||
memset(supp, 0, sizeof(*supp));
|
memset(supp, 0, sizeof(*supp));
|
||||||
|
|
@ -39,21 +46,23 @@ void optee_supp_release(struct optee_supp *supp)
|
||||||
{
|
{
|
||||||
int id;
|
int id;
|
||||||
struct optee_supp_req *req;
|
struct optee_supp_req *req;
|
||||||
struct optee_supp_req *req_tmp;
|
|
||||||
|
|
||||||
mutex_lock(&supp->mutex);
|
mutex_lock(&supp->mutex);
|
||||||
|
|
||||||
/* Abort all request retrieved by supplicant */
|
/* Abort all request */
|
||||||
idr_for_each_entry(&supp->idr, req, id) {
|
idr_for_each_entry(&supp->idr, req, id) {
|
||||||
idr_remove(&supp->idr, id);
|
idr_remove(&supp->idr, id);
|
||||||
req->ret = TEEC_ERROR_COMMUNICATION;
|
/* Skip if request was already marked invalid */
|
||||||
complete(&req->c);
|
if (IS_ERR(req))
|
||||||
}
|
continue;
|
||||||
|
|
||||||
/* Abort all queued requests */
|
/* For queued requests where supplicant has not seen it */
|
||||||
list_for_each_entry_safe(req, req_tmp, &supp->reqs, link) {
|
if (req->in_queue) {
|
||||||
list_del(&req->link);
|
list_del(&req->link);
|
||||||
req->in_queue = false;
|
req->in_queue = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
req->processed = true;
|
||||||
req->ret = TEEC_ERROR_COMMUNICATION;
|
req->ret = TEEC_ERROR_COMMUNICATION;
|
||||||
complete(&req->c);
|
complete(&req->c);
|
||||||
}
|
}
|
||||||
|
|
@ -100,8 +109,16 @@ u32 optee_supp_thrd_req(struct tee_context *ctx, u32 func, size_t num_params,
|
||||||
|
|
||||||
/* Insert the request in the request list */
|
/* Insert the request in the request list */
|
||||||
mutex_lock(&supp->mutex);
|
mutex_lock(&supp->mutex);
|
||||||
|
req->id = idr_alloc(&supp->idr, req, 1, 0, GFP_KERNEL);
|
||||||
|
if (req->id < 0) {
|
||||||
|
mutex_unlock(&supp->mutex);
|
||||||
|
kfree(req);
|
||||||
|
return TEEC_ERROR_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
list_add_tail(&req->link, &supp->reqs);
|
list_add_tail(&req->link, &supp->reqs);
|
||||||
req->in_queue = true;
|
req->in_queue = true;
|
||||||
|
req->processed = false;
|
||||||
mutex_unlock(&supp->mutex);
|
mutex_unlock(&supp->mutex);
|
||||||
|
|
||||||
/* Tell an eventual waiter there's a new request */
|
/* Tell an eventual waiter there's a new request */
|
||||||
|
|
@ -117,21 +134,43 @@ u32 optee_supp_thrd_req(struct tee_context *ctx, u32 func, size_t num_params,
|
||||||
if (wait_for_completion_killable(&req->c)) {
|
if (wait_for_completion_killable(&req->c)) {
|
||||||
mutex_lock(&supp->mutex);
|
mutex_lock(&supp->mutex);
|
||||||
if (req->in_queue) {
|
if (req->in_queue) {
|
||||||
|
/* Supplicant has not seen this request yet. */
|
||||||
|
idr_remove(&supp->idr, req->id);
|
||||||
list_del(&req->link);
|
list_del(&req->link);
|
||||||
req->in_queue = false;
|
req->in_queue = false;
|
||||||
|
|
||||||
|
ret = TEEC_ERROR_COMMUNICATION;
|
||||||
|
} else if (req->processed) {
|
||||||
|
/*
|
||||||
|
* Supplicant has processed this request. Ignore the
|
||||||
|
* kill signal for now and submit the result. req is not
|
||||||
|
* in supp->reqs (removed by supp_pop_entry()) nor in
|
||||||
|
* supp->idr (removed by supp_pop_req()).
|
||||||
|
*/
|
||||||
|
ret = req->ret;
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* Supplicant is in the middle of processing this
|
||||||
|
* request. Replace req with INVALID_REQ_PTR so that
|
||||||
|
* the ID remains busy, causing optee_supp_send() to
|
||||||
|
* fail on the next call to supp_pop_req() with this ID.
|
||||||
|
*/
|
||||||
|
idr_replace(&supp->idr, INVALID_REQ_PTR, req->id);
|
||||||
|
ret = TEEC_ERROR_COMMUNICATION;
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_unlock(&supp->mutex);
|
mutex_unlock(&supp->mutex);
|
||||||
req->ret = TEEC_ERROR_COMMUNICATION;
|
} else {
|
||||||
|
ret = req->ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = req->ret;
|
|
||||||
kfree(req);
|
kfree(req);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct optee_supp_req *supp_pop_entry(struct optee_supp *supp,
|
static struct optee_supp_req *supp_pop_entry(struct optee_supp *supp,
|
||||||
int num_params, int *id)
|
int num_params)
|
||||||
{
|
{
|
||||||
struct optee_supp_req *req;
|
struct optee_supp_req *req;
|
||||||
|
|
||||||
|
|
@ -153,10 +192,6 @@ static struct optee_supp_req *supp_pop_entry(struct optee_supp *supp,
|
||||||
return ERR_PTR(-EINVAL);
|
return ERR_PTR(-EINVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
*id = idr_alloc(&supp->idr, req, 1, 0, GFP_KERNEL);
|
|
||||||
if (*id < 0)
|
|
||||||
return ERR_PTR(-ENOMEM);
|
|
||||||
|
|
||||||
list_del(&req->link);
|
list_del(&req->link);
|
||||||
req->in_queue = false;
|
req->in_queue = false;
|
||||||
|
|
||||||
|
|
@ -214,7 +249,6 @@ int optee_supp_recv(struct tee_context *ctx, u32 *func, u32 *num_params,
|
||||||
struct optee *optee = tee_get_drvdata(teedev);
|
struct optee *optee = tee_get_drvdata(teedev);
|
||||||
struct optee_supp *supp = &optee->supp;
|
struct optee_supp *supp = &optee->supp;
|
||||||
struct optee_supp_req *req = NULL;
|
struct optee_supp_req *req = NULL;
|
||||||
int id;
|
|
||||||
size_t num_meta;
|
size_t num_meta;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
|
|
@ -224,15 +258,11 @@ int optee_supp_recv(struct tee_context *ctx, u32 *func, u32 *num_params,
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
mutex_lock(&supp->mutex);
|
mutex_lock(&supp->mutex);
|
||||||
req = supp_pop_entry(supp, *num_params - num_meta, &id);
|
req = supp_pop_entry(supp, *num_params - num_meta);
|
||||||
|
if (req)
|
||||||
|
break; /* Keep mutex held. */
|
||||||
mutex_unlock(&supp->mutex);
|
mutex_unlock(&supp->mutex);
|
||||||
|
|
||||||
if (req) {
|
|
||||||
if (IS_ERR(req))
|
|
||||||
return PTR_ERR(req);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we didn't get a request we'll block in
|
* If we didn't get a request we'll block in
|
||||||
* wait_for_completion() to avoid needless spinning.
|
* wait_for_completion() to avoid needless spinning.
|
||||||
|
|
@ -245,6 +275,13 @@ int optee_supp_recv(struct tee_context *ctx, u32 *func, u32 *num_params,
|
||||||
return -ERESTARTSYS;
|
return -ERESTARTSYS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* supp->mutex held and req != NULL. */
|
||||||
|
|
||||||
|
if (IS_ERR(req)) {
|
||||||
|
mutex_unlock(&supp->mutex);
|
||||||
|
return PTR_ERR(req);
|
||||||
|
}
|
||||||
|
|
||||||
if (num_meta) {
|
if (num_meta) {
|
||||||
/*
|
/*
|
||||||
* tee-supplicant support meta parameters -> requsts can be
|
* tee-supplicant support meta parameters -> requsts can be
|
||||||
|
|
@ -252,13 +289,11 @@ int optee_supp_recv(struct tee_context *ctx, u32 *func, u32 *num_params,
|
||||||
*/
|
*/
|
||||||
param->attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT |
|
param->attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT |
|
||||||
TEE_IOCTL_PARAM_ATTR_META;
|
TEE_IOCTL_PARAM_ATTR_META;
|
||||||
param->u.value.a = id;
|
param->u.value.a = req->id;
|
||||||
param->u.value.b = 0;
|
param->u.value.b = 0;
|
||||||
param->u.value.c = 0;
|
param->u.value.c = 0;
|
||||||
} else {
|
} else {
|
||||||
mutex_lock(&supp->mutex);
|
supp->req_id = req->id;
|
||||||
supp->req_id = id;
|
|
||||||
mutex_unlock(&supp->mutex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
*func = req->func;
|
*func = req->func;
|
||||||
|
|
@ -266,6 +301,7 @@ int optee_supp_recv(struct tee_context *ctx, u32 *func, u32 *num_params,
|
||||||
memcpy(param + num_meta, req->param,
|
memcpy(param + num_meta, req->param,
|
||||||
sizeof(struct tee_param) * req->num_params);
|
sizeof(struct tee_param) * req->num_params);
|
||||||
|
|
||||||
|
mutex_unlock(&supp->mutex);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -297,12 +333,17 @@ static struct optee_supp_req *supp_pop_req(struct optee_supp *supp,
|
||||||
if (!req)
|
if (!req)
|
||||||
return ERR_PTR(-ENOENT);
|
return ERR_PTR(-ENOENT);
|
||||||
|
|
||||||
|
/* optee_supp_thrd_req() already returned to optee. */
|
||||||
|
if (IS_ERR(req))
|
||||||
|
goto failed_req;
|
||||||
|
|
||||||
if ((num_params - nm) != req->num_params)
|
if ((num_params - nm) != req->num_params)
|
||||||
return ERR_PTR(-EINVAL);
|
return ERR_PTR(-EINVAL);
|
||||||
|
|
||||||
|
*num_meta = nm;
|
||||||
|
failed_req:
|
||||||
idr_remove(&supp->idr, id);
|
idr_remove(&supp->idr, id);
|
||||||
supp->req_id = -1;
|
supp->req_id = -1;
|
||||||
*num_meta = nm;
|
|
||||||
|
|
||||||
return req;
|
return req;
|
||||||
}
|
}
|
||||||
|
|
@ -328,10 +369,9 @@ int optee_supp_send(struct tee_context *ctx, u32 ret, u32 num_params,
|
||||||
|
|
||||||
mutex_lock(&supp->mutex);
|
mutex_lock(&supp->mutex);
|
||||||
req = supp_pop_req(supp, num_params, param, &num_meta);
|
req = supp_pop_req(supp, num_params, param, &num_meta);
|
||||||
mutex_unlock(&supp->mutex);
|
|
||||||
|
|
||||||
if (IS_ERR(req)) {
|
if (IS_ERR(req)) {
|
||||||
/* Something is wrong, let supplicant restart. */
|
mutex_unlock(&supp->mutex);
|
||||||
|
/* Something is wrong, let supplicant handel it. */
|
||||||
return PTR_ERR(req);
|
return PTR_ERR(req);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -355,9 +395,10 @@ int optee_supp_send(struct tee_context *ctx, u32 ret, u32 num_params,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
req->ret = ret;
|
req->ret = ret;
|
||||||
|
req->processed = true;
|
||||||
/* Let the requesting thread continue */
|
/* Let the requesting thread continue */
|
||||||
complete(&req->c);
|
complete(&req->c);
|
||||||
|
mutex_unlock(&supp->mutex);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -306,8 +306,10 @@ int qcomtee_object_user_init(struct qcomtee_object *object,
|
||||||
break;
|
break;
|
||||||
case QCOMTEE_OBJECT_TYPE_CB:
|
case QCOMTEE_OBJECT_TYPE_CB:
|
||||||
object->ops = ops;
|
object->ops = ops;
|
||||||
if (!object->ops->dispatch)
|
if (!object->ops->dispatch) {
|
||||||
return -EINVAL;
|
ret = -EINVAL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
/* If failed, "no-name". */
|
/* If failed, "no-name". */
|
||||||
object->name = kvasprintf_const(GFP_KERNEL, fmt, ap);
|
object->name = kvasprintf_const(GFP_KERNEL, fmt, ap);
|
||||||
|
|
|
||||||
|
|
@ -530,11 +530,24 @@ static int params_to_user(struct tee_ioctl_param __user *uparams,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void free_params(struct tee_param *params, size_t num_params)
|
||||||
|
{
|
||||||
|
size_t n;
|
||||||
|
|
||||||
|
if (!params)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (n = 0; n < num_params; n++)
|
||||||
|
if (tee_param_is_memref(params + n) && params[n].u.memref.shm)
|
||||||
|
tee_shm_put(params[n].u.memref.shm);
|
||||||
|
|
||||||
|
kfree(params);
|
||||||
|
}
|
||||||
|
|
||||||
static int tee_ioctl_open_session(struct tee_context *ctx,
|
static int tee_ioctl_open_session(struct tee_context *ctx,
|
||||||
struct tee_ioctl_buf_data __user *ubuf)
|
struct tee_ioctl_buf_data __user *ubuf)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
size_t n;
|
|
||||||
struct tee_ioctl_buf_data buf;
|
struct tee_ioctl_buf_data buf;
|
||||||
struct tee_ioctl_open_session_arg __user *uarg;
|
struct tee_ioctl_open_session_arg __user *uarg;
|
||||||
struct tee_ioctl_open_session_arg arg;
|
struct tee_ioctl_open_session_arg arg;
|
||||||
|
|
@ -595,16 +608,7 @@ out:
|
||||||
*/
|
*/
|
||||||
if (rc && have_session && ctx->teedev->desc->ops->close_session)
|
if (rc && have_session && ctx->teedev->desc->ops->close_session)
|
||||||
ctx->teedev->desc->ops->close_session(ctx, arg.session);
|
ctx->teedev->desc->ops->close_session(ctx, arg.session);
|
||||||
|
free_params(params, arg.num_params);
|
||||||
if (params) {
|
|
||||||
/* Decrease ref count for all valid shared memory pointers */
|
|
||||||
for (n = 0; n < arg.num_params; n++)
|
|
||||||
if (tee_param_is_memref(params + n) &&
|
|
||||||
params[n].u.memref.shm)
|
|
||||||
tee_shm_put(params[n].u.memref.shm);
|
|
||||||
kfree(params);
|
|
||||||
}
|
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -612,7 +616,6 @@ static int tee_ioctl_invoke(struct tee_context *ctx,
|
||||||
struct tee_ioctl_buf_data __user *ubuf)
|
struct tee_ioctl_buf_data __user *ubuf)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
size_t n;
|
|
||||||
struct tee_ioctl_buf_data buf;
|
struct tee_ioctl_buf_data buf;
|
||||||
struct tee_ioctl_invoke_arg __user *uarg;
|
struct tee_ioctl_invoke_arg __user *uarg;
|
||||||
struct tee_ioctl_invoke_arg arg;
|
struct tee_ioctl_invoke_arg arg;
|
||||||
|
|
@ -657,14 +660,7 @@ static int tee_ioctl_invoke(struct tee_context *ctx,
|
||||||
}
|
}
|
||||||
rc = params_to_user(uparams, arg.num_params, params);
|
rc = params_to_user(uparams, arg.num_params, params);
|
||||||
out:
|
out:
|
||||||
if (params) {
|
free_params(params, arg.num_params);
|
||||||
/* Decrease ref count for all valid shared memory pointers */
|
|
||||||
for (n = 0; n < arg.num_params; n++)
|
|
||||||
if (tee_param_is_memref(params + n) &&
|
|
||||||
params[n].u.memref.shm)
|
|
||||||
tee_shm_put(params[n].u.memref.shm);
|
|
||||||
kfree(params);
|
|
||||||
}
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -672,7 +668,6 @@ static int tee_ioctl_object_invoke(struct tee_context *ctx,
|
||||||
struct tee_ioctl_buf_data __user *ubuf)
|
struct tee_ioctl_buf_data __user *ubuf)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
size_t n;
|
|
||||||
struct tee_ioctl_buf_data buf;
|
struct tee_ioctl_buf_data buf;
|
||||||
struct tee_ioctl_object_invoke_arg __user *uarg;
|
struct tee_ioctl_object_invoke_arg __user *uarg;
|
||||||
struct tee_ioctl_object_invoke_arg arg;
|
struct tee_ioctl_object_invoke_arg arg;
|
||||||
|
|
@ -716,14 +711,7 @@ static int tee_ioctl_object_invoke(struct tee_context *ctx,
|
||||||
}
|
}
|
||||||
rc = params_to_user(uparams, arg.num_params, params);
|
rc = params_to_user(uparams, arg.num_params, params);
|
||||||
out:
|
out:
|
||||||
if (params) {
|
free_params(params, arg.num_params);
|
||||||
/* Decrease ref count for all valid shared memory pointers */
|
|
||||||
for (n = 0; n < arg.num_params; n++)
|
|
||||||
if (tee_param_is_memref(params + n) &&
|
|
||||||
params[n].u.memref.shm)
|
|
||||||
tee_shm_put(params[n].u.memref.shm);
|
|
||||||
kfree(params);
|
|
||||||
}
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -846,9 +834,15 @@ static int tee_ioctl_supp_recv(struct tee_context *ctx,
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
rc = params_from_user(ctx, params, num_params, uarg->params);
|
rc = params_from_user(ctx, params, num_params, uarg->params);
|
||||||
if (rc)
|
if (rc) {
|
||||||
goto out;
|
free_params(params, num_params);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* supp_recv() may consume and replace the supplied parameters, so the
|
||||||
|
* final cleanup cannot use free_params() like the other ioctl paths.
|
||||||
|
*/
|
||||||
rc = ctx->teedev->desc->ops->supp_recv(ctx, &func, &num_params, params);
|
rc = ctx->teedev->desc->ops->supp_recv(ctx, &func, &num_params, params);
|
||||||
if (rc)
|
if (rc)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
|
||||||
|
|
@ -435,7 +435,7 @@ register_shm_helper(struct tee_context *ctx, struct iov_iter *iter, u32 flags,
|
||||||
num_pages = iov_iter_npages(iter, INT_MAX);
|
num_pages = iov_iter_npages(iter, INT_MAX);
|
||||||
if (!num_pages) {
|
if (!num_pages) {
|
||||||
ret = ERR_PTR(-ENOMEM);
|
ret = ERR_PTR(-ENOMEM);
|
||||||
goto err_ctx_put;
|
goto err_free_shm;
|
||||||
}
|
}
|
||||||
|
|
||||||
shm->pages = kzalloc_objs(*shm->pages, num_pages);
|
shm->pages = kzalloc_objs(*shm->pages, num_pages);
|
||||||
|
|
|
||||||
|
|
@ -177,13 +177,13 @@ static int ufs_qcom_ice_init(struct ufs_qcom_host *host)
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
ice = devm_of_qcom_ice_get(dev);
|
ice = devm_of_qcom_ice_get(dev);
|
||||||
if (ice == ERR_PTR(-EOPNOTSUPP)) {
|
if (IS_ERR(ice)) {
|
||||||
dev_warn(dev, "Disabling inline encryption support\n");
|
if (ice != ERR_PTR(-EOPNOTSUPP))
|
||||||
ice = NULL;
|
return PTR_ERR(ice);
|
||||||
}
|
|
||||||
|
|
||||||
if (IS_ERR_OR_NULL(ice))
|
dev_warn(dev, "Disabling inline encryption support\n");
|
||||||
return PTR_ERR_OR_ZERO(ice);
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
host->ice = ice;
|
host->ice = ice;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -470,6 +470,7 @@ struct tee_ioctl_object_invoke_arg {
|
||||||
__u32 op;
|
__u32 op;
|
||||||
__u32 ret;
|
__u32 ret;
|
||||||
__u32 num_params;
|
__u32 num_params;
|
||||||
|
__u32 :32;
|
||||||
/* num_params tells the actual number of element in params */
|
/* num_params tells the actual number of element in params */
|
||||||
struct tee_ioctl_param params[];
|
struct tee_ioctl_param params[];
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue