diff --git a/Documentation/ABI/testing/configfs-usb-gadget-uvc b/Documentation/ABI/testing/configfs-usb-gadget-uvc index 809765bd9573..5d4180aaf18e 100644 --- a/Documentation/ABI/testing/configfs-usb-gadget-uvc +++ b/Documentation/ABI/testing/configfs-usb-gadget-uvc @@ -265,6 +265,71 @@ Description: Specific uncompressed frame descriptors bmCapabilities - still image support, fixed frame-rate support +What: /config/usb-gadget/gadget/functions/uvc.name/streaming/framebased +Date: Oct 2025 +KernelVersion: 5.4 +Description: Framebased format descriptors + +What: /config/usb-gadget/gadget/functions/uvc.name/streaming/framebased/name +Date: Oct 2025 +KernelVersion: 5.4 +Description: Specific framebased format descriptors + + ================== ======================================= + bFormatIndex unique id for this format descriptor; + only defined after parent header is + linked into the streaming class; + read-only + bmaControls this format's data for bmaControls in + the streaming header + bmInterlaceFlags specifies interlace information, + read-only + bAspectRatioY the X dimension of the picture aspect + ratio, read-only + bAspectRatioX the Y dimension of the picture aspect + ratio, read-only + bDefaultFrameIndex optimum frame index for this stream + bBitsPerPixel number of bits per pixel used to + specify color in the decoded video + frame + guidFormat globally unique id used to identify + stream-encoding format + ================== ======================================= + +What: /config/usb-gadget/gadget/functions/uvc.name/streaming/framebased/name/name +Date: Sept 2024 +KernelVersion: 5.15 +Description: Specific framebased frame descriptors + + ========================= ===================================== + bFrameIndex unique id for this framedescriptor; + only defined after parent format is + linked into the streaming header; + read-only + dwFrameInterval indicates how frame interval can be + programmed; a number of values + separated by newline can be specified + dwDefaultFrameInterval the frame interval the device would + like to use as default + dwBytesPerLine Specifies the number of bytes per line + + of video for packed fixed frame size + formats, allowing the receiver to + perform stride alignment of the video. + If the bVariableSize value (above) is + TRUE (1), or if the format does not + permit such alignment, this value shall + be set to zero (0). + dwMaxBitRate the maximum bit rate at the shortest + frame interval in bps + dwMinBitRate the minimum bit rate at the longest + frame interval in bps + wHeight height of decoded bitmap frame in px + wWidth width of decoded bitmam frame in px + bmCapabilities still image support, fixed frame-rate + support + ========================= ===================================== + What: /config/usb-gadget/gadget/functions/uvc.name/streaming/header Date: Dec 2014 KernelVersion: 4.0 diff --git a/drivers/gpu/msm/adreno_a6xx.c b/drivers/gpu/msm/adreno_a6xx.c index 048e33de599c..93bebbdb24fc 100644 --- a/drivers/gpu/msm/adreno_a6xx.c +++ b/drivers/gpu/msm/adreno_a6xx.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include @@ -2523,6 +2524,7 @@ int a6xx_perfcounter_update(struct adreno_device *adreno_dev, struct cpu_gpu_lock *lock = ptr; u32 *data = ptr + sizeof(*lock); int i, offset = 0; + u32 pending_pairs = 2; /* No of pairs to add: and */ if (cpu_gpu_lock(lock)) { cpu_gpu_unlock(lock); @@ -2546,6 +2548,13 @@ int a6xx_perfcounter_update(struct adreno_device *adreno_dev, offset += 2; } + /* Ensure there is enough space in the reglist buffer for new pairs */ + if ((offset + (pending_pairs * 2)) >= + (adreno_dev->pwrup_reglist->size / sizeof(u32))) { + cpu_gpu_unlock(lock); + return -ENOSPC; + } + /* * For all targets A6XX_RBBM_PERFCTR_CNTL needs to be the last entry, * so overwrite the existing A6XX_RBBM_PERFCNTL_CTRL and add it back to diff --git a/drivers/media/platform/msm/cvp/cvp.c b/drivers/media/platform/msm/cvp/cvp.c index 87adb4fbd975..76f7444a43b8 100644 --- a/drivers/media/platform/msm/cvp/cvp.c +++ b/drivers/media/platform/msm/cvp/cvp.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. - * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include @@ -135,6 +135,8 @@ static int msm_cvp_initialize_core(struct platform_device *pdev, INIT_LIST_HEAD(&core->instances); mutex_init(&core->lock); mutex_init(&core->clk_lock); + mutex_init(&core->idr_mtx); + idr_init(&core->sess_idr); core->state = CVP_CORE_UNINIT; for (i = SYS_MSG_INDEX(SYS_MSG_START); @@ -506,6 +508,8 @@ static int msm_cvp_remove(struct platform_device *pdev) msm_cvp_free_platform_resources(&core->resources); sysfs_remove_group(&pdev->dev.kobj, &msm_cvp_core_attr_group); dev_set_drvdata(&pdev->dev, NULL); + idr_destroy(&core->sess_idr); + mutex_destroy(&core->idr_mtx); mutex_destroy(&core->lock); mutex_destroy(&core->clk_lock); kfree(core); diff --git a/drivers/media/platform/msm/cvp/cvp_hfi.c b/drivers/media/platform/msm/cvp/cvp_hfi.c index 22340456d275..df430d2235f7 100644 --- a/drivers/media/platform/msm/cvp/cvp_hfi.c +++ b/drivers/media/platform/msm/cvp/cvp_hfi.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2018-2021, The Linux Foundation. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include @@ -29,6 +30,7 @@ #include "cvp_hfi_helper.h" #include "cvp_hfi_io.h" #include "msm_cvp_dsp.h" +#include "msm_cvp.h" #define FIRMWARE_SIZE 0X00A00000 #define REG_ADDR_OFFSET_BITMASK 0x000FFFFF @@ -469,6 +471,7 @@ static int __dsp_suspend(struct iris_hfi_device *device, bool force, u32 flags) { int rc; struct cvp_hal_session *temp; + struct msm_cvp_inst *inst = NULL; if (msm_cvp_dsp_disable) return 0; @@ -480,9 +483,10 @@ static int __dsp_suspend(struct iris_hfi_device *device, bool force, u32 flags) /* don't suspend if cvp session is not paused */ if (!(temp->flags & SESSION_PAUSE)) { + inst = (struct msm_cvp_inst *)temp->session_id; dprintk(CVP_DSP, "%s: cvp session %x not paused\n", - __func__, hash32_ptr(temp)); + __func__, inst->sess_id); return -EBUSY; } } @@ -2224,12 +2228,17 @@ static void __session_clean(struct cvp_hal_session *session) { struct cvp_hal_session *temp, *next; struct iris_hfi_device *device; + struct msm_cvp_core *core = NULL; + struct msm_cvp_inst *inst = NULL; + void *tmp = NULL; if (!session || !session->device) { dprintk(CVP_WARN, "%s: invalid params\n", __func__); return; } device = session->device; + core = list_first_entry(&cvp_driver->cores, struct msm_cvp_core, list); + inst = (struct msm_cvp_inst *) session->session_id; dprintk(CVP_SESS, "deleted the session: %pK\n", session); /* * session might have been removed from the device list in @@ -2241,6 +2250,13 @@ static void __session_clean(struct cvp_hal_session *session) break; } } + /* Remove the IDR id assigned to this session */ + mutex_lock(&core->idr_mtx); + tmp = idr_remove(&core->sess_idr, inst->sess_id); + if (tmp != session) + dprintk(CVP_WARN, "%s: session\n", __func__); + mutex_unlock(&core->idr_mtx); + /* Poison the session handle with zeros */ *session = (struct cvp_hal_session){ {0} }; kfree(session); @@ -2278,6 +2294,9 @@ static int iris_hfi_session_init(void *device, void *session_id, struct cvp_hfi_cmd_sys_session_init_packet pkt; struct iris_hfi_device *dev; struct cvp_hal_session *s; + struct msm_cvp_core *core; + struct msm_cvp_inst *inst; + int id = 0; if (!device || !new_session) { dprintk(CVP_ERR, "%s - invalid input\n", __func__); @@ -2285,6 +2304,8 @@ static int iris_hfi_session_init(void *device, void *session_id, } dev = device; + core = list_first_entry(&cvp_driver->cores, struct msm_cvp_core, list); + inst = session_id; mutex_lock(&dev->lock); s = kzalloc(sizeof(*s), GFP_KERNEL); @@ -2295,15 +2316,35 @@ static int iris_hfi_session_init(void *device, void *session_id, s->session_id = session_id; s->device = dev; + + mutex_lock(&core->idr_mtx); + idr_preload(GFP_KERNEL); + + /* Need to think if we can use core->lock or dev->lock or need a + * different new lock for this? + */ + id = idr_alloc(&core->sess_idr, (void *)s, 0x7FFF0000, INT_MAX, GFP_NOWAIT); + idr_preload_end(); + mutex_unlock(&core->idr_mtx); + if (id < 0) { + dprintk(CVP_ERR, + "%s: idr allocation failed for session %pK of inst %pK\n", + __func__, s, session_id); + goto err_session_init_fail; + } + dprintk(CVP_SESS, - "%s: inst %pK, session %pK\n", __func__, session_id, s); + "%s: inst %pK, session %pK, idr_id = 0x%x\n", __func__, session_id, s, id); list_add_tail(&s->list, &dev->sess_head); __set_default_sys_properties(device); + inst->sess_id = id; + if (call_hfi_pkt_op(dev, session_init, &pkt, s)) { dprintk(CVP_ERR, "session_init: failed to create packet\n"); + inst->sess_id = 0x0000DEAD; goto err_session_init_fail; } @@ -2317,6 +2358,7 @@ static int iris_hfi_session_init(void *device, void *session_id, err_session_init_fail: if (s) __session_clean(s); + inst->sess_id = 0; *new_session = NULL; mutex_unlock(&dev->lock); return -EINVAL; @@ -2878,9 +2920,11 @@ static struct cvp_hal_session *__get_session(struct iris_hfi_device *device, u32 session_id) { struct cvp_hal_session *temp = NULL; + struct msm_cvp_inst *inst = NULL; list_for_each_entry(temp, &device->sess_head, list) { - if (session_id == hash32_ptr(temp)) + inst = (struct msm_cvp_inst *)temp->session_id; + if (session_id == inst->sess_id) return temp; } @@ -3059,6 +3103,7 @@ static int __response_handler(struct iris_hfi_device *device) /* Process the packet types that we're interested in */ process_system_msg(info, device, raw_packet); + /* This session_id is a double pointer to the idr_id of session */ session_id = get_session_id(info); /* * hfi_process_msg_packet provides a session_id that's a hashed @@ -3070,11 +3115,6 @@ static int __response_handler(struct iris_hfi_device *device) if (session_id) { struct cvp_hal_session *session = NULL; - if (upper_32_bits((uintptr_t)*session_id) != 0) { - dprintk(CVP_ERR, - "Upper 32-bits != 0 for sess_id=%pK\n", - *session_id); - } session = __get_session(device, (u32)(uintptr_t)*session_id); if (!session) { diff --git a/drivers/media/platform/msm/cvp/hfi_packetization.c b/drivers/media/platform/msm/cvp/hfi_packetization.c index 107e2d744fff..edb6caaf1d34 100644 --- a/drivers/media/platform/msm/cvp/hfi_packetization.c +++ b/drivers/media/platform/msm/cvp/hfi_packetization.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include "hfi_packetization.h" @@ -208,7 +209,7 @@ inline int cvp_create_pkt_cmd_sys_session_init( pkt->size = sizeof(struct cvp_hfi_cmd_sys_session_init_packet); pkt->packet_type = HFI_CMD_SYS_SESSION_INIT; - pkt->session_id = hash32_ptr(session); + pkt->session_id = inst->sess_id; pkt->session_type = inst->prop.type; pkt->session_kmask = inst->prop.kernel_mask; pkt->session_prio = inst->prop.priority; @@ -266,13 +267,14 @@ int cvp_create_pkt_cmd_session_cmd(struct cvp_hal_session_cmd_pkt *pkt, int pkt_type, struct cvp_hal_session *session) { int rc = 0; + struct msm_cvp_inst *inst = session->session_id; if (!pkt) return -EINVAL; pkt->size = sizeof(struct cvp_hal_session_cmd_pkt); pkt->packet_type = pkt_type; - pkt->session_id = hash32_ptr(session); + pkt->session_id = inst->sess_id; return rc; } @@ -305,13 +307,14 @@ int cvp_create_pkt_cmd_session_set_buffers( { int rc = 0; struct cvp_hfi_cmd_session_set_buffers_packet *pkt; + struct msm_cvp_inst *inst = session->session_id; - if (!cmd || !session) + if (!cmd || !session || !inst) return -EINVAL; pkt = (struct cvp_hfi_cmd_session_set_buffers_packet *)cmd; pkt->packet_type = HFI_CMD_SESSION_CVP_SET_BUFFERS; - pkt->session_id = hash32_ptr(session); + pkt->session_id = inst->sess_id; pkt->buf_type.iova = iova; pkt->buf_type.size = size; pkt->size = sizeof(struct cvp_hfi_cmd_session_set_buffers_packet); @@ -324,13 +327,14 @@ int cvp_create_pkt_cmd_session_release_buffers( struct cvp_hal_session *session) { struct cvp_session_release_buffers_packet *pkt; + struct msm_cvp_inst *inst = session->session_id; - if (!cmd || !session) + if (!cmd || !session || !inst) return -EINVAL; pkt = (struct cvp_session_release_buffers_packet *)cmd; pkt->packet_type = HFI_CMD_SESSION_CVP_RELEASE_BUFFERS; - pkt->session_id = hash32_ptr(session); + pkt->session_id = inst->sess_id; pkt->num_buffers = 1; pkt->buffer_type = 0; pkt->size = sizeof(struct cvp_session_release_buffers_packet) + @@ -347,6 +351,7 @@ int cvp_create_pkt_cmd_session_send( int def_idx; struct cvp_hal_session_cmd_pkt *ptr = (struct cvp_hal_session_cmd_pkt *)in_pkt; + struct msm_cvp_inst *inst = session->session_id; if (!out_pkt || !in_pkt || !session) return -EINVAL; @@ -354,7 +359,7 @@ int cvp_create_pkt_cmd_session_send( if (ptr->size > MAX_HFI_PKT_SIZE * sizeof(unsigned int)) goto error_hfi_packet; - if (ptr->session_id != hash32_ptr(session)) + if (ptr->session_id != inst->sess_id) goto error_hfi_packet; def_idx = get_pkt_index(ptr); diff --git a/drivers/media/platform/msm/cvp/hfi_response_handler.c b/drivers/media/platform/msm/cvp/hfi_response_handler.c index 311f94106534..3c58c5d90b92 100644 --- a/drivers/media/platform/msm/cvp/hfi_response_handler.c +++ b/drivers/media/platform/msm/cvp/hfi_response_handler.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2018-2021, The Linux Foundation. All rights reserved. - * Copyright (c) 2022-2024, Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include @@ -462,7 +462,7 @@ static struct msm_cvp_inst *cvp_get_inst_from_id(struct msm_cvp_core *core, retry: if (mutex_trylock(&core->lock)) { list_for_each_entry(inst, &core->instances, list) { - if (hash32_ptr(inst->session) == session_id) { + if (inst->sess_id == session_id) { match = true; break; } diff --git a/drivers/media/platform/msm/cvp/msm_cvp.c b/drivers/media/platform/msm/cvp/msm_cvp.c index fefc06d6aee2..239ceb89acfa 100644 --- a/drivers/media/platform/msm/cvp/msm_cvp.c +++ b/drivers/media/platform/msm/cvp/msm_cvp.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2018-2021, The Linux Foundation. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include "msm_cvp.h" @@ -14,6 +15,47 @@ struct cvp_power_level { unsigned long bw_sum; }; +void *get_sessObj_from_idr(struct msm_cvp_inst *inst) +{ + void *sessObj = NULL; + struct msm_cvp_core *core = NULL; + + if (!inst || !inst->core) { + dprintk(CVP_ERR, "%s: invalid params\n", __func__); + return NULL; + } + + core = inst->core; + mutex_lock(&core->idr_mtx); + sessObj = idr_find(&core->sess_idr, inst->sess_id); + mutex_unlock(&core->idr_mtx); + if (!sessObj) + dprintk(CVP_ERR, "%s: Could not find the sess obj for given idr id\n", + __func__); + + return sessObj; +} + +u32 get_sessId_from_idr(void *session) +{ + void *ptr = NULL; + u32 sess_id = -1; + struct msm_cvp_core *core = NULL; + + core = list_first_entry(&cvp_driver->cores, struct msm_cvp_core, list); + if (!session || !core) + return -EINVAL; + mutex_lock(&core->idr_mtx); + idr_for_each_entry(&core->sess_idr, ptr, sess_id) { + if (ptr == session) { + mutex_unlock(&core->idr_mtx); + return sess_id; + } + } + mutex_unlock(&core->idr_mtx); + return sess_id; +} + static int msm_cvp_get_session_info(struct msm_cvp_inst *inst, struct cvp_kmd_session_info *session) { @@ -30,7 +72,7 @@ static int msm_cvp_get_session_info(struct msm_cvp_inst *inst, return -ECONNRESET; s->cur_cmd_type = CVP_KMD_GET_SESSION_INFO; - session->session_id = hash32_ptr(inst->session); + session->session_id = inst->sess_id; dprintk(CVP_SESS, "%s: id 0x%x\n", __func__, session->session_id); s->cur_cmd_type = 0; @@ -1227,7 +1269,7 @@ static int msm_cvp_session_stop(struct msm_cvp_inst *inst, sq->state = QUEUE_STOP; pr_info(CVP_DBG_TAG "Stop session: %pK session_id = %d\n", - "sess", inst, hash32_ptr(inst->session)); + "sess", inst, inst->sess_id); spin_unlock(&sq->lock); wake_up_all(&inst->session_queue.wq); @@ -1251,7 +1293,7 @@ int msm_cvp_session_queue_stop(struct msm_cvp_inst *inst) sq->state = QUEUE_STOP; dprintk(CVP_SESS, "Stop session queue: %pK session_id = %d\n", - inst, hash32_ptr(inst->session)); + inst, inst->sess_id); spin_unlock(&sq->lock); wake_up_all(&inst->session_queue.wq); @@ -1551,7 +1593,7 @@ static void cvp_clean_fence_queue(struct msm_cvp_inst *inst, int synx_state) ktid = f->pkt->client_data.kdata & (FENCE_BIT - 1); dprintk(CVP_SYNX, "%s: (%#x) flush frame %llu %llu wait_list\n", - __func__, hash32_ptr(inst->session), ktid, f->frame_id); + __func__, inst->sess_id, ktid, f->frame_id); list_del_init(&f->list); msm_cvp_unmap_frame(inst, f->pkt->client_data.kdata); @@ -1564,7 +1606,7 @@ static void cvp_clean_fence_queue(struct msm_cvp_inst *inst, int synx_state) ktid = f->pkt->client_data.kdata & (FENCE_BIT - 1); dprintk(CVP_SYNX, "%s: (%#x)flush frame %llu %llu sched_list\n", - __func__, hash32_ptr(inst->session), ktid, f->frame_id); + __func__, inst->sess_id, ktid, f->frame_id); cvp_cancel_synx(inst, CVP_INPUT_SYNX, f, synx_state); } @@ -1612,14 +1654,14 @@ static int cvp_flush_all(struct msm_cvp_inst *inst) return -ECONNRESET; dprintk(CVP_SESS, "session %llx (%#x)flush all starts\n", - inst, hash32_ptr(inst->session)); + inst, inst->sess_id); q = &inst->fence_cmd_queue; hdev = inst->core->device; cvp_clean_fence_queue(inst, SYNX_STATE_SIGNALED_CANCEL); dprintk(CVP_SESS, "%s: (%#x) send flush to fw\n", - __func__, hash32_ptr(inst->session)); + __func__, inst->sess_id); /* Send flush to FW */ rc = call_hfi_op(hdev, session_flush, (void *)inst->session); @@ -1636,7 +1678,7 @@ static int cvp_flush_all(struct msm_cvp_inst *inst) __func__, rc); dprintk(CVP_SESS, "%s: (%#x) received flush from fw\n", - __func__, hash32_ptr(inst->session)); + __func__, inst->sess_id); exit: rc = cvp_drain_fence_sched_list(inst); @@ -1859,10 +1901,10 @@ int msm_cvp_session_deinit(struct msm_cvp_inst *inst) return -EINVAL; } dprintk(CVP_SESS, "%s: inst %pK (%#x)\n", __func__, - inst, hash32_ptr(inst->session)); + inst, inst->sess_id); - session = (struct cvp_hal_session *)inst->session; - if (!session) + session = (struct cvp_hal_session *)get_sessObj_from_idr(inst); + if (!session || session != inst->session) return rc; rc = msm_cvp_comm_try_state(inst, MSM_CVP_CLOSE_DONE); @@ -1883,7 +1925,7 @@ int msm_cvp_session_init(struct msm_cvp_inst *inst) } dprintk(CVP_SESS, "%s: inst %pK (%#x)\n", __func__, - inst, hash32_ptr(inst->session)); + inst, inst->sess_id); /* set default frequency */ inst->clk_data.core_id = 0; diff --git a/drivers/media/platform/msm/cvp/msm_cvp.h b/drivers/media/platform/msm/cvp/msm_cvp.h index b21864b46f1c..b8ae6068de35 100644 --- a/drivers/media/platform/msm/cvp/msm_cvp.h +++ b/drivers/media/platform/msm/cvp/msm_cvp.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #ifndef _MSM_CVP_H_ @@ -34,4 +35,6 @@ int msm_cvp_session_init(struct msm_cvp_inst *inst); int msm_cvp_session_deinit(struct msm_cvp_inst *inst); int msm_cvp_session_queue_stop(struct msm_cvp_inst *inst); int cvp_stop_clean_fence_queue(struct msm_cvp_inst *inst); +void *get_sessObj_from_idr(struct msm_cvp_inst *inst); +u32 get_sessId_from_idr(void *session); #endif diff --git a/drivers/media/platform/msm/cvp/msm_cvp_buf.c b/drivers/media/platform/msm/cvp/msm_cvp_buf.c index 995c111edb7d..c16eed33efd3 100644 --- a/drivers/media/platform/msm/cvp/msm_cvp_buf.c +++ b/drivers/media/platform/msm/cvp/msm_cvp_buf.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2020, The Linux Foundation. All rights reserved. - * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include "msm_cvp_common.h" @@ -14,7 +14,7 @@ do { \ clear_bit(idx, &inst->dma_cache.usage_bitmap); \ dprintk(CVP_MEM, "clear %x bit %d dma_cache bitmap 0x%llx\n", \ - hash32_ptr(inst->session), smem->bitmap_index, \ + inst->sess_id, smem->bitmap_index, \ inst->dma_cache.usage_bitmap); \ } while (0) @@ -22,7 +22,7 @@ do { \ set_bit(idx, &inst->dma_cache.usage_bitmap); \ dprintk(CVP_MEM, "Set %x bit %d dma_cache bitmap 0x%llx\n", \ - hash32_ptr(inst->session), idx, \ + inst->sess_id, idx, \ inst->dma_cache.usage_bitmap); \ } while (0) @@ -36,7 +36,7 @@ void print_smem(u32 tag, const char *str, struct msm_cvp_inst *inst, if (smem->dma_buf) { dprintk(tag, "%s: %x : %s size %d flags %#x iova %#x idx %d ref %d", - str, hash32_ptr(inst->session), smem->dma_buf->name, + str, inst->sess_id, smem->dma_buf->name, smem->size, smem->flags, smem->device_addr, smem->bitmap_index, smem->refcount); } @@ -51,13 +51,13 @@ static void print_internal_buffer(u32 tag, const char *str, if (cbuf->smem->dma_buf) { dprintk(tag, "%s: %x : fd %d off %d %s size %d iova %#x", - str, hash32_ptr(inst->session), cbuf->fd, + str, inst->sess_id, cbuf->fd, cbuf->offset, cbuf->smem->dma_buf->name, cbuf->size, cbuf->smem->device_addr); } else { dprintk(tag, "%s: %x : idx %2d fd %d off %d size %d iova %#x", - str, hash32_ptr(inst->session), cbuf->fd, + str, inst->sess_id, cbuf->fd, cbuf->offset, cbuf->size, cbuf->smem->device_addr); } } @@ -77,7 +77,7 @@ void print_client_buffer(u32 tag, const char *str, dprintk(tag, "%s: %x : idx %2d fd %d off %d size %d type %d flags 0x%x\n", - str, hash32_ptr(inst->session), cbuf->index, cbuf->fd, + str, inst->sess_id, cbuf->index, cbuf->fd, cbuf->offset, cbuf->size, cbuf->type, cbuf->flags); } @@ -154,7 +154,7 @@ int msm_cvp_map_buf_dsp(struct msm_cvp_inst *inst, struct cvp_kmd_buffer *buf) } if (buf->index) { - rc = cvp_dsp_register_buffer(hash32_ptr(session), buf->fd, + rc = cvp_dsp_register_buffer(inst->sess_id, buf->fd, smem->dma_buf->size, buf->size, buf->offset, buf->index, (uint32_t)smem->device_addr); if (rc) { @@ -227,7 +227,7 @@ int msm_cvp_unmap_buf_dsp(struct msm_cvp_inst *inst, struct cvp_kmd_buffer *buf) } if (buf->index) { - rc = cvp_dsp_deregister_buffer(hash32_ptr(session), buf->fd, + rc = cvp_dsp_deregister_buffer(inst->sess_id, buf->fd, cbuf->smem->dma_buf->size, buf->size, buf->offset, buf->index, (uint32_t)cbuf->smem->device_addr); if (rc) { @@ -545,7 +545,7 @@ void msm_cvp_unmap_frame(struct msm_cvp_inst *inst, u64 ktid) ktid &= (FENCE_BIT - 1); dprintk(CVP_MEM, "%s: (%#x) unmap frame %llu\n", - __func__, hash32_ptr(inst->session), ktid); + __func__, inst->sess_id, ktid); found = false; mutex_lock(&inst->frames.lock); @@ -587,7 +587,7 @@ int msm_cvp_unmap_user_persist(struct msm_cvp_inst *inst, smem = pbuf->smem; dprintk(CVP_MEM, "unmap persist: %x %d %d %#x", - hash32_ptr(inst->session), pbuf->fd, + inst->sess_id, pbuf->fd, pbuf->size, smem->device_addr); if (smem->bitmap_index >= MAX_DMABUF_NUMS) { @@ -785,7 +785,7 @@ int msm_cvp_session_deinit_buffers(struct msm_cvp_inst *inst) list_for_each_entry_safe(cbuf, dummy, &inst->cvpdspbufs.list, list) { print_internal_buffer(CVP_MEM, "remove dspbufs", inst, cbuf); - rc = cvp_dsp_deregister_buffer(hash32_ptr(session), + rc = cvp_dsp_deregister_buffer(inst->sess_id, cbuf->fd, cbuf->smem->dma_buf->size, cbuf->size, cbuf->offset, cbuf->index, (uint32_t)cbuf->smem->device_addr); @@ -955,7 +955,7 @@ int cvp_release_arp_buffers(struct msm_cvp_inst *inst) if (buf->ownership == DRIVER) { dprintk(CVP_MEM, "%s: %x : fd %d %s size %d", - "free arp", hash32_ptr(inst->session), buf->fd, + "free arp", inst->sess_id, buf->fd, smem->dma_buf->name, buf->size); msm_cvp_smem_free(smem); kmem_cache_free(cvp_driver->smem_cache, smem); diff --git a/drivers/media/platform/msm/cvp/msm_cvp_common.c b/drivers/media/platform/msm/cvp/msm_cvp_common.c index 69787e51cc3d..22c8aa9441ad 100644 --- a/drivers/media/platform/msm/cvp/msm_cvp_common.c +++ b/drivers/media/platform/msm/cvp/msm_cvp_common.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2018-2021, The Linux Foundation. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include @@ -195,23 +196,31 @@ struct msm_cvp_inst *cvp_get_inst_validate(struct msm_cvp_core *core, { int rc = 0; struct cvp_hfi_device *hdev; - struct msm_cvp_inst *s; + struct msm_cvp_inst *inst; + void *sessObj = NULL; - s = cvp_get_inst(core, session_id); - if (!s) { - dprintk(CVP_ERR, "%s session doesn't exit\n", + inst = cvp_get_inst(core, session_id); + if (!inst) { + dprintk(CVP_ERR, "%s Inst doesn't exit\n", __builtin_return_address(0)); return NULL; } - hdev = s->core->device; - rc = call_hfi_op(hdev, validate_session, s->session, __func__); - if (rc) { - cvp_put_inst(s); - s = NULL; + sessObj = get_sessObj_from_idr(inst); + if (!sessObj || sessObj != inst->session) { + dprintk(CVP_ERR, + "Either sessionObj is null or not matching with inst->session\n"); + return NULL; } - return s; + hdev = inst->core->device; + rc = call_hfi_op(hdev, validate_session, sessObj, __func__); + if (rc) { + cvp_put_inst(inst); + inst = NULL; + } + + return inst; } static void cvp_handle_session_cmd_done(enum hal_command_response cmd, @@ -486,7 +495,7 @@ static void handle_session_init_done(enum hal_command_response cmd, void *data) } dprintk(CVP_SESS, "%s: cvp session %#x\n", __func__, - hash32_ptr(inst->session)); + inst->sess_id); signal_session_msg_receipt(cmd, inst); cvp_put_inst(inst); @@ -568,7 +577,7 @@ static void handle_session_error(enum hal_command_response cmd, void *data) hdev = inst->core->device; dprintk(CVP_ERR, "Session error received for inst %pK session %x\n", - inst, hash32_ptr(inst->session)); + inst, inst->sess_id); if (response->status == CVP_ERR_MAX_CLIENTS) { dprintk(CVP_WARN, "Too many clients, rejecting %pK", inst); @@ -901,7 +910,7 @@ static int msm_comm_session_abort(struct msm_cvp_inst *inst) abort_completion = SESSION_MSG_INDEX(HAL_SESSION_ABORT_DONE); dprintk(CVP_WARN, "%s: inst %pK session %x\n", __func__, - inst, hash32_ptr(inst->session)); + inst, inst->sess_id); rc = call_hfi_op(hdev, session_abort, (void *)inst->session); if (rc) { dprintk(CVP_ERR, @@ -914,7 +923,7 @@ static int msm_comm_session_abort(struct msm_cvp_inst *inst) inst->core->resources.msm_cvp_hw_rsp_timeout)); if (!rc) { dprintk(CVP_ERR, "%s: inst %pK session %x abort timed out\n", - __func__, inst, hash32_ptr(inst->session)); + __func__, inst, inst->sess_id); call_hfi_op(hdev, flush_debug_queue, hdev->hfi_device_data); dump_hfi_queue(hdev->hfi_device_data); msm_cvp_comm_generate_sys_error(inst); @@ -1268,7 +1277,7 @@ int msm_cvp_comm_try_state(struct msm_cvp_inst *inst, int state) } dprintk(CVP_SESS, "Trying to move inst: %pK (%#x) from: %#x to %#x\n", - inst, hash32_ptr(inst->session), inst->state, state); + inst, inst->sess_id, inst->state, state); mutex_lock(&inst->sync_lock); if (inst->state == MSM_CVP_CORE_INVALID) { @@ -1281,7 +1290,7 @@ int msm_cvp_comm_try_state(struct msm_cvp_inst *inst, int state) flipped_state = get_flipped_state(inst->state, state); dprintk(CVP_SESS, "inst: %pK (%#x) flipped_state = %#x %x\n", - inst, hash32_ptr(inst->session), flipped_state, state); + inst, inst->sess_id, flipped_state, state); switch (flipped_state) { case MSM_CVP_CORE_UNINIT_DONE: case MSM_CVP_CORE_INIT: @@ -1491,7 +1500,7 @@ int msm_cvp_comm_kill_session(struct msm_cvp_inst *inst) return 0; } dprintk(CVP_WARN, "%s: inst %pK, session %x state %d\n", __func__, - inst, hash32_ptr(inst->session), inst->state); + inst, inst->sess_id, inst->state); /* * We're internally forcibly killing the session, if fw is aware of * the session send session_abort to firmware to clean up and release @@ -1503,7 +1512,7 @@ int msm_cvp_comm_kill_session(struct msm_cvp_inst *inst) if (rc) { dprintk(CVP_ERR, "%s: inst %pK session %x abort failed\n", - __func__, inst, hash32_ptr(inst->session)); + __func__, inst, inst->sess_id); change_cvp_inst_state(inst, MSM_CVP_CORE_INVALID); } else { change_cvp_inst_state(inst, MSM_CVP_CORE_UNINIT); diff --git a/drivers/media/platform/msm/cvp/msm_cvp_core.c b/drivers/media/platform/msm/cvp/msm_cvp_core.c index 5347eade1782..b98d43730988 100644 --- a/drivers/media/platform/msm/cvp/msm_cvp_core.c +++ b/drivers/media/platform/msm/cvp/msm_cvp_core.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include @@ -165,7 +166,7 @@ void *msm_cvp_open(int core_id, int session_type) list_for_each_entry(inst, &core->instances, list) dprintk(CVP_ERR, "inst %pK, cmd %d id %d\n", inst, inst->cur_cmd_type, - hash32_ptr(inst->session)); + inst->sess_id); mutex_unlock(&core->lock); return NULL; @@ -369,7 +370,7 @@ int msm_cvp_destroy(struct msm_cvp_inst *inst) synx_uninitialize(inst->synx_session_id); pr_info(CVP_DBG_TAG "Closed cvp instance: %pK session_id = %d\n", - "sess", inst, hash32_ptr(inst->session)); + "sess", inst, inst->sess_id); if (inst->cur_cmd_type) dprintk(CVP_ERR, "deleted instance has pending cmd %d\n", inst->cur_cmd_type); diff --git a/drivers/media/platform/msm/cvp/msm_cvp_internal.h b/drivers/media/platform/msm/cvp/msm_cvp_internal.h index 533e16cfce56..31495ad77d35 100644 --- a/drivers/media/platform/msm/cvp/msm_cvp_internal.h +++ b/drivers/media/platform/msm/cvp/msm_cvp_internal.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #ifndef _MSM_CVP_INTERNAL_H_ @@ -290,6 +291,8 @@ struct msm_cvp_core { unsigned long curr_freq; struct cvp_cycle_info dyn_clk; atomic64_t kernel_trans_id; + struct idr sess_idr; + struct mutex idr_mtx; }; struct msm_cvp_inst { @@ -301,6 +304,7 @@ struct msm_cvp_inst { struct cvp_session_queue session_queue_fence; struct cvp_session_event event_handler; void *session; + u32 sess_id; enum instance_state state; struct msm_cvp_list freqs; struct msm_cvp_list persistbufs; diff --git a/drivers/media/platform/msm/cvp/msm_cvp_synx.c b/drivers/media/platform/msm/cvp/msm_cvp_synx.c index f70fb4013058..4580c582174b 100644 --- a/drivers/media/platform/msm/cvp/msm_cvp_synx.c +++ b/drivers/media/platform/msm/cvp/msm_cvp_synx.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include "msm_cvp_common.h" @@ -20,7 +21,7 @@ void cvp_dump_fence_queue(struct msm_cvp_inst *inst) ssid = inst->synx_session_id; mutex_lock(&q->lock); dprintk(CVP_WARN, "inst %x fence q mode %d, ssid %d\n", - hash32_ptr(inst->session), q->mode, ssid.client_id); + inst->sess_id, q->mode, ssid.client_id); dprintk(CVP_WARN, "fence cmdq wait list:\n"); list_for_each_entry(f, &q->wait_list, list) { diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c index 094a88ff9a67..b4c08b4ed602 100644 --- a/drivers/usb/gadget/function/f_uvc.c +++ b/drivers/usb/gadget/function/f_uvc.c @@ -808,9 +808,9 @@ static struct usb_function_instance *uvc_alloc_inst(void) cd->wObjectiveFocalLengthMax = cpu_to_le16(0); cd->wOcularFocalLength = cpu_to_le16(0); cd->bControlSize = 3; - cd->bmControls[0] = 2; - cd->bmControls[1] = 0; - cd->bmControls[2] = 0; + cd->bmControls[0] = 62; + cd->bmControls[1] = 126; + cd->bmControls[2] = 10; pd = &opts->uvc_processing; pd->bLength = UVC_DT_PROCESSING_UNIT_SIZE(2); @@ -820,8 +820,8 @@ static struct usb_function_instance *uvc_alloc_inst(void) pd->bSourceID = 1; pd->wMaxMultiplier = cpu_to_le16(16*1024); pd->bControlSize = 2; - pd->bmControls[0] = 1; - pd->bmControls[1] = 0; + pd->bmControls[0] = 91; + pd->bmControls[1] = 23; pd->iProcessing = 0; pd->bmVideoStandards = 0; diff --git a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c index 00fb58e50a15..5480a2988fe4 100644 --- a/drivers/usb/gadget/function/uvc_configfs.c +++ b/drivers/usb/gadget/function/uvc_configfs.c @@ -762,16 +762,19 @@ static const struct uvcg_config_group_type uvcg_control_grp_type = { /* ----------------------------------------------------------------------------- * streaming/uncompressed * streaming/mjpeg + * streaming/framebased */ static const char * const uvcg_format_names[] = { "uncompressed", "mjpeg", + "framebased" }; enum uvcg_format_type { UVCG_UNCOMPRESSED = 0, UVCG_MJPEG, + UVCG_FRAMEBASED, }; struct uvcg_format { @@ -1080,6 +1083,7 @@ struct uvcg_frame { u32 dw_max_video_frame_buffer_size; u32 dw_default_frame_interval; u8 b_frame_interval_type; + u32 dw_bytes_perline; } __attribute__((packed)) frame; u32 *dw_frame_interval; }; @@ -1190,6 +1194,7 @@ UVCG_FRAME_ATTR(dw_min_bit_rate, dwMinBitRate, 32); UVCG_FRAME_ATTR(dw_max_bit_rate, dwMaxBitRate, 32); UVCG_FRAME_ATTR(dw_max_video_frame_buffer_size, dwMaxVideoFrameBufferSize, 32); UVCG_FRAME_ATTR(dw_default_frame_interval, dwDefaultFrameInterval, 32); +UVCG_FRAME_ATTR(dw_bytes_perline, dwBytesPerLine, 32); #undef UVCG_FRAME_ATTR @@ -1324,7 +1329,7 @@ end: UVC_ATTR(uvcg_frame_, dw_frame_interval, dwFrameInterval); -static struct configfs_attribute *uvcg_frame_attrs[] = { +static struct configfs_attribute *uvcg_frame_attrs1[] = { &uvcg_frame_attr_b_frame_index, &uvcg_frame_attr_bm_capabilities, &uvcg_frame_attr_w_width, @@ -1337,12 +1342,32 @@ static struct configfs_attribute *uvcg_frame_attrs[] = { NULL, }; -static const struct config_item_type uvcg_frame_type = { +static struct configfs_attribute *uvcg_frame_attrs2[] = { + &uvcg_frame_attr_b_frame_index, + &uvcg_frame_attr_bm_capabilities, + &uvcg_frame_attr_w_width, + &uvcg_frame_attr_w_height, + &uvcg_frame_attr_dw_min_bit_rate, + &uvcg_frame_attr_dw_max_bit_rate, + &uvcg_frame_attr_dw_max_video_frame_buffer_size, + &uvcg_frame_attr_dw_default_frame_interval, + &uvcg_frame_attr_dw_frame_interval, + &uvcg_frame_attr_dw_bytes_perline, + NULL, +}; + +static const struct config_item_type uvcg_frame_type1 = { .ct_item_ops = &uvcg_config_item_ops, - .ct_attrs = uvcg_frame_attrs, + .ct_attrs = uvcg_frame_attrs1, .ct_owner = THIS_MODULE, }; +static const struct config_item_type uvcg_frame_type2 = { + .ct_item_ops = &uvcg_config_item_ops, + .ct_attrs = uvcg_frame_attrs2, + .ct_owner = THIS_MODULE, +}; + static struct config_item *uvcg_frame_make(struct config_group *group, const char *name) { @@ -1363,6 +1388,7 @@ static struct config_item *uvcg_frame_make(struct config_group *group, h->frame.dw_max_bit_rate = 55296000; h->frame.dw_max_video_frame_buffer_size = 460800; h->frame.dw_default_frame_interval = 666666; + h->frame.dw_bytes_perline = 0; opts_item = group->cg_item.ci_parent->ci_parent->ci_parent; opts = to_f_uvc_opts(opts_item); @@ -1375,6 +1401,9 @@ static struct config_item *uvcg_frame_make(struct config_group *group, } else if (fmt->type == UVCG_MJPEG) { h->frame.b_descriptor_subtype = UVC_VS_FRAME_MJPEG; h->fmt_type = UVCG_MJPEG; + } else if (fmt->type == UVCG_FRAMEBASED) { + h->frame.b_descriptor_subtype = UVC_VS_FRAME_FRAME_BASED; + h->fmt_type = UVCG_FRAMEBASED; } else { mutex_unlock(&opts->lock); kfree(h); @@ -1383,7 +1412,10 @@ static struct config_item *uvcg_frame_make(struct config_group *group, ++fmt->num_frames; mutex_unlock(&opts->lock); - config_item_init_type_name(&h->item, name, &uvcg_frame_type); + if (fmt->type == UVCG_FRAMEBASED) + config_item_init_type_name(&h->item, name, &uvcg_frame_type2); + else + config_item_init_type_name(&h->item, name, &uvcg_frame_type1); return &h->item; } @@ -1413,9 +1445,6 @@ static void uvcg_format_set_indices(struct config_group *fmt) list_for_each_entry(ci, &fmt->cg_children, ci_entry) { struct uvcg_frame *frm; - if (ci->ci_type != &uvcg_frame_type) - continue; - frm = to_uvcg_frame(ci); frm->frame.b_frame_index = i++; } @@ -1856,6 +1885,260 @@ static const struct uvcg_config_group_type uvcg_mjpeg_grp_type = { .name = "mjpeg", }; +/* ----------------------------------------------------------------------------- + * streaming/framebased/ + */ + +struct uvcg_framebased { + struct uvcg_format fmt; + struct uvc_format_framebased desc; +}; + +static inline struct uvcg_framebased *to_uvcg_framebased(struct config_item *item) +{ + return container_of(to_uvcg_format(item), struct uvcg_framebased, fmt); +} + +static struct configfs_group_operations uvcg_framebased_group_ops = { + .make_item = uvcg_frame_make, + .drop_item = uvcg_frame_drop, +}; + +#define UVCG_FRAMEBASED_ATTR_RO(cname, aname, bits) \ + static ssize_t uvcg_framebased_##cname##_show(struct config_item *item, \ + char *page) \ +{ \ + struct uvcg_framebased *u = to_uvcg_framebased(item); \ + struct f_uvc_opts *opts; \ + struct config_item *opts_item; \ + struct mutex *su_mutex = &u->fmt.group.cg_subsys->su_mutex; \ + int result; \ + \ + mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \ + \ + opts_item = u->fmt.group.cg_item.ci_parent->ci_parent->ci_parent; \ + opts = to_f_uvc_opts(opts_item); \ + \ + mutex_lock(&opts->lock); \ + result = scnprintf(page, PAGE_SIZE, "%u\n", le##bits##_to_cpu(u->desc.aname));\ + mutex_unlock(&opts->lock); \ + \ + mutex_unlock(su_mutex); \ + return result; \ +} \ + \ +UVC_ATTR_RO(uvcg_framebased_, cname, aname) + +#define UVCG_FRAMEBASED_ATTR(cname, aname, bits) \ + static ssize_t uvcg_framebased_##cname##_show(struct config_item *item, \ + char *page) \ +{ \ + struct uvcg_framebased *u = to_uvcg_framebased(item); \ + struct f_uvc_opts *opts; \ + struct config_item *opts_item; \ + struct mutex *su_mutex = &u->fmt.group.cg_subsys->su_mutex; \ + int result; \ + \ + mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \ + \ + opts_item = u->fmt.group.cg_item.ci_parent->ci_parent->ci_parent;\ + opts = to_f_uvc_opts(opts_item); \ + \ + mutex_lock(&opts->lock); \ + result = scnprintf(page, PAGE_SIZE, "%u\n", le##bits##_to_cpu(u->desc.aname));\ + mutex_unlock(&opts->lock); \ + \ + mutex_unlock(su_mutex); \ + return result; \ +} \ + \ +static ssize_t \ +uvcg_framebased_##cname##_store(struct config_item *item, \ + const char *page, size_t len) \ +{ \ + struct uvcg_framebased *u = to_uvcg_framebased(item); \ + struct f_uvc_opts *opts; \ + struct config_item *opts_item; \ + struct mutex *su_mutex = &u->fmt.group.cg_subsys->su_mutex; \ + int ret; \ + u8 num; \ + \ + mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \ + \ + opts_item = u->fmt.group.cg_item.ci_parent->ci_parent->ci_parent;\ + opts = to_f_uvc_opts(opts_item); \ + \ + mutex_lock(&opts->lock); \ + if (u->fmt.linked || opts->refcnt) { \ + ret = -EBUSY; \ + goto end; \ + } \ + \ + ret = kstrtou8(page, 0, &num); \ + if (ret) \ + goto end; \ + \ + if (num > 255) { \ + ret = -EINVAL; \ + goto end; \ + } \ + u->desc.aname = num; \ + ret = len; \ +end: \ + mutex_unlock(&opts->lock); \ + mutex_unlock(su_mutex); \ + return ret; \ +} \ + \ +UVC_ATTR(uvcg_framebased_, cname, aname) + +UVCG_FRAMEBASED_ATTR_RO(b_format_index, bFormatIndex, 8); +UVCG_FRAMEBASED_ATTR_RO(b_bits_per_pixel, bBitsPerPixel, 8); +UVCG_FRAMEBASED_ATTR(b_default_frame_index, bDefaultFrameIndex, 8); +UVCG_FRAMEBASED_ATTR_RO(b_aspect_ratio_x, bAspectRatioX, 8); +UVCG_FRAMEBASED_ATTR_RO(b_aspect_ratio_y, bAspectRatioY, 8); +UVCG_FRAMEBASED_ATTR_RO(bm_interface_flags, bmInterfaceFlags, 8); + +#undef UVCG_FRAMEBASED_ATTR +#undef UVCG_FRAMEBASED_ATTR_RO + +static ssize_t uvcg_framebased_guid_format_show(struct config_item *item, + char *page) +{ + struct uvcg_framebased *ch = to_uvcg_framebased(item); + struct f_uvc_opts *opts; + struct config_item *opts_item; + struct mutex *su_mutex = &ch->fmt.group.cg_subsys->su_mutex; + + mutex_lock(su_mutex); /* for navigating configfs hierarchy */ + + opts_item = ch->fmt.group.cg_item.ci_parent->ci_parent->ci_parent; + opts = to_f_uvc_opts(opts_item); + + mutex_lock(&opts->lock); + memcpy(page, ch->desc.guidFormat, sizeof(ch->desc.guidFormat)); + mutex_unlock(&opts->lock); + + mutex_unlock(su_mutex); + + return sizeof(ch->desc.guidFormat); +} + +static ssize_t uvcg_framebased_guid_format_store(struct config_item *item, + const char *page, size_t len) +{ + struct uvcg_framebased *ch = to_uvcg_framebased(item); + struct f_uvc_opts *opts; + struct config_item *opts_item; + struct mutex *su_mutex = &ch->fmt.group.cg_subsys->su_mutex; + int ret; + + mutex_lock(su_mutex); /* for navigating configfs hierarchy */ + + opts_item = ch->fmt.group.cg_item.ci_parent->ci_parent->ci_parent; + opts = to_f_uvc_opts(opts_item); + + mutex_lock(&opts->lock); + if (ch->fmt.linked || opts->refcnt) { + ret = -EBUSY; + goto end; + } + + memcpy(ch->desc.guidFormat, page, + min(sizeof(ch->desc.guidFormat), len)); + ret = sizeof(ch->desc.guidFormat); + +end: + mutex_unlock(&opts->lock); + mutex_unlock(su_mutex); + return ret; +} + +UVC_ATTR(uvcg_framebased_, guid_format, guidFormat); + + static inline ssize_t +uvcg_framebased_bma_controls_show(struct config_item *item, char *page) +{ + struct uvcg_framebased *u = to_uvcg_framebased(item); + + return uvcg_format_bma_controls_show(&u->fmt, page); +} + + static inline ssize_t +uvcg_framebased_bma_controls_store(struct config_item *item, + const char *page, size_t len) +{ + struct uvcg_framebased *u = to_uvcg_framebased(item); + + return uvcg_format_bma_controls_store(&u->fmt, page, len); +} + +UVC_ATTR(uvcg_framebased_, bma_controls, bmaControls); + +static struct configfs_attribute *uvcg_framebased_attrs[] = { + &uvcg_framebased_attr_b_format_index, + &uvcg_framebased_attr_b_default_frame_index, + &uvcg_framebased_attr_b_bits_per_pixel, + &uvcg_framebased_attr_b_aspect_ratio_x, + &uvcg_framebased_attr_b_aspect_ratio_y, + &uvcg_framebased_attr_bm_interface_flags, + &uvcg_framebased_attr_bma_controls, + &uvcg_framebased_attr_guid_format, + NULL, +}; + +static const struct config_item_type uvcg_framebased_type = { + .ct_item_ops = &uvcg_config_item_ops, + .ct_group_ops = &uvcg_framebased_group_ops, + .ct_attrs = uvcg_framebased_attrs, + .ct_owner = THIS_MODULE, +}; + +static struct config_group *uvcg_framebased_make(struct config_group *group, + const char *name) +{ + static char guid[] = { /*Declear frame based as H264 format*/ + 'H', '2', '6', '4', 0x00, 0x00, 0x10, 0x00, + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 + }; + struct uvcg_framebased *h; + + h = kzalloc(sizeof(*h), GFP_KERNEL); + if (!h) + return ERR_PTR(-ENOMEM); + + h->desc.bLength = UVC_DT_FORMAT_FRAMEBASED_SIZE; + h->desc.bDescriptorType = USB_DT_CS_INTERFACE; + h->desc.bDescriptorSubType = UVC_VS_FORMAT_FRAME_BASED; + memcpy(h->desc.guidFormat, guid, sizeof(guid)); + h->desc.bBitsPerPixel = 0; + h->desc.bDefaultFrameIndex = 1; + h->desc.bAspectRatioX = 0; + h->desc.bAspectRatioY = 0; + h->desc.bmInterfaceFlags = 0; + h->desc.bCopyProtect = 0; + h->desc.bVariableSize = 1; + + h->fmt.type = UVCG_FRAMEBASED; + config_group_init_type_name(&h->fmt.group, name, + &uvcg_framebased_type); + + return &h->fmt.group; +} + +static struct configfs_group_operations uvcg_framebased_grp_ops = { + .make_group = uvcg_framebased_make, +}; + +static const struct uvcg_config_group_type uvcg_framebased_grp_type = { + .type = { + .ct_item_ops = &uvcg_config_item_ops, + .ct_group_ops = &uvcg_framebased_grp_ops, + .ct_owner = THIS_MODULE, + }, + .name = "framebased", +}; + /* ----------------------------------------------------------------------------- * streaming/color_matching/default */ @@ -2001,6 +2284,7 @@ static int __uvcg_iter_strm_cls(struct uvcg_streaming_header *h, if (ret) return ret; grp = &f->fmt->group; + j = 0; list_for_each_entry(item, &grp->cg_children, ci_entry) { frm = to_uvcg_frame(item); ret = fun(frm, priv2, priv3, j++, UVCG_FRAME); @@ -2049,6 +2333,11 @@ static int __uvcg_cnt_strm(void *priv1, void *priv2, void *priv3, int n, container_of(fmt, struct uvcg_mjpeg, fmt); *size += sizeof(m->desc); + } else if (fmt->type == UVCG_FRAMEBASED) { + struct uvcg_framebased *f = + container_of(fmt, struct uvcg_framebased, fmt); + + *size += sizeof(f->desc); } else { return -EINVAL; } @@ -2059,6 +2348,11 @@ static int __uvcg_cnt_strm(void *priv1, void *priv2, void *priv3, int n, int sz = sizeof(frm->dw_frame_interval); *size += sizeof(frm->frame); + /* + * framebased has duplicate member with uncompressed and + * mjpeg, so minus it + */ + *size -= sizeof(u32); *size += frm->frame.b_frame_interval_type * sz; } break; @@ -2069,6 +2363,27 @@ static int __uvcg_cnt_strm(void *priv1, void *priv2, void *priv3, int n, return 0; } +static int __uvcg_copy_framebased_desc(void *dest, struct uvcg_frame *frm, + int sz) +{ + struct uvc_frame_framebased *desc = dest; + + desc->bLength = frm->frame.b_length; + desc->bDescriptorType = frm->frame.b_descriptor_type; + desc->bDescriptorSubType = frm->frame.b_descriptor_subtype; + desc->bFrameIndex = frm->frame.b_frame_index; + desc->bmCapabilities = frm->frame.bm_capabilities; + desc->wWidth = frm->frame.w_width; + desc->wHeight = frm->frame.w_height; + desc->dwMinBitRate = frm->frame.dw_min_bit_rate; + desc->dwMaxBitRate = frm->frame.dw_max_bit_rate; + desc->dwDefaultFrameInterval = frm->frame.dw_default_frame_interval; + desc->bFrameIntervalType = frm->frame.b_frame_interval_type; + desc->dwBytesPerLine = frm->frame.dw_bytes_perline; + + return 0; +} + /* * Fill an array of streaming descriptors. * @@ -2123,6 +2438,15 @@ static int __uvcg_fill_strm(void *priv1, void *priv2, void *priv3, int n, m->desc.bNumFrameDescriptors = fmt->num_frames; memcpy(*dest, &m->desc, sizeof(m->desc)); *dest += sizeof(m->desc); + } else if (fmt->type == UVCG_FRAMEBASED) { + struct uvcg_framebased *f = + container_of(fmt, struct uvcg_framebased, + fmt); + + f->desc.bFormatIndex = n + 1; + f->desc.bNumFrameDescriptors = fmt->num_frames; + memcpy(*dest, &f->desc, sizeof(f->desc)); + *dest += sizeof(f->desc); } else { return -EINVAL; } @@ -2132,8 +2456,11 @@ static int __uvcg_fill_strm(void *priv1, void *priv2, void *priv3, int n, struct uvcg_frame *frm = priv1; struct uvc_descriptor_header *h = *dest; - sz = sizeof(frm->frame); - memcpy(*dest, &frm->frame, sz); + sz = sizeof(frm->frame) - 4; + if (frm->fmt_type != UVCG_FRAMEBASED) + memcpy(*dest, &frm->frame, sz); + else + __uvcg_copy_framebased_desc(*dest, frm, sz); *dest += sz; sz = frm->frame.b_frame_interval_type * sizeof(*frm->dw_frame_interval); @@ -2145,6 +2472,9 @@ static int __uvcg_fill_strm(void *priv1, void *priv2, void *priv3, int n, else if (frm->fmt_type == UVCG_MJPEG) h->bLength = UVC_DT_FRAME_MJPEG_SIZE( frm->frame.b_frame_interval_type); + else if (frm->fmt_type == UVCG_FRAMEBASED) + h->bLength = UVC_DT_FRAME_FRAMEBASED_SIZE( + frm->frame.b_frame_interval_type); } break; } @@ -2357,6 +2687,7 @@ static const struct uvcg_config_group_type uvcg_streaming_grp_type = { &uvcg_streaming_header_grp_type, &uvcg_uncompressed_grp_type, &uvcg_mjpeg_grp_type, + &uvcg_framebased_grp_type, &uvcg_color_matching_grp_type, &uvcg_streaming_class_grp_type, NULL, diff --git a/drivers/usb/gadget/function/uvc_v4l2.c b/drivers/usb/gadget/function/uvc_v4l2.c index 93d0d0d2f75f..49f1f2ad134e 100644 --- a/drivers/usb/gadget/function/uvc_v4l2.c +++ b/drivers/usb/gadget/function/uvc_v4l2.c @@ -58,6 +58,7 @@ struct uvc_format { static struct uvc_format uvc_formats[] = { { 16, V4L2_PIX_FMT_YUYV }, { 0, V4L2_PIX_FMT_MJPEG }, + { 0, V4L2_PIX_FMT_H264 }, { 12, V4L2_PIX_FMT_YUV420 }, { 8, V4L2_PIX_FMT_GREY }, }; diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h index 9e2ad3b81690..e06623fa5b80 100644 --- a/include/linux/if_bridge.h +++ b/include/linux/if_bridge.h @@ -162,5 +162,9 @@ extern br_notify_hook_t __rcu *br_notify_hook; typedef int (br_multicast_handle_hook_t)(const struct net_bridge_port *src, struct sk_buff *skb); extern br_multicast_handle_hook_t __rcu *br_multicast_handle_hook; +typedef struct net_bridge_port *br_get_dst_hook_t( + const struct net_bridge_port *src, + struct sk_buff **skb); +extern br_get_dst_hook_t __rcu *br_get_dst_hook; #endif #endif diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 7d048d775eff..04fde5ea195b 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -2554,6 +2554,8 @@ enum netdev_cmd { NETDEV_CVLAN_FILTER_DROP_INFO, NETDEV_SVLAN_FILTER_PUSH_INFO, NETDEV_SVLAN_FILTER_DROP_INFO, + NETDEV_BR_JOIN, + NETDEV_BR_LEAVE, }; const char *netdev_cmd_to_name(enum netdev_cmd cmd); diff --git a/include/uapi/linux/usb/video.h b/include/uapi/linux/usb/video.h index c58854fb7d94..c79b6049d9d7 100644 --- a/include/uapi/linux/usb/video.h +++ b/include/uapi/linux/usb/video.h @@ -597,5 +597,63 @@ struct UVC_FRAME_MJPEG(n) { \ __le32 dwFrameInterval[n]; \ } __attribute__ ((packed)) +/* Frame Based Payload - 3.1.1. Frame Based Video Format Descriptor */ +struct uvc_format_framebased { + __u8 bLength; + __u8 bDescriptorType; + __u8 bDescriptorSubType; + __u8 bFormatIndex; + __u8 bNumFrameDescriptors; + __u8 guidFormat[16]; + __u8 bBitsPerPixel; + __u8 bDefaultFrameIndex; + __u8 bAspectRatioX; + __u8 bAspectRatioY; + __u8 bmInterfaceFlags; + __u8 bCopyProtect; + __u8 bVariableSize; +} __attribute__((__packed__)); + +#define UVC_DT_FORMAT_FRAMEBASED_SIZE 28 + +/* Frame Based Payload - 3.1.2. Frame Based Video Frame Descriptor */ +struct uvc_frame_framebased { + __u8 bLength; + __u8 bDescriptorType; + __u8 bDescriptorSubType; + __u8 bFrameIndex; + __u8 bmCapabilities; + __u16 wWidth; + __u16 wHeight; + __u32 dwMinBitRate; + __u32 dwMaxBitRate; + __u32 dwDefaultFrameInterval; + __u8 bFrameIntervalType; + __u32 dwBytesPerLine; + __u32 dwFrameInterval[]; +} __attribute__((__packed__)); + +#define UVC_DT_FRAME_FRAMEBASED_SIZE(n) (26+4*(n)) + +#define UVC_FRAME_FRAMEBASED(n) \ + uvc_frame_framebased_##n + +#define DECLARE_UVC_FRAME_FRAMEBASED(n) \ + struct UVC_FRAME_FRAMEBASED(n) { \ + __u8 bLength; \ + __u8 bDescriptorType; \ + __u8 bDescriptorSubType; \ + __u8 bFrameIndex; \ + __u8 bmCapabilities; \ + __u16 wWidth; \ + __u16 wHeight; \ + __u32 dwMinBitRate; \ + __u32 dwMaxBitRate; \ + __u32 dwDefaultFrameInterval; \ + __u8 bFrameIntervalType; \ + __u32 dwBytesPerLine; \ + __u32 dwFrameInterval[n]; \ + } __attribute__ ((packed)) + #endif /* __LINUX_USB_VIDEO_H */ diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c index 00438505c175..ec4dee64357b 100644 --- a/net/bridge/br_device.c +++ b/net/bridge/br_device.c @@ -34,6 +34,10 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev) const struct nf_br_ops *nf_ops; const unsigned char *dest; u16 vid = 0; +#ifdef CONFIG_HYFI_BRIDGE_HOOKS + struct net_bridge_port *pdst; + br_get_dst_hook_t *get_dst_hook; +#endif if (unlikely(!pskb_may_pull(skb, ETH_HLEN))) { kfree_skb(skb); @@ -82,6 +86,10 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev) br_do_suppress_nd(skb, br, vid, NULL, msg); } +#ifdef CONFIG_HYFI_BRIDGE_HOOKS + get_dst_hook = rcu_dereference(br_get_dst_hook); +#endif + dest = eth_hdr(skb)->h_dest; if (is_broadcast_ether_addr(dest)) { br_flood(br, skb, BR_PKT_BROADCAST, false, true); @@ -107,11 +115,24 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev) br_multicast_flood(mdst, skb, false, true); else br_flood(br, skb, BR_PKT_MULTICAST, false, true); - } else if ((dst = br_fdb_find_rcu(br, dest, vid)) != NULL) { - br_forward(dst->dst, skb, false, true); } else { - br_flood(br, skb, BR_PKT_UNICAST, false, true); +#ifdef CONFIG_HYFI_BRIDGE_HOOKS + pdst = __br_get(get_dst_hook, NULL, NULL, &skb); + if (pdst) { + if (!skb) + goto out; + br_forward(pdst, skb, false, true); + } else +#endif + { + dst = br_fdb_find_rcu(br, dest, vid); + if (dst) + br_forward(dst->dst, skb, false, true); + else + br_flood(br, skb, BR_PKT_UNICAST, false, true); + } } + out: rcu_read_unlock(); return NETDEV_TX_OK; diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index ea0ddd513cc1..a5565b7dfb06 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c @@ -695,6 +695,7 @@ int br_add_if(struct net_bridge *br, struct net_device *dev, br_set_gso_limits(br); kobject_uevent(&p->kobj, KOBJ_ADD); + call_netdevice_notifiers(NETDEV_BR_JOIN, dev); return 0; @@ -732,6 +733,8 @@ int br_del_if(struct net_bridge *br, struct net_device *dev) if (!p || p->br != br) return -EINVAL; + call_netdevice_notifiers(NETDEV_BR_LEAVE, dev); + /* Since more than one interface can be attached to a bridge, * there still maybe an alternate path for netconsole to use; * therefore there is no reason for a NETDEV_RELEASE event. diff --git a/net/bridge/br_input.c b/net/bridge/br_input.c index ace461e94830..02dbaf13f591 100644 --- a/net/bridge/br_input.c +++ b/net/bridge/br_input.c @@ -33,6 +33,11 @@ br_netif_receive_skb(struct net *net, struct sock *sk, struct sk_buff *skb) /* Hook for external Multicast handler */ br_multicast_handle_hook_t __rcu *br_multicast_handle_hook __read_mostly; EXPORT_SYMBOL(br_multicast_handle_hook); + +/* Hook for external forwarding logic */ +br_get_dst_hook_t __rcu *br_get_dst_hook __read_mostly; +EXPORT_SYMBOL_GPL(br_get_dst_hook); + #endif int br_pass_frame_up(struct sk_buff *skb) @@ -94,6 +99,8 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb struct net_bridge *br; #ifdef CONFIG_HYFI_BRIDGE_HOOKS br_multicast_handle_hook_t *multicast_handle_hook; + struct net_bridge_port *pdst = NULL; + br_get_dst_hook_t *get_dst_hook = rcu_dereference(br_get_dst_hook); #endif u16 vid = 0; @@ -168,7 +175,17 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb } break; case BR_PKT_UNICAST: - dst = br_fdb_find_rcu(br, eth_hdr(skb)->h_dest, vid); +#ifdef CONFIG_HYFI_BRIDGE_HOOKS + pdst = __br_get(get_dst_hook, NULL, p, &skb); + if (pdst) { + if (!skb) + goto out; + } else +#endif + { + dst = br_fdb_find_rcu(br, eth_hdr(skb)->h_dest, vid); + } + break; default: break; } diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index c7130fff57a0..023ecc1f4494 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -195,6 +195,9 @@ struct net_bridge_fdb_entry { struct net_bridge_fdb_key key; struct hlist_node fdb_node; + unsigned char is_local:1, + is_static:1; + unsigned long flags; unsigned char offloaded:1; diff --git a/net/core/dev.c b/net/core/dev.c index aad29ac5ac15..d4d84160b795 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1521,7 +1521,7 @@ const char *netdev_cmd_to_name(enum netdev_cmd cmd) N(UDP_TUNNEL_DROP_INFO) N(CHANGE_TX_QUEUE_LEN) N(CVLAN_FILTER_PUSH_INFO) N(CVLAN_FILTER_DROP_INFO) N(SVLAN_FILTER_PUSH_INFO) N(SVLAN_FILTER_DROP_INFO) - N(PRE_CHANGEADDR) + N(PRE_CHANGEADDR) N(BR_JOIN) N(BR_LEAVE) } #undef N return "UNKNOWN_NETDEV_EVENT";