summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Bestas <mkbestas@lineageos.org>2021-02-06 01:33:49 +0200
committerMichael Bestas <mkbestas@lineageos.org>2021-02-06 01:33:49 +0200
commit4d2544c30eab39bfe0eed6027fe4059f58ee91ad (patch)
treecdb839bc415cbac2a2342c8f82ffe963e40faa48
parent141849eac5defb4bb6cf6e6f1381cb24ffcfdba5 (diff)
parentc3cd6d0f0f73c7f0b0b5173ac7ad6753fb3b8ce1 (diff)
Merge tag 'LA.UM.9.2.r1-02000-SDMxx0.0' of https://source.codeaurora.org/quic/la/kernel/msm-4.4 into lineage-18.1-caf-msm8998
* tag 'LA.UM.9.2.r1-02000-SDMxx0.0' of https://source.codeaurora.org/quic/la/kernel/msm-4.4: net: ipv6: Use passed in table for nexthop lookups ipv6: addrconf: use stable address generator for ARPHRD_NONE msm: kgsl: Protect the memdesc->gpuaddr in SVM use cases msm: kgsl: Stop using memdesc->usermem msm: kgsl: Correct the refcount on current process PID HID: sony: Update hid_have_special_driver UPSTREAM: HID: input: map digitizer battery usage HID: input: ignore the battery in OKLICK Laser BTmouse defconfig: Enable CONFIG_HID_NINTENDO for msm8998 iio: qcom-rradc: Update logic to monitor health of RRADC peripheral qcom: fg-memif: Correct timeout condition for memory grant power: qpnp-fg-gen3: Add a property to reset FG BCL device msm: ipa3: Add check to validate rule_cnt power_supply: add FG_RESET_CLOCK property defconfig: Enable CONFIG_HID_NINTENDO for SDM660 FROMLIST: HID: nintendo: add nintendo switch controller driver defconfig: Enable UTS_NS for sdm660 Conflicts: drivers/hid/hid-input.c drivers/power/power_supply_sysfs.c include/linux/power_supply.h Change-Id: I577e4b1d9410887224dbdb192c6eea1f2de6aded
-rw-r--r--drivers/gpu/msm/kgsl.c95
-rw-r--r--drivers/gpu/msm/kgsl.h16
-rw-r--r--drivers/gpu/msm/kgsl_debugfs.c22
-rw-r--r--drivers/gpu/msm/kgsl_iommu.c10
-rw-r--r--drivers/gpu/msm/kgsl_mmu.c10
-rw-r--r--drivers/gpu/msm/kgsl_sharedmem.c7
-rw-r--r--drivers/gpu/msm/kgsl_sharedmem.h3
-rw-r--r--drivers/gpu/msm/kgsl_trace.h8
-rw-r--r--drivers/iio/adc/qcom-rradc.c136
-rw-r--r--drivers/platform/msm/ipa/ipa_v2/ipa_flt.c7
-rw-r--r--drivers/platform/msm/ipa/ipa_v2/ipa_i.h3
-rw-r--r--drivers/platform/msm/ipa/ipa_v2/ipa_rt.c7
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa_flt.c7
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa_i.h4
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa_rt.c5
-rw-r--r--drivers/power/power_supply_sysfs.c1
-rw-r--r--drivers/power/supply/qcom/fg-core.h3
-rw-r--r--drivers/power/supply/qcom/fg-memif.c60
-rw-r--r--drivers/power/supply/qcom/fg-reg.h17
-rw-r--r--drivers/power/supply/qcom/fg-util.c6
-rw-r--r--drivers/power/supply/qcom/qpnp-fg-gen3.c105
-rw-r--r--include/linux/power_supply.h1
-rw-r--r--include/uapi/linux/if_link.h1
-rw-r--r--net/ipv6/addrconf.c43
24 files changed, 502 insertions, 75 deletions
diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c
index 96b24176c388..2170a329d5bf 100644
--- a/drivers/gpu/msm/kgsl.c
+++ b/drivers/gpu/msm/kgsl.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2020, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2008-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
@@ -266,6 +266,7 @@ kgsl_mem_entry_create(void)
/* put this ref in the caller functions after init */
kref_get(&entry->refcount);
}
+ atomic_set(&entry->map_count, 0);
return entry;
}
#ifdef CONFIG_DMA_SHARED_BUFFER
@@ -916,17 +917,24 @@ static struct kgsl_process_private *kgsl_process_private_new(
list_for_each_entry(private, &kgsl_driver.process_list, list) {
if (private->pid == cur_pid) {
if (!kgsl_process_private_get(private)) {
- put_pid(cur_pid);
private = ERR_PTR(-EINVAL);
}
+ /*
+ * We need to hold only one reference to the PID for
+ * each process struct to avoid overflowing the
+ * reference counter which can lead to use-after-free.
+ */
+ put_pid(cur_pid);
return private;
}
}
/* Create a new object */
private = kzalloc(sizeof(struct kgsl_process_private), GFP_KERNEL);
- if (private == NULL)
+ if (private == NULL) {
+ put_pid(cur_pid);
return ERR_PTR(-ENOMEM);
+ }
kref_init(&private->refcount);
@@ -2131,7 +2139,7 @@ static int check_vma(unsigned long hostptr, u64 size)
return true;
}
-static int memdesc_sg_virt(struct kgsl_memdesc *memdesc)
+static int memdesc_sg_virt(struct kgsl_memdesc *memdesc, unsigned long useraddr)
{
int ret = 0;
long npages = 0, i;
@@ -2153,13 +2161,13 @@ static int memdesc_sg_virt(struct kgsl_memdesc *memdesc)
}
down_read(&current->mm->mmap_sem);
- if (!check_vma(memdesc->useraddr, memdesc->size)) {
+ if (!check_vma(useraddr, memdesc->size)) {
up_read(&current->mm->mmap_sem);
ret = ~EFAULT;
goto out;
}
- npages = get_user_pages(current, current->mm, memdesc->useraddr,
+ npages = get_user_pages(current, current->mm, useraddr,
sglen, write ? FOLL_WRITE : 0, pages, NULL);
up_read(&current->mm->mmap_sem);
@@ -2198,7 +2206,6 @@ static int kgsl_setup_anon_useraddr(struct kgsl_pagetable *pagetable,
entry->memdesc.pagetable = pagetable;
entry->memdesc.size = (uint64_t) size;
- entry->memdesc.useraddr = hostptr;
entry->memdesc.flags |= KGSL_MEMFLAGS_USERMEM_ADDR;
if (kgsl_memdesc_use_cpu_map(&entry->memdesc)) {
@@ -2206,15 +2213,15 @@ static int kgsl_setup_anon_useraddr(struct kgsl_pagetable *pagetable,
/* Register the address in the database */
ret = kgsl_mmu_set_svm_region(pagetable,
- (uint64_t) entry->memdesc.useraddr, (uint64_t) size);
+ (uint64_t) hostptr, (uint64_t) size);
if (ret)
return ret;
- entry->memdesc.gpuaddr = (uint64_t) entry->memdesc.useraddr;
+ entry->memdesc.gpuaddr = (uint64_t) hostptr;
}
- return memdesc_sg_virt(&entry->memdesc);
+ return memdesc_sg_virt(&entry->memdesc, hostptr);
}
static int match_file(const void *p, struct file *file, unsigned int fd)
@@ -2299,8 +2306,8 @@ static int kgsl_setup_dmabuf_useraddr(struct kgsl_device *device,
return ret;
}
- /* Setup the user addr/cache mode for cache operations */
- entry->memdesc.useraddr = hostptr;
+ /* Setup the cache mode for cache operations */
+
_setup_cache_mode(entry, vma);
up_read(&current->mm->mmap_sem);
return 0;
@@ -2434,6 +2441,8 @@ long kgsl_ioctl_gpuobj_import(struct kgsl_device_private *dev_priv,
if (entry == NULL)
return -ENOMEM;
+ spin_lock_init(&entry->memdesc.lock);
+
param->flags &= KGSL_MEMFLAGS_GPUREADONLY
| KGSL_MEMTYPE_MASK
| KGSL_MEMALIGN_MASK
@@ -2707,6 +2716,8 @@ long kgsl_ioctl_map_user_mem(struct kgsl_device_private *dev_priv,
if (entry == NULL)
return -ENOMEM;
+ spin_lock_init(&entry->memdesc.lock);
+
/*
* Convert from enum value to KGSL_MEM_ENTRY value, so that
* we can use the latter consistently everywhere.
@@ -3318,7 +3329,12 @@ long kgsl_ioctl_gpumem_get_info(struct kgsl_device_private *dev_priv,
param->flags = (unsigned int) entry->memdesc.flags;
param->size = (size_t) entry->memdesc.size;
param->mmapsize = (size_t) kgsl_memdesc_footprint(&entry->memdesc);
- param->useraddr = entry->memdesc.useraddr;
+ /*
+ * Entries can have multiple user mappings so thre isn't any one address
+ * we can report. Plus, the user should already know their mappings, so
+ * there isn't any value in reporting it back to them.
+ */
+ param->useraddr = 0;
kgsl_mem_entry_put(entry);
return result;
@@ -3482,6 +3498,8 @@ long kgsl_ioctl_sparse_virt_alloc(struct kgsl_device_private *dev_priv,
if (entry == NULL)
return -ENOMEM;
+ spin_lock_init(&entry->memdesc.lock);
+
entry->memdesc.flags = KGSL_MEMFLAGS_SPARSE_VIRT;
entry->memdesc.size = param->size;
entry->memdesc.cur_bindings = 0;
@@ -3784,9 +3802,6 @@ static int _sparse_bind(struct kgsl_process_private *process,
if (memdesc->gpuaddr)
return -EINVAL;
- if (memdesc->useraddr != 0)
- return -EINVAL;
-
pagetable = memdesc->pagetable;
/* Clear out any mappings */
@@ -4066,7 +4081,12 @@ long kgsl_ioctl_gpuobj_info(struct kgsl_device_private *dev_priv,
param->flags = entry->memdesc.flags;
param->size = entry->memdesc.size;
param->va_len = kgsl_memdesc_footprint(&entry->memdesc);
- param->va_addr = (uint64_t) entry->memdesc.useraddr;
+ /*
+ * Entries can have multiple user mappings so thre isn't any one address
+ * we can report. Plus, the user should already know their mappings, so
+ * there isn't any value in reporting it back to them.
+ */
+ param->va_addr = 0;
kgsl_mem_entry_put(entry);
return 0;
@@ -4234,6 +4254,8 @@ static void kgsl_gpumem_vm_open(struct vm_area_struct *vma)
if (kgsl_mem_entry_get(entry) == 0)
vma->vm_private_data = NULL;
+
+ atomic_inc(&entry->map_count);
}
static int
@@ -4257,7 +4279,8 @@ kgsl_gpumem_vm_close(struct vm_area_struct *vma)
if (!entry)
return;
- entry->memdesc.useraddr = 0;
+ atomic_dec(&entry->map_count);
+
kgsl_mem_entry_put(entry);
}
@@ -4296,7 +4319,8 @@ get_mmap_entry(struct kgsl_process_private *private,
}
}
- if (entry->memdesc.useraddr != 0) {
+ /* Don't allow ourselves to remap user memory */
+ if (entry->memdesc.flags & KGSL_MEMFLAGS_USERMEM_ADDR) {
ret = -EBUSY;
goto err_put;
}
@@ -4329,19 +4353,34 @@ static unsigned long _gpu_set_svm_region(struct kgsl_process_private *private,
{
int ret;
+ /*
+ * Protect access to the gpuaddr here to prevent multiple vmas from
+ * trying to map a SVM region at the same time
+ */
+ spin_lock(&entry->memdesc.lock);
+
+ if (entry->memdesc.gpuaddr) {
+ spin_unlock(&entry->memdesc.lock);
+ return (unsigned long) -EBUSY;
+ }
+
ret = kgsl_mmu_set_svm_region(private->pagetable, (uint64_t) addr,
(uint64_t) size);
- if (ret != 0)
- return ret;
+ if (ret != 0) {
+ spin_unlock(&entry->memdesc.lock);
+ return (unsigned long) ret;
+ }
entry->memdesc.gpuaddr = (uint64_t) addr;
+ spin_unlock(&entry->memdesc.lock);
+
entry->memdesc.pagetable = private->pagetable;
ret = kgsl_mmu_map(private->pagetable, &entry->memdesc);
if (ret) {
kgsl_mmu_put_gpuaddr(&entry->memdesc);
- return ret;
+ return (unsigned long) ret;
}
kgsl_memfree_purge(private->pagetable, entry->memdesc.gpuaddr,
@@ -4404,6 +4443,14 @@ static unsigned long _search_range(struct kgsl_process_private *private,
result = _gpu_set_svm_region(private, entry, cpu, len);
if (!IS_ERR_VALUE(result))
break;
+ /*
+ * _gpu_set_svm_region will return -EBUSY if we tried to set up
+ * SVM on an object that already has a GPU address. If
+ * that happens don't bother walking the rest of the
+ * region
+ */
+ if ((long) result == -EBUSY)
+ return -EBUSY;
trace_kgsl_mem_unmapped_area_collision(entry, cpu, len);
@@ -4620,9 +4667,9 @@ static int kgsl_mmap(struct file *file, struct vm_area_struct *vma)
vma->vm_file = file;
- entry->memdesc.useraddr = vma->vm_start;
+ atomic_inc(&entry->map_count);
- trace_kgsl_mem_mmap(entry);
+ trace_kgsl_mem_mmap(entry, vma->vm_start);
return 0;
}
diff --git a/drivers/gpu/msm/kgsl.h b/drivers/gpu/msm/kgsl.h
index 6b8ef82d340f..31257d291c7e 100644
--- a/drivers/gpu/msm/kgsl.h
+++ b/drivers/gpu/msm/kgsl.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008-2016,2018-2019, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2008-2016,2018-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
@@ -197,11 +197,9 @@ struct kgsl_memdesc_ops {
* @pagetable: Pointer to the pagetable that the object is mapped in
* @hostptr: Kernel virtual address
* @hostptr_count: Number of threads using hostptr
- * @useraddr: User virtual address (if applicable)
* @gpuaddr: GPU virtual address
* @physaddr: Physical address of the memory object
* @size: Size of the memory object
- * @mapsize: Size of memory mapped in userspace
* @priv: Internal flags and settings
* @sgt: Scatter gather table for allocated pages
* @ops: Function hooks for the memdesc memory type
@@ -216,11 +214,9 @@ struct kgsl_memdesc {
struct kgsl_pagetable *pagetable;
void *hostptr;
unsigned int hostptr_count;
- unsigned long useraddr;
uint64_t gpuaddr;
phys_addr_t physaddr;
uint64_t size;
- uint64_t mapsize;
unsigned int priv;
struct sg_table *sgt;
struct kgsl_memdesc_ops *ops;
@@ -230,6 +226,11 @@ struct kgsl_memdesc {
struct page **pages;
unsigned int page_count;
unsigned int cur_bindings;
+ /*
+ * @lock: Spinlock to protect the gpuaddr from being accessed by
+ * multiple entities trying to map the same SVM region at once
+ */
+ spinlock_t lock;
};
/*
@@ -278,6 +279,11 @@ struct kgsl_mem_entry {
struct work_struct work;
spinlock_t bind_lock;
struct rb_root bind_tree;
+ /*
+ * @map_count: Count how many vmas this object is mapped in - used for
+ * debugfs accounting
+ */
+ atomic_t map_count;
};
struct kgsl_device_private;
diff --git a/drivers/gpu/msm/kgsl_debugfs.c b/drivers/gpu/msm/kgsl_debugfs.c
index 30769de41a70..36bb4d801df9 100644
--- a/drivers/gpu/msm/kgsl_debugfs.c
+++ b/drivers/gpu/msm/kgsl_debugfs.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2008-2017,2020, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2002,2008-2017,2020-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
@@ -149,7 +149,11 @@ static int print_mem_entry(void *data, void *ptr)
flags[3] = get_alignflag(m);
flags[4] = get_cacheflag(m);
flags[5] = kgsl_memdesc_use_cpu_map(m) ? 'p' : '-';
- flags[6] = (m->useraddr) ? 'Y' : 'N';
+ /*
+ * Show Y if at least one vma has this entry
+ * mapped (could be multiple)
+ */
+ flags[6] = atomic_read(&entry->map_count) ? 'Y' : 'N';
flags[7] = kgsl_memdesc_is_secured(m) ? 's' : '-';
flags[8] = m->flags & KGSL_MEMFLAGS_SPARSE_PHYS ? 'P' : '-';
flags[9] = '\0';
@@ -160,12 +164,16 @@ static int print_mem_entry(void *data, void *ptr)
kgsl_get_egl_counts(entry, &egl_surface_count,
&egl_image_count);
- seq_printf(s, "%pK %pK %16llu %5d %9s %10s %16s %5d %16llu %6d %6d",
+ seq_printf(s, "%pK %d %16llu %5d %9s %10s %16s %5d %16d %6d %6d",
(uint64_t *)(uintptr_t) m->gpuaddr,
- (unsigned long *) m->useraddr,
- m->size, entry->id, flags,
+ /*
+ * Show zero for the useraddr - we can't reliably track
+ * that value for multiple vmas anyway
+ */
+ 0, m->size, entry->id, flags,
memtype_str(usermem_type),
- usage, (m->sgt ? m->sgt->nents : 0), m->mapsize,
+ usage, (m->sgt ? m->sgt->nents : 0),
+ atomic_read(&entry->map_count),
egl_surface_count, egl_image_count);
if (entry->metadata[0] != 0)
@@ -235,7 +243,7 @@ static int process_mem_seq_show(struct seq_file *s, void *ptr)
if (ptr == SEQ_START_TOKEN) {
seq_printf(s, "%16s %16s %16s %5s %9s %10s %16s %5s %16s %6s %6s\n",
"gpuaddr", "useraddr", "size", "id", "flags", "type",
- "usage", "sglen", "mapsize", "eglsrf", "eglimg");
+ "usage", "sglen", "mapcount", "eglsrf", "eglimg");
return 0;
} else
return print_mem_entry(s, ptr);
diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c
index aff54105474a..08f5c6d9d50b 100644
--- a/drivers/gpu/msm/kgsl_iommu.c
+++ b/drivers/gpu/msm/kgsl_iommu.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2020, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-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
@@ -270,6 +270,7 @@ static void kgsl_setup_qdss_desc(struct kgsl_device *device)
return;
}
+ spin_lock_init(&gpu_qdss_desc.lock);
gpu_qdss_desc.flags = 0;
gpu_qdss_desc.priv = 0;
gpu_qdss_desc.physaddr = gpu_qdss_entry[0];
@@ -315,6 +316,7 @@ static void kgsl_setup_qtimer_desc(struct kgsl_device *device)
return;
}
+ spin_lock_init(&gpu_qtimer_desc.lock);
gpu_qtimer_desc.flags = 0;
gpu_qtimer_desc.priv = 0;
gpu_qtimer_desc.physaddr = gpu_qtimer_entry[0];
@@ -1499,6 +1501,7 @@ static int _setstate_alloc(struct kgsl_device *device,
{
int ret;
+ spin_lock_init(&iommu->setstate.lock);
ret = kgsl_sharedmem_alloc_contig(device, &iommu->setstate, PAGE_SIZE);
if (!ret) {
@@ -2477,6 +2480,11 @@ static int kgsl_iommu_get_gpuaddr(struct kgsl_pagetable *pagetable,
goto out;
}
+ /*
+ * This path is only called in a non-SVM path with locks so we can be
+ * sure we aren't racing with anybody so we don't need to worry about
+ * taking the lock
+ */
ret = _insert_gpuaddr(pagetable, addr, size);
if (ret == 0) {
memdesc->gpuaddr = addr;
diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c
index aa7157e882ac..2303e8ee0721 100644
--- a/drivers/gpu/msm/kgsl_mmu.c
+++ b/drivers/gpu/msm/kgsl_mmu.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2007-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2002,2007-2017,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
@@ -443,10 +443,16 @@ void kgsl_mmu_put_gpuaddr(struct kgsl_memdesc *memdesc)
if (PT_OP_VALID(pagetable, put_gpuaddr) && (unmap_fail == 0))
pagetable->pt_ops->put_gpuaddr(memdesc);
+ memdesc->pagetable = NULL;
+
+ /*
+ * If SVM tries to take a GPU address it will lose the race until the
+ * gpuaddr returns to zero so we shouldn't need to worry about taking a
+ * lock here
+ */
if (!kgsl_memdesc_is_global(memdesc))
memdesc->gpuaddr = 0;
- memdesc->pagetable = NULL;
}
EXPORT_SYMBOL(kgsl_mmu_put_gpuaddr);
diff --git a/drivers/gpu/msm/kgsl_sharedmem.c b/drivers/gpu/msm/kgsl_sharedmem.c
index b233211620da..dfbea53c306b 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.c
+++ b/drivers/gpu/msm/kgsl_sharedmem.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2007-2017,2020, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2002,2007-2017,2020-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
@@ -342,6 +342,7 @@ int kgsl_allocate_user(struct kgsl_device *device,
int ret;
memdesc->flags = flags;
+ spin_lock_init(&memdesc->lock);
if (kgsl_mmu_get_mmutype(device) == KGSL_MMU_TYPE_NONE)
ret = kgsl_sharedmem_alloc_contig(device, memdesc, size);
@@ -373,8 +374,6 @@ static int kgsl_page_alloc_vmfault(struct kgsl_memdesc *memdesc,
get_page(page);
vmf->page = page;
- memdesc->mapsize += PAGE_SIZE;
-
return 0;
}
@@ -504,8 +503,6 @@ static int kgsl_contiguous_vmfault(struct kgsl_memdesc *memdesc,
else if (ret == -EFAULT)
return VM_FAULT_SIGBUS;
- memdesc->mapsize += PAGE_SIZE;
-
return VM_FAULT_NOPAGE;
}
diff --git a/drivers/gpu/msm/kgsl_sharedmem.h b/drivers/gpu/msm/kgsl_sharedmem.h
index e5da594b77b8..ee89cfb808d7 100644
--- a/drivers/gpu/msm/kgsl_sharedmem.h
+++ b/drivers/gpu/msm/kgsl_sharedmem.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2002,2007-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2002,2007-2017,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
@@ -283,6 +283,7 @@ static inline int kgsl_allocate_global(struct kgsl_device *device,
memdesc->flags = flags;
memdesc->priv = priv;
+ spin_lock_init(&memdesc->lock);
if (((memdesc->priv & KGSL_MEMDESC_CONTIG) != 0) ||
(kgsl_mmu_get_mmutype(device) == KGSL_MMU_TYPE_NONE))
diff --git a/drivers/gpu/msm/kgsl_trace.h b/drivers/gpu/msm/kgsl_trace.h
index 2d9bca7e7d7f..5f325729f71e 100644
--- a/drivers/gpu/msm/kgsl_trace.h
+++ b/drivers/gpu/msm/kgsl_trace.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011-2016,2020, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2011-2016,2020-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
@@ -433,9 +433,9 @@ TRACE_EVENT(kgsl_mem_alloc,
TRACE_EVENT(kgsl_mem_mmap,
- TP_PROTO(struct kgsl_mem_entry *mem_entry),
+ TP_PROTO(struct kgsl_mem_entry *mem_entry, unsigned long useraddr),
- TP_ARGS(mem_entry),
+ TP_ARGS(mem_entry, useraddr),
TP_STRUCT__entry(
__field(unsigned long, useraddr)
@@ -447,7 +447,7 @@ TRACE_EVENT(kgsl_mem_mmap,
),
TP_fast_assign(
- __entry->useraddr = mem_entry->memdesc.useraddr;
+ __entry->useraddr = useraddr;
__entry->gpuaddr = mem_entry->memdesc.gpuaddr;
__entry->size = mem_entry->memdesc.size;
kgsl_get_memory_usage(__entry->usage, sizeof(__entry->usage),
diff --git a/drivers/iio/adc/qcom-rradc.c b/drivers/iio/adc/qcom-rradc.c
index b3aa73f1a5a1..b9e12f795c79 100644
--- a/drivers/iio/adc/qcom-rradc.c
+++ b/drivers/iio/adc/qcom-rradc.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2017, 2020, 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
@@ -193,7 +193,8 @@
#define FG_RR_ADC_STS_CHANNEL_READING_MASK 0x3
#define FG_RR_ADC_STS_CHANNEL_STS 0x2
-#define FG_RR_CONV_CONTINUOUS_TIME_MIN_MS 50
+#define FG_RR_CONV_CONTINUOUS_TIME_MIN_MS 50
+#define FG_RR_CONV_CONT_CBK_TIME_MIN_MS 10
#define FG_RR_CONV_MAX_RETRY_CNT 50
#define FG_RR_TP_REV_VERSION1 21
#define FG_RR_TP_REV_VERSION2 29
@@ -236,6 +237,11 @@ struct rradc_chip {
struct pmic_revid_data *pmic_fab_id;
int volt;
struct power_supply *usb_trig;
+ struct power_supply *batt_psy;
+ struct power_supply *bms_psy;
+ struct notifier_block nb;
+ bool conv_cbk;
+ struct work_struct psy_notify_work;
};
struct rradc_channels {
@@ -680,6 +686,28 @@ static const struct rradc_channels rradc_chans[] = {
FG_ADC_RR_AUX_THERM_STS)
};
+static bool rradc_is_batt_psy_available(struct rradc_chip *chip)
+{
+ if (!chip->batt_psy)
+ chip->batt_psy = power_supply_get_by_name("battery");
+
+ if (!chip->batt_psy)
+ return false;
+
+ return true;
+}
+
+static bool rradc_is_bms_psy_available(struct rradc_chip *chip)
+{
+ if (!chip->bms_psy)
+ chip->bms_psy = power_supply_get_by_name("bms");
+
+ if (!chip->bms_psy)
+ return false;
+
+ return true;
+}
+
static int rradc_enable_continuous_mode(struct rradc_chip *chip)
{
int rc = 0;
@@ -749,6 +777,7 @@ static int rradc_check_status_ready_with_retry(struct rradc_chip *chip,
struct rradc_chan_prop *prop, u8 *buf, u16 status)
{
int rc = 0, retry_cnt = 0, mask = 0;
+ union power_supply_propval pval = {0, };
switch (prop->channel) {
case RR_ADC_BATT_ID:
@@ -775,7 +804,11 @@ static int rradc_check_status_ready_with_retry(struct rradc_chip *chip,
break;
}
- msleep(FG_RR_CONV_CONTINUOUS_TIME_MIN_MS);
+ if ((chip->conv_cbk) && (prop->channel == RR_ADC_USBIN_V))
+ msleep(FG_RR_CONV_CONT_CBK_TIME_MIN_MS);
+ else
+ msleep(FG_RR_CONV_CONTINUOUS_TIME_MIN_MS);
+
retry_cnt++;
rc = rradc_read(chip, status, buf, 1);
if (rc < 0) {
@@ -784,8 +817,26 @@ static int rradc_check_status_ready_with_retry(struct rradc_chip *chip,
}
}
- if (retry_cnt >= FG_RR_CONV_MAX_RETRY_CNT)
- rc = -ENODATA;
+ if ((retry_cnt >= FG_RR_CONV_MAX_RETRY_CNT) &&
+ ((prop->channel != RR_ADC_DCIN_V) ||
+ (prop->channel != RR_ADC_DCIN_I))) {
+ pr_err("rradc is hung, Proceed to recovery\n");
+ if (rradc_is_bms_psy_available(chip)) {
+ rc = power_supply_set_property(chip->bms_psy,
+ POWER_SUPPLY_PROP_FG_RESET_CLOCK,
+ &pval);
+ if (rc < 0) {
+ pr_err("Couldn't reset FG clock rc=%d\n", rc);
+ return rc;
+ }
+ } else {
+ pr_err("Error obtaining bms power supply\n");
+ rc = -EINVAL;
+ }
+ } else {
+ if (retry_cnt >= FG_RR_CONV_MAX_RETRY_CNT)
+ rc = -ENODATA;
+ }
return rc;
}
@@ -1073,6 +1124,67 @@ static int rradc_read_raw(struct iio_dev *indio_dev,
return rc;
}
+static void psy_notify_work(struct work_struct *work)
+{
+ struct rradc_chip *chip = container_of(work,
+ struct rradc_chip, psy_notify_work);
+
+ struct rradc_chan_prop *prop;
+ union power_supply_propval pval = {0, };
+ u16 adc_code;
+ int rc = 0;
+
+ if (rradc_is_batt_psy_available(chip)) {
+ rc = power_supply_get_property(chip->batt_psy,
+ POWER_SUPPLY_PROP_STATUS, &pval);
+ if (rc < 0)
+ pr_err("Error obtaining battery status, rc=%d\n", rc);
+
+ if (pval.intval == POWER_SUPPLY_STATUS_CHARGING) {
+ chip->conv_cbk = true;
+ prop = &chip->chan_props[RR_ADC_USBIN_V];
+ rc = rradc_do_conversion(chip, prop, &adc_code);
+ if (rc == -ENODATA) {
+ pr_err("rradc is hung, Proceed to recovery\n");
+ if (rradc_is_bms_psy_available(chip)) {
+ rc = power_supply_set_property
+ (chip->bms_psy,
+ POWER_SUPPLY_PROP_FG_RESET_CLOCK,
+ &pval);
+ if (rc < 0)
+ pr_err("Couldn't reset FG clock rc=%d\n",
+ rc);
+ prop = &chip->chan_props[RR_ADC_BATT_ID];
+ rc = rradc_do_conversion(chip, prop,
+ &adc_code);
+ if (rc == -ENODATA)
+ pr_err("RRADC read failed after reset");
+ } else {
+ pr_err("Error obtaining bms power supply");
+ }
+ }
+ }
+ } else {
+ pr_err("Error obtaining battery power supply");
+ }
+ chip->conv_cbk = false;
+ pm_relax(chip->dev);
+}
+
+static int rradc_psy_notifier_cb(struct notifier_block *nb,
+ unsigned long event, void *data)
+{
+ struct power_supply *psy = data;
+ struct rradc_chip *chip = container_of(nb, struct rradc_chip, nb);
+
+ if (strcmp(psy->desc->name, "battery") == 0) {
+ pm_stay_awake(chip->dev);
+ schedule_work(&chip->psy_notify_work);
+ }
+
+ return NOTIFY_OK;
+}
+
static const struct iio_info rradc_info = {
.read_raw = &rradc_read_raw,
.driver_module = THIS_MODULE,
@@ -1184,6 +1296,20 @@ static int rradc_probe(struct platform_device *pdev)
if (!chip->usb_trig)
pr_debug("Error obtaining usb power supply\n");
+ chip->batt_psy = power_supply_get_by_name("battery");
+ if (!chip->batt_psy)
+ pr_debug("Error obtaining battery power supply\n");
+
+ chip->bms_psy = power_supply_get_by_name("bms");
+ if (!chip->bms_psy)
+ pr_debug("Error obtaining bms power supply\n");
+
+ chip->nb.notifier_call = rradc_psy_notifier_cb;
+ rc = power_supply_reg_notifier(&chip->nb);
+ if (rc < 0)
+ pr_err("Error registering psy notifier rc = %d\n", rc);
+ INIT_WORK(&chip->psy_notify_work, psy_notify_work);
+
return devm_iio_device_register(dev, indio_dev);
}
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_flt.c b/drivers/platform/msm/ipa/ipa_v2/ipa_flt.c
index c29cbdf95057..b2e876c26749 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_flt.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_flt.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2018, 2020, 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
@@ -1065,7 +1065,10 @@ static int __ipa_add_flt_rule(struct ipa_flt_tbl *tbl, enum ipa_ip_type ip,
} else {
list_add(&entry->link, &tbl->head_flt_rule_list);
}
- tbl->rule_cnt++;
+ if (tbl->rule_cnt < IPA_RULE_CNT_MAX)
+ tbl->rule_cnt++;
+ else
+ return -EINVAL;
if (entry->rt_tbl)
entry->rt_tbl->ref_cnt++;
id = ipa_id_alloc(entry);
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_i.h b/drivers/platform/msm/ipa/ipa_v2/ipa_i.h
index 1c9eeb50d1cd..bf0b069f92bd 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_i.h
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_i.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2018, 2020, 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
@@ -201,6 +201,7 @@
#define IPA2_ACTIVE_CLIENTS_LOG_LINE_LEN 96
#define IPA2_ACTIVE_CLIENTS_LOG_HASHTABLE_SIZE 50
#define IPA2_ACTIVE_CLIENTS_LOG_NAME_LEN 40
+#define IPA_RULE_CNT_MAX 512
struct ipa2_active_client_htable_entry {
struct hlist_node list;
diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c b/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c
index 007f92bcee13..abb7947b2a06 100644
--- a/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c
+++ b/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2020, 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
@@ -1086,7 +1086,10 @@ static int __ipa_add_rt_rule(enum ipa_ip_type ip, const char *name,
list_add_tail(&entry->link, &tbl->head_rt_rule_list);
else
list_add(&entry->link, &tbl->head_rt_rule_list);
- tbl->rule_cnt++;
+ if (tbl->rule_cnt < IPA_RULE_CNT_MAX)
+ tbl->rule_cnt++;
+ else
+ return -EINVAL;
if (entry->hdr)
entry->hdr->ref_cnt++;
else if (entry->proc_ctx)
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c b/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c
index 060b40a3acc6..f36687b44b8d 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2020, 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
@@ -824,7 +824,10 @@ static int __ipa_finish_flt_rule_add(struct ipa3_flt_tbl *tbl,
{
int id;
- tbl->rule_cnt++;
+ if (tbl->rule_cnt < IPA_RULE_CNT_MAX)
+ tbl->rule_cnt++;
+ else
+ return -EINVAL;
if (entry->rt_tbl)
entry->rt_tbl->ref_cnt++;
id = ipa3_id_alloc(entry);
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
index 7691aa93d544..5c1e49435631 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2019, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2020, 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
@@ -190,6 +190,8 @@
#define IPA3_ACTIVE_CLIENTS_LOG_HASHTABLE_SIZE 50
#define IPA3_ACTIVE_CLIENTS_LOG_NAME_LEN 40
+#define IPA_RULE_CNT_MAX 512
+
struct ipa3_active_client_htable_entry {
struct hlist_node list;
char id_string[IPA3_ACTIVE_CLIENTS_LOG_NAME_LEN];
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c b/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c
index d8afb0c3becc..473618e9bd6a 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c
@@ -1000,7 +1000,10 @@ static int __ipa_finish_rt_rule_add(struct ipa3_rt_entry *entry, u32 *rule_hdl,
{
int id;
- tbl->rule_cnt++;
+ if (tbl->rule_cnt < IPA_RULE_CNT_MAX)
+ tbl->rule_cnt++;
+ else
+ return -EINVAL;
if (entry->hdr)
entry->hdr->ref_cnt++;
else if (entry->proc_ctx)
diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c
index 96853c18bc43..2907291dfa09 100644
--- a/drivers/power/power_supply_sysfs.c
+++ b/drivers/power/power_supply_sysfs.c
@@ -315,6 +315,7 @@ static struct device_attribute power_supply_attrs[] = {
POWER_SUPPLY_ATTR(parallel_batfet_mode),
POWER_SUPPLY_ATTR(parallel_fcc_max),
POWER_SUPPLY_ATTR(min_icl),
+ POWER_SUPPLY_ATTR(fg_reset_clock),
/* Local extensions of type int64_t */
POWER_SUPPLY_ATTR(charge_counter_ext),
/* Properties of type `const char *' */
diff --git a/drivers/power/supply/qcom/fg-core.h b/drivers/power/supply/qcom/fg-core.h
index 076cd49e6dd5..f596f85a5b50 100644
--- a/drivers/power/supply/qcom/fg-core.h
+++ b/drivers/power/supply/qcom/fg-core.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2017, 2020, 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
@@ -522,4 +522,5 @@ extern void fg_circ_buf_clr(struct fg_circ_buf *);
extern int fg_circ_buf_avg(struct fg_circ_buf *, int *);
extern int fg_circ_buf_median(struct fg_circ_buf *, int *);
extern int fg_lerp(const struct fg_pt *, size_t, s32, s32 *);
+extern int fg_dma_mem_req(struct fg_chip *, bool);
#endif
diff --git a/drivers/power/supply/qcom/fg-memif.c b/drivers/power/supply/qcom/fg-memif.c
index 8a949bfe61d0..694e8f769516 100644
--- a/drivers/power/supply/qcom/fg-memif.c
+++ b/drivers/power/supply/qcom/fg-memif.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2017, 2020, 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
@@ -746,6 +746,64 @@ out:
return rc;
}
+int fg_dma_mem_req(struct fg_chip *chip, bool request)
+{
+ int ret, rc = 0, retry_count = RETRY_COUNT;
+ u8 val;
+
+ if (request) {
+ /* configure for DMA access */
+ rc = fg_masked_write(chip, MEM_IF_MEM_INTF_CFG(chip),
+ MEM_ACCESS_REQ_BIT | IACS_SLCT_BIT,
+ MEM_ACCESS_REQ_BIT);
+ if (rc < 0) {
+ pr_err("failed to set mem_access bit rc=%d\n", rc);
+ return rc;
+ }
+
+ rc = fg_masked_write(chip, MEM_IF_MEM_ARB_CFG(chip),
+ MEM_IF_ARB_REQ_BIT, MEM_IF_ARB_REQ_BIT);
+ if (rc < 0) {
+ pr_err("failed to set mem_arb bit rc=%d\n", rc);
+ goto release_mem;
+ }
+
+ while (retry_count--) {
+ rc = fg_read(chip, MEM_IF_INT_RT_STS(chip), &val, 1);
+ if (rc < 0) {
+ pr_err("failed to set ima_rt_sts rc=%d\n", rc);
+ goto release_mem;
+ }
+ if (val & MEM_GNT_BIT)
+ break;
+ msleep(20);
+ }
+ if ((retry_count < 0) && !(val & MEM_GNT_BIT)) {
+ pr_err("failed to get memory access\n");
+ rc = -ETIMEDOUT;
+ goto release_mem;
+ }
+
+ return 0;
+ }
+
+release_mem:
+ /* Release access */
+ rc = fg_masked_write(chip, MEM_IF_MEM_INTF_CFG(chip),
+ MEM_ACCESS_REQ_BIT | IACS_SLCT_BIT, 0);
+ if (rc < 0)
+ pr_err("failed to reset mem_access bit rc = %d\n", rc);
+
+ ret = fg_masked_write(chip, MEM_IF_MEM_ARB_CFG(chip),
+ MEM_IF_ARB_REQ_BIT, 0);
+ if (ret < 0) {
+ pr_err("failed to release mem_arb bit rc=%d\n", ret);
+ return ret;
+ }
+
+ return rc;
+}
+
int fg_ima_init(struct fg_chip *chip)
{
int rc;
diff --git a/drivers/power/supply/qcom/fg-reg.h b/drivers/power/supply/qcom/fg-reg.h
index cd0b2fb4391f..906792e1ed79 100644
--- a/drivers/power/supply/qcom/fg-reg.h
+++ b/drivers/power/supply/qcom/fg-reg.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2017, 2020, 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
@@ -29,6 +29,7 @@
#define BATT_SOC_STS_CLR(chip) (chip->batt_soc_base + 0x4A)
#define BATT_SOC_LOW_PWR_CFG(chip) (chip->batt_soc_base + 0x52)
#define BATT_SOC_LOW_PWR_STS(chip) (chip->batt_soc_base + 0x56)
+#define BATT_SOC_RST_CTRL0(chip) (chip->batt_soc_base + 0xBA)
/* BATT_SOC_INT_RT_STS */
#define MSOC_EMPTY_BIT BIT(5)
@@ -39,6 +40,9 @@
/* BATT_SOC_RESTART */
#define RESTART_GO_BIT BIT(0)
+/* BCL_RESET */
+#define BCL_RESET_BIT BIT(2)
+
/* FG_BATT_INFO register definitions */
#define BATT_INFO_BATT_TEMP_STS(chip) (chip->batt_info_base + 0x06)
#define BATT_INFO_SYS_BATT(chip) (chip->batt_info_base + 0x07)
@@ -58,7 +62,6 @@
#define BATT_INFO_JEITA_COLD(chip) (chip->batt_info_base + 0x63)
#define BATT_INFO_JEITA_HOT(chip) (chip->batt_info_base + 0x64)
#define BATT_INFO_JEITA_TOO_HOT(chip) (chip->batt_info_base + 0x65)
-
/* only for v1.1 */
#define BATT_INFO_ESR_CFG(chip) (chip->batt_info_base + 0x69)
/* starting from v2.0 */
@@ -95,6 +98,8 @@
#define BATT_INFO_IADC_MSB(chip) (chip->batt_info_base + 0xAF)
#define BATT_INFO_TM_MISC(chip) (chip->batt_info_base + 0xE5)
#define BATT_INFO_TM_MISC1(chip) (chip->batt_info_base + 0xE6)
+#define BATT_INFO_PEEK_MUX1(chip) (chip->batt_info_base + 0xEB)
+#define BATT_INFO_RDBACK(chip) (chip->batt_info_base + 0xEF)
/* BATT_INFO_BATT_TEMP_STS */
#define JEITA_TOO_HOT_STS_BIT BIT(7)
@@ -264,8 +269,12 @@
#define ESR_REQ_CTL_BIT BIT(1)
#define ESR_REQ_CTL_EN_BIT BIT(0)
+/* BATT_INFO_PEEK_MUX1 */
+#define PEEK_MUX1_BIT BIT(0)
+
/* FG_MEM_IF register and bit definitions */
#define MEM_IF_INT_RT_STS(chip) ((chip->mem_if_base) + 0x10)
+#define MEM_IF_MEM_ARB_CFG(chip) ((chip->mem_if_base) + 0x40)
#define MEM_IF_MEM_INTF_CFG(chip) ((chip->mem_if_base) + 0x50)
#define MEM_IF_IMA_CTL(chip) ((chip->mem_if_base) + 0x51)
#define MEM_IF_IMA_CFG(chip) ((chip->mem_if_base) + 0x52)
@@ -286,6 +295,7 @@
/* MEM_IF_INT_RT_STS */
#define MEM_XCP_BIT BIT(1)
+#define MEM_GNT_BIT BIT(2)
/* MEM_IF_MEM_INTF_CFG */
#define MEM_ACCESS_REQ_BIT BIT(7)
@@ -326,4 +336,7 @@
/* MEM_IF_DMA_CTL */
#define DMA_CLEAR_LOG_BIT BIT(0)
+
+/* MEM_IF_REQ */
+#define MEM_IF_ARB_REQ_BIT BIT(0)
#endif
diff --git a/drivers/power/supply/qcom/fg-util.c b/drivers/power/supply/qcom/fg-util.c
index 23dd9131d402..f074ffe6c274 100644
--- a/drivers/power/supply/qcom/fg-util.c
+++ b/drivers/power/supply/qcom/fg-util.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2016-2017, 2020, 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
@@ -420,7 +420,7 @@ int fg_write(struct fg_chip *chip, int addr, u8 *val, int len)
return -ENXIO;
mutex_lock(&chip->bus_lock);
- sec_access = (addr & 0x00FF) > 0xD0;
+ sec_access = (addr & 0x00FF) >= 0xBA;
if (sec_access) {
rc = regmap_write(chip->regmap, (addr & 0xFF00) | 0xD0, 0xA5);
if (rc < 0) {
@@ -460,7 +460,7 @@ int fg_masked_write(struct fg_chip *chip, int addr, u8 mask, u8 val)
return -ENXIO;
mutex_lock(&chip->bus_lock);
- sec_access = (addr & 0x00FF) > 0xD0;
+ sec_access = (addr & 0x00FF) >= 0xBA;
if (sec_access) {
rc = regmap_write(chip->regmap, (addr & 0xFF00) | 0xD0, 0xA5);
if (rc < 0) {
diff --git a/drivers/power/supply/qcom/qpnp-fg-gen3.c b/drivers/power/supply/qcom/qpnp-fg-gen3.c
index 32fb0538cc8c..43b48d4878fd 100644
--- a/drivers/power/supply/qcom/qpnp-fg-gen3.c
+++ b/drivers/power/supply/qcom/qpnp-fg-gen3.c
@@ -3850,6 +3850,9 @@ static int fg_psy_get_property(struct power_supply *psy,
case POWER_SUPPLY_PROP_CC_STEP_SEL:
pval->intval = chip->ttf.cc_step.sel;
break;
+ case POWER_SUPPLY_PROP_FG_RESET_CLOCK:
+ pval->intval = 0;
+ break;
default:
pr_err("unsupported property %d\n", psp);
rc = -EINVAL;
@@ -3862,6 +3865,100 @@ static int fg_psy_get_property(struct power_supply *psy,
return 0;
}
+#define BCL_RESET_RETRY_COUNT 4
+static int fg_bcl_reset(struct fg_chip *chip)
+{
+ int i, ret, rc = 0;
+ u8 val, peek_mux;
+ bool success = false;
+
+ /* Read initial value of peek mux1 */
+ rc = fg_read(chip, BATT_INFO_PEEK_MUX1(chip), &peek_mux, 1);
+ if (rc < 0) {
+ pr_err("Error in writing peek mux1, rc=%d\n", rc);
+ return rc;
+ }
+
+ val = 0x83;
+ rc = fg_write(chip, BATT_INFO_PEEK_MUX1(chip), &val, 1);
+ if (rc < 0) {
+ pr_err("Error in writing peek mux1, rc=%d\n", rc);
+ return rc;
+ }
+
+ mutex_lock(&chip->sram_rw_lock);
+ for (i = 0; i < BCL_RESET_RETRY_COUNT; i++) {
+ rc = fg_dma_mem_req(chip, true);
+ if (rc < 0) {
+ pr_err("Error in locking memory, rc=%d\n", rc);
+ goto unlock;
+ }
+
+ rc = fg_read(chip, BATT_INFO_RDBACK(chip), &val, 1);
+ if (rc < 0) {
+ pr_err("Error in reading rdback, rc=%d\n", rc);
+ goto release_mem;
+ }
+
+ if (val & PEEK_MUX1_BIT) {
+ rc = fg_masked_write(chip, BATT_SOC_RST_CTRL0(chip),
+ BCL_RESET_BIT, BCL_RESET_BIT);
+ if (rc < 0) {
+ pr_err("Error in writing RST_CTRL0, rc=%d\n",
+ rc);
+ goto release_mem;
+ }
+
+ rc = fg_dma_mem_req(chip, false);
+ if (rc < 0)
+ pr_err("Error in unlocking memory, rc=%d\n",
+ rc);
+
+ /* Delay of 2ms */
+ usleep_range(2000, 3000);
+ ret = fg_masked_write(chip, BATT_SOC_RST_CTRL0(chip),
+ BCL_RESET_BIT, 0);
+ if (ret < 0)
+ pr_err("Error in writing RST_CTRL0, rc=%d\n",
+ rc);
+ if (!rc && !ret)
+ success = true;
+
+ goto unlock;
+ } else {
+ rc = fg_dma_mem_req(chip, false);
+ if (rc < 0) {
+ pr_err("Error in unlocking memory, rc=%d\n",
+ rc);
+ goto unlock;
+ }
+ success = false;
+ pr_err_ratelimited("PEEK_MUX1 not set retrying...\n");
+ msleep(1000);
+ }
+ }
+
+release_mem:
+ rc = fg_dma_mem_req(chip, false);
+ if (rc < 0)
+ pr_err("Error in unlocking memory, rc=%d\n", rc);
+
+unlock:
+ ret = fg_write(chip, BATT_INFO_PEEK_MUX1(chip), &peek_mux, 1);
+ if (ret < 0) {
+ pr_err("Error in writing peek mux1, rc=%d\n", rc);
+ mutex_unlock(&chip->sram_rw_lock);
+ return ret;
+ }
+
+ mutex_unlock(&chip->sram_rw_lock);
+
+ if (!success)
+ return -EAGAIN;
+ else
+ return rc;
+}
+
static int fg_psy_set_property(struct power_supply *psy,
enum power_supply_property psp,
const union power_supply_propval *pval)
@@ -3950,6 +4047,13 @@ static int fg_psy_set_property(struct power_supply *psy,
return rc;
}
break;
+ case POWER_SUPPLY_PROP_FG_RESET_CLOCK:
+ rc = fg_bcl_reset(chip);
+ if (rc < 0) {
+ pr_err("Error in resetting BCL clock, rc=%d\n", rc);
+ return rc;
+ }
+ break;
default:
break;
}
@@ -4047,6 +4151,7 @@ static enum power_supply_property fg_psy_props[] = {
POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
POWER_SUPPLY_PROP_CC_STEP,
POWER_SUPPLY_PROP_CC_STEP_SEL,
+ POWER_SUPPLY_PROP_FG_RESET_CLOCK,
};
static const struct power_supply_desc fg_psy_desc = {
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
index 2ebd54c98e61..4d2e20415071 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -275,6 +275,7 @@ enum power_supply_property {
POWER_SUPPLY_PROP_PARALLEL_BATFET_MODE,
POWER_SUPPLY_PROP_PARALLEL_FCC_MAX,
POWER_SUPPLY_PROP_MIN_ICL,
+ POWER_SUPPLY_PROP_FG_RESET_CLOCK,
/* Local extensions of type int64_t */
POWER_SUPPLY_PROP_CHARGE_COUNTER_EXT,
/* Properties of type `const char *' */
diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h
index 5ad57375a99f..7eb9178e3666 100644
--- a/include/uapi/linux/if_link.h
+++ b/include/uapi/linux/if_link.h
@@ -218,6 +218,7 @@ enum in6_addr_gen_mode {
IN6_ADDR_GEN_MODE_EUI64,
IN6_ADDR_GEN_MODE_NONE,
IN6_ADDR_GEN_MODE_STABLE_PRIVACY,
+ IN6_ADDR_GEN_MODE_RANDOM,
};
/* Bridge section */
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 441f6519e2e7..7061b435072b 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -2396,6 +2396,12 @@ static void manage_tempaddrs(struct inet6_dev *idev,
}
}
+static bool is_addr_mode_generate_stable(struct inet6_dev *idev)
+{
+ return idev->addr_gen_mode == IN6_ADDR_GEN_MODE_STABLE_PRIVACY ||
+ idev->addr_gen_mode == IN6_ADDR_GEN_MODE_RANDOM;
+}
+
void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len, bool sllao)
{
struct prefix_info *pinfo;
@@ -2512,8 +2518,7 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len, bool sllao)
in6_dev->token.s6_addr + 8, 8);
read_unlock_bh(&in6_dev->lock);
tokenized = true;
- } else if (in6_dev->addr_gen_mode ==
- IN6_ADDR_GEN_MODE_STABLE_PRIVACY &&
+ } else if (is_addr_mode_generate_stable(in6_dev) &&
!ipv6_generate_stable_address(&addr, 0,
in6_dev)) {
addr_flags |= IFA_F_STABLE_PRIVACY;
@@ -3113,6 +3118,17 @@ retry:
return 0;
}
+static void ipv6_gen_mode_random_init(struct inet6_dev *idev)
+{
+ struct ipv6_stable_secret *s = &idev->cnf.stable_secret;
+
+ if (s->initialized)
+ return;
+ s = &idev->cnf.stable_secret;
+ get_random_bytes(&s->secret, sizeof(s->secret));
+ s->initialized = true;
+}
+
static void addrconf_addr_gen(struct inet6_dev *idev, bool prefix_route)
{
struct in6_addr addr;
@@ -3123,13 +3139,18 @@ static void addrconf_addr_gen(struct inet6_dev *idev, bool prefix_route)
ipv6_addr_set(&addr, htonl(0xFE800000), 0, 0, 0);
- if (idev->addr_gen_mode == IN6_ADDR_GEN_MODE_STABLE_PRIVACY) {
+ switch (idev->addr_gen_mode) {
+ case IN6_ADDR_GEN_MODE_RANDOM:
+ ipv6_gen_mode_random_init(idev);
+ /* fallthrough */
+ case IN6_ADDR_GEN_MODE_STABLE_PRIVACY:
if (!ipv6_generate_stable_address(&addr, 0, idev))
addrconf_add_linklocal(idev, &addr,
IFA_F_STABLE_PRIVACY);
else if (prefix_route)
addrconf_prefix_route(&addr, 64, idev->dev, 0, 0);
- } else if (idev->addr_gen_mode == IN6_ADDR_GEN_MODE_EUI64) {
+ break;
+ case IN6_ADDR_GEN_MODE_EUI64:
/* addrconf_add_linklocal also adds a prefix_route and we
* only need to care about prefix routes if ipv6_generate_eui64
* couldn't generate one.
@@ -3138,6 +3159,11 @@ static void addrconf_addr_gen(struct inet6_dev *idev, bool prefix_route)
addrconf_add_linklocal(idev, &addr, 0);
else if (prefix_route)
addrconf_prefix_route(&addr, 64, idev->dev, 0, 0);
+ break;
+ case IN6_ADDR_GEN_MODE_NONE:
+ default:
+ /* will not add any link local address */
+ break;
}
}
@@ -3155,6 +3181,7 @@ static void addrconf_dev_config(struct net_device *dev)
(dev->type != ARPHRD_IEEE1394) &&
(dev->type != ARPHRD_TUNNEL6) &&
(dev->type != ARPHRD_6LOWPAN) &&
+ (dev->type != ARPHRD_NONE) &&
(dev->type != ARPHRD_RAWIP) &&
(dev->type != ARPHRD_INFINIBAND)) {
/* Alas, we support only Ethernet autoconfiguration. */
@@ -3165,6 +3192,11 @@ static void addrconf_dev_config(struct net_device *dev)
if (IS_ERR(idev))
return;
+ /* this device type has no EUI support */
+ if (dev->type == ARPHRD_NONE &&
+ idev->addr_gen_mode == IN6_ADDR_GEN_MODE_EUI64)
+ idev->addr_gen_mode = IN6_ADDR_GEN_MODE_RANDOM;
+
addrconf_addr_gen(idev, false);
}
@@ -5041,7 +5073,8 @@ static int inet6_set_link_af(struct net_device *dev, const struct nlattr *nla)
if (mode != IN6_ADDR_GEN_MODE_EUI64 &&
mode != IN6_ADDR_GEN_MODE_NONE &&
- mode != IN6_ADDR_GEN_MODE_STABLE_PRIVACY)
+ mode != IN6_ADDR_GEN_MODE_STABLE_PRIVACY &&
+ mode != IN6_ADDR_GEN_MODE_RANDOM)
return -EINVAL;
if (mode == IN6_ADDR_GEN_MODE_STABLE_PRIVACY &&