mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-13 16:16:15 -04:00
Merge 774e901388 on remote branch
Change-Id: Ibc8c93267cfdd3c78c80d62bdb38a2b10607f62f
This commit is contained in:
commit
b82eb1e1fa
35 changed files with 1029 additions and 219 deletions
7
arch/arm/configs/vendor/sdxlemur.config
vendored
7
arch/arm/configs/vendor/sdxlemur.config
vendored
|
|
@ -171,6 +171,8 @@ CONFIG_NET_SCH_PRIO=y
|
|||
CONFIG_NET_SCH_TBF=y
|
||||
CONFIG_QRTR=y
|
||||
CONFIG_QRTR_MHI=y
|
||||
CONFIG_QRTR_MHI_DEV=y
|
||||
CONFIG_QRTR_NODE_ID=2
|
||||
CONFIG_QRTR_SMD=y
|
||||
CONFIG_NETDEVICES=y
|
||||
CONFIG_MAILBOX=y
|
||||
|
|
@ -319,9 +321,7 @@ CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y
|
|||
CONFIG_QCOM_SPS_DMA=y
|
||||
CONFIG_I2C_MSM_V2=y
|
||||
CONFIG_SPI_QUP=y
|
||||
CONFIG_BLK_CGROUP=y
|
||||
CONFIG_IOSCHED_BFQ=y
|
||||
CONFIG_BFQ_GROUP_IOSCHED=y
|
||||
CONFIG_MMC=y
|
||||
CONFIG_SDC_QTI=y
|
||||
CONFIG_MMC_SDHCI=y
|
||||
|
|
@ -368,3 +368,6 @@ CONFIG_PCIEASPM_POWER_SUPERSAVE=y
|
|||
CONFIG_PAGE_POOL=y
|
||||
CONFIG_PHYLINK=m
|
||||
CONFIG_QPS615=m
|
||||
# CONFIG_BLK_CGROUP is not set
|
||||
# CONFIG_BLK_DEBUG_FS is not set
|
||||
# CONFIG_VT is not set
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@
|
|||
|
||||
#define pr_fmt(fmt) "cpufreq_hw_debug: %s: " fmt, __func__
|
||||
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
|
|
@ -19,6 +18,7 @@ enum debug_hw_regs_data {
|
|||
REG_PSTATE_STATUS,
|
||||
REG_EPSS_DEBUG_STATUS,
|
||||
REG_EPSS_DEBUG_SRB,
|
||||
REG_EPSS_DEBUG_LUT,
|
||||
|
||||
REG_ARRAY_SIZE,
|
||||
};
|
||||
|
|
@ -26,7 +26,6 @@ enum debug_hw_regs_data {
|
|||
struct cpufreq_hwregs {
|
||||
void __iomem *base[REG_ARRAY_SIZE];
|
||||
int domain_cnt;
|
||||
struct dentry *debugfs_base;
|
||||
};
|
||||
|
||||
struct cpufreq_register_data {
|
||||
|
|
@ -36,6 +35,8 @@ struct cpufreq_register_data {
|
|||
|
||||
static struct cpufreq_hwregs *hw_regs;
|
||||
static const u16 *offsets;
|
||||
static struct kobj_attribute cpufreq_hwregs_attr;
|
||||
static struct kobject *cpufreqhw_kobj;
|
||||
|
||||
static const u16 cpufreq_qcom_std_data[] = {
|
||||
[REG_PERF_STATE] = 0x920,
|
||||
|
|
@ -49,12 +50,14 @@ static const u16 cpufreq_qcom_std_epss_data[] = {
|
|||
[REG_PSTATE_STATUS] = 0x020,
|
||||
[REG_EPSS_DEBUG_STATUS] = 0x01c,
|
||||
[REG_EPSS_DEBUG_SRB] = 0x0bc,
|
||||
[REG_EPSS_DEBUG_LUT] = 0x100,
|
||||
};
|
||||
|
||||
static int print_cpufreq_hw_debug_regs(struct seq_file *s, void *unused)
|
||||
static ssize_t cpufreq_hwregs_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, char *buf)
|
||||
{
|
||||
int i, j, size = ARRAY_SIZE(cpufreq_qcom_std_data);
|
||||
u32 regval;
|
||||
u32 regval, count = 0;
|
||||
|
||||
static struct cpufreq_register_data data[] = {
|
||||
{"PERF_STATE_DESIRED", REG_PERF_STATE},
|
||||
|
|
@ -62,35 +65,26 @@ static int print_cpufreq_hw_debug_regs(struct seq_file *s, void *unused)
|
|||
{"PSTATE_STATUS", REG_PSTATE_STATUS},
|
||||
{"EPSS_DEBUG_STATUS", REG_EPSS_DEBUG_STATUS},
|
||||
{"EPSS_DEBUG_SRB", REG_EPSS_DEBUG_SRB},
|
||||
{"EPSS_DEBUG_LUT", REG_EPSS_DEBUG_LUT},
|
||||
};
|
||||
|
||||
if (offsets == cpufreq_qcom_std_epss_data)
|
||||
size = ARRAY_SIZE(cpufreq_qcom_std_epss_data);
|
||||
|
||||
for (i = 0; i < hw_regs->domain_cnt; i++) {
|
||||
seq_printf(s, "FREQUENCY DOMAIN %d\n", i);
|
||||
count += scnprintf(buf + count, PAGE_SIZE,
|
||||
"FREQUENCY DOMAIN %d\n", i);
|
||||
for (j = 0; j < size; j++) {
|
||||
regval = readl_relaxed(hw_regs->base[i] +
|
||||
offsets[data[j].offset]);
|
||||
seq_printf(s, "%25s: 0x%.8x\n", data[j].name, regval);
|
||||
count += scnprintf(buf + count, PAGE_SIZE,
|
||||
"%25s: 0x%.8x\n", data[j].name, regval);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return count;
|
||||
}
|
||||
|
||||
static int print_cpufreq_hw_reg_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, print_cpufreq_hw_debug_regs, NULL);
|
||||
}
|
||||
|
||||
static const struct file_operations cpufreq_debug_register_fops = {
|
||||
.open = print_cpufreq_hw_reg_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = seq_release,
|
||||
};
|
||||
|
||||
static int cpufreq_panic_callback(struct notifier_block *nfb,
|
||||
unsigned long event, void *unused)
|
||||
{
|
||||
|
|
@ -103,6 +97,7 @@ static int cpufreq_panic_callback(struct notifier_block *nfb,
|
|||
{"PSTATE_STATUS", REG_PSTATE_STATUS},
|
||||
{"EPSS_DEBUG_STATUS", REG_EPSS_DEBUG_STATUS},
|
||||
{"EPSS_DEBUG_SRB", REG_EPSS_DEBUG_SRB},
|
||||
{"EPSS_DEBUG_LUT", REG_EPSS_DEBUG_LUT},
|
||||
};
|
||||
|
||||
if (offsets == cpufreq_qcom_std_epss_data)
|
||||
|
|
@ -181,22 +176,23 @@ static int enable_cpufreq_hw_debug(struct platform_device *pdev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
hw_regs->debugfs_base = debugfs_create_dir("qcom-cpufreq-hw", NULL);
|
||||
if (!hw_regs->debugfs_base) {
|
||||
dev_err(&pdev->dev, "Failed to create debugfs entry\n");
|
||||
return -ENODEV;
|
||||
cpufreqhw_kobj = kobject_create_and_add("qcom-cpufreq-hw",
|
||||
kernel_kobj);
|
||||
if (!cpufreqhw_kobj)
|
||||
return -ENOMEM;
|
||||
|
||||
sysfs_attr_init(&cpufreq_hwregs_attr.attr);
|
||||
cpufreq_hwregs_attr.attr.name = "print_cpufreq_debug_regs";
|
||||
cpufreq_hwregs_attr.show = cpufreq_hwregs_show;
|
||||
cpufreq_hwregs_attr.attr.mode = 0444;
|
||||
|
||||
ret = sysfs_create_file(cpufreqhw_kobj, &cpufreq_hwregs_attr.attr);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Failed to create sysfs entry\n");
|
||||
kobject_put(cpufreqhw_kobj);
|
||||
}
|
||||
|
||||
if (!debugfs_create_file("print_cpufreq_debug_regs", 0444,
|
||||
hw_regs->debugfs_base, NULL, &cpufreq_debug_register_fops))
|
||||
goto debugfs_fail;
|
||||
|
||||
return 0;
|
||||
|
||||
debugfs_fail:
|
||||
dev_err(&pdev->dev, "Failed to create debugfs entry so cleaning up\n");
|
||||
debugfs_remove_recursive(hw_regs->debugfs_base);
|
||||
return -ENODEV;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int qcom_cpufreq_hw_debug_probe(struct platform_device *pdev)
|
||||
|
|
@ -206,7 +202,8 @@ static int qcom_cpufreq_hw_debug_probe(struct platform_device *pdev)
|
|||
|
||||
static int qcom_cpufreq_hw_debug_remove(struct platform_device *pdev)
|
||||
{
|
||||
debugfs_remove_recursive(hw_regs->debugfs_base);
|
||||
sysfs_remove_file(kernel_kobj, &cpufreq_hwregs_attr.attr);
|
||||
kobject_put(cpufreqhw_kobj);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -869,11 +869,25 @@ static void kgsl_destroy_process_private(struct kref *kref)
|
|||
struct kgsl_process_private *private = container_of(kref,
|
||||
struct kgsl_process_private, refcount);
|
||||
|
||||
mutex_lock(&kgsl_driver.process_mutex);
|
||||
debugfs_remove_recursive(private->debug_root);
|
||||
kgsl_process_uninit_sysfs(private);
|
||||
|
||||
/* When using global pagetables, do not detach global pagetable */
|
||||
if (private->pagetable->name != KGSL_MMU_GLOBAL_PT)
|
||||
kgsl_mmu_detach_pagetable(private->pagetable);
|
||||
|
||||
/* Remove the process struct from the master list */
|
||||
write_lock(&kgsl_driver.proclist_lock);
|
||||
list_del(&private->list);
|
||||
write_unlock(&kgsl_driver.proclist_lock);
|
||||
mutex_unlock(&kgsl_driver.process_mutex);
|
||||
|
||||
put_pid(private->pid);
|
||||
idr_destroy(&private->mem_idr);
|
||||
idr_destroy(&private->syncsource_idr);
|
||||
|
||||
/* When using global pagetables, do not detach global pagetable */
|
||||
/* When using global pagetables, do not put global pagetable */
|
||||
if (private->pagetable->name != KGSL_MMU_GLOBAL_PT)
|
||||
kgsl_mmu_putpagetable(private->pagetable);
|
||||
|
||||
|
|
@ -962,8 +976,15 @@ static struct kgsl_process_private *kgsl_process_private_new(
|
|||
|
||||
kfree(private);
|
||||
private = ERR_PTR(err);
|
||||
return private;
|
||||
}
|
||||
|
||||
kgsl_process_init_sysfs(device, private);
|
||||
kgsl_process_init_debugfs(private);
|
||||
write_lock(&kgsl_driver.proclist_lock);
|
||||
list_add(&private->list, &kgsl_driver.process_list);
|
||||
write_unlock(&kgsl_driver.proclist_lock);
|
||||
|
||||
return private;
|
||||
}
|
||||
|
||||
|
|
@ -1008,8 +1029,8 @@ static void kgsl_process_private_close(struct kgsl_device_private *dev_priv,
|
|||
}
|
||||
|
||||
/*
|
||||
* If this is the last file on the process take down the debug
|
||||
* directories and garbage collect any outstanding resources
|
||||
* If this is the last file on the process garbage collect
|
||||
* any outstanding resources
|
||||
*/
|
||||
|
||||
process_release_memory(private);
|
||||
|
|
@ -1017,18 +1038,6 @@ static void kgsl_process_private_close(struct kgsl_device_private *dev_priv,
|
|||
/* Release all syncsource objects from process private */
|
||||
kgsl_syncsource_process_release_syncsources(private);
|
||||
|
||||
debugfs_remove_recursive(private->debug_root);
|
||||
kgsl_process_uninit_sysfs(private);
|
||||
|
||||
/* When using global pagetables, do not detach global pagetable */
|
||||
if (private->pagetable->name != KGSL_MMU_GLOBAL_PT)
|
||||
kgsl_mmu_detach_pagetable(private->pagetable);
|
||||
|
||||
/* Remove the process struct from the master list */
|
||||
write_lock(&kgsl_driver.proclist_lock);
|
||||
list_del(&private->list);
|
||||
write_unlock(&kgsl_driver.proclist_lock);
|
||||
|
||||
mutex_unlock(&kgsl_driver.process_mutex);
|
||||
|
||||
kgsl_process_private_put(private);
|
||||
|
|
@ -1046,19 +1055,7 @@ static struct kgsl_process_private *kgsl_process_private_open(
|
|||
if (IS_ERR(private))
|
||||
goto done;
|
||||
|
||||
/*
|
||||
* If this is a new process create the debug directories and add it to
|
||||
* the process list
|
||||
*/
|
||||
|
||||
if (private->fd_count++ == 0) {
|
||||
kgsl_process_init_sysfs(device, private);
|
||||
kgsl_process_init_debugfs(private);
|
||||
|
||||
write_lock(&kgsl_driver.proclist_lock);
|
||||
list_add(&private->list, &kgsl_driver.process_list);
|
||||
write_unlock(&kgsl_driver.proclist_lock);
|
||||
}
|
||||
private->fd_count++;
|
||||
|
||||
done:
|
||||
mutex_unlock(&kgsl_driver.process_mutex);
|
||||
|
|
|
|||
|
|
@ -202,10 +202,10 @@ static ssize_t mem_entry_sysfs_show(struct kobject *kobj,
|
|||
ssize_t ret;
|
||||
|
||||
/*
|
||||
* kgsl_process_init_sysfs takes a refcount to the process_private,
|
||||
* which is put when the kobj is released. This implies that priv will
|
||||
* not be freed until this function completes, and no further locking
|
||||
* is needed.
|
||||
* sysfs_remove_file waits for reads to complete before the node is
|
||||
* deleted and process private is freed only once kobj is released.
|
||||
* This implies that priv will not be freed until this function
|
||||
* completes, and no further locking is needed.
|
||||
*/
|
||||
priv = kobj ? container_of(kobj, struct kgsl_process_private, kobj) :
|
||||
NULL;
|
||||
|
|
@ -228,10 +228,10 @@ static ssize_t memtype_sysfs_show(struct kobject *kobj,
|
|||
int id = 0;
|
||||
|
||||
/*
|
||||
* kgsl_process_init_sysfs takes a refcount to the process_private,
|
||||
* which is put when the kobj is released. This implies that priv will
|
||||
* not be freed until this function completes, and no further locking
|
||||
* is needed.
|
||||
* sysfs_remove_file waits for reads to complete before the node is
|
||||
* deleted and process private is freed only once kobj is released.
|
||||
* This implies that priv will not be freed until this function
|
||||
* completes, and no further locking is needed.
|
||||
*/
|
||||
priv = container_of(kobj, struct kgsl_process_private, kobj_memtype);
|
||||
memtype = container_of(attr, struct kgsl_memtype, attr);
|
||||
|
|
@ -261,13 +261,9 @@ static ssize_t memtype_sysfs_show(struct kobject *kobj,
|
|||
return scnprintf(buf, PAGE_SIZE, "%llu\n", size);
|
||||
}
|
||||
|
||||
/* Dummy release function - we have nothing to do here */
|
||||
static void mem_entry_release(struct kobject *kobj)
|
||||
{
|
||||
struct kgsl_process_private *priv;
|
||||
|
||||
priv = container_of(kobj, struct kgsl_process_private, kobj);
|
||||
/* Put the refcount we got in kgsl_process_init_sysfs */
|
||||
kgsl_process_private_put(priv);
|
||||
}
|
||||
|
||||
static const struct sysfs_ops mem_entry_sysfs_ops = {
|
||||
|
|
@ -329,9 +325,6 @@ void kgsl_process_init_sysfs(struct kgsl_device *device,
|
|||
{
|
||||
int i;
|
||||
|
||||
/* Keep private valid until the sysfs enries are removed. */
|
||||
kgsl_process_private_get(private);
|
||||
|
||||
if (kobject_init_and_add(&private->kobj, &ktype_mem_entry,
|
||||
kgsl_driver.prockobj, "%d", pid_nr(private->pid))) {
|
||||
dev_err(device->dev, "Unable to add sysfs for process %d\n",
|
||||
|
|
|
|||
|
|
@ -687,13 +687,18 @@ static void kgsl_device_snapshot_atomic(struct kgsl_device *device)
|
|||
}
|
||||
|
||||
device->snapshot_memory_atomic.size = device->snapshot_memory.size;
|
||||
device->snapshot_memory_atomic.ptr = devm_kzalloc(&device->pdev->dev,
|
||||
device->snapshot_memory_atomic.size, GFP_ATOMIC);
|
||||
if (!device->snapshot_faultcount) {
|
||||
/* Use non-atomic snapshot memory if it is unused */
|
||||
device->snapshot_memory_atomic.ptr = device->snapshot_memory.ptr;
|
||||
} else {
|
||||
device->snapshot_memory_atomic.ptr = devm_kzalloc(&device->pdev->dev,
|
||||
device->snapshot_memory_atomic.size, GFP_ATOMIC);
|
||||
|
||||
if (!device->snapshot_memory_atomic.ptr) {
|
||||
dev_err(device->dev,
|
||||
"KGSL failed to allocate memory for atomic snapshot\n");
|
||||
return;
|
||||
if (!device->snapshot_memory_atomic.ptr) {
|
||||
dev_err(device->dev,
|
||||
"KGSL failed to allocate memory for atomic snapshot\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Allocate memory for the snapshot instance */
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
|
|
@ -1718,6 +1718,13 @@ static int qnoc_probe(struct platform_device *pdev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
ret = clk_bulk_prepare_enable(qp->num_qos_clks, qp->qos_clks);
|
||||
if (ret) {
|
||||
clk_bulk_disable_unprepare(qp->num_clks, qp->bus_clks);
|
||||
dev_err(&pdev->dev, "failed to enable QoS clocks\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_nodes; i++) {
|
||||
size_t j;
|
||||
|
||||
|
|
@ -1732,6 +1739,11 @@ static int qnoc_probe(struct platform_device *pdev)
|
|||
goto err;
|
||||
}
|
||||
|
||||
if (qnodes[i]->qosbox) {
|
||||
qnodes[i]->noc_ops->set_qos(qnodes[i]);
|
||||
qnodes[i]->qosbox->initialized = true;
|
||||
}
|
||||
|
||||
node->name = qnodes[i]->name;
|
||||
node->data = qnodes[i];
|
||||
icc_node_add(node, provider);
|
||||
|
|
@ -1743,6 +1755,8 @@ static int qnoc_probe(struct platform_device *pdev)
|
|||
}
|
||||
data->num_nodes = num_nodes;
|
||||
|
||||
clk_bulk_disable_unprepare(qp->num_qos_clks, qp->qos_clks);
|
||||
|
||||
platform_set_drvdata(pdev, qp);
|
||||
|
||||
dev_info(dev, "Registered HOLI ICC\n");
|
||||
|
|
@ -1758,6 +1772,7 @@ err:
|
|||
icc_node_destroy(node->id);
|
||||
}
|
||||
|
||||
clk_bulk_disable_unprepare(qp->num_qos_clks, qp->qos_clks);
|
||||
clk_bulk_disable_unprepare(qp->num_clks, qp->bus_clks);
|
||||
icc_provider_del(provider);
|
||||
return ret;
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@ obj-$(CONFIG_QCOM_PDC) += qcom-pdc.o
|
|||
obj-$(CONFIG_CSKY_MPINTC) += irq-csky-mpintc.o
|
||||
obj-$(CONFIG_CSKY_APB_INTC) += irq-csky-apb-intc.o
|
||||
obj-$(CONFIG_QCOM_MPM) += mpm.o
|
||||
mpm-objs += qcom-mpm.o qcom-mpm-holi.o qcom-mpm-sdxnightjar.o qcom-mpm-monaco.o qcom-mpm-qcs405.o
|
||||
mpm-objs += qcom-mpm.o qcom-mpm-holi.o qcom-mpm-sdxnightjar.o qcom-mpm-monaco.o qcom-mpm-qcs405.o qcom-mpm-blair.o
|
||||
obj-$(CONFIG_SIFIVE_PLIC) += irq-sifive-plic.o
|
||||
obj-$(CONFIG_IMX_IRQSTEER) += irq-imx-irqsteer.o
|
||||
obj-$(CONFIG_MADERA_IRQ) += irq-madera.o
|
||||
|
|
|
|||
17
drivers/irqchip/qcom-mpm-blair.c
Normal file
17
drivers/irqchip/qcom-mpm-blair.c
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
/*
|
||||
* Copyright (c) 2021, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <soc/qcom/mpm.h>
|
||||
const struct mpm_pin mpm_blair_gic_chip_data[] = {
|
||||
{5, 296}, /* lpass_irq_out_sdc */
|
||||
{12, 422}, /* qmp_usb3_lfps_rxterm_irq_cx */
|
||||
{86, 183}, /* mpm_wake,spmi_m */
|
||||
{89, 314}, /* tsens0_tsens_0C_int */
|
||||
{90, 315}, /* tsens1_tsens_0C_int */
|
||||
{93, 164}, /* eud_p0_dmse_int_mx */
|
||||
{94, 165}, /* eud_p0_dpse_int_mx */
|
||||
{-1},
|
||||
};
|
||||
|
|
@ -572,6 +572,10 @@ static const struct of_device_id mpm_gic_chip_data_table[] = {
|
|||
.compatible = "qcom,mpm-gic-qcs405",
|
||||
.data = mpm_qcs405_gic_chip_data,
|
||||
},
|
||||
{
|
||||
.compatible = "qcom,mpm-gic-blair",
|
||||
.data = mpm_blair_gic_chip_data,
|
||||
},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, mpm_gic_chip_data_table);
|
||||
|
|
|
|||
|
|
@ -312,6 +312,7 @@ void rtc6226_scan(struct work_struct *work)
|
|||
struct kfifo *data_b;
|
||||
int len = 0;
|
||||
u32 next_freq_khz;
|
||||
u8 factor;
|
||||
int retval = 0;
|
||||
int i, rssi;
|
||||
|
||||
|
|
@ -427,7 +428,26 @@ void rtc6226_scan(struct work_struct *work)
|
|||
TUNE_STEP_SIZE) == next_freq_khz) {
|
||||
FMDERR("%s Seek one more time if lower freq is valid\n",
|
||||
__func__);
|
||||
retval = rtc6226_set_seek(radio, SRCH_UP, WRAP_ENABLE);
|
||||
// Tuned to band low limit + chan spacing then seek down with
|
||||
// bandlimit config
|
||||
if (radio->space == 0)
|
||||
factor = 20;
|
||||
else if (radio->space == 1)
|
||||
factor = 10;
|
||||
else
|
||||
factor = 5;
|
||||
retval = rtc6226_set_freq(radio,
|
||||
(radio->recv_conf.band_low_limit + factor) * TUNE_STEP_SIZE);
|
||||
if (retval < 0)
|
||||
goto seek_tune_fail;
|
||||
/* wait for tune to complete. */
|
||||
if (!wait_for_completion_timeout(&radio->completion,
|
||||
msecs_to_jiffies(TUNE_TIMEOUT_MSEC))) {
|
||||
FMDERR("In %s, didn't receive STC for tune\n", __func__);
|
||||
rtc6226_q_event(radio, RTC6226_EVT_ERROR);
|
||||
return;
|
||||
}
|
||||
retval = rtc6226_set_seek(radio, SRCH_DOWN, WRAP_DISABLE);
|
||||
if (retval < 0) {
|
||||
FMDERR("%s seek fail %d\n", __func__, retval);
|
||||
goto seek_tune_fail;
|
||||
|
|
@ -454,10 +474,12 @@ void rtc6226_scan(struct work_struct *work)
|
|||
rssi = radio->registers[RSSI] & RSSI_RSSI;
|
||||
FMDBG("%s freq %d, rssi %d rssi threshold %d\n",
|
||||
__func__, next_freq_khz, rssi, radio->rssi_th);
|
||||
if ((radio->recv_conf.band_low_limit *
|
||||
TUNE_STEP_SIZE) ==
|
||||
next_freq_khz &&
|
||||
rssi >= radio->rssi_th) {
|
||||
// Reach to band low limit,
|
||||
// if SF is 0, means frequency at low limit is a commercial
|
||||
// station Or a invalid channel
|
||||
if (((radio->registers[STATUS] & STATUS_SF) == 0) ||
|
||||
(radio->recv_conf.band_high_limit *
|
||||
TUNE_STEP_SIZE) == next_freq_khz) {
|
||||
FMDERR("lower band freq is valid\n");
|
||||
rtc6226_q_event(radio,
|
||||
RTC6226_EVT_TUNE_SUCC);
|
||||
|
|
|
|||
|
|
@ -200,7 +200,7 @@
|
|||
#define SCAN_PENDING 3
|
||||
#define START_SCAN 1
|
||||
#define TUNE_TIMEOUT_MSEC 3000
|
||||
#define SEEK_TIMEOUT_MSEC 15000
|
||||
#define SEEK_TIMEOUT_MSEC 30000
|
||||
|
||||
#define RTC6226_MIN_SRCH_MODE 0x00
|
||||
#define RTC6226_MAX_SRCH_MODE 0x02
|
||||
|
|
|
|||
|
|
@ -3913,8 +3913,7 @@ int cnss_pci_alloc_fw_mem(struct cnss_pci_data *pci_priv)
|
|||
if (!fw_mem[i].va) {
|
||||
cnss_pr_err("Failed to allocate memory for FW, size: 0x%zx, type: %u\n",
|
||||
fw_mem[i].size, fw_mem[i].type);
|
||||
|
||||
return -ENOMEM;
|
||||
BUG();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@
|
|||
#include <linux/types.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <soc/qcom/subsystem_notif.h>
|
||||
#include <linux/pinctrl/qcom-pinctrl.h>
|
||||
|
||||
#include "../pci.h"
|
||||
|
||||
|
|
@ -764,6 +765,7 @@ struct msm_pcie_dev_t {
|
|||
uint32_t gpio_n;
|
||||
uint32_t parf_deemph;
|
||||
uint32_t parf_swing;
|
||||
uint32_t clkreq_gpio;
|
||||
|
||||
struct msm_pcie_vreg_info_t *cx_vreg;
|
||||
struct msm_pcie_clk_info_t *rate_change_clk;
|
||||
|
|
@ -6266,6 +6268,12 @@ static int msm_pcie_probe(struct platform_device *pdev)
|
|||
PCIE_DBG(pcie_dev, "RC%d: aux clock frequency: %d.\n",
|
||||
pcie_dev->rc_idx, pcie_dev->aux_clk_freq);
|
||||
|
||||
of_property_read_u32(of_node, "qcom,clkreq-gpio",
|
||||
&pcie_dev->clkreq_gpio);
|
||||
|
||||
PCIE_DBG(pcie_dev, "RC%d: clkreq gpio no:%u\n",
|
||||
pcie_dev->rc_idx, pcie_dev->clkreq_gpio);
|
||||
|
||||
pcie_dev->shadow_en = true;
|
||||
pcie_dev->aer_enable = true;
|
||||
|
||||
|
|
@ -7725,6 +7733,10 @@ static int msm_pcie_drv_resume(struct msm_pcie_dev_t *pcie_dev)
|
|||
PCIE_DBG(pcie_dev, "PCIe RC%d: LTSSM_STATE: %s\n",
|
||||
pcie_dev->rc_idx, TO_LTSSM_STR(val & 0x3f));
|
||||
|
||||
msm_gpio_mpm_wake_set(pcie_dev->clkreq_gpio, false);
|
||||
|
||||
PCIE_DBG(pcie_dev, "PCIe: RC%d: disable wake up cap for CLKREQ GPIO\n",
|
||||
pcie_dev->rc_idx);
|
||||
mutex_unlock(&pcie_dev->setup_lock);
|
||||
mutex_unlock(&pcie_dev->recovery_lock);
|
||||
|
||||
|
|
@ -7747,6 +7759,10 @@ static int msm_pcie_drv_suspend(struct msm_pcie_dev_t *pcie_dev,
|
|||
}
|
||||
|
||||
mutex_lock(&pcie_dev->recovery_lock);
|
||||
msm_gpio_mpm_wake_set(pcie_dev->clkreq_gpio, true);
|
||||
|
||||
PCIE_DBG(pcie_dev, "PCIe: RC%d:Enable wake up cap for CLKREQ GPIO\n",
|
||||
pcie_dev->rc_idx);
|
||||
|
||||
/* disable global irq - no more linkdown/aer detection */
|
||||
disable_irq(pcie_dev->irq[MSM_PCIE_INT_GLOBAL_INT].num);
|
||||
|
|
|
|||
|
|
@ -118,7 +118,23 @@
|
|||
.offset = qup_offset, \
|
||||
}
|
||||
|
||||
#define TLMM_NORTH_SPARE_OFFSET 0x1B3000
|
||||
#define TLMM_NORTH_SPARE1_OFFSET 0x1B4000
|
||||
|
||||
#define SPARE_REG(sparereg, spare_offset) \
|
||||
{ \
|
||||
.spare_reg = tlmm_##sparereg, \
|
||||
.offset = spare_offset, \
|
||||
}
|
||||
|
||||
enum blair_tlmm_spare {
|
||||
tlmm_west_spare,
|
||||
tlmm_west_spare1,
|
||||
tlmm_north_spare,
|
||||
tlmm_north_spare1,
|
||||
tlmm_south_spare,
|
||||
tlmm_south_spare1,
|
||||
};
|
||||
|
||||
static const struct pinctrl_pin_desc blair_pins[] = {
|
||||
PINCTRL_PIN(0, "GPIO_0"),
|
||||
|
|
@ -1312,6 +1328,15 @@ static const struct msm_function blair_functions[] = {
|
|||
FUNCTION(USB_PHY),
|
||||
};
|
||||
|
||||
static const struct msm_spare_tlmm blair_spare_regs[] = {
|
||||
SPARE_REG(west_spare, 0),
|
||||
SPARE_REG(west_spare1, 0),
|
||||
SPARE_REG(north_spare, TLMM_NORTH_SPARE_OFFSET),
|
||||
SPARE_REG(north_spare1, TLMM_NORTH_SPARE1_OFFSET),
|
||||
SPARE_REG(south_spare, 0),
|
||||
SPARE_REG(south_spare1, 0),
|
||||
};
|
||||
|
||||
/* Every pin is maintained as a single group, and missing or non-existing pin
|
||||
* would be maintained as dummy group to synchronize pin group index with
|
||||
* pin descriptor registered with pinctrl core.
|
||||
|
|
@ -1652,6 +1677,8 @@ static const struct msm_pinctrl_soc_data blair_pinctrl = {
|
|||
.ngpios = 157,
|
||||
.wakeirq_map = blair_mpm_map,
|
||||
.nwakeirq_map = ARRAY_SIZE(blair_mpm_map),
|
||||
.spare_regs = blair_spare_regs,
|
||||
.nspare_regs = ARRAY_SIZE(blair_spare_regs),
|
||||
};
|
||||
|
||||
static int blair_pinctrl_probe(struct platform_device *pdev)
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@
|
|||
#define MAX_NR_TILES 4
|
||||
#define PS_HOLD_OFFSET 0x820
|
||||
#define QUP_MASK GENMASK(5, 0)
|
||||
#define SPARE_MASK GENMASK(15, 8)
|
||||
|
||||
/**
|
||||
* struct msm_pinctrl - state for a pinctrl-msm device
|
||||
|
|
@ -1505,6 +1506,45 @@ int msm_qup_read(unsigned int mode)
|
|||
return -ENOENT;
|
||||
}
|
||||
|
||||
int msm_spare_write(int spare_reg, u32 val)
|
||||
{
|
||||
u32 offset;
|
||||
const struct msm_spare_tlmm *regs = msm_pinctrl_data->soc->spare_regs;
|
||||
int num_regs = msm_pinctrl_data->soc->nspare_regs;
|
||||
|
||||
if (!regs || spare_reg >= num_regs)
|
||||
return -ENOENT;
|
||||
|
||||
offset = regs[spare_reg].offset;
|
||||
if (offset != 0) {
|
||||
writel_relaxed(val & SPARE_MASK,
|
||||
msm_pinctrl_data->regs[0] + offset);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
EXPORT_SYMBOL(msm_spare_write);
|
||||
|
||||
int msm_spare_read(int spare_reg)
|
||||
{
|
||||
u32 offset, val;
|
||||
const struct msm_spare_tlmm *regs = msm_pinctrl_data->soc->spare_regs;
|
||||
int num_regs = msm_pinctrl_data->soc->nspare_regs;
|
||||
|
||||
if (!regs || spare_reg >= num_regs)
|
||||
return -ENOENT;
|
||||
|
||||
offset = regs[spare_reg].offset;
|
||||
if (offset != 0) {
|
||||
val = readl_relaxed(msm_pinctrl_data->regs[0] + offset);
|
||||
return val & SPARE_MASK;
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
EXPORT_SYMBOL(msm_spare_read);
|
||||
|
||||
/*
|
||||
* msm_gpio_mpm_wake_set - API to make interrupt wakeup capable
|
||||
* @dev: Device corrsponding to pinctrl
|
||||
|
|
|
|||
|
|
@ -125,6 +125,16 @@ struct pinctrl_qup {
|
|||
u32 offset;
|
||||
};
|
||||
|
||||
/*
|
||||
* struct msm_spare_tlmm - TLMM spare registers config
|
||||
* @spare_reg: spare register number
|
||||
* @offset: Offset of spare register
|
||||
*/
|
||||
struct msm_spare_tlmm {
|
||||
int spare_reg;
|
||||
u32 offset;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct msm_gpio_wakeirq_map - Map of GPIOs and their wakeup pins
|
||||
* @gpio: The GPIOs that are wakeup capable
|
||||
|
|
@ -169,6 +179,8 @@ struct msm_pinctrl_soc_data {
|
|||
unsigned int n_no_wake_gpios;
|
||||
struct pinctrl_qup *qup_regs;
|
||||
unsigned int nqup_regs;
|
||||
const struct msm_spare_tlmm *spare_regs;
|
||||
unsigned int nspare_regs;
|
||||
struct msm_dir_conn *dir_conn;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -180,15 +180,6 @@ config R8125_IOSS
|
|||
To compile this driver as a module, choose M here. Module will be
|
||||
called r8125_ioss. If unsure, say N.
|
||||
|
||||
config R8125_IPA_OFFLOAD
|
||||
bool "Enable IPA offload on Realtek R8125 driver"
|
||||
depends on IPA3
|
||||
help
|
||||
Enables IPA Ethernet Offload path on Realtek R8125 driver. It is
|
||||
designed to support generic HW processing of UL/DL IP packets for
|
||||
various use cases independent of radio technology. When this is
|
||||
disabled Realtek R8125 driver switches to embedded software path.
|
||||
|
||||
config AQFWD_IOSS
|
||||
tristate "AQC glue driver for IOSS v2"
|
||||
depends on AQFWD
|
||||
|
|
|
|||
|
|
@ -87,6 +87,10 @@ static int mhi_dev_alloc_evt_buf_evt_req(struct mhi_dev *mhi,
|
|||
static int mhi_dev_schedule_msi_ipa(struct mhi_dev *mhi,
|
||||
struct event_req *ereq);
|
||||
static void mhi_dev_event_msi_cb(void *req);
|
||||
static void mhi_dev_cmd_event_msi_cb(void *req);
|
||||
|
||||
static int mhi_dev_alloc_cmd_ack_buf_req(struct mhi_dev *mhi);
|
||||
|
||||
|
||||
static struct mhi_dev_uevent_info channel_state_info[MHI_MAX_CHANNELS];
|
||||
static DECLARE_COMPLETION(read_from_host);
|
||||
|
|
@ -262,7 +266,7 @@ static int mhi_dev_schedule_msi_ipa(struct mhi_dev *mhi, struct event_req *ereq)
|
|||
{
|
||||
struct ep_pcie_msi_config cfg;
|
||||
struct mhi_addr msi_addr;
|
||||
struct mhi_dev_channel *ch = ereq->context;
|
||||
struct mhi_dev_channel *ch;
|
||||
uint64_t evnt_ring_idx = mhi->ev_ring_start + ereq->event_ring;
|
||||
struct mhi_dev_ring *ring = &mhi->ring[evnt_ring_idx];
|
||||
union mhi_dev_ring_ctx *ctx;
|
||||
|
|
@ -283,14 +287,23 @@ static int mhi_dev_schedule_msi_ipa(struct mhi_dev *mhi, struct event_req *ereq)
|
|||
msi_addr.phy_addr = ring->msi_buf_dma_handle;
|
||||
|
||||
ereq->event_type = SEND_MSI;
|
||||
ereq->msi_cb = mhi_dev_event_msi_cb;
|
||||
if (!ereq->is_cmd_cpl) {
|
||||
ch = ereq->context;
|
||||
ereq->msi_cb = mhi_dev_event_msi_cb;
|
||||
ch->msi_cnt++;
|
||||
mhi_log(MHI_MSG_VERBOSE,
|
||||
"Sending MSI %d to 0x%llx as data = 0x%x for ch %d msi_count %d, ereq flush_num %d\n",
|
||||
ctx->ev.msivec, msi_addr.host_pa,
|
||||
*ring->msi_buf, ch->ch_id,
|
||||
ch->msi_cnt, ereq->flush_num);
|
||||
} else {
|
||||
ereq->msi_cb = mhi_dev_cmd_event_msi_cb;
|
||||
mhi_log(MHI_MSG_VERBOSE,
|
||||
"Sending MSI %d to 0x%llx as data = 0x%x for cmd ack, ereq flush_num %d\n",
|
||||
ctx->ev.msivec, msi_addr.host_pa, *ring->msi_buf,
|
||||
ereq->flush_num);
|
||||
}
|
||||
|
||||
ch->msi_cnt++;
|
||||
|
||||
mhi_log(MHI_MSG_VERBOSE,
|
||||
"Sending MSI %d to 0x%llx as data = 0x%x for ch %d msi_count %d, ereq flush_num %d\n",
|
||||
ctx->ev.msivec, msi_addr.host_pa, *ring->msi_buf, ch->ch_id,
|
||||
ch->msi_cnt, ereq->flush_num);
|
||||
mhi_ctx->write_to_host(mhi, &msi_addr, ereq, MHI_DEV_DMA_ASYNC);
|
||||
|
||||
return 0;
|
||||
|
|
@ -314,6 +327,27 @@ static void mhi_dev_event_rd_offset_completion_cb(void *req)
|
|||
sizeof(uint64_t), DMA_TO_DEVICE);
|
||||
}
|
||||
|
||||
static void mhi_dev_cmd_event_msi_cb(void *req)
|
||||
{
|
||||
struct mhi_cmd_cmpl_ctx *cmd_ctx;
|
||||
struct mhi_dev *mhi;
|
||||
struct event_req *ereq = req;
|
||||
unsigned long flags;
|
||||
|
||||
mhi_log(MHI_MSG_VERBOSE, "MSI completed for flush req %d\n",
|
||||
ereq->flush_num);
|
||||
|
||||
/*Cmd completion handling*/
|
||||
mhi = ereq->context;
|
||||
cmd_ctx = mhi->cmd_ctx;
|
||||
cmd_ctx->cmd_buf_wp += ereq->num_events;
|
||||
if (cmd_ctx->cmd_buf_wp == NUM_CMD_EVENTS_DEFAULT)
|
||||
cmd_ctx->cmd_buf_wp = 0;
|
||||
spin_lock_irqsave(&mhi->lock, flags);
|
||||
list_add_tail(&ereq->list, &cmd_ctx->cmd_req_buffers);
|
||||
spin_unlock_irqrestore(&mhi->lock, flags);
|
||||
}
|
||||
|
||||
static void mhi_dev_event_msi_cb(void *req)
|
||||
{
|
||||
struct event_req *ereq = req;
|
||||
|
|
@ -401,7 +435,8 @@ static int mhi_trigger_msi_edma(struct mhi_dev_ring *ring, u32 idx)
|
|||
}
|
||||
|
||||
static int mhi_dev_send_multiple_tr_events(struct mhi_dev *mhi, int evnt_ring,
|
||||
struct event_req *ereq, uint32_t evt_len)
|
||||
struct event_req *ereq, uint32_t evt_len,
|
||||
enum mhi_dev_tr_compl_evt_type event_type)
|
||||
{
|
||||
int rc = 0;
|
||||
uint64_t evnt_ring_idx = mhi->ev_ring_start + evnt_ring;
|
||||
|
|
@ -430,25 +465,25 @@ static int mhi_dev_send_multiple_tr_events(struct mhi_dev *mhi, int evnt_ring,
|
|||
return rc;
|
||||
}
|
||||
}
|
||||
ch = ereq->context;
|
||||
/* Check the limits of the buffer to be flushed */
|
||||
if (ereq->tr_events < ch->tr_events ||
|
||||
(ereq->tr_events + ereq->num_events) >
|
||||
(ch->tr_events + ch->evt_buf_size)) {
|
||||
pr_err("%s: Invalid completion event buffer!\n", __func__);
|
||||
mhi_log(MHI_MSG_ERROR,
|
||||
"Invalid cmpl evt buf - start %pK, end %pK\n",
|
||||
ereq->tr_events, ereq->tr_events + ereq->num_events);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
||||
mutex_lock(&ring->event_lock);
|
||||
mhi_log(MHI_MSG_VERBOSE, "Flushing %d cmpl events of ch %d\n",
|
||||
ereq->num_events, ch->ch_id);
|
||||
|
||||
/* add the events */
|
||||
ereq->client_cb = mhi_dev_event_buf_completion_cb;
|
||||
ereq->is_cmd_cpl = (event_type == SEND_CMD_CMP) ? true:false;
|
||||
ereq->event_type = SEND_EVENT_BUFFER;
|
||||
|
||||
if (!ereq->is_cmd_cpl) {
|
||||
ch = ereq->context;
|
||||
mhi_log(MHI_MSG_VERBOSE, "Flushing %d cmpl events of ch %d\n",
|
||||
ereq->num_events, ch->ch_id);
|
||||
} else {
|
||||
mhi_log(MHI_MSG_VERBOSE,
|
||||
"Flushing %d cmpl events of cmd ring\n",
|
||||
ereq->num_events);
|
||||
}
|
||||
|
||||
rc = mhi_dev_add_element(ring, ereq->tr_events, ereq, evt_len);
|
||||
if (rc) {
|
||||
pr_err("%s(): error in adding element rc %d\n", __func__, rc);
|
||||
|
|
@ -506,6 +541,55 @@ static int mhi_dev_send_multiple_tr_events(struct mhi_dev *mhi, int evnt_ring,
|
|||
return rc;
|
||||
}
|
||||
|
||||
static int mhi_dev_flush_cmd_completion_events(struct mhi_dev *mhi,
|
||||
union mhi_dev_ring_element_type *el)
|
||||
{
|
||||
struct mhi_cmd_cmpl_ctx *cmd_ctx = mhi->cmd_ctx;
|
||||
unsigned long flags;
|
||||
struct event_req *flush_ereq;
|
||||
union mhi_dev_ring_element_type *compl_ev;
|
||||
int rc = 0;
|
||||
|
||||
/*cmd completions are sent on event ring 0 always*/
|
||||
if (!mhi->cmd_ctx) {
|
||||
if (mhi_dev_alloc_cmd_ack_buf_req(mhi)) {
|
||||
mhi_log(MHI_MSG_ERROR, "Alloc cmd ack buff failed");
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
cmd_ctx = mhi->cmd_ctx;
|
||||
if (list_empty(&cmd_ctx->cmd_req_buffers)) {
|
||||
mhi_log(MHI_MSG_ERROR, "cmd req buff list is empty");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&mhi->lock, flags);
|
||||
flush_ereq = container_of(cmd_ctx->cmd_req_buffers.next,
|
||||
struct event_req, list);
|
||||
list_del_init(&flush_ereq->list);
|
||||
flush_ereq->context = mhi;
|
||||
spin_unlock_irqrestore(&mhi->lock, flags);
|
||||
|
||||
compl_ev = cmd_ctx->cmd_events + cmd_ctx->cmd_buf_rp;
|
||||
memcpy(compl_ev, el, sizeof(union mhi_dev_ring_element_type));
|
||||
cmd_ctx->cmd_buf_rp++;
|
||||
if (cmd_ctx->cmd_buf_rp == NUM_CMD_EVENTS_DEFAULT)
|
||||
cmd_ctx->cmd_buf_rp = 0;
|
||||
flush_ereq->tr_events = compl_ev;
|
||||
rc = mhi_dev_send_multiple_tr_events(mhi,
|
||||
0,
|
||||
flush_ereq,
|
||||
(1 *
|
||||
sizeof(union mhi_dev_ring_element_type)),
|
||||
SEND_CMD_CMP);
|
||||
if (rc) {
|
||||
mhi_log(MHI_MSG_ERROR, "failed to send compl evts\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int mhi_dev_flush_transfer_completion_events(struct mhi_dev *mhi,
|
||||
struct mhi_dev_channel *ch)
|
||||
{
|
||||
|
|
@ -539,11 +623,25 @@ static int mhi_dev_flush_transfer_completion_events(struct mhi_dev *mhi,
|
|||
flush_ereq->flush_num = ch->flush_req_cnt;
|
||||
mhi_log(MHI_MSG_DBG, "Flush num %d called for ch %d\n",
|
||||
ch->flush_req_cnt, ch->ch_id);
|
||||
|
||||
/* Check the limits of the buffer to be flushed */
|
||||
if (flush_ereq->tr_events < ch->tr_events ||
|
||||
(flush_ereq->tr_events + flush_ereq->num_events) >
|
||||
(ch->tr_events + ch->evt_buf_size)) {
|
||||
pr_err("%s: Invalid completion event buffer!\n",
|
||||
__func__);
|
||||
mhi_log(MHI_MSG_ERROR,
|
||||
"Invalid cmpl evt buf - start %pK, end %pK\n",
|
||||
flush_ereq->tr_events,
|
||||
flush_ereq->tr_events + flush_ereq->num_events);
|
||||
return -EINVAL;
|
||||
}
|
||||
rc = mhi_dev_send_multiple_tr_events(mhi,
|
||||
mhi->ch_ctx_cache[ch->ch_id].err_indx,
|
||||
flush_ereq,
|
||||
(flush_ereq->num_events *
|
||||
sizeof(union mhi_dev_ring_element_type)));
|
||||
sizeof(union mhi_dev_ring_element_type)),
|
||||
SEND_EVENT_BUFFER);
|
||||
if (rc) {
|
||||
mhi_log(MHI_MSG_ERROR, "failed to send compl evts\n");
|
||||
break;
|
||||
|
|
@ -1608,7 +1706,7 @@ int mhi_dev_send_state_change_event(struct mhi_dev *mhi,
|
|||
event.evt_state_change.type = MHI_DEV_RING_EL_MHI_STATE_CHG;
|
||||
event.evt_state_change.mhistate = state;
|
||||
|
||||
return mhi_dev_send_event(mhi, 0, &event);
|
||||
return mhi_dev_flush_cmd_completion_events(mhi, &event);
|
||||
}
|
||||
EXPORT_SYMBOL(mhi_dev_send_state_change_event);
|
||||
|
||||
|
|
@ -1619,7 +1717,7 @@ int mhi_dev_send_ee_event(struct mhi_dev *mhi, enum mhi_dev_execenv exec_env)
|
|||
event.evt_ee_state.type = MHI_DEV_RING_EL_EE_STATE_CHANGE_NOTIFY;
|
||||
event.evt_ee_state.execenv = exec_env;
|
||||
|
||||
return mhi_dev_send_event(mhi, 0, &event);
|
||||
return mhi_dev_flush_cmd_completion_events(mhi, &event);
|
||||
}
|
||||
EXPORT_SYMBOL(mhi_dev_send_ee_event);
|
||||
|
||||
|
|
@ -1669,7 +1767,7 @@ static int mhi_dev_send_cmd_comp_event(struct mhi_dev *mhi,
|
|||
(size_t) event.evt_cmd_comp.ptr);
|
||||
event.evt_cmd_comp.type = MHI_DEV_RING_EL_CMD_COMPLETION_EVT;
|
||||
event.evt_cmd_comp.code = code;
|
||||
return mhi_dev_send_event(mhi, 0, &event);
|
||||
return mhi_dev_flush_cmd_completion_events(mhi, &event);
|
||||
}
|
||||
|
||||
static int mhi_dev_process_stop_cmd(struct mhi_dev_ring *ring, uint32_t ch_id,
|
||||
|
|
@ -1852,7 +1950,7 @@ send_start_completion_event:
|
|||
event.evt_cmd_comp.code =
|
||||
MHI_CMD_COMPL_CODE_UNDEFINED;
|
||||
|
||||
rc = mhi_dev_send_event(mhi, 0, &event);
|
||||
rc = mhi_dev_flush_cmd_completion_events(mhi, &event);
|
||||
if (rc) {
|
||||
pr_err("stop event send failed\n");
|
||||
return;
|
||||
|
|
@ -1912,7 +2010,7 @@ send_start_completion_event:
|
|||
event.evt_cmd_comp.code =
|
||||
MHI_CMD_COMPL_CODE_UNDEFINED;
|
||||
|
||||
rc = mhi_dev_send_event(mhi, 0, &event);
|
||||
rc = mhi_dev_flush_cmd_completion_events(mhi, &event);
|
||||
if (rc) {
|
||||
pr_err("stop event send failed\n");
|
||||
return;
|
||||
|
|
@ -2723,6 +2821,61 @@ static uint32_t mhi_dev_get_evt_ring_size(struct mhi_dev *mhi, uint32_t ch_id)
|
|||
mhi->ch_ctx_cache[ch_id].err_indx].ring_size;
|
||||
}
|
||||
|
||||
static int mhi_dev_alloc_cmd_ack_buf_req(struct mhi_dev *mhi)
|
||||
{
|
||||
int rc = 0;
|
||||
uint32_t i;
|
||||
struct mhi_cmd_cmpl_ctx *cmd_ctx;
|
||||
union mhi_dev_ring_element_type *cmd_events;
|
||||
|
||||
mhi->cmd_ctx = kmalloc(sizeof(struct mhi_cmd_cmpl_ctx),
|
||||
GFP_KERNEL);
|
||||
if (!mhi->cmd_ctx)
|
||||
return -ENOMEM;
|
||||
|
||||
cmd_ctx = mhi->cmd_ctx;
|
||||
/* Allocate event requests */
|
||||
cmd_ctx->ereqs = kcalloc(NUM_CMD_EVENTS_DEFAULT,
|
||||
sizeof(*cmd_ctx->ereqs),
|
||||
GFP_KERNEL);
|
||||
if (!cmd_ctx->ereqs) {
|
||||
goto free_ereqs;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Allocate buffers to queue transfer completion events */
|
||||
cmd_ctx->cmd_events = kcalloc(NUM_CMD_EVENTS_DEFAULT,
|
||||
sizeof(*cmd_events),
|
||||
GFP_KERNEL);
|
||||
if (!cmd_ctx->cmd_events) {
|
||||
rc = -ENOMEM;
|
||||
goto free_ereqs;
|
||||
}
|
||||
|
||||
/* Organize event flush requests into a linked list */
|
||||
INIT_LIST_HEAD(&cmd_ctx->cmd_req_buffers);
|
||||
|
||||
for (i = 0; i < NUM_CMD_EVENTS_DEFAULT; ++i) {
|
||||
list_add_tail(&cmd_ctx->ereqs[i].list,
|
||||
&cmd_ctx->cmd_req_buffers);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize cmpl event buffer indexes - cmd_buf_rp and
|
||||
* cmd_buf_wp point to the first and last free index available.
|
||||
*/
|
||||
cmd_ctx->cmd_buf_rp = 0;
|
||||
cmd_ctx->cmd_buf_wp = NUM_CMD_EVENTS_DEFAULT - 1;
|
||||
|
||||
return 0;
|
||||
free_ereqs:
|
||||
kfree(mhi->cmd_ctx);
|
||||
kfree(cmd_ctx->ereqs);
|
||||
cmd_ctx->ereqs = NULL;
|
||||
mhi->cmd_ctx = NULL;
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int mhi_dev_alloc_evt_buf_evt_req(struct mhi_dev *mhi,
|
||||
struct mhi_dev_channel *ch, struct mhi_dev_ring *evt_ring)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -271,6 +271,8 @@ struct mhi_config {
|
|||
|
||||
/* maximum transfer completion events buffer */
|
||||
#define NUM_TR_EVENTS_DEFAULT 128
|
||||
#define NUM_CMD_EVENTS_DEFAULT 20
|
||||
|
||||
|
||||
/* Set flush threshold to 80% of event buf size */
|
||||
#define MHI_CMPL_EVT_FLUSH_THRSHLD(n) ((n * 8) / 10)
|
||||
|
|
@ -354,7 +356,8 @@ enum mhi_dev_ch_operation {
|
|||
enum mhi_dev_tr_compl_evt_type {
|
||||
SEND_EVENT_BUFFER,
|
||||
SEND_EVENT_RD_OFFSET,
|
||||
SEND_MSI
|
||||
SEND_MSI,
|
||||
SEND_CMD_CMP,
|
||||
};
|
||||
|
||||
enum mhi_dev_transfer_type {
|
||||
|
|
@ -448,6 +451,18 @@ struct event_req {
|
|||
void (*msi_cb)(void *req);
|
||||
struct list_head list;
|
||||
u32 flush_num;
|
||||
bool is_cmd_cpl;
|
||||
};
|
||||
|
||||
struct mhi_cmd_cmpl_ctx {
|
||||
/* Indices for completion event buffer */
|
||||
uint32_t cmd_buf_rp;
|
||||
uint32_t cmd_buf_wp;
|
||||
uint32_t cmd_buf_size;
|
||||
bool mem_allocated;
|
||||
struct list_head cmd_req_buffers;
|
||||
struct event_req *ereqs;
|
||||
union mhi_dev_ring_element_type *cmd_events;
|
||||
};
|
||||
|
||||
struct mhi_dev_channel {
|
||||
|
|
@ -531,6 +546,7 @@ struct mhi_dev {
|
|||
struct mhi_dev_ring *ring;
|
||||
int mhi_irq;
|
||||
struct mhi_dev_channel *ch;
|
||||
struct mhi_cmd_cmpl_ctx *cmd_ctx;
|
||||
|
||||
int ctrl_int;
|
||||
int cmd_int;
|
||||
|
|
|
|||
|
|
@ -22,7 +22,10 @@
|
|||
#define MHI_SM_FUNC_ENTRY() MHI_SM_DBG("ENTRY\n")
|
||||
#define MHI_SM_FUNC_EXIT() MHI_SM_DBG("EXIT\n")
|
||||
|
||||
#define PCIE_EP_TIMER_US 500000000
|
||||
#define PCIE_EP_TIMER_US 500000000
|
||||
#define MHI_IPA_DISABLE_DELAY_MS 10
|
||||
#define MHI_IPA_DISABLE_COUNTER 20
|
||||
|
||||
|
||||
static inline const char *mhi_sm_dev_event_str(enum mhi_dev_event state)
|
||||
{
|
||||
|
|
@ -591,7 +594,7 @@ static int mhi_sm_prepare_suspend(enum mhi_dev_state new_state)
|
|||
{
|
||||
enum mhi_dev_state old_state;
|
||||
struct ep_pcie_inactivity inact_param;
|
||||
int res = 0, rc;
|
||||
int res = 0, rc, wait_timeout = 0;
|
||||
|
||||
MHI_SM_DBG("Switching event:%d\n", new_state);
|
||||
|
||||
|
|
@ -668,11 +671,24 @@ static int mhi_sm_prepare_suspend(enum mhi_dev_state new_state)
|
|||
(new_state == MHI_DEV_M3_STATE))) {
|
||||
if (mhi_sm_ctx->mhi_dev->use_ipa) {
|
||||
MHI_SM_DBG("Disable IPA with ipa_dma_disable()\n");
|
||||
res = ipa_dma_disable();
|
||||
if (res) {
|
||||
MHI_SM_ERR("IPA disable failed\n");
|
||||
while (wait_timeout < MHI_IPA_DISABLE_COUNTER) {
|
||||
/* wait for the disable to finish */
|
||||
res = ipa_dma_disable();
|
||||
if (!res)
|
||||
break;
|
||||
MHI_SM_ERR
|
||||
("IPA disable fail cnt:%d\n",
|
||||
wait_timeout);
|
||||
msleep(MHI_IPA_DISABLE_DELAY_MS);
|
||||
wait_timeout++;
|
||||
}
|
||||
|
||||
if (wait_timeout >= MHI_IPA_DISABLE_COUNTER) {
|
||||
MHI_SM_ERR
|
||||
("Fail to disable IPA for M3\n");
|
||||
goto exit;
|
||||
}
|
||||
MHI_SM_ERR("IPA DMA successfully disabled\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
#include <linux/cdev.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/uio.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/sched.h>
|
||||
|
|
@ -95,8 +96,11 @@ static void mhi_uci_generic_client_cb(struct mhi_dev_client_cb_data *cb_data);
|
|||
static void mhi_uci_at_ctrl_client_cb(struct mhi_dev_client_cb_data *cb_data);
|
||||
static void mhi_uci_at_ctrl_tre_cb(struct mhi_dev_client_cb_reason *reason);
|
||||
|
||||
/* UCI channel attributes table */
|
||||
static const struct chan_attr uci_chan_attr_table[] = {
|
||||
/* MHI channel attributes table
|
||||
* Skip node creation for IPCR channels but still allow uevent broadcast to
|
||||
* QRTR client by setting the broadcast flag
|
||||
*/
|
||||
static const struct chan_attr mhi_chan_attr_table[] = {
|
||||
{
|
||||
MHI_CLIENT_LOOPBACK_OUT,
|
||||
TRB_MAX_DATA_SIZE,
|
||||
|
|
@ -266,7 +270,7 @@ static const struct chan_attr uci_chan_attr_table[] = {
|
|||
NULL,
|
||||
NULL,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
true
|
||||
},
|
||||
{
|
||||
|
|
@ -424,6 +428,8 @@ static ssize_t mhi_uci_ctrl_client_read(struct file *file, char __user *buf,
|
|||
size_t count, loff_t *offp);
|
||||
static ssize_t mhi_uci_client_write(struct file *file,
|
||||
const char __user *buf, size_t count, loff_t *offp);
|
||||
static ssize_t mhi_uci_client_write_iter(struct kiocb *iocb,
|
||||
struct iov_iter *buf);
|
||||
static int mhi_uci_client_open(struct inode *mhi_inode, struct file*);
|
||||
static int mhi_uci_ctrl_open(struct inode *mhi_inode, struct file*);
|
||||
static int mhi_uci_client_release(struct inode *mhi_inode,
|
||||
|
|
@ -1221,8 +1227,8 @@ static int mhi_state_uevent(struct device *dev, struct kobj_uevent_env *env)
|
|||
mhi_parse_state(buf, &nbytes, info);
|
||||
add_uevent_var(env, "MHI_STATE=%s", buf);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(uci_chan_attr_table); i++) {
|
||||
chan_attrib = &uci_chan_attr_table[i];
|
||||
for (i = 0; i < ARRAY_SIZE(mhi_chan_attr_table); i++) {
|
||||
chan_attrib = &mhi_chan_attr_table[i];
|
||||
if (chan_attrib->state_bcast) {
|
||||
uci_log(UCI_DBG_ERROR, "Calling notify for ch %d\n",
|
||||
chan_attrib->chan_id);
|
||||
|
|
@ -1480,14 +1486,73 @@ error_memcpy:
|
|||
|
||||
}
|
||||
|
||||
static ssize_t mhi_uci_client_write_iter(struct kiocb *iocb,
|
||||
struct iov_iter *buf)
|
||||
{
|
||||
struct uci_client *uci_handle = NULL;
|
||||
void *data_loc;
|
||||
unsigned long memcpy_result;
|
||||
int rc;
|
||||
struct file *file = iocb->ki_filp;
|
||||
ssize_t count = iov_iter_count(buf);
|
||||
|
||||
if (!file || !buf || !count || !file->private_data) {
|
||||
uci_log(UCI_DBG_DBG, "Invalid access to write-iter\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
uci_handle = file->private_data;
|
||||
if (!uci_handle->send || !uci_handle->out_handle) {
|
||||
uci_log(UCI_DBG_DBG, "Invalid handle or send\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (atomic_read(&uci_ctxt.mhi_disabled)) {
|
||||
uci_log(UCI_DBG_ERROR,
|
||||
"Client %d attempted to write while MHI is disabled\n",
|
||||
uci_handle->out_chan);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (!mhi_uci_are_channels_connected(uci_handle)) {
|
||||
uci_log(UCI_DBG_ERROR, "%s:Channels are not connected\n",
|
||||
__func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (count > TRB_MAX_DATA_SIZE) {
|
||||
uci_log(UCI_DBG_ERROR,
|
||||
"Too big write size: %lu, max supported size is %d\n",
|
||||
count, TRB_MAX_DATA_SIZE);
|
||||
return -EFBIG;
|
||||
}
|
||||
|
||||
data_loc = kmalloc(count, GFP_KERNEL);
|
||||
if (!data_loc)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy_result = copy_from_iter_full(data_loc, count, buf);
|
||||
if (!memcpy_result) {
|
||||
rc = -EFAULT;
|
||||
goto error_memcpy;
|
||||
}
|
||||
|
||||
rc = mhi_uci_send_packet(uci_handle, data_loc, count);
|
||||
if (rc == count)
|
||||
return rc;
|
||||
|
||||
error_memcpy:
|
||||
kfree(data_loc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
void mhi_uci_chan_state_notify_all(struct mhi_dev *mhi,
|
||||
enum mhi_ctrl_info ch_state)
|
||||
{
|
||||
unsigned int i;
|
||||
const struct chan_attr *chan_attrib;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(uci_chan_attr_table); i++) {
|
||||
chan_attrib = &uci_chan_attr_table[i];
|
||||
for (i = 0; i < ARRAY_SIZE(mhi_chan_attr_table); i++) {
|
||||
chan_attrib = &mhi_chan_attr_table[i];
|
||||
if (chan_attrib->state_bcast) {
|
||||
uci_log(UCI_DBG_ERROR, "Calling notify for ch %d\n",
|
||||
chan_attrib->chan_id);
|
||||
|
|
@ -1877,6 +1942,7 @@ static const struct file_operations mhi_uci_ctrl_client_fops = {
|
|||
static const struct file_operations mhi_uci_client_fops = {
|
||||
.read = mhi_uci_client_read,
|
||||
.write = mhi_uci_client_write,
|
||||
.write_iter = mhi_uci_client_write_iter,
|
||||
.open = mhi_uci_client_open,
|
||||
.release = mhi_uci_client_release,
|
||||
.poll = mhi_uci_client_poll,
|
||||
|
|
@ -2038,8 +2104,8 @@ static int uci_init_client_attributes(struct mhi_uci_ctxt_t *uci_ctxt)
|
|||
struct uci_client *client;
|
||||
const struct chan_attr *chan_attrib;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(uci_chan_attr_table); i += 2) {
|
||||
chan_attrib = &uci_chan_attr_table[i];
|
||||
for (i = 0; i < ARRAY_SIZE(mhi_chan_attr_table); i += 2) {
|
||||
chan_attrib = &mhi_chan_attr_table[i];
|
||||
index = CHAN_TO_CLIENT(chan_attrib->chan_id);
|
||||
client = &uci_ctxt->client_handles[index];
|
||||
client->out_chan_attr = chan_attrib;
|
||||
|
|
|
|||
|
|
@ -1656,6 +1656,36 @@ static void icnss_update_state_send_modem_shutdown(struct icnss_priv *priv,
|
|||
}
|
||||
}
|
||||
|
||||
static char *icnss_subsys_notify_state_to_str(enum subsys_notif_type code)
|
||||
{
|
||||
switch (code) {
|
||||
case SUBSYS_BEFORE_SHUTDOWN:
|
||||
return "BEFORE_SHUTDOWN";
|
||||
case SUBSYS_AFTER_SHUTDOWN:
|
||||
return "AFTER_SHUTDOWN";
|
||||
case SUBSYS_BEFORE_POWERUP:
|
||||
return "BEFORE_POWERUP";
|
||||
case SUBSYS_AFTER_POWERUP:
|
||||
return "AFTER_POWERUP";
|
||||
case SUBSYS_BEFORE_AUTH_AND_RESET:
|
||||
return "BEFORE_AUTH_AND_RESET";
|
||||
case SUBSYS_RAMDUMP_NOTIFICATION:
|
||||
return "RAMDUMP_NOTIFICATION";
|
||||
case SUBSYS_POWERUP_FAILURE:
|
||||
return "POWERUP_FAILURE";
|
||||
case SUBSYS_PROXY_VOTE:
|
||||
return "PROXY_VOTE";
|
||||
case SUBSYS_PROXY_UNVOTE:
|
||||
return "PROXY_UNVOTE";
|
||||
case SUBSYS_SOC_RESET:
|
||||
return "SOC_RESET";
|
||||
case SUBSYS_NOTIF_TYPE_COUNT:
|
||||
return "NOTIF_TYPE_COUNT";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
};
|
||||
|
||||
static int icnss_wpss_notifier_nb(struct notifier_block *nb,
|
||||
unsigned long code,
|
||||
void *data)
|
||||
|
|
@ -1666,7 +1696,8 @@ static int icnss_wpss_notifier_nb(struct notifier_block *nb,
|
|||
wpss_ssr_nb);
|
||||
struct icnss_uevent_fw_down_data fw_down_data = {0};
|
||||
|
||||
icnss_pr_vdbg("WPSS-Notify: event %lu\n", code);
|
||||
icnss_pr_vdbg("WPSS-Notify: event %s(%lu)\n",
|
||||
icnss_subsys_notify_state_to_str(code), code);
|
||||
|
||||
if (code == SUBSYS_AFTER_SHUTDOWN) {
|
||||
icnss_pr_info("Collecting msa0 segment dump\n");
|
||||
|
|
@ -1723,7 +1754,8 @@ static int icnss_modem_notifier_nb(struct notifier_block *nb,
|
|||
modem_ssr_nb);
|
||||
struct icnss_uevent_fw_down_data fw_down_data = {0};
|
||||
|
||||
icnss_pr_vdbg("Modem-Notify: event %lu\n", code);
|
||||
icnss_pr_vdbg("Modem-Notify: event %s(%lu)\n",
|
||||
icnss_subsys_notify_state_to_str(code), code);
|
||||
|
||||
if (code == SUBSYS_AFTER_SHUTDOWN) {
|
||||
icnss_pr_info("Collecting msa0 segment dump\n");
|
||||
|
|
|
|||
|
|
@ -976,6 +976,22 @@ static int icnss_get_bdf_file_name(struct icnss_priv *priv,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static char *icnss_bdf_type_to_str(enum icnss_bdf_type bdf_type)
|
||||
{
|
||||
switch (bdf_type) {
|
||||
case ICNSS_BDF_BIN:
|
||||
return "BDF";
|
||||
case ICNSS_BDF_ELF:
|
||||
return "BDF";
|
||||
case ICNSS_BDF_REGDB:
|
||||
return "REGDB";
|
||||
case ICNSS_BDF_DUMMY:
|
||||
return "BDF";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
};
|
||||
|
||||
int icnss_wlfw_bdf_dnld_send_sync(struct icnss_priv *priv, u32 bdf_type)
|
||||
{
|
||||
struct wlfw_bdf_download_req_msg_v01 *req;
|
||||
|
|
@ -987,8 +1003,8 @@ int icnss_wlfw_bdf_dnld_send_sync(struct icnss_priv *priv, u32 bdf_type)
|
|||
unsigned int remaining;
|
||||
int ret = 0;
|
||||
|
||||
icnss_pr_dbg("Sending BDF download message, state: 0x%lx, type: %d\n",
|
||||
priv->state, bdf_type);
|
||||
icnss_pr_dbg("Sending %s download message, state: 0x%lx, type: %d\n",
|
||||
icnss_bdf_type_to_str(bdf_type), priv->state, bdf_type);
|
||||
|
||||
req = kzalloc(sizeof(*req), GFP_KERNEL);
|
||||
if (!req)
|
||||
|
|
@ -1012,7 +1028,8 @@ int icnss_wlfw_bdf_dnld_send_sync(struct icnss_priv *priv, u32 bdf_type)
|
|||
|
||||
ret = request_firmware(&fw_entry, filename, &priv->pdev->dev);
|
||||
if (ret) {
|
||||
icnss_pr_err("Failed to load BDF: %s\n", filename);
|
||||
icnss_pr_err("Failed to load %s: %s ret:%d\n",
|
||||
icnss_bdf_type_to_str(bdf_type), filename, ret);
|
||||
goto err_req_fw;
|
||||
}
|
||||
|
||||
|
|
@ -1020,7 +1037,8 @@ int icnss_wlfw_bdf_dnld_send_sync(struct icnss_priv *priv, u32 bdf_type)
|
|||
remaining = fw_entry->size;
|
||||
|
||||
bypass_bdf:
|
||||
icnss_pr_dbg("Downloading BDF: %s, size: %u\n", filename, remaining);
|
||||
icnss_pr_dbg("Downloading %s: %s, size: %u\n",
|
||||
icnss_bdf_type_to_str(bdf_type), filename, remaining);
|
||||
|
||||
while (remaining) {
|
||||
req->valid = 1;
|
||||
|
|
@ -1046,8 +1064,8 @@ bypass_bdf:
|
|||
ret = qmi_txn_init(&priv->qmi, &txn,
|
||||
wlfw_bdf_download_resp_msg_v01_ei, resp);
|
||||
if (ret < 0) {
|
||||
icnss_pr_err("Failed to initialize txn for BDF download request, err: %d\n",
|
||||
ret);
|
||||
icnss_pr_err("Failed to initialize txn for %s download request, err: %d\n",
|
||||
icnss_bdf_type_to_str(bdf_type), ret);
|
||||
goto err_send;
|
||||
}
|
||||
|
||||
|
|
@ -1058,21 +1076,22 @@ bypass_bdf:
|
|||
wlfw_bdf_download_req_msg_v01_ei, req);
|
||||
if (ret < 0) {
|
||||
qmi_txn_cancel(&txn);
|
||||
icnss_pr_err("Failed to send respond BDF download request, err: %d\n",
|
||||
ret);
|
||||
icnss_pr_err("Failed to send respond %s download request, err: %d\n",
|
||||
icnss_bdf_type_to_str(bdf_type), ret);
|
||||
goto err_send;
|
||||
}
|
||||
|
||||
ret = qmi_txn_wait(&txn, priv->ctrl_params.qmi_timeout);
|
||||
if (ret < 0) {
|
||||
icnss_pr_err("Failed to wait for response of BDF download request, err: %d\n",
|
||||
ret);
|
||||
icnss_pr_err("Failed to wait for response of %s download request, err: %d\n",
|
||||
icnss_bdf_type_to_str(bdf_type), ret);
|
||||
goto err_send;
|
||||
}
|
||||
|
||||
if (resp->resp.result != QMI_RESULT_SUCCESS_V01) {
|
||||
icnss_pr_err("BDF download request failed, result: %d, err: %d\n",
|
||||
resp->resp.result, resp->resp.error);
|
||||
icnss_pr_err("%s download request failed, result: %d, err: %d\n",
|
||||
icnss_bdf_type_to_str(bdf_type), resp->resp.result,
|
||||
resp->resp.error);
|
||||
ret = -resp->resp.result;
|
||||
goto err_send;
|
||||
}
|
||||
|
|
@ -1250,8 +1269,8 @@ int icnss_wlfw_qdss_dnld_send_sync(struct icnss_priv *priv)
|
|||
ret = request_firmware(&fw_entry, filename,
|
||||
&priv->pdev->dev);
|
||||
if (ret) {
|
||||
icnss_pr_err("Failed to load QDSS: %s\n",
|
||||
filename);
|
||||
icnss_pr_err("Failed to load QDSS: %s ret:%d\n",
|
||||
filename, ret);
|
||||
goto err_req_fw;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1350,9 +1350,14 @@ static int spi_geni_prepare_transfer_hardware(struct spi_master *spi)
|
|||
struct se_geni_rsc *rsc;
|
||||
int ret = 0;
|
||||
|
||||
rsc = &mas->spi_rsc;
|
||||
ret = pinctrl_select_state(rsc->geni_pinctrl,
|
||||
rsc->geni_gpio_active);
|
||||
if (!mas->is_la_vm) {
|
||||
/* Do this only for non TVM LA usecase */
|
||||
/* May not be needed here, but maintain parity */
|
||||
rsc = &mas->spi_rsc;
|
||||
ret = pinctrl_select_state(rsc->geni_pinctrl,
|
||||
rsc->geni_gpio_active);
|
||||
}
|
||||
|
||||
if (ret)
|
||||
GENI_SE_ERR(mas->ipc, false, NULL,
|
||||
"%s: Error %d pinctrl_select_state\n", __func__, ret);
|
||||
|
|
@ -1400,17 +1405,17 @@ static int spi_geni_unprepare_transfer_hardware(struct spi_master *spi)
|
|||
if (mas->shared_ee || mas->is_le_vm)
|
||||
return 0;
|
||||
|
||||
if (mas->is_la_vm)
|
||||
/* Client on LA VM to controls resources, hence return */
|
||||
return 0;
|
||||
|
||||
if (mas->gsi_mode) {
|
||||
struct se_geni_rsc *rsc;
|
||||
int ret = 0;
|
||||
|
||||
rsc = &mas->spi_rsc;
|
||||
ret = pinctrl_select_state(rsc->geni_pinctrl,
|
||||
if (!mas->is_la_vm) {
|
||||
/* Do this only for non TVM LA usecase */
|
||||
rsc = &mas->spi_rsc;
|
||||
ret = pinctrl_select_state(rsc->geni_pinctrl,
|
||||
rsc->geni_gpio_sleep);
|
||||
}
|
||||
|
||||
if (ret)
|
||||
GENI_SE_ERR(mas->ipc, false, NULL,
|
||||
"%s: Error %d pinctrl_select_state\n", __func__, ret);
|
||||
|
|
|
|||
|
|
@ -490,11 +490,15 @@ struct dwc3_msm {
|
|||
bool suspend;
|
||||
bool use_pdc_interrupts;
|
||||
enum dwc3_id_state id_state;
|
||||
bool use_pwr_event_for_wakeup;
|
||||
unsigned long use_pwr_event_for_wakeup;
|
||||
#define PWR_EVENT_SS_WAKEUP BIT(0)
|
||||
#define PWR_EVENT_HS_WAKEUP BIT(1)
|
||||
|
||||
unsigned long lpm_flags;
|
||||
#define MDWC3_SS_PHY_SUSPEND BIT(0)
|
||||
#define MDWC3_ASYNC_IRQ_WAKE_CAPABILITY BIT(1)
|
||||
#define MDWC3_POWER_COLLAPSE BIT(2)
|
||||
#define MDWC3_USE_PWR_EVENT_IRQ_FOR_WAKEUP BIT(3)
|
||||
|
||||
struct extcon_nb *extcon;
|
||||
int ext_idx;
|
||||
|
|
@ -3047,7 +3051,7 @@ static void configure_usb_wakeup_interrupt(struct dwc3_msm *mdwc,
|
|||
}
|
||||
}
|
||||
|
||||
static void enable_usb_pdc_interrupt(struct dwc3_msm *mdwc, bool enable)
|
||||
static void configure_usb_wakeup_interrupts(struct dwc3_msm *mdwc, bool enable)
|
||||
{
|
||||
if (!enable)
|
||||
goto disable_usb_irq;
|
||||
|
|
@ -3131,7 +3135,7 @@ static void configure_nonpdc_usb_interrupt(struct dwc3_msm *mdwc,
|
|||
}
|
||||
}
|
||||
|
||||
static void dwc3_msm_set_ss_pwr_events(struct dwc3_msm *mdwc, bool on)
|
||||
static void dwc3_msm_set_pwr_events(struct dwc3_msm *mdwc, bool on)
|
||||
{
|
||||
u32 irq_mask, irq_stat;
|
||||
|
||||
|
|
@ -3142,12 +3146,28 @@ static void dwc3_msm_set_ss_pwr_events(struct dwc3_msm *mdwc, bool on)
|
|||
|
||||
irq_mask = dwc3_msm_read_reg(mdwc->base, PWR_EVNT_IRQ_MASK_REG);
|
||||
|
||||
if (on)
|
||||
irq_mask |= (PWR_EVNT_POWERDOWN_OUT_P3_MASK |
|
||||
PWR_EVNT_LPM_OUT_RX_ELECIDLE_IRQ_MASK);
|
||||
else
|
||||
irq_mask &= ~(PWR_EVNT_POWERDOWN_OUT_P3_MASK |
|
||||
PWR_EVNT_LPM_OUT_RX_ELECIDLE_IRQ_MASK);
|
||||
if (on) {
|
||||
/*
|
||||
* In case of platforms which use mpm interrupts, in case where
|
||||
* suspend happens with a hs/fs/ls device connected in host mode.
|
||||
* DP/DM falling edge will be monitored, but gic doesn't have
|
||||
* capability to detect falling edge. So program power event irq
|
||||
* to notify exit from lpm in such case.
|
||||
*/
|
||||
if (mdwc->use_pwr_event_for_wakeup & PWR_EVENT_HS_WAKEUP)
|
||||
irq_mask |= PWR_EVNT_LPM_OUT_L2_MASK;
|
||||
if ((mdwc->use_pwr_event_for_wakeup & PWR_EVENT_SS_WAKEUP)
|
||||
&& !(mdwc->lpm_flags & MDWC3_SS_PHY_SUSPEND))
|
||||
irq_mask |= (PWR_EVNT_POWERDOWN_OUT_P3_MASK |
|
||||
PWR_EVNT_LPM_OUT_RX_ELECIDLE_IRQ_MASK);
|
||||
} else {
|
||||
if (mdwc->use_pwr_event_for_wakeup & PWR_EVENT_HS_WAKEUP)
|
||||
irq_mask &= ~PWR_EVNT_LPM_OUT_L2_MASK;
|
||||
if ((mdwc->use_pwr_event_for_wakeup & PWR_EVENT_SS_WAKEUP)
|
||||
&& !(mdwc->lpm_flags & MDWC3_SS_PHY_SUSPEND))
|
||||
irq_mask &= ~(PWR_EVNT_POWERDOWN_OUT_P3_MASK |
|
||||
PWR_EVNT_LPM_OUT_RX_ELECIDLE_IRQ_MASK);
|
||||
}
|
||||
|
||||
dwc3_msm_write_reg(mdwc->base, PWR_EVNT_IRQ_MASK_REG, irq_mask);
|
||||
}
|
||||
|
|
@ -3280,7 +3300,7 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc, bool force_power_collapse,
|
|||
((mdwc->hs_phy->flags & (PHY_HSFS_MODE | PHY_LS_MODE)) &&
|
||||
!dwc3_msm_is_superspeed(mdwc)));
|
||||
can_suspend_ssphy = dwc->maximum_speed >= USB_SPEED_SUPER &&
|
||||
(!mdwc->use_pwr_event_for_wakeup || no_active_ss ||
|
||||
(!(mdwc->use_pwr_event_for_wakeup & PWR_EVENT_SS_WAKEUP) || no_active_ss ||
|
||||
!enable_wakeup);
|
||||
/* Suspend SS PHY */
|
||||
if (can_suspend_ssphy) {
|
||||
|
|
@ -3306,11 +3326,21 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc, bool force_power_collapse,
|
|||
usb_phy_set_suspend(mdwc->ss_phy, 1);
|
||||
usb_phy_set_suspend(mdwc->ss_phy1, 1);
|
||||
mdwc->lpm_flags |= MDWC3_SS_PHY_SUSPEND;
|
||||
} else if (mdwc->use_pwr_event_for_wakeup) {
|
||||
dwc3_msm_set_ss_pwr_events(mdwc, true);
|
||||
enable_irq(mdwc->wakeup_irq[PWR_EVNT_IRQ].irq);
|
||||
} else if (mdwc->use_pwr_event_for_wakeup & PWR_EVENT_SS_WAKEUP) {
|
||||
mdwc->lpm_flags |= MDWC3_USE_PWR_EVENT_IRQ_FOR_WAKEUP;
|
||||
}
|
||||
|
||||
/*
|
||||
* When operating in HS host mode, check if pwr event IRQ is
|
||||
* required for wakeup.
|
||||
*/
|
||||
if (mdwc->in_host_mode && (mdwc->use_pwr_event_for_wakeup
|
||||
& PWR_EVENT_HS_WAKEUP))
|
||||
mdwc->lpm_flags |= MDWC3_USE_PWR_EVENT_IRQ_FOR_WAKEUP;
|
||||
|
||||
if (mdwc->lpm_flags & MDWC3_USE_PWR_EVENT_IRQ_FOR_WAKEUP)
|
||||
dwc3_msm_set_pwr_events(mdwc, true);
|
||||
|
||||
/* make sure above writes are completed before turning off clocks */
|
||||
wmb();
|
||||
|
||||
|
|
@ -3362,11 +3392,13 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc, bool force_power_collapse,
|
|||
/*
|
||||
* with the core in power collapse, we dont require wakeup
|
||||
* using HS_PHY_IRQ or SS_PHY_IRQ. Hence enable wakeup only in
|
||||
* case of host bus suspend and device bus suspend.
|
||||
* case of host bus suspend and device bus suspend. Also in
|
||||
* case of platforms with mpm interrupts and snps phy, enable
|
||||
* dpse hsphy irq and dmse hsphy irq as done for pdc interrupts.
|
||||
*/
|
||||
if (!(mdwc->lpm_flags & MDWC3_POWER_COLLAPSE) && enable_wakeup) {
|
||||
if (mdwc->use_pdc_interrupts) {
|
||||
enable_usb_pdc_interrupt(mdwc, true);
|
||||
if (mdwc->use_pdc_interrupts || !mdwc->wakeup_irq[HS_PHY_IRQ].irq) {
|
||||
configure_usb_wakeup_interrupts(mdwc, true);
|
||||
} else {
|
||||
uirq = &mdwc->wakeup_irq[HS_PHY_IRQ];
|
||||
configure_nonpdc_usb_interrupt(mdwc, uirq, true);
|
||||
|
|
@ -3376,6 +3408,9 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc, bool force_power_collapse,
|
|||
mdwc->lpm_flags |= MDWC3_ASYNC_IRQ_WAKE_CAPABILITY;
|
||||
}
|
||||
|
||||
if (mdwc->lpm_flags & MDWC3_USE_PWR_EVENT_IRQ_FOR_WAKEUP)
|
||||
enable_irq(mdwc->wakeup_irq[PWR_EVNT_IRQ].irq);
|
||||
|
||||
dev_info(mdwc->dev, "DWC3 in low power mode\n");
|
||||
dbg_event(0xFF, "Ctl Sus", atomic_read(&dwc->in_lpm));
|
||||
|
||||
|
|
@ -3468,10 +3503,10 @@ static int dwc3_msm_resume(struct dwc3_msm *mdwc)
|
|||
* Disable any wakeup events that were enabled if pwr_event_irq
|
||||
* is used as wakeup interrupt.
|
||||
*/
|
||||
if (mdwc->use_pwr_event_for_wakeup &&
|
||||
!(mdwc->lpm_flags & MDWC3_SS_PHY_SUSPEND)) {
|
||||
if (mdwc->lpm_flags & MDWC3_USE_PWR_EVENT_IRQ_FOR_WAKEUP) {
|
||||
disable_irq_nosync(mdwc->wakeup_irq[PWR_EVNT_IRQ].irq);
|
||||
dwc3_msm_set_ss_pwr_events(mdwc, false);
|
||||
dwc3_msm_set_pwr_events(mdwc, false);
|
||||
mdwc->lpm_flags &= ~MDWC3_USE_PWR_EVENT_IRQ_FOR_WAKEUP;
|
||||
}
|
||||
|
||||
/* Resume SS PHY */
|
||||
|
|
@ -3542,8 +3577,8 @@ static int dwc3_msm_resume(struct dwc3_msm *mdwc)
|
|||
|
||||
/* Disable wakeup capable for HS_PHY IRQ & SS_PHY_IRQ if enabled */
|
||||
if (mdwc->lpm_flags & MDWC3_ASYNC_IRQ_WAKE_CAPABILITY) {
|
||||
if (mdwc->use_pdc_interrupts) {
|
||||
enable_usb_pdc_interrupt(mdwc, false);
|
||||
if (mdwc->use_pdc_interrupts || !mdwc->wakeup_irq[HS_PHY_IRQ].irq) {
|
||||
configure_usb_wakeup_interrupts(mdwc, false);
|
||||
} else {
|
||||
uirq = &mdwc->wakeup_irq[HS_PHY_IRQ];
|
||||
configure_nonpdc_usb_interrupt(mdwc, uirq, false);
|
||||
|
|
@ -3791,6 +3826,13 @@ static void dwc3_pwr_event_handler(struct dwc3_msm *mdwc)
|
|||
irq_clear |= PWR_EVNT_LPM_OUT_L1_MASK;
|
||||
}
|
||||
|
||||
/* Handle exit from L2 events */
|
||||
if (irq_stat & PWR_EVNT_LPM_OUT_L2_MASK) {
|
||||
dev_dbg(mdwc->dev, "%s: handling PWR_EVNT_LPM_OUT_L2_MASK\n",
|
||||
__func__);
|
||||
irq_stat &= ~PWR_EVNT_LPM_OUT_L2_MASK;
|
||||
irq_clear |= PWR_EVNT_LPM_OUT_L2_MASK;
|
||||
}
|
||||
/* Unhandled events */
|
||||
if (irq_stat)
|
||||
dev_dbg(mdwc->dev, "%s: unexpected PWR_EVNT, irq_stat=%X\n",
|
||||
|
|
@ -4895,8 +4937,17 @@ static int dwc3_msm_probe(struct platform_device *pdev)
|
|||
* On platforms with SS PHY that do not support ss_phy_irq for wakeup
|
||||
* events, use pwr_event_irq for wakeup events in superspeed mode.
|
||||
*/
|
||||
mdwc->use_pwr_event_for_wakeup = dwc->maximum_speed >= USB_SPEED_SUPER
|
||||
&& !mdwc->wakeup_irq[SS_PHY_IRQ].irq;
|
||||
if (dwc->maximum_speed >= USB_SPEED_SUPER
|
||||
&& !mdwc->wakeup_irq[SS_PHY_IRQ].irq)
|
||||
mdwc->use_pwr_event_for_wakeup |= PWR_EVENT_SS_WAKEUP;
|
||||
|
||||
/*
|
||||
* On platforms with mpm interrupts and snps phy, when operating in
|
||||
* HS host mode use power event irq for wakeup events as GIC is not
|
||||
* capable to detect falling edge of dp/dm hsphy irq.
|
||||
*/
|
||||
if (!mdwc->use_pdc_interrupts && !mdwc->wakeup_irq[HS_PHY_IRQ].irq)
|
||||
mdwc->use_pwr_event_for_wakeup |= PWR_EVENT_HS_WAKEUP;
|
||||
|
||||
/*
|
||||
* Clocks and regulators will not be turned on until the first time
|
||||
|
|
|
|||
|
|
@ -1866,8 +1866,6 @@ int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value, int protocol)
|
|||
{
|
||||
struct dwc3_gadget_ep_cmd_params params;
|
||||
struct dwc3 *dwc = dep->dwc;
|
||||
struct dwc3_request *req;
|
||||
struct dwc3_request *tmp;
|
||||
int ret;
|
||||
|
||||
if (!dep->endpoint.desc) {
|
||||
|
|
@ -1926,15 +1924,13 @@ int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value, int protocol)
|
|||
if (!dep->gsi) {
|
||||
dwc3_stop_active_transfer(dep, true, true);
|
||||
|
||||
list_for_each_entry_safe(req, tmp, &dep->started_list, list)
|
||||
dwc3_gadget_move_cancelled_request(req);
|
||||
if (!list_empty(&dep->started_list))
|
||||
dep->flags |= DWC3_EP_DELAY_START;
|
||||
|
||||
if (dep->flags & DWC3_EP_END_TRANSFER_PENDING) {
|
||||
dep->flags |= DWC3_EP_PENDING_CLEAR_STALL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
dwc3_gadget_ep_cleanup_cancelled_requests(dep);
|
||||
}
|
||||
|
||||
ret = dwc3_send_clear_stall_ep_cmd(dep);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2019, The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2019,2021 The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_PINCTRL_MSM_H__
|
||||
|
|
@ -15,4 +15,8 @@ int msm_qup_read(u32 mode);
|
|||
/* API to write to mpm_wakeup registers */
|
||||
int msm_gpio_mpm_wake_set(unsigned int gpio, bool enable);
|
||||
|
||||
/* APIS to TLMM Spare registers */
|
||||
int msm_spare_write(int spare_reg, u32 val);
|
||||
int msm_spare_read(int spare_reg);
|
||||
|
||||
#endif /* __LINUX_PINCTRL_MSM_H__ */
|
||||
|
|
|
|||
|
|
@ -20,4 +20,5 @@ extern const struct mpm_pin mpm_holi_gic_chip_data[];
|
|||
extern const struct mpm_pin mpm_sdxnightjar_gic_chip_data[];
|
||||
extern const struct mpm_pin mpm_monaco_gic_chip_data[];
|
||||
extern const struct mpm_pin mpm_qcs405_gic_chip_data[];
|
||||
extern const struct mpm_pin mpm_blair_gic_chip_data[];
|
||||
#endif /* __QCOM_MPM_H__ */
|
||||
|
|
|
|||
|
|
@ -386,9 +386,24 @@ static void __init get_fs_names(char *page)
|
|||
static int __init do_mount_root(char *name, char *fs, int flags, void *data)
|
||||
{
|
||||
struct super_block *s;
|
||||
int err = ksys_mount(name, "/root", fs, flags, data);
|
||||
if (err)
|
||||
return err;
|
||||
char *data_page = NULL;
|
||||
struct page *p = NULL;
|
||||
int ret;
|
||||
|
||||
if (data) {
|
||||
/* do_mount() requires a full page as fifth argument */
|
||||
p = alloc_page(GFP_KERNEL);
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
|
||||
data_page = page_address(p);
|
||||
/* zero-pad. do_mount() will make sure it's terminated */
|
||||
strscpy(data_page, data, PAGE_SIZE);
|
||||
}
|
||||
|
||||
ret = ksys_mount(name, "/root", fs, flags, data_page);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ksys_chdir("/root");
|
||||
s = current->fs->pwd.dentry->d_sb;
|
||||
|
|
@ -398,7 +413,11 @@ static int __init do_mount_root(char *name, char *fs, int flags, void *data)
|
|||
s->s_type->name,
|
||||
sb_rdonly(s) ? " readonly" : "",
|
||||
MAJOR(ROOT_DEV), MINOR(ROOT_DEV));
|
||||
return 0;
|
||||
|
||||
out:
|
||||
if (p)
|
||||
put_page(p);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void __init mount_block_root(char *name, int flags)
|
||||
|
|
|
|||
|
|
@ -2187,6 +2187,7 @@ static const struct nf_conntrack_expect_policy sip_exp_policy[SIP_EXPECT_MAX + 1
|
|||
static void __exit nf_conntrack_sip_fini(void)
|
||||
{
|
||||
nf_conntrack_helpers_unregister(sip, ports_c * 4);
|
||||
unregister_net_sysctl_table(sip_sysctl_header);
|
||||
}
|
||||
|
||||
static int __init nf_conntrack_sip_init(void)
|
||||
|
|
|
|||
|
|
@ -68,4 +68,13 @@ config QRTR_HAVEN
|
|||
Router communication between two virtual machines. The transport
|
||||
uses dynamically shared memory and haven doorbells.
|
||||
|
||||
config QRTR_MHI_DEV
|
||||
tristate "MHI Device IPC Router channels"
|
||||
depends on MSM_MHI_DEV || (COMPILE_TEST && MSM_MHI_DEV=n)
|
||||
help
|
||||
Say Y here to support MHI base ipcrouter channels for device
|
||||
endpoint mode. MHI is the transport used for external modem
|
||||
connections. This driver enables QRTR to run on the modem device
|
||||
side.
|
||||
|
||||
endif # QRTR
|
||||
|
|
|
|||
|
|
@ -7,5 +7,7 @@ obj-$(CONFIG_QRTR_TUN) += qrtr-tun.o
|
|||
qrtr-tun-y := tun.o
|
||||
obj-$(CONFIG_QRTR_MHI) += qrtr-mhi.o
|
||||
qrtr-mhi-y := mhi.o
|
||||
obj-$(CONFIG_QRTR_MHI_DEV) += qrtr-mhi-dev.o
|
||||
qrtr-mhi-dev-y := mhi_dev.o
|
||||
obj-$(CONFIG_QRTR_HAVEN) += qrtr-haven.o
|
||||
qrtr-haven-y := haven.o
|
||||
|
|
|
|||
266
net/qrtr/mhi_dev.c
Normal file
266
net/qrtr/mhi_dev.c
Normal file
|
|
@ -0,0 +1,266 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/* Copyright (c) 2019-2021 The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/msm_mhi_dev.h>
|
||||
#include "qrtr.h"
|
||||
|
||||
#define QRTR_MAX_PKT_SIZE SZ_32K
|
||||
|
||||
/* MHI DEV Enums are defined from Host perspective */
|
||||
#define QRTR_MHI_DEV_OUT MHI_CLIENT_IPCR_IN
|
||||
#define QRTR_MHI_DEV_IN MHI_CLIENT_IPCR_OUT
|
||||
|
||||
/**
|
||||
* struct qrtr_mhi_dev_ep - qrtr mhi device endpoint
|
||||
* @ep: endpoint
|
||||
* @dev: device from platform bus
|
||||
* @out: channel handle from mhi dev
|
||||
* @out_tre: complete when channel is ready to send
|
||||
* @out_lock: hold when resetting completion variable
|
||||
* @in: channel handle from mhi dev
|
||||
* @buf_in: buffer to hold incoming data
|
||||
* @net_id: subnet id used by qrtr core
|
||||
* @rt: realtime option used by qrtr core
|
||||
*/
|
||||
struct qrtr_mhi_dev_ep {
|
||||
struct qrtr_endpoint ep;
|
||||
struct device *dev;
|
||||
struct mhi_dev_client *out;
|
||||
struct completion out_tre;
|
||||
struct mutex out_lock; /* for out critical sections */
|
||||
struct mhi_dev_client *in;
|
||||
void *buf_in;
|
||||
|
||||
u32 net_id;
|
||||
bool rt;
|
||||
};
|
||||
|
||||
static struct qrtr_mhi_dev_ep *qrtr_mhi_device_endpoint;
|
||||
|
||||
static int qrtr_mhi_dev_send(struct qrtr_endpoint *ep, struct sk_buff *skb)
|
||||
{
|
||||
struct qrtr_mhi_dev_ep *qep;
|
||||
struct mhi_req req = { 0 };
|
||||
int rc;
|
||||
|
||||
qep = container_of(ep, struct qrtr_mhi_dev_ep, ep);
|
||||
rc = skb_linearize(skb);
|
||||
if (rc) {
|
||||
kfree_skb(skb);
|
||||
return rc;
|
||||
}
|
||||
|
||||
req.chan = QRTR_MHI_DEV_OUT;
|
||||
req.client = qep->out;
|
||||
req.mode = DMA_SYNC;
|
||||
req.buf = skb->data;
|
||||
req.len = skb->len;
|
||||
|
||||
do {
|
||||
wait_for_completion(&qep->out_tre);
|
||||
|
||||
mutex_lock(&qep->out_lock);
|
||||
rc = mhi_dev_write_channel(&req);
|
||||
if (rc == 0)
|
||||
reinit_completion(&qep->out_tre);
|
||||
mutex_unlock(&qep->out_lock);
|
||||
} while (!rc);
|
||||
|
||||
if (rc != skb->len) {
|
||||
dev_err(qep->dev, "send failed rc:%d len:%d\n", rc, skb->len);
|
||||
kfree_skb(skb);
|
||||
return rc;
|
||||
}
|
||||
|
||||
consume_skb(skb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void qrtr_mhi_dev_read(struct qrtr_mhi_dev_ep *qep)
|
||||
{
|
||||
struct mhi_req req = { 0 };
|
||||
int rc;
|
||||
int bytes_read;
|
||||
|
||||
req.chan = QRTR_MHI_DEV_IN;
|
||||
req.client = qep->in;
|
||||
req.mode = DMA_SYNC;
|
||||
req.buf = qep->buf_in;
|
||||
req.len = QRTR_MAX_PKT_SIZE;
|
||||
|
||||
do {
|
||||
bytes_read = mhi_dev_read_channel(&req);
|
||||
if (bytes_read < 0) {
|
||||
dev_err(qep->dev, "failed to read channel %d\n",
|
||||
bytes_read);
|
||||
return;
|
||||
}
|
||||
if (bytes_read == 0)
|
||||
return;
|
||||
|
||||
rc = qrtr_endpoint_post(&qep->ep, req.buf, req.transfer_len);
|
||||
if (rc == -EINVAL)
|
||||
dev_err(qep->dev, "invalid ipcrouter packet\n");
|
||||
} while (bytes_read > 0);
|
||||
}
|
||||
|
||||
static void qrtr_mhi_dev_event_cb(struct mhi_dev_client_cb_reason *reason)
|
||||
{
|
||||
struct qrtr_mhi_dev_ep *qep;
|
||||
|
||||
qep = qrtr_mhi_device_endpoint;
|
||||
if (!qep)
|
||||
return;
|
||||
|
||||
if (reason->reason == MHI_DEV_TRE_AVAILABLE) {
|
||||
pr_debug("TRE available event for chan %d\n", reason->ch_id);
|
||||
if (reason->ch_id == QRTR_MHI_DEV_IN) {
|
||||
qrtr_mhi_dev_read(qep);
|
||||
} else {
|
||||
mutex_lock(&qep->out_lock);
|
||||
complete_all(&qep->out_tre);
|
||||
mutex_unlock(&qep->out_lock);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int qrtr_mhi_dev_open_channels(struct qrtr_mhi_dev_ep *qep)
|
||||
{
|
||||
int rc;
|
||||
|
||||
/* write channel */
|
||||
rc = mhi_dev_open_channel(QRTR_MHI_DEV_IN, &qep->in,
|
||||
qrtr_mhi_dev_event_cb);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
/* read channel */
|
||||
rc = mhi_dev_open_channel(QRTR_MHI_DEV_OUT, &qep->out,
|
||||
qrtr_mhi_dev_event_cb);
|
||||
if (rc < 0) {
|
||||
mhi_dev_close_channel(qep->in);
|
||||
return rc;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void qrtr_mhi_dev_close_channels(struct qrtr_mhi_dev_ep *qep)
|
||||
{
|
||||
|
||||
mhi_dev_close_channel(qep->in);
|
||||
mhi_dev_close_channel(qep->out);
|
||||
}
|
||||
|
||||
static void qrtr_mhi_dev_state_cb(struct mhi_dev_client_cb_data *cb_data)
|
||||
{
|
||||
struct qrtr_mhi_dev_ep *qep;
|
||||
int rc;
|
||||
|
||||
if (!cb_data || !cb_data->user_data)
|
||||
return;
|
||||
qep = cb_data->user_data;
|
||||
|
||||
switch (cb_data->ctrl_info) {
|
||||
case MHI_STATE_CONNECTED:
|
||||
rc = qrtr_mhi_dev_open_channels(qep);
|
||||
if (rc) {
|
||||
dev_err(qep->dev, "open failed %d\n", rc);
|
||||
return;
|
||||
}
|
||||
|
||||
rc = qrtr_endpoint_register(&qep->ep, qep->net_id, qep->rt);
|
||||
if (rc) {
|
||||
dev_err(qep->dev, "register failed %d\n", rc);
|
||||
qrtr_mhi_dev_close_channels(qep);
|
||||
}
|
||||
break;
|
||||
case MHI_STATE_DISCONNECTED:
|
||||
qrtr_endpoint_unregister(&qep->ep);
|
||||
qrtr_mhi_dev_close_channels(qep);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int qrtr_mhi_dev_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct qrtr_mhi_dev_ep *qep;
|
||||
struct device_node *node;
|
||||
int rc;
|
||||
struct mhi_dev_client_cb_data cb_data;
|
||||
|
||||
qep = devm_kzalloc(&pdev->dev, sizeof(*qep), GFP_KERNEL);
|
||||
if (!qep)
|
||||
return -ENOMEM;
|
||||
qep->dev = &pdev->dev;
|
||||
|
||||
node = pdev->dev.of_node;
|
||||
rc = of_property_read_u32(node, "qcom,net-id", &qep->net_id);
|
||||
if (rc < 0)
|
||||
qep->net_id = QRTR_EP_NET_ID_AUTO;
|
||||
qep->rt = of_property_read_bool(node, "qcom,low-latency");
|
||||
|
||||
qep->buf_in = devm_kzalloc(&pdev->dev, QRTR_MAX_PKT_SIZE, GFP_KERNEL);
|
||||
if (!qep->buf_in)
|
||||
return -ENOMEM;
|
||||
|
||||
qrtr_mhi_device_endpoint = qep;
|
||||
|
||||
mutex_init(&qep->out_lock);
|
||||
init_completion(&qep->out_tre);
|
||||
qep->ep.xmit = qrtr_mhi_dev_send;
|
||||
/* HOST init TX first followed by RX, so register for endpoint TX
|
||||
* which makes both channel ready by checking one channel state.
|
||||
*/
|
||||
rc = mhi_register_state_cb(qrtr_mhi_dev_state_cb, qep,
|
||||
QRTR_MHI_DEV_OUT);
|
||||
if (rc == -EEXIST) {
|
||||
/**
|
||||
* MHI stack will return -EEXIST if mhi channel is already
|
||||
* opend by the host and will not invoke reqistered callback.
|
||||
* But future state change notification will inform through
|
||||
* registered callback.
|
||||
*/
|
||||
complete_all(&qep->out_tre);
|
||||
cb_data.user_data = (void *)qep;
|
||||
cb_data.channel = QRTR_MHI_DEV_OUT;
|
||||
cb_data.ctrl_info = MHI_STATE_CONNECTED;
|
||||
qrtr_mhi_dev_state_cb(&cb_data);
|
||||
} else if (rc) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id qrtr_mhi_dev_match_table[] = {
|
||||
{ .compatible = "qcom,qrtr-mhi-dev"},
|
||||
{},
|
||||
};
|
||||
|
||||
static struct platform_driver qrtr_mhi_dev_driver = {
|
||||
.probe = qrtr_mhi_dev_probe,
|
||||
.driver = {
|
||||
.name = "qrtr_mhi_dev",
|
||||
.of_match_table = qrtr_mhi_dev_match_table,
|
||||
},
|
||||
};
|
||||
module_platform_driver(qrtr_mhi_dev_driver);
|
||||
|
||||
MODULE_DESCRIPTION("QTI IPC-Router MHI device interface driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
|
@ -227,24 +227,26 @@ static int announce_servers(struct sockaddr_qrtr *sq)
|
|||
struct qrtr_server *srv;
|
||||
struct qrtr_node *node;
|
||||
unsigned long index;
|
||||
unsigned long node_idx;
|
||||
int ret;
|
||||
|
||||
node = node_get(qrtr_ns.local_node);
|
||||
if (!node)
|
||||
return 0;
|
||||
|
||||
/* Announce the list of servers registered in this node */
|
||||
xa_for_each(&node->servers, index, srv) {
|
||||
ret = service_announce_new(sq, srv);
|
||||
if (ret < 0) {
|
||||
if (ret == -ENODEV)
|
||||
continue;
|
||||
xa_for_each(&nodes, node_idx, node) {
|
||||
if (node->id == sq->sq_node) {
|
||||
pr_info("Avoiding duplicate announce for NODE ID %u\n", node->id);
|
||||
continue;
|
||||
}
|
||||
xa_for_each(&node->servers, index, srv) {
|
||||
ret = service_announce_new(sq, srv);
|
||||
if (ret < 0) {
|
||||
if (ret == -ENODEV)
|
||||
continue;
|
||||
|
||||
pr_err("failed to announce new service %d\n", ret);
|
||||
return ret;
|
||||
pr_err("failed to announce new service %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -63,6 +63,20 @@ header-test- += xen/evtchn.h
|
|||
header-test- += xen/gntdev.h
|
||||
header-test- += xen/privcmd.h
|
||||
|
||||
header-test- += camera/media/cam_jpeg.h
|
||||
header-test- += camera/media/cam_icp.h
|
||||
header-test- += camera/media/cam_isp.h
|
||||
header-test- += camera/media/cam_cpas.h
|
||||
header-test- += camera/media/cam_sensor.h
|
||||
header-test- += camera/media/cam_fd.h
|
||||
header-test- += camera/media/cam_tfe.h
|
||||
header-test- += camera/media/cam_custom.h
|
||||
header-test- += camera/media/cam_ope.h
|
||||
header-test- += camera/media/cam_sync.h
|
||||
header-test- += camera/media/cam_req_mgr.h
|
||||
header-test- += camera/media/cam_lrme.h
|
||||
header-test- += camera/media/cam_defs.h
|
||||
|
||||
header-test- += ais/media/ais_isp.h
|
||||
header-test- += ais/media/cam_lrme.h
|
||||
header-test- += ais/media/cam_cpas.h
|
||||
|
|
|
|||
Loading…
Reference in a new issue