Qualcomm ARM Based Driver Updates for v4.20

* Refactor of SCM compatibles and clock requirements
 * SMEM cleanup
 * Add LLCC EDAC driver
 * Fixes for GENI clocks and macros
 * Fix includes for llcc-slice and smem
 * String overflow fixes for APR and wcnss_ctrl
 * Fixup for COMPILE_TEST of qcom driver Kconfigs
 * Cleanup of Kconfig depends of rpmh, smd_rpm, smsm, and smp2p
 * Add SCM dependencies to SPM and rmtfs-mem
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIcBAABAgAGBQJbsQupAAoJEFKiBbHx2RXVQBYQAKWr3RsQlWJ09M0vm8qGeCCA
 8FXxX9wqcU34KvYR16IIXzQ/25L4h1uLjvjBfQurn7zOFIrCoqn2PGOchGOyJEA0
 hPw+RomT17BV1hRSJkl8lIXMqGCAvoc44VrAQyipCTpEJO82emh6qJ1ki5XpIvfI
 EOad6S2IGNXU39F0B6rtl4+LL/Vfh+MOJcz0E23SVujtDT0pvxuP5aVGM+Faqif/
 rQ4dKcYZokRHmuTlfg2azo4OmkLyrwsMjirna3NN3MX14wK5Ox53ESplGZXndt3V
 Gy48IbXdTTjbmHT07aqPVSkFgulkaE9Z3MTw+vyn/r10ww6R55XtoSJIbS/v4+Y0
 mzjTYTSHmxzpGHR4Rs+E1q9/7y8tbxO0uzFMHlmD8fNNbkK3FlXymGfVJFjSJGSN
 hTN97zEYUKco4M6RXAly8XUrOetSglZwul1+gQnHYYCx7Y8BhgpyZtyjVeKzg1Mw
 wqgAi+1+cOLG2JjI+h0Xo0xqvuWwl3e2jrmBZNs9BWoXaaWA2L7oqPL3bxq2TeWs
 kF56I7YH5eD5sUGvShjrJ9WfKeN4hWpYSif/qg58kqz/zbCSjmmfiqQ7HmjJUetm
 JnAZaik38YhsDvR8K1gECQiN2myjojjdyg3ONBk2y0Yho+ClVSMPo/qCceRy21/q
 LVTRThQ0tZExH8zEJrJt
 =rx3Z
 -----END PGP SIGNATURE-----

Merge tag 'qcom-drivers-for-4.20' of git://git.kernel.org/pub/scm/linux/kernel/git/agross/linux into next/drivers

Qualcomm ARM Based Driver Updates for v4.20

* Refactor of SCM compatibles and clock requirements
* SMEM cleanup
* Add LLCC EDAC driver
* Fixes for GENI clocks and macros
* Fix includes for llcc-slice and smem
* String overflow fixes for APR and wcnss_ctrl
* Fixup for COMPILE_TEST of qcom driver Kconfigs
* Cleanup of Kconfig depends of rpmh, smd_rpm, smsm, and smp2p
* Add SCM dependencies to SPM and rmtfs-mem

* tag 'qcom-drivers-for-4.20' of git://git.kernel.org/pub/scm/linux/kernel/git/agross/linux: (38 commits)
  soc: qcom: geni: geni_se_clk_freq_match() should always accept multiples
  soc: qcom: geni: Don't ignore clk_round_rate() errors in geni_se_clk_tbl_get()
  soc: qcom: geni: Make version macros simpler
  dt-bindings: firmware: scm: Add MSM8998 and SDM845
  firmware: qcom: scm: Refactor clock handling
  dt-bindings: firmware: scm: Refactor compatibles and clocks
  soc: qcom: smem: a few last cleanups
  soc: qcom: smem: verify partition host ids match
  soc: qcom: smem: small change in global entry loop
  soc: qcom: smem: verify partition offset_free_uncached
  soc: qcom: smem: verify partition header size
  soc: qcom: smem: introduce qcom_smem_partition_header()
  soc: qcom: smem: require order of host ids to match
  soc: qcom: smem: verify both host ids in partition header
  soc: qcom: smem: small refactor in qcom_smem_enumerate_partitions()
  soc: qcom: smem: always ignore partitions with 0 offset or size
  soc: qcom: smem: initialize region struct only when successful
  soc: qcom: smem: rename variable in qcom_smem_get_global()
  drivers: qcom: rpmh-rsc: clear wait_for_compl after use
  soc: qcom: rmtfs-mem: Validate that scm is available
  ...

Signed-off-by: Arnd Bergmann <[email protected]>
This commit is contained in:
Arnd Bergmann 2018-10-02 10:11:05 +02:00
commit 64d20b774f
18 changed files with 732 additions and 202 deletions

View file

@ -33,7 +33,7 @@ config QCOM_GLINK_SSR
config QCOM_GSBI
tristate "QCOM General Serial Bus Interface"
depends on ARCH_QCOM
depends on ARCH_QCOM || COMPILE_TEST
select MFD_SYSCON
help
Say y here to enable GSBI support. The GSBI provides control
@ -42,7 +42,7 @@ config QCOM_GSBI
config QCOM_LLCC
tristate "Qualcomm Technologies, Inc. LLCC driver"
depends on ARCH_QCOM
depends on ARCH_QCOM || COMPILE_TEST
help
Qualcomm Technologies, Inc. platform specific
Last Level Cache Controller(LLCC) driver. This provides interfaces
@ -73,7 +73,8 @@ config QCOM_PM
config QCOM_QMI_HELPERS
tristate
depends on ARCH_QCOM && NET
depends on ARCH_QCOM || COMPILE_TEST
depends on NET
help
Helper library for handling QMI encoded messages. QMI encoded
messages are used in communication between the majority of QRTR
@ -94,7 +95,7 @@ config QCOM_RMTFS_MEM
config QCOM_RPMH
bool "Qualcomm RPM-Hardened (RPMH) Communication"
depends on ARCH_QCOM && ARM64 && OF || COMPILE_TEST
depends on ARCH_QCOM && ARM64 || COMPILE_TEST
help
Support for communication with the hardened-RPM blocks in
Qualcomm Technologies Inc (QTI) SoCs. RPMH communication uses an
@ -104,7 +105,7 @@ config QCOM_RPMH
config QCOM_SMEM
tristate "Qualcomm Shared Memory Manager (SMEM)"
depends on ARCH_QCOM
depends on ARCH_QCOM || COMPILE_TEST
depends on HWSPINLOCK
help
Say y here to enable support for the Qualcomm Shared Memory Manager.
@ -113,8 +114,8 @@ config QCOM_SMEM
config QCOM_SMD_RPM
tristate "Qualcomm Resource Power Manager (RPM) over SMD"
depends on ARCH_QCOM
depends on RPMSG && OF
depends on ARCH_QCOM || COMPILE_TEST
depends on RPMSG
help
If you say yes to this option, support will be included for the
Resource Power Manager system found in the Qualcomm 8974 based
@ -134,6 +135,7 @@ config QCOM_SMP2P
depends on MAILBOX
depends on QCOM_SMEM
select QCOM_SMEM_STATE
select IRQ_DOMAIN
help
Say yes here to support the Qualcomm Shared Memory Point to Point
protocol.
@ -142,13 +144,14 @@ config QCOM_SMSM
tristate "Qualcomm Shared Memory State Machine"
depends on QCOM_SMEM
select QCOM_SMEM_STATE
select IRQ_DOMAIN
help
Say yes here to support the Qualcomm Shared Memory State Machine.
The state machine is represented by bits in shared memory.
config QCOM_WCNSS_CTRL
tristate "Qualcomm WCNSS control driver"
depends on ARCH_QCOM
depends on ARCH_QCOM || COMPILE_TEST
depends on RPMSG
help
Client driver for the WCNSS_CTRL SMD channel, used to download nv
@ -156,7 +159,7 @@ config QCOM_WCNSS_CTRL
config QCOM_APR
tristate "Qualcomm APR Bus (Asynchronous Packet Router)"
depends on ARCH_QCOM
depends on ARCH_QCOM || COMPILE_TEST
depends on RPMSG
help
Enable APR IPC protocol support between

View file

@ -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) {
dev_err(apr->dev, "APR: Wrong paket size\n");
dev_err(apr->dev, "APR: Wrong packet size\n");
return -EINVAL;
}
@ -219,9 +219,9 @@ static int apr_add_device(struct device *dev, struct device_node *np,
adev->domain_id = id->domain_id;
adev->version = id->svc_version;
if (np)
strncpy(adev->name, np->name, APR_NAME_SIZE);
strscpy(adev->name, np->name, APR_NAME_SIZE);
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,
id->domain_id, id->svc_id);

View file

@ -13,6 +13,7 @@
#include <linux/mutex.h>
#include <linux/of_device.h>
#include <linux/regmap.h>
#include <linux/sizes.h>
#include <linux/slab.h>
#include <linux/soc/qcom/llcc-qcom.h>
@ -106,22 +107,24 @@ static int llcc_update_act_ctrl(u32 sid,
u32 slice_status;
int ret;
act_ctrl_reg = drv_data->bcast_off + LLCC_TRP_ACT_CTRLn(sid);
status_reg = drv_data->bcast_off + LLCC_TRP_STATUSn(sid);
act_ctrl_reg = LLCC_TRP_ACT_CTRLn(sid);
status_reg = LLCC_TRP_STATUSn(sid);
/* Set the ACTIVE trigger */
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)
return ret;
/* Clear the ACTIVE trigger */
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)
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),
0, LLCC_STATUS_READ_DELAY);
return ret;
@ -223,19 +226,16 @@ static int qcom_llcc_cfg_program(struct platform_device *pdev)
u32 attr0_val;
u32 max_cap_cacheline;
u32 sz;
int ret;
int ret = 0;
const struct llcc_slice_config *llcc_table;
struct llcc_slice_desc desc;
u32 bcast_off = drv_data->bcast_off;
sz = drv_data->cfg_size;
llcc_table = drv_data->cfg;
for (i = 0; i < sz; i++) {
attr1_cfg = bcast_off +
LLCC_TRP_ATTR1_CFGn(llcc_table[i].slice_id);
attr0_cfg = bcast_off +
LLCC_TRP_ATTR0_CFGn(llcc_table[i].slice_id);
attr1_cfg = LLCC_TRP_ATTR1_CFGn(llcc_table[i].slice_id);
attr0_cfg = LLCC_TRP_ATTR0_CFGn(llcc_table[i].slice_id);
attr1_val = llcc_table[i].cache_mode;
attr1_val |= llcc_table[i].probe_target_ways <<
@ -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].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)
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)
return ret;
if (llcc_table[i].activate_on_init) {
@ -279,24 +281,37 @@ int qcom_llcc_probe(struct platform_device *pdev,
{
u32 num_banks;
struct device *dev = &pdev->dev;
struct resource *res;
void __iomem *base;
struct resource *llcc_banks_res, *llcc_bcast_res;
void __iomem *llcc_banks_base, *llcc_bcast_base;
int ret, i;
struct platform_device *llcc_edac;
drv_data = devm_kzalloc(dev, sizeof(*drv_data), GFP_KERNEL);
if (!drv_data)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(base))
return PTR_ERR(base);
llcc_banks_res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"llcc_base");
llcc_banks_base = devm_ioremap_resource(&pdev->dev, llcc_banks_res);
if (IS_ERR(llcc_banks_base))
return PTR_ERR(llcc_banks_base);
drv_data->regmap = devm_regmap_init_mmio(dev, base,
&llcc_regmap_config);
drv_data->regmap = devm_regmap_init_mmio(dev, llcc_banks_base,
&llcc_regmap_config);
if (IS_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,
&num_banks);
if (ret)
@ -318,8 +333,6 @@ int qcom_llcc_probe(struct platform_device *pdev,
for (i = 0; i < num_banks; i++)
drv_data->offsets[i] = i * BANK_OFFSET_STRIDE;
drv_data->bcast_off = num_banks * BANK_OFFSET_STRIDE;
drv_data->bitmap = devm_kcalloc(dev,
BITS_TO_LONGS(drv_data->max_slices), sizeof(unsigned long),
GFP_KERNEL);
@ -331,7 +344,20 @@ int qcom_llcc_probe(struct platform_device *pdev,
mutex_init(&drv_data->lock);
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);

View file

@ -513,7 +513,7 @@ EXPORT_SYMBOL(geni_se_resources_on);
*/
int geni_se_clk_tbl_get(struct geni_se *se, unsigned long **tbl)
{
unsigned long freq = 0;
long freq = 0;
int i;
if (se->clk_perf_tbl) {
@ -529,7 +529,7 @@ int geni_se_clk_tbl_get(struct geni_se *se, unsigned long **tbl)
for (i = 0; i < MAX_CLK_PERF_LEVEL; i++) {
freq = clk_round_rate(se->clk, freq + 1);
if (!freq || freq == se->clk_perf_tbl[i - 1])
if (freq <= 0 || freq == se->clk_perf_tbl[i - 1])
break;
se->clk_perf_tbl[i] = freq;
}
@ -544,16 +544,17 @@ EXPORT_SYMBOL(geni_se_clk_tbl_get);
* @se: Pointer to the concerned serial engine.
* @req_freq: Requested clock frequency.
* @index: Index of the resultant frequency in the table.
* @res_freq: Resultant frequency which matches or is closer to the
* requested frequency.
* @res_freq: Resultant frequency of the source clock.
* @exact: Flag to indicate exact multiple requirement of the requested
* frequency.
*
* This function is called by the protocol drivers to determine the matching
* or exact multiple of the requested frequency, as provided by the serial
* engine clock in order to meet the performance requirements. If there is
* no matching or exact multiple of the requested frequency found, then it
* selects the closest floor frequency, if exact flag is not set.
* This function is called by the protocol drivers to determine the best match
* of the requested frequency as provided by the serial engine clock in order
* to meet the performance requirements.
*
* If we return success:
* - if @exact is true then @res_freq / <an_integer> == @req_freq
* - if @exact is false then @res_freq / <an_integer> <= @req_freq
*
* Return: 0 on success, standard Linux error codes on failure.
*/
@ -564,6 +565,9 @@ int geni_se_clk_freq_match(struct geni_se *se, unsigned long req_freq,
unsigned long *tbl;
int num_clk_levels;
int i;
unsigned long best_delta;
unsigned long new_delta;
unsigned int divider;
num_clk_levels = geni_se_clk_tbl_get(se, &tbl);
if (num_clk_levels < 0)
@ -572,18 +576,21 @@ int geni_se_clk_freq_match(struct geni_se *se, unsigned long req_freq,
if (num_clk_levels == 0)
return -EINVAL;
*res_freq = 0;
best_delta = ULONG_MAX;
for (i = 0; i < num_clk_levels; i++) {
if (!(tbl[i] % req_freq)) {
divider = DIV_ROUND_UP(tbl[i], req_freq);
new_delta = req_freq - tbl[i] / divider;
if (new_delta < best_delta) {
/* We have a new best! */
*index = i;
*res_freq = tbl[i];
return 0;
}
if (!(*res_freq) || ((tbl[i] > *res_freq) &&
(tbl[i] < req_freq))) {
*index = i;
*res_freq = tbl[i];
/* If the new best is exact then we're done */
if (new_delta == 0)
return 0;
/* Record how close we got */
best_delta = new_delta;
}
}

View file

@ -212,6 +212,11 @@ static int qcom_rmtfs_mem_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "failed to parse qcom,vmid\n");
goto remove_cdev;
} else if (!ret) {
if (!qcom_scm_is_available()) {
ret = -EPROBE_DEFER;
goto remove_cdev;
}
perms[0].vmid = QCOM_SCM_VMID_HLOS;
perms[0].perm = QCOM_SCM_PERM_RW;
perms[1].vmid = vmid;

View file

@ -121,6 +121,7 @@ static int tcs_invalidate(struct rsc_drv *drv, int type)
return -EAGAIN;
}
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);
spin_unlock(&tcs->lock);
@ -239,6 +240,7 @@ static irqreturn_t tcs_tx_done(int irq, void *p)
skip:
/* Reclaim the TCS */
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));
spin_lock(&drv->lock);
clear_bit(i, drv->tcs_in_use);

View file

@ -18,6 +18,7 @@
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
#include <linux/sizes.h>
#include <linux/slab.h>
#include <linux/soc/qcom/smem.h>
@ -277,7 +278,7 @@ struct qcom_smem {
u32 item_count;
unsigned num_regions;
struct smem_region regions[0];
struct smem_region regions[];
};
static void *
@ -489,7 +490,7 @@ static void *qcom_smem_get_global(struct qcom_smem *smem,
size_t *size)
{
struct smem_header *header;
struct smem_region *area;
struct smem_region *region;
struct smem_global_entry *entry;
u32 aux_base;
unsigned i;
@ -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;
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)
*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)
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)
{
struct smem_partition_header *header;
struct smem_ptable_entry *entry;
struct smem_ptable *ptable;
u32 host0, host1, size;
bool found = false;
int i;
@ -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++) {
entry = &ptable->entry[i];
host0 = le16_to_cpu(entry->host0);
host1 = le16_to_cpu(entry->host1);
if (!le32_to_cpu(entry->offset))
continue;
if (!le32_to_cpu(entry->size))
continue;
if (host0 == SMEM_GLOBAL_HOST && host0 == host1) {
if (le16_to_cpu(entry->host0) != SMEM_GLOBAL_HOST)
continue;
if (le16_to_cpu(entry->host1) == SMEM_GLOBAL_HOST) {
found = true;
break;
}
@ -756,36 +809,10 @@ static int qcom_smem_set_global_partition(struct qcom_smem *smem)
return -EINVAL;
}
if (!le32_to_cpu(entry->offset) || !le32_to_cpu(entry->size)) {
dev_err(smem->dev, "Invalid entry for global partition\n");
header = qcom_smem_partition_header(smem, entry,
SMEM_GLOBAL_HOST, SMEM_GLOBAL_HOST);
if (!header)
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_cacheline = le32_to_cpu(entry->cacheline);
@ -793,14 +820,14 @@ static int qcom_smem_set_global_partition(struct qcom_smem *smem)
return 0;
}
static int qcom_smem_enumerate_partitions(struct qcom_smem *smem,
unsigned int local_host)
static int
qcom_smem_enumerate_partitions(struct qcom_smem *smem, u16 local_host)
{
struct smem_partition_header *header;
struct smem_ptable_entry *entry;
struct smem_ptable *ptable;
unsigned int remote_host;
u32 host0, host1;
u16 host0, host1;
int i;
ptable = qcom_smem_get_ptable(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++) {
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))
continue;
if (!le32_to_cpu(entry->size))
continue;
host0 = le16_to_cpu(entry->host0);
host1 = le16_to_cpu(entry->host1);
if (host0 == local_host)
remote_host = host1;
else
else if (host1 == local_host)
remote_host = host0;
else
continue;
if (remote_host >= SMEM_HOST_COUNT) {
dev_err(smem->dev,
"Invalid remote host %d\n",
remote_host);
dev_err(smem->dev, "bad host %hu\n", remote_host);
return -EINVAL;
}
if (smem->partitions[remote_host]) {
dev_err(smem->dev,
"Already found a partition for host %d\n",
remote_host);
dev_err(smem->dev, "duplicate host %hu\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);
header = qcom_smem_partition_header(smem, entry, host0, host1);
if (!header)
return -EINVAL;
}
if (host0 != local_host && host1 != local_host) {
dev_err(smem->dev,
"Partition %d hosts are invalid\n", i);
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->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,
{
struct device_node *np;
struct resource r;
resource_size_t size;
int ret;
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,
of_node_put(np);
if (ret)
return ret;
size = resource_size(&r);
smem->regions[i].aux_base = (u32)r.start;
smem->regions[i].size = resource_size(&r);
smem->regions[i].virt_base = devm_ioremap_wc(dev, r.start, resource_size(&r));
smem->regions[i].virt_base = devm_ioremap_wc(dev, r.start, size);
if (!smem->regions[i].virt_base)
return -ENOMEM;
smem->regions[i].aux_base = (u32)r.start;
smem->regions[i].size = size;
return 0;
}
@ -962,6 +953,7 @@ static int qcom_smem_probe(struct platform_device *pdev)
return -EINVAL;
}
BUILD_BUG_ON(SMEM_HOST_APPS >= SMEM_HOST_COUNT);
ret = qcom_smem_enumerate_partitions(smem, SMEM_HOST_APPS);
if (ret < 0 && ret != -ENOENT)
return ret;

View file

@ -219,6 +219,9 @@ static int __init qcom_cpuidle_init(struct device_node *cpu_node, int cpu)
cpumask_t mask;
bool use_scm_power_down = false;
if (!qcom_scm_is_available())
return -EPROBE_DEFER;
for (i = 0; ; i++) {
state_node = of_parse_phandle(cpu_node, "cpu-idle-states", i);
if (!state_node)

View file

@ -281,7 +281,7 @@ struct rpmsg_endpoint *qcom_wcnss_open_channel(void *wcnss, const char *name, rp
struct rpmsg_channel_info chinfo;
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.dst = RPMSG_ADDR_ANY;