diff options
| author | Mark Brown <broonie@kernel.org> | 2026-01-06 18:48:26 +0000 |
|---|---|---|
| committer | Mark Brown <broonie@kernel.org> | 2026-01-06 18:48:26 +0000 |
| commit | 49d3bd9fe2d93ec6eaf7d550e2eb9608b401c915 (patch) | |
| tree | dd4bd4b6c37f81f50a9f5b8dfff546cb4ee0ca95 /drivers | |
| parent | 04b61513dfe40f80f0dcc795003637b510522b3c (diff) | |
| parent | 9bf0bd7bdea6c402007ffb784dd0c0f704aa2310 (diff) | |
ASoC: nau8821: Fixes and driver cleanup
Merge series from Cristian Ciocaltea <cristian.ciocaltea@collabora.com>:
This series provides several fixes and cleanup patches for the Nuvoton
NAU88L21 audio codec driver.
Testing and validation has been performed on Valve Steam Deck.
Diffstat (limited to 'drivers')
169 files changed, 1362 insertions, 918 deletions
diff --git a/drivers/block/rnbd/rnbd-clt.h b/drivers/block/rnbd/rnbd-clt.h index a48e040abe63..fbc1ed766025 100644 --- a/drivers/block/rnbd/rnbd-clt.h +++ b/drivers/block/rnbd/rnbd-clt.h @@ -112,7 +112,7 @@ struct rnbd_clt_dev { struct rnbd_queue *hw_queues; u32 device_id; /* local Idr index - used to track minor number allocations. */ - u32 clt_device_id; + int clt_device_id; struct mutex lock; enum rnbd_clt_dev_state dev_state; refcount_t refcount; diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c index cfd2132410dd..837fedb02e0d 100644 --- a/drivers/block/ublk_drv.c +++ b/drivers/block/ublk_drv.c @@ -237,6 +237,7 @@ struct ublk_device { bool canceling; pid_t ublksrv_tgid; struct delayed_work exit_work; + struct work_struct partition_scan_work; struct ublk_queue *queues[]; }; @@ -254,6 +255,20 @@ static inline struct request *__ublk_check_and_get_req(struct ublk_device *ub, u16 q_id, u16 tag, struct ublk_io *io, size_t offset); static inline unsigned int ublk_req_build_flags(struct request *req); +static void ublk_partition_scan_work(struct work_struct *work) +{ + struct ublk_device *ub = + container_of(work, struct ublk_device, partition_scan_work); + + if (WARN_ON_ONCE(!test_and_clear_bit(GD_SUPPRESS_PART_SCAN, + &ub->ub_disk->state))) + return; + + mutex_lock(&ub->ub_disk->open_mutex); + bdev_disk_changed(ub->ub_disk, false); + mutex_unlock(&ub->ub_disk->open_mutex); +} + static inline struct ublksrv_io_desc * ublk_get_iod(const struct ublk_queue *ubq, unsigned tag) { @@ -1607,8 +1622,7 @@ static bool ublk_check_and_reset_active_ref(struct ublk_device *ub) { int i, j; - if (!(ub->dev_info.flags & (UBLK_F_SUPPORT_ZERO_COPY | - UBLK_F_AUTO_BUF_REG))) + if (!ublk_dev_need_req_ref(ub)) return false; for (i = 0; i < ub->dev_info.nr_hw_queues; i++) { @@ -2027,6 +2041,7 @@ static void ublk_stop_dev(struct ublk_device *ub) mutex_lock(&ub->mutex); ublk_stop_dev_unlocked(ub); mutex_unlock(&ub->mutex); + flush_work(&ub->partition_scan_work); ublk_cancel_dev(ub); } @@ -2955,9 +2970,17 @@ static int ublk_ctrl_start_dev(struct ublk_device *ub, ublk_apply_params(ub); - /* don't probe partitions if any daemon task is un-trusted */ - if (ub->unprivileged_daemons) - set_bit(GD_SUPPRESS_PART_SCAN, &disk->state); + /* + * Suppress partition scan to avoid potential IO hang. + * + * If ublk server error occurs during partition scan, the IO may + * wait while holding ub->mutex, which can deadlock with other + * operations that need the mutex. Defer partition scan to async + * work. + * For unprivileged daemons, keep GD_SUPPRESS_PART_SCAN set + * permanently. + */ + set_bit(GD_SUPPRESS_PART_SCAN, &disk->state); ublk_get_device(ub); ub->dev_info.state = UBLK_S_DEV_LIVE; @@ -2974,6 +2997,10 @@ static int ublk_ctrl_start_dev(struct ublk_device *ub, set_bit(UB_STATE_USED, &ub->state); + /* Schedule async partition scan for trusted daemons */ + if (!ub->unprivileged_daemons) + schedule_work(&ub->partition_scan_work); + out_put_cdev: if (ret) { ublk_detach_disk(ub); @@ -3139,6 +3166,7 @@ static int ublk_ctrl_add_dev(const struct ublksrv_ctrl_cmd *header) mutex_init(&ub->mutex); spin_lock_init(&ub->lock); mutex_init(&ub->cancel_mutex); + INIT_WORK(&ub->partition_scan_work, ublk_partition_scan_work); ret = ublk_alloc_dev_number(ub, header->dev_id); if (ret < 0) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 8ed3883ab8ee..ded09e94d296 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -4052,7 +4052,7 @@ static int btusb_probe(struct usb_interface *intf, return -ENODEV; } - data = devm_kzalloc(&intf->dev, sizeof(*data), GFP_KERNEL); + data = kzalloc(sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; @@ -4075,8 +4075,10 @@ static int btusb_probe(struct usb_interface *intf, } } - if (!data->intr_ep || !data->bulk_tx_ep || !data->bulk_rx_ep) + if (!data->intr_ep || !data->bulk_tx_ep || !data->bulk_rx_ep) { + kfree(data); return -ENODEV; + } if (id->driver_info & BTUSB_AMP) { data->cmdreq_type = USB_TYPE_CLASS | 0x01; @@ -4131,8 +4133,10 @@ static int btusb_probe(struct usb_interface *intf, data->recv_acl = hci_recv_frame; hdev = hci_alloc_dev_priv(priv_size); - if (!hdev) + if (!hdev) { + kfree(data); return -ENOMEM; + } hdev->bus = HCI_USB; hci_set_drvdata(hdev, data); @@ -4406,6 +4410,7 @@ out_free_dev: if (data->reset_gpio) gpiod_put(data->reset_gpio); hci_free_dev(hdev); + kfree(data); return err; } @@ -4454,6 +4459,7 @@ static void btusb_disconnect(struct usb_interface *intf) } hci_free_dev(hdev); + kfree(data); } #ifdef CONFIG_PM diff --git a/drivers/crypto/hisilicon/qm.c b/drivers/crypto/hisilicon/qm.c index f8bfff5dd0bd..d47bf06a90f7 100644 --- a/drivers/crypto/hisilicon/qm.c +++ b/drivers/crypto/hisilicon/qm.c @@ -991,7 +991,7 @@ static void qm_get_complete_eqe_num(struct hisi_qm *qm) return; poll_data = &qm->poll_data[cqn]; - while (QM_EQE_PHASE(dw0) != qm->status.eqc_phase) { + do { poll_data->qp_finish_id[eqe_num] = dw0 & QM_EQE_CQN_MASK; eqe_num++; @@ -1004,11 +1004,10 @@ static void qm_get_complete_eqe_num(struct hisi_qm *qm) qm->status.eq_head++; } - if (eqe_num == (eq_depth >> 1) - 1) - break; - dw0 = le32_to_cpu(eqe->dw0); - } + if (QM_EQE_PHASE(dw0) != qm->status.eqc_phase) + break; + } while (eqe_num < (eq_depth >> 1) - 1); poll_data->eqe_num = eqe_num; queue_work(qm->wq, &poll_data->work); diff --git a/drivers/firewire/nosy.c b/drivers/firewire/nosy.c index ea31ac7ac1ca..e59053738a43 100644 --- a/drivers/firewire/nosy.c +++ b/drivers/firewire/nosy.c @@ -36,6 +36,8 @@ static char driver_name[] = KBUILD_MODNAME; +#define RCV_BUFFER_SIZE (16 * 1024) + /* this is the physical layout of a PCL, its size is 128 bytes */ struct pcl { __le32 next; @@ -517,16 +519,14 @@ remove_card(struct pci_dev *dev) lynx->rcv_start_pcl, lynx->rcv_start_pcl_bus); dma_free_coherent(&lynx->pci_device->dev, sizeof(struct pcl), lynx->rcv_pcl, lynx->rcv_pcl_bus); - dma_free_coherent(&lynx->pci_device->dev, PAGE_SIZE, lynx->rcv_buffer, - lynx->rcv_buffer_bus); + dma_free_coherent(&lynx->pci_device->dev, RCV_BUFFER_SIZE, + lynx->rcv_buffer, lynx->rcv_buffer_bus); iounmap(lynx->registers); pci_disable_device(dev); lynx_put(lynx); } -#define RCV_BUFFER_SIZE (16 * 1024) - static int add_card(struct pci_dev *dev, const struct pci_device_id *unused) { @@ -680,7 +680,7 @@ fail_deallocate_buffers: dma_free_coherent(&lynx->pci_device->dev, sizeof(struct pcl), lynx->rcv_pcl, lynx->rcv_pcl_bus); if (lynx->rcv_buffer) - dma_free_coherent(&lynx->pci_device->dev, PAGE_SIZE, + dma_free_coherent(&lynx->pci_device->dev, RCV_BUFFER_SIZE, lynx->rcv_buffer, lynx->rcv_buffer_bus); iounmap(lynx->registers); diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index a9070d00b833..55452e61af31 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c @@ -73,6 +73,7 @@ struct mm_struct efi_mm = { MMAP_LOCK_INITIALIZER(efi_mm) .page_table_lock = __SPIN_LOCK_UNLOCKED(efi_mm.page_table_lock), .mmlist = LIST_HEAD_INIT(efi_mm.mmlist), + .user_ns = &init_user_ns, .cpu_bitmap = { [BITS_TO_LONGS(NR_CPUS)] = 0}, #ifdef CONFIG_SCHED_MM_CID .mm_cid.lock = __RAW_SPIN_LOCK_UNLOCKED(efi_mm.mm_cid.lock), diff --git a/drivers/firmware/efi/libstub/gop.c b/drivers/firmware/efi/libstub/gop.c index 72d74436a7a4..80dc8cfeb33e 100644 --- a/drivers/firmware/efi/libstub/gop.c +++ b/drivers/firmware/efi/libstub/gop.c @@ -513,15 +513,15 @@ efi_status_t efi_setup_graphics(struct screen_info *si, struct edid_info *edid) status = efi_bs_call(handle_protocol, handle, &EFI_EDID_ACTIVE_PROTOCOL_GUID, (void **)&active_edid); if (status == EFI_SUCCESS) { - gop_size_of_edid = active_edid->size_of_edid; - gop_edid = active_edid->edid; + gop_size_of_edid = efi_table_attr(active_edid, size_of_edid); + gop_edid = efi_table_attr(active_edid, edid); } else { status = efi_bs_call(handle_protocol, handle, &EFI_EDID_DISCOVERED_PROTOCOL_GUID, (void **)&discovered_edid); if (status == EFI_SUCCESS) { - gop_size_of_edid = discovered_edid->size_of_edid; - gop_edid = discovered_edid->edid; + gop_size_of_edid = efi_table_attr(discovered_edid, size_of_edid); + gop_edid = efi_table_attr(discovered_edid, edid); } } diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c index 93b9cff89080..f13eb5f36e8a 100644 --- a/drivers/gpu/drm/drm_gem_shmem_helper.c +++ b/drivers/gpu/drm/drm_gem_shmem_helper.c @@ -96,7 +96,8 @@ err_release: /** * drm_gem_shmem_init - Initialize an allocated object. * @dev: DRM device - * @obj: The allocated shmem GEM object. + * @shmem: The allocated shmem GEM object. + * @size: Buffer size in bytes * * Returns: * 0 on success, or a negative error code on failure. @@ -895,4 +896,4 @@ EXPORT_SYMBOL_GPL(drm_gem_shmem_prime_import_no_map); MODULE_DESCRIPTION("DRM SHMEM memory-management helpers"); MODULE_IMPORT_NS("DMA_BUF"); -MODULE_LICENSE("GPL v2"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/drm_pagemap.c b/drivers/gpu/drm/drm_pagemap.c index 37d7cfbbb3e8..06c1bd8fc4d1 100644 --- a/drivers/gpu/drm/drm_pagemap.c +++ b/drivers/gpu/drm/drm_pagemap.c @@ -3,6 +3,7 @@ * Copyright © 2024-2025 Intel Corporation */ +#include <linux/dma-fence.h> #include <linux/dma-mapping.h> #include <linux/migrate.h> #include <linux/pagemap.h> @@ -408,10 +409,14 @@ int drm_pagemap_migrate_to_devmem(struct drm_pagemap_devmem *devmem_allocation, drm_pagemap_get_devmem_page(page, zdd); } - err = ops->copy_to_devmem(pages, pagemap_addr, npages); + err = ops->copy_to_devmem(pages, pagemap_addr, npages, + devmem_allocation->pre_migrate_fence); if (err) goto err_finalize; + dma_fence_put(devmem_allocation->pre_migrate_fence); + devmem_allocation->pre_migrate_fence = NULL; + /* Upon success bind devmem allocation to range and zdd */ devmem_allocation->timeslice_expiration = get_jiffies_64() + msecs_to_jiffies(timeslice_ms); @@ -596,7 +601,7 @@ retry: for (i = 0; i < npages; ++i) pages[i] = migrate_pfn_to_page(src[i]); - err = ops->copy_to_ram(pages, pagemap_addr, npages); + err = ops->copy_to_ram(pages, pagemap_addr, npages, NULL); if (err) goto err_finalize; @@ -732,7 +737,7 @@ static int __drm_pagemap_migrate_to_ram(struct vm_area_struct *vas, for (i = 0; i < npages; ++i) pages[i] = migrate_pfn_to_page(migrate.src[i]); - err = ops->copy_to_ram(pages, pagemap_addr, npages); + err = ops->copy_to_ram(pages, pagemap_addr, npages, NULL); if (err) goto err_finalize; @@ -813,11 +818,14 @@ EXPORT_SYMBOL_GPL(drm_pagemap_pagemap_ops_get); * @ops: Pointer to the operations structure for GPU SVM device memory * @dpagemap: The struct drm_pagemap we're allocating from. * @size: Size of device memory allocation + * @pre_migrate_fence: Fence to wait for or pipeline behind before migration starts. + * (May be NULL). */ void drm_pagemap_devmem_init(struct drm_pagemap_devmem *devmem_allocation, struct device *dev, struct mm_struct *mm, const struct drm_pagemap_devmem_ops *ops, - struct drm_pagemap *dpagemap, size_t size) + struct drm_pagemap *dpagemap, size_t size, + struct dma_fence *pre_migrate_fence) { init_completion(&devmem_allocation->detached); devmem_allocation->dev = dev; @@ -825,6 +833,7 @@ void drm_pagemap_devmem_init(struct drm_pagemap_devmem *devmem_allocation, devmem_allocation->ops = ops; devmem_allocation->dpagemap = dpagemap; devmem_allocation->size = size; + devmem_allocation->pre_migrate_fence = pre_migrate_fence; } EXPORT_SYMBOL_GPL(drm_pagemap_devmem_init); diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c index b057c2fa03a4..d49e96f9be51 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c @@ -951,13 +951,13 @@ static int eb_lookup_vmas(struct i915_execbuffer *eb) vma = eb_lookup_vma(eb, eb->exec[i].handle); if (IS_ERR(vma)) { err = PTR_ERR(vma); - goto err; + return err; } err = eb_validate_vma(eb, &eb->exec[i], vma); if (unlikely(err)) { i915_vma_put(vma); - goto err; + return err; } err = eb_add_vma(eb, ¤t_batch, i, vma); @@ -966,19 +966,8 @@ static int eb_lookup_vmas(struct i915_execbuffer *eb) if (i915_gem_object_is_userptr(vma->obj)) { err = i915_gem_object_userptr_submit_init(vma->obj); - if (err) { - if (i + 1 < eb->buffer_count) { - /* - * Execbuffer code expects last vma entry to be NULL, - * since we already initialized this entry, - * set the next value to NULL or we mess up - * cleanup handling. - */ - eb->vma[i + 1].vma = NULL; - } - + if (err) return err; - } eb->vma[i].flags |= __EXEC_OBJECT_USERPTR_INIT; eb->args->flags |= __EXEC_USERPTR_USED; @@ -986,10 +975,6 @@ static int eb_lookup_vmas(struct i915_execbuffer *eb) } return 0; - -err: - eb->vma[i].vma = NULL; - return err; } static int eb_lock_vmas(struct i915_execbuffer *eb) @@ -3375,7 +3360,8 @@ i915_gem_do_execbuffer(struct drm_device *dev, eb.exec = exec; eb.vma = (struct eb_vma *)(exec + args->buffer_count + 1); - eb.vma[0].vma = NULL; + memset(eb.vma, 0, (args->buffer_count + 1) * sizeof(struct eb_vma)); + eb.batch_pool = NULL; eb.invalid_flags = __EXEC_OBJECT_UNKNOWN_FLAGS; @@ -3584,7 +3570,18 @@ i915_gem_execbuffer2_ioctl(struct drm_device *dev, void *data, if (err) return err; - /* Allocate extra slots for use by the command parser */ + /* + * Allocate extra slots for use by the command parser. + * + * Note that this allocation handles two different arrays (the + * exec2_list array, and the eventual eb.vma array introduced in + * i915_gem_do_execbuffer()), that reside in virtually contiguous + * memory. Also note that the allocation intentionally doesn't fill the + * area with zeros, because the exec2_list part doesn't need to be, as + * it's immediately overwritten by user data a few lines below. + * However, the eb.vma part is explicitly zeroed later in + * i915_gem_do_execbuffer(). + */ exec2_list = kvmalloc_array(count + 2, eb_element_size(), __GFP_NOWARN | GFP_KERNEL); if (exec2_list == NULL) { diff --git a/drivers/gpu/drm/imagination/pvr_gem.c b/drivers/gpu/drm/imagination/pvr_gem.c index a66cf082af24..c07c9a915190 100644 --- a/drivers/gpu/drm/imagination/pvr_gem.c +++ b/drivers/gpu/drm/imagination/pvr_gem.c @@ -28,6 +28,16 @@ static void pvr_gem_object_free(struct drm_gem_object *obj) drm_gem_shmem_object_free(obj); } +static struct dma_buf *pvr_gem_export(struct drm_gem_object *obj, int flags) +{ + struct pvr_gem_object *pvr_obj = gem_to_pvr_gem(obj); + + if (pvr_obj->flags & DRM_PVR_BO_PM_FW_PROTECT) + return ERR_PTR(-EPERM); + + return drm_gem_prime_export(obj, flags); +} + static int pvr_gem_mmap(struct drm_gem_object *gem_obj, struct vm_area_struct *vma) { struct pvr_gem_object *pvr_obj = gem_to_pvr_gem(gem_obj); @@ -42,6 +52,7 @@ static int pvr_gem_mmap(struct drm_gem_object *gem_obj, struct vm_area_struct *v static const struct drm_gem_object_funcs pvr_gem_object_funcs = { .free = pvr_gem_object_free, .print_info = drm_gem_shmem_object_print_info, + .export = pvr_gem_export, .pin = drm_gem_shmem_object_pin, .unpin = drm_gem_shmem_object_unpin, .get_sg_table = drm_gem_shmem_object_get_sg_table, diff --git a/drivers/gpu/drm/msm/adreno/a6xx_catalog.c b/drivers/gpu/drm/msm/adreno/a6xx_catalog.c index 29107b362346..ac9a95aab2fb 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_catalog.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_catalog.c @@ -1376,7 +1376,6 @@ static const uint32_t a7xx_pwrup_reglist_regs[] = { REG_A6XX_UCHE_MODE_CNTL, REG_A6XX_RB_NC_MODE_CNTL, REG_A6XX_RB_CMP_DBG_ECO_CNTL, - REG_A7XX_GRAS_NC_MODE_CNTL, REG_A6XX_RB_CONTEXT_SWITCH_GMEM_SAVE_RESTORE_ENABLE, REG_A6XX_UCHE_GBIF_GX_CONFIG, REG_A6XX_UCHE_CLIENT_PF, @@ -1392,6 +1391,7 @@ static const u32 a750_ifpc_reglist_regs[] = { REG_A6XX_TPL1_BICUBIC_WEIGHTS_TABLE(2), REG_A6XX_TPL1_BICUBIC_WEIGHTS_TABLE(3), REG_A6XX_TPL1_BICUBIC_WEIGHTS_TABLE(4), + REG_A6XX_RBBM_PERFCTR_CNTL, REG_A6XX_TPL1_NC_MODE_CNTL, REG_A6XX_SP_NC_MODE_CNTL, REG_A6XX_CP_DBG_ECO_CNTL, @@ -1448,6 +1448,12 @@ static const u32 a750_ifpc_reglist_regs[] = { DECLARE_ADRENO_REGLIST_LIST(a750_ifpc_reglist); +static const struct adreno_reglist_pipe a7xx_dyn_pwrup_reglist_regs[] = { + { REG_A7XX_GRAS_NC_MODE_CNTL, 0, BIT(PIPE_BV) | BIT(PIPE_BR) }, +}; + +DECLARE_ADRENO_REGLIST_PIPE_LIST(a7xx_dyn_pwrup_reglist); + static const struct adreno_info a7xx_gpus[] = { { .chip_ids = ADRENO_CHIP_IDS(0x07000200), @@ -1491,6 +1497,7 @@ static const struct adreno_info a7xx_gpus[] = { .hwcg = a730_hwcg, .protect = &a730_protect, .pwrup_reglist = &a7xx_pwrup_reglist, + .dyn_pwrup_reglist = &a7xx_dyn_pwrup_reglist, .gbif_cx = a640_gbif, .gmu_cgc_mode = 0x00020000, }, @@ -1513,6 +1520,7 @@ static const struct adreno_info a7xx_gpus[] = { .hwcg = a740_hwcg, .protect = &a730_protect, .pwrup_reglist = &a7xx_pwrup_reglist, + .dyn_pwrup_reglist = &a7xx_dyn_pwrup_reglist, .gbif_cx = a640_gbif, .gmu_chipid = 0x7020100, .gmu_cgc_mode = 0x00020202, @@ -1547,6 +1555,7 @@ static const struct adreno_info a7xx_gpus[] = { .hwcg = a740_hwcg, .protect = &a730_protect, .pwrup_reglist = &a7xx_pwrup_reglist, + .dyn_pwrup_reglist = &a7xx_dyn_pwrup_reglist, .ifpc_reglist = &a750_ifpc_reglist, .gbif_cx = a640_gbif, .gmu_chipid = 0x7050001, @@ -1589,6 +1598,7 @@ static const struct adreno_info a7xx_gpus[] = { .a6xx = &(const struct a6xx_info) { .protect = &a730_protect, .pwrup_reglist = &a7xx_pwrup_reglist, + .dyn_pwrup_reglist = &a7xx_dyn_pwrup_reglist, .ifpc_reglist = &a750_ifpc_reglist, .gbif_cx = a640_gbif, .gmu_chipid = 0x7090100, @@ -1623,6 +1633,7 @@ static const struct adreno_info a7xx_gpus[] = { .hwcg = a740_hwcg, .protect = &a730_protect, .pwrup_reglist = &a7xx_pwrup_reglist, + .dyn_pwrup_reglist = &a7xx_dyn_pwrup_reglist, .gbif_cx = a640_gbif, .gmu_chipid = 0x70f0000, .gmu_cgc_mode = 0x00020222, diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c index 0200a7e71cdf..2129d230a92b 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c @@ -849,9 +849,16 @@ static void a6xx_set_ubwc_config(struct msm_gpu *gpu) min_acc_len_64b << 3 | hbb_lo << 1 | ubwc_mode); - if (adreno_is_a7xx(adreno_gpu)) - gpu_write(gpu, REG_A7XX_GRAS_NC_MODE_CNTL, - FIELD_PREP(GENMASK(8, 5), hbb_lo)); + if (adreno_is_a7xx(adreno_gpu)) { + for (u32 pipe_id = PIPE_BR; pipe_id <= PIPE_BV; pipe_id++) { + gpu_write(gpu, REG_A7XX_CP_APERTURE_CNTL_HOST, + A7XX_CP_APERTURE_CNTL_HOST_PIPE(pipe_id)); + gpu_write(gpu, REG_A7XX_GRAS_NC_MODE_CNTL, + FIELD_PREP(GENMASK(8, 5), hbb_lo)); + } + gpu_write(gpu, REG_A7XX_CP_APERTURE_CNTL_HOST, + A7XX_CP_APERTURE_CNTL_HOST_PIPE(PIPE_NONE)); + } gpu_write(gpu, REG_A6XX_UCHE_MODE_CNTL, min_acc_len_64b << 23 | hbb_lo << 21); @@ -865,23 +872,27 @@ static void a7xx_patch_pwrup_reglist(struct msm_gpu *gpu) struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu); struct a6xx_gpu *a6xx_gpu = to_a6xx_gpu(adreno_gpu); const struct adreno_reglist_list *reglist; + const struct adreno_reglist_pipe_list *dyn_pwrup_reglist; void *ptr = a6xx_gpu->pwrup_reglist_ptr; struct cpu_gpu_lock *lock = ptr; u32 *dest = (u32 *)&lock->regs[0]; + u32 dyn_pwrup_reglist_count = 0; int i; lock->gpu_req = lock->cpu_req = lock->turn = 0; reglist = adreno_gpu->info->a6xx->ifpc_reglist; - lock->ifpc_list_len = reglist->count; + if (reglist) { + lock->ifpc_list_len = reglist->count; - /* - * For each entry in each of the lists, write the offset and the current - * register value into the GPU buffer - */ - for (i = 0; i < reglist->count; i++) { - *dest++ = reglist->regs[i]; - *dest++ = gpu_read(gpu, reglist->regs[i]); + /* + * For each entry in each of the lists, write the offset and the current + * register value into the GPU buffer + */ + for (i = 0; i < reglist->count; i++) { + *dest++ = reglist->regs[i]; + *dest++ = gpu_read(gpu, reglist->regs[i]); + } } reglist = adreno_gpu->info->a6xx->pwrup_reglist; @@ -907,7 +918,24 @@ static void a7xx_patch_pwrup_reglist(struct msm_gpu *gpu) * (<aperture, shifted 12 bits> <address> <data>), and the length is * stored as number for triplets in dynamic_list_len. */ - lock->dynamic_list_len = 0; + dyn_pwrup_reglist = adreno_gpu->info->a6xx->dyn_pwrup_reglist; + if (dyn_pwrup_reglist) { + for (u32 pipe_id = PIPE_BR; pipe_id <= PIPE_BV; pipe_id++) { + gpu_write(gpu, REG_A7XX_CP_APERTURE_CNTL_HOST, + A7XX_CP_APERTURE_CNTL_HOST_PIPE(pipe_id)); + for (i = 0; i < dyn_pwrup_reglist->count; i++) { + if ((dyn_pwrup_reglist->regs[i].pipe & BIT(pipe_id)) == 0) + continue; + *dest++ = A7XX_CP_APERTURE_CNTL_HOST_PIPE(pipe_id); + *dest++ = dyn_pwrup_reglist->regs[i].offset; + *dest++ = gpu_read(gpu, dyn_pwrup_reglist->regs[i].offset); + dyn_pwrup_reglist_count++; + } + } + gpu_write(gpu, REG_A7XX_CP_APERTURE_CNTL_HOST, + A7XX_CP_APERTURE_CNTL_HOST_PIPE(PIPE_NONE)); + } + lock->dynamic_list_len = dyn_pwrup_reglist_count; } static int a7xx_preempt_start(struct msm_gpu *gpu) diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.h b/drivers/gpu/drm/msm/adreno/a6xx_gpu.h index 6820216ec5fc..4eaa04711246 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.h +++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.h @@ -45,6 +45,7 @@ struct a6xx_info { const struct adreno_reglist *hwcg; const struct adreno_protect *protect; const struct adreno_reglist_list *pwrup_reglist; + const struct adreno_reglist_pipe_list *dyn_pwrup_reglist; const struct adreno_reglist_list *ifpc_reglist; const struct adreno_reglist *gbif_cx; const struct adreno_reglist_pipe *nonctxt_reglist; diff --git a/drivers/gpu/drm/msm/adreno/a6xx_preempt.c b/drivers/gpu/drm/msm/adreno/a6xx_preempt.c index afc5f4aa3b17..747a22afad9f 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_preempt.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_preempt.c @@ -454,11 +454,11 @@ void a6xx_preempt_init(struct msm_gpu *gpu) gpu->vm, &a6xx_gpu->preempt_postamble_bo, &a6xx_gpu->preempt_postamble_iova); - preempt_prepare_postamble(a6xx_gpu); - if (IS_ERR(a6xx_gpu->preempt_postamble_ptr)) goto fail; + preempt_prepare_postamble(a6xx_gpu); + timer_setup(&a6xx_gpu->preempt_timer, a6xx_preempt_timer, 0); return; diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.h b/drivers/gpu/drm/msm/adreno/adreno_gpu.h index 0f8d3de97636..1d0145f8b3ec 100644 --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.h +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.h @@ -188,6 +188,19 @@ static const struct adreno_reglist_list name = { \ .count = ARRAY_SIZE(name ## _regs), \ }; +struct adreno_reglist_pipe_list { + /** @reg: List of register **/ + const struct adreno_reglist_pipe *regs; + /** @count: Number of registers in the list **/ + u32 count; +}; + +#define DECLARE_ADRENO_REGLIST_PIPE_LIST(name) \ +static const struct adreno_reglist_pipe_list name = { \ + .regs = name ## _regs, \ + .count = ARRAY_SIZE(name ## _regs), \ +}; + struct adreno_gpu { struct msm_gpu base; const struct adreno_info *info; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c index c39f1908ea65..2d06c950e814 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.c @@ -200,7 +200,7 @@ static int dpu_crtc_get_lm_crc(struct drm_crtc *crtc, struct dpu_crtc_state *crtc_state) { struct dpu_crtc_mixer *m; - u32 crcs[CRTC_QUAD_MIXERS]; + u32 crcs[CRTC_DUAL_MIXERS]; int rc = 0; int i; @@ -1328,7 +1328,6 @@ static struct msm_display_topology dpu_crtc_get_topology( struct drm_display_mode *mode = &crtc_state->adjusted_mode; struct msm_display_topology topology = {0}; struct drm_encoder *drm_enc; - u32 num_rt_intf; drm_for_each_encoder_mask(drm_enc, crtc->dev, crtc_state->encoder_mask) dpu_encoder_update_topology(drm_enc, &topology, crtc_state->state, @@ -1342,14 +1341,11 @@ static struct msm_display_topology dpu_crtc_get_topology( * Dual display * 2 LM, 2 INTF ( Split display using 2 interfaces) * - * If DSC is enabled, try to use 4:4:2 topology if there is enough - * resource. Otherwise, use 2:2:2 topology. - * * Single display * 1 LM, 1 INTF * 2 LM, 1 INTF (stream merge to support high resolution interfaces) * - * If DSC is enabled, use 2:2:1 topology + * If DSC is enabled, use 2 LMs for 2:2:1 topology * * Add dspps to the reservation requirements if ctm is requested * @@ -1361,23 +1357,14 @@ static struct msm_display_topology dpu_crtc_get_topology( * (mode->hdisplay > MAX_HDISPLAY_SPLIT) check. */ - num_rt_intf = topology.num_intf; - if (topology.cwb_enabled) - num_rt_intf--; - - if (topology.num_dsc) { - if (dpu_kms->catalog->dsc_count >= num_rt_intf * 2) - topology.num_dsc = num_rt_intf * 2; - else - topology.num_dsc = num_rt_intf; - topology.num_lm = topology.num_dsc; - } else if (num_rt_intf == 2) { + if (topology.num_intf == 2 && !topology.cwb_enabled) + topology.num_lm = 2; + else if (topology.num_dsc == 2) topology.num_lm = 2; - } else if (dpu_kms->catalog->caps->has_3d_merge) { + else if (dpu_kms->catalog->caps->has_3d_merge) topology.num_lm = (mode->hdisplay > MAX_HDISPLAY_SPLIT) ? 2 : 1; - } else { + else topology.num_lm = 1; - } if (crtc_state->ctm) topology.num_dspp = topology.num_lm; @@ -1620,17 +1607,6 @@ int dpu_crtc_vblank(struct drm_crtc *crtc, bool en) return 0; } -/** - * dpu_crtc_get_num_lm - Get mixer number in this CRTC pipeline - * @state: Pointer to drm crtc state object - */ -unsigned int dpu_crtc_get_num_lm(const struct drm_crtc_state *state) -{ - struct dpu_crtc_state *cstate = to_dpu_crtc_state(state); - - return cstate->num_mixers; -} - #ifdef CONFIG_DEBUG_FS static int _dpu_debugfs_status_show(struct seq_file *s, void *data) { diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h index 455073c7025b..94392b9b9245 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_crtc.h @@ -210,7 +210,7 @@ struct dpu_crtc_state { bool bw_control; bool bw_split_vote; - struct drm_rect lm_bounds[CRTC_QUAD_MIXERS]; + struct drm_rect lm_bounds[CRTC_DUAL_MIXERS]; uint64_t input_fence_timeout_ns; @@ -218,10 +218,10 @@ struct dpu_crtc_state { /* HW Resources reserved for the crtc */ u32 num_mixers; - struct dpu_crtc_mixer mixers[CRTC_QUAD_MIXERS]; + struct dpu_crtc_mixer mixers[CRTC_DUAL_MIXERS]; u32 num_ctls; - struct dpu_hw_ctl *hw_ctls[CRTC_QUAD_MIXERS]; + struct dpu_hw_ctl *hw_ctls[CRTC_DUAL_MIXERS]; enum dpu_crtc_crc_source crc_source; int crc_frame_skip_count; @@ -267,6 +267,4 @@ static inline enum dpu_crtc_client_type dpu_crtc_get_client_type( void dpu_crtc_frame_event_cb(struct drm_crtc *crtc, u32 event); -unsigned int dpu_crtc_get_num_lm(const struct drm_crtc_state *state); - #endif /* _DPU_CRTC_H_ */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c index d1cfe81a3373..9f3957f24c6a 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder.c @@ -55,7 +55,7 @@ #define MAX_PHYS_ENCODERS_PER_VIRTUAL \ (MAX_H_TILES_PER_DISPLAY * NUM_PHYS_ENCODER_TYPES) -#define MAX_CHANNELS_PER_ENC 4 +#define MAX_CHANNELS_PER_ENC 2 #define MAX_CWB_PER_ENC 2 #define IDLE_SHORT_TIMEOUT 1 @@ -661,6 +661,7 @@ void dpu_encoder_update_topology(struct drm_encoder *drm_enc, struct dpu_encoder_virt *dpu_enc = to_dpu_encoder_virt(drm_enc); struct msm_drm_private *priv = dpu_enc->base.dev->dev_private; struct msm_display_info *disp_info = &dpu_enc->disp_info; + struct dpu_kms *dpu_kms = to_dpu_kms(priv->kms); struct drm_connector *connector; struct drm_connector_state *conn_state; struct drm_framebuffer *fb; @@ -674,12 +675,22 @@ void dpu_encoder_update_topology(struct drm_encoder *drm_enc, dsc = dpu_encoder_get_dsc_config(drm_enc); - /* - * Set DSC number as 1 to mark the enabled status, will be adjusted - * in dpu_crtc_get_topology() - */ - if (dsc) - topology->num_dsc = 1; + /* We only support 2 DSC mode (with 2 LM and 1 INTF) */ + if (dsc) { + /* + * Use 2 DSC encoders, 2 layer mixers and 1 or 2 interfaces + * when Display Stream Compression (DSC) is enabled, + * and when enough DSC blocks are available. + * This is power-optimal and can drive up to (including) 4k + * screens. + */ + WARN(topology->num_intf > 2, + "DSC topology cannot support more than 2 interfaces\n"); + if (topology->num_intf >= 2 || dpu_kms->catalog->dsc_count >= 2) + topology->num_dsc = 2; + else + topology->num_dsc = 1; + } connector = drm_atomic_get_new_connector_for_encoder(state, drm_enc); if (!connector) @@ -2169,8 +2180,8 @@ static void dpu_encoder_helper_reset_mixers(struct dpu_encoder_phys *phys_enc) { int i, num_lm; struct dpu_global_state *global_state; - struct dpu_hw_blk *hw_lm[MAX_CHANNELS_PER_ENC]; - struct dpu_hw_mixer *hw_mixer[MAX_CHANNELS_PER_ENC]; + struct dpu_hw_blk *hw_lm[2]; + struct dpu_hw_mixer *hw_mixer[2]; struct dpu_hw_ctl *ctl = phys_enc->hw_ctl; /* reset all mixers for this encoder */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h index 09395d7910ac..61b22d949454 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys.h @@ -302,7 +302,7 @@ static inline enum dpu_3d_blend_mode dpu_encoder_helper_get_3d_blend_mode( /* Use merge_3d unless DSC MERGE topology is used */ if (phys_enc->split_role == ENC_ROLE_SOLO && - (dpu_cstate->num_mixers != 1) && + dpu_cstate->num_mixers == CRTC_DUAL_MIXERS && !dpu_encoder_use_dsc_merge(phys_enc->parent)) return BLEND_3D_H_ROW_INT; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c index 46f348972a97..6d28f2281c76 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_wb.c @@ -247,14 +247,12 @@ static void dpu_encoder_phys_wb_setup_ctl(struct dpu_encoder_phys *phys_enc) if (hw_cdm) intf_cfg.cdm = hw_cdm->idx; - if (phys_enc->hw_pp->merge_3d && phys_enc->hw_pp->merge_3d->ops.setup_3d_mode) - phys_enc->hw_pp->merge_3d->ops.setup_3d_mode(phys_enc->hw_pp->merge_3d, - mode_3d); + if (hw_pp && hw_pp->merge_3d && hw_pp->merge_3d->ops.setup_3d_mode) + hw_pp->merge_3d->ops.setup_3d_mode(hw_pp->merge_3d, mode_3d); /* setup which pp blk will connect to this wb */ - if (hw_pp && phys_enc->hw_wb->ops.bind_pingpong_blk) - phys_enc->hw_wb->ops.bind_pingpong_blk(phys_enc->hw_wb, - phys_enc->hw_pp->idx); + if (hw_pp && hw_wb->ops.bind_pingpong_blk) + hw_wb->ops.bind_pingpong_blk(hw_wb, hw_pp->idx); phys_enc->hw_ctl->ops.setup_intf_cfg(phys_enc->hw_ctl, &intf_cfg); } else if (phys_enc->hw_ctl && phys_enc->hw_ctl->ops.setup_intf_cfg) { diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h index 336757103b5a..4964e70610d1 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_catalog.h @@ -24,7 +24,7 @@ #define DPU_MAX_IMG_WIDTH 0x3fff #define DPU_MAX_IMG_HEIGHT 0x3fff -#define CRTC_QUAD_MIXERS 4 +#define CRTC_DUAL_MIXERS 2 #define MAX_XIN_COUNT 16 diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cdm.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cdm.h index 6bb3476a05f8..75e6dae0fcd9 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cdm.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cdm.h @@ -89,13 +89,13 @@ enum dpu_hw_cdwn_op_mode_method_h_v { */ struct dpu_hw_cdm_ops { /** - * Enable the CDM module + * @enable: Enable the CDM module * @cdm Pointer to chroma down context */ int (*enable)(struct dpu_hw_cdm *cdm, struct dpu_hw_cdm_cfg *cfg); /** - * Enable/disable the connection with pingpong + * @bind_pingpong_blk: Enable/disable the connection with pingpong * @cdm Pointer to chroma down context * @pp pingpong block id. */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h index 15931b22ec94..e535bf013825 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_ctl.h @@ -12,9 +12,9 @@ #include "dpu_hw_sspp.h" /** - * dpu_ctl_mode_sel: Interface mode selection - * DPU_CTL_MODE_SEL_VID: Video mode interface - * DPU_CTL_MODE_SEL_CMD: Command mode interface + * enum dpu_ctl_mode_sel: Interface mode selection + * @DPU_CTL_MODE_SEL_VID: Video mode interface + * @DPU_CTL_MODE_SEL_CMD: Command mode interface */ enum dpu_ctl_mode_sel { DPU_CTL_MODE_SEL_VID = 0, @@ -37,6 +37,7 @@ struct dpu_hw_stage_cfg { * struct dpu_hw_intf_cfg :Describes how the DPU writes data to output interface * @intf : Interface id * @intf_master: Master interface id in the dual pipe topology + * @wb: Writeback mode * @mode_3d: 3d mux configuration * @merge_3d: 3d merge block used * @intf_mode_sel: Interface mode, cmd / vid @@ -64,21 +65,21 @@ struct dpu_hw_intf_cfg { */ struct dpu_hw_ctl_ops { /** - * kickoff hw operation for Sw controlled interfaces + * @trigger_start: kickoff hw operation for Sw controlled interfaces * DSI cmd mode and WB interface are SW controlled * @ctx : ctl path ctx pointer */ void (*trigger_start)(struct dpu_hw_ctl *ctx); /** - * check if the ctl is started + * @is_started: check if the ctl is started * @ctx : ctl path ctx pointer * @Return: true if started, false if stopped */ bool (*is_started)(struct dpu_hw_ctl *ctx); /** - * kickoff prepare is in progress hw operation for sw + * @trigger_pending: kickoff prepare is in progress hw operation for sw * controlled interfaces: DSI cmd mode and WB interface * are SW controlled * @ctx : ctl path ctx pointer @@ -86,7 +87,7 @@ struct dpu_hw_ctl_ops { void (*trigger_pending)(struct dpu_hw_ctl *ctx); /** - * Clear the value of the cached pending_flush_mask + * @clear_pending_flush: Clear the value of the cached pending_flush_mask * No effect on hardware. * Required to be implemented. * @ctx : ctl path ctx pointer @@ -94,14 +95,15 @@ struct dpu_hw_ctl_ops { void (*clear_pending_flush)(struct dpu_hw_ctl *ctx); /** - * Query the value of the cached pending_flush_mask + * @get_pending_flush: Query the value of the cached pending_flush_mask * No effect on hardware * @ctx : ctl path ctx pointer */ u32 (*get_pending_flush)(struct dpu_hw_ctl *ctx); /** - * OR in the given flushbits to the cached pending_flush_mask + * @update_pending_flush: OR in the given flushbits to the cached + * pending_flush_mask. * No effect on hardware * @ctx : ctl path ctx pointer * @flushbits : module flushmask @@ -110,7 +112,8 @@ struct dpu_hw_ctl_ops { u32 flushbits); /** - * OR in the given flushbits to the cached pending_(wb_)flush_mask + * @update_pending_flush_wb: OR in the given flushbits to the + * cached pending_(wb_)flush_mask. * No effect on hardware * @ctx : ctl path ctx pointer * @blk : writeback block index @@ -119,7 +122,8 @@ struct dpu_hw_ctl_ops { enum dpu_wb blk); /** - * OR in the given flushbits to the cached pending_(cwb_)flush_mask + * @update_pending_flush_cwb: OR in the given flushbits to the + * cached pending_(cwb_)flush_mask. * No effect on hardware * @ctx : ctl path ctx pointer * @blk : concurrent writeback block index @@ -128,7 +132,8 @@ struct dpu_hw_ctl_ops { enum dpu_cwb blk); /** - * OR in the given flushbits to the cached pending_(intf_)flush_mask + * @update_pending_flush_intf: OR in the given flushbits to the + * cached pending_(intf_)flush_mask. * No effect on hardware * @ctx : ctl path ctx pointer * @blk : interface block index @@ -137,7 +142,8 @@ struct dpu_hw_ctl_ops { enum dpu_intf blk); /** - * OR in the given flushbits to the cached pending_(periph_)flush_mask + * @update_pending_flush_periph: OR in the given flushbits to the + * cached pending_(periph_)flush_mask. * No effect on hardware * @ctx : ctl path ctx pointer * @blk : interface block index @@ -146,7 +152,8 @@ struct dpu_hw_ctl_ops { enum dpu_intf blk); /** - * OR in the given flushbits to the cached pending_(merge_3d_)flush_mask + * @update_pending_flush_merge_3d: OR in the given flushbits to the + * cached pending_(merge_3d_)flush_mask. * No effect on hardware * @ctx : ctl path ctx pointer * @blk : interface block index @@ -155,7 +162,8 @@ struct dpu_hw_ctl_ops { enum dpu_merge_3d blk); /** - * OR in the given flushbits to the cached pending_flush_mask + * @update_pending_flush_sspp: OR in the given flushbits to the + * cached pending_flush_mask. * No effect on hardware * @ctx : ctl path ctx pointer * @blk : SSPP block index @@ -164,7 +172,8 @@ struct dpu_hw_ctl_ops { enum dpu_sspp blk); /** - * OR in the given flushbits to the cached pending_flush_mask + * @update_pending_flush_mixer: OR in the given flushbits to the + * cached pending_flush_mask. * No effect on hardware * @ctx : ctl path ctx pointer * @blk : LM block index @@ -173,7 +182,8 @@ struct dpu_hw_ctl_ops { enum dpu_lm blk); /** - * OR in the given flushbits to the cached pending_flush_mask + * @update_pending_flush_dspp: OR in the given flushbits to the + * cached pending_flush_mask. * No effect on hardware * @ctx : ctl path ctx pointer * @blk : DSPP block index @@ -183,7 +193,8 @@ struct dpu_hw_ctl_ops { enum dpu_dspp blk, u32 dspp_sub_blk); /** - * OR in the given flushbits to the cached pending_(dsc_)flush_mask + * @update_pending_flush_dsc: OR in the given flushbits to the + * cached pending_(dsc_)flush_mask. * No effect on hardware * @ctx: ctl path ctx pointer * @blk: interface block index @@ -192,7 +203,8 @@ struct dpu_hw_ctl_ops { enum dpu_dsc blk); /** - * OR in the given flushbits to the cached pending_(cdm_)flush_mask + * @update_pending_flush_cdm: OR in the given flushbits to the + * cached pending_(cdm_)flush_mask. * No effect on hardware * @ctx: ctl path ctx pointer * @cdm_num: idx of cdm to be flushed @@ -200,20 +212,20 @@ struct dpu_hw_ctl_ops { void (*update_pending_flush_cdm)(struct dpu_hw_ctl *ctx, enum dpu_cdm cdm_num); /** - * Write the value of the pending_flush_mask to hardware + * @trigger_flush: Write the value of the pending_flush_mask to hardware * @ctx : ctl path ctx pointer */ void (*trigger_flush)(struct dpu_hw_ctl *ctx); /** - * Read the value of the flush register + * @get_flush_register: Read the value of the flush register * @ctx : ctl path ctx pointer * @Return: value of the ctl flush register. */ u32 (*get_flush_register)(struct dpu_hw_ctl *ctx); /** - * Setup ctl_path interface config + * @setup_intf_cfg: Setup ctl_path interface config * @ctx * @cfg : interface config structure pointer */ @@ -221,17 +233,20 @@ struct dpu_hw_ctl_ops { struct dpu_hw_intf_cfg *cfg); /** - * reset ctl_path interface config + * @reset_intf_cfg: reset ctl_path interface config * @ctx : ctl path ctx pointer * @cfg : interface config structure pointer */ void (*reset_intf_cfg)(struct dpu_hw_ctl *ctx, struct dpu_hw_intf_cfg *cfg); + /** + * @reset: reset function for this ctl type + */ int (*reset)(struct dpu_hw_ctl *c); - /* - * wait_reset_status - checks ctl reset status + /** + * @wait_reset_status: checks ctl reset status * @ctx : ctl path ctx pointer * * This function checks the ctl reset status bit. @@ -242,13 +257,13 @@ struct dpu_hw_ctl_ops { int (*wait_reset_status)(struct dpu_hw_ctl *ctx); /** - * Set all blend stages to disabled + * @clear_all_blendstages: Set all blend stages to disabled * @ctx : ctl path ctx pointer */ void (*clear_all_blendstages)(struct dpu_hw_ctl *ctx); /** - * Configure layer mixer to pipe configuration + * @setup_blendstage: Configure layer mixer to pipe configuration * @ctx : ctl path ctx pointer * @lm : layer mixer enumeration * @cfg : blend stage configuration @@ -256,11 +271,16 @@ struct dpu_hw_ctl_ops { void (*setup_blendstage)(struct dpu_hw_ctl *ctx, enum dpu_lm lm, struct dpu_hw_stage_cfg *cfg); + /** + * @set_active_fetch_pipes: Set active pipes attached to this CTL + * @ctx: ctl path ctx pointer + * @active_pipes: bitmap of enum dpu_sspp + */ void (*set_active_fetch_pipes)(struct dpu_hw_ctl *ctx, unsigned long *fetch_active); /** - * Set active pipes attached to this CTL + * @set_active_pipes: Set active pipes attached to this CTL * @ctx: ctl path ctx pointer * @active_pipes: bitmap of enum dpu_sspp */ @@ -268,13 +288,12 @@ struct dpu_hw_ctl_ops { unsigned long *active_pipes); /** - * Set active layer mixers attached to this CTL + * @set_active_lms: Set active layer mixers attached to this CTL * @ctx: ctl path ctx pointer * @active_lms: bitmap of enum dpu_lm */ void (*set_active_lms)(struct dpu_hw_ctl *ctx, unsigned long *active_lms); - }; /** @@ -289,6 +308,9 @@ struct dpu_hw_ctl_ops { * @pending_intf_flush_mask: pending INTF flush * @pending_wb_flush_mask: pending WB flush * @pending_cwb_flush_mask: pending CWB flush + * @pending_periph_flush_mask: pending PERIPH flush + * @pending_merge_3d_flush_mask: pending MERGE 3D flush + * @pending_dspp_flush_mask: pending DSPP flush * @pending_dsc_flush_mask: pending DSC flush * @pending_cdm_flush_mask: pending CDM flush * @mdss_ver: MDSS revision information @@ -320,7 +342,7 @@ struct dpu_hw_ctl { }; /** - * dpu_hw_ctl - convert base object dpu_hw_base to container + * to_dpu_hw_ctl - convert base object dpu_hw_base to container * @hw: Pointer to base hardware block * return: Pointer to hardware block container */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cwb.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cwb.h index 96b6edf6b2bb..ed7bfcee7f1c 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cwb.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_cwb.h @@ -28,7 +28,6 @@ struct dpu_hw_cwb_setup_cfg { }; /** - * * struct dpu_hw_cwb_ops : Interface to the cwb hw driver functions * @config_cwb: configure CWB mux */ @@ -54,7 +53,7 @@ struct dpu_hw_cwb { }; /** - * dpu_hw_cwb - convert base object dpu_hw_base to container + * to_dpu_hw_cwb - convert base object dpu_hw_base to container * @hw: Pointer to base hardware block * return: Pointer to hardware block container */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h index cc7cc6f6f7cd..39d93b9df051 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dsc.h @@ -21,13 +21,13 @@ struct dpu_hw_dsc; */ struct dpu_hw_dsc_ops { /** - * dsc_disable - disable dsc + * @dsc_disable: disable dsc * @hw_dsc: Pointer to dsc context */ void (*dsc_disable)(struct dpu_hw_dsc *hw_dsc); /** - * dsc_config - configures dsc encoder + * @dsc_config: configures dsc encoder * @hw_dsc: Pointer to dsc context * @dsc: panel dsc parameters * @mode: dsc topology mode to be set @@ -39,13 +39,17 @@ struct dpu_hw_dsc_ops { u32 initial_lines); /** - * dsc_config_thresh - programs panel thresholds + * @dsc_config_thresh: programs panel thresholds * @hw_dsc: Pointer to dsc context * @dsc: panel dsc parameters */ void (*dsc_config_thresh)(struct dpu_hw_dsc *hw_dsc, struct drm_dsc_config *dsc); + /** + * @dsc_bind_pingpong_blk: binds pixel output from a DSC block + * to a pingpong block + */ void (*dsc_bind_pingpong_blk)(struct dpu_hw_dsc *hw_dsc, enum dpu_pingpong pp); }; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.h index 45c26cd49fa3..722b0f482e9b 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_dspp.h @@ -22,7 +22,7 @@ struct dpu_hw_pcc_coeff { }; /** - * struct dpu_hw_pcc - pcc feature structure + * struct dpu_hw_pcc_cfg - pcc feature structure * @r: red coefficients. * @g: green coefficients. * @b: blue coefficients. @@ -40,7 +40,7 @@ struct dpu_hw_pcc_cfg { */ struct dpu_hw_dspp_ops { /** - * setup_pcc - setup dspp pcc + * @setup_pcc: setup_pcc - setup dspp pcc * @ctx: Pointer to dspp context * @cfg: Pointer to configuration */ @@ -69,7 +69,7 @@ struct dpu_hw_dspp { }; /** - * dpu_hw_dspp - convert base object dpu_hw_base to container + * to_dpu_hw_dspp - convert base object dpu_hw_base to container * @hw: Pointer to base hardware block * return: Pointer to hardware block container */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h index f31067a9aaf1..5a19cd74fa94 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_intf.h @@ -57,11 +57,11 @@ struct dpu_hw_intf_cmd_mode_cfg { /** * struct dpu_hw_intf_ops : Interface to the interface Hw driver functions * Assumption is these functions will be called after clocks are enabled - * @ setup_timing_gen : programs the timing engine - * @ setup_prog_fetch : enables/disables the programmable fetch logic - * @ enable_timing: enable/disable timing engine - * @ get_status: returns if timing engine is enabled or not - * @ get_line_count: reads current vertical line counter + * @setup_timing_gen : programs the timing engine + * @setup_prg_fetch : enables/disables the programmable fetch logic + * @enable_timing: enable/disable timing engine + * @get_status: returns if timing engine is enabled or not + * @get_line_count: reads current vertical line counter * @bind_pingpong_blk: enable/disable the connection with pingpong which will * feed pixels to this interface * @setup_misr: enable/disable MISR @@ -70,12 +70,9 @@ struct dpu_hw_intf_cmd_mode_cfg { * pointer and programs the tear check configuration * @disable_tearcheck: Disables tearcheck block * @connect_external_te: Read, modify, write to either set or clear listening to external TE - * Return: 1 if TE was originally connected, 0 if not, or -ERROR - * @get_vsync_info: Provides the programmed and current line_count - * @setup_autorefresh: Configure and enable the autorefresh config - * @get_autorefresh: Retrieve autorefresh config from hardware - * Return: 0 on success, -ETIMEDOUT on timeout + * Returns 1 if TE was originally connected, 0 if not, or -ERROR * @vsync_sel: Select vsync signal for tear-effect configuration + * @disable_autorefresh: Disable autorefresh if enabled * @program_intf_cmd_cfg: Program the DPU to interface datapath for command mode */ struct dpu_hw_intf_ops { @@ -109,9 +106,6 @@ struct dpu_hw_intf_ops { void (*vsync_sel)(struct dpu_hw_intf *intf, enum dpu_vsync_source vsync_source); - /** - * Disable autorefresh if enabled - */ void (*disable_autorefresh)(struct dpu_hw_intf *intf, uint32_t encoder_id, u16 vdisplay); void (*program_intf_cmd_cfg)(struct dpu_hw_intf *intf, diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.h index 1b9ecd082d7f..ecbb77711d83 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_lm.h @@ -25,39 +25,38 @@ struct dpu_hw_color3_cfg { }; /** - * * struct dpu_hw_lm_ops : Interface to the mixer Hw driver functions * Assumption is these functions will be called after clocks are enabled */ struct dpu_hw_lm_ops { - /* - * Sets up mixer output width and height + /** + * @setup_mixer_out: Sets up mixer output width and height * and border color if enabled */ void (*setup_mixer_out)(struct dpu_hw_mixer *ctx, struct dpu_hw_mixer_cfg *cfg); - /* - * Alpha blending configuration + /** + * @setup_blend_config: Alpha blending configuration * for the specified stage */ void (*setup_blend_config)(struct dpu_hw_mixer *ctx, uint32_t stage, uint32_t fg_alpha, uint32_t bg_alpha, uint32_t blend_op); - /* - * Alpha color component selection from either fg or bg + /** + * @setup_alpha_out: Alpha color component selection from either fg or bg */ void (*setup_alpha_out)(struct dpu_hw_mixer *ctx, uint32_t mixer_op); /** - * Clear layer mixer to pipe configuration + * @clear_all_blendstages: Clear layer mixer to pipe configuration * @ctx : mixer ctx pointer * Returns: 0 on success or -error */ int (*clear_all_blendstages)(struct dpu_hw_mixer *ctx); /** - * Configure layer mixer to pipe configuration + * @setup_blendstage: Configure layer mixer to pipe configuration * @ctx : mixer ctx pointer * @lm : layer mixer enumeration * @stage_cfg : blend stage configuration @@ -67,19 +66,19 @@ struct dpu_hw_lm_ops { struct dpu_hw_stage_cfg *stage_cfg); /** - * setup_border_color : enable/disable border color + * @setup_border_color : enable/disable border color */ void (*setup_border_color)(struct dpu_hw_mixer *ctx, struct dpu_mdss_color *color, u8 border_en); /** - * setup_misr: Enable/disable MISR + * @setup_misr: Enable/disable MISR */ void (*setup_misr)(struct dpu_hw_mixer *ctx); /** - * collect_misr: Read MISR signature + * @collect_misr: Read MISR signature */ int (*collect_misr)(struct dpu_hw_mixer *ctx, u32 *misr_value); }; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h index 31451241f083..046b683d4c66 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_mdss.h @@ -34,7 +34,7 @@ #define DPU_MAX_PLANES 4 #endif -#define STAGES_PER_PLANE 2 +#define STAGES_PER_PLANE 1 #define PIPES_PER_STAGE 2 #define PIPES_PER_PLANE (PIPES_PER_STAGE * STAGES_PER_PLANE) #ifndef DPU_MAX_DE_CURVES diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_merge3d.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_merge3d.h index 6833c0207523..b57f88187148 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_merge3d.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_merge3d.h @@ -12,7 +12,6 @@ struct dpu_hw_merge_3d; /** - * * struct dpu_hw_merge_3d_ops : Interface to the merge_3d Hw driver functions * Assumption is these functions will be called after clocks are enabled * @setup_3d_mode : enable 3D merge diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h index dd99e1c21a1e..effd012d864a 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_pingpong.h @@ -34,7 +34,6 @@ struct dpu_hw_dither_cfg { }; /** - * * struct dpu_hw_pingpong_ops : Interface to the pingpong Hw driver functions * Assumption is these functions will be called after clocks are enabled * @enable_tearcheck: program and enable tear check block @@ -44,51 +43,52 @@ struct dpu_hw_dither_cfg { */ struct dpu_hw_pingpong_ops { /** - * enables vysnc generation and sets up init value of + * @enable_tearcheck: enables vysnc generation and sets up init value of * read pointer and programs the tear check cofiguration */ int (*enable_tearcheck)(struct dpu_hw_pingpong *pp, struct dpu_hw_tear_check *cfg); /** - * disables tear check block + * @disable_tearcheck: disables tear check block */ int (*disable_tearcheck)(struct dpu_hw_pingpong *pp); /** - * read, modify, write to either set or clear listening to external TE + * @connect_external_te: read, modify, write to either set or clear + * listening to external TE * @Return: 1 if TE was originally connected, 0 if not, or -ERROR */ int (*connect_external_te)(struct dpu_hw_pingpong *pp, bool enable_external_te); /** - * Obtain current vertical line counter + * @get_line_count: Obtain current vertical line counter */ u32 (*get_line_count)(struct dpu_hw_pingpong *pp); /** - * Disable autorefresh if enabled + * @disable_autorefresh: Disable autorefresh if enabled */ void (*disable_autorefresh)(struct dpu_hw_pingpong *pp, uint32_t encoder_id, u16 vdisplay); /** - * Setup dither matix for pingpong block + * @setup_dither: Setup dither matix for pingpong block */ void (*setup_dither)(struct dpu_hw_pingpong *pp, struct dpu_hw_dither_cfg *cfg); /** - * Enable DSC + * @enable_dsc: Enable DSC */ int (*enable_dsc)(struct dpu_hw_pingpong *pp); /** - * Disable DSC + * @disable_dsc: Disable DSC */ void (*disable_dsc)(struct dpu_hw_pingpong *pp); /** - * Setup DSC + * @setup_dsc: Setup DSC */ int (*setup_dsc)(struct dpu_hw_pingpong *pp); }; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h index bdac5c04bf79..3822094f85bc 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.h @@ -14,7 +14,7 @@ struct dpu_hw_sspp; #define DPU_SSPP_MAX_PITCH_SIZE 0xffff -/** +/* * Flags */ #define DPU_SSPP_FLIP_LR BIT(0) @@ -23,7 +23,7 @@ struct dpu_hw_sspp; #define DPU_SSPP_ROT_90 BIT(3) #define DPU_SSPP_SOLID_FILL BIT(4) -/** +/* * Component indices */ enum { @@ -36,9 +36,10 @@ enum { }; /** - * DPU_SSPP_RECT_SOLO - multirect disabled - * DPU_SSPP_RECT_0 - rect0 of a multirect pipe - * DPU_SSPP_RECT_1 - rect1 of a multirect pipe + * enum dpu_sspp_multirect_index - multirect mode + * @DPU_SSPP_RECT_SOLO: multirect disabled + * @DPU_SSPP_RECT_0: rect0 of a multirect pipe + * @DPU_SSPP_RECT_1: rect1 of a multirect pipe * * Note: HW supports multirect with either RECT0 or * RECT1. Considering no benefit of such configs over @@ -143,7 +144,7 @@ struct dpu_hw_pixel_ext { * struct dpu_sw_pipe_cfg : software pipe configuration * @src_rect: src ROI, caller takes into account the different operations * such as decimation, flip etc to program this field - * @dest_rect: destination ROI. + * @dst_rect: destination ROI. * @rotation: simplified drm rotation hint */ struct dpu_sw_pipe_cfg { @@ -165,8 +166,8 @@ struct dpu_hw_pipe_ts_cfg { /** * struct dpu_sw_pipe - software pipe description * @sspp: backing SSPP pipe - * @index: index of the rectangle of SSPP - * @mode: parallel or time multiplex multirect mode + * @multirect_index: index of the rectangle of SSPP + * @multirect_mode: parallel or time multiplex multirect mode */ struct dpu_sw_pipe { struct dpu_hw_sspp *sspp; @@ -181,7 +182,7 @@ struct dpu_sw_pipe { */ struct dpu_hw_sspp_ops { /** - * setup_format - setup pixel format cropping rectangle, flip + * @setup_format: setup pixel format cropping rectangle, flip * @pipe: Pointer to software pipe context * @cfg: Pointer to pipe config structure * @flags: Extra flags for format config @@ -190,7 +191,7 @@ struct dpu_hw_sspp_ops { const struct msm_format *fmt, u32 flags); /** - * setup_rects - setup pipe ROI rectangles + * @setup_rects: setup pipe ROI rectangles * @pipe: Pointer to software pipe context * @cfg: Pointer to pipe config structure */ @@ -198,7 +199,7 @@ struct dpu_hw_sspp_ops { struct dpu_sw_pipe_cfg *cfg); /** - * setup_pe - setup pipe pixel extension + * @setup_pe: setup pipe pixel extension * @ctx: Pointer to pipe context * @pe_ext: Pointer to pixel ext settings */ @@ -206,7 +207,7 @@ struct dpu_hw_sspp_ops { struct dpu_hw_pixel_ext *pe_ext); /** - * setup_sourceaddress - setup pipe source addresses + * @setup_sourceaddress: setup pipe source addresses * @pipe: Pointer to software pipe context * @layout: format layout information for programming buffer to hardware */ @@ -214,14 +215,14 @@ struct dpu_hw_sspp_ops { struct dpu_hw_fmt_layout *layout); /** - * setup_csc - setup color space coversion + * @setup_csc: setup color space coversion * @ctx: Pointer to pipe context * @data: Pointer to config structure */ void (*setup_csc)(struct dpu_hw_sspp *ctx, const struct dpu_csc_cfg *data); /** - * setup_solidfill - enable/disable colorfill + * @setup_solidfill: enable/disable colorfill * @pipe: Pointer to software pipe context * @const_color: Fill color value * @flags: Pipe flags @@ -229,23 +230,22 @@ struct dpu_hw_sspp_ops { void (*setup_solidfill)(struct dpu_sw_pipe *pipe, u32 color); /** - * setup_multirect - setup multirect configuration + * @setup_multirect: setup multirect configuration * @pipe: Pointer to software pipe context */ void (*setup_multirect)(struct dpu_sw_pipe *pipe); /** - * setup_sharpening - setup sharpening + * @setup_sharpening: setup sharpening * @ctx: Pointer to pipe context * @cfg: Pointer to config structure */ void (*setup_sharpening)(struct dpu_hw_sspp *ctx, struct dpu_hw_sharp_cfg *cfg); - /** - * setup_qos_lut - setup QoS LUTs + * @setup_qos_lut: setup QoS LUTs * @ctx: Pointer to pipe context * @cfg: LUT configuration */ @@ -253,7 +253,7 @@ struct dpu_hw_sspp_ops { struct dpu_hw_qos_cfg *cfg); /** - * setup_qos_ctrl - setup QoS control + * @setup_qos_ctrl: setup QoS control * @ctx: Pointer to pipe context * @danger_safe_en: flags controlling enabling of danger/safe QoS/LUT */ @@ -261,7 +261,7 @@ struct dpu_hw_sspp_ops { bool danger_safe_en); /** - * setup_clk_force_ctrl - setup clock force control + * @setup_clk_force_ctrl: setup clock force control * @ctx: Pointer to pipe context * @enable: enable clock force if true */ @@ -269,7 +269,7 @@ struct dpu_hw_sspp_ops { bool enable); /** - * setup_histogram - setup histograms + * @setup_histogram: setup histograms * @ctx: Pointer to pipe context * @cfg: Pointer to histogram configuration */ @@ -277,7 +277,7 @@ struct dpu_hw_sspp_ops { void *cfg); /** - * setup_scaler - setup scaler + * @setup_scaler: setup scaler * @scaler3_cfg: Pointer to scaler configuration * @format: pixel format parameters */ @@ -286,7 +286,7 @@ struct dpu_hw_sspp_ops { const struct msm_format *format); /** - * setup_cdp - setup client driven prefetch + * @setup_cdp: setup client driven prefetch * @pipe: Pointer to software pipe context * @fmt: format used by the sw pipe * @enable: whether the CDP should be enabled for this pipe @@ -303,6 +303,7 @@ struct dpu_hw_sspp_ops { * @ubwc: UBWC configuration data * @idx: pipe index * @cap: pointer to layer_cfg + * @mdss_ver: MDSS version info to use for feature checks * @ops: pointer to operations possible for this pipe */ struct dpu_hw_sspp { diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.h index 04efdcd21ceb..80279d87c2cd 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_top.h @@ -77,12 +77,11 @@ enum dpu_dp_phy_sel { /** * struct dpu_hw_mdp_ops - interface to the MDP TOP Hw driver functions * Assumption is these functions will be called after clocks are enabled. - * @setup_split_pipe : Programs the pipe control registers - * @setup_pp_split : Programs the pp split control registers - * @setup_traffic_shaper : programs traffic shaper control */ struct dpu_hw_mdp_ops { - /** setup_split_pipe() : Registers are not double buffered, thisk + /** + * @setup_split_pipe : Programs the pipe control registers. + * Registers are not double buffered, this * function should be called before timing control enable * @mdp : mdp top context driver * @cfg : upper and lower part of pipe configuration @@ -91,7 +90,7 @@ struct dpu_hw_mdp_ops { struct split_pipe_cfg *p); /** - * setup_traffic_shaper() : Setup traffic shaper control + * @setup_traffic_shaper : programs traffic shaper control. * @mdp : mdp top context driver * @cfg : traffic shaper configuration */ @@ -99,7 +98,7 @@ struct dpu_hw_mdp_ops { struct traffic_shaper_cfg *cfg); /** - * setup_clk_force_ctrl - set clock force control + * @setup_clk_force_ctrl: set clock force control * @mdp: mdp top context driver * @clk_ctrl: clock to be controlled * @enable: force on enable @@ -109,7 +108,7 @@ struct dpu_hw_mdp_ops { enum dpu_clk_ctrl_type clk_ctrl, bool enable); /** - * get_danger_status - get danger status + * @get_danger_status: get danger status * @mdp: mdp top context driver * @status: Pointer to danger safe status */ @@ -117,7 +116,7 @@ struct dpu_hw_mdp_ops { struct dpu_danger_safe_status *status); /** - * setup_vsync_source - setup vsync source configuration details + * @setup_vsync_source: setup vsync source configuration details * @mdp: mdp top context driver * @cfg: vsync source selection configuration */ @@ -125,7 +124,7 @@ struct dpu_hw_mdp_ops { struct dpu_vsync_source_cfg *cfg); /** - * get_safe_status - get safe status + * @get_safe_status: get safe status * @mdp: mdp top context driver * @status: Pointer to danger safe status */ @@ -133,14 +132,14 @@ struct dpu_hw_mdp_ops { struct dpu_danger_safe_status *status); /** - * dp_phy_intf_sel - configure intf to phy mapping + * @dp_phy_intf_sel: configure intf to phy mapping * @mdp: mdp top context driver * @phys: list of phys the DP interfaces should be connected to. 0 disables the INTF. */ void (*dp_phy_intf_sel)(struct dpu_hw_mdp *mdp, enum dpu_dp_phy_sel phys[2]); /** - * intf_audio_select - select the external interface for audio + * @intf_audio_select: select the external interface for audio * @mdp: mdp top context driver */ void (*intf_audio_select)(struct dpu_hw_mdp *mdp); diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_vbif.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_vbif.h index 285121ec804c..9ac49448e432 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_vbif.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_vbif.h @@ -17,7 +17,7 @@ struct dpu_hw_vbif; */ struct dpu_hw_vbif_ops { /** - * set_limit_conf - set transaction limit config + * @set_limit_conf: set transaction limit config * @vbif: vbif context driver * @xin_id: client interface identifier * @rd: true for read limit; false for write limit @@ -27,7 +27,7 @@ struct dpu_hw_vbif_ops { u32 xin_id, bool rd, u32 limit); /** - * get_limit_conf - get transaction limit config + * @get_limit_conf: get transaction limit config * @vbif: vbif context driver * @xin_id: client interface identifier * @rd: true for read limit; false for write limit @@ -37,7 +37,7 @@ struct dpu_hw_vbif_ops { u32 xin_id, bool rd); /** - * set_halt_ctrl - set halt control + * @set_halt_ctrl: set halt control * @vbif: vbif context driver * @xin_id: client interface identifier * @enable: halt control enable @@ -46,7 +46,7 @@ struct dpu_hw_vbif_ops { u32 xin_id, bool enable); /** - * get_halt_ctrl - get halt control + * @get_halt_ctrl: get halt control * @vbif: vbif context driver * @xin_id: client interface identifier * @return: halt control enable @@ -55,7 +55,7 @@ struct dpu_hw_vbif_ops { u32 xin_id); /** - * set_qos_remap - set QoS priority remap + * @set_qos_remap: set QoS priority remap * @vbif: vbif context driver * @xin_id: client interface identifier * @level: priority level @@ -65,7 +65,7 @@ struct dpu_hw_vbif_ops { u32 xin_id, u32 level, u32 remap_level); /** - * set_mem_type - set memory type + * @set_mem_type: set memory type * @vbif: vbif context driver * @xin_id: client interface identifier * @value: memory type value @@ -74,7 +74,7 @@ struct dpu_hw_vbif_ops { u32 xin_id, u32 value); /** - * clear_errors - clear any vbif errors + * @clear_errors: clear any vbif errors * This function clears any detected pending/source errors * on the VBIF interface, and optionally returns the detected * error mask(s). @@ -86,7 +86,7 @@ struct dpu_hw_vbif_ops { u32 *pnd_errors, u32 *src_errors); /** - * set_write_gather_en - set write_gather enable + * @set_write_gather_en: set write_gather enable * @vbif: vbif context driver * @xin_id: client interface identifier */ diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.h b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.h index ee5e5ab786e1..cfdbb5bb2a0f 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.h +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_wb.h @@ -22,11 +22,11 @@ struct dpu_hw_wb_cfg { }; /** - * * struct dpu_hw_wb_ops : Interface to the wb hw driver functions * Assumption is these functions will be called after clocks are enabled * @setup_outaddress: setup output address from the writeback job * @setup_outformat: setup output format of writeback block from writeback job + * @setup_roi: setup ROI (Region of Interest) parameters * @setup_qos_lut: setup qos LUT for writeback block based on input * @setup_cdp: setup chroma down prefetch block for writeback block * @setup_clk_force_ctrl: setup clock force control @@ -61,7 +61,7 @@ struct dpu_hw_wb_ops { * struct dpu_hw_wb : WB driver object * @hw: block hardware details * @idx: hardware index number within type - * @wb_hw_caps: hardware capabilities + * @caps: hardware capabilities * @ops: function pointers */ struct dpu_hw_wb { diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c index d07a6ab6e7ee..9b7a8b46bfa9 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_plane.c @@ -826,12 +826,8 @@ static int dpu_plane_atomic_check_nosspp(struct drm_plane *plane, struct dpu_plane_state *pstate = to_dpu_plane_state(new_plane_state); struct dpu_sw_pipe_cfg *pipe_cfg; struct dpu_sw_pipe_cfg *r_pipe_cfg; - struct dpu_sw_pipe_cfg init_pipe_cfg; struct drm_rect fb_rect = { 0 }; - const struct drm_display_mode *mode = &crtc_state->adjusted_mode; uint32_t max_linewidth; - u32 num_lm; - int stage_id, num_stages; min_scale = FRAC_16_16(1, MAX_UPSCALE_RATIO); max_scale = MAX_DOWNSCALE_RATIO << 16; @@ -854,10 +850,13 @@ static int dpu_plane_atomic_check_nosspp(struct drm_plane *plane, return -EINVAL; } - num_lm = dpu_crtc_get_num_lm(crtc_state); - + /* move the assignment here, to ease handling to another pairs later */ + pipe_cfg = &pstate->pipe_cfg[0]; + r_pipe_cfg = &pstate->pipe_cfg[1]; /* state->src is 16.16, src_rect is not */ - drm_rect_fp_to_int(&init_pipe_cfg.src_rect, &new_plane_state->src); + drm_rect_fp_to_int(&pipe_cfg->src_rect, &new_plane_state->src); + + pipe_cfg->dst_rect = new_plane_state->dst; fb_rect.x2 = new_plane_state->fb->width; fb_rect.y2 = new_plane_state->fb->height; @@ -882,94 +881,35 @@ static int dpu_plane_atomic_check_nosspp(struct drm_plane *plane, max_linewidth = pdpu->catalog->caps->max_linewidth; - drm_rect_rotate(&init_pipe_cfg.src_rect, + drm_rect_rotate(&pipe_cfg->src_rect, new_plane_state->fb->width, new_plane_state->fb->height, new_plane_state->rotation); - /* - * We have 1 mixer pair cfg for 1:1:1 and 2:2:1 topology, 2 mixer pair - * configs for left and right half screen in case of 4:4:2 topology. - * But we may have 2 rect to split wide plane that exceeds limit with 1 - * config for 2:2:1. So need to handle both wide plane splitting, and - * two halves of screen splitting for quad-pipe case. Check dest - * rectangle left/right clipping first, then check wide rectangle - * splitting in every half next. - */ - num_stages = (num_lm + 1) / 2; - /* iterate mixer configs for this plane, to separate left/right with the id */ - for (stage_id = 0; stage_id < num_stages; stage_id++) { - struct drm_rect mixer_rect = { - .x1 = stage_id * mode->hdisplay / num_stages, - .y1 = 0, - .x2 = (stage_id + 1) * mode->hdisplay / num_stages, - .y2 = mode->vdisplay - }; - int cfg_idx = stage_id * PIPES_PER_STAGE; - - pipe_cfg = &pstate->pipe_cfg[cfg_idx]; - r_pipe_cfg = &pstate->pipe_cfg[cfg_idx + 1]; - - drm_rect_fp_to_int(&pipe_cfg->src_rect, &new_plane_state->src); - pipe_cfg->dst_rect = new_plane_state->dst; - - DPU_DEBUG_PLANE(pdpu, "checking src " DRM_RECT_FMT - " vs clip window " DRM_RECT_FMT "\n", - DRM_RECT_ARG(&pipe_cfg->src_rect), - DRM_RECT_ARG(&mixer_rect)); - - /* - * If this plane does not fall into mixer rect, check next - * mixer rect. - */ - if (!drm_rect_clip_scaled(&pipe_cfg->src_rect, - &pipe_cfg->dst_rect, - &mixer_rect)) { - memset(pipe_cfg, 0, 2 * sizeof(struct dpu_sw_pipe_cfg)); - - continue; + if ((drm_rect_width(&pipe_cfg->src_rect) > max_linewidth) || + _dpu_plane_calc_clk(&crtc_state->adjusted_mode, pipe_cfg) > max_mdp_clk_rate) { + if (drm_rect_width(&pipe_cfg->src_rect) > 2 * max_linewidth) { + DPU_DEBUG_PLANE(pdpu, "invalid src " DRM_RECT_FMT " line:%u\n", + DRM_RECT_ARG(&pipe_cfg->src_rect), max_linewidth); + return -E2BIG; } - pipe_cfg->dst_rect.x1 -= mixer_rect.x1; - pipe_cfg->dst_rect.x2 -= mixer_rect.x1; - - DPU_DEBUG_PLANE(pdpu, "Got clip src:" DRM_RECT_FMT " dst: " DRM_RECT_FMT "\n", - DRM_RECT_ARG(&pipe_cfg->src_rect), DRM_RECT_ARG(&pipe_cfg->dst_rect)); - - /* Split wide rect into 2 rect */ - if ((drm_rect_width(&pipe_cfg->src_rect) > max_linewidth) || - _dpu_plane_calc_clk(mode, pipe_cfg) > max_mdp_clk_rate) { - - if (drm_rect_width(&pipe_cfg->src_rect) > 2 * max_linewidth) { - DPU_DEBUG_PLANE(pdpu, "invalid src " DRM_RECT_FMT " line:%u\n", - DRM_RECT_ARG(&pipe_cfg->src_rect), max_linewidth); - return -E2BIG; - } - - memcpy(r_pipe_cfg, pipe_cfg, sizeof(struct dpu_sw_pipe_cfg)); - pipe_cfg->src_rect.x2 = (pipe_cfg->src_rect.x1 + pipe_cfg->src_rect.x2) >> 1; - pipe_cfg->dst_rect.x2 = (pipe_cfg->dst_rect.x1 + pipe_cfg->dst_rect.x2) >> 1; - r_pipe_cfg->src_rect.x1 = pipe_cfg->src_rect.x2; - r_pipe_cfg->dst_rect.x1 = pipe_cfg->dst_rect.x2; - DPU_DEBUG_PLANE(pdpu, "Split wide plane into:" - DRM_RECT_FMT " and " DRM_RECT_FMT "\n", - DRM_RECT_ARG(&pipe_cfg->src_rect), - DRM_RECT_ARG(&r_pipe_cfg->src_rect)); - } else { - memset(r_pipe_cfg, 0, sizeof(struct dpu_sw_pipe_cfg)); - } + *r_pipe_cfg = *pipe_cfg; + pipe_cfg->src_rect.x2 = (pipe_cfg->src_rect.x1 + pipe_cfg->src_rect.x2) >> 1; + pipe_cfg->dst_rect.x2 = (pipe_cfg->dst_rect.x1 + pipe_cfg->dst_rect.x2) >> 1; + r_pipe_cfg->src_rect.x1 = pipe_cfg->src_rect.x2; + r_pipe_cfg->dst_rect.x1 = pipe_cfg->dst_rect.x2; + } else { + memset(r_pipe_cfg, 0, sizeof(*r_pipe_cfg)); + } - drm_rect_rotate_inv(&pipe_cfg->src_rect, - new_plane_state->fb->width, - new_plane_state->fb->height, + drm_rect_rotate_inv(&pipe_cfg->src_rect, + new_plane_state->fb->width, new_plane_state->fb->height, + new_plane_state->rotation); + if (drm_rect_width(&r_pipe_cfg->src_rect) != 0) + drm_rect_rotate_inv(&r_pipe_cfg->src_rect, + new_plane_state->fb->width, new_plane_state->fb->height, new_plane_state->rotation); - if (drm_rect_width(&r_pipe_cfg->src_rect) != 0) - drm_rect_rotate_inv(&r_pipe_cfg->src_rect, - new_plane_state->fb->width, - new_plane_state->fb->height, - new_plane_state->rotation); - } - pstate->needs_qos_remap = drm_atomic_crtc_needs_modeset(crtc_state); return 0; @@ -1045,17 +985,20 @@ static int dpu_plane_atomic_check_sspp(struct drm_plane *plane, drm_atomic_get_new_plane_state(state, plane); struct dpu_plane *pdpu = to_dpu_plane(plane); struct dpu_plane_state *pstate = to_dpu_plane_state(new_plane_state); - struct dpu_sw_pipe *pipe; - struct dpu_sw_pipe_cfg *pipe_cfg; - int ret = 0, i; + struct dpu_sw_pipe *pipe = &pstate->pipe[0]; + struct dpu_sw_pipe *r_pipe = &pstate->pipe[1]; + struct dpu_sw_pipe_cfg *pipe_cfg = &pstate->pipe_cfg[0]; + struct dpu_sw_pipe_cfg *r_pipe_cfg = &pstate->pipe_cfg[1]; + int ret = 0; - for (i = 0; i < PIPES_PER_PLANE; i++) { - pipe = &pstate->pipe[i]; - pipe_cfg = &pstate->pipe_cfg[i]; - if (!drm_rect_width(&pipe_cfg->src_rect)) - continue; - DPU_DEBUG_PLANE(pdpu, "pipe %d is in use, validate it\n", i); - ret = dpu_plane_atomic_check_pipe(pdpu, pipe, pipe_cfg, + ret = dpu_plane_atomic_check_pipe(pdpu, pipe, pipe_cfg, + &crtc_state->adjusted_mode, + new_plane_state); + if (ret) + return ret; + + if (drm_rect_width(&r_pipe_cfg->src_rect) != 0) { + ret = dpu_plane_atomic_check_pipe(pdpu, r_pipe, r_pipe_cfg, &crtc_state->adjusted_mode, new_plane_state); if (ret) diff --git a/drivers/gpu/drm/msm/disp/mdp_format.h b/drivers/gpu/drm/msm/disp/mdp_format.h index a00d646ff4d4..915954bf5dc7 100644 --- a/drivers/gpu/drm/msm/disp/mdp_format.h +++ b/drivers/gpu/drm/msm/disp/mdp_format.h @@ -24,7 +24,7 @@ enum msm_format_flags { #define MSM_FORMAT_FLAG_UNPACK_TIGHT BIT(MSM_FORMAT_FLAG_UNPACK_TIGHT_BIT) #define MSM_FORMAT_FLAG_UNPACK_ALIGN_MSB BIT(MSM_FORMAT_FLAG_UNPACK_ALIGN_MSB_BIT) -/** +/* * DPU HW,Component order color map */ enum { @@ -37,6 +37,10 @@ enum { /** * struct msm_format: defines the format configuration * @pixel_format: format fourcc + * @bpc_g_y: element bit widths: BPC for G or Y + * @bpc_b_cb: element bit widths: BPC for B or Cb + * @bpc_r_cr: element bit widths: BPC for R or Cr + * @bpc_a: element bit widths: BPC for the alpha channel * @element: element color ordering * @fetch_type: how the color components are packed in pixel format * @chroma_sample: chroma sub-samplng type diff --git a/drivers/gpu/drm/msm/dp/dp_debug.h b/drivers/gpu/drm/msm/dp/dp_debug.h index 6dc0ff4f0f65..a90083fec856 100644 --- a/drivers/gpu/drm/msm/dp/dp_debug.h +++ b/drivers/gpu/drm/msm/dp/dp_debug.h @@ -12,7 +12,7 @@ #if defined(CONFIG_DEBUG_FS) /** - * msm_dp_debug_get() - configure and get the DisplayPlot debug module data + * msm_dp_debug_init() - configure and get the DisplayPlot debug module data * * @dev: device instance of the caller * @panel: instance of panel module diff --git a/drivers/gpu/drm/msm/dp/dp_drm.c b/drivers/gpu/drm/msm/dp/dp_drm.c index 9a461ab2f32f..fd6443d2b6ce 100644 --- a/drivers/gpu/drm/msm/dp/dp_drm.c +++ b/drivers/gpu/drm/msm/dp/dp_drm.c @@ -18,6 +18,7 @@ /** * msm_dp_bridge_detect - callback to determine if connector is connected * @bridge: Pointer to drm bridge structure + * @connector: Pointer to drm connector structure * Returns: Bridge's 'is connected' status */ static enum drm_connector_status diff --git a/drivers/gpu/drm/msm/dp/dp_link.h b/drivers/gpu/drm/msm/dp/dp_link.h index b1eb2de6d2a7..8460e4ad2d35 100644 --- a/drivers/gpu/drm/msm/dp/dp_link.h +++ b/drivers/gpu/drm/msm/dp/dp_link.h @@ -80,11 +80,11 @@ struct msm_dp_link { }; /** - * mdss_dp_test_bit_depth_to_bpp() - convert test bit depth to bpp + * msm_dp_link_bit_depth_to_bpp() - convert test bit depth to bpp * @tbd: test bit depth * - * Returns the bits per pixel (bpp) to be used corresponding to the - * git bit depth value. This function assumes that bit depth has + * Returns: the bits per pixel (bpp) to be used corresponding to the + * bit depth value. This function assumes that bit depth has * already been validated. */ static inline u32 msm_dp_link_bit_depth_to_bpp(u32 tbd) @@ -120,7 +120,8 @@ bool msm_dp_link_send_edid_checksum(struct msm_dp_link *msm_dp_link, u8 checksum /** * msm_dp_link_get() - get the functionalities of dp test module - * + * @dev: kernel device structure + * @aux: DisplayPort AUX channel * * return: a pointer to msm_dp_link struct */ diff --git a/drivers/gpu/drm/msm/dp/dp_panel.h b/drivers/gpu/drm/msm/dp/dp_panel.h index 921a296852d4..177c1328fd99 100644 --- a/drivers/gpu/drm/msm/dp/dp_panel.h +++ b/drivers/gpu/drm/msm/dp/dp_panel.h @@ -63,9 +63,9 @@ void msm_dp_panel_disable_vsc_sdp(struct msm_dp_panel *msm_dp_panel); /** * is_link_rate_valid() - validates the link rate - * @lane_rate: link rate requested by the sink + * @bw_code: link rate requested by the sink * - * Returns true if the requested link rate is supported. + * Returns: true if the requested link rate is supported. */ static inline bool is_link_rate_valid(u32 bw_code) { @@ -76,10 +76,10 @@ static inline bool is_link_rate_valid(u32 bw_code) } /** - * msm_dp_link_is_lane_count_valid() - validates the lane count + * is_lane_count_valid() - validates the lane count * @lane_count: lane count requested by the sink * - * Returns true if the requested lane count is supported. + * Returns: true if the requested lane count is supported. */ static inline bool is_lane_count_valid(u32 lane_count) { diff --git a/drivers/gpu/drm/msm/msm_fence.h b/drivers/gpu/drm/msm/msm_fence.h index 148196375a0b..3317a485beef 100644 --- a/drivers/gpu/drm/msm/msm_fence.h +++ b/drivers/gpu/drm/msm/msm_fence.h @@ -16,34 +16,29 @@ * incrementing fence seqno at the end of each submit */ struct msm_fence_context { + /** @dev: the drm device */ struct drm_device *dev; - /** name: human readable name for fence timeline */ + /** @name: human readable name for fence timeline */ char name[32]; - /** context: see dma_fence_context_alloc() */ + /** @context: see dma_fence_context_alloc() */ unsigned context; - /** index: similar to context, but local to msm_fence_context's */ + /** @index: similar to context, but local to msm_fence_context's */ unsigned index; - /** - * last_fence: - * + * @last_fence: * Last assigned fence, incremented each time a fence is created * on this fence context. If last_fence == completed_fence, * there is no remaining pending work */ uint32_t last_fence; - /** - * completed_fence: - * + * @completed_fence: * The last completed fence, updated from the CPU after interrupt * from GPU */ uint32_t completed_fence; - /** - * fenceptr: - * + * @fenceptr: * The address that the GPU directly writes with completed fence * seqno. This can be ahead of completed_fence. We can peek at * this to see if a fence has already signaled but the CPU hasn't @@ -51,6 +46,9 @@ struct msm_fence_context { */ volatile uint32_t *fenceptr; + /** + * @spinlock: fence context spinlock + */ spinlock_t spinlock; /* @@ -59,18 +57,22 @@ struct msm_fence_context { * don't queue, so maybe that is ok */ - /** next_deadline: Time of next deadline */ + /** @next_deadline: Time of next deadline */ ktime_t next_deadline; - /** - * next_deadline_fence: - * + * @next_deadline_fence: * Fence value for next pending deadline. The deadline timer is * canceled when this fence is signaled. */ uint32_t next_deadline_fence; - + /** + * @deadline_timer: tracks nearest deadline of a fence timeline and + * expires just before it. + */ struct hrtimer deadline_timer; + /** + * @deadline_work: work to do after deadline_timer expires + */ struct kthread_work deadline_work; }; diff --git a/drivers/gpu/drm/msm/msm_gem_vma.c b/drivers/gpu/drm/msm/msm_gem_vma.c index 71d5238437eb..8f7c90167447 100644 --- a/drivers/gpu/drm/msm/msm_gem_vma.c +++ b/drivers/gpu/drm/msm/msm_gem_vma.c @@ -65,7 +65,7 @@ struct msm_vm_unmap_op { }; /** - * struct msm_vma_op - A MAP or UNMAP operation + * struct msm_vm_op - A MAP or UNMAP operation */ struct msm_vm_op { /** @op: The operation type */ @@ -798,6 +798,9 @@ static const struct drm_sched_backend_ops msm_vm_bind_ops = { * synchronous operations are supported. In a user managed VM, userspace * handles virtual address allocation, and both async and sync operations * are supported. + * + * Returns: pointer to the created &struct drm_gpuvm on success + * or an ERR_PTR(-errno) on failure. */ struct drm_gpuvm * msm_gem_vm_create(struct drm_device *drm, struct msm_mmu *mmu, const char *name, diff --git a/drivers/gpu/drm/msm/msm_gpu.h b/drivers/gpu/drm/msm/msm_gpu.h index 2894fc118485..666cf499b7ec 100644 --- a/drivers/gpu/drm/msm/msm_gpu.h +++ b/drivers/gpu/drm/msm/msm_gpu.h @@ -116,15 +116,12 @@ struct msm_gpu_fault_info { * struct msm_gpu_devfreq - devfreq related state */ struct msm_gpu_devfreq { - /** devfreq: devfreq instance */ + /** @devfreq: devfreq instance */ struct devfreq *devfreq; - - /** lock: lock for "suspended", "busy_cycles", and "time" */ + /** @lock: lock for "suspended", "busy_cycles", and "time" */ struct mutex lock; - /** - * idle_freq: - * + * @idle_freq: * Shadow frequency used while the GPU is idle. From the PoV of * the devfreq governor, we are continuing to sample busyness and * adjust frequency while the GPU is idle, but we use this shadow @@ -132,43 +129,34 @@ struct msm_gpu_devfreq { * it is inactive. */ unsigned long idle_freq; - /** - * boost_constraint: - * + * @boost_freq: * A PM QoS constraint to boost min freq for a period of time * until the boost expires. */ struct dev_pm_qos_request boost_freq; - /** - * busy_cycles: Last busy counter value, for calculating elapsed busy + * @busy_cycles: Last busy counter value, for calculating elapsed busy * cycles since last sampling period. */ u64 busy_cycles; - - /** time: Time of last sampling period. */ + /** @time: Time of last sampling period. */ ktime_t time; - - /** idle_time: Time of last transition to idle: */ + /** @idle_time: Time of last transition to idle. */ ktime_t idle_time; - /** - * idle_work: - * + * @idle_work: * Used to delay clamping to idle freq on active->idle transition. */ struct msm_hrtimer_work idle_work; - /** - * boost_work: - * + * @boost_work: * Used to reset the boost_constraint after the boost period has * elapsed */ struct msm_hrtimer_work boost_work; - /** suspended: tracks if we're suspended */ + /** @suspended: tracks if we're suspended */ bool suspended; }; @@ -358,57 +346,43 @@ struct msm_gpu_perfcntr { struct msm_context { /** @queuelock: synchronizes access to submitqueues list */ rwlock_t queuelock; - /** @submitqueues: list of &msm_gpu_submitqueue created by userspace */ struct list_head submitqueues; - /** * @queueid: - * * Counter incremented each time a submitqueue is created, used to * assign &msm_gpu_submitqueue.id */ int queueid; - /** * @closed: The device file associated with this context has been closed. - * * Once the device is closed, any submits that have not been written * to the ring buffer are no-op'd. */ bool closed; - /** * @userspace_managed_vm: - * * Has userspace opted-in to userspace managed VM (ie. VM_BIND) via * MSM_PARAM_EN_VM_BIND? */ bool userspace_managed_vm; - /** * @vm: - * * The per-process GPU address-space. Do not access directly, use * msm_context_vm(). */ struct drm_gpuvm *vm; - - /** @kref: the reference count */ + /** @ref: the reference count */ struct kref ref; - /** * @seqno: - * * A unique per-process sequence number. Used to detect context * switches, without relying on keeping a, potentially dangling, * pointer to the previous context. */ int seqno; - /** * @sysprof: - * * The value of MSM_PARAM_SYSPROF set by userspace. This is * intended to be used by system profiling tools like Mesa's * pps-producer (perfetto), and restricted to CAP_SYS_ADMIN. @@ -423,40 +397,32 @@ struct msm_context { * file is closed. */ int sysprof; - /** * @comm: Overridden task comm, see MSM_PARAM_COMM * * Accessed under msm_gpu::lock */ char *comm; - /** * @cmdline: Overridden task cmdline, see MSM_PARAM_CMDLINE * * Accessed under msm_gpu::lock */ char *cmdline; - /** - * @elapsed: - * + * @elapsed_ns: * The total (cumulative) elapsed time GPU was busy with rendering * from this context in ns. */ uint64_t elapsed_ns; - /** * @cycles: - * * The total (cumulative) GPU cycles elapsed attributed to this * context. */ uint64_t cycles; - /** * @entities: - * * Table of per-priority-level sched entities used by submitqueues * associated with this &drm_file. Because some userspace apps * make assumptions about rendering from multiple gl contexts @@ -466,10 +432,8 @@ struct msm_context { * level. */ struct drm_sched_entity *entities[NR_SCHED_PRIORITIES * MSM_GPU_MAX_RINGS]; - /** * @ctx_mem: - * * Total amount of memory of GEM buffers with handles attached for * this context. */ @@ -479,7 +443,7 @@ struct msm_context { struct drm_gpuvm *msm_context_vm(struct drm_device *dev, struct msm_context *ctx); /** - * msm_context_is_vm_bind() - has userspace opted in to VM_BIND? + * msm_context_is_vmbind() - has userspace opted in to VM_BIND? * * @ctx: the drm_file context * @@ -487,6 +451,8 @@ struct drm_gpuvm *msm_context_vm(struct drm_device *dev, struct msm_context *ctx * do sparse binding including having multiple, potentially partial, * mappings in the VM. Therefore certain legacy uabi (ie. GET_IOVA, * SET_IOVA) are rejected because they don't have a sensible meaning. + * + * Returns: %true if userspace is managing the VM, %false otherwise. */ static inline bool msm_context_is_vmbind(struct msm_context *ctx) @@ -518,6 +484,8 @@ msm_context_is_vmbind(struct msm_context *ctx) * This allows generations without preemption (nr_rings==1) to have some * amount of prioritization, and provides more priority levels for gens * that do have preemption. + * + * Returns: %0 on success, %-errno on error. */ static inline int msm_gpu_convert_priority(struct msm_gpu *gpu, int prio, unsigned *ring_nr, enum drm_sched_priority *sched_prio) @@ -541,7 +509,7 @@ static inline int msm_gpu_convert_priority(struct msm_gpu *gpu, int prio, } /** - * struct msm_gpu_submitqueues - Userspace created context. + * struct msm_gpu_submitqueue - Userspace created context. * * A submitqueue is associated with a gl context or vk queue (or equiv) * in userspace. diff --git a/drivers/gpu/drm/msm/msm_iommu.c b/drivers/gpu/drm/msm/msm_iommu.c index a188617653e8..d5dede4ff761 100644 --- a/drivers/gpu/drm/msm/msm_iommu.c +++ b/drivers/gpu/drm/msm/msm_iommu.c @@ -364,7 +364,7 @@ msm_iommu_pagetable_prealloc_cleanup(struct msm_mmu *mmu, struct msm_mmu_preallo } /** - * alloc_pt() - Custom page table allocator + * msm_iommu_pagetable_alloc_pt() - Custom page table allocator * @cookie: Cookie passed at page table allocation time. * @size: Size of the page table. This size should be fixed, * and determined at creation time based on the granule size. @@ -416,7 +416,7 @@ msm_iommu_pagetable_alloc_pt(void *cookie, size_t size, gfp_t gfp) /** - * free_pt() - Custom page table free function + * msm_iommu_pagetable_free_pt() - Custom page table free function * @cookie: Cookie passed at page table allocation time. * @data: Page table to free. * @size: Size of the page table. This size should be fixed, diff --git a/drivers/gpu/drm/msm/msm_perf.c b/drivers/gpu/drm/msm/msm_perf.c index d3c7889aaf26..c369d4acc378 100644 --- a/drivers/gpu/drm/msm/msm_perf.c +++ b/drivers/gpu/drm/msm/msm_perf.c @@ -65,13 +65,13 @@ static int refill_buf(struct msm_perf_state *perf) if ((perf->cnt++ % 32) == 0) { /* Header line: */ - n = snprintf(ptr, rem, "%%BUSY"); + n = scnprintf(ptr, rem, "%%BUSY"); ptr += n; rem -= n; for (i = 0; i < gpu->num_perfcntrs; i++) { const struct msm_gpu_perfcntr *perfcntr = &gpu->perfcntrs[i]; - n = snprintf(ptr, rem, "\t%s", perfcntr->name); + n = scnprintf(ptr, rem, "\t%s", perfcntr->name); ptr += n; rem -= n; } @@ -93,21 +93,21 @@ static int refill_buf(struct msm_perf_state *perf) return ret; val = totaltime ? 1000 * activetime / totaltime : 0; - n = snprintf(ptr, rem, "%3d.%d%%", val / 10, val % 10); + n = scnprintf(ptr, rem, "%3d.%d%%", val / 10, val % 10); ptr += n; rem -= n; for (i = 0; i < ret; i++) { /* cycle counters (I think).. convert to MHz.. */ val = cntrs[i] / 10000; - n = snprintf(ptr, rem, "\t%5d.%02d", + n = scnprintf(ptr, rem, "\t%5d.%02d", val / 100, val % 100); ptr += n; rem -= n; } } - n = snprintf(ptr, rem, "\n"); + n = scnprintf(ptr, rem, "\n"); ptr += n; rem -= n; diff --git a/drivers/gpu/drm/nouveau/dispnv50/atom.h b/drivers/gpu/drm/nouveau/dispnv50/atom.h index 93f8f4f64578..b43c4f9bbcdf 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/atom.h +++ b/drivers/gpu/drm/nouveau/dispnv50/atom.h @@ -152,8 +152,21 @@ static inline struct nv50_head_atom * nv50_head_atom_get(struct drm_atomic_state *state, struct drm_crtc *crtc) { struct drm_crtc_state *statec = drm_atomic_get_crtc_state(state, crtc); + if (IS_ERR(statec)) return (void *)statec; + + return nv50_head_atom(statec); +} + +static inline struct nv50_head_atom * +nv50_head_atom_get_new(struct drm_atomic_state *state, struct drm_crtc *crtc) +{ + struct drm_crtc_state *statec = drm_atomic_get_new_crtc_state(state, crtc); + + if (!statec) + return NULL; + return nv50_head_atom(statec); } diff --git a/drivers/gpu/drm/nouveau/dispnv50/wndw.c b/drivers/gpu/drm/nouveau/dispnv50/wndw.c index ef9e410babbf..9a2c20fce0f3 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/wndw.c +++ b/drivers/gpu/drm/nouveau/dispnv50/wndw.c @@ -583,7 +583,7 @@ nv50_wndw_prepare_fb(struct drm_plane *plane, struct drm_plane_state *state) asyw->image.offset[0] = nvbo->offset; if (wndw->func->prepare) { - asyh = nv50_head_atom_get(asyw->state.state, asyw->state.crtc); + asyh = nv50_head_atom_get_new(asyw->state.state, asyw->state.crtc); if (IS_ERR(asyh)) return PTR_ERR(asyh); diff --git a/drivers/gpu/drm/xe/xe_guc_ct.c b/drivers/gpu/drm/xe/xe_guc_ct.c index 4ac434ad216f..a5019d1e741b 100644 --- a/drivers/gpu/drm/xe/xe_guc_ct.c +++ b/drivers/gpu/drm/xe/xe_guc_ct.c @@ -104,7 +104,9 @@ static void g2h_fence_cancel(struct g2h_fence *g2h_fence) { g2h_fence->cancel = true; g2h_fence->fail = true; - g2h_fence->done = true; + + /* WRITE_ONCE pairs with READ_ONCEs in guc_ct_send_recv. */ + WRITE_ONCE(g2h_fence->done, true); } static bool g2h_fence_needs_alloc(struct g2h_fence *g2h_fence) @@ -1203,10 +1205,13 @@ retry_same_fence: return ret; } - ret = wait_event_timeout(ct->g2h_fence_wq, g2h_fence.done, HZ); + /* READ_ONCEs pairs with WRITE_ONCEs in parse_g2h_response + * and g2h_fence_cancel. + */ + ret = wait_event_timeout(ct->g2h_fence_wq, READ_ONCE(g2h_fence.done), HZ); if (!ret) { LNL_FLUSH_WORK(&ct->g2h_worker); - if (g2h_fence.done) { + if (READ_ONCE(g2h_fence.done)) { xe_gt_warn(gt, "G2H fence %u, action %04x, done\n", g2h_fence.seqno, action[0]); ret = 1; @@ -1454,7 +1459,8 @@ static int parse_g2h_response(struct xe_guc_ct *ct, u32 *msg, u32 len) g2h_release_space(ct, GUC_CTB_HXG_MSG_MAX_LEN); - g2h_fence->done = true; + /* WRITE_ONCE pairs with READ_ONCEs in guc_ct_send_recv. */ + WRITE_ONCE(g2h_fence->done, true); smp_mb(); wake_up_all(&ct->g2h_fence_wq); diff --git a/drivers/gpu/drm/xe/xe_migrate.c b/drivers/gpu/drm/xe/xe_migrate.c index 2184af413b91..5a95b08a4723 100644 --- a/drivers/gpu/drm/xe/xe_migrate.c +++ b/drivers/gpu/drm/xe/xe_migrate.c @@ -2062,6 +2062,7 @@ static struct dma_fence *xe_migrate_vram(struct xe_migrate *m, unsigned long sram_offset, struct drm_pagemap_addr *sram_addr, u64 vram_addr, + struct dma_fence *deps, const enum xe_migrate_copy_dir dir) { struct xe_gt *gt = m->tile->primary_gt; @@ -2150,6 +2151,14 @@ static struct dma_fence *xe_migrate_vram(struct xe_migrate *m, xe_sched_job_add_migrate_flush(job, MI_INVALIDATE_TLB); + if (deps && !dma_fence_is_signaled(deps)) { + dma_fence_get(deps); + err = drm_sched_job_add_dependency(&job->drm, deps); + if (err) + dma_fence_wait(deps, false); + err = 0; + } + mutex_lock(&m->job_mutex); xe_sched_job_arm(job); fence = dma_fence_get(&job->drm.s_fence->finished); @@ -2175,6 +2184,8 @@ err: * @npages: Number of pages to migrate. * @src_addr: Array of DMA information (source of migrate) * @dst_addr: Device physical address of VRAM (destination of migrate) + * @deps: struct dma_fence representing the dependencies that need + * to be signaled before migration. * * Copy from an array dma addresses to a VRAM device physical address * @@ -2184,10 +2195,11 @@ err: struct dma_fence *xe_migrate_to_vram(struct xe_migrate *m, unsigned long npages, struct drm_pagemap_addr *src_addr, - u64 dst_addr) + u64 dst_addr, + struct dma_fence *deps) { return xe_migrate_vram(m, npages * PAGE_SIZE, 0, src_addr, dst_addr, - XE_MIGRATE_COPY_TO_VRAM); + deps, XE_MIGRATE_COPY_TO_VRAM); } /** @@ -2196,6 +2208,8 @@ struct dma_fence *xe_migrate_to_vram(struct xe_migrate *m, * @npages: Number of pages to migrate. * @src_addr: Device physical address of VRAM (source of migrate) * @dst_addr: Array of DMA information (destination of migrate) + * @deps: struct dma_fence representing the dependencies that need + * to be signaled before migration. * * Copy from a VRAM device physical address to an array dma addresses * @@ -2205,10 +2219,11 @@ struct dma_fence *xe_migrate_to_vram(struct xe_migrate *m, struct dma_fence *xe_migrate_from_vram(struct xe_migrate *m, unsigned long npages, u64 src_addr, - struct drm_pagemap_addr *dst_addr) + struct drm_pagemap_addr *dst_addr, + struct dma_fence *deps) { return xe_migrate_vram(m, npages * PAGE_SIZE, 0, dst_addr, src_addr, - XE_MIGRATE_COPY_TO_SRAM); + deps, XE_MIGRATE_COPY_TO_SRAM); } static void xe_migrate_dma_unmap(struct xe_device *xe, @@ -2384,7 +2399,7 @@ int xe_migrate_access_memory(struct xe_migrate *m, struct xe_bo *bo, __fence = xe_migrate_vram(m, current_bytes, (unsigned long)buf & ~PAGE_MASK, &pagemap_addr[current_page], - vram_addr, write ? + vram_addr, NULL, write ? XE_MIGRATE_COPY_TO_VRAM : XE_MIGRATE_COPY_TO_SRAM); if (IS_ERR(__fence)) { diff --git a/drivers/gpu/drm/xe/xe_migrate.h b/drivers/gpu/drm/xe/xe_migrate.h index 260e298e5dd7..b76441f062b4 100644 --- a/drivers/gpu/drm/xe/xe_migrate.h +++ b/drivers/gpu/drm/xe/xe_migrate.h @@ -116,12 +116,14 @@ int xe_migrate_init(struct xe_migrate *m); struct dma_fence *xe_migrate_to_vram(struct xe_migrate *m, unsigned long npages, struct drm_pagemap_addr *src_addr, - u64 dst_addr); + u64 dst_addr, + struct dma_fence *deps); struct dma_fence *xe_migrate_from_vram(struct xe_migrate *m, unsigned long npages, u64 src_addr, - struct drm_pagemap_addr *dst_addr); + struct drm_pagemap_addr *dst_addr, + struct dma_fence *deps); struct dma_fence *xe_migrate_copy(struct xe_migrate *m, struct xe_bo *src_bo, diff --git a/drivers/gpu/drm/xe/xe_svm.c b/drivers/gpu/drm/xe/xe_svm.c index 55c5a0eb82e1..f97e0af6a9b0 100644 --- a/drivers/gpu/drm/xe/xe_svm.c +++ b/drivers/gpu/drm/xe/xe_svm.c @@ -476,7 +476,8 @@ static void xe_svm_copy_us_stats_incr(struct xe_gt *gt, static int xe_svm_copy(struct page **pages, struct drm_pagemap_addr *pagemap_addr, - unsigned long npages, const enum xe_svm_copy_dir dir) + unsigned long npages, const enum xe_svm_copy_dir dir, + struct dma_fence *pre_migrate_fence) { struct xe_vram_region *vr = NULL; struct xe_gt *gt = NULL; @@ -565,7 +566,8 @@ static int xe_svm_copy(struct page **pages, __fence = xe_migrate_from_vram(vr->migrate, i - pos + incr, vram_addr, - &pagemap_addr[pos]); + &pagemap_addr[pos], + pre_migrate_fence); } else { vm_dbg(&xe->drm, "COPY TO VRAM - 0x%016llx -> 0x%016llx, NPAGES=%ld", @@ -574,13 +576,14 @@ static int xe_svm_copy(struct page **pages, __fence = xe_migrate_to_vram(vr->migrate, i - pos + incr, &pagemap_addr[pos], - vram_addr); + vram_addr, + pre_migrate_fence); } if (IS_ERR(__fence)) { err = PTR_ERR(__fence); goto err_out; } - + pre_migrate_fence = NULL; dma_fence_put(fence); fence = __fence; } @@ -603,20 +606,22 @@ static int xe_svm_copy(struct page **pages, vram_addr, (u64)pagemap_addr[pos].addr, 1); __fence = xe_migrate_from_vram(vr->migrate, 1, vram_addr, - &pagemap_addr[pos]); + &pagemap_addr[pos], + pre_migrate_fence); } else { vm_dbg(&xe->drm, "COPY TO VRAM - 0x%016llx -> 0x%016llx, NPAGES=%d", (u64)pagemap_addr[pos].addr, vram_addr, 1); __fence = xe_migrate_to_vram(vr->migrate, 1, &pagemap_addr[pos], - vram_addr); + vram_addr, + pre_migrate_fence); } if (IS_ERR(__fence)) { err = PTR_ERR(__fence); goto err_out; } - + pre_migrate_fence = NULL; dma_fence_put(fence); fence = __fence; } @@ -629,6 +634,8 @@ err_out: dma_fence_wait(fence, false); dma_fence_put(fence); } + if (pre_migrate_fence) + dma_fence_wait(pre_migrate_fence, false); /* * XXX: We can't derive the GT here (or anywhere in this functions, but @@ -645,16 +652,20 @@ err_out: static int xe_svm_copy_to_devmem(struct page **pages, struct drm_pagemap_addr *pagemap_addr, - unsigned long npages) + unsigned long npages, + struct dma_fence *pre_migrate_fence) { - return xe_svm_copy(pages, pagemap_addr, npages, XE_SVM_COPY_TO_VRAM); + return xe_svm_copy(pages, pagemap_addr, npages, XE_SVM_COPY_TO_VRAM, + pre_migrate_fence); } static int xe_svm_copy_to_ram(struct page **pages, struct drm_pagemap_addr *pagemap_addr, - unsigned long npages) + unsigned long npages, + struct dma_fence *pre_migrate_fence) { - return xe_svm_copy(pages, pagemap_addr, npages, XE_SVM_COPY_TO_SRAM); + return xe_svm_copy(pages, pagemap_addr, npages, XE_SVM_COPY_TO_SRAM, + pre_migrate_fence); } static struct xe_bo *to_xe_bo(struct drm_pagemap_devmem *devmem_allocation) @@ -667,6 +678,7 @@ static void xe_svm_devmem_release(struct drm_pagemap_devmem *devmem_allocation) struct xe_bo *bo = to_xe_bo(devmem_allocation); struct xe_device *xe = xe_bo_device(bo); + dma_fence_put(devmem_allocation->pre_migrate_fence); xe_bo_put_async(bo); xe_pm_runtime_put(xe); } @@ -861,6 +873,7 @@ static int xe_drm_pagemap_populate_mm(struct drm_pagemap *dpagemap, unsigned long timeslice_ms) { struct xe_vram_region *vr = container_of(dpagemap, typeof(*vr), dpagemap); + struct dma_fence *pre_migrate_fence = NULL; struct xe_device *xe = vr->xe; struct device *dev = xe->drm.dev; struct drm_buddy_block *block; @@ -887,8 +900,20 @@ static int xe_drm_pagemap_populate_mm(struct drm_pagemap *dpagemap, break; } + /* Ensure that any clearing or async eviction will complete before migration. */ + if (!dma_resv_test_signaled(bo->ttm.base.resv, DMA_RESV_USAGE_KERNEL)) { + err = dma_resv_get_singleton(bo->ttm.base.resv, DMA_RESV_USAGE_KERNEL, + &pre_migrate_fence); + if (err) + dma_resv_wait_timeout(bo->ttm.base.resv, DMA_RESV_USAGE_KERNEL, + false, MAX_SCHEDULE_TIMEOUT); + else if (pre_migrate_fence) + dma_fence_enable_sw_signaling(pre_migrate_fence); + } + drm_pagemap_devmem_init(&bo->devmem_allocation, dev, mm, - &dpagemap_devmem_ops, dpagemap, end - start); + &dpagemap_devmem_ops, dpagemap, end - start, + pre_migrate_fence); blocks = &to_xe_ttm_vram_mgr_resource(bo->ttm.resource)->blocks; list_for_each_entry(block, blocks, link) @@ -941,7 +966,7 @@ bool xe_svm_range_needs_migrate_to_vram(struct xe_svm_range *range, struct xe_vm xe_assert(vm->xe, IS_DGFX(vm->xe)); if (xe_svm_range_in_vram(range)) { - drm_info(&vm->xe->drm, "Range is already in VRAM\n"); + drm_dbg(&vm->xe->drm, "Range is already in VRAM\n"); return false; } diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c index 61596cda2b65..35ba852a172a 100644 --- a/drivers/infiniband/core/addr.c +++ b/drivers/infiniband/core/addr.c @@ -80,37 +80,25 @@ static const struct nla_policy ib_nl_addr_policy[LS_NLA_TYPE_MAX] = { .min = sizeof(struct rdma_nla_ls_gid)}, }; -static inline bool ib_nl_is_good_ip_resp(const struct nlmsghdr *nlh) +static void ib_nl_process_ip_rsep(const struct nlmsghdr *nlh) { struct nlattr *tb[LS_NLA_TYPE_MAX] = {}; + union ib_gid gid; + struct addr_req *req; + int found = 0; int ret; if (nlh->nlmsg_flags & RDMA_NL_LS_F_ERR) - return false; + return; ret = nla_parse_deprecated(tb, LS_NLA_TYPE_MAX - 1, nlmsg_data(nlh), nlmsg_len(nlh), ib_nl_addr_policy, NULL); if (ret) - return false; - - return true; -} - -static void ib_nl_process_good_ip_rsep(const struct nlmsghdr *nlh) -{ - const struct nlattr *head, *curr; - union ib_gid gid; - struct addr_req *req; - int len, rem; - int found = 0; - - head = (const struct nlattr *)nlmsg_data(nlh); - len = nlmsg_len(nlh); + return; - nla_for_each_attr(curr, head, len, rem) { - if (curr->nla_type == LS_NLA_TYPE_DGID) - memcpy(&gid, nla_data(curr), nla_len(curr)); - } + if (!tb[LS_NLA_TYPE_DGID]) + return; + memcpy(&gid, nla_data(tb[LS_NLA_TYPE_DGID]), sizeof(gid)); spin_lock_bh(&lock); list_for_each_entry(req, &req_list, list) { @@ -137,8 +125,7 @@ int ib_nl_handle_ip_res_resp(struct sk_buff *skb, !(NETLINK_CB(skb).sk)) return -EPERM; - if (ib_nl_is_good_ip_resp(nlh)) - ib_nl_process_good_ip_rsep(nlh); + ib_nl_process_ip_rsep(nlh); return 0; } diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index 95e89f5c147c..f00f1d3fbd9c 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -2009,6 +2009,7 @@ static void destroy_mc(struct rdma_id_private *id_priv, ib_sa_free_multicast(mc->sa_mc); if (rdma_protocol_roce(id_priv->id.device, id_priv->id.port_num)) { + struct rdma_cm_event *event = &mc->iboe_join.event; struct rdma_dev_addr *dev_addr = &id_priv->id.route.addr.dev_addr; struct net_device *ndev = NULL; @@ -2031,6 +2032,8 @@ static void destroy_mc(struct rdma_id_private *id_priv, dev_put(ndev); cancel_work_sync(&mc->iboe_join.work); + if (event->event == RDMA_CM_EVENT_MULTICAST_JOIN) + rdma_destroy_ah_attr(&event->param.ud.ah_attr); } kfree(mc); } diff --git a/drivers/infiniband/core/device.c b/drivers/infiniband/core/device.c index 13e8a1714bbd..1174ab7da629 100644 --- a/drivers/infiniband/core/device.c +++ b/drivers/infiniband/core/device.c @@ -2881,8 +2881,10 @@ int ib_del_sub_device_and_put(struct ib_device *sub) { struct ib_device *parent = sub->parent; - if (!parent) + if (!parent) { + ib_device_put(sub); return -EOPNOTSUPP; + } mutex_lock(&parent->subdev_lock); list_del(&sub->subdev_list); diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c index 11b1a194de44..ee390928511a 100644 --- a/drivers/infiniband/core/verbs.c +++ b/drivers/infiniband/core/verbs.c @@ -738,7 +738,7 @@ int ib_get_gids_from_rdma_hdr(const union rdma_network_hdr *hdr, (struct in6_addr *)dgid); return 0; } else if (net_type == RDMA_NETWORK_IPV6 || - net_type == RDMA_NETWORK_IB || RDMA_NETWORK_ROCE_V1) { + net_type == RDMA_NETWORK_IB || net_type == RDMA_NETWORK_ROCE_V1) { *dgid = hdr->ibgrh.dgid; *sgid = hdr->ibgrh.sgid; return 0; diff --git a/drivers/infiniband/hw/bnxt_re/hw_counters.h b/drivers/infiniband/hw/bnxt_re/hw_counters.h index 09d371d442aa..cebec033f4a0 100644 --- a/drivers/infiniband/hw/bnxt_re/hw_counters.h +++ b/drivers/infiniband/hw/bnxt_re/hw_counters.h @@ -89,6 +89,9 @@ enum bnxt_re_hw_stats { BNXT_RE_RES_SRQ_LOAD_ERR, BNXT_RE_RES_TX_PCI_ERR, BNXT_RE_RES_RX_PCI_ERR, + BNXT_RE_REQ_CQE_ERROR, + BNXT_RE_RESP_CQE_ERROR, + BNXT_RE_RESP_REMOTE_ACCESS_ERRS, BNXT_RE_OUT_OF_SEQ_ERR, BNXT_RE_TX_ATOMIC_REQ, BNXT_RE_TX_READ_REQ, @@ -110,9 +113,6 @@ enum bnxt_re_hw_stats { BNXT_RE_TX_CNP, BNXT_RE_RX_CNP, BNXT_RE_RX_ECN, - BNXT_RE_REQ_CQE_ERROR, - BNXT_RE_RESP_CQE_ERROR, - BNXT_RE_RESP_REMOTE_ACCESS_ERRS, BNXT_RE_NUM_EXT_COUNTERS }; diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.c b/drivers/infiniband/hw/bnxt_re/ib_verbs.c index f19b55c13d58..ff91511bd338 100644 --- a/drivers/infiniband/hw/bnxt_re/ib_verbs.c +++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.c @@ -2919,14 +2919,9 @@ int bnxt_re_post_send(struct ib_qp *ib_qp, const struct ib_send_wr *wr, wqe.rawqp1.lflags |= SQ_SEND_RAWETH_QP1_LFLAGS_ROCE_CRC; } - switch (wr->send_flags) { - case IB_SEND_IP_CSUM: + if (wr->send_flags & IB_SEND_IP_CSUM) wqe.rawqp1.lflags |= SQ_SEND_RAWETH_QP1_LFLAGS_IP_CHKSUM; - break; - default: - break; - } fallthrough; case IB_WR_SEND_WITH_INV: rc = bnxt_re_build_send_wqe(qp, wr, &wqe); diff --git a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c index 295a9610f3e6..4dad0cfcfa98 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c +++ b/drivers/infiniband/hw/bnxt_re/qplib_rcfw.c @@ -1112,7 +1112,7 @@ static int bnxt_qplib_map_creq_db(struct bnxt_qplib_rcfw *rcfw, u32 reg_offt) creq_db->dbinfo.flags = 0; creq_db->reg.bar_id = RCFW_COMM_CONS_PCI_BAR_REGION; creq_db->reg.bar_base = pci_resource_start(pdev, creq_db->reg.bar_id); - if (!creq_db->reg.bar_id) + if (!creq_db->reg.bar_base) dev_err(&pdev->dev, "QPLIB: CREQ BAR region %d resc start is 0!", creq_db->reg.bar_id); diff --git a/drivers/infiniband/hw/bnxt_re/qplib_res.c b/drivers/infiniband/hw/bnxt_re/qplib_res.c index 875d7b52c06a..4d674a3aee1a 100644 --- a/drivers/infiniband/hw/bnxt_re/qplib_res.c +++ b/drivers/infiniband/hw/bnxt_re/qplib_res.c @@ -64,9 +64,7 @@ static void __free_pbl(struct bnxt_qplib_res *res, struct bnxt_qplib_pbl *pbl, for (i = 0; i < pbl->pg_count; i++) { if (pbl->pg_arr[i]) dma_free_coherent(&pdev->dev, pbl->pg_size, - (void *)((unsigned long) - pbl->pg_arr[i] & - PAGE_MASK), + pbl->pg_arr[i], pbl->pg_map_arr[i]); else dev_warn(&pdev->dev, @@ -237,7 +235,7 @@ int bnxt_qplib_alloc_init_hwq(struct bnxt_qplib_hwq *hwq, if (npbl % BIT(MAX_PDL_LVL_SHIFT)) npde++; /* Alloc PDE pages */ - sginfo.pgsize = npde * pg_size; + sginfo.pgsize = npde * ROCE_PG_SIZE_4K; sginfo.npages = 1; rc = __alloc_pbl(res, &hwq->pbl[PBL_LVL_0], &sginfo); if (rc) @@ -245,7 +243,7 @@ int bnxt_qplib_alloc_init_hwq(struct bnxt_qplib_hwq *hwq, /* Alloc PBL pages */ sginfo.npages = npbl; - sginfo.pgsize = PAGE_SIZE; + sginfo.pgsize = ROCE_PG_SIZE_4K; rc = __alloc_pbl(res, &hwq->pbl[PBL_LVL_1], &sginfo); if (rc) goto fail; diff --git a/drivers/infiniband/hw/efa/efa_verbs.c b/drivers/infiniband/hw/efa/efa_verbs.c index 22d3e25c3b9d..755bba8d58bb 100644 --- a/drivers/infiniband/hw/efa/efa_verbs.c +++ b/drivers/infiniband/hw/efa/efa_verbs.c @@ -1320,13 +1320,9 @@ static int umem_to_page_list(struct efa_dev *dev, u32 hp_cnt, u8 hp_shift) { - u32 pages_in_hp = BIT(hp_shift - PAGE_SHIFT); struct ib_block_iter biter; unsigned int hp_idx = 0; - ibdev_dbg(&dev->ibdev, "hp_cnt[%u], pages_in_hp[%u]\n", - hp_cnt, pages_in_hp); - rdma_umem_for_each_dma_block(umem, &biter, BIT(hp_shift)) page_list[hp_idx++] = rdma_block_iter_dma_address(&biter); diff --git a/drivers/infiniband/hw/irdma/utils.c b/drivers/infiniband/hw/irdma/utils.c index cc2a12f735d3..13d7499131d4 100644 --- a/drivers/infiniband/hw/irdma/utils.c +++ b/drivers/infiniband/hw/irdma/utils.c @@ -251,7 +251,7 @@ int irdma_net_event(struct notifier_block *notifier, unsigned long event, void *ptr) { struct neighbour *neigh = ptr; - struct net_device *real_dev, *netdev = (struct net_device *)neigh->dev; + struct net_device *real_dev, *netdev; struct irdma_device *iwdev; struct ib_device *ibdev; __be32 *p; @@ -260,6 +260,7 @@ int irdma_net_event(struct notifier_block *notifier, unsigned long event, switch (event) { case NETEVENT_NEIGH_UPDATE: + netdev = neigh->dev; real_dev = rdma_vlan_dev_real_dev(netdev); if (!real_dev) real_dev = netdev; diff --git a/drivers/infiniband/hw/mana/cq.c b/drivers/infiniband/hw/mana/cq.c index 1becc8779123..7600412b0739 100644 --- a/drivers/infiniband/hw/mana/cq.c +++ b/drivers/infiniband/hw/mana/cq.c @@ -56,6 +56,10 @@ int mana_ib_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr, doorbell = mana_ucontext->doorbell; } else { is_rnic_cq = true; + if (attr->cqe > U32_MAX / COMP_ENTRY_SIZE / 2 + 1) { + ibdev_dbg(ibdev, "CQE %d exceeding limit\n", attr->cqe); + return -EINVAL; + } buf_size = MANA_PAGE_ALIGN(roundup_pow_of_two(attr->cqe * COMP_ENTRY_SIZE)); cq->cqe = buf_size / COMP_ENTRY_SIZE; err = mana_ib_create_kernel_queue(mdev, buf_size, GDMA_CQ, &cq->queue); diff --git a/drivers/infiniband/sw/rxe/rxe_net.c b/drivers/infiniband/sw/rxe/rxe_net.c index 0195d361e5e3..0bd0902b11f7 100644 --- a/drivers/infiniband/sw/rxe/rxe_net.c +++ b/drivers/infiniband/sw/rxe/rxe_net.c @@ -64,7 +64,39 @@ static inline void rxe_reclassify_recv_socket(struct socket *sock) break; default: WARN_ON_ONCE(1); + return; } + /* + * sock_lock_init_class_and_name() calls + * sk_owner_set(sk, THIS_MODULE); in order + * to make sure the referenced global + * variables rxe_recv_slock_key and + * rxe_recv_sk_key are not removed + * before the socket is closed. + * + * However this prevents rxe_net_exit() + * from being called and 'rmmod rdma_rxe' + * is refused because of the references. + * + * For the global sockets in recv_sockets, + * we are sure that rxe_net_exit() will call + * rxe_release_udp_tunnel -> udp_tunnel_sock_release. + * + * So we don't need the additional reference to + * our own (THIS_MODULE). + */ + sk_owner_put(sk); + /* + * We also call sk_owner_clear() otherwise + * sk_owner_put(sk) in sk_prot_free will + * fail, which is called via + * sk_free -> __sk_free -> sk_destruct + * and sk_destruct calls __sk_destruct + * directly or via call_rcu() + * so sk_prot_free() might be called + * after rxe_net_exit(). + */ + sk_owner_clear(sk); #endif /* CONFIG_DEBUG_LOCK_ALLOC */ } diff --git a/drivers/infiniband/sw/rxe/rxe_odp.c b/drivers/infiniband/sw/rxe/rxe_odp.c index ae71812bea82..c928cbf2e35f 100644 --- a/drivers/infiniband/sw/rxe/rxe_odp.c +++ b/drivers/infiniband/sw/rxe/rxe_odp.c @@ -179,8 +179,10 @@ static int rxe_odp_map_range_and_lock(struct rxe_mr *mr, u64 iova, int length, u return err; need_fault = rxe_check_pagefault(umem_odp, iova, length); - if (need_fault) + if (need_fault) { + mutex_unlock(&umem_odp->umem_mutex); return -EFAULT; + } } return 0; diff --git a/drivers/infiniband/ulp/rtrs/rtrs-clt.c b/drivers/infiniband/ulp/rtrs/rtrs-clt.c index 71387811b281..2b397a544cb9 100644 --- a/drivers/infiniband/ulp/rtrs/rtrs-clt.c +++ b/drivers/infiniband/ulp/rtrs/rtrs-clt.c @@ -1464,6 +1464,7 @@ static void query_fast_reg_mode(struct rtrs_clt_path *clt_path) mr_page_shift = max(12, ffs(ib_dev->attrs.page_size_cap) - 1); max_pages_per_mr = ib_dev->attrs.max_mr_size; do_div(max_pages_per_mr, (1ull << mr_page_shift)); + max_pages_per_mr = min_not_zero((u32)max_pages_per_mr, U32_MAX); clt_path->max_pages_per_mr = min3(clt_path->max_pages_per_mr, (u32)max_pages_per_mr, ib_dev->attrs.max_fast_reg_page_list_len); diff --git a/drivers/infiniband/ulp/rtrs/rtrs-pri.h b/drivers/infiniband/ulp/rtrs/rtrs-pri.h index ef29bd483b5a..59529d593869 100644 --- a/drivers/infiniband/ulp/rtrs/rtrs-pri.h +++ b/drivers/infiniband/ulp/rtrs/rtrs-pri.h @@ -150,7 +150,7 @@ enum rtrs_msg_types { /** * enum rtrs_msg_flags - RTRS message flags. - * @RTRS_NEED_INVAL: Send invalidation in response. + * @RTRS_MSG_NEED_INVAL_F: Send invalidation in response. * @RTRS_MSG_NEW_RKEY_F: Send refreshed rkey in response. */ enum rtrs_msg_flags { @@ -179,16 +179,19 @@ struct rtrs_sg_desc { * @recon_cnt: Reconnections counter * @sess_uuid: UUID of a session (path) * @paths_uuid: UUID of a group of sessions (paths) - * + * @first_conn: %1 if the connection request is the first for that session, + * otherwise %0 * NOTE: max size 56 bytes, see man rdma_connect(). */ struct rtrs_msg_conn_req { - /* Is set to 0 by cma.c in case of AF_IB, do not touch that. - * see https://www.spinics.net/lists/linux-rdma/msg22397.html + /** + * @__cma_version: Is set to 0 by cma.c in case of AF_IB, do not touch + * that. See https://www.spinics.net/lists/linux-rdma/msg22397.html */ u8 __cma_version; - /* On sender side that should be set to 0, or cma_save_ip_info() - * extract garbage and will fail. + /** + * @__ip_version: On sender side that should be set to 0, or + * cma_save_ip_info() extract garbage and will fail. */ u8 __ip_version; __le16 magic; @@ -199,6 +202,7 @@ struct rtrs_msg_conn_req { uuid_t sess_uuid; uuid_t paths_uuid; u8 first_conn : 1; + /* private: */ u8 reserved_bits : 7; u8 reserved[11]; }; @@ -211,6 +215,7 @@ struct rtrs_msg_conn_req { * @queue_depth: max inflight messages (queue-depth) in this session * @max_io_size: max io size server supports * @max_hdr_size: max msg header size server supports + * @flags: RTRS message flags for this message * * NOTE: size is 56 bytes, max possible is 136 bytes, see man rdma_accept(). */ @@ -222,22 +227,24 @@ struct rtrs_msg_conn_rsp { __le32 max_io_size; __le32 max_hdr_size; __le32 flags; + /* private: */ u8 reserved[36]; }; /** - * struct rtrs_msg_info_req + * struct rtrs_msg_info_req - client additional info request * @type: @RTRS_MSG_INFO_REQ * @pathname: Path name chosen by client */ struct rtrs_msg_info_req { __le16 type; u8 pathname[NAME_MAX]; + /* private: */ u8 reserved[15]; }; /** - * struct rtrs_msg_info_rsp + * struct rtrs_msg_info_rsp - server additional info response * @type: @RTRS_MSG_INFO_RSP * @sg_cnt: Number of @desc entries * @desc: RDMA buffers where the client can write to server @@ -245,12 +252,14 @@ struct rtrs_msg_info_req { struct rtrs_msg_info_rsp { __le16 type; __le16 sg_cnt; + /* private: */ u8 reserved[4]; + /* public: */ struct rtrs_sg_desc desc[]; }; /** - * struct rtrs_msg_rkey_rsp + * struct rtrs_msg_rkey_rsp - server refreshed rkey response * @type: @RTRS_MSG_RKEY_RSP * @buf_id: RDMA buf_id of the new rkey * @rkey: new remote key for RDMA buffers id from server @@ -264,6 +273,7 @@ struct rtrs_msg_rkey_rsp { /** * struct rtrs_msg_rdma_read - RDMA data transfer request from client * @type: always @RTRS_MSG_READ + * @flags: RTRS message flags (enum rtrs_msg_flags) * @usr_len: length of user payload * @sg_cnt: number of @desc entries * @desc: RDMA buffers where the server can write the result to @@ -277,7 +287,7 @@ struct rtrs_msg_rdma_read { }; /** - * struct_msg_rdma_write - Message transferred to server with RDMA-Write + * struct rtrs_msg_rdma_write - Message transferred to server with RDMA-Write * @type: always @RTRS_MSG_WRITE * @usr_len: length of user payload */ @@ -287,7 +297,7 @@ struct rtrs_msg_rdma_write { }; /** - * struct_msg_rdma_hdr - header for read or write request + * struct rtrs_msg_rdma_hdr - header for read or write request * @type: @RTRS_MSG_WRITE | @RTRS_MSG_READ */ struct rtrs_msg_rdma_hdr { diff --git a/drivers/infiniband/ulp/rtrs/rtrs.h b/drivers/infiniband/ulp/rtrs/rtrs.h index b48b53a7c143..b5bd35712de0 100644 --- a/drivers/infiniband/ulp/rtrs/rtrs.h +++ b/drivers/infiniband/ulp/rtrs/rtrs.h @@ -24,8 +24,8 @@ struct rtrs_srv_op; /** * enum rtrs_clt_link_ev - Events about connectivity state of a client - * @RTRS_CLT_LINK_EV_RECONNECTED Client was reconnected. - * @RTRS_CLT_LINK_EV_DISCONNECTED Client was disconnected. + * @RTRS_CLT_LINK_EV_RECONNECTED: Client was reconnected. + * @RTRS_CLT_LINK_EV_DISCONNECTED: Client was disconnected. */ enum rtrs_clt_link_ev { RTRS_CLT_LINK_EV_RECONNECTED, @@ -33,7 +33,9 @@ enum rtrs_clt_link_ev { }; /** - * Source and destination address of a path to be established + * struct rtrs_addr - Source and destination address of a path to be established + * @src: source address + * @dst: destination address */ struct rtrs_addr { struct sockaddr_storage *src; @@ -41,7 +43,7 @@ struct rtrs_addr { }; /** - * rtrs_clt_ops - it holds the link event callback and private pointer. + * struct rtrs_clt_ops - it holds the link event callback and private pointer. * @priv: User supplied private data. * @link_ev: Event notification callback function for connection state changes * @priv: User supplied data that was passed to rtrs_clt_open() @@ -67,10 +69,10 @@ enum wait_type { }; /** - * enum rtrs_clt_con_type() type of ib connection to use with a given + * enum rtrs_clt_con_type - type of ib connection to use with a given * rtrs_permit - * @ADMIN_CON - use connection reserved for "service" messages - * @IO_CON - use a connection reserved for IO + * @RTRS_ADMIN_CON: use connection reserved for "service" messages + * @RTRS_IO_CON: use a connection reserved for IO */ enum rtrs_clt_con_type { RTRS_ADMIN_CON, @@ -85,7 +87,7 @@ void rtrs_clt_put_permit(struct rtrs_clt_sess *sess, struct rtrs_permit *permit); /** - * rtrs_clt_req_ops - it holds the request confirmation callback + * struct rtrs_clt_req_ops - it holds the request confirmation callback * and a private pointer. * @priv: User supplied private data. * @conf_fn: callback function to be called as confirmation @@ -105,7 +107,11 @@ int rtrs_clt_request(int dir, struct rtrs_clt_req_ops *ops, int rtrs_clt_rdma_cq_direct(struct rtrs_clt_sess *clt, unsigned int index); /** - * rtrs_attrs - RTRS session attributes + * struct rtrs_attrs - RTRS session attributes + * @queue_depth: queue_depth saved from rtrs_clt_sess message + * @max_io_size: max_io_size from rtrs_clt_sess message, capped to + * @max_segments * %SZ_4K + * @max_segments: max_segments saved from rtrs_clt_sess message */ struct rtrs_attrs { u32 queue_depth; diff --git a/drivers/md/md.c b/drivers/md/md.c index e5922a682953..6d73f6e196a9 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -1999,7 +1999,6 @@ static int super_1_validate(struct mddev *mddev, struct md_rdev *freshest, struc mddev->layout = le32_to_cpu(sb->layout); mddev->raid_disks = le32_to_cpu(sb->raid_disks); mddev->dev_sectors = le64_to_cpu(sb->size); - mddev->logical_block_size = le32_to_cpu(sb->logical_block_size); mddev->events = ev1; mddev->bitmap_info.offset = 0; mddev->bitmap_info.space = 0; @@ -2015,6 +2014,9 @@ static int super_1_validate(struct mddev *mddev, struct md_rdev *freshest, struc mddev->max_disks = (4096-256)/2; + if (!mddev->logical_block_size) + mddev->logical_block_size = le32_to_cpu(sb->logical_block_size); + if ((le32_to_cpu(sb->feature_map) & MD_FEATURE_BITMAP_OFFSET) && mddev->bitmap_info.file == NULL) { mddev->bitmap_info.offset = @@ -3882,7 +3884,6 @@ out_free_rdev: static int analyze_sbs(struct mddev *mddev) { - int i; struct md_rdev *rdev, *freshest, *tmp; freshest = NULL; @@ -3909,11 +3910,9 @@ static int analyze_sbs(struct mddev *mddev) super_types[mddev->major_version]. validate_super(mddev, NULL/*freshest*/, freshest); - i = 0; rdev_for_each_safe(rdev, tmp, mddev) { if (mddev->max_disks && - (rdev->desc_nr >= mddev->max_disks || - i > mddev->max_disks)) { + rdev->desc_nr >= mddev->max_disks) { pr_warn("md: %s: %pg: only %d devices permitted\n", mdname(mddev), rdev->bdev, mddev->max_disks); @@ -4407,7 +4406,7 @@ raid_disks_store(struct mddev *mddev, const char *buf, size_t len) if (err < 0) return err; - err = mddev_lock(mddev); + err = mddev_suspend_and_lock(mddev); if (err) return err; if (mddev->pers) @@ -4432,7 +4431,7 @@ raid_disks_store(struct mddev *mddev, const char *buf, size_t len) } else mddev->raid_disks = n; out_unlock: - mddev_unlock(mddev); + mddev_unlock_and_resume(mddev); return err ? err : len; } static struct md_sysfs_entry md_raid_disks = @@ -5981,13 +5980,33 @@ lbs_store(struct mddev *mddev, const char *buf, size_t len) if (mddev->major_version == 0) return -EINVAL; - if (mddev->pers) - return -EBUSY; - err = kstrtouint(buf, 10, &lbs); if (err < 0) return -EINVAL; + if (mddev->pers) { + unsigned int curr_lbs; + + if (mddev->logical_block_size) + return -EBUSY; + /* + * To fix forward compatibility issues, LBS is not + * configured for arrays from old kernels (<=6.18) by default. + * If the user confirms no rollback to old kernels, + * enable LBS by writing current LBS — to prevent data + * loss from LBS changes. + */ + curr_lbs = queue_logical_block_size(mddev->gendisk->queue); + if (lbs != curr_lbs) + return -EINVAL; + + mddev->logical_block_size = curr_lbs; + set_bit(MD_SB_CHANGE_DEVS, &mddev->sb_flags); + pr_info("%s: logical block size configured successfully, array will not be assembled in old kernels (<= 6.18)\n", + mdname(mddev)); + return len; + } + err = mddev_lock(mddev); if (err) goto unlock; @@ -6163,7 +6182,27 @@ int mddev_stack_rdev_limits(struct mddev *mddev, struct queue_limits *lim, mdname(mddev)); return -EINVAL; } - mddev->logical_block_size = lim->logical_block_size; + + /* Only 1.x meta needs to set logical block size */ + if (mddev->major_version == 0) + return 0; + + /* + * Fix forward compatibility issue. Only set LBS by default for + * new arrays, mddev->events == 0 indicates the array was just + * created. When assembling an array, read LBS from the superblock + * instead — LBS is 0 in superblocks created by old kernels. + */ + if (!mddev->events) { + pr_info("%s: array will not be assembled in old kernels that lack configurable LBS support (<= 6.18)\n", + mdname(mddev)); + mddev->logical_block_size = lim->logical_block_size; + } + + if (!mddev->logical_block_size) + pr_warn("%s: echo current LBS to md/logical_block_size to prevent data loss issues from LBS changes.\n" + "\tNote: After setting, array will not be assembled in old kernels (<= 6.18)\n", + mdname(mddev)); return 0; } diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index e57ce3295292..8dc98f545969 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -7187,12 +7187,14 @@ raid5_store_group_thread_cnt(struct mddev *mddev, const char *page, size_t len) err = mddev_suspend_and_lock(mddev); if (err) return err; + conf = mddev->private; + if (!conf) { + mddev_unlock_and_resume(mddev); + return -ENODEV; + } raid5_quiesce(mddev, true); - conf = mddev->private; - if (!conf) - err = -ENODEV; - else if (new != conf->worker_cnt_per_group) { + if (new != conf->worker_cnt_per_group) { old_groups = conf->worker_groups; if (old_groups) flush_workqueue(raid5_wq); diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c index a1a177713d99..2c4131ed7e30 100644 --- a/drivers/net/dsa/b53/b53_common.c +++ b/drivers/net/dsa/b53/b53_common.c @@ -2169,6 +2169,9 @@ static int b53_fdb_copy(int port, const struct b53_arl_entry *ent, if (!ent->is_valid) return 0; + if (is_multicast_ether_addr(ent->mac)) + return 0; + if (port != ent->port) return 0; diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c index 75893c90a0a1..315d97036ac1 100644 --- a/drivers/net/ethernet/airoha/airoha_eth.c +++ b/drivers/net/ethernet/airoha/airoha_eth.c @@ -2924,19 +2924,26 @@ static int airoha_alloc_gdm_port(struct airoha_eth *eth, port->id = id; eth->ports[p] = port; - err = airoha_metadata_dst_alloc(port); - if (err) - return err; + return airoha_metadata_dst_alloc(port); +} - err = register_netdev(dev); - if (err) - goto free_metadata_dst; +static int airoha_register_gdm_devices(struct airoha_eth *eth) +{ + int i; - return 0; + for (i = 0; i < ARRAY_SIZE(eth->ports); i++) { + struct airoha_gdm_port *port = eth->ports[i]; + int err; -free_metadata_dst: - airoha_metadata_dst_free(port); - return err; + if (!port) + continue; + + err = register_netdev(port->dev); + if (err) + return err; + } + + return 0; } static int airoha_probe(struct platform_device *pdev) @@ -3027,6 +3034,10 @@ static int airoha_probe(struct platform_device *pdev) } } + err = airoha_register_gdm_devices(eth); + if (err) + goto error_napi_stop; + return 0; error_napi_stop: @@ -3040,10 +3051,12 @@ error_hw_cleanup: for (i = 0; i < ARRAY_SIZE(eth->ports); i++) { struct airoha_gdm_port *port = eth->ports[i]; - if (port && port->dev->reg_state == NETREG_REGISTERED) { + if (!port) + continue; + + if (port->dev->reg_state == NETREG_REGISTERED) unregister_netdev(port->dev); - airoha_metadata_dst_free(port); - } + airoha_metadata_dst_free(port); } free_netdev(eth->napi_dev); platform_set_drvdata(pdev, NULL); diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c b/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c index a68757e8fd22..c63ddb12237e 100644 --- a/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c +++ b/drivers/net/ethernet/amd/xgbe/xgbe-phy-v2.c @@ -1928,6 +1928,7 @@ static void xgbe_set_rx_adap_mode(struct xgbe_prv_data *pdata, { if (pdata->rx_adapt_retries++ >= MAX_RX_ADAPT_RETRIES) { pdata->rx_adapt_retries = 0; + pdata->mode_set = false; return; } @@ -1974,6 +1975,7 @@ static void xgbe_rx_adaptation(struct xgbe_prv_data *pdata) */ netif_dbg(pdata, link, pdata->netdev, "Block_lock done"); pdata->rx_adapt_done = true; + pdata->rx_adapt_retries = 0; pdata->mode_set = false; return; } diff --git a/drivers/net/ethernet/broadcom/Kconfig b/drivers/net/ethernet/broadcom/Kconfig index 666522d64775..ca565ace6e6a 100644 --- a/drivers/net/ethernet/broadcom/Kconfig +++ b/drivers/net/ethernet/broadcom/Kconfig @@ -255,14 +255,14 @@ config BNXT_HWMON devices, via the hwmon sysfs interface. config BNGE - tristate "Broadcom Ethernet device support" + tristate "Broadcom ThorUltra Ethernet device support" depends on PCI select NET_DEVLINK select PAGE_POOL help - This driver supports Broadcom 50/100/200/400/800 gigabit Ethernet cards. - The module will be called bng_en. To compile this driver as a module, - choose M here. + This driver supports Broadcom ThorUltra 50/100/200/400/800 gigabit + Ethernet cards. The module will be called bng_en. To compile this + driver as a module, choose M here. config BCMASP tristate "Broadcom ASP 2.0 Ethernet support" diff --git a/drivers/net/ethernet/broadcom/bnge/bnge.h b/drivers/net/ethernet/broadcom/bnge/bnge.h index 411744894349..32fc16a37d02 100644 --- a/drivers/net/ethernet/broadcom/bnge/bnge.h +++ b/drivers/net/ethernet/broadcom/bnge/bnge.h @@ -5,7 +5,7 @@ #define _BNGE_H_ #define DRV_NAME "bng_en" -#define DRV_SUMMARY "Broadcom 800G Ethernet Linux Driver" +#define DRV_SUMMARY "Broadcom ThorUltra NIC Ethernet Driver" #include <linux/etherdevice.h> #include <linux/bnxt/hsi.h> diff --git a/drivers/net/ethernet/broadcom/bnge/bnge_core.c b/drivers/net/ethernet/broadcom/bnge/bnge_core.c index c94e132bebc8..b4090283df0f 100644 --- a/drivers/net/ethernet/broadcom/bnge/bnge_core.c +++ b/drivers/net/ethernet/broadcom/bnge/bnge_core.c @@ -19,7 +19,7 @@ char bnge_driver_name[] = DRV_NAME; static const struct { char *name; } board_info[] = { - [BCM57708] = { "Broadcom BCM57708 50Gb/100Gb/200Gb/400Gb/800Gb Ethernet" }, + [BCM57708] = { "Broadcom BCM57708 ThorUltra 50Gb/100Gb/200Gb/400Gb/800Gb Ethernet" }, }; static const struct pci_device_id bnge_pci_tbl[] = { diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c index e461f5072884..6511ecd5856b 100644 --- a/drivers/net/ethernet/cadence/macb_main.c +++ b/drivers/net/ethernet/cadence/macb_main.c @@ -708,7 +708,6 @@ static void macb_mac_link_up(struct phylink_config *config, /* Initialize rings & buffers as clearing MACB_BIT(TE) in link down * cleared the pipeline and control registers. */ - bp->macbgem_ops.mog_init_rings(bp); macb_init_buffers(bp); for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) @@ -2954,6 +2953,8 @@ static int macb_open(struct net_device *dev) goto pm_exit; } + bp->macbgem_ops.mog_init_rings(bp); + for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) { napi_enable(&queue->napi_rx); napi_enable(&queue->napi_tx); diff --git a/drivers/net/ethernet/freescale/enetc/netc_blk_ctrl.c b/drivers/net/ethernet/freescale/enetc/netc_blk_ctrl.c index 443983fdecd9..7fd39f895290 100644 --- a/drivers/net/ethernet/freescale/enetc/netc_blk_ctrl.c +++ b/drivers/net/ethernet/freescale/enetc/netc_blk_ctrl.c @@ -577,11 +577,17 @@ static int imx94_enetc_mdio_phyaddr_config(struct netc_blk_ctrl *priv, } addr = netc_get_phy_addr(np); - if (addr <= 0) { + if (addr < 0) { dev_err(dev, "Failed to get PHY address\n"); return addr; } + /* The default value of LaBCR[MDIO_PHYAD_PRTAD] is 0, + * so no need to set the register. + */ + if (!addr) + return 0; + if (phy_mask & BIT(addr)) { dev_err(dev, "Find same PHY address in EMDIO and ENETC node\n"); diff --git a/drivers/net/ethernet/google/gve/gve_main.c b/drivers/net/ethernet/google/gve/gve_main.c index a7a088a77f37..7eb64e1e4d85 100644 --- a/drivers/net/ethernet/google/gve/gve_main.c +++ b/drivers/net/ethernet/google/gve/gve_main.c @@ -558,7 +558,7 @@ static int gve_alloc_notify_blocks(struct gve_priv *priv) block->priv = priv; err = request_irq(priv->msix_vectors[msix_idx].vector, gve_is_gqi(priv) ? gve_intr : gve_intr_dqo, - 0, block->name, block); + IRQF_NO_AUTOEN, block->name, block); if (err) { dev_err(&priv->pdev->dev, "Failed to receive msix vector %d\n", i); diff --git a/drivers/net/ethernet/google/gve/gve_utils.c b/drivers/net/ethernet/google/gve/gve_utils.c index ace9b8698021..b53b7fcdcdaf 100644 --- a/drivers/net/ethernet/google/gve/gve_utils.c +++ b/drivers/net/ethernet/google/gve/gve_utils.c @@ -112,11 +112,13 @@ void gve_add_napi(struct gve_priv *priv, int ntfy_idx, netif_napi_add_locked(priv->dev, &block->napi, gve_poll); netif_napi_set_irq_locked(&block->napi, block->irq); + enable_irq(block->irq); } void gve_remove_napi(struct gve_priv *priv, int ntfy_idx) { struct gve_notify_block *block = &priv->ntfy_blocks[ntfy_idx]; + disable_irq(block->irq); netif_napi_del_locked(&block->napi); } diff --git a/drivers/net/ethernet/intel/e1000/e1000_main.c b/drivers/net/ethernet/intel/e1000/e1000_main.c index 292389aceb2d..7f078ec9c14c 100644 --- a/drivers/net/ethernet/intel/e1000/e1000_main.c +++ b/drivers/net/ethernet/intel/e1000/e1000_main.c @@ -4094,7 +4094,15 @@ static bool e1000_tbi_should_accept(struct e1000_adapter *adapter, u32 length, const u8 *data) { struct e1000_hw *hw = &adapter->hw; - u8 last_byte = *(data + length - 1); + u8 last_byte; + + /* Guard against OOB on data[length - 1] */ + if (unlikely(!length)) + return false; + /* Upper bound: length must not exceed rx_buffer_len */ + if (unlikely(length > adapter->rx_buffer_len)) + return false; + last_byte = *(data + length - 1); if (TBI_ACCEPT(hw, status, errors, length, last_byte)) { unsigned long irq_flags; diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h index d2d03db2acec..dcb50c2e1aa2 100644 --- a/drivers/net/ethernet/intel/i40e/i40e.h +++ b/drivers/net/ethernet/intel/i40e/i40e.h @@ -1422,4 +1422,15 @@ static inline struct i40e_veb *i40e_pf_get_main_veb(struct i40e_pf *pf) return (pf->lan_veb != I40E_NO_VEB) ? pf->veb[pf->lan_veb] : NULL; } +static inline u32 i40e_get_max_num_descriptors(const struct i40e_pf *pf) +{ + const struct i40e_hw *hw = &pf->hw; + + switch (hw->mac.type) { + case I40E_MAC_XL710: + return I40E_MAX_NUM_DESCRIPTORS_XL710; + default: + return I40E_MAX_NUM_DESCRIPTORS; + } +} #endif /* _I40E_H_ */ diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index f2c2646ea298..6a47ea0927e9 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -2013,18 +2013,6 @@ static void i40e_get_drvinfo(struct net_device *netdev, drvinfo->n_priv_flags += I40E_GL_PRIV_FLAGS_STR_LEN; } -static u32 i40e_get_max_num_descriptors(struct i40e_pf *pf) -{ - struct i40e_hw *hw = &pf->hw; - - switch (hw->mac.type) { - case I40E_MAC_XL710: - return I40E_MAX_NUM_DESCRIPTORS_XL710; - default: - return I40E_MAX_NUM_DESCRIPTORS; - } -} - static void i40e_get_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring, struct kernel_ethtool_ringparam *kernel_ring, diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index d8192aa23254..0b1cc0481027 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -2234,6 +2234,7 @@ static void i40e_set_rx_mode(struct net_device *netdev) vsi->flags |= I40E_VSI_FLAG_FILTER_CHANGED; set_bit(__I40E_MACVLAN_SYNC_PENDING, vsi->back->state); } + i40e_service_event_schedule(vsi->back); } /** diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c index 8b30a3accd31..1fa877b52f61 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c @@ -656,7 +656,7 @@ static int i40e_config_vsi_tx_queue(struct i40e_vf *vf, u16 vsi_id, /* ring_len has to be multiple of 8 */ if (!IS_ALIGNED(info->ring_len, 8) || - info->ring_len > I40E_MAX_NUM_DESCRIPTORS_XL710) { + info->ring_len > i40e_get_max_num_descriptors(pf)) { ret = -EINVAL; goto error_context; } @@ -726,7 +726,7 @@ static int i40e_config_vsi_rx_queue(struct i40e_vf *vf, u16 vsi_id, /* ring_len has to be multiple of 32 */ if (!IS_ALIGNED(info->ring_len, 32) || - info->ring_len > I40E_MAX_NUM_DESCRIPTORS_XL710) { + info->ring_len > i40e_get_max_num_descriptors(pf)) { ret = -EINVAL; goto error_param; } diff --git a/drivers/net/ethernet/intel/iavf/iavf_main.c b/drivers/net/ethernet/intel/iavf/iavf_main.c index c2fbe443ef85..4b0fc8f354bc 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_main.c +++ b/drivers/net/ethernet/intel/iavf/iavf_main.c @@ -1726,11 +1726,11 @@ static int iavf_config_rss_reg(struct iavf_adapter *adapter) u16 i; dw = (u32 *)adapter->rss_key; - for (i = 0; i <= adapter->rss_key_size / 4; i++) + for (i = 0; i < adapter->rss_key_size / 4; i++) wr32(hw, IAVF_VFQF_HKEY(i), dw[i]); dw = (u32 *)adapter->rss_lut; - for (i = 0; i <= adapter->rss_lut_size / 4; i++) + for (i = 0; i < adapter->rss_lut_size / 4; i++) wr32(hw, IAVF_VFQF_HLUT(i), dw[i]); iavf_flush(hw); diff --git a/drivers/net/ethernet/intel/idpf/idpf_lib.c b/drivers/net/ethernet/intel/idpf/idpf_lib.c index 7a7e101afeb6..7ce4eb71a433 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_lib.c +++ b/drivers/net/ethernet/intel/idpf/idpf_lib.c @@ -1271,7 +1271,7 @@ void idpf_mbx_task(struct work_struct *work) idpf_mb_irq_enable(adapter); else queue_delayed_work(adapter->mbx_wq, &adapter->mbx_task, - msecs_to_jiffies(300)); + usecs_to_jiffies(300)); idpf_recv_mb_msg(adapter); } diff --git a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c index 44cd4b466c48..5bbe7d9294c1 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c +++ b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c @@ -1016,6 +1016,9 @@ static int idpf_send_get_lan_memory_regions(struct idpf_adapter *adapter) struct idpf_vc_xn_params xn_params = { .vc_op = VIRTCHNL2_OP_GET_LAN_MEMORY_REGIONS, .recv_buf.iov_len = IDPF_CTLQ_MAX_BUF_LEN, + .send_buf.iov_len = + sizeof(struct virtchnl2_get_lan_memory_regions) + + sizeof(struct virtchnl2_mem_region), .timeout_ms = IDPF_VC_XN_DEFAULT_TIMEOUT_MSEC, }; int num_regions, size; @@ -1028,6 +1031,8 @@ static int idpf_send_get_lan_memory_regions(struct idpf_adapter *adapter) return -ENOMEM; xn_params.recv_buf.iov_base = rcvd_regions; + rcvd_regions->num_memory_regions = cpu_to_le16(1); + xn_params.send_buf.iov_base = rcvd_regions; reply_sz = idpf_vc_xn_exec(adapter, &xn_params); if (reply_sz < 0) return reply_sz; diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_ethtool.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_ethtool.c index b90e23dc49de..b6449f0a9e7d 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_ethtool.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_ethtool.c @@ -418,6 +418,14 @@ static int otx2_set_ringparam(struct net_device *netdev, */ if (rx_count < pfvf->hw.rq_skid) rx_count = pfvf->hw.rq_skid; + + if (ring->rx_pending < 16) { + netdev_err(netdev, + "rx ring size %u invalid, min is 16\n", + ring->rx_pending); + return -EINVAL; + } + rx_count = Q_COUNT(Q_SIZE(rx_count, 3)); /* Due pipelining impact minimum 2000 unused SQ CQE's diff --git a/drivers/net/ethernet/microsoft/mana/gdma_main.c b/drivers/net/ethernet/microsoft/mana/gdma_main.c index efb4e412ec7e..0055c231acf6 100644 --- a/drivers/net/ethernet/microsoft/mana/gdma_main.c +++ b/drivers/net/ethernet/microsoft/mana/gdma_main.c @@ -481,7 +481,7 @@ static void mana_serv_reset(struct pci_dev *pdev) /* Perform PCI rescan on device if we failed on HWC */ dev_err(&pdev->dev, "MANA service: resume failed, rescanning\n"); mana_serv_rescan(pdev); - goto out; + return; } if (ret) diff --git a/drivers/net/ethernet/smsc/smc91x.c b/drivers/net/ethernet/smsc/smc91x.c index 9d1a83a5fa7e..d16c178d1034 100644 --- a/drivers/net/ethernet/smsc/smc91x.c +++ b/drivers/net/ethernet/smsc/smc91x.c @@ -516,15 +516,7 @@ static inline void smc_rcv(struct net_device *dev) * any other concurrent access and C would always interrupt B. But life * isn't that easy in a SMP world... */ -#define smc_special_trylock(lock, flags) \ -({ \ - int __ret; \ - local_irq_save(flags); \ - __ret = spin_trylock(lock); \ - if (!__ret) \ - local_irq_restore(flags); \ - __ret; \ -}) +#define smc_special_trylock(lock, flags) spin_trylock_irqsave(lock, flags) #define smc_special_lock(lock, flags) spin_lock_irqsave(lock, flags) #define smc_special_unlock(lock, flags) spin_unlock_irqrestore(lock, flags) #else diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index da206b24aaed..b3730312aeed 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -89,6 +89,7 @@ MODULE_PARM_DESC(phyaddr, "Physical device address"); #define STMMAC_XDP_CONSUMED BIT(0) #define STMMAC_XDP_TX BIT(1) #define STMMAC_XDP_REDIRECT BIT(2) +#define STMMAC_XSK_CONSUMED BIT(3) static int flow_ctrl = 0xdead; module_param(flow_ctrl, int, 0644); @@ -5126,6 +5127,7 @@ static int stmmac_xdp_get_tx_queue(struct stmmac_priv *priv, static int stmmac_xdp_xmit_back(struct stmmac_priv *priv, struct xdp_buff *xdp) { + bool zc = !!(xdp->rxq->mem.type == MEM_TYPE_XSK_BUFF_POOL); struct xdp_frame *xdpf = xdp_convert_buff_to_frame(xdp); int cpu = smp_processor_id(); struct netdev_queue *nq; @@ -5142,9 +5144,18 @@ static int stmmac_xdp_xmit_back(struct stmmac_priv *priv, /* Avoids TX time-out as we are sharing with slow path */ txq_trans_cond_update(nq); - res = stmmac_xdp_xmit_xdpf(priv, queue, xdpf, false); - if (res == STMMAC_XDP_TX) + /* For zero copy XDP_TX action, dma_map is true */ + res = stmmac_xdp_xmit_xdpf(priv, queue, xdpf, zc); + if (res == STMMAC_XDP_TX) { stmmac_flush_tx_descriptors(priv, queue); + } else if (res == STMMAC_XDP_CONSUMED && zc) { + /* xdp has been freed by xdp_convert_buff_to_frame(), + * no need to call xsk_buff_free() again, so return + * STMMAC_XSK_CONSUMED. + */ + res = STMMAC_XSK_CONSUMED; + xdp_return_frame(xdpf); + } __netif_tx_unlock(nq); @@ -5494,6 +5505,8 @@ read_again: break; case STMMAC_XDP_CONSUMED: xsk_buff_free(buf->xdp); + fallthrough; + case STMMAC_XSK_CONSUMED: rx_dropped++; break; case STMMAC_XDP_TX: diff --git a/drivers/net/ethernet/wangxun/Kconfig b/drivers/net/ethernet/wangxun/Kconfig index d138dea7d208..ec278f99d295 100644 --- a/drivers/net/ethernet/wangxun/Kconfig +++ b/drivers/net/ethernet/wangxun/Kconfig @@ -21,6 +21,7 @@ config LIBWX depends on PTP_1588_CLOCK_OPTIONAL select PAGE_POOL select DIMLIB + select PHYLINK help Common library for Wangxun(R) Ethernet drivers. @@ -29,7 +30,6 @@ config NGBE depends on PCI depends on PTP_1588_CLOCK_OPTIONAL select LIBWX - select PHYLINK help This driver supports Wangxun(R) GbE PCI Express family of adapters. @@ -48,7 +48,6 @@ config TXGBE depends on PTP_1588_CLOCK_OPTIONAL select MARVELL_10G_PHY select REGMAP - select PHYLINK select HWMON if TXGBE=y select SFP select GPIOLIB @@ -71,7 +70,6 @@ config TXGBEVF depends on PCI_MSI depends on PTP_1588_CLOCK_OPTIONAL select LIBWX - select PHYLINK help This driver supports virtual functions for SP1000A, WX1820AL, WX5XXX, WX5XXXAL. diff --git a/drivers/net/fjes/fjes_hw.c b/drivers/net/fjes/fjes_hw.c index b9b5554ea862..5ad2673f213d 100644 --- a/drivers/net/fjes/fjes_hw.c +++ b/drivers/net/fjes/fjes_hw.c @@ -334,7 +334,7 @@ int fjes_hw_init(struct fjes_hw *hw) ret = fjes_hw_reset(hw); if (ret) - return ret; + goto err_iounmap; fjes_hw_set_irqmask(hw, REG_ICTL_MASK_ALL, true); @@ -347,8 +347,10 @@ int fjes_hw_init(struct fjes_hw *hw) hw->max_epid = fjes_hw_get_max_epid(hw); hw->my_epid = fjes_hw_get_my_epid(hw); - if ((hw->max_epid == 0) || (hw->my_epid >= hw->max_epid)) - return -ENXIO; + if ((hw->max_epid == 0) || (hw->my_epid >= hw->max_epid)) { + ret = -ENXIO; + goto err_iounmap; + } ret = fjes_hw_setup(hw); @@ -356,6 +358,10 @@ int fjes_hw_init(struct fjes_hw *hw) hw->hw_info.trace_size = FJES_DEBUG_BUFFER_SIZE; return ret; + +err_iounmap: + fjes_hw_iounmap(hw); + return ret; } void fjes_hw_exit(struct fjes_hw *hw) diff --git a/drivers/net/mdio/mdio-aspeed.c b/drivers/net/mdio/mdio-aspeed.c index e55be6dc9ae7..d6b9004c61dc 100644 --- a/drivers/net/mdio/mdio-aspeed.c +++ b/drivers/net/mdio/mdio-aspeed.c @@ -63,6 +63,13 @@ static int aspeed_mdio_op(struct mii_bus *bus, u8 st, u8 op, u8 phyad, u8 regad, iowrite32(ctrl, ctx->base + ASPEED_MDIO_CTRL); + /* Workaround for read-after-write issue. + * The controller may return stale data if a read follows immediately + * after a write. A dummy read forces the hardware to update its + * internal state, ensuring that the next real read returns correct data. + */ + ioread32(ctx->base + ASPEED_MDIO_CTRL); + return readl_poll_timeout(ctx->base + ASPEED_MDIO_CTRL, ctrl, !(ctrl & ASPEED_MDIO_CTRL_FIRE), ASPEED_MDIO_INTERVAL_US, diff --git a/drivers/net/mdio/mdio-realtek-rtl9300.c b/drivers/net/mdio/mdio-realtek-rtl9300.c index 33694c3ff9a7..405a07075dd1 100644 --- a/drivers/net/mdio/mdio-realtek-rtl9300.c +++ b/drivers/net/mdio/mdio-realtek-rtl9300.c @@ -354,7 +354,6 @@ static int rtl9300_mdiobus_probe_one(struct device *dev, struct rtl9300_mdio_pri struct fwnode_handle *node) { struct rtl9300_mdio_chan *chan; - struct fwnode_handle *child; struct mii_bus *bus; u32 mdio_bus; int err; @@ -371,7 +370,7 @@ static int rtl9300_mdiobus_probe_one(struct device *dev, struct rtl9300_mdio_pri * compatible = "ethernet-phy-ieee802.3-c45". This does mean we can't * support both c45 and c22 on the same MDIO bus. */ - fwnode_for_each_child_node(node, child) + fwnode_for_each_child_node_scoped(node, child) if (fwnode_device_is_compatible(child, "ethernet-phy-ieee802.3-c45")) priv->smi_bus_is_c45[mdio_bus] = true; @@ -409,7 +408,6 @@ static int rtl9300_mdiobus_map_ports(struct device *dev) { struct rtl9300_mdio_priv *priv = dev_get_drvdata(dev); struct device *parent = dev->parent; - struct fwnode_handle *port; int err; struct fwnode_handle *ports __free(fwnode_handle) = @@ -418,7 +416,7 @@ static int rtl9300_mdiobus_map_ports(struct device *dev) return dev_err_probe(dev, -EINVAL, "%pfwP missing ethernet-ports\n", dev_fwnode(parent)); - fwnode_for_each_child_node(ports, port) { + fwnode_for_each_child_node_scoped(ports, port) { struct device_node *mdio_dn; u32 addr; u32 bus; diff --git a/drivers/net/phy/mediatek/mtk-ge-soc.c b/drivers/net/phy/mediatek/mtk-ge-soc.c index cd09fbf92ef2..2c4bbc236202 100644 --- a/drivers/net/phy/mediatek/mtk-ge-soc.c +++ b/drivers/net/phy/mediatek/mtk-ge-soc.c @@ -1167,9 +1167,9 @@ static int mt798x_phy_calibration(struct phy_device *phydev) } buf = (u32 *)nvmem_cell_read(cell, &len); + nvmem_cell_put(cell); if (IS_ERR(buf)) return PTR_ERR(buf); - nvmem_cell_put(cell); if (!buf[0] || !buf[1] || !buf[2] || !buf[3] || len < 4 * sizeof(u32)) { phydev_err(phydev, "invalid efuse data\n"); diff --git a/drivers/net/team/team_core.c b/drivers/net/team/team_core.c index 4d5c9ae8f221..c08a5c1bd6e4 100644 --- a/drivers/net/team/team_core.c +++ b/drivers/net/team/team_core.c @@ -878,7 +878,7 @@ static void __team_queue_override_enabled_check(struct team *team) static void team_queue_override_port_prio_changed(struct team *team, struct team_port *port) { - if (!port->queue_id || team_port_enabled(port)) + if (!port->queue_id || !team_port_enabled(port)) return; __team_queue_override_port_del(team, port); __team_queue_override_port_add(team, port); diff --git a/drivers/net/usb/asix_common.c b/drivers/net/usb/asix_common.c index 7fd763917ae2..6ab3486072cb 100644 --- a/drivers/net/usb/asix_common.c +++ b/drivers/net/usb/asix_common.c @@ -335,6 +335,11 @@ int asix_read_phy_addr(struct usbnet *dev, bool internal) offset = (internal ? 1 : 0); ret = buf[offset]; + if (ret >= PHY_MAX_ADDR) { + netdev_err(dev->net, "invalid PHY address: %d\n", ret); + return -ENODEV; + } + netdev_dbg(dev->net, "%s PHY address 0x%x\n", internal ? "internal" : "external", ret); diff --git a/drivers/net/usb/ax88172a.c b/drivers/net/usb/ax88172a.c index f613e4bc68c8..758a423a459b 100644 --- a/drivers/net/usb/ax88172a.c +++ b/drivers/net/usb/ax88172a.c @@ -210,11 +210,7 @@ static int ax88172a_bind(struct usbnet *dev, struct usb_interface *intf) ret = asix_read_phy_addr(dev, priv->use_embdphy); if (ret < 0) goto free; - if (ret >= PHY_MAX_ADDR) { - netdev_err(dev->net, "Invalid PHY address %#x\n", ret); - ret = -ENODEV; - goto free; - } + priv->phy_addr = ret; ax88172a_reset_phy(dev, priv->use_embdphy); diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c index 278e6cb6f4d9..e40b0669d9f4 100644 --- a/drivers/net/usb/rtl8150.c +++ b/drivers/net/usb/rtl8150.c @@ -211,6 +211,8 @@ static int async_set_registers(rtl8150_t *dev, u16 indx, u16 size, u16 reg) if (res == -ENODEV) netif_device_detach(dev->netdev); dev_err(&dev->udev->dev, "%s failed with %d\n", __func__, res); + kfree(req); + usb_free_urb(async_urb); } return res; } diff --git a/drivers/net/usb/sr9700.c b/drivers/net/usb/sr9700.c index 091bc2aca7e8..820c4c506979 100644 --- a/drivers/net/usb/sr9700.c +++ b/drivers/net/usb/sr9700.c @@ -52,7 +52,7 @@ static int sr_read_reg(struct usbnet *dev, u8 reg, u8 *value) static int sr_write_reg(struct usbnet *dev, u8 reg, u8 value) { - return usbnet_write_cmd(dev, SR_WR_REGS, SR_REQ_WR_REG, + return usbnet_write_cmd(dev, SR_WR_REG, SR_REQ_WR_REG, value, reg, NULL, 0); } @@ -65,7 +65,7 @@ static void sr_write_async(struct usbnet *dev, u8 reg, u16 length, static void sr_write_reg_async(struct usbnet *dev, u8 reg, u8 value) { - usbnet_write_cmd_async(dev, SR_WR_REGS, SR_REQ_WR_REG, + usbnet_write_cmd_async(dev, SR_WR_REG, SR_REQ_WR_REG, value, reg, NULL, 0); } @@ -539,6 +539,11 @@ static const struct usb_device_id products[] = { USB_DEVICE(0x0fe6, 0x9700), /* SR9700 device */ .driver_info = (unsigned long)&sr9700_driver_info, }, + { + /* SR9700 with virtual driver CD-ROM - interface 0 is the CD-ROM device */ + USB_DEVICE_INTERFACE_NUMBER(0x0fe6, 0x9702, 1), + .driver_info = (unsigned long)&sr9700_driver_info, + }, {}, /* END */ }; diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 1d9faa70ba3b..36742e64cff7 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -831,7 +831,6 @@ int usbnet_stop(struct net_device *net) clear_bit(EVENT_DEV_OPEN, &dev->flags); netif_stop_queue(net); - netdev_reset_queue(net); netif_info(dev, ifdown, dev->net, "stop stats: rx/tx %lu/%lu, errs %lu/%lu\n", @@ -875,6 +874,8 @@ int usbnet_stop(struct net_device *net) timer_delete_sync(&dev->delay); cancel_work_sync(&dev->kevent); + netdev_reset_queue(net); + if (!pm) usb_autopm_put_interface(dev->intf); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c index 3391f07b01de..f8fc6f30fbe5 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c @@ -1597,7 +1597,7 @@ static void _iwl_op_mode_stop(struct iwl_drv *drv) */ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context) { - unsigned int min_core, max_core, loaded_core; + int min_core, max_core, loaded_core; struct iwl_drv *drv = context; struct iwl_fw *fw = &drv->fw; const struct iwl_ucode_header *ucode; @@ -1676,7 +1676,7 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context) if (loaded_core < min_core || loaded_core > max_core) { IWL_ERR(drv, "Driver unable to support your firmware API. " - "Driver supports FW core %u..%u, firmware is %u.\n", + "Driver supports FW core %d..%d, firmware is %d.\n", min_core, max_core, loaded_core); goto try_again; } diff --git a/drivers/net/wireless/intel/iwlwifi/mld/ptp.c b/drivers/net/wireless/intel/iwlwifi/mld/ptp.c index ffeb37a7f830..231920425c06 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/ptp.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/ptp.c @@ -121,6 +121,12 @@ static int iwl_mld_ptp_gettime(struct ptp_clock_info *ptp, return 0; } +static int iwl_mld_ptp_settime(struct ptp_clock_info *ptp, + const struct timespec64 *ts) +{ + return -EOPNOTSUPP; +} + static int iwl_mld_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) { struct iwl_mld *mld = container_of(ptp, struct iwl_mld, @@ -279,6 +285,7 @@ void iwl_mld_ptp_init(struct iwl_mld *mld) mld->ptp_data.ptp_clock_info.owner = THIS_MODULE; mld->ptp_data.ptp_clock_info.gettime64 = iwl_mld_ptp_gettime; + mld->ptp_data.ptp_clock_info.settime64 = iwl_mld_ptp_settime; mld->ptp_data.ptp_clock_info.max_adj = 0x7fffffff; mld->ptp_data.ptp_clock_info.adjtime = iwl_mld_ptp_adjtime; mld->ptp_data.ptp_clock_info.adjfine = iwl_mld_ptp_adjfine; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ptp.c b/drivers/net/wireless/intel/iwlwifi/mvm/ptp.c index 06a4c9f74797..ad156b82eaa9 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ptp.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ptp.c @@ -220,6 +220,12 @@ static int iwl_mvm_ptp_gettime(struct ptp_clock_info *ptp, return 0; } +static int iwl_mvm_ptp_settime(struct ptp_clock_info *ptp, + const struct timespec64 *ts) +{ + return -EOPNOTSUPP; +} + static int iwl_mvm_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) { struct iwl_mvm *mvm = container_of(ptp, struct iwl_mvm, @@ -281,6 +287,7 @@ void iwl_mvm_ptp_init(struct iwl_mvm *mvm) mvm->ptp_data.ptp_clock_info.adjfine = iwl_mvm_ptp_adjfine; mvm->ptp_data.ptp_clock_info.adjtime = iwl_mvm_ptp_adjtime; mvm->ptp_data.ptp_clock_info.gettime64 = iwl_mvm_ptp_gettime; + mvm->ptp_data.ptp_clock_info.settime64 = iwl_mvm_ptp_settime; mvm->ptp_data.scaled_freq = SCALE_FACTOR; /* Give a short 'friendly name' to identify the PHC clock */ diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c index ea99167765b0..0457712286d5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c @@ -3019,7 +3019,7 @@ int mt76_connac2_load_ram(struct mt76_dev *dev, const char *fw_wm, } hdr = (const void *)(fw->data + fw->size - sizeof(*hdr)); - dev_info(dev->dev, "WM Firmware Version: %.10s, Build Time: %.15s\n", + dev_info(dev->dev, "WM Firmware Version: %.10s, Build Time: %.15s", hdr->fw_ver, hdr->build_date); ret = mt76_connac_mcu_send_ram_firmware(dev, hdr, fw->data, false); @@ -3048,7 +3048,7 @@ int mt76_connac2_load_ram(struct mt76_dev *dev, const char *fw_wm, } hdr = (const void *)(fw->data + fw->size - sizeof(*hdr)); - dev_info(dev->dev, "WA Firmware Version: %.10s, Build Time: %.15s\n", + dev_info(dev->dev, "WA Firmware Version: %.10s, Build Time: %.15s", hdr->fw_ver, hdr->build_date); ret = mt76_connac_mcu_send_ram_firmware(dev, hdr, fw->data, true); @@ -3101,7 +3101,6 @@ int mt76_connac2_load_patch(struct mt76_dev *dev, const char *fw_name) int i, ret, sem, max_len = mt76_is_sdio(dev) ? 2048 : 4096; const struct mt76_connac2_patch_hdr *hdr; const struct firmware *fw = NULL; - char build_date[17]; sem = mt76_connac_mcu_patch_sem_ctrl(dev, true); switch (sem) { @@ -3125,11 +3124,8 @@ int mt76_connac2_load_patch(struct mt76_dev *dev, const char *fw_name) } hdr = (const void *)fw->data; - strscpy(build_date, hdr->build_date, sizeof(build_date)); - build_date[16] = '\0'; - strim(build_date); - dev_info(dev->dev, "HW/SW Version: 0x%x, Build Time: %.16s\n", - be32_to_cpu(hdr->hw_sw_ver), build_date); + dev_info(dev->dev, "HW/SW Version: 0x%x, Build Time: %.16s", + be32_to_cpu(hdr->hw_sw_ver), hdr->build_date); for (i = 0; i < be32_to_cpu(hdr->desc.n_region); i++) { struct mt76_connac2_patch_sec *sec; diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/trx.c b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/trx.c index aa702ba7c9f5..d6c35e8d02a5 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/trx.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/trx.c @@ -511,7 +511,8 @@ void rtl92cu_tx_fill_desc(struct ieee80211_hw *hw, if (sta) { sta_entry = (struct rtl_sta_info *)sta->drv_priv; tid = ieee80211_get_tid(hdr); - agg_state = sta_entry->tids[tid].agg.agg_state; + if (tid < MAX_TID_COUNT) + agg_state = sta_entry->tids[tid].agg.agg_state; ampdu_density = sta->deflink.ht_cap.ampdu_density; } diff --git a/drivers/net/wireless/realtek/rtw88/sdio.c b/drivers/net/wireless/realtek/rtw88/sdio.c index 99d7c629eac6..e35de52d8eb4 100644 --- a/drivers/net/wireless/realtek/rtw88/sdio.c +++ b/drivers/net/wireless/realtek/rtw88/sdio.c @@ -144,8 +144,10 @@ static u32 rtw_sdio_to_io_address(struct rtw_dev *rtwdev, u32 addr, static bool rtw_sdio_use_direct_io(struct rtw_dev *rtwdev, u32 addr) { + bool might_indirect_under_power_off = rtwdev->chip->id == RTW_CHIP_TYPE_8822C; + if (!test_bit(RTW_FLAG_POWERON, rtwdev->flags) && - !rtw_sdio_is_bus_addr(addr)) + !rtw_sdio_is_bus_addr(addr) && might_indirect_under_power_off) return false; return !rtw_sdio_is_sdio30_supported(rtwdev) || diff --git a/drivers/net/wireless/realtek/rtw88/usb.c b/drivers/net/wireless/realtek/rtw88/usb.c index 009202c627d2..3b5126ffc81a 100644 --- a/drivers/net/wireless/realtek/rtw88/usb.c +++ b/drivers/net/wireless/realtek/rtw88/usb.c @@ -965,8 +965,7 @@ static int rtw_usb_init_rx(struct rtw_dev *rtwdev) struct sk_buff *rx_skb; int i; - rtwusb->rxwq = alloc_workqueue("rtw88_usb: rx wq", WQ_BH | WQ_UNBOUND, - 0); + rtwusb->rxwq = alloc_workqueue("rtw88_usb: rx wq", WQ_BH, 0); if (!rtwusb->rxwq) { rtw_err(rtwdev, "failed to create RX work queue\n"); return -ENOMEM; diff --git a/drivers/net/wireless/ti/wlcore/tx.c b/drivers/net/wireless/ti/wlcore/tx.c index f76087be2f75..6241866d39df 100644 --- a/drivers/net/wireless/ti/wlcore/tx.c +++ b/drivers/net/wireless/ti/wlcore/tx.c @@ -207,6 +207,11 @@ static int wl1271_tx_allocate(struct wl1271 *wl, struct wl12xx_vif *wlvif, total_blocks = wlcore_hw_calc_tx_blocks(wl, total_len, spare_blocks); if (total_blocks <= wl->tx_blocks_available) { + if (skb_headroom(skb) < (total_len - skb->len) && + pskb_expand_head(skb, (total_len - skb->len), 0, GFP_ATOMIC)) { + wl1271_free_tx_id(wl, id); + return -EAGAIN; + } desc = skb_push(skb, total_len - skb->len); wlcore_hw_set_tx_desc_blocks(wl, desc, total_blocks, diff --git a/drivers/parisc/sba_iommu.c b/drivers/parisc/sba_iommu.c index a6eb6bffa5ea..eefb2bac8443 100644 --- a/drivers/parisc/sba_iommu.c +++ b/drivers/parisc/sba_iommu.c @@ -578,8 +578,8 @@ sba_io_pdir_entry(__le64 *pdir_ptr, space_t sid, phys_addr_t pba, pba &= IOVP_MASK; pba |= (ci >> PAGE_SHIFT) & 0xff; /* move CI (8 bits) into lowest byte */ - pba |= SBA_PDIR_VALID_BIT; /* set "valid" bit */ - *pdir_ptr = cpu_to_le64(pba); /* swap and store into I/O Pdir */ + /* set "valid" bit, swap and store into I/O Pdir */ + *pdir_ptr = cpu_to_le64((unsigned long)pba | SBA_PDIR_VALID_BIT); /* * If the PDC_MODEL capabilities has Non-coherent IO-PDIR bit set diff --git a/drivers/platform/mellanox/mlxbf-pmc.c b/drivers/platform/mellanox/mlxbf-pmc.c index 16a2fd9fdd9b..5ec1ad471696 100644 --- a/drivers/platform/mellanox/mlxbf-pmc.c +++ b/drivers/platform/mellanox/mlxbf-pmc.c @@ -801,18 +801,18 @@ static const struct mlxbf_pmc_events mlxbf_pmc_llt_miss_events[] = { {11, "GDC_MISS_MACHINE_CHI_TXDAT"}, {12, "GDC_MISS_MACHINE_CHI_RXDAT"}, {13, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC0_0"}, - {14, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC0_1 "}, + {14, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC0_1"}, {15, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC0_2"}, - {16, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC0_3 "}, - {17, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC1_0 "}, - {18, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC1_1 "}, - {19, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC1_2 "}, - {20, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC1_3 "}, + {16, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC0_3"}, + {17, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC1_0"}, + {18, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC1_1"}, + {19, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC1_2"}, + {20, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC1_3"}, {21, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC_DONE0_0"}, {22, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC_DONE0_1"}, {23, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC_DONE0_2"}, {24, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC_DONE0_3"}, - {25, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC_DONE1_0 "}, + {25, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC_DONE1_0"}, {26, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC_DONE1_1"}, {27, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC_DONE1_2"}, {28, "GDC_MISS_MACHINE_G_FIFO_FF_EXEC_DONE1_3"}, diff --git a/drivers/platform/x86/asus-armoury.h b/drivers/platform/x86/asus-armoury.h index a1bb2005c3f3..3ac7aea37838 100644 --- a/drivers/platform/x86/asus-armoury.h +++ b/drivers/platform/x86/asus-armoury.h @@ -449,12 +449,27 @@ static const struct dmi_system_id power_limits[] = { .ac_data = &(struct power_limits) { .ppt_pl1_spl_min = 15, .ppt_pl1_spl_max = 80, - .ppt_pl2_sppt_min = 25, + .ppt_pl2_sppt_min = 35, .ppt_pl2_sppt_max = 80, .ppt_pl3_fppt_min = 35, - .ppt_pl3_fppt_max = 80 + .ppt_pl3_fppt_max = 80, + .nv_dynamic_boost_min = 5, + .nv_dynamic_boost_max = 25, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + }, + .dc_data = &(struct power_limits) { + .ppt_pl1_spl_min = 15, + .ppt_pl1_spl_def = 45, + .ppt_pl1_spl_max = 65, + .ppt_pl2_sppt_min = 35, + .ppt_pl2_sppt_def = 54, + .ppt_pl2_sppt_max = 65, + .ppt_pl3_fppt_min = 35, + .ppt_pl3_fppt_max = 65, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, }, - .dc_data = NULL, }, }, { @@ -554,6 +569,42 @@ static const struct dmi_system_id power_limits[] = { }, { .matches = { + DMI_MATCH(DMI_BOARD_NAME, "FA608UM"), + }, + .driver_data = &(struct power_data) { + .ac_data = &(struct power_limits) { + .ppt_pl1_spl_min = 15, + .ppt_pl1_spl_def = 45, + .ppt_pl1_spl_max = 90, + .ppt_pl2_sppt_min = 35, + .ppt_pl2_sppt_def = 54, + .ppt_pl2_sppt_max = 90, + .ppt_pl3_fppt_min = 35, + .ppt_pl3_fppt_def = 90, + .ppt_pl3_fppt_max = 65, + .nv_dynamic_boost_min = 10, + .nv_dynamic_boost_max = 15, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + .nv_tgp_min = 55, + .nv_tgp_max = 100, + }, + .dc_data = &(struct power_limits) { + .ppt_pl1_spl_min = 15, + .ppt_pl1_spl_def = 45, + .ppt_pl1_spl_max = 65, + .ppt_pl2_sppt_min = 35, + .ppt_pl2_sppt_def = 54, + .ppt_pl2_sppt_max = 65, + .ppt_pl3_fppt_min = 35, + .ppt_pl3_fppt_max = 65, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + }, + }, + }, + { + .matches = { DMI_MATCH(DMI_BOARD_NAME, "FA608WI"), }, .driver_data = &(struct power_data) { @@ -824,6 +875,38 @@ static const struct dmi_system_id power_limits[] = { }, { .matches = { + DMI_MATCH(DMI_BOARD_NAME, "GA403WR"), + }, + .driver_data = &(struct power_data) { + .ac_data = &(struct power_limits) { + .ppt_pl1_spl_min = 15, + .ppt_pl1_spl_max = 80, + .ppt_pl2_sppt_min = 25, + .ppt_pl2_sppt_max = 80, + .ppt_pl3_fppt_min = 35, + .ppt_pl3_fppt_max = 80, + .nv_dynamic_boost_min = 0, + .nv_dynamic_boost_max = 25, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + .nv_tgp_min = 80, + .nv_tgp_max = 95, + }, + .dc_data = &(struct power_limits) { + .ppt_pl1_spl_min = 15, + .ppt_pl1_spl_max = 35, + .ppt_pl2_sppt_min = 25, + .ppt_pl2_sppt_max = 35, + .ppt_pl3_fppt_min = 35, + .ppt_pl3_fppt_max = 65, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + }, + .requires_fan_curve = true, + }, + }, + { + .matches = { DMI_MATCH(DMI_BOARD_NAME, "GA503QR"), }, .driver_data = &(struct power_data) { @@ -952,6 +1035,35 @@ static const struct dmi_system_id power_limits[] = { }, { .matches = { + DMI_MATCH(DMI_BOARD_NAME, "GU605CR"), + }, + .driver_data = &(struct power_data) { + .ac_data = &(struct power_limits) { + .ppt_pl1_spl_min = 30, + .ppt_pl1_spl_max = 85, + .ppt_pl2_sppt_min = 38, + .ppt_pl2_sppt_max = 110, + .nv_dynamic_boost_min = 5, + .nv_dynamic_boost_max = 20, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + .nv_tgp_min = 80, + .nv_tgp_def = 90, + .nv_tgp_max = 105, + }, + .dc_data = &(struct power_limits) { + .ppt_pl1_spl_min = 30, + .ppt_pl1_spl_max = 85, + .ppt_pl2_sppt_min = 38, + .ppt_pl2_sppt_max = 110, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + }, + .requires_fan_curve = true, + }, + }, + { + .matches = { DMI_MATCH(DMI_BOARD_NAME, "GU605CW"), }, .driver_data = &(struct power_data) { @@ -1262,6 +1374,35 @@ static const struct dmi_system_id power_limits[] = { }, { .matches = { + DMI_MATCH(DMI_BOARD_NAME, "G615LR"), + }, + .driver_data = &(struct power_data) { + .ac_data = &(struct power_limits) { + .ppt_pl1_spl_min = 28, + .ppt_pl1_spl_def = 140, + .ppt_pl1_spl_max = 175, + .ppt_pl2_sppt_min = 28, + .ppt_pl2_sppt_max = 175, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + .nv_dynamic_boost_min = 5, + .nv_dynamic_boost_max = 25, + .nv_tgp_min = 65, + .nv_tgp_max = 115, + }, + .dc_data = &(struct power_limits) { + .ppt_pl1_spl_min = 25, + .ppt_pl1_spl_max = 55, + .ppt_pl2_sppt_min = 25, + .ppt_pl2_sppt_max = 70, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + }, + .requires_fan_curve = true, + }, + }, + { + .matches = { DMI_MATCH(DMI_BOARD_NAME, "G634J"), }, .driver_data = &(struct power_data) { @@ -1428,6 +1569,35 @@ static const struct dmi_system_id power_limits[] = { }, { .matches = { + DMI_MATCH(DMI_BOARD_NAME, "G835LW"), + }, + .driver_data = &(struct power_data) { + .ac_data = &(struct power_limits) { + .ppt_pl1_spl_min = 28, + .ppt_pl1_spl_def = 140, + .ppt_pl1_spl_max = 175, + .ppt_pl2_sppt_min = 28, + .ppt_pl2_sppt_max = 175, + .nv_dynamic_boost_min = 5, + .nv_dynamic_boost_max = 25, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + .nv_tgp_min = 80, + .nv_tgp_max = 150, + }, + .dc_data = &(struct power_limits) { + .ppt_pl1_spl_min = 25, + .ppt_pl1_spl_max = 55, + .ppt_pl2_sppt_min = 25, + .ppt_pl2_sppt_max = 70, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + }, + .requires_fan_curve = true, + }, + }, + { + .matches = { DMI_MATCH(DMI_BOARD_NAME, "H7606W"), }, .driver_data = &(struct power_data) { diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c index 6a62bc5b02fd..a38a65f5c550 100644 --- a/drivers/platform/x86/asus-nb-wmi.c +++ b/drivers/platform/x86/asus-nb-wmi.c @@ -580,6 +580,7 @@ static const struct key_entry asus_nb_wmi_keymap[] = { { KE_KEY, 0x2a, { KEY_SELECTIVE_SCREENSHOT } }, { KE_IGNORE, 0x2b, }, /* PrintScreen (also send via PS/2) on newer models */ { KE_IGNORE, 0x2c, }, /* CapsLock (also send via PS/2) on newer models */ + { KE_KEY, 0x2d, { KEY_DISPLAYTOGGLE } }, { KE_KEY, 0x30, { KEY_VOLUMEUP } }, { KE_KEY, 0x31, { KEY_VOLUMEDOWN } }, { KE_KEY, 0x32, { KEY_MUTE } }, diff --git a/drivers/platform/x86/dell/alienware-wmi-wmax.c b/drivers/platform/x86/dell/alienware-wmi-wmax.c index 1418bd326edf..e69b50162bb1 100644 --- a/drivers/platform/x86/dell/alienware-wmi-wmax.c +++ b/drivers/platform/x86/dell/alienware-wmi-wmax.c @@ -90,6 +90,30 @@ static struct awcc_quirks empty_quirks; static const struct dmi_system_id awcc_dmi_table[] __initconst = { { + .ident = "Alienware 16 Area-51", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), + DMI_MATCH(DMI_PRODUCT_NAME, "Alienware 16 Area-51"), + }, + .driver_data = &g_series_quirks, + }, + { + .ident = "Alienware 16X Aurora", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), + DMI_MATCH(DMI_PRODUCT_NAME, "Alienware 16X Aurora"), + }, + .driver_data = &g_series_quirks, + }, + { + .ident = "Alienware 18 Area-51", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), + DMI_MATCH(DMI_PRODUCT_NAME, "Alienware 18 Area-51"), + }, + .driver_data = &g_series_quirks, + }, + { .ident = "Alienware 16 Aurora", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), @@ -162,6 +186,14 @@ static const struct dmi_system_id awcc_dmi_table[] __initconst = { .driver_data = &generic_quirks, }, { + .ident = "Alienware x16", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), + DMI_MATCH(DMI_PRODUCT_NAME, "Alienware x16"), + }, + .driver_data = &g_series_quirks, + }, + { .ident = "Alienware x17", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), diff --git a/drivers/platform/x86/dell/dell-lis3lv02d.c b/drivers/platform/x86/dell/dell-lis3lv02d.c index 77905a9ddde9..fe52bcd896f7 100644 --- a/drivers/platform/x86/dell/dell-lis3lv02d.c +++ b/drivers/platform/x86/dell/dell-lis3lv02d.c @@ -44,6 +44,7 @@ static const struct dmi_system_id lis3lv02d_devices[] __initconst = { /* * Additional individual entries were added after verification. */ + DELL_LIS3LV02D_DMI_ENTRY("Latitude 5400", 0x29), DELL_LIS3LV02D_DMI_ENTRY("Latitude 5480", 0x29), DELL_LIS3LV02D_DMI_ENTRY("Latitude 5500", 0x29), DELL_LIS3LV02D_DMI_ENTRY("Latitude E6330", 0x29), diff --git a/drivers/platform/x86/hp/hp-bioscfg/enum-attributes.c b/drivers/platform/x86/hp/hp-bioscfg/enum-attributes.c index c50ad5880503..f346aad8e9d8 100644 --- a/drivers/platform/x86/hp/hp-bioscfg/enum-attributes.c +++ b/drivers/platform/x86/hp/hp-bioscfg/enum-attributes.c @@ -207,7 +207,7 @@ static int hp_populate_enumeration_elements_from_package(union acpi_object *enum case PREREQUISITES: size = min_t(u32, enum_data->common.prerequisites_size, MAX_PREREQUISITES_SIZE); for (reqs = 0; reqs < size; reqs++) { - if (elem >= enum_obj_count) { + if (elem + reqs >= enum_obj_count) { pr_err("Error enum-objects package is too small\n"); return -EINVAL; } @@ -255,7 +255,7 @@ static int hp_populate_enumeration_elements_from_package(union acpi_object *enum for (pos_values = 0; pos_values < size && pos_values < MAX_VALUES_SIZE; pos_values++) { - if (elem >= enum_obj_count) { + if (elem + pos_values >= enum_obj_count) { pr_err("Error enum-objects package is too small\n"); return -EINVAL; } diff --git a/drivers/platform/x86/hp/hp-bioscfg/int-attributes.c b/drivers/platform/x86/hp/hp-bioscfg/int-attributes.c index 6c7f4d5fa9cb..63b1fda2be4e 100644 --- a/drivers/platform/x86/hp/hp-bioscfg/int-attributes.c +++ b/drivers/platform/x86/hp/hp-bioscfg/int-attributes.c @@ -227,7 +227,7 @@ static int hp_populate_integer_elements_from_package(union acpi_object *integer_ size = min_t(u32, integer_data->common.prerequisites_size, MAX_PREREQUISITES_SIZE); for (reqs = 0; reqs < size; reqs++) { - if (elem >= integer_obj_count) { + if (elem + reqs >= integer_obj_count) { pr_err("Error elem-objects package is too small\n"); return -EINVAL; } diff --git a/drivers/platform/x86/hp/hp-bioscfg/order-list-attributes.c b/drivers/platform/x86/hp/hp-bioscfg/order-list-attributes.c index c6e57bb9d8b7..6a31f47ce3f5 100644 --- a/drivers/platform/x86/hp/hp-bioscfg/order-list-attributes.c +++ b/drivers/platform/x86/hp/hp-bioscfg/order-list-attributes.c @@ -216,6 +216,11 @@ static int hp_populate_ordered_list_elements_from_package(union acpi_object *ord size = min_t(u32, ordered_list_data->common.prerequisites_size, MAX_PREREQUISITES_SIZE); for (reqs = 0; reqs < size; reqs++) { + if (elem + reqs >= order_obj_count) { + pr_err("Error elem-objects package is too small\n"); + return -EINVAL; + } + ret = hp_convert_hexstr_to_str(order_obj[elem + reqs].string.pointer, order_obj[elem + reqs].string.length, &str_value, &value_len); diff --git a/drivers/platform/x86/hp/hp-bioscfg/passwdobj-attributes.c b/drivers/platform/x86/hp/hp-bioscfg/passwdobj-attributes.c index 187b372123ed..ec79d9d50377 100644 --- a/drivers/platform/x86/hp/hp-bioscfg/passwdobj-attributes.c +++ b/drivers/platform/x86/hp/hp-bioscfg/passwdobj-attributes.c @@ -303,6 +303,11 @@ static int hp_populate_password_elements_from_package(union acpi_object *passwor MAX_PREREQUISITES_SIZE); for (reqs = 0; reqs < size; reqs++) { + if (elem + reqs >= password_obj_count) { + pr_err("Error elem-objects package is too small\n"); + return -EINVAL; + } + ret = hp_convert_hexstr_to_str(password_obj[elem + reqs].string.pointer, password_obj[elem + reqs].string.length, &str_value, &value_len); diff --git a/drivers/platform/x86/hp/hp-bioscfg/string-attributes.c b/drivers/platform/x86/hp/hp-bioscfg/string-attributes.c index 27758b779b2d..7b885d25650c 100644 --- a/drivers/platform/x86/hp/hp-bioscfg/string-attributes.c +++ b/drivers/platform/x86/hp/hp-bioscfg/string-attributes.c @@ -217,7 +217,7 @@ static int hp_populate_string_elements_from_package(union acpi_object *string_ob MAX_PREREQUISITES_SIZE); for (reqs = 0; reqs < size; reqs++) { - if (elem >= string_obj_count) { + if (elem + reqs >= string_obj_count) { pr_err("Error elem-objects package is too small\n"); return -EINVAL; } diff --git a/drivers/platform/x86/ibm_rtl.c b/drivers/platform/x86/ibm_rtl.c index 231b37909801..139956168cf9 100644 --- a/drivers/platform/x86/ibm_rtl.c +++ b/drivers/platform/x86/ibm_rtl.c @@ -273,7 +273,7 @@ static int __init ibm_rtl_init(void) { /* search for the _RTL_ signature at the start of the table */ for (i = 0 ; i < ebda_size/sizeof(unsigned int); i++) { struct ibm_rtl_table __iomem * tmp; - tmp = (struct ibm_rtl_table __iomem *) (ebda_map+i); + tmp = (struct ibm_rtl_table __iomem *) (ebda_map + i*sizeof(unsigned int)); if ((readq(&tmp->signature) & RTL_MASK) == RTL_SIGNATURE) { phys_addr_t addr; unsigned int plen; diff --git a/drivers/platform/x86/intel/pmt/discovery.c b/drivers/platform/x86/intel/pmt/discovery.c index 32713a194a55..e500aa327d23 100644 --- a/drivers/platform/x86/intel/pmt/discovery.c +++ b/drivers/platform/x86/intel/pmt/discovery.c @@ -503,8 +503,10 @@ static int pmt_features_discovery(struct pmt_features_priv *priv, ret = kobject_init_and_add(&feature->kobj, ktype, &priv->dev->kobj, "%s", pmt_feature_names[feature->id]); - if (ret) + if (ret) { + kobject_put(&feature->kobj); return ret; + } kobject_uevent(&feature->kobj, KOBJ_ADD); pmt_features_add_feat(feature); @@ -546,9 +548,9 @@ static int pmt_features_probe(struct auxiliary_device *auxdev, const struct auxi priv->dev = device_create(&intel_pmt_class, &auxdev->dev, MKDEV(0, 0), priv, "%s-%s", "features", dev_name(priv->parent)); if (IS_ERR(priv->dev)) - return dev_err_probe(priv->dev, PTR_ERR(priv->dev), + return dev_err_probe(&auxdev->dev, PTR_ERR(priv->dev), "Could not create %s-%s device node\n", - "features", dev_name(priv->dev)); + "features", dev_name(priv->parent)); /* Initialize each feature */ for (i = 0; i < ivdev->num_resources; i++) { diff --git a/drivers/platform/x86/lenovo/ideapad-laptop.c b/drivers/platform/x86/lenovo/ideapad-laptop.c index 5171a077f62c..7d5f7a2f6564 100644 --- a/drivers/platform/x86/lenovo/ideapad-laptop.c +++ b/drivers/platform/x86/lenovo/ideapad-laptop.c @@ -1367,7 +1367,7 @@ static const struct key_entry ideapad_keymap[] = { /* Performance toggle also Fn+Q, handled inside ideapad_wmi_notify() */ { KE_KEY, 0x3d | IDEAPAD_WMI_KEY, { KEY_PROG4 } }, /* shift + prtsc */ - { KE_KEY, 0x2d | IDEAPAD_WMI_KEY, { KEY_CUT } }, + { KE_KEY, 0x2d | IDEAPAD_WMI_KEY, { KEY_SELECTIVE_SCREENSHOT } }, { KE_KEY, 0x29 | IDEAPAD_WMI_KEY, { KEY_TOUCHPAD_TOGGLE } }, { KE_KEY, 0x2a | IDEAPAD_WMI_KEY, { KEY_ROOT_MENU } }, diff --git a/drivers/platform/x86/lenovo/think-lmi.c b/drivers/platform/x86/lenovo/think-lmi.c index 540b472b1bf3..c45f0206b4ab 100644 --- a/drivers/platform/x86/lenovo/think-lmi.c +++ b/drivers/platform/x86/lenovo/think-lmi.c @@ -195,7 +195,7 @@ static const struct tlmi_cert_guids thinkpad_cert_guid = { }; static const struct tlmi_cert_guids thinkcenter_cert_guid = { - .thumbprint = NULL, + .thumbprint = LENOVO_CERT_THUMBPRINT_GUID, /* Same GUID as TP */ .set_bios_setting = LENOVO_TC_SET_BIOS_SETTING_CERT_GUID, .save_bios_setting = LENOVO_TC_SAVE_BIOS_SETTING_CERT_GUID, .cert_to_password = LENOVO_TC_CERT_TO_PASSWORD_GUID, @@ -709,6 +709,10 @@ static ssize_t cert_thumbprint(char *buf, const char *arg, int count) if (!tlmi_priv.cert_guid->thumbprint) return -EOPNOTSUPP; + /* Older ThinkCenter BIOS may not have support */ + if (!wmi_has_guid(tlmi_priv.cert_guid->thumbprint)) + return -EOPNOTSUPP; + status = wmi_evaluate_method(tlmi_priv.cert_guid->thumbprint, 0, 0, &input, &output); if (ACPI_FAILURE(status)) { kfree(output.pointer); diff --git a/drivers/platform/x86/msi-laptop.c b/drivers/platform/x86/msi-laptop.c index c4b150fa093f..ddef6b78d2fa 100644 --- a/drivers/platform/x86/msi-laptop.c +++ b/drivers/platform/x86/msi-laptop.c @@ -1130,6 +1130,9 @@ static void __exit msi_cleanup(void) sysfs_remove_group(&msipf_device->dev.kobj, &msipf_attribute_group); if (!quirks->old_ec_model && threeg_exists) device_remove_file(&msipf_device->dev, &dev_attr_threeg); + if (quirks->old_ec_model) + sysfs_remove_group(&msipf_device->dev.kobj, + &msipf_old_attribute_group); platform_device_unregister(msipf_device); platform_driver_unregister(&msipf_driver); backlight_device_unregister(msibl_device); diff --git a/drivers/platform/x86/samsung-galaxybook.c b/drivers/platform/x86/samsung-galaxybook.c index 3c13e13d4885..755cb82bdb60 100644 --- a/drivers/platform/x86/samsung-galaxybook.c +++ b/drivers/platform/x86/samsung-galaxybook.c @@ -442,12 +442,13 @@ static int galaxybook_battery_ext_property_get(struct power_supply *psy, union power_supply_propval *val) { struct samsung_galaxybook *galaxybook = ext_data; + u8 value; int err; if (psp != POWER_SUPPLY_PROP_CHARGE_CONTROL_END_THRESHOLD) return -EINVAL; - err = charge_control_end_threshold_acpi_get(galaxybook, (u8 *)&val->intval); + err = charge_control_end_threshold_acpi_get(galaxybook, &value); if (err) return err; @@ -455,8 +456,10 @@ static int galaxybook_battery_ext_property_get(struct power_supply *psy, * device stores "no end threshold" as 0 instead of 100; * if device has 0, report 100 */ - if (val->intval == 0) - val->intval = 100; + if (value == 0) + value = 100; + + val->intval = value; return 0; } diff --git a/drivers/platform/x86/uniwill/uniwill-acpi.c b/drivers/platform/x86/uniwill/uniwill-acpi.c index bd7e63dd5181..0f935532f250 100644 --- a/drivers/platform/x86/uniwill/uniwill-acpi.c +++ b/drivers/platform/x86/uniwill/uniwill-acpi.c @@ -1845,6 +1845,13 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = { }, }, { + .ident = "TUXEDO Book BA15 Gen10 AMD", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "PF5PU1G"), + }, + }, + { .ident = "TUXEDO Pulse 14 Gen1 AMD", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"), diff --git a/drivers/pmdomain/imx/gpc.c b/drivers/pmdomain/imx/gpc.c index a34b260274f7..de695f1944ab 100644 --- a/drivers/pmdomain/imx/gpc.c +++ b/drivers/pmdomain/imx/gpc.c @@ -402,13 +402,12 @@ clk_err: static int imx_gpc_probe(struct platform_device *pdev) { const struct imx_gpc_dt_data *of_id_data = device_get_match_data(&pdev->dev); - struct device_node *pgc_node; + struct device_node *pgc_node __free(device_node) + = of_get_child_by_name(pdev->dev.of_node, "pgc"); struct regmap *regmap; void __iomem *base; int ret; - pgc_node = of_get_child_by_name(pdev->dev.of_node, "pgc"); - /* bail out if DT too old and doesn't provide the necessary info */ if (!of_property_present(pdev->dev.of_node, "#power-domain-cells") && !pgc_node) diff --git a/drivers/pmdomain/mediatek/mtk-pm-domains.c b/drivers/pmdomain/mediatek/mtk-pm-domains.c index 80561d27f2b2..f64f24d520dd 100644 --- a/drivers/pmdomain/mediatek/mtk-pm-domains.c +++ b/drivers/pmdomain/mediatek/mtk-pm-domains.c @@ -984,18 +984,6 @@ static void scpsys_domain_cleanup(struct scpsys *scpsys) } } -static struct device_node *scpsys_get_legacy_regmap(struct device_node *np, const char *pn) -{ - struct device_node *local_node; - - for_each_child_of_node(np, local_node) { - if (of_property_present(local_node, pn)) - return local_node; - } - - return NULL; -} - static int scpsys_get_bus_protection_legacy(struct device *dev, struct scpsys *scpsys) { const u8 bp_blocks[3] = { @@ -1017,7 +1005,8 @@ static int scpsys_get_bus_protection_legacy(struct device *dev, struct scpsys *s * this makes it then possible to allocate the array of bus_prot * regmaps and convert all to the new style handling. */ - node = scpsys_get_legacy_regmap(np, "mediatek,infracfg"); + of_node_get(np); + node = of_find_node_with_property(np, "mediatek,infracfg"); if (node) { regmap[0] = syscon_regmap_lookup_by_phandle(node, "mediatek,infracfg"); of_node_put(node); @@ -1030,7 +1019,8 @@ static int scpsys_get_bus_protection_legacy(struct device *dev, struct scpsys *s regmap[0] = NULL; } - node = scpsys_get_legacy_regmap(np, "mediatek,smi"); + of_node_get(np); + node = of_find_node_with_property(np, "mediatek,smi"); if (node) { smi_np = of_parse_phandle(node, "mediatek,smi", 0); of_node_put(node); @@ -1048,7 +1038,8 @@ static int scpsys_get_bus_protection_legacy(struct device *dev, struct scpsys *s regmap[1] = NULL; } - node = scpsys_get_legacy_regmap(np, "mediatek,infracfg-nao"); + of_node_get(np); + node = of_find_node_with_property(np, "mediatek,infracfg-nao"); if (node) { regmap[2] = syscon_regmap_lookup_by_phandle(node, "mediatek,infracfg-nao"); num_regmaps++; diff --git a/drivers/regulator/fp9931.c b/drivers/regulator/fp9931.c index fef0bb07fd5d..69b3c712e5d5 100644 --- a/drivers/regulator/fp9931.c +++ b/drivers/regulator/fp9931.c @@ -391,6 +391,7 @@ static const struct regulator_desc regulators[] = { { .name = "v3p3", .of_match = of_match_ptr("v3p3"), + .regulators_node = of_match_ptr("regulators"), .id = 0, .ops = &fp9931_v3p3ops, .type = REGULATOR_VOLTAGE, @@ -403,6 +404,7 @@ static const struct regulator_desc regulators[] = { { .name = "vposneg", .of_match = of_match_ptr("vposneg"), + .regulators_node = of_match_ptr("regulators"), .id = 1, .ops = &fp9931_vposneg_ops, .type = REGULATOR_VOLTAGE, @@ -415,6 +417,7 @@ static const struct regulator_desc regulators[] = { { .name = "vcom", .of_match = of_match_ptr("vcom"), + .regulators_node = of_match_ptr("regulators"), .id = 2, .ops = &fp9931_vcom_ops, .type = REGULATOR_VOLTAGE, diff --git a/drivers/scsi/mpi3mr/mpi/mpi30_ioc.h b/drivers/scsi/mpi3mr/mpi/mpi30_ioc.h index b42933fcd423..6561f98c3cb2 100644 --- a/drivers/scsi/mpi3mr/mpi/mpi30_ioc.h +++ b/drivers/scsi/mpi3mr/mpi/mpi30_ioc.h @@ -166,6 +166,7 @@ struct mpi3_ioc_facts_data { #define MPI3_IOCFACTS_FLAGS_SIGNED_NVDATA_REQUIRED (0x00010000) #define MPI3_IOCFACTS_FLAGS_DMA_ADDRESS_WIDTH_MASK (0x0000ff00) #define MPI3_IOCFACTS_FLAGS_DMA_ADDRESS_WIDTH_SHIFT (8) +#define MPI3_IOCFACTS_FLAGS_MAX_REQ_PER_REPLY_QUEUE_LIMIT (0x00000040) #define MPI3_IOCFACTS_FLAGS_INITIAL_PORT_ENABLE_MASK (0x00000030) #define MPI3_IOCFACTS_FLAGS_INITIAL_PORT_ENABLE_SHIFT (4) #define MPI3_IOCFACTS_FLAGS_INITIAL_PORT_ENABLE_NOT_STARTED (0x00000000) diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c index 8fe6e0bf342e..8c4bb7169a87 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_fw.c +++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c @@ -3158,6 +3158,8 @@ static void mpi3mr_process_factsdata(struct mpi3mr_ioc *mrioc, mrioc->facts.dma_mask = (facts_flags & MPI3_IOCFACTS_FLAGS_DMA_ADDRESS_WIDTH_MASK) >> MPI3_IOCFACTS_FLAGS_DMA_ADDRESS_WIDTH_SHIFT; + mrioc->facts.max_req_limit = (facts_flags & + MPI3_IOCFACTS_FLAGS_MAX_REQ_PER_REPLY_QUEUE_LIMIT); mrioc->facts.protocol_flags = facts_data->protocol_flags; mrioc->facts.mpi_version = le32_to_cpu(facts_data->mpi_version.word); mrioc->facts.max_reqs = le16_to_cpu(facts_data->max_outstanding_requests); diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 1f2a53ba5dd9..c5085e6d2e75 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -7459,7 +7459,7 @@ MODULE_PARM_DESC(lbprz, MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)"); MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)"); MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)"); -MODULE_PARM_DESC(atomic_write, "enable ATOMIC WRITE support, support WRITE ATOMIC(16) (def=0)"); +MODULE_PARM_DESC(atomic_wr, "enable ATOMIC WRITE support, support WRITE ATOMIC(16) (def=0)"); MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)"); MODULE_PARM_DESC(lun_format, "LUN format: 0->peripheral (def); 1 --> flat address method"); MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)"); diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index b3af9b78fa12..57fba34832ad 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -731,6 +731,8 @@ sg_new_write(Sg_fd *sfp, struct file *file, const char __user *buf, sg_remove_request(sfp, srp); return -EFAULT; } + hp->duration = jiffies_to_msecs(jiffies); + if (hp->interface_id != 'S') { sg_remove_request(sfp, srp); return -ENOSYS; @@ -815,7 +817,6 @@ sg_common_write(Sg_fd * sfp, Sg_request * srp, return -ENODEV; } - hp->duration = jiffies_to_msecs(jiffies); if (hp->interface_id != '\0' && /* v3 (or later) interface */ (SG_FLAG_Q_AT_TAIL & hp->flags)) at_head = 0; @@ -1338,9 +1339,6 @@ sg_rq_end_io(struct request *rq, blk_status_t status) "sg_cmd_done: pack_id=%d, res=0x%x\n", srp->header.pack_id, result)); srp->header.resid = resid; - ms = jiffies_to_msecs(jiffies); - srp->header.duration = (ms > srp->header.duration) ? - (ms - srp->header.duration) : 0; if (0 != result) { struct scsi_sense_hdr sshdr; @@ -1389,6 +1387,9 @@ sg_rq_end_io(struct request *rq, blk_status_t status) done = 0; } srp->done = done; + ms = jiffies_to_msecs(jiffies); + srp->header.duration = (ms > srp->header.duration) ? + (ms - srp->header.duration) : 0; write_unlock_irqrestore(&sfp->rq_list_lock, iflags); if (likely(done)) { @@ -2533,6 +2534,7 @@ static void sg_proc_debug_helper(struct seq_file *s, Sg_device * sdp) const sg_io_hdr_t *hp; const char * cp; unsigned int ms; + unsigned int duration; k = 0; list_for_each_entry(fp, &sdp->sfds, sfd_siblings) { @@ -2570,13 +2572,17 @@ static void sg_proc_debug_helper(struct seq_file *s, Sg_device * sdp) seq_printf(s, " id=%d blen=%d", srp->header.pack_id, blen); if (srp->done) - seq_printf(s, " dur=%d", hp->duration); + seq_printf(s, " dur=%u", hp->duration); else { ms = jiffies_to_msecs(jiffies); - seq_printf(s, " t_o/elap=%d/%d", + duration = READ_ONCE(hp->duration); + if (duration) + duration = (ms > duration ? + ms - duration : 0); + seq_printf(s, " t_o/elap=%u/%u", (new_interface ? hp->timeout : jiffies_to_msecs(fp->timeout)), - (ms > hp->duration ? ms - hp->duration : 0)); + duration); } seq_printf(s, "ms sgat=%d op=0x%02x\n", usg, (int) srp->data.cmd_opcode); diff --git a/drivers/spi/spi-cadence-quadspi.c b/drivers/spi/spi-cadence-quadspi.c index f8823e83a622..965b4cea3388 100644 --- a/drivers/spi/spi-cadence-quadspi.c +++ b/drivers/spi/spi-cadence-quadspi.c @@ -300,6 +300,9 @@ struct cqspi_driver_platdata { CQSPI_REG_IRQ_IND_SRAM_FULL | \ CQSPI_REG_IRQ_IND_COMP) +#define CQSPI_IRQ_MASK_RD_SLOW_SRAM (CQSPI_REG_IRQ_WATERMARK | \ + CQSPI_REG_IRQ_IND_COMP) + #define CQSPI_IRQ_MASK_WR (CQSPI_REG_IRQ_IND_COMP | \ CQSPI_REG_IRQ_WATERMARK | \ CQSPI_REG_IRQ_UNDERFLOW) @@ -381,7 +384,7 @@ static irqreturn_t cqspi_irq_handler(int this_irq, void *dev) else if (!cqspi->slow_sram) irq_status &= CQSPI_IRQ_MASK_RD | CQSPI_IRQ_MASK_WR; else - irq_status &= CQSPI_REG_IRQ_WATERMARK | CQSPI_IRQ_MASK_WR; + irq_status &= CQSPI_IRQ_MASK_RD_SLOW_SRAM | CQSPI_IRQ_MASK_WR; if (irq_status) complete(&cqspi->transfer_complete); @@ -757,7 +760,7 @@ static int cqspi_indirect_read_execute(struct cqspi_flash_pdata *f_pdata, */ if (use_irq && cqspi->slow_sram) - writel(CQSPI_REG_IRQ_WATERMARK, reg_base + CQSPI_REG_IRQMASK); + writel(CQSPI_IRQ_MASK_RD_SLOW_SRAM, reg_base + CQSPI_REG_IRQMASK); else if (use_irq) writel(CQSPI_IRQ_MASK_RD, reg_base + CQSPI_REG_IRQMASK); else @@ -769,17 +772,19 @@ static int cqspi_indirect_read_execute(struct cqspi_flash_pdata *f_pdata, readl(reg_base + CQSPI_REG_INDIRECTRD); /* Flush posted write. */ while (remaining > 0) { + ret = 0; if (use_irq && !wait_for_completion_timeout(&cqspi->transfer_complete, msecs_to_jiffies(CQSPI_READ_TIMEOUT_MS))) ret = -ETIMEDOUT; /* - * Disable all read interrupts until - * we are out of "bytes to read" + * Prevent lost interrupt and race condition by reinitializing early. + * A spurious wakeup and another wait cycle can occur here, + * which is preferable to waiting until timeout if interrupt is lost. */ - if (cqspi->slow_sram) - writel(0x0, reg_base + CQSPI_REG_IRQMASK); + if (use_irq) + reinit_completion(&cqspi->transfer_complete); bytes_to_read = cqspi_get_rd_sram_level(cqspi); @@ -811,12 +816,6 @@ static int cqspi_indirect_read_execute(struct cqspi_flash_pdata *f_pdata, remaining -= bytes_to_read; bytes_to_read = cqspi_get_rd_sram_level(cqspi); } - - if (use_irq && remaining > 0) { - reinit_completion(&cqspi->transfer_complete); - if (cqspi->slow_sram) - writel(CQSPI_REG_IRQ_WATERMARK, reg_base + CQSPI_REG_IRQMASK); - } } /* Check indirect done status */ diff --git a/drivers/spi/spi-sun6i.c b/drivers/spi/spi-sun6i.c index 871dfd3e77be..d1de6c99e762 100644 --- a/drivers/spi/spi-sun6i.c +++ b/drivers/spi/spi-sun6i.c @@ -795,10 +795,13 @@ static const struct sun6i_spi_cfg sun50i_r329_spi_cfg = { static const struct of_device_id sun6i_spi_match[] = { { .compatible = "allwinner,sun6i-a31-spi", .data = &sun6i_a31_spi_cfg }, { .compatible = "allwinner,sun8i-h3-spi", .data = &sun8i_h3_spi_cfg }, - { - .compatible = "allwinner,sun50i-r329-spi", - .data = &sun50i_r329_spi_cfg - }, + { .compatible = "allwinner,sun50i-r329-spi", .data = &sun50i_r329_spi_cfg }, + /* + * A523's SPI controller has a combined RX buffer + FIFO counter + * at offset 0x400, instead of split buffer count in FIFO status + * register. But in practice we only care about the FIFO level. + */ + { .compatible = "allwinner,sun55i-a523-spi", .data = &sun50i_r329_spi_cfg }, {} }; MODULE_DEVICE_TABLE(of, sun6i_spi_match); diff --git a/drivers/tty/serial/8250/8250_loongson.c b/drivers/tty/serial/8250/8250_loongson.c index 53153a116c01..47df3c4c9d21 100644 --- a/drivers/tty/serial/8250/8250_loongson.c +++ b/drivers/tty/serial/8250/8250_loongson.c @@ -128,8 +128,8 @@ static int loongson_uart_probe(struct platform_device *pdev) port->private_data = priv; port->membase = devm_platform_get_and_ioremap_resource(pdev, 0, &priv->res); - if (!port->membase) - return -ENOMEM; + if (IS_ERR(port->membase)) + return PTR_ERR(port->membase); port->mapbase = priv->res->start; port->mapsize = resource_size(priv->res); diff --git a/drivers/tty/serial/serial_base_bus.c b/drivers/tty/serial/serial_base_bus.c index 22749ab0428a..1e1ad28d83fc 100644 --- a/drivers/tty/serial/serial_base_bus.c +++ b/drivers/tty/serial/serial_base_bus.c @@ -13,7 +13,7 @@ #include <linux/device.h> #include <linux/idr.h> #include <linux/module.h> -#include <linux/of.h> +#include <linux/property.h> #include <linux/serial_core.h> #include <linux/slab.h> #include <linux/spinlock.h> @@ -60,6 +60,7 @@ void serial_base_driver_unregister(struct device_driver *driver) driver_unregister(driver); } +/* On failure the caller must put device @dev with put_device() */ static int serial_base_device_init(struct uart_port *port, struct device *dev, struct device *parent_dev, @@ -73,7 +74,9 @@ static int serial_base_device_init(struct uart_port *port, dev->parent = parent_dev; dev->bus = &serial_base_bus_type; dev->release = release; - device_set_of_node_from_dev(dev, parent_dev); + dev->of_node_reused = true; + + device_set_node(dev, fwnode_handle_get(dev_fwnode(parent_dev))); if (!serial_base_initialized) { dev_dbg(port->dev, "uart_add_one_port() called before arch_initcall()?\n"); @@ -94,7 +97,7 @@ static void serial_base_ctrl_release(struct device *dev) { struct serial_ctrl_device *ctrl_dev = to_serial_base_ctrl_device(dev); - of_node_put(dev->of_node); + fwnode_handle_put(dev_fwnode(dev)); kfree(ctrl_dev); } @@ -142,7 +145,7 @@ static void serial_base_port_release(struct device *dev) { struct serial_port_device *port_dev = to_serial_base_port_device(dev); - of_node_put(dev->of_node); + fwnode_handle_put(dev_fwnode(dev)); kfree(port_dev); } diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 53edbf1d8963..fbfe5575bd3c 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -1914,7 +1914,7 @@ static void sci_dma_check_tx_occurred(struct sci_port *s) struct dma_tx_state state; enum dma_status status; - if (!s->chan_tx) + if (!s->chan_tx || s->cookie_tx <= 0) return; status = dmaengine_tx_status(s->chan_tx, s->cookie_tx, &state); diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c index c793fc74c26b..c593d20a1b5b 100644 --- a/drivers/tty/serial/xilinx_uartps.c +++ b/drivers/tty/serial/xilinx_uartps.c @@ -428,10 +428,17 @@ static void cdns_uart_handle_tx(void *dev_id) struct tty_port *tport = &port->state->port; unsigned int numbytes; unsigned char ch; + ktime_t rts_delay; if (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port)) { /* Disable the TX Empty interrupt */ writel(CDNS_UART_IXR_TXEMPTY, port->membase + CDNS_UART_IDR); + /* Set RTS line after delay */ + if (cdns_uart->port->rs485.flags & SER_RS485_ENABLED) { + cdns_uart->tx_timer.function = &cdns_rs485_rx_callback; + rts_delay = ns_to_ktime(cdns_calc_after_tx_delay(cdns_uart)); + hrtimer_start(&cdns_uart->tx_timer, rts_delay, HRTIMER_MODE_REL); + } return; } @@ -448,13 +455,6 @@ static void cdns_uart_handle_tx(void *dev_id) /* Enable the TX Empty interrupt */ writel(CDNS_UART_IXR_TXEMPTY, cdns_uart->port->membase + CDNS_UART_IER); - - if (cdns_uart->port->rs485.flags & SER_RS485_ENABLED && - (kfifo_is_empty(&tport->xmit_fifo) || uart_tx_stopped(port))) { - hrtimer_update_function(&cdns_uart->tx_timer, cdns_rs485_rx_callback); - hrtimer_start(&cdns_uart->tx_timer, - ns_to_ktime(cdns_calc_after_tx_delay(cdns_uart)), HRTIMER_MODE_REL); - } } /** diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 80c0b49f30b0..0babb7035200 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -10359,7 +10359,7 @@ static int ufshcd_suspend(struct ufs_hba *hba) ret = ufshcd_setup_clocks(hba, false); if (ret) { ufshcd_enable_irq(hba); - return ret; + goto out; } if (ufshcd_is_clkgating_allowed(hba)) { hba->clk_gating.state = CLKS_OFF; @@ -10371,6 +10371,9 @@ static int ufshcd_suspend(struct ufs_hba *hba) /* Put the host controller in low power mode if possible */ ufshcd_hba_vreg_set_lpm(hba); ufshcd_pm_qos_update(hba, false); +out: + if (ret) + ufshcd_update_evt_hist(hba, UFS_EVT_SUSPEND_ERR, (u32)ret); return ret; } diff --git a/drivers/usb/dwc3/dwc3-of-simple.c b/drivers/usb/dwc3/dwc3-of-simple.c index a4954a21be93..c116143335d9 100644 --- a/drivers/usb/dwc3/dwc3-of-simple.c +++ b/drivers/usb/dwc3/dwc3-of-simple.c @@ -70,11 +70,11 @@ static int dwc3_of_simple_probe(struct platform_device *pdev) simple->num_clocks = ret; ret = clk_bulk_prepare_enable(simple->num_clocks, simple->clks); if (ret) - goto err_resetc_assert; + goto err_clk_put_all; ret = of_platform_populate(np, NULL, NULL, dev); if (ret) - goto err_clk_put; + goto err_clk_disable; pm_runtime_set_active(dev); pm_runtime_enable(dev); @@ -82,8 +82,9 @@ static int dwc3_of_simple_probe(struct platform_device *pdev) return 0; -err_clk_put: +err_clk_disable: clk_bulk_disable_unprepare(simple->num_clocks, simple->clks); +err_clk_put_all: clk_bulk_put_all(simple->num_clocks, simple->clks); err_resetc_assert: diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index bc3fe31638b9..8a35a6901db7 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -4826,7 +4826,7 @@ void dwc3_gadget_exit(struct dwc3 *dwc) if (!dwc->gadget) return; - dwc3_enable_susphy(dwc, false); + dwc3_enable_susphy(dwc, true); usb_del_gadget(dwc->gadget); dwc3_gadget_free_endpoints(dwc); usb_put_gadget(dwc->gadget); diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c index cf6512ed17a6..96b588bd08cd 100644 --- a/drivers/usb/dwc3/host.c +++ b/drivers/usb/dwc3/host.c @@ -227,7 +227,7 @@ void dwc3_host_exit(struct dwc3 *dwc) if (dwc->sys_wakeup) device_init_wakeup(&dwc->xhci->dev, false); - dwc3_enable_susphy(dwc, false); + dwc3_enable_susphy(dwc, true); platform_device_unregister(dwc->xhci); dwc->xhci = NULL; } diff --git a/drivers/usb/gadget/udc/lpc32xx_udc.c b/drivers/usb/gadget/udc/lpc32xx_udc.c index 1a7d3c4f652f..83c7e243dcf9 100644 --- a/drivers/usb/gadget/udc/lpc32xx_udc.c +++ b/drivers/usb/gadget/udc/lpc32xx_udc.c @@ -3020,7 +3020,7 @@ static int lpc32xx_udc_probe(struct platform_device *pdev) pdev->dev.dma_mask = &lpc32xx_usbd_dmamask; retval = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); if (retval) - return retval; + goto err_put_client; udc->board = &lpc32xx_usbddata; @@ -3038,28 +3038,32 @@ static int lpc32xx_udc_probe(struct platform_device *pdev) /* Get IRQs */ for (i = 0; i < 4; i++) { udc->udp_irq[i] = platform_get_irq(pdev, i); - if (udc->udp_irq[i] < 0) - return udc->udp_irq[i]; + if (udc->udp_irq[i] < 0) { + retval = udc->udp_irq[i]; + goto err_put_client; + } } udc->udp_baseaddr = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(udc->udp_baseaddr)) { dev_err(udc->dev, "IO map failure\n"); - return PTR_ERR(udc->udp_baseaddr); + retval = PTR_ERR(udc->udp_baseaddr); + goto err_put_client; } /* Get USB device clock */ udc->usb_slv_clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(udc->usb_slv_clk)) { dev_err(udc->dev, "failed to acquire USB device clock\n"); - return PTR_ERR(udc->usb_slv_clk); + retval = PTR_ERR(udc->usb_slv_clk); + goto err_put_client; } /* Enable USB device clock */ retval = clk_prepare_enable(udc->usb_slv_clk); if (retval < 0) { dev_err(udc->dev, "failed to start USB device clock\n"); - return retval; + goto err_put_client; } /* Setup deferred workqueue data */ @@ -3080,7 +3084,7 @@ static int lpc32xx_udc_probe(struct platform_device *pdev) if (!udc->udca_v_base) { dev_err(udc->dev, "error getting UDCA region\n"); retval = -ENOMEM; - goto i2c_fail; + goto err_disable_clk; } udc->udca_p_base = dma_handle; dev_dbg(udc->dev, "DMA buffer(0x%x bytes), P:0x%08x, V:0x%p\n", @@ -3093,7 +3097,7 @@ static int lpc32xx_udc_probe(struct platform_device *pdev) if (!udc->dd_cache) { dev_err(udc->dev, "error getting DD DMA region\n"); retval = -ENOMEM; - goto dma_alloc_fail; + goto err_free_dma; } /* Clear USB peripheral and initialize gadget endpoints */ @@ -3107,14 +3111,14 @@ static int lpc32xx_udc_probe(struct platform_device *pdev) if (retval < 0) { dev_err(udc->dev, "LP request irq %d failed\n", udc->udp_irq[IRQ_USB_LP]); - goto irq_req_fail; + goto err_destroy_pool; } retval = devm_request_irq(dev, udc->udp_irq[IRQ_USB_HP], lpc32xx_usb_hp_irq, 0, "udc_hp", udc); if (retval < 0) { dev_err(udc->dev, "HP request irq %d failed\n", udc->udp_irq[IRQ_USB_HP]); - goto irq_req_fail; + goto err_destroy_pool; } retval = devm_request_irq(dev, udc->udp_irq[IRQ_USB_DEVDMA], @@ -3122,7 +3126,7 @@ static int lpc32xx_udc_probe(struct platform_device *pdev) if (retval < 0) { dev_err(udc->dev, "DEV request irq %d failed\n", udc->udp_irq[IRQ_USB_DEVDMA]); - goto irq_req_fail; + goto err_destroy_pool; } /* The transceiver interrupt is used for VBUS detection and will @@ -3133,7 +3137,7 @@ static int lpc32xx_udc_probe(struct platform_device *pdev) if (retval < 0) { dev_err(udc->dev, "VBUS request irq %d failed\n", udc->udp_irq[IRQ_USB_ATX]); - goto irq_req_fail; + goto err_destroy_pool; } /* Initialize wait queue */ @@ -3142,7 +3146,7 @@ static int lpc32xx_udc_probe(struct platform_device *pdev) retval = usb_add_gadget_udc(dev, &udc->gadget); if (retval < 0) - goto add_gadget_fail; + goto err_destroy_pool; dev_set_drvdata(dev, udc); device_init_wakeup(dev, 1); @@ -3154,14 +3158,16 @@ static int lpc32xx_udc_probe(struct platform_device *pdev) dev_info(udc->dev, "%s version %s\n", driver_name, DRIVER_VERSION); return 0; -add_gadget_fail: -irq_req_fail: +err_destroy_pool: dma_pool_destroy(udc->dd_cache); -dma_alloc_fail: +err_free_dma: dma_free_coherent(&pdev->dev, UDCA_BUFF_SIZE, udc->udca_v_base, udc->udca_p_base); -i2c_fail: +err_disable_clk: clk_disable_unprepare(udc->usb_slv_clk); +err_put_client: + put_device(&udc->isp1301_i2c_client->dev); + dev_err(udc->dev, "%s probe failed, %d\n", driver_name, retval); return retval; @@ -3190,6 +3196,8 @@ static void lpc32xx_udc_remove(struct platform_device *pdev) udc->udca_v_base, udc->udca_p_base); clk_disable_unprepare(udc->usb_slv_clk); + + put_device(&udc->isp1301_i2c_client->dev); } #ifdef CONFIG_PM diff --git a/drivers/usb/host/ohci-nxp.c b/drivers/usb/host/ohci-nxp.c index 24d5a1dc5056..7663f2aa35e9 100644 --- a/drivers/usb/host/ohci-nxp.c +++ b/drivers/usb/host/ohci-nxp.c @@ -169,13 +169,13 @@ static int ohci_hcd_nxp_probe(struct platform_device *pdev) ret = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); if (ret) - goto fail_disable; + goto err_put_client; dev_dbg(&pdev->dev, "%s: " DRIVER_DESC " (nxp)\n", hcd_name); if (usb_disabled()) { dev_err(&pdev->dev, "USB is disabled\n"); ret = -ENODEV; - goto fail_disable; + goto err_put_client; } /* Enable USB host clock */ @@ -183,7 +183,7 @@ static int ohci_hcd_nxp_probe(struct platform_device *pdev) if (IS_ERR(usb_host_clk)) { dev_err(&pdev->dev, "failed to acquire and start USB OHCI clock\n"); ret = PTR_ERR(usb_host_clk); - goto fail_disable; + goto err_put_client; } isp1301_configure(); @@ -192,13 +192,13 @@ static int ohci_hcd_nxp_probe(struct platform_device *pdev) if (!hcd) { dev_err(&pdev->dev, "Failed to allocate HC buffer\n"); ret = -ENOMEM; - goto fail_disable; + goto err_put_client; } hcd->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(hcd->regs)) { ret = PTR_ERR(hcd->regs); - goto fail_resource; + goto err_put_hcd; } hcd->rsrc_start = res->start; hcd->rsrc_len = resource_size(res); @@ -206,7 +206,7 @@ static int ohci_hcd_nxp_probe(struct platform_device *pdev) irq = platform_get_irq(pdev, 0); if (irq < 0) { ret = -ENXIO; - goto fail_resource; + goto err_put_hcd; } ohci_nxp_start_hc(); @@ -220,9 +220,10 @@ static int ohci_hcd_nxp_probe(struct platform_device *pdev) } ohci_nxp_stop_hc(); -fail_resource: +err_put_hcd: usb_put_hcd(hcd); -fail_disable: +err_put_client: + put_device(&isp1301_i2c_client->dev); isp1301_i2c_client = NULL; return ret; } @@ -234,6 +235,7 @@ static void ohci_hcd_nxp_remove(struct platform_device *pdev) usb_remove_hcd(hcd); ohci_nxp_stop_hc(); usb_put_hcd(hcd); + put_device(&isp1301_i2c_client->dev); isp1301_i2c_client = NULL; } diff --git a/drivers/usb/host/xhci-dbgtty.c b/drivers/usb/host/xhci-dbgtty.c index 57cdda4e09c8..90282e51e23e 100644 --- a/drivers/usb/host/xhci-dbgtty.c +++ b/drivers/usb/host/xhci-dbgtty.c @@ -554,7 +554,7 @@ static void xhci_dbc_tty_unregister_device(struct xhci_dbc *dbc) * Hang up the TTY. This wakes up any blocked * writers and causes subsequent writes to fail. */ - tty_vhangup(port->port.tty); + tty_port_tty_vhangup(&port->port); tty_unregister_device(dbc_tty_driver, port->minor); xhci_dbc_tty_exit_port(port); diff --git a/drivers/usb/phy/phy-fsl-usb.c b/drivers/usb/phy/phy-fsl-usb.c index 40ac68e52cee..e266a47c4d48 100644 --- a/drivers/usb/phy/phy-fsl-usb.c +++ b/drivers/usb/phy/phy-fsl-usb.c @@ -988,6 +988,7 @@ static void fsl_otg_remove(struct platform_device *pdev) { struct fsl_usb2_platform_data *pdata = dev_get_platdata(&pdev->dev); + disable_delayed_work_sync(&fsl_otg_dev->otg_event); usb_remove_phy(&fsl_otg_dev->phy); free_irq(fsl_otg_dev->irq, fsl_otg_dev); diff --git a/drivers/usb/phy/phy-isp1301.c b/drivers/usb/phy/phy-isp1301.c index f9b5c411aee4..2940f0c84e1b 100644 --- a/drivers/usb/phy/phy-isp1301.c +++ b/drivers/usb/phy/phy-isp1301.c @@ -149,7 +149,12 @@ struct i2c_client *isp1301_get_client(struct device_node *node) return client; /* non-DT: only one ISP1301 chip supported */ - return isp1301_i2c_client; + if (isp1301_i2c_client) { + get_device(&isp1301_i2c_client->dev); + return isp1301_i2c_client; + } + + return NULL; } EXPORT_SYMBOL_GPL(isp1301_get_client); diff --git a/drivers/usb/renesas_usbhs/pipe.c b/drivers/usb/renesas_usbhs/pipe.c index 75fff2e4cbc6..56fc3ff5016f 100644 --- a/drivers/usb/renesas_usbhs/pipe.c +++ b/drivers/usb/renesas_usbhs/pipe.c @@ -713,11 +713,13 @@ struct usbhs_pipe *usbhs_pipe_malloc(struct usbhs_priv *priv, /* make sure pipe is not busy */ ret = usbhsp_pipe_barrier(pipe); if (ret < 0) { + usbhsp_put_pipe(pipe); dev_err(dev, "pipe setup failed %d\n", usbhs_pipe_number(pipe)); return NULL; } if (usbhsp_setup_pipecfg(pipe, is_host, dir_in, &pipecfg)) { + usbhsp_put_pipe(pipe); dev_err(dev, "can't setup pipe\n"); return NULL; } diff --git a/drivers/usb/storage/unusual_uas.h b/drivers/usb/storage/unusual_uas.h index b695f5ba9a40..939a98c2d3f7 100644 --- a/drivers/usb/storage/unusual_uas.h +++ b/drivers/usb/storage/unusual_uas.h @@ -98,7 +98,7 @@ UNUSUAL_DEV(0x125f, 0xa94a, 0x0160, 0x0160, US_FL_NO_ATA_1X), /* Reported-by: Benjamin Tissoires <benjamin.tissoires@redhat.com> */ -UNUSUAL_DEV(0x13fd, 0x3940, 0x0309, 0x0309, +UNUSUAL_DEV(0x13fd, 0x3940, 0x0000, 0x0309, "Initio Corporation", "INIC-3069", USB_SC_DEVICE, USB_PR_DEVICE, NULL, diff --git a/drivers/usb/typec/altmodes/displayport.c b/drivers/usb/typec/altmodes/displayport.c index 8d111ad3b71b..d96ab106a980 100644 --- a/drivers/usb/typec/altmodes/displayport.c +++ b/drivers/usb/typec/altmodes/displayport.c @@ -766,12 +766,16 @@ int dp_altmode_probe(struct typec_altmode *alt) if (!(DP_CAP_PIN_ASSIGN_DFP_D(port->vdo) & DP_CAP_PIN_ASSIGN_UFP_D(alt->vdo)) && !(DP_CAP_PIN_ASSIGN_UFP_D(port->vdo) & - DP_CAP_PIN_ASSIGN_DFP_D(alt->vdo))) + DP_CAP_PIN_ASSIGN_DFP_D(alt->vdo))) { + typec_altmode_put_plug(plug); return -ENODEV; + } dp = devm_kzalloc(&alt->dev, sizeof(*dp), GFP_KERNEL); - if (!dp) + if (!dp) { + typec_altmode_put_plug(plug); return -ENOMEM; + } INIT_WORK(&dp->work, dp_altmode_work); mutex_init(&dp->lock); diff --git a/drivers/usb/typec/ucsi/Kconfig b/drivers/usb/typec/ucsi/Kconfig index 7fcb1e1de5d6..b812be4d0e67 100644 --- a/drivers/usb/typec/ucsi/Kconfig +++ b/drivers/usb/typec/ucsi/Kconfig @@ -96,6 +96,7 @@ config UCSI_LENOVO_YOGA_C630 config UCSI_HUAWEI_GAOKUN tristate "UCSI Interface Driver for Huawei Matebook E Go" depends on EC_HUAWEI_GAOKUN + depends on DRM || !DRM select DRM_AUX_HPD_BRIDGE if DRM_BRIDGE && OF help This driver enables UCSI support on the Huawei Matebook E Go tablet, diff --git a/drivers/usb/typec/ucsi/cros_ec_ucsi.c b/drivers/usb/typec/ucsi/cros_ec_ucsi.c index d753f2188e25..eed2a7d0ebc6 100644 --- a/drivers/usb/typec/ucsi/cros_ec_ucsi.c +++ b/drivers/usb/typec/ucsi/cros_ec_ucsi.c @@ -105,12 +105,13 @@ static int cros_ucsi_async_control(struct ucsi *ucsi, u64 cmd) return 0; } -static int cros_ucsi_sync_control(struct ucsi *ucsi, u64 cmd, u32 *cci) +static int cros_ucsi_sync_control(struct ucsi *ucsi, u64 cmd, u32 *cci, + void *data, size_t size) { struct cros_ucsi_data *udata = ucsi_get_drvdata(ucsi); int ret; - ret = ucsi_sync_control_common(ucsi, cmd, cci); + ret = ucsi_sync_control_common(ucsi, cmd, cci, data, size); switch (ret) { case -EBUSY: /* EC may return -EBUSY if CCI.busy is set. diff --git a/drivers/usb/typec/ucsi/debugfs.c b/drivers/usb/typec/ucsi/debugfs.c index 174f4d53b777..f3684ab787fe 100644 --- a/drivers/usb/typec/ucsi/debugfs.c +++ b/drivers/usb/typec/ucsi/debugfs.c @@ -37,9 +37,7 @@ static int ucsi_cmd(void *data, u64 val) case UCSI_SET_USB: case UCSI_SET_POWER_LEVEL: case UCSI_READ_POWER_LEVEL: - case UCSI_SET_PDOS: - ucsi->message_in_size = 0; - ret = ucsi_send_command(ucsi, val); + ret = ucsi_send_command(ucsi, val, NULL, 0); break; case UCSI_GET_CAPABILITY: case UCSI_GET_CONNECTOR_CAPABILITY: @@ -54,9 +52,9 @@ static int ucsi_cmd(void *data, u64 val) case UCSI_GET_ATTENTION_VDO: case UCSI_GET_CAM_CS: case UCSI_GET_LPM_PPM_INFO: - ucsi->message_in_size = sizeof(ucsi->debugfs->response); - ret = ucsi_send_command(ucsi, val); - memcpy(&ucsi->debugfs->response, ucsi->message_in, sizeof(ucsi->debugfs->response)); + ret = ucsi_send_command(ucsi, val, + &ucsi->debugfs->response, + sizeof(ucsi->debugfs->response)); break; default: ret = -EOPNOTSUPP; @@ -111,30 +109,6 @@ static int ucsi_vbus_volt_show(struct seq_file *m, void *v) } DEFINE_SHOW_ATTRIBUTE(ucsi_vbus_volt); -static ssize_t ucsi_message_out_write(struct file *file, - const char __user *data, size_t count, loff_t *ppos) -{ - struct ucsi *ucsi = file->private_data; - int ret; - - char *buf __free(kfree) = memdup_user_nul(data, count); - if (IS_ERR(buf)) - return PTR_ERR(buf); - - ucsi->message_out_size = min(count / 2, UCSI_MAX_MESSAGE_OUT_LENGTH); - ret = hex2bin(ucsi->message_out, buf, ucsi->message_out_size); - if (ret) - return ret; - - return count; -} - -static const struct file_operations ucsi_message_out_fops = { - .open = simple_open, - .write = ucsi_message_out_write, - .llseek = generic_file_llseek, -}; - void ucsi_debugfs_register(struct ucsi *ucsi) { ucsi->debugfs = kzalloc(sizeof(*ucsi->debugfs), GFP_KERNEL); @@ -147,8 +121,6 @@ void ucsi_debugfs_register(struct ucsi *ucsi) debugfs_create_file("peak_current", 0400, ucsi->debugfs->dentry, ucsi, &ucsi_peak_curr_fops); debugfs_create_file("avg_current", 0400, ucsi->debugfs->dentry, ucsi, &ucsi_avg_curr_fops); debugfs_create_file("vbus_voltage", 0400, ucsi->debugfs->dentry, ucsi, &ucsi_vbus_volt_fops); - debugfs_create_file("message_out", 0200, ucsi->debugfs->dentry, ucsi, - &ucsi_message_out_fops); } void ucsi_debugfs_unregister(struct ucsi *ucsi) diff --git a/drivers/usb/typec/ucsi/displayport.c b/drivers/usb/typec/ucsi/displayport.c index a09b4900ec76..8aae80b457d7 100644 --- a/drivers/usb/typec/ucsi/displayport.c +++ b/drivers/usb/typec/ucsi/displayport.c @@ -67,14 +67,11 @@ static int ucsi_displayport_enter(struct typec_altmode *alt, u32 *vdo) } command = UCSI_GET_CURRENT_CAM | UCSI_CONNECTOR_NUMBER(dp->con->num); - ucsi->message_in_size = sizeof(cur); - ret = ucsi_send_command(ucsi, command); + ret = ucsi_send_command(ucsi, command, &cur, sizeof(cur)); if (ret < 0) { if (ucsi->version > 0x0100) goto err_unlock; cur = 0xff; - } else { - memcpy(&cur, ucsi->message_in, ucsi->message_in_size); } if (cur != 0xff) { @@ -129,8 +126,7 @@ static int ucsi_displayport_exit(struct typec_altmode *alt) } command = UCSI_CMD_SET_NEW_CAM(dp->con->num, 0, dp->offset, 0); - dp->con->ucsi->message_in_size = 0; - ret = ucsi_send_command(dp->con->ucsi, command); + ret = ucsi_send_command(dp->con->ucsi, command, NULL, 0); if (ret < 0) goto out_unlock; @@ -197,8 +193,7 @@ static int ucsi_displayport_configure(struct ucsi_dp *dp) command = UCSI_CMD_SET_NEW_CAM(dp->con->num, 1, dp->offset, pins); - dp->con->ucsi->message_in_size = 0; - return ucsi_send_command(dp->con->ucsi, command); + return ucsi_send_command(dp->con->ucsi, command, NULL, 0); } static int ucsi_displayport_vdm(struct typec_altmode *alt, diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c index 9b3df776137a..a7b388dc7fa0 100644 --- a/drivers/usb/typec/ucsi/ucsi.c +++ b/drivers/usb/typec/ucsi/ucsi.c @@ -55,7 +55,8 @@ void ucsi_notify_common(struct ucsi *ucsi, u32 cci) } EXPORT_SYMBOL_GPL(ucsi_notify_common); -int ucsi_sync_control_common(struct ucsi *ucsi, u64 command, u32 *cci) +int ucsi_sync_control_common(struct ucsi *ucsi, u64 command, u32 *cci, + void *data, size_t size) { bool ack = UCSI_COMMAND(command) == UCSI_ACK_CC_CI; int ret; @@ -67,20 +68,6 @@ int ucsi_sync_control_common(struct ucsi *ucsi, u64 command, u32 *cci) reinit_completion(&ucsi->complete); - if (ucsi->message_out_size > 0) { - if (!ucsi->ops->write_message_out) { - ucsi->message_out_size = 0; - ret = -EOPNOTSUPP; - goto out_clear_bit; - } - - ret = ucsi->ops->write_message_out(ucsi, ucsi->message_out, - ucsi->message_out_size); - ucsi->message_out_size = 0; - if (ret) - goto out_clear_bit; - } - ret = ucsi->ops->async_control(ucsi, command); if (ret) goto out_clear_bit; @@ -97,10 +84,9 @@ out_clear_bit: if (!ret && cci) ret = ucsi->ops->read_cci(ucsi, cci); - if (!ret && ucsi->message_in_size > 0 && + if (!ret && data && (*cci & UCSI_CCI_COMMAND_COMPLETE)) - ret = ucsi->ops->read_message_in(ucsi, ucsi->message_in, - ucsi->message_in_size); + ret = ucsi->ops->read_message_in(ucsi, data, size); return ret; } @@ -117,25 +103,23 @@ static int ucsi_acknowledge(struct ucsi *ucsi, bool conn_ack) ctrl |= UCSI_ACK_CONNECTOR_CHANGE; } - ucsi->message_in_size = 0; - return ucsi->ops->sync_control(ucsi, ctrl, NULL); + return ucsi->ops->sync_control(ucsi, ctrl, NULL, NULL, 0); } -static int ucsi_run_command(struct ucsi *ucsi, u64 command, u32 *cci, bool conn_ack) +static int ucsi_run_command(struct ucsi *ucsi, u64 command, u32 *cci, + void *data, size_t size, bool conn_ack) { int ret, err; *cci = 0; - if (ucsi->message_in_size > UCSI_MAX_DATA_LENGTH(ucsi)) + if (size > UCSI_MAX_DATA_LENGTH(ucsi)) return -EINVAL; - ret = ucsi->ops->sync_control(ucsi, command, cci); + ret = ucsi->ops->sync_control(ucsi, command, cci, data, size); - if (*cci & UCSI_CCI_BUSY) { - ucsi->message_in_size = 0; - return ucsi_run_command(ucsi, UCSI_CANCEL, cci, false) ?: -EBUSY; - } + if (*cci & UCSI_CCI_BUSY) + return ucsi_run_command(ucsi, UCSI_CANCEL, cci, NULL, 0, false) ?: -EBUSY; if (ret) return ret; @@ -167,13 +151,10 @@ static int ucsi_read_error(struct ucsi *ucsi, u8 connector_num) int ret; command = UCSI_GET_ERROR_STATUS | UCSI_CONNECTOR_NUMBER(connector_num); - ucsi->message_in_size = sizeof(error); - ret = ucsi_run_command(ucsi, command, &cci, false); + ret = ucsi_run_command(ucsi, command, &cci, &error, sizeof(error), false); if (ret < 0) return ret; - memcpy(&error, ucsi->message_in, sizeof(error)); - switch (error) { case UCSI_ERROR_INCOMPATIBLE_PARTNER: return -EOPNOTSUPP; @@ -219,7 +200,8 @@ static int ucsi_read_error(struct ucsi *ucsi, u8 connector_num) return -EIO; } -static int ucsi_send_command_common(struct ucsi *ucsi, u64 cmd, bool conn_ack) +static int ucsi_send_command_common(struct ucsi *ucsi, u64 cmd, + void *data, size_t size, bool conn_ack) { u8 connector_num; u32 cci; @@ -247,7 +229,7 @@ static int ucsi_send_command_common(struct ucsi *ucsi, u64 cmd, bool conn_ack) mutex_lock(&ucsi->ppm_lock); - ret = ucsi_run_command(ucsi, cmd, &cci, conn_ack); + ret = ucsi_run_command(ucsi, cmd, &cci, data, size, conn_ack); if (cci & UCSI_CCI_ERROR) ret = ucsi_read_error(ucsi, connector_num); @@ -256,9 +238,10 @@ static int ucsi_send_command_common(struct ucsi *ucsi, u64 cmd, bool conn_ack) return ret; } -int ucsi_send_command(struct ucsi *ucsi, u64 command) +int ucsi_send_command(struct ucsi *ucsi, u64 command, + void *data, size_t size) { - return ucsi_send_command_common(ucsi, command, false); + return ucsi_send_command_common(ucsi, command, data, size, false); } EXPORT_SYMBOL_GPL(ucsi_send_command); @@ -336,8 +319,7 @@ void ucsi_altmode_update_active(struct ucsi_connector *con) int i; command = UCSI_GET_CURRENT_CAM | UCSI_CONNECTOR_NUMBER(con->num); - con->ucsi->message_in_size = sizeof(cur); - ret = ucsi_send_command(con->ucsi, command); + ret = ucsi_send_command(con->ucsi, command, &cur, sizeof(cur)); if (ret < 0) { if (con->ucsi->version > 0x0100) { dev_err(con->ucsi->dev, @@ -345,8 +327,6 @@ void ucsi_altmode_update_active(struct ucsi_connector *con) return; } cur = 0xff; - } else { - memcpy(&cur, con->ucsi->message_in, sizeof(cur)); } if (cur < UCSI_MAX_ALTMODES) @@ -530,8 +510,7 @@ ucsi_register_altmodes_nvidia(struct ucsi_connector *con, u8 recipient) command |= UCSI_GET_ALTMODE_RECIPIENT(recipient); command |= UCSI_GET_ALTMODE_CONNECTOR_NUMBER(con->num); command |= UCSI_GET_ALTMODE_OFFSET(i); - ucsi->message_in_size = sizeof(alt); - len = ucsi_send_command(con->ucsi, command); + len = ucsi_send_command(con->ucsi, command, &alt, sizeof(alt)); /* * We are collecting all altmodes first and then registering. * Some type-C device will return zero length data beyond last @@ -540,8 +519,6 @@ ucsi_register_altmodes_nvidia(struct ucsi_connector *con, u8 recipient) if (len < 0) return len; - memcpy(&alt, ucsi->message_in, sizeof(alt)); - /* We got all altmodes, now break out and register them */ if (!len || !alt.svid) break; @@ -609,15 +586,12 @@ static int ucsi_register_altmodes(struct ucsi_connector *con, u8 recipient) command |= UCSI_GET_ALTMODE_RECIPIENT(recipient); command |= UCSI_GET_ALTMODE_CONNECTOR_NUMBER(con->num); command |= UCSI_GET_ALTMODE_OFFSET(i); - con->ucsi->message_in_size = sizeof(alt); - len = ucsi_send_command(con->ucsi, command); + len = ucsi_send_command(con->ucsi, command, alt, sizeof(alt)); if (len == -EBUSY) continue; if (len <= 0) return len; - memcpy(&alt, con->ucsi->message_in, sizeof(alt)); - /* * This code is requesting one alt mode at a time, but some PPMs * may still return two. If that happens both alt modes need be @@ -685,9 +659,7 @@ static int ucsi_get_connector_status(struct ucsi_connector *con, bool conn_ack) UCSI_MAX_DATA_LENGTH(con->ucsi)); int ret; - con->ucsi->message_in_size = size; - ret = ucsi_send_command_common(con->ucsi, command, conn_ack); - memcpy(&con->status, con->ucsi->message_in, size); + ret = ucsi_send_command_common(con->ucsi, command, &con->status, size, conn_ack); return ret < 0 ? ret : 0; } @@ -710,9 +682,8 @@ static int ucsi_read_pdos(struct ucsi_connector *con, command |= UCSI_GET_PDOS_PDO_OFFSET(offset); command |= UCSI_GET_PDOS_NUM_PDOS(num_pdos - 1); command |= is_source(role) ? UCSI_GET_PDOS_SRC_PDOS : 0; - ucsi->message_in_size = num_pdos * sizeof(u32); - ret = ucsi_send_command(ucsi, command); - memcpy(pdos + offset, ucsi->message_in, num_pdos * sizeof(u32)); + ret = ucsi_send_command(ucsi, command, pdos + offset, + num_pdos * sizeof(u32)); if (ret < 0 && ret != -ETIMEDOUT) dev_err(ucsi->dev, "UCSI_GET_PDOS failed (%d)\n", ret); @@ -799,9 +770,7 @@ static int ucsi_get_pd_message(struct ucsi_connector *con, u8 recipient, command |= UCSI_GET_PD_MESSAGE_BYTES(len); command |= UCSI_GET_PD_MESSAGE_TYPE(type); - con->ucsi->message_in_size = len; - ret = ucsi_send_command(con->ucsi, command); - memcpy(data + offset, con->ucsi->message_in, len); + ret = ucsi_send_command(con->ucsi, command, data + offset, len); if (ret < 0) return ret; } @@ -966,9 +935,7 @@ static int ucsi_register_cable(struct ucsi_connector *con) int ret; command = UCSI_GET_CABLE_PROPERTY | UCSI_CONNECTOR_NUMBER(con->num); - con->ucsi->message_in_size = sizeof(cable_prop); - ret = ucsi_send_command(con->ucsi, command); - memcpy(&cable_prop, con->ucsi->message_in, sizeof(cable_prop)); + ret = ucsi_send_command(con->ucsi, command, &cable_prop, sizeof(cable_prop)); if (ret < 0) { dev_err(con->ucsi->dev, "GET_CABLE_PROPERTY failed (%d)\n", ret); return ret; @@ -1029,9 +996,7 @@ static int ucsi_check_connector_capability(struct ucsi_connector *con) return 0; command = UCSI_GET_CONNECTOR_CAPABILITY | UCSI_CONNECTOR_NUMBER(con->num); - con->ucsi->message_in_size = sizeof(con->cap); - ret = ucsi_send_command(con->ucsi, command); - memcpy(&con->cap, con->ucsi->message_in, sizeof(con->cap)); + ret = ucsi_send_command(con->ucsi, command, &con->cap, sizeof(con->cap)); if (ret < 0) { dev_err(con->ucsi->dev, "GET_CONNECTOR_CAPABILITY failed (%d)\n", ret); return ret; @@ -1415,8 +1380,7 @@ static int ucsi_reset_connector(struct ucsi_connector *con, bool hard) else if (con->ucsi->version >= UCSI_VERSION_2_0) command |= hard ? 0 : UCSI_CONNECTOR_RESET_DATA_VER_2_0; - con->ucsi->message_in_size = 0; - return ucsi_send_command(con->ucsi, command); + return ucsi_send_command(con->ucsi, command, NULL, 0); } static int ucsi_reset_ppm(struct ucsi *ucsi) @@ -1497,8 +1461,7 @@ static int ucsi_role_cmd(struct ucsi_connector *con, u64 command) { int ret; - con->ucsi->message_in_size = 0; - ret = ucsi_send_command(con->ucsi, command); + ret = ucsi_send_command(con->ucsi, command, NULL, 0); if (ret == -ETIMEDOUT) { u64 c; @@ -1506,8 +1469,7 @@ static int ucsi_role_cmd(struct ucsi_connector *con, u64 command) ucsi_reset_ppm(con->ucsi); c = UCSI_SET_NOTIFICATION_ENABLE | con->ucsi->ntfy; - con->ucsi->message_in_size = 0; - ucsi_send_command(con->ucsi, c); + ucsi_send_command(con->ucsi, c, NULL, 0); ucsi_reset_connector(con, true); } @@ -1660,13 +1622,10 @@ static int ucsi_register_port(struct ucsi *ucsi, struct ucsi_connector *con) /* Get connector capability */ command = UCSI_GET_CONNECTOR_CAPABILITY; command |= UCSI_CONNECTOR_NUMBER(con->num); - ucsi->message_in_size = sizeof(con->cap); - ret = ucsi_send_command(ucsi, command); + ret = ucsi_send_command(ucsi, command, &con->cap, sizeof(con->cap)); if (ret < 0) goto out_unlock; - memcpy(&con->cap, ucsi->message_in, sizeof(con->cap)); - if (UCSI_CONCAP(con, OPMODE_DRP)) cap->data = TYPEC_PORT_DRD; else if (UCSI_CONCAP(con, OPMODE_DFP)) @@ -1863,20 +1822,17 @@ static int ucsi_init(struct ucsi *ucsi) /* Enable basic notifications */ ntfy = UCSI_ENABLE_NTFY_CMD_COMPLETE | UCSI_ENABLE_NTFY_ERROR; command = UCSI_SET_NOTIFICATION_ENABLE | ntfy; - ucsi->message_in_size = 0; - ret = ucsi_send_command(ucsi, command); + ret = ucsi_send_command(ucsi, command, NULL, 0); if (ret < 0) goto err_reset; /* Get PPM capabilities */ command = UCSI_GET_CAPABILITY; - ucsi->message_in_size = BITS_TO_BYTES(UCSI_GET_CAPABILITY_SIZE); - ret = ucsi_send_command(ucsi, command); + ret = ucsi_send_command(ucsi, command, &ucsi->cap, + BITS_TO_BYTES(UCSI_GET_CAPABILITY_SIZE)); if (ret < 0) goto err_reset; - memcpy(&ucsi->cap, ucsi->message_in, BITS_TO_BYTES(UCSI_GET_CAPABILITY_SIZE)); - if (!ucsi->cap.num_connectors) { ret = -ENODEV; goto err_reset; @@ -1906,8 +1862,7 @@ static int ucsi_init(struct ucsi *ucsi) /* Enable all supported notifications */ ntfy = ucsi_get_supported_notifications(ucsi); command = UCSI_SET_NOTIFICATION_ENABLE | ntfy; - ucsi->message_in_size = 0; - ret = ucsi_send_command(ucsi, command); + ret = ucsi_send_command(ucsi, command, NULL, 0); if (ret < 0) goto err_unregister; @@ -1958,8 +1913,7 @@ static void ucsi_resume_work(struct work_struct *work) /* Restore UCSI notification enable mask after system resume */ command = UCSI_SET_NOTIFICATION_ENABLE | ucsi->ntfy; - ucsi->message_in_size = 0; - ret = ucsi_send_command(ucsi, command); + ret = ucsi_send_command(ucsi, command, NULL, 0); if (ret < 0) { dev_err(ucsi->dev, "failed to re-enable notifications (%d)\n", ret); return; diff --git a/drivers/usb/typec/ucsi/ucsi.h b/drivers/usb/typec/ucsi/ucsi.h index f946b728c373..410389ef173a 100644 --- a/drivers/usb/typec/ucsi/ucsi.h +++ b/drivers/usb/typec/ucsi/ucsi.h @@ -29,10 +29,6 @@ struct dentry; #define UCSI_MESSAGE_OUT 32 #define UCSIv2_MESSAGE_OUT 272 -/* Define maximum lengths for message buffers */ -#define UCSI_MAX_MESSAGE_IN_LENGTH 256 -#define UCSI_MAX_MESSAGE_OUT_LENGTH 256 - /* UCSI versions */ #define UCSI_VERSION_1_0 0x0100 #define UCSI_VERSION_1_1 0x0110 @@ -69,7 +65,6 @@ struct dentry; * @read_cci: Read CCI register * @poll_cci: Read CCI register while polling with notifications disabled * @read_message_in: Read message data from UCSI - * @write_message_out: Write message data to UCSI * @sync_control: Blocking control operation * @async_control: Non-blocking control operation * @update_altmodes: Squashes duplicate DP altmodes @@ -85,8 +80,8 @@ struct ucsi_operations { int (*read_cci)(struct ucsi *ucsi, u32 *cci); int (*poll_cci)(struct ucsi *ucsi, u32 *cci); int (*read_message_in)(struct ucsi *ucsi, void *val, size_t val_len); - int (*write_message_out)(struct ucsi *ucsi, void *data, size_t data_len); - int (*sync_control)(struct ucsi *ucsi, u64 command, u32 *cci); + int (*sync_control)(struct ucsi *ucsi, u64 command, u32 *cci, + void *data, size_t size); int (*async_control)(struct ucsi *ucsi, u64 command); bool (*update_altmodes)(struct ucsi *ucsi, u8 recipient, struct ucsi_altmode *orig, @@ -137,7 +132,6 @@ void ucsi_connector_change(struct ucsi *ucsi, u8 num); #define UCSI_GET_PD_MESSAGE 0x15 #define UCSI_GET_CAM_CS 0x18 #define UCSI_SET_SINK_PATH 0x1c -#define UCSI_SET_PDOS 0x1d #define UCSI_READ_POWER_LEVEL 0x1e #define UCSI_SET_USB 0x21 #define UCSI_GET_LPM_PPM_INFO 0x22 @@ -499,12 +493,6 @@ struct ucsi { unsigned long quirks; #define UCSI_NO_PARTNER_PDOS BIT(0) /* Don't read partner's PDOs */ #define UCSI_DELAY_DEVICE_PDOS BIT(1) /* Reading PDOs fails until the parter is in PD mode */ - - /* Fixed-size buffers for incoming and outgoing messages */ - u8 message_in[UCSI_MAX_MESSAGE_IN_LENGTH]; - size_t message_in_size; - u8 message_out[UCSI_MAX_MESSAGE_OUT_LENGTH]; - size_t message_out_size; }; #define UCSI_MAX_DATA_LENGTH(u) (((u)->version < UCSI_VERSION_2_0) ? 0x10 : 0xff) @@ -567,13 +555,15 @@ struct ucsi_connector { struct usb_pd_identity cable_identity; }; -int ucsi_send_command(struct ucsi *ucsi, u64 command); +int ucsi_send_command(struct ucsi *ucsi, u64 command, + void *retval, size_t size); void ucsi_altmode_update_active(struct ucsi_connector *con); int ucsi_resume(struct ucsi *ucsi); void ucsi_notify_common(struct ucsi *ucsi, u32 cci); -int ucsi_sync_control_common(struct ucsi *ucsi, u64 command, u32 *cci); +int ucsi_sync_control_common(struct ucsi *ucsi, u64 command, u32 *cci, + void *data, size_t size); #if IS_ENABLED(CONFIG_POWER_SUPPLY) int ucsi_register_port_psy(struct ucsi_connector *con); diff --git a/drivers/usb/typec/ucsi/ucsi_acpi.c b/drivers/usb/typec/ucsi/ucsi_acpi.c index f9beeb835238..6b92f296e985 100644 --- a/drivers/usb/typec/ucsi/ucsi_acpi.c +++ b/drivers/usb/typec/ucsi/ucsi_acpi.c @@ -86,21 +86,6 @@ static int ucsi_acpi_read_message_in(struct ucsi *ucsi, void *val, size_t val_le return 0; } -static int ucsi_acpi_write_message_out(struct ucsi *ucsi, void *data, size_t data_len) -{ - struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi); - - if (!data || !data_len) - return -EINVAL; - - if (ucsi->version <= UCSI_VERSION_1_2) - memcpy(ua->base + UCSI_MESSAGE_OUT, data, data_len); - else - memcpy(ua->base + UCSIv2_MESSAGE_OUT, data, data_len); - - return 0; -} - static int ucsi_acpi_async_control(struct ucsi *ucsi, u64 command) { struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi); @@ -116,19 +101,19 @@ static const struct ucsi_operations ucsi_acpi_ops = { .read_cci = ucsi_acpi_read_cci, .poll_cci = ucsi_acpi_poll_cci, .read_message_in = ucsi_acpi_read_message_in, - .write_message_out = ucsi_acpi_write_message_out, .sync_control = ucsi_sync_control_common, .async_control = ucsi_acpi_async_control }; -static int ucsi_gram_sync_control(struct ucsi *ucsi, u64 command, u32 *cci) +static int ucsi_gram_sync_control(struct ucsi *ucsi, u64 command, u32 *cci, + void *val, size_t len) { u16 bogus_change = UCSI_CONSTAT_POWER_LEVEL_CHANGE | UCSI_CONSTAT_PDOS_CHANGE; struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi); int ret; - ret = ucsi_sync_control_common(ucsi, command, cci); + ret = ucsi_sync_control_common(ucsi, command, cci, val, len); if (ret < 0) return ret; @@ -140,8 +125,8 @@ static int ucsi_gram_sync_control(struct ucsi *ucsi, u64 command, u32 *cci) if (UCSI_COMMAND(ua->cmd) == UCSI_GET_CONNECTOR_STATUS && ua->check_bogus_event) { /* Clear the bogus change */ - if (*(u16 *)ucsi->message_in == bogus_change) - *(u16 *)ucsi->message_in = 0; + if (*(u16 *)val == bogus_change) + *(u16 *)val = 0; ua->check_bogus_event = false; } diff --git a/drivers/usb/typec/ucsi/ucsi_ccg.c b/drivers/usb/typec/ucsi/ucsi_ccg.c index ead1b2a25c79..d83a0051c737 100644 --- a/drivers/usb/typec/ucsi/ucsi_ccg.c +++ b/drivers/usb/typec/ucsi/ucsi_ccg.c @@ -606,7 +606,8 @@ static int ucsi_ccg_async_control(struct ucsi *ucsi, u64 command) return ccg_write(uc, reg, (u8 *)&command, sizeof(command)); } -static int ucsi_ccg_sync_control(struct ucsi *ucsi, u64 command, u32 *cci) +static int ucsi_ccg_sync_control(struct ucsi *ucsi, u64 command, u32 *cci, + void *data, size_t size) { struct ucsi_ccg *uc = ucsi_get_drvdata(ucsi); struct ucsi_connector *con; @@ -628,16 +629,16 @@ static int ucsi_ccg_sync_control(struct ucsi *ucsi, u64 command, u32 *cci) ucsi_ccg_update_set_new_cam_cmd(uc, con, &command); } - ret = ucsi_sync_control_common(ucsi, command, cci); + ret = ucsi_sync_control_common(ucsi, command, cci, data, size); switch (UCSI_COMMAND(command)) { case UCSI_GET_CURRENT_CAM: if (uc->has_multiple_dp) - ucsi_ccg_update_get_current_cam_cmd(uc, (u8 *)ucsi->message_in); + ucsi_ccg_update_get_current_cam_cmd(uc, (u8 *)data); break; case UCSI_GET_ALTERNATE_MODES: if (UCSI_ALTMODE_RECIPIENT(command) == UCSI_RECIPIENT_SOP) { - struct ucsi_altmode *alt = (struct ucsi_altmode *)ucsi->message_in; + struct ucsi_altmode *alt = data; if (alt[0].svid == USB_TYPEC_NVIDIA_VLINK_SID) ucsi_ccg_nvidia_altmode(uc, alt, command); @@ -645,7 +646,7 @@ static int ucsi_ccg_sync_control(struct ucsi *ucsi, u64 command, u32 *cci) break; case UCSI_GET_CAPABILITY: if (uc->fw_build == CCG_FW_BUILD_NVIDIA_TEGRA) { - struct ucsi_capability *cap = (struct ucsi_capability *)ucsi->message_in; + struct ucsi_capability *cap = data; cap->features &= ~UCSI_CAP_ALT_MODE_DETAILS; } diff --git a/drivers/usb/typec/ucsi/ucsi_yoga_c630.c b/drivers/usb/typec/ucsi/ucsi_yoga_c630.c index 299081444caa..0187c1c4b21a 100644 --- a/drivers/usb/typec/ucsi/ucsi_yoga_c630.c +++ b/drivers/usb/typec/ucsi/ucsi_yoga_c630.c @@ -88,7 +88,8 @@ static int yoga_c630_ucsi_async_control(struct ucsi *ucsi, u64 command) static int yoga_c630_ucsi_sync_control(struct ucsi *ucsi, u64 command, - u32 *cci) + u32 *cci, + void *data, size_t size) { int ret; @@ -106,8 +107,8 @@ static int yoga_c630_ucsi_sync_control(struct ucsi *ucsi, }; dev_dbg(ucsi->dev, "faking DP altmode for con1\n"); - memset(ucsi->message_in, 0, ucsi->message_in_size); - memcpy(ucsi->message_in, &alt, min(sizeof(alt), ucsi->message_in_size)); + memset(data, 0, size); + memcpy(data, &alt, min(sizeof(alt), size)); *cci = UCSI_CCI_COMMAND_COMPLETE | UCSI_SET_CCI_LENGTH(sizeof(alt)); return 0; } @@ -120,18 +121,18 @@ static int yoga_c630_ucsi_sync_control(struct ucsi *ucsi, if (UCSI_COMMAND(command) == UCSI_GET_ALTERNATE_MODES && UCSI_GET_ALTMODE_GET_CONNECTOR_NUMBER(command) == 2) { dev_dbg(ucsi->dev, "ignoring altmodes for con2\n"); - memset(ucsi->message_in, 0, ucsi->message_in_size); + memset(data, 0, size); *cci = UCSI_CCI_COMMAND_COMPLETE; return 0; } - ret = ucsi_sync_control_common(ucsi, command, cci); + ret = ucsi_sync_control_common(ucsi, command, cci, data, size); if (ret < 0) return ret; /* UCSI_GET_CURRENT_CAM is off-by-one on all ports */ - if (UCSI_COMMAND(command) == UCSI_GET_CURRENT_CAM && ucsi->message_in_size > 0) - ucsi->message_in[0]--; + if (UCSI_COMMAND(command) == UCSI_GET_CURRENT_CAM && data) + ((u8 *)data)[0]--; return ret; } diff --git a/drivers/vfio/pci/nvgrace-gpu/main.c b/drivers/vfio/pci/nvgrace-gpu/main.c index 84d142a47ec6..b45a24d00387 100644 --- a/drivers/vfio/pci/nvgrace-gpu/main.c +++ b/drivers/vfio/pci/nvgrace-gpu/main.c @@ -561,7 +561,7 @@ nvgrace_gpu_map_and_read(struct nvgrace_gpu_pci_core_device *nvdev, ret = vfio_pci_core_do_io_rw(&nvdev->core_device, false, nvdev->resmem.ioaddr, buf, offset, mem_count, - 0, 0, false); + 0, 0, false, VFIO_PCI_IO_WIDTH_8); } return ret; @@ -693,7 +693,7 @@ nvgrace_gpu_map_and_write(struct nvgrace_gpu_pci_core_device *nvdev, ret = vfio_pci_core_do_io_rw(&nvdev->core_device, false, nvdev->resmem.ioaddr, (char __user *)buf, pos, mem_count, - 0, 0, true); + 0, 0, true, VFIO_PCI_IO_WIDTH_8); } return ret; diff --git a/drivers/vfio/pci/pds/dirty.c b/drivers/vfio/pci/pds/dirty.c index 481992142f79..4915a7c1c491 100644 --- a/drivers/vfio/pci/pds/dirty.c +++ b/drivers/vfio/pci/pds/dirty.c @@ -292,8 +292,11 @@ static int pds_vfio_dirty_enable(struct pds_vfio_pci_device *pds_vfio, len = num_ranges * sizeof(*region_info); node = interval_tree_iter_first(ranges, 0, ULONG_MAX); - if (!node) - return -EINVAL; + if (!node) { + err = -EINVAL; + goto out_free_region_info; + } + for (int i = 0; i < num_ranges; i++) { struct pds_lm_dirty_region_info *ri = ®ion_info[i]; u64 region_size = node->last - node->start + 1; diff --git a/drivers/vfio/pci/vfio_pci_rdwr.c b/drivers/vfio/pci/vfio_pci_rdwr.c index 6192788c8ba3..b38627b35c35 100644 --- a/drivers/vfio/pci/vfio_pci_rdwr.c +++ b/drivers/vfio/pci/vfio_pci_rdwr.c @@ -135,7 +135,8 @@ VFIO_IORDWR(64) ssize_t vfio_pci_core_do_io_rw(struct vfio_pci_core_device *vdev, bool test_mem, void __iomem *io, char __user *buf, loff_t off, size_t count, size_t x_start, - size_t x_end, bool iswrite) + size_t x_end, bool iswrite, + enum vfio_pci_io_width max_width) { ssize_t done = 0; int ret; @@ -150,20 +151,19 @@ ssize_t vfio_pci_core_do_io_rw(struct vfio_pci_core_device *vdev, bool test_mem, else fillable = 0; - if (fillable >= 8 && !(off % 8)) { + if (fillable >= 8 && !(off % 8) && max_width >= 8) { ret = vfio_pci_iordwr64(vdev, iswrite, test_mem, io, buf, off, &filled); if (ret) return ret; - } else - if (fillable >= 4 && !(off % 4)) { + } else if (fillable >= 4 && !(off % 4) && max_width >= 4) { ret = vfio_pci_iordwr32(vdev, iswrite, test_mem, io, buf, off, &filled); if (ret) return ret; - } else if (fillable >= 2 && !(off % 2)) { + } else if (fillable >= 2 && !(off % 2) && max_width >= 2) { ret = vfio_pci_iordwr16(vdev, iswrite, test_mem, io, buf, off, &filled); if (ret) @@ -234,6 +234,7 @@ ssize_t vfio_pci_bar_rw(struct vfio_pci_core_device *vdev, char __user *buf, void __iomem *io; struct resource *res = &vdev->pdev->resource[bar]; ssize_t done; + enum vfio_pci_io_width max_width = VFIO_PCI_IO_WIDTH_8; if (pci_resource_start(pdev, bar)) end = pci_resource_len(pdev, bar); @@ -262,6 +263,16 @@ ssize_t vfio_pci_bar_rw(struct vfio_pci_core_device *vdev, char __user *buf, if (!io) return -ENOMEM; x_end = end; + + /* + * Certain devices (e.g. Intel X710) don't support qword + * access to the ROM bar. Otherwise PCI AER errors might be + * triggered. + * + * Disable qword access to the ROM bar universally, which + * worked reliably for years before qword access is enabled. + */ + max_width = VFIO_PCI_IO_WIDTH_4; } else { int ret = vfio_pci_core_setup_barmap(vdev, bar); if (ret) { @@ -278,7 +289,7 @@ ssize_t vfio_pci_bar_rw(struct vfio_pci_core_device *vdev, char __user *buf, } done = vfio_pci_core_do_io_rw(vdev, res->flags & IORESOURCE_MEM, io, buf, pos, - count, x_start, x_end, iswrite); + count, x_start, x_end, iswrite, max_width); if (done >= 0) *ppos += done; @@ -352,7 +363,7 @@ ssize_t vfio_pci_vga_rw(struct vfio_pci_core_device *vdev, char __user *buf, * to the memory enable bit in the command register. */ done = vfio_pci_core_do_io_rw(vdev, false, iomem, buf, off, count, - 0, 0, iswrite); + 0, 0, iswrite, VFIO_PCI_IO_WIDTH_4); vga_put(vdev->pdev, rsrc); diff --git a/drivers/vfio/pci/xe/main.c b/drivers/vfio/pci/xe/main.c index 0156b53c678b..2a5eb9260ec7 100644 --- a/drivers/vfio/pci/xe/main.c +++ b/drivers/vfio/pci/xe/main.c @@ -250,6 +250,7 @@ xe_vfio_pci_alloc_file(struct xe_vfio_pci_core_device *xe_vdev, struct xe_vfio_pci_migration_file *migf; const struct file_operations *fops; int flags; + int ret; migf = kzalloc(sizeof(*migf), GFP_KERNEL_ACCOUNT); if (!migf) @@ -259,8 +260,9 @@ xe_vfio_pci_alloc_file(struct xe_vfio_pci_core_device *xe_vdev, flags = type == XE_VFIO_FILE_SAVE ? O_RDONLY : O_WRONLY; migf->filp = anon_inode_getfile("xe_vfio_mig", fops, migf, flags); if (IS_ERR(migf->filp)) { + ret = PTR_ERR(migf->filp); kfree(migf); - return ERR_CAST(migf->filp); + return ERR_PTR(ret); } mutex_init(&migf->lock); @@ -504,6 +506,7 @@ static const struct vfio_device_ops xe_vfio_pci_ops = { .open_device = xe_vfio_pci_open_device, .close_device = xe_vfio_pci_close_device, .ioctl = vfio_pci_core_ioctl, + .get_region_info_caps = vfio_pci_ioctl_get_region_info, .device_feature = vfio_pci_core_ioctl_feature, .read = vfio_pci_core_read, .write = vfio_pci_core_write, diff --git a/drivers/vhost/vsock.c b/drivers/vhost/vsock.c index 0298ddc34824..552cfb53498a 100644 --- a/drivers/vhost/vsock.c +++ b/drivers/vhost/vsock.c @@ -66,14 +66,15 @@ static u32 vhost_transport_get_local_cid(void) return VHOST_VSOCK_DEFAULT_HOST_CID; } -/* Callers that dereference the return value must hold vhost_vsock_mutex or the - * RCU read lock. +/* Callers must be in an RCU read section or hold the vhost_vsock_mutex. + * The return value can only be dereferenced while within the section. */ static struct vhost_vsock *vhost_vsock_get(u32 guest_cid) { struct vhost_vsock *vsock; - hash_for_each_possible_rcu(vhost_vsock_hash, vsock, hash, guest_cid) { + hash_for_each_possible_rcu(vhost_vsock_hash, vsock, hash, guest_cid, + lockdep_is_held(&vhost_vsock_mutex)) { u32 other_cid = vsock->guest_cid; /* Skip instances that have no CID yet */ @@ -709,9 +710,15 @@ static void vhost_vsock_reset_orphans(struct sock *sk) * executing. */ + rcu_read_lock(); + /* If the peer is still valid, no need to reset connection */ - if (vhost_vsock_get(vsk->remote_addr.svm_cid)) + if (vhost_vsock_get(vsk->remote_addr.svm_cid)) { + rcu_read_unlock(); return; + } + + rcu_read_unlock(); /* If the close timeout is pending, let it expire. This avoids races * with the timeout callback. |
