diff options
Diffstat (limited to 'drivers/char')
| -rw-r--r-- | drivers/char/adsprpc.c | 33 | ||||
| -rw-r--r-- | drivers/char/adsprpc_compat.c | 109 | ||||
| -rw-r--r-- | drivers/char/adsprpc_shared.h | 18 | ||||
| -rw-r--r-- | drivers/char/agp/intel-gtt.c | 2 | ||||
| -rw-r--r-- | drivers/char/diag/diag_dci.c | 47 | ||||
| -rw-r--r-- | drivers/char/diag/diag_memorydevice.c | 65 | ||||
| -rw-r--r-- | drivers/char/diag/diag_memorydevice.h | 5 | ||||
| -rw-r--r-- | drivers/char/diag/diag_mux.c | 4 | ||||
| -rw-r--r-- | drivers/char/diag/diagchar.h | 5 | ||||
| -rw-r--r-- | drivers/char/diag/diagchar_core.c | 109 | ||||
| -rw-r--r-- | drivers/char/diag/diagfwd.c | 151 | ||||
| -rw-r--r-- | drivers/char/diag/diagfwd_peripheral.c | 22 | ||||
| -rw-r--r-- | drivers/char/hw_random/exynos-rng.c | 10 | ||||
| -rw-r--r-- | drivers/char/ipmi/ipmi_ssif.c | 2 | ||||
| -rw-r--r-- | drivers/char/ipmi/ipmi_watchdog.c | 8 | ||||
| -rw-r--r-- | drivers/char/random.c | 12 | ||||
| -rw-r--r-- | drivers/char/tpm/st33zp24/st33zp24.c | 4 | ||||
| -rw-r--r-- | drivers/char/tpm/tpm-interface.c | 5 | ||||
| -rw-r--r-- | drivers/char/tpm/tpm2-cmd.c | 6 | ||||
| -rw-r--r-- | drivers/char/tpm/tpm_i2c_infineon.c | 5 | ||||
| -rw-r--r-- | drivers/char/tpm/tpm_i2c_nuvoton.c | 8 | ||||
| -rw-r--r-- | drivers/char/tpm/tpm_tis.c | 5 | ||||
| -rw-r--r-- | drivers/char/virtio_console.c | 49 |
23 files changed, 542 insertions, 142 deletions
diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c index 76594144d73e..c0787608af56 100644 --- a/drivers/char/adsprpc.c +++ b/drivers/char/adsprpc.c @@ -1188,7 +1188,10 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx) if (err) goto bail; } - if (ctx->buf->virt && metalen <= copylen) + VERIFY(err, ctx->buf->virt != NULL); + if (err) + goto bail; + if (metalen <= copylen) memset(ctx->buf->virt, 0, metalen); /* copy metadata */ @@ -1250,7 +1253,7 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx) /* copy non ion buffers */ PERF(ctx->fl->profile, ctx->fl->perf.copy, rlen = copylen - metalen; - for (oix = 0; oix < inbufs + outbufs; ++oix) { + for (oix = 0; rpra && oix < inbufs + outbufs; ++oix) { int i = ctx->overps[oix]->raix; struct fastrpc_mmap *map = ctx->maps[i]; size_t mlen; @@ -1301,7 +1304,7 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx) if (map && (map->attr & FASTRPC_ATTR_COHERENT)) continue; - if (rpra[i].buf.len && ctx->overps[oix]->mstart) { + if (rpra && rpra[i].buf.len && ctx->overps[oix]->mstart) { if (map && map->handle) msm_ion_do_cache_op(ctx->fl->apps->client, map->handle, @@ -1317,7 +1320,7 @@ static int get_args(uint32_t kernel, struct smq_invoke_ctx *ctx) PERF_END); inh = inbufs + outbufs; - for (i = 0; i < REMOTE_SCALARS_INHANDLES(sc); i++) { + for (i = 0; rpra && i < REMOTE_SCALARS_INHANDLES(sc); i++) { rpra[inh + i].buf.pv = ptr_to_uint64(ctx->lpra[inh + i].buf.pv); rpra[inh + i].buf.len = ctx->lpra[inh + i].buf.len; rpra[inh + i].h = ctx->lpra[inh + i].h; @@ -2771,6 +2774,28 @@ static long fastrpc_device_ioctl(struct file *file, unsigned int ioctl_num, if (err) goto bail; break; + case FASTRPC_IOCTL_MMAP_64: + K_COPY_FROM_USER(err, 0, &p.mmap, param, + sizeof(p.mmap)); + if (err) + goto bail; + VERIFY(err, 0 == (err = fastrpc_internal_mmap(fl, &p.mmap))); + if (err) + goto bail; + K_COPY_TO_USER(err, 0, param, &p.mmap, sizeof(p.mmap)); + if (err) + goto bail; + break; + case FASTRPC_IOCTL_MUNMAP_64: + K_COPY_FROM_USER(err, 0, &p.munmap, param, + sizeof(p.munmap)); + if (err) + goto bail; + VERIFY(err, 0 == (err = fastrpc_internal_munmap(fl, + &p.munmap))); + if (err) + goto bail; + break; case FASTRPC_IOCTL_SETMODE: switch ((uint32_t)ioctl_param) { case FASTRPC_MODE_PARALLEL: diff --git a/drivers/char/adsprpc_compat.c b/drivers/char/adsprpc_compat.c index fc6450336061..e1e061748f22 100644 --- a/drivers/char/adsprpc_compat.c +++ b/drivers/char/adsprpc_compat.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2014-2018, 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 @@ -36,6 +36,11 @@ _IOWR('R', 9, struct compat_fastrpc_ioctl_perf) #define COMPAT_FASTRPC_IOCTL_INIT_ATTRS \ _IOWR('R', 10, struct compat_fastrpc_ioctl_init_attrs) +#define COMPAT_FASTRPC_IOCTL_MMAP_64 \ + _IOWR('R', 14, struct compat_fastrpc_ioctl_mmap_64) +#define COMPAT_FASTRPC_IOCTL_MUNMAP_64 \ + _IOWR('R', 15, struct compat_fastrpc_ioctl_munmap_64) + struct compat_remote_buf { compat_uptr_t pv; /* buffer pointer */ @@ -72,11 +77,24 @@ struct compat_fastrpc_ioctl_mmap { compat_uptr_t vaddrout; /* dsps virtual address */ }; +struct compat_fastrpc_ioctl_mmap_64 { + compat_int_t fd; /* ion fd */ + compat_uint_t flags; /* flags for dsp to map with */ + compat_u64 vaddrin; /* optional virtual address */ + compat_size_t size; /* size */ + compat_u64 vaddrout; /* dsps virtual address */ +}; + struct compat_fastrpc_ioctl_munmap { compat_uptr_t vaddrout; /* address to unmap */ compat_size_t size; /* size */ }; +struct compat_fastrpc_ioctl_munmap_64 { + compat_u64 vaddrout; /* address to unmap */ + compat_size_t size; /* size */ +}; + struct compat_fastrpc_ioctl_init { compat_uint_t flags; /* one of FASTRPC_INIT_* macros */ compat_uptr_t file; /* pointer to elf file */ @@ -209,6 +227,28 @@ static int compat_get_fastrpc_ioctl_mmap( return err; } +static int compat_get_fastrpc_ioctl_mmap_64( + struct compat_fastrpc_ioctl_mmap_64 __user *map32, + struct fastrpc_ioctl_mmap __user *map) +{ + compat_uint_t u; + compat_int_t i; + compat_size_t s; + compat_u64 p; + int err; + + err = get_user(i, &map32->fd); + err |= put_user(i, &map->fd); + err |= get_user(u, &map32->flags); + err |= put_user(u, &map->flags); + err |= get_user(p, &map32->vaddrin); + err |= put_user(p, &map->vaddrin); + err |= get_user(s, &map32->size); + err |= put_user(s, &map->size); + + return err; +} + static int compat_put_fastrpc_ioctl_mmap( struct compat_fastrpc_ioctl_mmap __user *map32, struct fastrpc_ioctl_mmap __user *map) @@ -222,6 +262,19 @@ static int compat_put_fastrpc_ioctl_mmap( return err; } +static int compat_put_fastrpc_ioctl_mmap_64( + struct compat_fastrpc_ioctl_mmap_64 __user *map32, + struct fastrpc_ioctl_mmap __user *map) +{ + compat_u64 p; + int err; + + err = get_user(p, &map->vaddrout); + err |= put_user(p, &map32->vaddrout); + + return err; +} + static int compat_get_fastrpc_ioctl_munmap( struct compat_fastrpc_ioctl_munmap __user *unmap32, struct fastrpc_ioctl_munmap __user *unmap) @@ -238,6 +291,22 @@ static int compat_get_fastrpc_ioctl_munmap( return err; } +static int compat_get_fastrpc_ioctl_munmap_64( + struct compat_fastrpc_ioctl_munmap_64 __user *unmap32, + struct fastrpc_ioctl_munmap __user *unmap) +{ + compat_u64 p; + compat_size_t s; + int err; + + err = get_user(p, &unmap32->vaddrout); + err |= put_user(p, &unmap->vaddrout); + err |= get_user(s, &unmap32->size); + err |= put_user(s, &unmap->size); + + return err; +} + static int compat_get_fastrpc_ioctl_perf( struct compat_fastrpc_ioctl_perf __user *perf32, struct fastrpc_ioctl_perf __user *perf) @@ -343,6 +412,27 @@ long compat_fastrpc_device_ioctl(struct file *filp, unsigned int cmd, VERIFY(err, 0 == compat_put_fastrpc_ioctl_mmap(map32, map)); return err; } + case COMPAT_FASTRPC_IOCTL_MMAP_64: + { + struct compat_fastrpc_ioctl_mmap_64 __user *map32; + struct fastrpc_ioctl_mmap __user *map; + long ret; + + map32 = compat_ptr(arg); + VERIFY(err, NULL != (map = compat_alloc_user_space( + sizeof(*map)))); + if (err) + return -EFAULT; + VERIFY(err, 0 == compat_get_fastrpc_ioctl_mmap_64(map32, map)); + if (err) + return err; + ret = filp->f_op->unlocked_ioctl(filp, FASTRPC_IOCTL_MMAP_64, + (unsigned long)map); + if (ret) + return ret; + VERIFY(err, 0 == compat_put_fastrpc_ioctl_mmap_64(map32, map)); + return err; + } case COMPAT_FASTRPC_IOCTL_MUNMAP: { struct compat_fastrpc_ioctl_munmap __user *unmap32; @@ -360,6 +450,23 @@ long compat_fastrpc_device_ioctl(struct file *filp, unsigned int cmd, return filp->f_op->unlocked_ioctl(filp, FASTRPC_IOCTL_MUNMAP, (unsigned long)unmap); } + case COMPAT_FASTRPC_IOCTL_MUNMAP_64: + { + struct compat_fastrpc_ioctl_munmap_64 __user *unmap32; + struct fastrpc_ioctl_munmap __user *unmap; + + unmap32 = compat_ptr(arg); + VERIFY(err, NULL != (unmap = compat_alloc_user_space( + sizeof(*unmap)))); + if (err) + return -EFAULT; + VERIFY(err, 0 == compat_get_fastrpc_ioctl_munmap_64(unmap32, + unmap)); + if (err) + return err; + return filp->f_op->unlocked_ioctl(filp, FASTRPC_IOCTL_MUNMAP_64, + (unsigned long)unmap); + } case COMPAT_FASTRPC_IOCTL_INIT: /* fall through */ case COMPAT_FASTRPC_IOCTL_INIT_ATTRS: diff --git a/drivers/char/adsprpc_shared.h b/drivers/char/adsprpc_shared.h index be8d1a536d6c..a88c668440c7 100644 --- a/drivers/char/adsprpc_shared.h +++ b/drivers/char/adsprpc_shared.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. + * Copyright (c) 2012-2018, 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 @@ -19,6 +19,8 @@ #define FASTRPC_IOCTL_INVOKE _IOWR('R', 1, struct fastrpc_ioctl_invoke) #define FASTRPC_IOCTL_MMAP _IOWR('R', 2, struct fastrpc_ioctl_mmap) #define FASTRPC_IOCTL_MUNMAP _IOWR('R', 3, struct fastrpc_ioctl_munmap) +#define FASTRPC_IOCTL_MMAP_64 _IOWR('R', 14, struct fastrpc_ioctl_mmap_64) +#define FASTRPC_IOCTL_MUNMAP_64 _IOWR('R', 15, struct fastrpc_ioctl_munmap_64) #define FASTRPC_IOCTL_INVOKE_FD _IOWR('R', 4, struct fastrpc_ioctl_invoke_fd) #define FASTRPC_IOCTL_SETMODE _IOWR('R', 5, uint32_t) #define FASTRPC_IOCTL_INIT _IOWR('R', 6, struct fastrpc_ioctl_init) @@ -171,6 +173,11 @@ struct fastrpc_ioctl_munmap { size_t size; /* size */ }; +struct fastrpc_ioctl_munmap_64 { + uint64_t vaddrout; /* address to unmap */ + size_t size; /* size */ +}; + struct fastrpc_ioctl_mmap { int fd; /* ion fd */ uint32_t flags; /* flags for dsp to map with */ @@ -179,6 +186,15 @@ struct fastrpc_ioctl_mmap { uintptr_t vaddrout; /* dsps virtual address */ }; + +struct fastrpc_ioctl_mmap_64 { + int fd; /* ion fd */ + uint32_t flags; /* flags for dsp to map with */ + uint64_t vaddrin; /* optional virtual address */ + size_t size; /* size */ + uint64_t vaddrout; /* dsps virtual address */ +}; + struct fastrpc_ioctl_perf { /* kernel performance data */ uintptr_t data; uint32_t numkeys; diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index 1341a94cc779..76afc841232c 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -859,6 +859,8 @@ void intel_gtt_insert_sg_entries(struct sg_table *st, } } wmb(); + if (intel_private.driver->chipset_flush) + intel_private.driver->chipset_flush(); } EXPORT_SYMBOL(intel_gtt_insert_sg_entries); diff --git a/drivers/char/diag/diag_dci.c b/drivers/char/diag/diag_dci.c index 6b8b00809cd3..b0b36d00415d 100644 --- a/drivers/char/diag/diag_dci.c +++ b/drivers/char/diag/diag_dci.c @@ -26,6 +26,7 @@ #include <linux/reboot.h> #include <asm/current.h> #include <soc/qcom/restart.h> +#include <linux/vmalloc.h> #ifdef CONFIG_DIAG_OVER_USB #include <linux/usb/usbdiag.h> #endif @@ -258,7 +259,7 @@ static int diag_dci_init_buffer(struct diag_dci_buffer_t *buffer, int type) switch (type) { case DCI_BUF_PRIMARY: buffer->capacity = IN_BUF_SIZE; - buffer->data = kzalloc(buffer->capacity, GFP_KERNEL); + buffer->data = vzalloc(buffer->capacity); if (!buffer->data) return -ENOMEM; break; @@ -268,7 +269,7 @@ static int diag_dci_init_buffer(struct diag_dci_buffer_t *buffer, int type) break; case DCI_BUF_CMD: buffer->capacity = DIAG_MAX_REQ_SIZE + DCI_BUF_SIZE; - buffer->data = kzalloc(buffer->capacity, GFP_KERNEL); + buffer->data = vzalloc(buffer->capacity); if (!buffer->data) return -ENOMEM; break; @@ -688,7 +689,7 @@ int diag_dci_query_log_mask(struct diag_dci_client_tbl *entry, byte_mask = 0x01 << (item_num % 8); offset = equip_id * 514; - if (offset + byte_index > DCI_LOG_MASK_SIZE) { + if (offset + byte_index >= DCI_LOG_MASK_SIZE) { pr_err("diag: In %s, invalid offset: %d, log_code: %d, byte_index: %d\n", __func__, offset, log_code, byte_index); return 0; @@ -715,7 +716,7 @@ int diag_dci_query_event_mask(struct diag_dci_client_tbl *entry, bit_index = event_id % 8; byte_mask = 0x1 << bit_index; - if (byte_index > DCI_EVENT_MASK_SIZE) { + if (byte_index >= DCI_EVENT_MASK_SIZE) { pr_err("diag: In %s, invalid, event_id: %d, byte_index: %d\n", __func__, event_id, byte_index); return 0; @@ -863,7 +864,7 @@ static void dci_process_ctrl_status(unsigned char *buf, int len, int token) read_len += sizeof(struct diag_ctrl_dci_status); for (i = 0; i < header->count; i++) { - if (read_len > len) { + if (read_len > (len - 2)) { pr_err("diag: In %s, Invalid length len: %d\n", __func__, len); return; @@ -2719,7 +2720,7 @@ static int diag_dci_init_remote(void) create_dci_event_mask_tbl(temp->event_mask_composite); } - partial_pkt.data = kzalloc(MAX_DCI_PACKET_SZ, GFP_KERNEL); + partial_pkt.data = vzalloc(MAX_DCI_PACKET_SZ); if (!partial_pkt.data) { pr_err("diag: Unable to create partial pkt data\n"); return -ENOMEM; @@ -2775,7 +2776,7 @@ int diag_dci_init(void) goto err; if (driver->apps_dci_buf == NULL) { - driver->apps_dci_buf = kzalloc(DCI_BUF_SIZE, GFP_KERNEL); + driver->apps_dci_buf = vzalloc(DCI_BUF_SIZE); if (driver->apps_dci_buf == NULL) goto err; } @@ -2792,12 +2793,12 @@ int diag_dci_init(void) return DIAG_DCI_NO_ERROR; err: pr_err("diag: Could not initialize diag DCI buffers"); - kfree(driver->apps_dci_buf); + vfree(driver->apps_dci_buf); driver->apps_dci_buf = NULL; if (driver->diag_dci_wq) destroy_workqueue(driver->diag_dci_wq); - kfree(partial_pkt.data); + vfree(partial_pkt.data); partial_pkt.data = NULL; mutex_destroy(&driver->dci_mutex); mutex_destroy(&dci_log_mask_mutex); @@ -2817,9 +2818,9 @@ void diag_dci_channel_init(void) void diag_dci_exit(void) { - kfree(partial_pkt.data); + vfree(partial_pkt.data); partial_pkt.data = NULL; - kfree(driver->apps_dci_buf); + vfree(driver->apps_dci_buf); driver->apps_dci_buf = NULL; mutex_destroy(&driver->dci_mutex); mutex_destroy(&dci_log_mask_mutex); @@ -2959,7 +2960,7 @@ int diag_dci_register_client(struct diag_dci_reg_tbl_t *reg_entry) new_entry->in_service = 0; INIT_LIST_HEAD(&new_entry->list_write_buf); mutex_init(&new_entry->write_buf_mutex); - new_entry->dci_log_mask = kzalloc(DCI_LOG_MASK_SIZE, GFP_KERNEL); + new_entry->dci_log_mask = vzalloc(DCI_LOG_MASK_SIZE); if (!new_entry->dci_log_mask) { pr_err("diag: Unable to create log mask for client, %d", driver->dci_client_id); @@ -2967,7 +2968,7 @@ int diag_dci_register_client(struct diag_dci_reg_tbl_t *reg_entry) } create_dci_log_mask_tbl(new_entry->dci_log_mask, DCI_LOG_MASK_CLEAN); - new_entry->dci_event_mask = kzalloc(DCI_EVENT_MASK_SIZE, GFP_KERNEL); + new_entry->dci_event_mask = vzalloc(DCI_EVENT_MASK_SIZE); if (!new_entry->dci_event_mask) { pr_err("diag: Unable to create event mask for client, %d", driver->dci_client_id); @@ -2977,7 +2978,7 @@ int diag_dci_register_client(struct diag_dci_reg_tbl_t *reg_entry) new_entry->buffers = kzalloc(new_entry->num_buffers * sizeof(struct diag_dci_buf_peripheral_t), - GFP_KERNEL); + GFP_KERNEL); if (!new_entry->buffers) { pr_err("diag: Unable to allocate buffers for peripherals in %s\n", __func__); @@ -3001,7 +3002,7 @@ int diag_dci_register_client(struct diag_dci_reg_tbl_t *reg_entry) if (!proc_buf->buf_primary) goto fail_alloc; proc_buf->buf_cmd = kzalloc(sizeof(struct diag_dci_buffer_t), - GFP_KERNEL); + GFP_KERNEL); if (!proc_buf->buf_cmd) goto fail_alloc; err = diag_dci_init_buffer(proc_buf->buf_primary, @@ -3034,7 +3035,7 @@ fail_alloc: if (proc_buf) { mutex_destroy(&proc_buf->health_mutex); if (proc_buf->buf_primary) { - kfree(proc_buf->buf_primary->data); + vfree(proc_buf->buf_primary->data); proc_buf->buf_primary->data = NULL; mutex_destroy( &proc_buf->buf_primary->data_mutex); @@ -3042,7 +3043,7 @@ fail_alloc: kfree(proc_buf->buf_primary); proc_buf->buf_primary = NULL; if (proc_buf->buf_cmd) { - kfree(proc_buf->buf_cmd->data); + vfree(proc_buf->buf_cmd->data); proc_buf->buf_cmd->data = NULL; mutex_destroy( &proc_buf->buf_cmd->data_mutex); @@ -3051,9 +3052,9 @@ fail_alloc: proc_buf->buf_cmd = NULL; } } - kfree(new_entry->dci_event_mask); + vfree(new_entry->dci_event_mask); new_entry->dci_event_mask = NULL; - kfree(new_entry->dci_log_mask); + vfree(new_entry->dci_log_mask); new_entry->dci_log_mask = NULL; kfree(new_entry->buffers); new_entry->buffers = NULL; @@ -3088,7 +3089,7 @@ int diag_dci_deinit_client(struct diag_dci_client_tbl *entry) * Clear the client's log and event masks, update the cumulative * masks and send the masks to peripherals */ - kfree(entry->dci_log_mask); + vfree(entry->dci_log_mask); entry->dci_log_mask = NULL; diag_dci_invalidate_cumulative_log_mask(token); if (token == DCI_LOCAL_PROC) @@ -3097,7 +3098,7 @@ int diag_dci_deinit_client(struct diag_dci_client_tbl *entry) if (ret != DIAG_DCI_NO_ERROR) { return ret; } - kfree(entry->dci_event_mask); + vfree(entry->dci_event_mask); entry->dci_event_mask = NULL; diag_dci_invalidate_cumulative_event_mask(token); if (token == DCI_LOCAL_PROC) @@ -3161,12 +3162,12 @@ int diag_dci_deinit_client(struct diag_dci_client_tbl *entry) } mutex_lock(&proc_buf->buf_primary->data_mutex); - kfree(proc_buf->buf_primary->data); + vfree(proc_buf->buf_primary->data); proc_buf->buf_primary->data = NULL; mutex_unlock(&proc_buf->buf_primary->data_mutex); mutex_lock(&proc_buf->buf_cmd->data_mutex); - kfree(proc_buf->buf_cmd->data); + vfree(proc_buf->buf_cmd->data); proc_buf->buf_cmd->data = NULL; mutex_unlock(&proc_buf->buf_cmd->data_mutex); diff --git a/drivers/char/diag/diag_memorydevice.c b/drivers/char/diag/diag_memorydevice.c index a752cdc675a3..aa45c2e7ec7b 100644 --- a/drivers/char/diag/diag_memorydevice.c +++ b/drivers/char/diag/diag_memorydevice.c @@ -37,6 +37,7 @@ struct diag_md_info diag_md[NUM_DIAG_MD_DEV] = { .ctx = 0, .mempool = POOL_TYPE_MUX_APPS, .num_tbl_entries = 0, + .md_info_inited = 0, .tbl = NULL, .ops = NULL, }, @@ -46,6 +47,7 @@ struct diag_md_info diag_md[NUM_DIAG_MD_DEV] = { .ctx = 0, .mempool = POOL_TYPE_MDM_MUX, .num_tbl_entries = 0, + .md_info_inited = 0, .tbl = NULL, .ops = NULL, }, @@ -54,6 +56,7 @@ struct diag_md_info diag_md[NUM_DIAG_MD_DEV] = { .ctx = 0, .mempool = POOL_TYPE_MDM2_MUX, .num_tbl_entries = 0, + .md_info_inited = 0, .tbl = NULL, .ops = NULL, }, @@ -62,6 +65,7 @@ struct diag_md_info diag_md[NUM_DIAG_MD_DEV] = { .ctx = 0, .mempool = POOL_TYPE_QSC_MUX, .num_tbl_entries = 0, + .md_info_inited = 0, .tbl = NULL, .ops = NULL, } @@ -85,6 +89,8 @@ void diag_md_open_all() for (i = 0; i < NUM_DIAG_MD_DEV; i++) { ch = &diag_md[i]; + if (!ch->md_info_inited) + continue; if (ch->ops && ch->ops->open) ch->ops->open(ch->ctx, DIAG_MEMORY_DEVICE_MODE); } @@ -101,6 +107,8 @@ void diag_md_close_all() for (i = 0; i < NUM_DIAG_MD_DEV; i++) { ch = &diag_md[i]; + if (!ch->md_info_inited) + continue; if (ch->ops && ch->ops->close) ch->ops->close(ch->ctx, DIAG_MEMORY_DEVICE_MODE); @@ -159,7 +167,7 @@ int diag_md_write(int id, unsigned char *buf, int len, int ctx) mutex_unlock(&driver->md_session_lock); ch = &diag_md[id]; - if (!ch) + if (!ch || !ch->md_info_inited) return -EINVAL; spin_lock_irqsave(&ch->lock, flags); @@ -236,6 +244,8 @@ int diag_md_copy_to_user(char __user *buf, int *pret, size_t buf_size, for (i = 0; i < NUM_DIAG_MD_DEV && !err; i++) { ch = &diag_md[i]; + if (!ch->md_info_inited) + continue; for (j = 0; j < ch->num_tbl_entries && !err; j++) { entry = &ch->tbl[j]; if (entry->len <= 0 || entry->buf == NULL) @@ -358,6 +368,8 @@ int diag_md_close_peripheral(int id, uint8_t peripheral) return -EINVAL; ch = &diag_md[id]; + if (!ch || !ch->md_info_inited) + return -EINVAL; spin_lock_irqsave(&ch->lock, flags); for (i = 0; i < ch->num_tbl_entries && !found; i++) { @@ -385,12 +397,12 @@ int diag_md_close_peripheral(int id, uint8_t peripheral) return 0; } -int diag_md_init() +int diag_md_init(void) { int i, j; struct diag_md_info *ch = NULL; - for (i = 0; i < NUM_DIAG_MD_DEV; i++) { + for (i = 0; i < DIAG_MD_LOCAL_LAST; i++) { ch = &diag_md[i]; ch->num_tbl_entries = diag_mempools[ch->mempool].poolsize; ch->tbl = kzalloc(ch->num_tbl_entries * @@ -405,6 +417,7 @@ int diag_md_init() ch->tbl[j].ctx = 0; } spin_lock_init(&(ch->lock)); + ch->md_info_inited = 1; } return 0; @@ -414,12 +427,54 @@ fail: return -ENOMEM; } -void diag_md_exit() +int diag_md_mdm_init(void) +{ + int i, j; + struct diag_md_info *ch = NULL; + + for (i = DIAG_MD_BRIDGE_BASE; i < NUM_DIAG_MD_DEV; i++) { + ch = &diag_md[i]; + ch->num_tbl_entries = diag_mempools[ch->mempool].poolsize; + ch->tbl = kcalloc(ch->num_tbl_entries, sizeof(*ch->tbl), + GFP_KERNEL); + if (!ch->tbl) + goto fail; + + for (j = 0; j < ch->num_tbl_entries; j++) { + ch->tbl[j].buf = NULL; + ch->tbl[j].len = 0; + ch->tbl[j].ctx = 0; + } + spin_lock_init(&(ch->lock)); + ch->md_info_inited = 1; + } + + return 0; + +fail: + diag_md_mdm_exit(); + return -ENOMEM; +} + +void diag_md_exit(void) { int i; struct diag_md_info *ch = NULL; - for (i = 0; i < NUM_DIAG_MD_DEV; i++) { + for (i = 0; i < DIAG_MD_LOCAL_LAST; i++) { + ch = &diag_md[i]; + kfree(ch->tbl); + ch->num_tbl_entries = 0; + ch->ops = NULL; + } +} + +void diag_md_mdm_exit(void) +{ + int i; + struct diag_md_info *ch = NULL; + + for (i = DIAG_MD_BRIDGE_BASE; i < NUM_DIAG_MD_DEV; i++) { ch = &diag_md[i]; kfree(ch->tbl); ch->num_tbl_entries = 0; diff --git a/drivers/char/diag/diag_memorydevice.h b/drivers/char/diag/diag_memorydevice.h index 35a1ee35a956..4d65dedfdb58 100644 --- a/drivers/char/diag/diag_memorydevice.h +++ b/drivers/char/diag/diag_memorydevice.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2015, 2018 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 @@ -38,6 +38,7 @@ struct diag_md_info { int ctx; int mempool; int num_tbl_entries; + int md_info_inited; spinlock_t lock; struct diag_buf_tbl_t *tbl; struct diag_mux_ops *ops; @@ -46,7 +47,9 @@ struct diag_md_info { extern struct diag_md_info diag_md[NUM_DIAG_MD_DEV]; int diag_md_init(void); +int diag_md_mdm_init(void); void diag_md_exit(void); +void diag_md_mdm_exit(void); void diag_md_open_all(void); void diag_md_close_all(void); int diag_md_register(int id, int ctx, struct diag_mux_ops *ops); diff --git a/drivers/char/diag/diag_mux.c b/drivers/char/diag/diag_mux.c index 8cc803eef552..8d766e1ae583 100644 --- a/drivers/char/diag/diag_mux.c +++ b/drivers/char/diag/diag_mux.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2018, 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 @@ -239,6 +239,8 @@ int diag_mux_switch_logging(int *req_mode, int *peripheral_mask) new_mask = ~(*peripheral_mask) & diag_mux->mux_mask; if (new_mask != DIAG_CON_NONE) *req_mode = DIAG_MULTI_MODE; + if (new_mask == DIAG_CON_ALL) + *req_mode = DIAG_MEMORY_DEVICE_MODE; break; case DIAG_MEMORY_DEVICE_MODE: new_mask = (*peripheral_mask) | diag_mux->mux_mask; diff --git a/drivers/char/diag/diagchar.h b/drivers/char/diag/diagchar.h index 75080f0d4c39..afea5f40bfee 100644 --- a/drivers/char/diag/diagchar.h +++ b/drivers/char/diag/diagchar.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2008-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2008-2018, 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 @@ -580,6 +580,7 @@ struct diagchar_dev { /* buffer for updating mask to peripherals */ unsigned char *buf_feature_mask_update; uint8_t hdlc_disabled; + uint8_t p_hdlc_disabled[NUM_MD_SESSIONS]; struct mutex hdlc_disable_mutex; struct mutex hdlc_recovery_mutex; struct timer_list hdlc_reset_timer; @@ -604,6 +605,7 @@ struct diagchar_dev { struct work_struct diag_drain_work; struct work_struct update_user_clients; struct work_struct update_md_clients; + struct work_struct diag_hdlc_reset_work; struct workqueue_struct *diag_cntl_wq; uint8_t log_on_demand_support; uint8_t *apps_req_buf; @@ -683,5 +685,6 @@ void diag_record_stats(int type, int flag); struct diag_md_session_t *diag_md_session_get_pid(int pid); struct diag_md_session_t *diag_md_session_get_peripheral(uint8_t peripheral); +int diag_md_session_match_pid_peripheral(int pid, uint8_t peripheral); #endif diff --git a/drivers/char/diag/diagchar_core.c b/drivers/char/diag/diagchar_core.c index 678e3a2b051c..6df597dfa750 100644 --- a/drivers/char/diag/diagchar_core.c +++ b/drivers/char/diag/diagchar_core.c @@ -252,18 +252,13 @@ static void diag_update_md_client_work_fn(struct work_struct *work) void diag_drain_work_fn(struct work_struct *work) { - struct diag_md_session_t *session_info = NULL; uint8_t hdlc_disabled = 0; timer_in_progress = 0; mutex_lock(&apps_data_mutex); - mutex_lock(&driver->md_session_lock); - session_info = diag_md_session_get_peripheral(APPS_DATA); - if (session_info) - hdlc_disabled = session_info->hdlc_disabled; - else - hdlc_disabled = driver->hdlc_disabled; - mutex_unlock(&driver->md_session_lock); + mutex_lock(&driver->hdlc_disable_mutex); + hdlc_disabled = driver->p_hdlc_disabled[APPS_DATA]; + mutex_unlock(&driver->hdlc_disable_mutex); if (!hdlc_disabled) diag_drain_apps_data(&hdlc_data); else @@ -389,8 +384,8 @@ static int diagchar_open(struct inode *inode, struct file *file) return -ENOMEM; fail: - mutex_unlock(&driver->diagchar_mutex); driver->num_clients--; + mutex_unlock(&driver->diagchar_mutex); pr_err_ratelimited("diag: Insufficient memory for new client"); return -ENOMEM; } @@ -1006,6 +1001,7 @@ static int diag_remote_init(void) poolsize_mdm_dci_write); diagmem_setsize(POOL_TYPE_QSC_MUX, itemsize_qsc_usb, poolsize_qsc_usb); + diag_md_mdm_init(); driver->hdlc_encode_buf = kzalloc(DIAG_MAX_HDLC_BUF_SIZE, GFP_KERNEL); if (!driver->hdlc_encode_buf) return -ENOMEM; @@ -1029,7 +1025,6 @@ static int diag_send_raw_data_remote(int proc, void *buf, int len, struct diag_send_desc_type send = { NULL, NULL, DIAG_STATE_START, 0 }; struct diag_hdlc_dest_type enc = { NULL, NULL, 0 }; int bridge_index = proc - 1; - struct diag_md_session_t *session_info = NULL; uint8_t hdlc_disabled = 0; if (!buf) @@ -1055,13 +1050,9 @@ static int diag_send_raw_data_remote(int proc, void *buf, int len, if (driver->hdlc_encode_buf_len != 0) return -EAGAIN; - mutex_lock(&driver->md_session_lock); - session_info = diag_md_session_get_peripheral(APPS_DATA); - if (session_info) - hdlc_disabled = session_info->hdlc_disabled; - else - hdlc_disabled = driver->hdlc_disabled; - mutex_unlock(&driver->md_session_lock); + mutex_lock(&driver->hdlc_disable_mutex); + hdlc_disabled = driver->p_hdlc_disabled[APPS_DATA]; + mutex_unlock(&driver->hdlc_disable_mutex); if (hdlc_disabled) { if (len < 4) { pr_err("diag: In %s, invalid len: %d of non_hdlc pkt", @@ -1483,6 +1474,43 @@ struct diag_md_session_t *diag_md_session_get_peripheral(uint8_t peripheral) return driver->md_session_map[peripheral]; } +/* + * diag_md_session_match_pid_peripheral + * + * 1. Pass valid PID and get all the peripherals in logging session + * for that PID + * 2. Pass valid Peipheral and get the pid logging for that peripheral + * + */ + +int diag_md_session_match_pid_peripheral(int pid, + uint8_t peripheral) +{ + int i, flag = 0; + + if (pid <= 0 || peripheral >= NUM_MD_SESSIONS) + return -EINVAL; + + if (!peripheral) { + for (i = 0; i < NUM_MD_SESSIONS; i++) { + if (driver->md_session_map[i] && + driver->md_session_map[i]->pid == pid) { + peripheral |= 1 << i; + flag = 1; + } + } + if (flag) + return peripheral; + } + + if (!pid) { + if (driver->md_session_map[peripheral]) + return driver->md_session_map[peripheral]->pid; + } + + return -EINVAL; +} + static int diag_md_peripheral_switch(int pid, int peripheral_mask, int req_mode) { int i, bit = 0; @@ -1637,6 +1665,13 @@ static int diag_md_session_check(int curr_mode, int req_mode, } err = diag_md_session_create(DIAG_MD_PERIPHERAL, param->peripheral_mask, DIAG_LOCAL_PROC); + mutex_lock(&driver->hdlc_disable_mutex); + for (i = 0; i < NUM_MD_SESSIONS; i++) { + if ((param->peripheral_mask > 0) && + (param->peripheral_mask & (1 << i))) + driver->p_hdlc_disabled[i] = 0; + } + mutex_unlock(&driver->hdlc_disable_mutex); } *change_mode = 1; return err; @@ -1710,19 +1745,20 @@ static int diag_switch_logging(struct diag_logging_mode_param_t *param) return -EINVAL; } + i = upd - UPD_WLAN; + if (driver->md_session_map[peripheral] && (MD_PERIPHERAL_MASK(peripheral) & - diag_mux->mux_mask)) { + diag_mux->mux_mask) && + !driver->pd_session_clear[i]) { DIAG_LOG(DIAG_DEBUG_USERSPACE, "diag_fr: User PD is already logging onto active peripheral logging\n"); - i = upd - UPD_WLAN; driver->pd_session_clear[i] = 0; return -EINVAL; } peripheral_mask = diag_translate_mask(param->pd_mask); param->peripheral_mask = peripheral_mask; - i = upd - UPD_WLAN; if (!driver->pd_session_clear[i]) { driver->pd_logging_mode[i] = 1; driver->num_pd_session += 1; @@ -2084,11 +2120,14 @@ static int diag_ioctl_dci_support(unsigned long ioarg) static int diag_ioctl_hdlc_toggle(unsigned long ioarg) { - uint8_t hdlc_support; + uint8_t hdlc_support, i; + int peripheral = -EINVAL; struct diag_md_session_t *session_info = NULL; + if (copy_from_user(&hdlc_support, (void __user *)ioarg, sizeof(uint8_t))) return -EFAULT; + mutex_lock(&driver->hdlc_disable_mutex); mutex_lock(&driver->md_session_lock); session_info = diag_md_session_get_pid(current->tgid); @@ -2096,6 +2135,25 @@ static int diag_ioctl_hdlc_toggle(unsigned long ioarg) session_info->hdlc_disabled = hdlc_support; else driver->hdlc_disabled = hdlc_support; + + peripheral = + diag_md_session_match_pid_peripheral(current->tgid, + 0); + for (i = 0; i < NUM_MD_SESSIONS; i++) { + if (peripheral > 0 && session_info) { + if (peripheral & (1 << i)) + driver->p_hdlc_disabled[i] = + session_info->hdlc_disabled; + else if (!diag_md_session_get_peripheral(i)) + driver->p_hdlc_disabled[i] = + driver->hdlc_disabled; + } else { + if (!diag_md_session_get_peripheral(i)) + driver->p_hdlc_disabled[i] = + driver->hdlc_disabled; + } + } + mutex_unlock(&driver->md_session_lock); mutex_unlock(&driver->hdlc_disable_mutex); diag_update_md_clients(HDLC_SUPPORT_TYPE); @@ -2969,7 +3027,6 @@ static int diag_user_process_apps_data(const char __user *buf, int len, int stm_size = 0; const int mempool = POOL_TYPE_COPY; unsigned char *user_space_data = NULL; - struct diag_md_session_t *session_info = NULL; uint8_t hdlc_disabled; if (!buf || len <= 0 || len > DIAG_MAX_RSP_SIZE) { @@ -3023,13 +3080,7 @@ static int diag_user_process_apps_data(const char __user *buf, int len, mutex_lock(&apps_data_mutex); mutex_lock(&driver->hdlc_disable_mutex); - mutex_lock(&driver->md_session_lock); - session_info = diag_md_session_get_peripheral(APPS_DATA); - if (session_info) - hdlc_disabled = session_info->hdlc_disabled; - else - hdlc_disabled = driver->hdlc_disabled; - mutex_unlock(&driver->md_session_lock); + hdlc_disabled = driver->p_hdlc_disabled[APPS_DATA]; if (hdlc_disabled) ret = diag_process_apps_data_non_hdlc(user_space_data, len, pkt_type); diff --git a/drivers/char/diag/diagfwd.c b/drivers/char/diag/diagfwd.c index f876489e202d..c7b46304dc84 100644 --- a/drivers/char/diag/diagfwd.c +++ b/drivers/char/diag/diagfwd.c @@ -49,6 +49,11 @@ #define STM_RSP_STATUS_INDEX 8 #define STM_RSP_NUM_BYTES 9 +struct diag_md_hdlc_reset_work { + int pid; + struct work_struct work; +}; + static int timestamp_switch; module_param(timestamp_switch, int, 0644); @@ -436,6 +441,7 @@ static void diag_send_rsp(unsigned char *buf, int len, int pid) { struct diag_md_session_t *session_info = NULL, *info = NULL; uint8_t hdlc_disabled; + mutex_lock(&driver->md_session_lock); info = diag_md_session_get_pid(pid); session_info = (info) ? info : @@ -445,6 +451,7 @@ static void diag_send_rsp(unsigned char *buf, int len, int pid) else hdlc_disabled = driver->hdlc_disabled; mutex_unlock(&driver->md_session_lock); + if (hdlc_disabled) pack_rsp_and_send(buf, len, pid); else @@ -948,7 +955,7 @@ void diag_send_error_rsp(unsigned char *buf, int len, int diag_process_apps_pkt(unsigned char *buf, int len, int pid) { int i, p_mask = 0; - int mask_ret; + int mask_ret, peripheral = -EINVAL; int write_len = 0; unsigned char *temp = NULL; struct diag_cmd_reg_entry_t entry; @@ -1003,8 +1010,11 @@ int diag_process_apps_pkt(unsigned char *buf, int len, int pid) } else { mutex_unlock(&driver->md_session_lock); if (MD_PERIPHERAL_MASK(reg_item->proc) & - driver->logging_mask) + driver->logging_mask) { + mutex_unlock(&driver->cmd_reg_mutex); diag_send_error_rsp(buf, len, pid); + return write_len; + } else write_len = diag_send_data(reg_item, buf, len); } @@ -1172,6 +1182,22 @@ int diag_process_apps_pkt(unsigned char *buf, int len, int pid) info->hdlc_disabled = 1; else driver->hdlc_disabled = 1; + peripheral = + diag_md_session_match_pid_peripheral(pid, 0); + for (i = 0; i < NUM_MD_SESSIONS; i++) { + if (peripheral > 0 && info) { + if (peripheral & (1 << i)) + driver->p_hdlc_disabled[i] = + info->hdlc_disabled; + else if (!diag_md_session_get_peripheral(i)) + driver->p_hdlc_disabled[i] = + driver->hdlc_disabled; + } else { + if (!diag_md_session_get_peripheral(i)) + driver->p_hdlc_disabled[i] = + driver->hdlc_disabled; + } + } mutex_unlock(&driver->md_session_lock); diag_update_md_clients(HDLC_SUPPORT_TYPE); mutex_unlock(&driver->hdlc_disable_mutex); @@ -1347,8 +1373,17 @@ static int diagfwd_mux_close(int id, int mode) pr_debug("diag: In %s, re-enabling HDLC encoding\n", __func__); mutex_lock(&driver->hdlc_disable_mutex); - if (driver->md_session_mode == DIAG_MD_NONE) + if (driver->md_session_mode == DIAG_MD_NONE) { driver->hdlc_disabled = 0; + /* + * HDLC encoding is re-enabled when + * there is logical/physical disconnection of diag + * to USB. + */ + for (i = 0; i < NUM_MD_SESSIONS; i++) + driver->p_hdlc_disabled[i] = + driver->hdlc_disabled; + } mutex_unlock(&driver->hdlc_disable_mutex); queue_work(driver->diag_wq, &(driver->update_user_clients)); @@ -1363,6 +1398,7 @@ static uint8_t hdlc_reset; static void hdlc_reset_timer_start(int pid) { struct diag_md_session_t *info = NULL; + mutex_lock(&driver->md_session_lock); info = diag_md_session_get_pid(pid); if (!hdlc_timer_in_progress) { @@ -1377,30 +1413,99 @@ static void hdlc_reset_timer_start(int pid) mutex_unlock(&driver->md_session_lock); } +/* + * diag_timer_work_fn + * Queued in workqueue to protect md_session_info structure + * + * Update hdlc_disabled for each peripheral + * which are not in any md_session_info. + * + */ +static void diag_timer_work_fn(struct work_struct *work) +{ + int i = 0; + struct diag_md_session_t *session_info = NULL; + + mutex_lock(&driver->hdlc_disable_mutex); + driver->hdlc_disabled = 0; + mutex_lock(&driver->md_session_lock); + for (i = 0; i < NUM_MD_SESSIONS; i++) { + session_info = diag_md_session_get_peripheral(i); + if (!session_info) + driver->p_hdlc_disabled[i] = + driver->hdlc_disabled; + } + mutex_unlock(&driver->md_session_lock); + mutex_unlock(&driver->hdlc_disable_mutex); +} + +/* + * diag_md_timer_work_fn + * Queued in workqueue to protect md_session_info structure + * + * Update hdlc_disabled for each peripheral + * which are in any md_session_info + * + */ +static void diag_md_timer_work_fn(struct work_struct *work) +{ + int peripheral = -EINVAL, i = 0; + struct diag_md_session_t *session_info = NULL; + struct diag_md_hdlc_reset_work *hdlc_work = container_of(work, + struct diag_md_hdlc_reset_work, work); + + if (!hdlc_work) + return; + + mutex_lock(&driver->hdlc_disable_mutex); + mutex_lock(&driver->md_session_lock); + session_info = diag_md_session_get_pid(hdlc_work->pid); + if (session_info) + session_info->hdlc_disabled = 0; + peripheral = + diag_md_session_match_pid_peripheral(hdlc_work->pid, 0); + if (peripheral > 0 && session_info) { + for (i = 0; i < NUM_MD_SESSIONS; i++) { + if (peripheral & (1 << i)) + driver->p_hdlc_disabled[i] = + session_info->hdlc_disabled; + } + } + kfree(hdlc_work); + mutex_unlock(&driver->md_session_lock); + mutex_unlock(&driver->hdlc_disable_mutex); +} + static void hdlc_reset_timer_func(unsigned long data) { pr_debug("diag: In %s, re-enabling HDLC encoding\n", __func__); + if (hdlc_reset) { - driver->hdlc_disabled = 0; - queue_work(driver->diag_wq, - &(driver->update_user_clients)); + queue_work(driver->diag_wq, &(driver->diag_hdlc_reset_work)); + queue_work(driver->diag_wq, &(driver->update_user_clients)); } hdlc_timer_in_progress = 0; } void diag_md_hdlc_reset_timer_func(unsigned long pid) { - struct diag_md_session_t *session_info = NULL; + struct diag_md_hdlc_reset_work *hdlc_reset_work = NULL; pr_debug("diag: In %s, re-enabling HDLC encoding\n", __func__); + hdlc_reset_work = kmalloc(sizeof(*hdlc_reset_work), GFP_ATOMIC); + if (!hdlc_reset_work) { + DIAG_LOG(DIAG_DEBUG_PERIPHERALS, + "diag: Could not allocate hdlc_reset_work\n"); + hdlc_timer_in_progress = 0; + return; + } if (hdlc_reset) { - session_info = diag_md_session_get_pid(pid); - if (session_info) - session_info->hdlc_disabled = 0; - queue_work(driver->diag_wq, - &(driver->update_md_clients)); + hdlc_reset_work->pid = pid; + INIT_WORK(&hdlc_reset_work->work, diag_md_timer_work_fn); + queue_work(driver->diag_wq, &(hdlc_reset_work->work)); + queue_work(driver->diag_wq, &(driver->update_md_clients)); } hdlc_timer_in_progress = 0; } @@ -1408,7 +1513,7 @@ void diag_md_hdlc_reset_timer_func(unsigned long pid) static void diag_hdlc_start_recovery(unsigned char *buf, int len, int pid) { - int i; + int i, peripheral = -EINVAL; static uint32_t bad_byte_counter; unsigned char *start_ptr = NULL; struct diag_pkt_frame_t *actual_pkt = NULL; @@ -1440,6 +1545,24 @@ static void diag_hdlc_start_recovery(unsigned char *buf, int len, info->hdlc_disabled = 0; else driver->hdlc_disabled = 0; + + peripheral = + diag_md_session_match_pid_peripheral(pid, 0); + for (i = 0; i < NUM_MD_SESSIONS; i++) { + if (peripheral > 0 && info) { + if (peripheral & (1 << i)) + driver->p_hdlc_disabled[i] = + info->hdlc_disabled; + else if ( + !diag_md_session_get_peripheral(i)) + driver->p_hdlc_disabled[i] = + driver->hdlc_disabled; + } else { + if (!diag_md_session_get_peripheral(i)) + driver->p_hdlc_disabled[i] = + driver->hdlc_disabled; + } + } mutex_unlock(&driver->md_session_lock); mutex_unlock(&driver->hdlc_disable_mutex); diag_update_md_clients(HDLC_SUPPORT_TYPE); @@ -1697,6 +1820,8 @@ int diagfwd_init(void) INIT_LIST_HEAD(&driver->cmd_reg_list); driver->cmd_reg_count = 0; mutex_init(&driver->cmd_reg_mutex); + INIT_WORK(&(driver->diag_hdlc_reset_work), + diag_timer_work_fn); for (i = 0; i < NUM_PERIPHERALS; i++) { driver->feature[i].separate_cmd_rsp = 0; diff --git a/drivers/char/diag/diagfwd_peripheral.c b/drivers/char/diag/diagfwd_peripheral.c index a7abe3dafb69..6b74c0056d1b 100644 --- a/drivers/char/diag/diagfwd_peripheral.c +++ b/drivers/char/diag/diagfwd_peripheral.c @@ -284,7 +284,6 @@ static void diagfwd_data_process_done(struct diagfwd_info *fwd_info, int err = 0; int write_len = 0, peripheral = 0; unsigned char *write_buf = NULL; - struct diag_md_session_t *session_info = NULL; uint8_t hdlc_disabled = 0; if (!fwd_info || !buf || len <= 0) { @@ -316,13 +315,9 @@ static void diagfwd_data_process_done(struct diagfwd_info *fwd_info, diag_ws_release(); return; } - mutex_lock(&driver->md_session_lock); - session_info = diag_md_session_get_peripheral(peripheral); - if (session_info) - hdlc_disabled = session_info->hdlc_disabled; - else - hdlc_disabled = driver->hdlc_disabled; - mutex_unlock(&driver->md_session_lock); + + hdlc_disabled = driver->p_hdlc_disabled[peripheral]; + if (hdlc_disabled) { /* The data is raw and and on APPS side HDLC is disabled */ if (!buf) { @@ -615,7 +610,6 @@ static void diagfwd_data_read_done(struct diagfwd_info *fwd_info, int write_len = 0; unsigned char *write_buf = NULL; struct diagfwd_buf_t *temp_buf = NULL; - struct diag_md_session_t *session_info = NULL; uint8_t hdlc_disabled = 0; if (!fwd_info || !buf || len <= 0) { @@ -637,13 +631,9 @@ static void diagfwd_data_read_done(struct diagfwd_info *fwd_info, mutex_lock(&driver->hdlc_disable_mutex); mutex_lock(&fwd_info->data_mutex); - mutex_lock(&driver->md_session_lock); - session_info = diag_md_session_get_peripheral(fwd_info->peripheral); - if (session_info) - hdlc_disabled = session_info->hdlc_disabled; - else - hdlc_disabled = driver->hdlc_disabled; - mutex_unlock(&driver->md_session_lock); + + hdlc_disabled = driver->p_hdlc_disabled[fwd_info->peripheral]; + if (!driver->feature[fwd_info->peripheral].encode_hdlc) { if (fwd_info->buf_1 && fwd_info->buf_1->data == buf) { temp_buf = fwd_info->buf_1; diff --git a/drivers/char/hw_random/exynos-rng.c b/drivers/char/hw_random/exynos-rng.c index 7845a38b6604..7ba0ae060d61 100644 --- a/drivers/char/hw_random/exynos-rng.c +++ b/drivers/char/hw_random/exynos-rng.c @@ -155,8 +155,7 @@ static int exynos_rng_probe(struct platform_device *pdev) return ret; } -#ifdef CONFIG_PM -static int exynos_rng_runtime_suspend(struct device *dev) +static int __maybe_unused exynos_rng_runtime_suspend(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct exynos_rng *exynos_rng = platform_get_drvdata(pdev); @@ -166,7 +165,7 @@ static int exynos_rng_runtime_suspend(struct device *dev) return 0; } -static int exynos_rng_runtime_resume(struct device *dev) +static int __maybe_unused exynos_rng_runtime_resume(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct exynos_rng *exynos_rng = platform_get_drvdata(pdev); @@ -174,12 +173,12 @@ static int exynos_rng_runtime_resume(struct device *dev) return clk_prepare_enable(exynos_rng->clk); } -static int exynos_rng_suspend(struct device *dev) +static int __maybe_unused exynos_rng_suspend(struct device *dev) { return pm_runtime_force_suspend(dev); } -static int exynos_rng_resume(struct device *dev) +static int __maybe_unused exynos_rng_resume(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct exynos_rng *exynos_rng = platform_get_drvdata(pdev); @@ -191,7 +190,6 @@ static int exynos_rng_resume(struct device *dev) return exynos_rng_configure(exynos_rng); } -#endif static const struct dev_pm_ops exynos_rng_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(exynos_rng_suspend, exynos_rng_resume) diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c index f53e8ba2c718..83c206f0fc98 100644 --- a/drivers/char/ipmi/ipmi_ssif.c +++ b/drivers/char/ipmi/ipmi_ssif.c @@ -409,6 +409,7 @@ static void start_event_fetch(struct ssif_info *ssif_info, unsigned long *flags) msg = ipmi_alloc_smi_msg(); if (!msg) { ssif_info->ssif_state = SSIF_NORMAL; + ipmi_ssif_unlock_cond(ssif_info, flags); return; } @@ -431,6 +432,7 @@ static void start_recv_msg_fetch(struct ssif_info *ssif_info, msg = ipmi_alloc_smi_msg(); if (!msg) { ssif_info->ssif_state = SSIF_NORMAL; + ipmi_ssif_unlock_cond(ssif_info, flags); return; } diff --git a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c index 40d400fe5bb7..4ada103945f0 100644 --- a/drivers/char/ipmi/ipmi_watchdog.c +++ b/drivers/char/ipmi/ipmi_watchdog.c @@ -515,7 +515,7 @@ static void panic_halt_ipmi_heartbeat(void) msg.cmd = IPMI_WDOG_RESET_TIMER; msg.data = NULL; msg.data_len = 0; - atomic_add(2, &panic_done_count); + atomic_add(1, &panic_done_count); rv = ipmi_request_supply_msgs(watchdog_user, (struct ipmi_addr *) &addr, 0, @@ -525,7 +525,7 @@ static void panic_halt_ipmi_heartbeat(void) &panic_halt_heartbeat_recv_msg, 1); if (rv) - atomic_sub(2, &panic_done_count); + atomic_sub(1, &panic_done_count); } static struct ipmi_smi_msg panic_halt_smi_msg = { @@ -549,12 +549,12 @@ static void panic_halt_ipmi_set_timeout(void) /* Wait for the messages to be free. */ while (atomic_read(&panic_done_count) != 0) ipmi_poll_interface(watchdog_user); - atomic_add(2, &panic_done_count); + atomic_add(1, &panic_done_count); rv = i_ipmi_set_timeout(&panic_halt_smi_msg, &panic_halt_recv_msg, &send_heartbeat_now); if (rv) { - atomic_sub(2, &panic_done_count); + atomic_sub(1, &panic_done_count); printk(KERN_WARNING PFX "Unable to extend the watchdog timeout."); } else { diff --git a/drivers/char/random.c b/drivers/char/random.c index 1822472dffab..dffd06a3bb76 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -724,7 +724,7 @@ retry: static int credit_entropy_bits_safe(struct entropy_store *r, int nbits) { - const int nbits_max = (int)(~0U >> (ENTROPY_SHIFT + 1)); + const int nbits_max = r->poolinfo->poolwords * 32; if (nbits < 0) return -EINVAL; @@ -886,12 +886,16 @@ static void add_interrupt_bench(cycles_t start) static __u32 get_reg(struct fast_pool *f, struct pt_regs *regs) { __u32 *ptr = (__u32 *) regs; + unsigned int idx; if (regs == NULL) return 0; - if (f->reg_idx >= sizeof(struct pt_regs) / sizeof(__u32)) - f->reg_idx = 0; - return *(ptr + f->reg_idx++); + idx = READ_ONCE(f->reg_idx); + if (idx >= sizeof(struct pt_regs) / sizeof(__u32)) + idx = 0; + ptr += idx++; + WRITE_ONCE(f->reg_idx, idx); + return *ptr; } void add_interrupt_randomness(int irq, int irq_flags) diff --git a/drivers/char/tpm/st33zp24/st33zp24.c b/drivers/char/tpm/st33zp24/st33zp24.c index 8d626784cd8d..49e4040eeb55 100644 --- a/drivers/char/tpm/st33zp24/st33zp24.c +++ b/drivers/char/tpm/st33zp24/st33zp24.c @@ -485,7 +485,7 @@ static int st33zp24_recv(struct tpm_chip *chip, unsigned char *buf, size_t count) { int size = 0; - int expected; + u32 expected; if (!chip) return -EBUSY; @@ -502,7 +502,7 @@ static int st33zp24_recv(struct tpm_chip *chip, unsigned char *buf, } expected = be32_to_cpu(*(__be32 *)(buf + 2)); - if (expected > count) { + if (expected > count || expected < TPM_HEADER_SIZE) { size = -EIO; goto out; } diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index aaa5fa95dede..36afc1a21699 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -1040,6 +1040,11 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max) break; recd = be32_to_cpu(tpm_cmd.params.getrandom_out.rng_data_len); + if (recd > num_bytes) { + total = -EFAULT; + break; + } + memcpy(dest, tpm_cmd.params.getrandom_out.rng_data, recd); dest += recd; diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c index 286bd090a488..389a009b83f2 100644 --- a/drivers/char/tpm/tpm2-cmd.c +++ b/drivers/char/tpm/tpm2-cmd.c @@ -622,6 +622,11 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip, if (!rc) { data_len = be16_to_cpup( (__be16 *) &buf.data[TPM_HEADER_SIZE + 4]); + if (data_len < MIN_KEY_SIZE || data_len > MAX_KEY_SIZE + 1) { + rc = -EFAULT; + goto out; + } + data = &buf.data[TPM_HEADER_SIZE + 6]; memcpy(payload->key, data, data_len - 1); @@ -629,6 +634,7 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip, payload->migratable = data[data_len - 1]; } +out: tpm_buf_destroy(&buf); return rc; } diff --git a/drivers/char/tpm/tpm_i2c_infineon.c b/drivers/char/tpm/tpm_i2c_infineon.c index f2aa99e34b4b..9f12ad74a09b 100644 --- a/drivers/char/tpm/tpm_i2c_infineon.c +++ b/drivers/char/tpm/tpm_i2c_infineon.c @@ -436,7 +436,8 @@ static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count) static int tpm_tis_i2c_recv(struct tpm_chip *chip, u8 *buf, size_t count) { int size = 0; - int expected, status; + int status; + u32 expected; if (count < TPM_HEADER_SIZE) { size = -EIO; @@ -451,7 +452,7 @@ static int tpm_tis_i2c_recv(struct tpm_chip *chip, u8 *buf, size_t count) } expected = be32_to_cpu(*(__be32 *)(buf + 2)); - if ((size_t) expected > count) { + if (((size_t) expected > count) || (expected < TPM_HEADER_SIZE)) { size = -EIO; goto out; } diff --git a/drivers/char/tpm/tpm_i2c_nuvoton.c b/drivers/char/tpm/tpm_i2c_nuvoton.c index a1e1474dda30..aedf726cbab6 100644 --- a/drivers/char/tpm/tpm_i2c_nuvoton.c +++ b/drivers/char/tpm/tpm_i2c_nuvoton.c @@ -267,7 +267,11 @@ static int i2c_nuvoton_recv(struct tpm_chip *chip, u8 *buf, size_t count) struct device *dev = chip->dev.parent; struct i2c_client *client = to_i2c_client(dev); s32 rc; - int expected, status, burst_count, retries, size = 0; + int status; + int burst_count; + int retries; + int size = 0; + u32 expected; if (count < TPM_HEADER_SIZE) { i2c_nuvoton_ready(chip); /* return to idle */ @@ -309,7 +313,7 @@ static int i2c_nuvoton_recv(struct tpm_chip *chip, u8 *buf, size_t count) * to machine native */ expected = be32_to_cpu(*(__be32 *) (buf + 2)); - if (expected > count) { + if (expected > count || expected < size) { dev_err(dev, "%s() expected > count\n", __func__); size = -EIO; continue; diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index 7f13221aeb30..9dd93a209ef2 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c @@ -283,7 +283,8 @@ static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count) static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count) { int size = 0; - int expected, status; + int status; + u32 expected; if (count < TPM_HEADER_SIZE) { size = -EIO; @@ -298,7 +299,7 @@ static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count) } expected = be32_to_cpu(*(__be32 *) (buf + 2)); - if (expected > count) { + if (expected > count || expected < TPM_HEADER_SIZE) { size = -EIO; goto out; } diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index be0b09a0fb44..2aca689061e1 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -1399,7 +1399,6 @@ static int add_port(struct ports_device *portdev, u32 id) { char debugfs_name[16]; struct port *port; - struct port_buffer *buf; dev_t devt; unsigned int nr_added_bufs; int err; @@ -1510,8 +1509,6 @@ static int add_port(struct ports_device *portdev, u32 id) return 0; free_inbufs: - while ((buf = virtqueue_detach_unused_buf(port->in_vq))) - free_buf(buf, true); free_device: device_destroy(pdrvdata.class, port->dev->devt); free_cdev: @@ -1536,34 +1533,14 @@ static void remove_port(struct kref *kref) static void remove_port_data(struct port *port) { - struct port_buffer *buf; - spin_lock_irq(&port->inbuf_lock); /* Remove unused data this port might have received. */ discard_port_data(port); spin_unlock_irq(&port->inbuf_lock); - /* Remove buffers we queued up for the Host to send us data in. */ - do { - spin_lock_irq(&port->inbuf_lock); - buf = virtqueue_detach_unused_buf(port->in_vq); - spin_unlock_irq(&port->inbuf_lock); - if (buf) - free_buf(buf, true); - } while (buf); - spin_lock_irq(&port->outvq_lock); reclaim_consumed_buffers(port); spin_unlock_irq(&port->outvq_lock); - - /* Free pending buffers from the out-queue. */ - do { - spin_lock_irq(&port->outvq_lock); - buf = virtqueue_detach_unused_buf(port->out_vq); - spin_unlock_irq(&port->outvq_lock); - if (buf) - free_buf(buf, true); - } while (buf); } /* @@ -1788,13 +1765,24 @@ static void control_work_handler(struct work_struct *work) spin_unlock(&portdev->c_ivq_lock); } +static void flush_bufs(struct virtqueue *vq, bool can_sleep) +{ + struct port_buffer *buf; + unsigned int len; + + while ((buf = virtqueue_get_buf(vq, &len))) + free_buf(buf, can_sleep); +} + static void out_intr(struct virtqueue *vq) { struct port *port; port = find_port_by_vq(vq->vdev->priv, vq); - if (!port) + if (!port) { + flush_bufs(vq, false); return; + } wake_up_interruptible(&port->waitqueue); } @@ -1805,8 +1793,10 @@ static void in_intr(struct virtqueue *vq) unsigned long flags; port = find_port_by_vq(vq->vdev->priv, vq); - if (!port) + if (!port) { + flush_bufs(vq, false); return; + } spin_lock_irqsave(&port->inbuf_lock, flags); port->inbuf = get_inbuf(port); @@ -1981,6 +1971,15 @@ static const struct file_operations portdev_fops = { static void remove_vqs(struct ports_device *portdev) { + struct virtqueue *vq; + + virtio_device_for_each_vq(portdev->vdev, vq) { + struct port_buffer *buf; + + flush_bufs(vq, true); + while ((buf = virtqueue_detach_unused_buf(vq))) + free_buf(buf, true); + } portdev->vdev->config->del_vqs(portdev->vdev); kfree(portdev->in_vqs); kfree(portdev->out_vqs); |
