Commit 579fde69 authored by Andy Gross's avatar Andy Gross

Merge branch 'drivers-for-4.20' into drivers-for-4.20-final

parents bbd4b28b bb85ce51
...@@ -16,11 +16,26 @@ Properties: ...@@ -16,11 +16,26 @@ Properties:
- reg: - reg:
Usage: required Usage: required
Value Type: <prop-encoded-array> Value Type: <prop-encoded-array>
Definition: Start address and the the size of the register region. Definition: The first element specifies the llcc base start address and
the size of the register region. The second element specifies
the llcc broadcast base address and size of the register region.
- reg-names:
Usage: required
Value Type: <stringlist>
Definition: Register region names. Must be "llcc_base", "llcc_broadcast_base".
- interrupts:
Usage: required
Definition: The interrupt is associated with the llcc edac device.
It's used for llcc cache single and double bit error detection
and reporting.
Example: Example:
cache-controller@1100000 { cache-controller@1100000 {
compatible = "qcom,sdm845-llcc"; compatible = "qcom,sdm845-llcc";
reg = <0x1100000 0x250000>; reg = <0x1100000 0x200000>, <0x1300000 0x50000> ;
reg-names = "llcc_base", "llcc_broadcast_base";
interrupts = <GIC_SPI 582 IRQ_TYPE_LEVEL_HIGH>;
}; };
...@@ -7,16 +7,23 @@ assorted actions. ...@@ -7,16 +7,23 @@ assorted actions.
Required properties: Required properties:
- compatible: must contain one of the following: - compatible: must contain one of the following:
* "qcom,scm-apq8064" for APQ8064 platforms * "qcom,scm-apq8064"
* "qcom,scm-msm8660" for MSM8660 platforms * "qcom,scm-apq8084"
* "qcom,scm-msm8690" for MSM8690 platforms * "qcom,scm-msm8660"
* "qcom,scm-msm8996" for MSM8996 platforms * "qcom,scm-msm8916"
* "qcom,scm-ipq4019" for IPQ4019 platforms * "qcom,scm-msm8960"
* "qcom,scm" for later processors (MSM8916, APQ8084, MSM8974, etc) * "qcom,scm-msm8974"
- clocks: One to three clocks may be required based on compatible. * "qcom,scm-msm8996"
* No clock required for "qcom,scm-msm8996", "qcom,scm-ipq4019" * "qcom,scm-msm8998"
* Only core clock required for "qcom,scm-apq8064", "qcom,scm-msm8660", and "qcom,scm-msm8960" * "qcom,scm-ipq4019"
* Core, iface, and bus clocks required for "qcom,scm" * "qcom,scm-sdm845"
and:
* "qcom,scm"
- clocks: Specifies clocks needed by the SCM interface, if any:
* core clock required for "qcom,scm-apq8064", "qcom,scm-msm8660" and
"qcom,scm-msm8960"
* core, iface and bus clocks required for "qcom,scm-apq8084",
"qcom,scm-msm8916" and "qcom,scm-msm8974"
- clock-names: Must contain "core" for the core clock, "iface" for the interface - clock-names: Must contain "core" for the core clock, "iface" for the interface
clock and "bus" for the bus clock per the requirements of the compatible. clock and "bus" for the bus clock per the requirements of the compatible.
- qcom,dload-mode: phandle to the TCSR hardware block and offset of the - qcom,dload-mode: phandle to the TCSR hardware block and offset of the
...@@ -26,8 +33,10 @@ Example for MSM8916: ...@@ -26,8 +33,10 @@ Example for MSM8916:
firmware { firmware {
scm { scm {
compatible = "qcom,scm"; compatible = "qcom,msm8916", "qcom,scm";
clocks = <&gcc GCC_CRYPTO_CLK> , <&gcc GCC_CRYPTO_AXI_CLK>, <&gcc GCC_CRYPTO_AHB_CLK>; clocks = <&gcc GCC_CRYPTO_CLK> ,
<&gcc GCC_CRYPTO_AXI_CLK>,
<&gcc GCC_CRYPTO_AHB_CLK>;
clock-names = "core", "bus", "iface"; clock-names = "core", "bus", "iface";
}; };
}; };
...@@ -5346,6 +5346,14 @@ L: linux-edac@vger.kernel.org ...@@ -5346,6 +5346,14 @@ L: linux-edac@vger.kernel.org
S: Maintained S: Maintained
F: drivers/edac/ti_edac.c F: drivers/edac/ti_edac.c
EDAC-QCOM
M: Channagoud Kadabi <ckadabi@codeaurora.org>
M: Venkata Narendra Kumar Gutta <vnkgutta@codeaurora.org>
L: linux-arm-msm@vger.kernel.org
L: linux-edac@vger.kernel.org
S: Maintained
F: drivers/edac/qcom_edac.c
EDIROL UA-101/UA-1000 DRIVER EDIROL UA-101/UA-1000 DRIVER
M: Clemens Ladisch <clemens@ladisch.de> M: Clemens Ladisch <clemens@ladisch.de>
L: alsa-devel@alsa-project.org (moderated for non-subscribers) L: alsa-devel@alsa-project.org (moderated for non-subscribers)
......
...@@ -460,4 +460,18 @@ config EDAC_TI ...@@ -460,4 +460,18 @@ config EDAC_TI
Support for error detection and correction on the Support for error detection and correction on the
TI SoCs. TI SoCs.
config EDAC_QCOM
tristate "QCOM EDAC Controller"
depends on ARCH_QCOM && QCOM_LLCC
help
Support for error detection and correction on the
Qualcomm Technologies, Inc. SoCs.
This driver reports Single Bit Errors (SBEs) and Double Bit Errors (DBEs).
As of now, it supports error reporting for Last Level Cache Controller (LLCC)
of Tag RAM and Data RAM.
For debugging issues having to do with stability and overall system
health, you should probably say 'Y' here.
endif # EDAC endif # EDAC
...@@ -77,3 +77,4 @@ obj-$(CONFIG_EDAC_ALTERA) += altera_edac.o ...@@ -77,3 +77,4 @@ obj-$(CONFIG_EDAC_ALTERA) += altera_edac.o
obj-$(CONFIG_EDAC_SYNOPSYS) += synopsys_edac.o obj-$(CONFIG_EDAC_SYNOPSYS) += synopsys_edac.o
obj-$(CONFIG_EDAC_XGENE) += xgene_edac.o obj-$(CONFIG_EDAC_XGENE) += xgene_edac.o
obj-$(CONFIG_EDAC_TI) += ti_edac.o obj-$(CONFIG_EDAC_TI) += ti_edac.o
obj-$(CONFIG_EDAC_QCOM) += qcom_edac.o
This diff is collapsed.
...@@ -525,34 +525,44 @@ static int qcom_scm_probe(struct platform_device *pdev) ...@@ -525,34 +525,44 @@ static int qcom_scm_probe(struct platform_device *pdev)
return ret; return ret;
clks = (unsigned long)of_device_get_match_data(&pdev->dev); clks = (unsigned long)of_device_get_match_data(&pdev->dev);
if (clks & SCM_HAS_CORE_CLK) {
scm->core_clk = devm_clk_get(&pdev->dev, "core"); scm->core_clk = devm_clk_get(&pdev->dev, "core");
if (IS_ERR(scm->core_clk)) { if (IS_ERR(scm->core_clk)) {
if (PTR_ERR(scm->core_clk) != -EPROBE_DEFER) if (PTR_ERR(scm->core_clk) == -EPROBE_DEFER)
dev_err(&pdev->dev, return PTR_ERR(scm->core_clk);
"failed to acquire core clk\n");
if (clks & SCM_HAS_CORE_CLK) {
dev_err(&pdev->dev, "failed to acquire core clk\n");
return PTR_ERR(scm->core_clk); return PTR_ERR(scm->core_clk);
} }
scm->core_clk = NULL;
} }
if (clks & SCM_HAS_IFACE_CLK) { scm->iface_clk = devm_clk_get(&pdev->dev, "iface");
scm->iface_clk = devm_clk_get(&pdev->dev, "iface"); if (IS_ERR(scm->iface_clk)) {
if (IS_ERR(scm->iface_clk)) { if (PTR_ERR(scm->iface_clk) == -EPROBE_DEFER)
if (PTR_ERR(scm->iface_clk) != -EPROBE_DEFER) return PTR_ERR(scm->iface_clk);
dev_err(&pdev->dev,
"failed to acquire iface clk\n"); if (clks & SCM_HAS_IFACE_CLK) {
dev_err(&pdev->dev, "failed to acquire iface clk\n");
return PTR_ERR(scm->iface_clk); return PTR_ERR(scm->iface_clk);
} }
scm->iface_clk = NULL;
} }
if (clks & SCM_HAS_BUS_CLK) { scm->bus_clk = devm_clk_get(&pdev->dev, "bus");
scm->bus_clk = devm_clk_get(&pdev->dev, "bus"); if (IS_ERR(scm->bus_clk)) {
if (IS_ERR(scm->bus_clk)) { if (PTR_ERR(scm->bus_clk) == -EPROBE_DEFER)
if (PTR_ERR(scm->bus_clk) != -EPROBE_DEFER) return PTR_ERR(scm->bus_clk);
dev_err(&pdev->dev,
"failed to acquire bus clk\n"); if (clks & SCM_HAS_BUS_CLK) {
dev_err(&pdev->dev, "failed to acquire bus clk\n");
return PTR_ERR(scm->bus_clk); return PTR_ERR(scm->bus_clk);
} }
scm->bus_clk = NULL;
} }
scm->reset.ops = &qcom_scm_pas_reset_ops; scm->reset.ops = &qcom_scm_pas_reset_ops;
...@@ -594,23 +604,23 @@ static const struct of_device_id qcom_scm_dt_match[] = { ...@@ -594,23 +604,23 @@ static const struct of_device_id qcom_scm_dt_match[] = {
{ .compatible = "qcom,scm-apq8064", { .compatible = "qcom,scm-apq8064",
/* FIXME: This should have .data = (void *) SCM_HAS_CORE_CLK */ /* FIXME: This should have .data = (void *) SCM_HAS_CORE_CLK */
}, },
{ .compatible = "qcom,scm-msm8660", { .compatible = "qcom,scm-apq8084", .data = (void *)(SCM_HAS_CORE_CLK |
.data = (void *) SCM_HAS_CORE_CLK, SCM_HAS_IFACE_CLK |
}, SCM_HAS_BUS_CLK)
{ .compatible = "qcom,scm-msm8960",
.data = (void *) SCM_HAS_CORE_CLK,
},
{ .compatible = "qcom,scm-msm8996",
.data = NULL, /* no clocks */
}, },
{ .compatible = "qcom,scm-ipq4019", { .compatible = "qcom,scm-ipq4019" },
.data = NULL, /* no clocks */ { .compatible = "qcom,scm-msm8660", .data = (void *) SCM_HAS_CORE_CLK },
{ .compatible = "qcom,scm-msm8960", .data = (void *) SCM_HAS_CORE_CLK },
{ .compatible = "qcom,scm-msm8916", .data = (void *)(SCM_HAS_CORE_CLK |
SCM_HAS_IFACE_CLK |
SCM_HAS_BUS_CLK)
}, },
{ .compatible = "qcom,scm", { .compatible = "qcom,scm-msm8974", .data = (void *)(SCM_HAS_CORE_CLK |
.data = (void *)(SCM_HAS_CORE_CLK SCM_HAS_IFACE_CLK |
| SCM_HAS_IFACE_CLK SCM_HAS_BUS_CLK)
| SCM_HAS_BUS_CLK),
}, },
{ .compatible = "qcom,scm-msm8996" },
{ .compatible = "qcom,scm" },
{} {}
}; };
......
...@@ -33,7 +33,7 @@ config QCOM_GLINK_SSR ...@@ -33,7 +33,7 @@ config QCOM_GLINK_SSR
config QCOM_GSBI config QCOM_GSBI
tristate "QCOM General Serial Bus Interface" tristate "QCOM General Serial Bus Interface"
depends on ARCH_QCOM depends on ARCH_QCOM || COMPILE_TEST
select MFD_SYSCON select MFD_SYSCON
help help
Say y here to enable GSBI support. The GSBI provides control Say y here to enable GSBI support. The GSBI provides control
...@@ -42,7 +42,7 @@ config QCOM_GSBI ...@@ -42,7 +42,7 @@ config QCOM_GSBI
config QCOM_LLCC config QCOM_LLCC
tristate "Qualcomm Technologies, Inc. LLCC driver" tristate "Qualcomm Technologies, Inc. LLCC driver"
depends on ARCH_QCOM depends on ARCH_QCOM || COMPILE_TEST
help help
Qualcomm Technologies, Inc. platform specific Qualcomm Technologies, Inc. platform specific
Last Level Cache Controller(LLCC) driver. This provides interfaces Last Level Cache Controller(LLCC) driver. This provides interfaces
...@@ -73,7 +73,8 @@ config QCOM_PM ...@@ -73,7 +73,8 @@ config QCOM_PM
config QCOM_QMI_HELPERS config QCOM_QMI_HELPERS
tristate tristate
depends on ARCH_QCOM && NET depends on ARCH_QCOM || COMPILE_TEST
depends on NET
help help
Helper library for handling QMI encoded messages. QMI encoded Helper library for handling QMI encoded messages. QMI encoded
messages are used in communication between the majority of QRTR messages are used in communication between the majority of QRTR
...@@ -94,7 +95,7 @@ config QCOM_RMTFS_MEM ...@@ -94,7 +95,7 @@ config QCOM_RMTFS_MEM
config QCOM_RPMH config QCOM_RPMH
bool "Qualcomm RPM-Hardened (RPMH) Communication" bool "Qualcomm RPM-Hardened (RPMH) Communication"
depends on ARCH_QCOM && ARM64 && OF || COMPILE_TEST depends on ARCH_QCOM && ARM64 || COMPILE_TEST
help help
Support for communication with the hardened-RPM blocks in Support for communication with the hardened-RPM blocks in
Qualcomm Technologies Inc (QTI) SoCs. RPMH communication uses an Qualcomm Technologies Inc (QTI) SoCs. RPMH communication uses an
...@@ -104,7 +105,7 @@ config QCOM_RPMH ...@@ -104,7 +105,7 @@ config QCOM_RPMH
config QCOM_SMEM config QCOM_SMEM
tristate "Qualcomm Shared Memory Manager (SMEM)" tristate "Qualcomm Shared Memory Manager (SMEM)"
depends on ARCH_QCOM depends on ARCH_QCOM || COMPILE_TEST
depends on HWSPINLOCK depends on HWSPINLOCK
help help
Say y here to enable support for the Qualcomm Shared Memory Manager. Say y here to enable support for the Qualcomm Shared Memory Manager.
...@@ -113,8 +114,8 @@ config QCOM_SMEM ...@@ -113,8 +114,8 @@ config QCOM_SMEM
config QCOM_SMD_RPM config QCOM_SMD_RPM
tristate "Qualcomm Resource Power Manager (RPM) over SMD" tristate "Qualcomm Resource Power Manager (RPM) over SMD"
depends on ARCH_QCOM depends on ARCH_QCOM || COMPILE_TEST
depends on RPMSG && OF depends on RPMSG
help help
If you say yes to this option, support will be included for the If you say yes to this option, support will be included for the
Resource Power Manager system found in the Qualcomm 8974 based Resource Power Manager system found in the Qualcomm 8974 based
...@@ -134,6 +135,7 @@ config QCOM_SMP2P ...@@ -134,6 +135,7 @@ config QCOM_SMP2P
depends on MAILBOX depends on MAILBOX
depends on QCOM_SMEM depends on QCOM_SMEM
select QCOM_SMEM_STATE select QCOM_SMEM_STATE
select IRQ_DOMAIN
help help
Say yes here to support the Qualcomm Shared Memory Point to Point Say yes here to support the Qualcomm Shared Memory Point to Point
protocol. protocol.
...@@ -142,13 +144,14 @@ config QCOM_SMSM ...@@ -142,13 +144,14 @@ config QCOM_SMSM
tristate "Qualcomm Shared Memory State Machine" tristate "Qualcomm Shared Memory State Machine"
depends on QCOM_SMEM depends on QCOM_SMEM
select QCOM_SMEM_STATE select QCOM_SMEM_STATE
select IRQ_DOMAIN
help help
Say yes here to support the Qualcomm Shared Memory State Machine. Say yes here to support the Qualcomm Shared Memory State Machine.
The state machine is represented by bits in shared memory. The state machine is represented by bits in shared memory.
config QCOM_WCNSS_CTRL config QCOM_WCNSS_CTRL
tristate "Qualcomm WCNSS control driver" tristate "Qualcomm WCNSS control driver"
depends on ARCH_QCOM depends on ARCH_QCOM || COMPILE_TEST
depends on RPMSG depends on RPMSG
help help
Client driver for the WCNSS_CTRL SMD channel, used to download nv Client driver for the WCNSS_CTRL SMD channel, used to download nv
...@@ -156,7 +159,7 @@ config QCOM_WCNSS_CTRL ...@@ -156,7 +159,7 @@ config QCOM_WCNSS_CTRL
config QCOM_APR config QCOM_APR
tristate "Qualcomm APR Bus (Asynchronous Packet Router)" tristate "Qualcomm APR Bus (Asynchronous Packet Router)"
depends on ARCH_QCOM depends on ARCH_QCOM || COMPILE_TEST
depends on RPMSG depends on RPMSG
help help
Enable APR IPC protocol support between Enable APR IPC protocol support between
......
...@@ -87,7 +87,7 @@ static int apr_callback(struct rpmsg_device *rpdev, void *buf, ...@@ -87,7 +87,7 @@ static int apr_callback(struct rpmsg_device *rpdev, void *buf,
} }
if (hdr->pkt_size < APR_HDR_SIZE || hdr->pkt_size != len) { if (hdr->pkt_size < APR_HDR_SIZE || hdr->pkt_size != len) {
dev_err(apr->dev, "APR: Wrong paket size\n"); dev_err(apr->dev, "APR: Wrong packet size\n");
return -EINVAL; return -EINVAL;
} }
...@@ -219,9 +219,9 @@ static int apr_add_device(struct device *dev, struct device_node *np, ...@@ -219,9 +219,9 @@ static int apr_add_device(struct device *dev, struct device_node *np,
adev->domain_id = id->domain_id; adev->domain_id = id->domain_id;
adev->version = id->svc_version; adev->version = id->svc_version;
if (np) if (np)
strncpy(adev->name, np->name, APR_NAME_SIZE); strscpy(adev->name, np->name, APR_NAME_SIZE);
else else
strncpy(adev->name, id->name, APR_NAME_SIZE); strscpy(adev->name, id->name, APR_NAME_SIZE);
dev_set_name(&adev->dev, "aprsvc:%s:%x:%x", adev->name, dev_set_name(&adev->dev, "aprsvc:%s:%x:%x", adev->name,
id->domain_id, id->svc_id); id->domain_id, id->svc_id);
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/sizes.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/soc/qcom/llcc-qcom.h> #include <linux/soc/qcom/llcc-qcom.h>
...@@ -106,22 +107,24 @@ static int llcc_update_act_ctrl(u32 sid, ...@@ -106,22 +107,24 @@ static int llcc_update_act_ctrl(u32 sid,
u32 slice_status; u32 slice_status;
int ret; int ret;
act_ctrl_reg = drv_data->bcast_off + LLCC_TRP_ACT_CTRLn(sid); act_ctrl_reg = LLCC_TRP_ACT_CTRLn(sid);
status_reg = drv_data->bcast_off + LLCC_TRP_STATUSn(sid); status_reg = LLCC_TRP_STATUSn(sid);
/* Set the ACTIVE trigger */ /* Set the ACTIVE trigger */
act_ctrl_reg_val |= ACT_CTRL_ACT_TRIG; act_ctrl_reg_val |= ACT_CTRL_ACT_TRIG;
ret = regmap_write(drv_data->regmap, act_ctrl_reg, act_ctrl_reg_val); ret = regmap_write(drv_data->bcast_regmap, act_ctrl_reg,
act_ctrl_reg_val);
if (ret) if (ret)
return ret; return ret;
/* Clear the ACTIVE trigger */ /* Clear the ACTIVE trigger */
act_ctrl_reg_val &= ~ACT_CTRL_ACT_TRIG; act_ctrl_reg_val &= ~ACT_CTRL_ACT_TRIG;
ret = regmap_write(drv_data->regmap, act_ctrl_reg, act_ctrl_reg_val); ret = regmap_write(drv_data->bcast_regmap, act_ctrl_reg,
act_ctrl_reg_val);
if (ret) if (ret)
return ret; return ret;
ret = regmap_read_poll_timeout(drv_data->regmap, status_reg, ret = regmap_read_poll_timeout(drv_data->bcast_regmap, status_reg,
slice_status, !(slice_status & status), slice_status, !(slice_status & status),
0, LLCC_STATUS_READ_DELAY); 0, LLCC_STATUS_READ_DELAY);
return ret; return ret;
...@@ -223,19 +226,16 @@ static int qcom_llcc_cfg_program(struct platform_device *pdev) ...@@ -223,19 +226,16 @@ static int qcom_llcc_cfg_program(struct platform_device *pdev)
u32 attr0_val; u32 attr0_val;
u32 max_cap_cacheline; u32 max_cap_cacheline;
u32 sz; u32 sz;
int ret; int ret = 0;
const struct llcc_slice_config *llcc_table; const struct llcc_slice_config *llcc_table;
struct llcc_slice_desc desc; struct llcc_slice_desc desc;
u32 bcast_off = drv_data->bcast_off;
sz = drv_data->cfg_size; sz = drv_data->cfg_size;
llcc_table = drv_data->cfg; llcc_table = drv_data->cfg;
for (i = 0; i < sz; i++) { for (i = 0; i < sz; i++) {
attr1_cfg = bcast_off + attr1_cfg = LLCC_TRP_ATTR1_CFGn(llcc_table[i].slice_id);
LLCC_TRP_ATTR1_CFGn(llcc_table[i].slice_id); attr0_cfg = LLCC_TRP_ATTR0_CFGn(llcc_table[i].slice_id);
attr0_cfg = bcast_off +
LLCC_TRP_ATTR0_CFGn(llcc_table[i].slice_id);
attr1_val = llcc_table[i].cache_mode; attr1_val = llcc_table[i].cache_mode;
attr1_val |= llcc_table[i].probe_target_ways << attr1_val |= llcc_table[i].probe_target_ways <<
...@@ -260,10 +260,12 @@ static int qcom_llcc_cfg_program(struct platform_device *pdev) ...@@ -260,10 +260,12 @@ static int qcom_llcc_cfg_program(struct platform_device *pdev)
attr0_val = llcc_table[i].res_ways & ATTR0_RES_WAYS_MASK; attr0_val = llcc_table[i].res_ways & ATTR0_RES_WAYS_MASK;
attr0_val |= llcc_table[i].bonus_ways << ATTR0_BONUS_WAYS_SHIFT; attr0_val |= llcc_table[i].bonus_ways << ATTR0_BONUS_WAYS_SHIFT;
ret = regmap_write(drv_data->regmap, attr1_cfg, attr1_val); ret = regmap_write(drv_data->bcast_regmap, attr1_cfg,
attr1_val);
if (ret) if (ret)
return ret; return ret;
ret = regmap_write(drv_data->regmap, attr0_cfg, attr0_val); ret = regmap_write(drv_data->bcast_regmap, attr0_cfg,
attr0_val);
if (ret) if (ret)
return ret; return ret;
if (llcc_table[i].activate_on_init) { if (llcc_table[i].activate_on_init) {
...@@ -279,24 +281,37 @@ int qcom_llcc_probe(struct platform_device *pdev, ...@@ -279,24 +281,37 @@ int qcom_llcc_probe(struct platform_device *pdev,
{ {
u32 num_banks; u32 num_banks;
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct resource *res; struct resource *llcc_banks_res, *llcc_bcast_res;
void __iomem *base; void __iomem *llcc_banks_base, *llcc_bcast_base;
int ret, i; int ret, i;
struct platform_device *llcc_edac;
drv_data = devm_kzalloc(dev, sizeof(*drv_data), GFP_KERNEL); drv_data = devm_kzalloc(dev, sizeof(*drv_data), GFP_KERNEL);
if (!drv_data) if (!drv_data)
return -ENOMEM; return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); llcc_banks_res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
base = devm_ioremap_resource(&pdev->dev, res); "llcc_base");
if (IS_ERR(base)) llcc_banks_base = devm_ioremap_resource(&pdev->dev, llcc_banks_res);
return PTR_ERR(base); if (IS_ERR(llcc_banks_base))
return PTR_ERR(llcc_banks_base);
drv_data->regmap = devm_regmap_init_mmio(dev, base, drv_data->regmap = devm_regmap_init_mmio(dev, llcc_banks_base,
&llcc_regmap_config); &llcc_regmap_config);
if (IS_ERR(drv_data->regmap)) if (IS_ERR(drv_data->regmap))
return PTR_ERR(drv_data->regmap); return PTR_ERR(drv_data->regmap);
llcc_bcast_res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"llcc_broadcast_base");
llcc_bcast_base = devm_ioremap_resource(&pdev->dev, llcc_bcast_res);
if (IS_ERR(llcc_bcast_base))
return PTR_ERR(llcc_bcast_base);
drv_data->bcast_regmap = devm_regmap_init_mmio(dev, llcc_bcast_base,
&llcc_regmap_config);
if (IS_ERR(drv_data->bcast_regmap))
return PTR_ERR(drv_data->bcast_regmap);
ret = regmap_read(drv_data->regmap, LLCC_COMMON_STATUS0, ret = regmap_read(drv_data->regmap, LLCC_COMMON_STATUS0,
&num_banks); &num_banks);
if (ret) if (ret)
...@@ -318,8 +333,6 @@ int qcom_llcc_probe(struct platform_device *pdev, ...@@ -318,8 +333,6 @@ int qcom_llcc_probe(struct platform_device *pdev,
for (i = 0; i < num_banks; i++) for (i = 0; i < num_banks; i++)
drv_data->offsets[i] = i * BANK_OFFSET_STRIDE; drv_data->offsets[i] = i * BANK_OFFSET_STRIDE;
drv_data->bcast_off = num_banks * BANK_OFFSET_STRIDE;
drv_data->bitmap = devm_kcalloc(dev, drv_data->bitmap = devm_kcalloc(dev,
BITS_TO_LONGS(drv_data->max_slices), sizeof(unsigned long), BITS_TO_LONGS(drv_data->max_slices), sizeof(unsigned long),
GFP_KERNEL); GFP_KERNEL);
...@@ -331,7 +344,20 @@ int qcom_llcc_probe(struct platform_device *pdev, ...@@ -331,7 +344,20 @@ int qcom_llcc_probe(struct platform_device *pdev,
mutex_init(&drv_data->lock); mutex_init(&drv_data->lock);
platform_set_drvdata(pdev, drv_data); platform_set_drvdata(pdev, drv_data);
return qcom_llcc_cfg_program(pdev); ret = qcom_llcc_cfg_program(pdev);
if (ret)
return ret;
drv_data->ecc_irq = platform_get_irq(pdev, 0);
if (drv_data->ecc_irq >= 0) {
llcc_edac = platform_device_register_data(&pdev->dev,
"qcom_llcc_edac", -1, drv_data,
sizeof(*drv_data));
if (IS_ERR(llcc_edac))
dev_err(dev, "Failed to register llcc edac driver\n");
}
return ret;
} }
EXPORT_SYMBOL_GPL(qcom_llcc_probe); EXPORT_SYMBOL_GPL(qcom_llcc_probe);
......
...@@ -212,6 +212,11 @@ static int qcom_rmtfs_mem_probe(struct platform_device *pdev) ...@@ -212,6 +212,11 @@ static int qcom_rmtfs_mem_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "failed to parse qcom,vmid\n"); dev_err(&pdev->dev, "failed to parse qcom,vmid\n");
goto remove_cdev; goto remove_cdev;
} else if (!ret) { } else if (!ret) {
if (!qcom_scm_is_available()) {
ret = -EPROBE_DEFER;
goto remove_cdev;
}
perms[0].vmid = QCOM_SCM_VMID_HLOS; perms[0].vmid = QCOM_SCM_VMID_HLOS;
perms[0].perm = QCOM_SCM_PERM_RW; perms[0].perm = QCOM_SCM_PERM_RW;
perms[1].vmid = vmid; perms[1].vmid = vmid;
......
...@@ -121,6 +121,7 @@ static int tcs_invalidate(struct rsc_drv *drv, int type) ...@@ -121,6 +121,7 @@ static int tcs_invalidate(struct rsc_drv *drv, int type)
return -EAGAIN; return -EAGAIN;
} }
write_tcs_reg_sync(drv, RSC_DRV_CMD_ENABLE, m, 0); write_tcs_reg_sync(drv, RSC_DRV_CMD_ENABLE, m, 0);
write_tcs_reg_sync(drv, RSC_DRV_CMD_WAIT_FOR_CMPL, m, 0);
} }
bitmap_zero(tcs->slots, MAX_TCS_SLOTS); bitmap_zero(tcs->slots, MAX_TCS_SLOTS);
spin_unlock(&tcs->lock); spin_unlock(&tcs->lock);
...@@ -239,6 +240,7 @@ static irqreturn_t tcs_tx_done(int irq, void *p) ...@@ -239,6 +240,7 @@ static irqreturn_t tcs_tx_done(int irq, void *p)
skip: skip:
/* Reclaim the TCS */ /* Reclaim the TCS */
write_tcs_reg(drv, RSC_DRV_CMD_ENABLE, i, 0); write_tcs_reg(drv, RSC_DRV_CMD_ENABLE, i, 0);
write_tcs_reg(drv, RSC_DRV_CMD_WAIT_FOR_CMPL, i, 0);
write_tcs_reg(drv, RSC_DRV_IRQ_CLEAR, 0, BIT(i)); write_tcs_reg(drv, RSC_DRV_IRQ_CLEAR, 0, BIT(i));
spin_lock(&drv->lock); spin_lock(&drv->lock);
clear_bit(i, drv->tcs_in_use); clear_bit(i, drv->tcs_in_use);
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/sizes.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/soc/qcom/smem.h> #include <linux/soc/qcom/smem.h>
...@@ -277,7 +278,7 @@ struct qcom_smem { ...@@ -277,7 +278,7 @@ struct qcom_smem {
u32 item_count; u32 item_count;
unsigned num_regions; unsigned num_regions;
struct smem_region regions[0]; struct smem_region regions[];
}; };
static void * static void *
...@@ -489,7 +490,7 @@ static void *qcom_smem_get_global(struct qcom_smem *smem, ...@@ -489,7 +490,7 @@ static void *qcom_smem_get_global(struct qcom_smem *smem,
size_t *size) size_t *size)
{ {
struct smem_header *header; struct smem_header *header;
struct smem_region *area; struct smem_region *region;
struct smem_global_entry *entry; struct smem_global_entry *entry;
u32 aux_base; u32 aux_base;
unsigned i; unsigned i;
...@@ -502,12 +503,12 @@ static void *qcom_smem_get_global(struct qcom_smem *smem, ...@@ -502,12 +503,12 @@ static void *qcom_smem_get_global(struct qcom_smem *smem,
aux_base = le32_to_cpu(entry->aux_base) & AUX_BASE_MASK; aux_base = le32_to_cpu(entry->aux_base) & AUX_BASE_MASK;
for (i = 0; i < smem->num_regions; i++) { for (i = 0; i < smem->num_regions; i++) {
area = &smem->regions[i]; region = &smem->regions[i];
if (area->aux_base == aux_base || !aux_base) { if (region->aux_base == aux_base || !aux_base) {
if (size != NULL) if (size != NULL)
*size = le32_to_cpu(entry->size); *size = le32_to_cpu(entry->size);
return area->virt_base + le32_to_cpu(entry->offset); return region->virt_base + le32_to_cpu(entry->offset);
} }
} }
...@@ -722,12 +723,59 @@ static u32 qcom_smem_get_item_count(struct qcom_smem *smem) ...@@ -722,12 +723,59 @@ static u32 qcom_smem_get_item_count(struct qcom_smem *smem)
return le16_to_cpu(info->num_items); return le16_to_cpu(info->num_items);
} }
/*
* Validate the partition header for a partition whose partition
* table entry is supplied. Returns a pointer to its header if
* valid, or a null pointer otherwise.
*/
static struct smem_partition_header *
qcom_smem_partition_header(struct qcom_smem *smem,
struct smem_ptable_entry *entry, u16 host0, u16 host1)
{
struct smem_partition_header *header;
u32 size;
header = smem->regions[0].virt_base + le32_to_cpu(entry->offset);
if (memcmp(header->magic, SMEM_PART_MAGIC, sizeof(header->magic))) {
dev_err(smem->dev, "bad partition magic %02x %02x %02x %02x\n",
header->magic[0], header->magic[1],
header->magic[2], header->magic[3]);
return NULL;
}
if (host0 != le16_to_cpu(header->host0)) {
dev_err(smem->dev, "bad host0 (%hu != %hu)\n",
host0, le16_to_cpu(header->host0));
return NULL;
}
if (host1 != le16_to_cpu(header->host1)) {
dev_err(smem->dev, "bad host1 (%hu != %hu)\n",
host1, le16_to_cpu(header->host1));
return NULL;
}
size = le32_to_cpu(header->size);
if (size != le32_to_cpu(entry->size)) {
dev_err(smem->dev, "bad partition size (%u != %u)\n",
size, le32_to_cpu(entry->size));
return NULL;
}
if (le32_to_cpu(header->offset_free_uncached) > size) {
dev_err(smem->dev, "bad partition free uncached (%u > %u)\n",
le32_to_cpu(header->offset_free_uncached), size);
return NULL;
}
return header;
}
static int qcom_smem_set_global_partition(struct qcom_smem *smem) static int qcom_smem_set_global_partition(struct qcom_smem *smem)
{ {
struct smem_partition_header *header; struct smem_partition_header *header;
struct smem_ptable_entry *entry; struct smem_ptable_entry *entry;
struct smem_ptable *ptable; struct smem_ptable *ptable;
u32 host0, host1, size;
bool found = false; bool found = false;
int i; int i;
...@@ -742,10 +790,15 @@ static int qcom_smem_set_global_partition(struct qcom_smem *smem) ...@@ -742,10 +790,15 @@ static int qcom_smem_set_global_partition(struct qcom_smem *smem)
for (i = 0; i < le32_to_cpu(ptable->num_entries); i++) { for (i = 0; i < le32_to_cpu(ptable->num_entries); i++) {
entry = &ptable->entry[i]; entry = &ptable->entry[i];
host0 = le16_to_cpu(entry->host0); if (!le32_to_cpu(entry->offset))
host1 = le16_to_cpu(entry->host1); continue;
if (!le32_to_cpu(entry->size))
continue;
if (le16_to_cpu(entry->host0) != SMEM_GLOBAL_HOST)
continue;
if (host0 == SMEM_GLOBAL_HOST && host0 == host1) { if (le16_to_cpu(entry->host1) == SMEM_GLOBAL_HOST) {
found = true; found = true;
break; break;
} }
...@@ -756,36 +809,10 @@ static int qcom_smem_set_global_partition(struct qcom_smem *smem) ...@@ -756,36 +809,10 @@ static int qcom_smem_set_global_partition(struct qcom_smem *smem)
return -EINVAL; return -EINVAL;
} }
if (!le32_to_cpu(entry->offset) || !le32_to_cpu(entry->size)) { header = qcom_smem_partition_header(smem, entry,
dev_err(smem->dev, "Invalid entry for global partition\n"); SMEM_GLOBAL_HOST, SMEM_GLOBAL_HOST);
if (!header)
return -EINVAL; return -EINVAL;
}
header = smem->regions[0].virt_base + le32_to_cpu(entry->offset);
host0 = le16_to_cpu(header->host0);
host1 = le16_to_cpu(header->host1);
if (memcmp(header->magic, SMEM_PART_MAGIC, sizeof(header->magic))) {
dev_err(smem->dev, "Global partition has invalid magic\n");
return -EINVAL;
}
if (host0 != SMEM_GLOBAL_HOST && host1 != SMEM_GLOBAL_HOST) {
dev_err(smem->dev, "Global partition hosts are invalid\n");
return -EINVAL;
}
if (le32_to_cpu(header->size) != le32_to_cpu(entry->size)) {
dev_err(smem->dev, "Global partition has invalid size\n");
return -EINVAL;
}
size = le32_to_cpu(header->offset_free_uncached);
if (size > le32_to_cpu(header->size)) {
dev_err(smem->dev,
"Global partition has invalid free pointer\n");
return -EINVAL;
}
smem->global_partition = header; smem->global_partition = header;
smem->global_cacheline = le32_to_cpu(entry->cacheline); smem->global_cacheline = le32_to_cpu(entry->cacheline);
...@@ -793,14 +820,14 @@ static int qcom_smem_set_global_partition(struct qcom_smem *smem) ...@@ -793,14 +820,14 @@ static int qcom_smem_set_global_partition(struct qcom_smem *smem)
return 0; return 0;
} }
static int qcom_smem_enumerate_partitions(struct qcom_smem *smem, static int
unsigned int local_host) qcom_smem_enumerate_partitions(struct qcom_smem *smem, u16 local_host)
{ {
struct smem_partition_header *header; struct smem_partition_header *header;
struct smem_ptable_entry *entry; struct smem_ptable_entry *entry;
struct smem_ptable *ptable; struct smem_ptable *ptable;
unsigned int remote_host; unsigned int remote_host;
u32 host0, host1; u16 host0, host1;
int i; int i;
ptable = qcom_smem_get_ptable(smem); ptable = qcom_smem_get_ptable(smem);
...@@ -809,71 +836,33 @@ static int qcom_smem_enumerate_partitions(struct qcom_smem *smem, ...@@ -809,71 +836,33 @@ static int qcom_smem_enumerate_partitions(struct qcom_smem *smem,
for (i = 0; i < le32_to_cpu(ptable->num_entries); i++) { for (i = 0; i < le32_to_cpu(ptable->num_entries); i++) {
entry = &ptable->entry[i]; entry = &ptable->entry[i];
host0 = le16_to_cpu(entry->host0);
host1 = le16_to_cpu(entry->host1);
if (host0 != local_host && host1 != local_host)
continue;
if (!le32_to_cpu(entry->offset)) if (!le32_to_cpu(entry->offset))
continue; continue;
if (!le32_to_cpu(entry->size)) if (!le32_to_cpu(entry->size))
continue; continue;
host0 = le16_to_cpu(entry->host0);
host1 = le16_to_cpu(entry->host1);
if (host0 == local_host) if (host0 == local_host)
remote_host = host1; remote_host = host1;
else else if (host1 == local_host)
remote_host = host0; remote_host = host0;
else
continue;
if (remote_host >= SMEM_HOST_COUNT) { if (remote_host >= SMEM_HOST_COUNT) {
dev_err(smem->dev, dev_err(smem->dev, "bad host %hu\n", remote_host);
"Invalid remote host %d\n",
remote_host);
return -EINVAL; return -EINVAL;
} }
if (smem->partitions[remote_host]) { if (smem->partitions[remote_host]) {
dev_err(smem->dev, dev_err(smem->dev, "duplicate host %hu\n", remote_host);
"Already found a partition for host %d\n",
remote_host);
return -EINVAL;
}
header = smem->regions[0].virt_base + le32_to_cpu(entry->offset);
host0 = le16_to_cpu(header->host0);
host1 = le16_to_cpu(header->host1);
if (memcmp(header->magic, SMEM_PART_MAGIC,
sizeof(header->magic))) {
dev_err(smem->dev,
"Partition %d has invalid magic\n", i);
return -EINVAL; return -EINVAL;
} }
if (host0 != local_host && host1 != local_host) { header = qcom_smem_partition_header(smem, entry, host0, host1);
dev_err(smem->dev, if (!header)
"Partition %d hosts are invalid\n", i);
return -EINVAL; return -EINVAL;
}
if (host0 != remote_host && host1 != remote_host) {
dev_err(smem->dev,
"Partition %d hosts are invalid\n", i);
return -EINVAL;
}
if (le32_to_cpu(header->size) != le32_to_cpu(entry->size)) {
dev_err(smem->dev,
"Partition %d has invalid size\n", i);
return -EINVAL;
}
if (le32_to_cpu(header->offset_free_uncached) > le32_to_cpu(header->size)) {
dev_err(smem->dev,
"Partition %d has invalid free pointer\n", i);
return -EINVAL;
}
smem->partitions[remote_host] = header; smem->partitions[remote_host] = header;
smem->cacheline[remote_host] = le32_to_cpu(entry->cacheline); smem->cacheline[remote_host] = le32_to_cpu(entry->cacheline);
...@@ -887,6 +876,7 @@ static int qcom_smem_map_memory(struct qcom_smem *smem, struct device *dev, ...@@ -887,6 +876,7 @@ static int qcom_smem_map_memory(struct qcom_smem *smem, struct device *dev,
{ {
struct device_node *np; struct device_node *np;
struct resource r; struct resource r;
resource_size_t size;
int ret; int ret;
np = of_parse_phandle(dev->of_node, name, 0); np = of_parse_phandle(dev->of_node, name, 0);
...@@ -899,12 +889,13 @@ static int qcom_smem_map_memory(struct qcom_smem *smem, struct device *dev, ...@@ -899,12 +889,13 @@ static int qcom_smem_map_memory(struct qcom_smem *smem, struct device *dev,
of_node_put(np); of_node_put(np);
if (ret) if (ret)
return ret; return ret;
size = resource_size(&r);
smem->regions[i].aux_base = (u32)r.start; smem->regions[i].virt_base = devm_ioremap_wc(dev, r.start, size);
smem->regions[i].size = resource_size(&r);
smem->regions[i].virt_base = devm_ioremap_wc(dev, r.start, resource_size(&r));
if (!smem->regions[i].virt_base) if (!smem->regions[i].virt_base)
return -ENOMEM; return -ENOMEM;
smem->regions[i].aux_base = (u32)r.start;
smem->regions[i].size = size;
return 0; return 0;
} }
...@@ -962,6 +953,7 @@ static int qcom_smem_probe(struct platform_device *pdev) ...@@ -962,6 +953,7 @@ static int qcom_smem_probe(struct platform_device *pdev)
return -EINVAL; return -EINVAL;
} }
BUILD_BUG_ON(SMEM_HOST_APPS >= SMEM_HOST_COUNT);
ret = qcom_smem_enumerate_partitions(smem, SMEM_HOST_APPS); ret = qcom_smem_enumerate_partitions(smem, SMEM_HOST_APPS);
if (ret < 0 && ret != -ENOENT) if (ret < 0 && ret != -ENOENT)
return ret; return ret;
......
...@@ -219,6 +219,9 @@ static int __init qcom_cpuidle_init(struct device_node *cpu_node, int cpu) ...@@ -219,6 +219,9 @@ static int __init qcom_cpuidle_init(struct device_node *cpu_node, int cpu)
cpumask_t mask; cpumask_t mask;
bool use_scm_power_down = false; bool use_scm_power_down = false;
if (!qcom_scm_is_available())
return -EPROBE_DEFER;
for (i = 0; ; i++) { for (i = 0; ; i++) {
state_node = of_parse_phandle(cpu_node, "cpu-idle-states", i); state_node = of_parse_phandle(cpu_node, "cpu-idle-states", i);
if (!state_node) if (!state_node)
......
...@@ -281,7 +281,7 @@ struct rpmsg_endpoint *qcom_wcnss_open_channel(void *wcnss, const char *name, rp ...@@ -281,7 +281,7 @@ struct rpmsg_endpoint *qcom_wcnss_open_channel(void *wcnss, const char *name, rp
struct rpmsg_channel_info chinfo; struct rpmsg_channel_info chinfo;
struct wcnss_ctrl *_wcnss = wcnss; struct wcnss_ctrl *_wcnss = wcnss;
strncpy(chinfo.name, name, sizeof(chinfo.name)); strscpy(chinfo.name, name, sizeof(chinfo.name));
chinfo.src = RPMSG_ADDR_ANY; chinfo.src = RPMSG_ADDR_ANY;
chinfo.dst = RPMSG_ADDR_ANY; chinfo.dst = RPMSG_ADDR_ANY;
......
...@@ -70,25 +70,51 @@ struct llcc_slice_config { ...@@ -70,25 +70,51 @@ struct llcc_slice_config {
/** /**
* llcc_drv_data - Data associated with the llcc driver * llcc_drv_data - Data associated with the llcc driver
* @regmap: regmap associated with the llcc device * @regmap: regmap associated with the llcc device
* @bcast_regmap: regmap associated with llcc broadcast offset
* @cfg: pointer to the data structure for slice configuration * @cfg: pointer to the data structure for slice configuration
* @lock: mutex associated with each slice * @lock: mutex associated with each slice
* @cfg_size: size of the config data table * @cfg_size: size of the config data table
* @max_slices: max slices as read from device tree * @max_slices: max slices as read from device tree
* @bcast_off: Offset of the broadcast bank
* @num_banks: Number of llcc banks * @num_banks: Number of llcc banks
* @bitmap: Bit map to track the active slice ids * @bitmap: Bit map to track the active slice ids
* @offsets: Pointer to the bank offsets array * @offsets: Pointer to the bank offsets array
* @ecc_irq: interrupt for llcc cache error detection and reporting
*/ */
struct llcc_drv_data { struct llcc_drv_data {
struct regmap *regmap; struct regmap *regmap;
struct regmap *bcast_regmap;
const struct llcc_slice_config *cfg; const struct llcc_slice_config *cfg;
struct mutex lock; struct mutex lock;
u32 cfg_size; u32 cfg_size;
u32 max_slices; u32 max_slices;
u32 bcast_off;
u32 num_banks; u32 num_banks;
unsigned long *bitmap; unsigned long *bitmap;
u32 *offsets; u32 *offsets;
int ecc_irq;
};
/**
* llcc_edac_reg_data - llcc edac registers data for each error type
* @name: Name of the error
* @synd_reg: Syndrome register address
* @count_status_reg: Status register address to read the error count
* @ways_status_reg: Status register address to read the error ways
* @reg_cnt: Number of registers
* @count_mask: Mask value to get the error count
* @ways_mask: Mask value to get the error ways
* @count_shift: Shift value to get the error count
* @ways_shift: Shift value to get the error ways
*/
struct llcc_edac_reg_data {
char *name;
u64 synd_reg;
u64 count_status_reg;
u64 ways_status_reg;
u32 reg_cnt;
u32 count_mask;
u32 ways_mask;
u8 count_shift;
u8 ways_shift;
}; };
#if IS_ENABLED(CONFIG_QCOM_LLCC) #if IS_ENABLED(CONFIG_QCOM_LLCC)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment