diff options
| author | Jakub Kicinski <kuba@kernel.org> | 2026-09-17 14:24:32 -0700 |
|---|---|---|
| committer | Jakub Kicinski <kuba@kernel.org> | 2026-09-17 14:31:42 -0700 |
| commit | f2b5c73c032bb03c48dce1072fc3edaf74c92402 (patch) | |
| tree | 31766a4a370366d74deeacebdcb715a9d4372677 /drivers | |
| parent | 26ee8cd69d46a14b37ba5e512084fe80d730127a (diff) | |
| parent | b5a051f6b840d48f159166ef073d3021989bfb50 (diff) | |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net
Cross-merge networking fixes after downstream PR (net-7.3-rc4).
Conflicts:
net/core/neighbour.c
979aabdad8dd0 ("neighbour: Skip default parms when resumed in neightbl_dump_info().")
7b430fcfc972f ("neighbour: Don't render blackhole_netdev via RTM_GETNEIGHTBL.")
fae1c59810b86 ("neighbour: Remove unnecessary net_eq().")
https://lore.kernel.org/20260911173056.44ec06e0@kernel.org
https://lore.kernel.org/aqfbJi7nAX4IbmnR@sirena.co.uk
Adjacent changes:
net/netlink/af_netlink.c
ceac0de741bf ("netlink: do not free nlk->groups while lockless readers can use it")
7c0ec6288b49 ("net: Replace %pK output with 0")
net/bridge/br_vlan.c
2842ce397dd0 ("net: bridge: vlan: fix bugs caused by switchdev deletion errors")
5bec8f861114 ("net: bridge: vlan: annotate lockless use of num_vlans")
2b1f8fd3118c ("net: bridge: vlan: annotate lockless vlan flags use")
net/bridge/br_mst.c
18a6fe05fb6e ("net: bridge: mst: move switchdev call outside rcu")
120207a08fc0 ("net: bridge: vlan: annotate lockless use of msti")
drivers/net/ethernet/stmicro/stmmac/hwif.h
90e4b849dfa6 ("net: stmmac: propagate FPE preemption-class mapping errors")
85ca3292d7a3 ("net: stmmac: Remove ARP offload code")
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Diffstat (limited to 'drivers')
186 files changed, 1792 insertions, 817 deletions
diff --git a/drivers/accel/ethosu/ethosu_device.h b/drivers/accel/ethosu/ethosu_device.h index d4458eac8447..1eca8590e68d 100644 --- a/drivers/accel/ethosu/ethosu_device.h +++ b/drivers/accel/ethosu/ethosu_device.h @@ -87,6 +87,7 @@ struct gen_pool; #define PMU_EV_TYPE_IDLE 0x20 enum ethosu_cmds { + NPU_OP_STOP = 0x0, NPU_OP_CONV = 0x2, NPU_OP_DEPTHWISE = 0x3, NPU_OP_POOL = 0x5, diff --git a/drivers/accel/ethosu/ethosu_drv.c b/drivers/accel/ethosu/ethosu_drv.c index 1cf284e7f300..8108622de258 100644 --- a/drivers/accel/ethosu/ethosu_drv.c +++ b/drivers/accel/ethosu/ethosu_drv.c @@ -281,8 +281,6 @@ static int ethosu_device_suspend(struct device *dev) static int ethosu_sram_init(struct ethosu_device *ethosudev) { - ethosudev->npu_info.sram_size = 0; - ethosudev->srampool = of_gen_pool_get(ethosudev->base.dev->of_node, "sram", 0); if (!ethosudev->srampool) return 0; @@ -293,6 +291,7 @@ static int ethosu_sram_init(struct ethosu_device *ethosudev) ethosudev->npu_info.sram_size, ðosudev->sramphys); if (!ethosudev->sram) { + ethosudev->npu_info.sram_size = 0; dev_err(ethosudev->base.dev, "failed to allocate from SRAM pool\n"); return -ENOMEM; } diff --git a/drivers/accel/ethosu/ethosu_gem.c b/drivers/accel/ethosu/ethosu_gem.c index fa37a190e9ff..9afe2549ec84 100644 --- a/drivers/accel/ethosu/ethosu_gem.c +++ b/drivers/accel/ethosu/ethosu_gem.c @@ -390,6 +390,7 @@ static int ethosu_gem_cmdstream_copy_and_validate(struct drm_device *ddev, struct ethosu_validated_cmdstream_info __free(kfree) *info = kzalloc_obj(*info); struct ethosu_device *edev = to_ethosu_device(ddev); u32 *bocmds = bo->base.vaddr; + bool ends_with_stop = false; struct cmd_state st; int i, ret; @@ -426,6 +427,11 @@ static int ethosu_gem_cmdstream_copy_and_validate(struct drm_device *ddev, } switch (cmd) { + case NPU_OP_STOP: + if (i != size / 4 - 1) + return -EINVAL; + ends_with_stop = true; + break; case NPU_OP_DMA_START: srclen = dma_length(info, &st.dma, &st.dma.src); dstlen = dma_length(info, &st.dma, &st.dma.dst); @@ -688,6 +694,9 @@ static int ethosu_gem_cmdstream_copy_and_validate(struct drm_device *ddev, } } + if (!ends_with_stop) + return -EINVAL; + for (i = 0; i < NPU_BASEP_REGION_MAX; i++) { if (!info->region_size[i]) continue; diff --git a/drivers/accel/ethosu/ethosu_job.c b/drivers/accel/ethosu/ethosu_job.c index 4ced44a65f23..8dce74db0cb4 100644 --- a/drivers/accel/ethosu/ethosu_job.c +++ b/drivers/accel/ethosu/ethosu_job.c @@ -343,7 +343,7 @@ int ethosu_job_init(struct ethosu_device *edev) ret = devm_request_threaded_irq(dev, edev->irq, ethosu_job_irq_handler, ethosu_job_irq_handler_thread, - IRQF_SHARED, KBUILD_MODNAME, + 0, KBUILD_MODNAME, edev); if (ret) { dev_err(dev, "failed to request irq\n"); @@ -374,12 +374,10 @@ int ethosu_job_open(struct ethosu_file_priv *ethosu_priv) { struct ethosu_device *dev = ethosu_priv->edev; struct drm_gpu_scheduler *sched = &dev->sched; - int ret; - ret = drm_sched_entity_init(ðosu_priv->sched_entity, - DRM_SCHED_PRIORITY_NORMAL, - &sched, 1, NULL); - return WARN_ON(ret); + return drm_sched_entity_init(ðosu_priv->sched_entity, + DRM_SCHED_PRIORITY_NORMAL, + &sched, 1, NULL); } void ethosu_job_close(struct ethosu_file_priv *ethosu_priv) @@ -449,13 +447,13 @@ static int ethosu_ioctl_submit_job(struct drm_device *dev, struct drm_file *file if (!cmd_info->region_size[i]) continue; if (i == ETHOSU_SRAM_REGION) { - if (cmd_info->region_size[i] <= edev->npu_info.sram_size) + if (cmd_info->region_size[i] <= ejob->sram_size) continue; dev_err(dev->dev, - "cmd stream region %d size greater than SRAM size (%llu > %u)\n", + "cmd stream region %d size greater than job SRAM size (%llu > %u)\n", i, cmd_info->region_size[i], - edev->npu_info.sram_size); + ejob->sram_size); ret = -EINVAL; goto out_cleanup_job; } diff --git a/drivers/accel/ivpu/ivpu_fw_log.c b/drivers/accel/ivpu/ivpu_fw_log.c index 716467aa3156..9eafc42120b6 100644 --- a/drivers/accel/ivpu/ivpu_fw_log.c +++ b/drivers/accel/ivpu/ivpu_fw_log.c @@ -26,10 +26,17 @@ MODULE_PARM_DESC(fw_log_level, " error=" __stringify(IVPU_FW_LOG_ERROR) " fatal=" __stringify(IVPU_FW_LOG_FATAL)); +struct ivpu_fw_log_desc { + struct vpu_tracing_buffer_header *log; + u32 header_size; + u32 size; +}; + static int fw_log_from_bo(struct ivpu_device *vdev, struct ivpu_bo *bo, u32 *offset, - struct vpu_tracing_buffer_header **out_log) + struct ivpu_fw_log_desc *desc) { struct vpu_tracing_buffer_header *log; + u32 header_size, size; if ((*offset + sizeof(*log)) > ivpu_bo_size(bo)) return -EINVAL; @@ -39,26 +46,32 @@ static int fw_log_from_bo(struct ivpu_device *vdev, struct ivpu_bo *bo, u32 *off if (log->vpu_canary_start != VPU_TRACING_BUFFER_CANARY) return -EINVAL; - if (log->header_size < sizeof(*log) || log->header_size > 1024) { - ivpu_dbg(vdev, FW_BOOT, "Invalid header size 0x%x\n", log->header_size); + header_size = READ_ONCE(log->header_size); + size = READ_ONCE(log->size); + + if (header_size < sizeof(*log) || header_size > 1024) { + ivpu_dbg(vdev, FW_BOOT, "Invalid header size 0x%x\n", header_size); return -EINVAL; } - if (log->size < log->header_size) { - ivpu_dbg(vdev, FW_BOOT, "Invalid log size 0x%x\n", log->size); + if ((char *)log + size > (char *)ivpu_bo_vaddr(bo) + ivpu_bo_size(bo)) { + ivpu_dbg(vdev, FW_BOOT, "Invalid log size 0x%x\n", size); return -EINVAL; } - if ((char *)log + log->size > (char *)ivpu_bo_vaddr(bo) + ivpu_bo_size(bo)) { - ivpu_dbg(vdev, FW_BOOT, "Invalid log size 0x%x\n", log->size); + if (size < header_size) { + ivpu_dbg(vdev, FW_BOOT, "Invalid log size 0x%x < header size 0x%x\n", + size, header_size); return -EINVAL; } - *out_log = log; - *offset += log->size; + desc->log = log; + desc->header_size = header_size; + desc->size = size; + *offset += size; ivpu_dbg(vdev, FW_BOOT, - "FW log name \"%s\", write offset 0x%x size 0x%x, wrap count %d, hdr version %d size %d format %d, alignment %d", - log->name, log->write_index, log->size, log->wrap_count, log->header_version, - log->header_size, log->format, log->alignment); + "FW log name \"%.*s\", write offset 0x%x size 0x%x, wrap count %d, hdr version %d size %d format %d, alignment %d", + (int)ARRAY_SIZE(log->name), log->name, log->write_index, size, log->wrap_count, + log->header_version, header_size, log->format, log->alignment); return 0; } @@ -94,11 +107,12 @@ static void fw_log_print_lines(char *buffer, u32 size, struct drm_printer *p) drm_printf(p, "%s", line); } -static void fw_log_print_buffer(struct vpu_tracing_buffer_header *log, const char *prefix, +static void fw_log_print_buffer(struct ivpu_fw_log_desc *desc, const char *prefix, bool only_new_msgs, struct drm_printer *p) { - char *log_data = (void *)log + log->header_size; - u32 data_size = log->size - log->header_size; + struct vpu_tracing_buffer_header *log = desc->log; + char *log_data = (void *)log + desc->header_size; + u32 data_size = desc->size - desc->header_size; u32 log_start = only_new_msgs ? READ_ONCE(log->read_index) : 0; u32 log_end = READ_ONCE(log->write_index); @@ -109,7 +123,8 @@ static void fw_log_print_buffer(struct vpu_tracing_buffer_header *log, const cha if (log->wrap_count == log->read_wrap_count) { if (log_end <= log_start) { - drm_printf(p, "==== %s \"%s\" log empty ====\n", prefix, log->name); + drm_printf(p, "==== %s \"%.*s\" log empty ====\n", prefix, + (int)ARRAY_SIZE(log->name), log->name); return; } } else if (log->wrap_count == log->read_wrap_count + 1) { @@ -119,7 +134,8 @@ static void fw_log_print_buffer(struct vpu_tracing_buffer_header *log, const cha log_start = log_end; } - drm_printf(p, "==== %s \"%s\" log start ====\n", prefix, log->name); + drm_printf(p, "==== %s \"%.*s\" log start ====\n", prefix, (int)ARRAY_SIZE(log->name), + log->name); if (log_end > log_start) { fw_log_print_lines(log_data + log_start, log_end - log_start, p); } else { @@ -127,18 +143,19 @@ static void fw_log_print_buffer(struct vpu_tracing_buffer_header *log, const cha fw_log_print_lines(log_data, log_end, p); } drm_printf(p, "\n\x1b[0m"); /* add new line and clear formatting */ - drm_printf(p, "==== %s \"%s\" log end ====\n", prefix, log->name); + drm_printf(p, "==== %s \"%.*s\" log end ====\n", prefix, (int)ARRAY_SIZE(log->name), + log->name); } static void fw_log_print_all_in_bo(struct ivpu_device *vdev, const char *name, struct ivpu_bo *bo, bool only_new_msgs, struct drm_printer *p) { - struct vpu_tracing_buffer_header *log; + struct ivpu_fw_log_desc desc; u32 next = 0; - while (fw_log_from_bo(vdev, bo, &next, &log) == 0) - fw_log_print_buffer(log, name, only_new_msgs, p); + while (fw_log_from_bo(vdev, bo, &next, &desc) == 0) + fw_log_print_buffer(&desc, name, only_new_msgs, p); } void ivpu_fw_log_print(struct ivpu_device *vdev, bool only_new_msgs, struct drm_printer *p) @@ -149,36 +166,36 @@ void ivpu_fw_log_print(struct ivpu_device *vdev, bool only_new_msgs, struct drm_ void ivpu_fw_log_mark_read(struct ivpu_device *vdev) { - struct vpu_tracing_buffer_header *log; + struct ivpu_fw_log_desc desc; u32 next; next = 0; - while (fw_log_from_bo(vdev, vdev->fw->mem_log_crit, &next, &log) == 0) { - log->read_index = READ_ONCE(log->write_index); - log->read_wrap_count = READ_ONCE(log->wrap_count); + while (fw_log_from_bo(vdev, vdev->fw->mem_log_crit, &next, &desc) == 0) { + desc.log->read_index = READ_ONCE(desc.log->write_index); + desc.log->read_wrap_count = READ_ONCE(desc.log->wrap_count); } next = 0; - while (fw_log_from_bo(vdev, vdev->fw->mem_log_verb, &next, &log) == 0) { - log->read_index = READ_ONCE(log->write_index); - log->read_wrap_count = READ_ONCE(log->wrap_count); + while (fw_log_from_bo(vdev, vdev->fw->mem_log_verb, &next, &desc) == 0) { + desc.log->read_index = READ_ONCE(desc.log->write_index); + desc.log->read_wrap_count = READ_ONCE(desc.log->wrap_count); } } void ivpu_fw_log_reset(struct ivpu_device *vdev) { - struct vpu_tracing_buffer_header *log; + struct ivpu_fw_log_desc desc; u32 next; next = 0; - while (fw_log_from_bo(vdev, vdev->fw->mem_log_crit, &next, &log) == 0) { - log->read_index = 0; - log->read_wrap_count = 0; + while (fw_log_from_bo(vdev, vdev->fw->mem_log_crit, &next, &desc) == 0) { + desc.log->read_index = 0; + desc.log->read_wrap_count = 0; } next = 0; - while (fw_log_from_bo(vdev, vdev->fw->mem_log_verb, &next, &log) == 0) { - log->read_index = 0; - log->read_wrap_count = 0; + while (fw_log_from_bo(vdev, vdev->fw->mem_log_verb, &next, &desc) == 0) { + desc.log->read_index = 0; + desc.log->read_wrap_count = 0; } } diff --git a/drivers/accel/ivpu/ivpu_gem.h b/drivers/accel/ivpu/ivpu_gem.h index 0c3350f22b55..b1ae020a4fc2 100644 --- a/drivers/accel/ivpu/ivpu_gem.h +++ b/drivers/accel/ivpu/ivpu_gem.h @@ -87,15 +87,23 @@ static inline bool ivpu_bo_is_resident(struct ivpu_bo *bo) return !!bo->base.pages; } -static inline void *ivpu_to_cpu_addr(struct ivpu_bo *bo, u32 vpu_addr) +static inline void *ivpu_to_cpu_addr(struct ivpu_bo *bo, u64 vpu_addr, u64 size) { + u64 bo_size = ivpu_bo_size(bo); + u64 offset; + if (vpu_addr < bo->vpu_addr) return NULL; - if (vpu_addr >= (bo->vpu_addr + ivpu_bo_size(bo))) + if (size > bo_size) + return NULL; + + offset = vpu_addr - bo->vpu_addr; + + if (offset > bo_size - size) return NULL; - return ivpu_bo_vaddr(bo) + (vpu_addr - bo->vpu_addr); + return ivpu_bo_vaddr(bo) + offset; } static inline u32 cpu_to_vpu_addr(struct ivpu_bo *bo, void *cpu_addr) diff --git a/drivers/accel/ivpu/ivpu_ipc.c b/drivers/accel/ivpu/ivpu_ipc.c index 62607ec8ca8f..8e960293b77a 100644 --- a/drivers/accel/ivpu/ivpu_ipc.c +++ b/drivers/accel/ivpu/ivpu_ipc.c @@ -79,7 +79,7 @@ ivpu_ipc_tx_prepare(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons, return -ENOMEM; } - tx_buf = ivpu_to_cpu_addr(ipc->mem_tx, tx_buf_vpu_addr); + tx_buf = ivpu_to_cpu_addr(ipc->mem_tx, tx_buf_vpu_addr, sizeof(*tx_buf)); if (drm_WARN_ON(&vdev->drm, !tx_buf)) { gen_pool_free(ipc->mm_tx, tx_buf_vpu_addr, sizeof(*tx_buf)); return -EIO; @@ -420,7 +420,7 @@ void ivpu_ipc_irq_handler(struct ivpu_device *vdev) return; } - ipc_hdr = ivpu_to_cpu_addr(ipc->mem_rx, vpu_addr); + ipc_hdr = ivpu_to_cpu_addr(ipc->mem_rx, vpu_addr, sizeof(*ipc_hdr)); if (!ipc_hdr) { ivpu_warn_ratelimited(vdev, "IPC msg 0x%x out of range\n", vpu_addr); continue; @@ -429,7 +429,8 @@ void ivpu_ipc_irq_handler(struct ivpu_device *vdev) jsm_msg = NULL; if (ipc_hdr->channel != IVPU_IPC_CHAN_BOOT_MSG) { - jsm_msg = ivpu_to_cpu_addr(ipc->mem_rx, ipc_hdr->data_addr); + jsm_msg = ivpu_to_cpu_addr(ipc->mem_rx, ipc_hdr->data_addr, + sizeof(*jsm_msg)); if (!jsm_msg) { ivpu_warn_ratelimited(vdev, "JSM msg 0x%x out of range\n", ipc_hdr->data_addr); diff --git a/drivers/block/sunvdc.c b/drivers/block/sunvdc.c index 020bd9f1a7b6..2be8231dcd5b 100644 --- a/drivers/block/sunvdc.c +++ b/drivers/block/sunvdc.c @@ -525,6 +525,23 @@ static int __send_request(struct request *req) err = __vdc_tx_trigger(port); if (err < 0) { printk(KERN_ERR PFX "vdc_tx_trigger() failure, err=%d\n", err); + /* + * If the port was reset (-ENOTCONN), the dring and the + * LDC channel including all of its mappings are already + * torn down and reallocated - there is nothing to undo + * and @desc must not be touched. + * + * For any other failure the descriptor was never handed + * to the peer: unmap the cookies and free the descriptor + * again, so that a later retry of the request does not + * leak LDC map table entries. + */ + if (err != -ENOTCONN) { + ldc_unmap(port->vio.lp, desc->cookies, + desc->ncookies); + desc->hdr.state = VIO_DESC_FREE; + rqe->req = NULL; + } } else { port->req_id++; dr->prod = vio_dring_next(dr, dr->prod); @@ -539,6 +556,7 @@ static blk_status_t vdc_queue_rq(struct blk_mq_hw_ctx *hctx, struct vdc_port *port = hctx->queue->queuedata; struct vio_dring_state *dr; unsigned long flags; + int ret; dr = &port->vio.drings[VIO_DRIVER_TX_RING]; @@ -560,7 +578,13 @@ static blk_status_t vdc_queue_rq(struct blk_mq_hw_ctx *hctx, return BLK_STS_DEV_RESOURCE; } - if (__send_request(bd->rq) < 0) { + ret = __send_request(bd->rq); + if (ret == -EAGAIN) { + spin_unlock_irqrestore(&port->vio.lock, flags); + /* already spun for 10msec, defer 10msec and retry */ + blk_mq_delay_kick_requeue_list(hctx->queue, 10); + return BLK_STS_DEV_RESOURCE; + } else if (ret < 0) { spin_unlock_irqrestore(&port->vio.lock, flags); return BLK_STS_IOERR; } diff --git a/drivers/block/ublk_drv.c b/drivers/block/ublk_drv.c index c387fb589c57..66eb55e7162e 100644 --- a/drivers/block/ublk_drv.c +++ b/drivers/block/ublk_drv.c @@ -3030,6 +3030,7 @@ static void ublk_queue_reset_io_flags(struct ublk_queue *ubq) ubq->canceling = false; spin_unlock(&ubq->cancel_lock); ubq->fail_io = false; + ubq->force_abort = false; } /* device can only be started after all IOs are ready */ diff --git a/drivers/bluetooth/btintel_pcie.c b/drivers/bluetooth/btintel_pcie.c index 6d9649776ae7..6e6e2b19815c 100644 --- a/drivers/bluetooth/btintel_pcie.c +++ b/drivers/bluetooth/btintel_pcie.c @@ -404,6 +404,12 @@ static int btintel_pcie_send_sync(struct btintel_pcie_data *data, if (tfd_index > txq->count) return -ERANGE; + if (skb->len > BTINTEL_PCIE_BUFFER_SIZE - BTINTEL_PCIE_HCI_TYPE_LEN) { + bt_dev_err(hdev, "TX skb too large (%u > %u)", skb->len, + BTINTEL_PCIE_BUFFER_SIZE - BTINTEL_PCIE_HCI_TYPE_LEN); + return -EMSGSIZE; + } + /* Firmware raises alive interrupt on HCI_OP_RESET or * BTINTEL_HCI_OP_RESET */ @@ -502,7 +508,7 @@ static int btintel_pcie_submit_rx(struct btintel_pcie_data *data) frbd_index = data->ia.tr_hia[BTINTEL_PCIE_RXQ_NUM]; - if (frbd_index > rxq->count) + if (frbd_index >= rxq->count) return -ERANGE; /* Prepare for RX submit. It updates the FRBD with the address of DMA diff --git a/drivers/bluetooth/btmtk.c b/drivers/bluetooth/btmtk.c index 26d525acd659..7ea8bcd8a7ec 100644 --- a/drivers/bluetooth/btmtk.c +++ b/drivers/bluetooth/btmtk.c @@ -721,7 +721,12 @@ static int btmtk_usb_hci_wmt_sync(struct hci_dev *hdev, case BTMTK_WMT_FUNC_CTRL: if (!skb_pull_data(data->evt_skb, sizeof(wmt_evt_funcc->status))) { - status = BTMTK_WMT_ON_UNDONE; + /* A plain enable/disable request is acked with just + * the WMT header and no trailing status word; the + * result is carried in the header's own flag byte. + */ + status = wmt_evt->whdr.flag ? BTMTK_WMT_ON_UNDONE : + BTMTK_WMT_ON_DONE; break; } diff --git a/drivers/bluetooth/btmtksdio.c b/drivers/bluetooth/btmtksdio.c index 94aa60d9cc20..a15ae6598c66 100644 --- a/drivers/bluetooth/btmtksdio.c +++ b/drivers/bluetooth/btmtksdio.c @@ -217,7 +217,14 @@ static int mtk_hci_wmt_sync(struct hci_dev *hdev, } /* Parse and handle the return WMT event */ - wmt_evt = (struct btmtk_hci_wmt_evt *)bdev->evt_skb->data; + wmt_evt = skb_pull_data(bdev->evt_skb, sizeof(*wmt_evt)); + if (!wmt_evt) { + bt_dev_err(hdev, "WMT event too short (%u bytes)", + bdev->evt_skb->len); + err = -EINVAL; + goto err_free_skb; + } + if (wmt_evt->whdr.op != hdr->op) { bt_dev_err(hdev, "Wrong op received %d expected %d", wmt_evt->whdr.op, hdr->op); @@ -233,6 +240,17 @@ static int mtk_hci_wmt_sync(struct hci_dev *hdev, status = BTMTK_WMT_PATCH_DONE; break; case BTMTK_WMT_FUNC_CTRL: + if (!skb_pull_data(bdev->evt_skb, + sizeof(wmt_evt_funcc->status))) { + /* A plain enable/disable request is acked with just + * the WMT header and no trailing status word; the + * result is carried in the header's own flag byte. + */ + status = wmt_evt->whdr.flag ? BTMTK_WMT_ON_UNDONE : + BTMTK_WMT_ON_DONE; + break; + } + wmt_evt_funcc = (struct btmtk_hci_wmt_evt_funcc *)wmt_evt; if (be16_to_cpu(wmt_evt_funcc->status) == 0x404) status = BTMTK_WMT_ON_DONE; @@ -1244,10 +1262,8 @@ static int btmtksdio_shutdown(struct hci_dev *hdev) wmt_params.status = NULL; err = mtk_hci_wmt_sync(hdev, &wmt_params); - if (err < 0) { + if (err < 0) bt_dev_err(hdev, "Failed to send wmt func ctrl (%d)", err); - return err; - } ignore_wmt_cmd: pm_runtime_put_noidle(bdev->dev); diff --git a/drivers/bluetooth/btmtkuart.c b/drivers/bluetooth/btmtkuart.c index 27aa48ff3ac2..4af6fbbbd302 100644 --- a/drivers/bluetooth/btmtkuart.c +++ b/drivers/bluetooth/btmtkuart.c @@ -151,7 +151,14 @@ static int mtk_hci_wmt_sync(struct hci_dev *hdev, } /* Parse and handle the return WMT event */ - wmt_evt = (struct btmtk_hci_wmt_evt *)bdev->evt_skb->data; + wmt_evt = skb_pull_data(bdev->evt_skb, sizeof(*wmt_evt)); + if (!wmt_evt) { + bt_dev_err(hdev, "WMT event too short (%u bytes)", + bdev->evt_skb->len); + err = -EINVAL; + goto err_free_wc; + } + if (wmt_evt->whdr.op != hdr->op) { bt_dev_err(hdev, "Wrong op received %d expected %d", wmt_evt->whdr.op, hdr->op); @@ -167,6 +174,17 @@ static int mtk_hci_wmt_sync(struct hci_dev *hdev, status = BTMTK_WMT_PATCH_DONE; break; case BTMTK_WMT_FUNC_CTRL: + if (!skb_pull_data(bdev->evt_skb, + sizeof(wmt_evt_funcc->status))) { + /* A plain enable/disable request is acked with just + * the WMT header and no trailing status word; the + * result is carried in the header's own flag byte. + */ + status = wmt_evt->whdr.flag ? BTMTK_WMT_ON_UNDONE : + BTMTK_WMT_ON_DONE; + break; + } + wmt_evt_funcc = (struct btmtk_hci_wmt_evt_funcc *)wmt_evt; if (be16_to_cpu(wmt_evt_funcc->status) == 0x404) status = BTMTK_WMT_ON_DONE; diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 002b9f975710..dc7191bf4234 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -71,6 +71,15 @@ static struct usb_driver btusb_driver; #define BTUSB_BROKEN_EXT_SCAN BIT(29) static const struct usb_device_id btusb_table[] = { + /* + * NXP IW610 (0471:0215): the composite device reports Bluetooth + * class at the whole-device level, so the generic entry below + * would also match this WiFi vendor interface. Ignore it here + * first so mwifiex-nxp can bind it instead. + */ + { USB_DEVICE_AND_INTERFACE_INFO(0x0471, 0x0215, 0xff, 0xff, 0xff), + .driver_info = BTUSB_IGNORE }, + /* Generic Bluetooth USB device */ { USB_DEVICE_INFO(0xe0, 0x01, 0x01) }, @@ -477,6 +486,14 @@ static const struct usb_device_id quirks_table[] = { { USB_DEVICE(0x1286, 0x2046), .driver_info = BTUSB_MARVELL }, { USB_DEVICE(0x1286, 0x204e), .driver_info = BTUSB_MARVELL }, + /* + * NXP IW610 BT interfaces (Marvell-lineage silicon, same quirk as + * the 0x1286 entries above). Scoped to the BT interface class, + * not just VID/PID -- see the btusb_table entry above. + */ + { USB_DEVICE_AND_INTERFACE_INFO(0x0471, 0x0215, 0xe0, 0x01, 0x01), + .driver_info = BTUSB_MARVELL }, + /* Intel Bluetooth devices */ { USB_DEVICE(0x8087, 0x0025), .driver_info = BTUSB_INTEL_COMBINED }, { USB_DEVICE(0x8087, 0x0026), .driver_info = BTUSB_INTEL_COMBINED }, diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c index faa964735adb..7089e9b639b2 100644 --- a/drivers/bluetooth/hci_qca.c +++ b/drivers/bluetooth/hci_qca.c @@ -2228,8 +2228,8 @@ static void qca_power_off(struct hci_uart *hu) bool sw_ctrl_state; struct qca_power *power; - /* From this point we go into power off state. But serial port is - * still open, stop queueing the IBS data and flush all the buffered + /* From this point we go into power off state. But serial port may + * still be open, stop queueing the IBS data and flush all the buffered * data in skb's. */ spin_lock_irqsave(&qca->hci_ibs_lock, flags); @@ -2251,8 +2251,14 @@ static void qca_power_off(struct hci_uart *hu) case QCA_WCN3990: case QCA_WCN3991: case QCA_WCN3998: - host_set_baudrate(hu, 2400); - qca_send_power_pulse(hu, false); + /* Both of these write to the serial port which may have + * already been closed by hci_uart_close(), which closes + * the port if HCI_QUIRK_NON_PERSISTENT_SETUP is set. + */ + if (test_bit(HCI_UART_PROTO_READY, &hu->flags)) { + host_set_baudrate(hu, 2400); + qca_send_power_pulse(hu, false); + } break; default: break; diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 0d0df986fa3d..96515880b4ac 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1249,7 +1249,7 @@ static struct cpufreq_policy *cpufreq_policy_alloc(unsigned int cpu) if (!policy) return NULL; - if (!alloc_cpumask_var(&policy->cpus, GFP_KERNEL)) + if (!zalloc_cpumask_var(&policy->cpus, GFP_KERNEL)) goto err_free_policy; if (!zalloc_cpumask_var(&policy->related_cpus, GFP_KERNEL)) @@ -1258,6 +1258,8 @@ static struct cpufreq_policy *cpufreq_policy_alloc(unsigned int cpu) if (!zalloc_cpumask_var(&policy->real_cpus, GFP_KERNEL)) goto err_free_rcpumask; + init_rwsem(&policy->rwsem); + init_completion(&policy->kobj_unregister); ret = kobject_init_and_add(&policy->kobj, &ktype_cpufreq, cpufreq_global_kobject, "policy%u", cpu); @@ -1272,8 +1274,6 @@ static struct cpufreq_policy *cpufreq_policy_alloc(unsigned int cpu) goto err_free_real_cpus; } - init_rwsem(&policy->rwsem); - freq_constraints_init(&policy->constraints); policy->nb_min.notifier_call = cpufreq_notifier_min; diff --git a/drivers/dpll/dpll_netlink.c b/drivers/dpll/dpll_netlink.c index 523d76a5fd49..45365214fbef 100644 --- a/drivers/dpll/dpll_netlink.c +++ b/drivers/dpll/dpll_netlink.c @@ -1202,6 +1202,7 @@ dpll_pin_ref_sync_state_set(struct dpll_pin *pin, const enum dpll_pin_state state, struct netlink_ext_ack *extack) { + void *pin_priv, *ref_sync_pin_priv; const struct dpll_pin_ops *ops; enum dpll_pin_state old_state; struct dpll_pin *ref_sync_pin; @@ -1230,9 +1231,15 @@ dpll_pin_ref_sync_state_set(struct dpll_pin *pin, return -EOPNOTSUPP; } dpll = ref->dpll; - ret = ops->ref_sync_get(pin, dpll_pin_on_dpll_priv(dpll, pin), - ref_sync_pin, - dpll_pin_on_dpll_priv(dpll, ref_sync_pin), + pin_priv = dpll_pin_on_dpll_priv(dpll, pin); + ref_sync_pin_priv = dpll_pin_on_dpll_priv(dpll, ref_sync_pin); + /* Pin may have been unregistered from this dpll already */ + if (!ref_sync_pin_priv) { + NL_SET_ERR_MSG(extack, + "reference sync pin not registered with the dpll"); + return -ENODEV; + } + ret = ops->ref_sync_get(pin, pin_priv, ref_sync_pin, ref_sync_pin_priv, &old_state, extack); if (ret) { NL_SET_ERR_MSG(extack, "unable to get old reference sync state"); @@ -1241,9 +1248,7 @@ dpll_pin_ref_sync_state_set(struct dpll_pin *pin, if (state == old_state) return 0; - ret = ops->ref_sync_set(pin, dpll_pin_on_dpll_priv(dpll, pin), - ref_sync_pin, - dpll_pin_on_dpll_priv(dpll, ref_sync_pin), + ret = ops->ref_sync_set(pin, pin_priv, ref_sync_pin, ref_sync_pin_priv, state, extack); if (ret) { NL_SET_ERR_MSG_FMT(extack, diff --git a/drivers/edac/altera_edac.c b/drivers/edac/altera_edac.c index 1d1e2b5ca14c..68846f583eee 100644 --- a/drivers/edac/altera_edac.c +++ b/drivers/edac/altera_edac.c @@ -1534,7 +1534,7 @@ static int altr_portb_setup(struct altr_edac_device_dev *device) altdev = dci->pvt_info; *altdev = *device; - if (!devres_open_group(&altdev->ddev, altr_portb_setup, GFP_KERNEL)) + if (!devres_open_group(device->edac->dev, altr_portb_setup, GFP_KERNEL)) return -ENOMEM; /* Update PortB specific values */ @@ -1562,7 +1562,7 @@ static int altr_portb_setup(struct altr_edac_device_dev *device) rc = -ENODEV; goto err_release_group_1; } - rc = devm_request_irq(&altdev->ddev, altdev->sb_irq, + rc = devm_request_irq(device->edac->dev, altdev->sb_irq, prv->ecc_irq_handler, IRQF_TRIGGER_HIGH, ecc_name, altdev); if (rc) { @@ -1584,7 +1584,7 @@ static int altr_portb_setup(struct altr_edac_device_dev *device) rc = -ENODEV; goto err_release_group_1; } - rc = devm_request_irq(&altdev->ddev, altdev->db_irq, + rc = devm_request_irq(device->edac->dev, altdev->db_irq, prv->ecc_irq_handler, IRQF_TRIGGER_HIGH, ecc_name, altdev); if (rc) { @@ -1604,13 +1604,13 @@ static int altr_portb_setup(struct altr_edac_device_dev *device) list_add(&altdev->next, &altdev->edac->a10_ecc_devices); - devres_remove_group(&altdev->ddev, altr_portb_setup); + devres_remove_group(device->edac->dev, altr_portb_setup); return 0; err_release_group_1: edac_device_free_ctl_info(dci); - devres_release_group(&altdev->ddev, altr_portb_setup); + devres_release_group(device->edac->dev, altr_portb_setup); edac_printk(KERN_ERR, EDAC_DEVICE, "%s:Error setting up EDAC device: %d\n", ecc_name, rc); return rc; diff --git a/drivers/gpio/gpio-virtuser.c b/drivers/gpio/gpio-virtuser.c index 449fb1aed24b..70ddccccc1c4 100644 --- a/drivers/gpio/gpio-virtuser.c +++ b/drivers/gpio/gpio-virtuser.c @@ -692,7 +692,8 @@ static int gpio_virtuser_interrupts_set(void *data, u64 val) atomic_set(&ld->irq, irq); } else { irq = atomic_xchg(&ld->irq, 0); - free_irq(irq, ld); + if (irq) + free_irq(irq, ld); } return 0; diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index 940b566946ce..f36e4b171fa7 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -788,13 +788,13 @@ static int of_gpio_notify(struct notifier_block *nb, unsigned long action, if (!of_property_read_bool(rd->dn, "gpio-hog")) return NOTIFY_DONE; /* not for us */ - if (of_node_test_and_set_flag(rd->dn, OF_POPULATED)) - return NOTIFY_DONE; - gdev = of_find_gpio_device_by_node(rd->dn->parent); if (!gdev) return NOTIFY_DONE; /* not for us */ + if (of_node_test_and_set_flag(rd->dn, OF_POPULATED)) + return NOTIFY_DONE; + ret = gpiochip_add_hog(gpio_device_get_chip(gdev), of_fwnode_handle(rd->dn)); if (ret < 0) { pr_err("%s: failed to add hogs for %pOF\n", __func__, diff --git a/drivers/gpio/gpiolib-shared.c b/drivers/gpio/gpiolib-shared.c index 495bd3d0ddf0..5f9623e40b0f 100644 --- a/drivers/gpio/gpiolib-shared.c +++ b/drivers/gpio/gpiolib-shared.c @@ -261,10 +261,13 @@ static int gpio_shared_of_traverse(struct device_node *curr) con_id[con_id_len - suffix_len] = '\0'; } - ref = gpio_shared_make_ref(fwnode_handle_get(of_fwnode_handle(curr)), - con_id, args.args[1]); - if (!ref) + struct fwnode_handle *curr_fwnode = + fwnode_handle_get(of_fwnode_handle(curr)); + ref = gpio_shared_make_ref(curr_fwnode, con_id, args.args[1]); + if (!ref) { + fwnode_handle_put(curr_fwnode); return -ENOMEM; + } if (!list_empty(&entry->refs)) pr_debug("GPIO %u at %s is shared by multiple firmware nodes\n", diff --git a/drivers/gpu/drm/adp/Kconfig b/drivers/gpu/drm/adp/Kconfig index 9fcc27eb200d..acfa21ee06d2 100644 --- a/drivers/gpu/drm/adp/Kconfig +++ b/drivers/gpu/drm/adp/Kconfig @@ -6,7 +6,6 @@ config DRM_ADP select DRM_KMS_HELPER select DRM_BRIDGE_CONNECTOR select DRM_DISPLAY_HELPER - select DRM_KMS_DMA_HELPER select DRM_GEM_DMA_HELPER select DRM_PANEL_BRIDGE select VIDEOMODE_HELPERS diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c index 5d9d137209b6..1b6c32a177fb 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c @@ -1701,9 +1701,8 @@ u64 amdgpu_bo_print_info(int id, struct amdgpu_bo *bo, struct seq_file *m) if (dma_resv_trylock(bo->tbo.base.resv)) { dma_resv_describe(bo->tbo.base.resv, m); dma_resv_unlock(bo->tbo.base.resv); - } else { - seq_puts(m, "\n"); } + seq_puts(m, "\n"); return size; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index 05abf4c31dce..016957cac1f2 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -191,6 +191,8 @@ amdgpu_ttm_job_submit(struct amdgpu_device *adev, struct amdgpu_ttm_buffer_entit * @tmz: if we should setup a TMZ enabled mapping * @size: in number of bytes to map, out number of bytes mapped * @addr: resulting address inside the MC address space + * @vm_needs_flush: out, set true if a GART window was programmed (VMID 0 flush + * needed) or false for a direct address * * Setup one of the GART windows to access a specific piece of memory or return * the physical address for local memory. @@ -200,7 +202,8 @@ static int amdgpu_ttm_map_buffer(struct amdgpu_ttm_buffer_entity *entity, struct ttm_resource *mem, struct amdgpu_res_cursor *mm_cur, unsigned int window, - bool tmz, uint64_t *size, uint64_t *addr) + bool tmz, uint64_t *size, uint64_t *addr, + bool *vm_needs_flush) { struct amdgpu_device *adev = amdgpu_ttm_adev(bo->bdev); unsigned int offset, num_pages, num_dw, num_bytes; @@ -221,9 +224,12 @@ static int amdgpu_ttm_map_buffer(struct amdgpu_ttm_buffer_entity *entity, if (!tmz && mem->start != AMDGPU_BO_INVALID_OFFSET) { *addr = amdgpu_ttm_domain_start(adev, mem->mem_type) + mm_cur->start; + *vm_needs_flush = false; return 0; } + /* A GART window is programmed below, so its VMID 0 TLB needs a flush */ + *vm_needs_flush = true; /* * If start begins at an offset inside the page, then adjust the size @@ -324,6 +330,7 @@ static int amdgpu_ttm_copy_mem_to_mem(struct amdgpu_device *adev, while (src_mm.remaining) { uint64_t from, to, cur_size, tiling_flags; uint32_t num_type, data_format, max_com, write_compress_disable; + bool src_vm_flush, dst_vm_flush; struct dma_fence *next; /* Never copy more than 256MiB at once to avoid a timeout */ @@ -331,12 +338,12 @@ static int amdgpu_ttm_copy_mem_to_mem(struct amdgpu_device *adev, /* Map src to window 0 and dst to window 1. */ r = amdgpu_ttm_map_buffer(entity, src->bo, src->mem, &src_mm, - 0, tmz, &cur_size, &from); + 0, tmz, &cur_size, &from, &src_vm_flush); if (r) goto error; r = amdgpu_ttm_map_buffer(entity, dst->bo, dst->mem, &dst_mm, - 1, tmz, &cur_size, &to); + 1, tmz, &cur_size, &to, &dst_vm_flush); if (r) goto error; @@ -364,7 +371,7 @@ static int amdgpu_ttm_copy_mem_to_mem(struct amdgpu_device *adev, } r = amdgpu_copy_buffer(adev, entity, from, to, cur_size, resv, - &next, true, copy_flags); + &next, src_vm_flush || dst_vm_flush, copy_flags); if (r) goto error; @@ -2624,6 +2631,7 @@ int amdgpu_ttm_clear_buffer(struct amdgpu_ttm_buffer_entity *entity, struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev); struct dma_fence *fence = NULL; struct amdgpu_res_cursor dst; + bool vm_needs_flush = false; int r; if (!entity) @@ -2645,13 +2653,13 @@ int amdgpu_ttm_clear_buffer(struct amdgpu_ttm_buffer_entity *entity, cur_size = min(dst.size, 256ULL << 20); r = amdgpu_ttm_map_buffer(entity, &bo->tbo, bo->tbo.resource, &dst, - 0, false, &cur_size, &to); + 0, false, &cur_size, &to, &vm_needs_flush); if (r) goto error; r = amdgpu_ttm_fill_mem(adev, entity, 0, to, cur_size, resv, - &next, true, k_job_id); + &next, vm_needs_flush, k_job_id); if (r) goto error; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index 2fe934036e36..08b8605029ab 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -747,9 +747,9 @@ static int amdgpu_dm_init(struct amdgpu_device *adev) } if (adev->dm.dc->caps.max_links > 0) { adev->dm.hdmi_frl_status_polling_wq = - create_singlethread_workqueue("hdmi_frl_status_polling_workqueue"); + create_singlethread_workqueue("hdmi_frl_status_polling_wq"); if (!adev->dm.hdmi_frl_status_polling_wq) - drm_err(adev_to_drm(adev), "failed to initialize hdmi_frl_status_polling_workqueue\n"); + drm_err(adev_to_drm(adev), "failed to initialize hdmi_frl_status_polling_wq\n"); } if (dc_is_dmub_outbox_supported(adev->dm.dc)) { init_completion(&adev->dm.dmub_aux_transfer_done); @@ -1972,6 +1972,10 @@ static int dm_resume(struct amdgpu_ip_block *ip_block) /* On resume we need to rewrite the MSTM control bits to enable MST*/ s3_handle_mst(ddev, false); + /* Exit IPS before the detection loop's first AUX/DDC access. */ + scoped_guard(mutex, &dm->dc_lock) + dc_exit_ips_for_hw_access(dm->dc); + /* Do detection*/ drm_connector_list_iter_begin(ddev, &iter); drm_for_each_connector_iter(connector, &iter) { diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c index c8a1ab8c3b16..154e1f35dcb1 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_connector.c @@ -756,10 +756,14 @@ amdgpu_dm_get_output_color_space(const struct dc_crtc_timing *dc_crtc_timing, break; case DRM_MODE_COLORIMETRY_BT2020_RGB: case DRM_MODE_COLORIMETRY_BT2020_YCC: - if (dc_crtc_timing->pixel_encoding == PIXEL_ENCODING_RGB) - color_space = COLOR_SPACE_2020_RGB_FULLRANGE; - else + if (dc_crtc_timing->pixel_encoding == PIXEL_ENCODING_RGB) { + if (connector_state->hdmi.broadcast_rgb == DRM_HDMI_BROADCAST_RGB_LIMITED) + color_space = COLOR_SPACE_2020_RGB_LIMITEDRANGE; + else + color_space = COLOR_SPACE_2020_RGB_FULLRANGE; + } else { color_space = COLOR_SPACE_2020_YCBCR_LIMITED; + } break; case DRM_MODE_COLORIMETRY_DEFAULT: /* ITU601 */ default: @@ -3937,17 +3941,15 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector, } /* Handle MCCS */ - if (do_mccs) + if (do_mccs) { dm_helpers_read_mccs_caps(adev->dm.dc->ctx, amdgpu_dm_connector->dc_link, sink); - if ((sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A || - as_type == FREESYNC_TYPE_PCON_IN_WHITELIST) && - (!sink->edid_caps.freesync_vcp_code || - (sink->edid_caps.freesync_vcp_code && !sink->mccs_caps.freesync_supported))) - freesync_capable = false; + if (sink->edid_caps.freesync_vcp_code && !sink->mccs_caps.freesync_supported) + freesync_capable = false; - if (do_mccs && sink->mccs_caps.freesync_supported && freesync_capable) - dm_helpers_mccs_vcp_set(adev->dm.dc->ctx, amdgpu_dm_connector->dc_link, sink); + if (sink->mccs_caps.freesync_supported && freesync_capable) + dm_helpers_mccs_vcp_set(adev->dm.dc->ctx, amdgpu_dm_connector->dc_link, sink); + } update: if (dm_con_state) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c index c4b2fc690fd7..2a6b48e24869 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c @@ -196,7 +196,6 @@ static ssize_t dp_link_settings_read(struct file *f, char __user *buf, char *rd_buf_ptr = NULL; const uint32_t rd_buf_size = 100; uint32_t result = 0; - uint8_t str_len = 0; int r; if (*pos & 3 || size & 3) @@ -208,29 +207,26 @@ static ssize_t dp_link_settings_read(struct file *f, char __user *buf, rd_buf_ptr = rd_buf; - str_len = strlen("Current: %d 0x%x %d "); - snprintf(rd_buf_ptr, str_len, "Current: %d 0x%x %d ", + rd_buf_ptr += scnprintf(rd_buf_ptr, rd_buf_size - (rd_buf_ptr - rd_buf), + "Current: %d 0x%x %d ", link->cur_link_settings.lane_count, link->cur_link_settings.link_rate, link->cur_link_settings.link_spread); - rd_buf_ptr += str_len; - str_len = strlen("Verified: %d 0x%x %d "); - snprintf(rd_buf_ptr, str_len, "Verified: %d 0x%x %d ", + rd_buf_ptr += scnprintf(rd_buf_ptr, rd_buf_size - (rd_buf_ptr - rd_buf), + "Verified: %d 0x%x %d ", link->verified_link_cap.lane_count, link->verified_link_cap.link_rate, link->verified_link_cap.link_spread); - rd_buf_ptr += str_len; - str_len = strlen("Reported: %d 0x%x %d "); - snprintf(rd_buf_ptr, str_len, "Reported: %d 0x%x %d ", + rd_buf_ptr += scnprintf(rd_buf_ptr, rd_buf_size - (rd_buf_ptr - rd_buf), + "Reported: %d 0x%x %d ", link->reported_link_cap.lane_count, link->reported_link_cap.link_rate, link->reported_link_cap.link_spread); - rd_buf_ptr += str_len; - str_len = strlen("Preferred: %d 0x%x %d "); - snprintf(rd_buf_ptr, str_len, "Preferred: %d 0x%x %d\n", + rd_buf_ptr += scnprintf(rd_buf_ptr, rd_buf_size - (rd_buf_ptr - rd_buf), + "Preferred: %d 0x%x %d\n", link->preferred_link_setting.lane_count, link->preferred_link_setting.link_rate, link->preferred_link_setting.link_spread); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c index d451082552e8..298de7b75ca8 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c @@ -200,6 +200,7 @@ enum dc_edid_status dm_helpers_parse_edid_caps( edid_caps->edid_hdmi = connector->display_info.is_hdmi; if (edid_caps->edid_hdmi) { + edid_caps->qs_bit = connector->display_info.rgb_quant_range_selectable; populate_hdmi_info_from_connector(link->dc->config.enable_frl, &connector->display_info.hdmi, edid_caps); drm_dbg_driver(connector->dev, "%s: HDMI_FRL [%s] max_frl_rate %d\n", __func__, connector->name, edid_caps->max_frl_rate); if (edid_caps->frl_dsc_support) @@ -1202,9 +1203,10 @@ void populate_hdmi_info_from_connector(bool enable_frl, struct drm_hdmi_info *hd edid_caps->max_frl_rate = get_max_frl_rate(hdmi->max_lanes, hdmi->max_frl_rate_per_lane); edid_caps->frl_dsc_support = hdmi->dsc_cap.v_1p2; if (edid_caps->frl_dsc_support) { - if (hdmi->dsc_cap.bpc_supported == 10) + /* HF-VSDB DSC max bpc is cumulative: >=12 implies 10 and 8. */ + if (hdmi->dsc_cap.bpc_supported >= 10) edid_caps->frl_dsc_10bpc = true; - else if (hdmi->dsc_cap.bpc_supported == 12) + if (hdmi->dsc_cap.bpc_supported >= 12) edid_caps->frl_dsc_12bpc = true; edid_caps->frl_dsc_all_bpp = hdmi->dsc_cap.all_bpp; edid_caps->frl_dsc_native_420 = hdmi->dsc_cap.native_420; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c index 0d2f9dbce0a9..212a7536e65b 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_connector_test.c @@ -568,6 +568,23 @@ static void dm_test_output_color_space_bt2020_rgb(struct kunit *test) } /** + * dm_test_output_color_space_bt2020_rgb_limited - Test limited BT.2020 RGB + * @test: The KUnit test context + */ +static void dm_test_output_color_space_bt2020_rgb_limited(struct kunit *test) +{ + struct dc_crtc_timing timing = {}; + struct drm_connector_state state = {}; + + timing.pixel_encoding = PIXEL_ENCODING_RGB; + state.colorspace = DRM_MODE_COLORIMETRY_BT2020_RGB; + state.hdmi.broadcast_rgb = DRM_HDMI_BROADCAST_RGB_LIMITED; + + KUNIT_EXPECT_EQ(test, (int)amdgpu_dm_get_output_color_space(&timing, &state), + (int)COLOR_SPACE_2020_RGB_LIMITEDRANGE); +} + +/** * dm_test_output_color_space_bt2020_ycc - Test Output color space bt2020 ycc * @test: The KUnit test context */ @@ -639,6 +656,24 @@ static void dm_test_output_color_space_bt2020_ycc_rgb_encoding(struct kunit *tes } /** + * dm_test_output_color_space_bt2020_ycc_rgb_encoding_limited - Test limited + * BT.2020 RGB output selected through the BT.2020 YCC connector colorspace + * @test: The KUnit test context + */ +static void dm_test_output_color_space_bt2020_ycc_rgb_encoding_limited(struct kunit *test) +{ + struct dc_crtc_timing timing = {}; + struct drm_connector_state state = {}; + + timing.pixel_encoding = PIXEL_ENCODING_RGB; + state.colorspace = DRM_MODE_COLORIMETRY_BT2020_YCC; + state.hdmi.broadcast_rgb = DRM_HDMI_BROADCAST_RGB_LIMITED; + + KUNIT_EXPECT_EQ(test, (int)amdgpu_dm_get_output_color_space(&timing, &state), + (int)COLOR_SPACE_2020_RGB_LIMITEDRANGE); +} + +/** * dm_test_output_color_space_bt2020_rgb_ycc_encoding - Test Output color space * bt2020 rgb with non-rgb pixel encoding falls back to limited ycbcr * @test: The KUnit test context @@ -5422,10 +5457,12 @@ static struct kunit_case amdgpu_dm_connector_tests[] = { KUNIT_CASE(dm_test_output_color_space_bt709_y_only), KUNIT_CASE(dm_test_output_color_space_oprgb), KUNIT_CASE(dm_test_output_color_space_bt2020_rgb), + KUNIT_CASE(dm_test_output_color_space_bt2020_rgb_limited), KUNIT_CASE(dm_test_output_color_space_bt2020_ycc), KUNIT_CASE(dm_test_output_color_space_default_ycbcr709_y_only), KUNIT_CASE(dm_test_output_color_space_default_ycbcr601), KUNIT_CASE(dm_test_output_color_space_bt2020_ycc_rgb_encoding), + KUNIT_CASE(dm_test_output_color_space_bt2020_ycc_rgb_encoding_limited), KUNIT_CASE(dm_test_output_color_space_bt2020_rgb_ycc_encoding), /* Tests for amdgpu_dm_convert_dc_color_depth_into_bpc */ KUNIT_CASE(dm_test_convert_color_depth_bpc_mappings), diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_helpers_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_helpers_test.c index 058e1ad15dfe..82e0c984693c 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_helpers_test.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_helpers_test.c @@ -358,12 +358,14 @@ static void dm_test_parse_edid_caps_hdmi_frl(struct kunit *test) /* Drive the HDMI/FRL branch */ connector->display_info.is_hdmi = true; + connector->display_info.rgb_quant_range_selectable = true; connector->display_info.hdmi.scdc.supported = true; connector->display_info.hdmi.max_lanes = 4; connector->display_info.hdmi.max_frl_rate_per_lane = 12; KUNIT_EXPECT_EQ(test, dm_helpers_parse_edid_caps(link, dc_edid, edid_caps), EDID_OK); KUNIT_EXPECT_TRUE(test, edid_caps->edid_hdmi); + KUNIT_EXPECT_EQ(test, edid_caps->qs_bit, 1); KUNIT_EXPECT_TRUE(test, edid_caps->scdc_present); /* max_lanes 4 + max_frl_rate_per_lane 12 -> rate index 6 */ KUNIT_EXPECT_EQ(test, edid_caps->max_frl_rate, 6); @@ -909,7 +911,7 @@ static void dm_test_populate_hdmi_frl_dsc_12bpc(struct kunit *test) KUNIT_EXPECT_EQ(test, caps->max_frl_rate, 2); KUNIT_EXPECT_TRUE(test, caps->frl_dsc_support); - KUNIT_EXPECT_FALSE(test, caps->frl_dsc_10bpc); + KUNIT_EXPECT_TRUE(test, caps->frl_dsc_10bpc); KUNIT_EXPECT_TRUE(test, caps->frl_dsc_12bpc); KUNIT_EXPECT_EQ(test, caps->frl_dsc_max_slices, 7); KUNIT_EXPECT_EQ(test, caps->frl_dsc_max_frl_rate, 1); diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index a98ed4617a03..519ac878ada1 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -3198,6 +3198,7 @@ static struct dc_update_descriptor check_update_surfaces_for_stream( } if ((stream_update->hdr_static_metadata && !stream_update->stream->use_dynamic_meta) || + stream_update->output_color_space || stream_update->vrr_infopacket || stream_update->vsc_infopacket || stream_update->vsp_infopacket || @@ -4188,6 +4189,7 @@ static void commit_planes_do_stream_update_sequence(struct dc *dc, hwss_add_setup_periodic_interrupt(&seq_state, dc, pipe_ctx); if ((stream_update->hdr_static_metadata && !stream->use_dynamic_meta) || + stream_update->output_color_space || stream_update->vrr_infopacket || stream_update->vsc_infopacket || stream_update->vsp_infopacket || @@ -4370,6 +4372,7 @@ static void commit_planes_do_stream_update(struct dc *dc, dc->hwss.setup_periodic_interrupt(dc, pipe_ctx); if ((stream_update->hdr_static_metadata && !stream->use_dynamic_meta) || + stream_update->output_color_space || stream_update->vrr_infopacket || stream_update->vsc_infopacket || stream_update->vsp_infopacket || diff --git a/drivers/gpu/drm/amd/pm/amdgpu_dpm.c b/drivers/gpu/drm/amd/pm/amdgpu_dpm.c index ce526db4d24a..808be6c425bf 100644 --- a/drivers/gpu/drm/amd/pm/amdgpu_dpm.c +++ b/drivers/gpu/drm/amd/pm/amdgpu_dpm.c @@ -348,7 +348,8 @@ int amdgpu_dpm_switch_power_profile(struct amdgpu_device *adev, const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; int ret = 0; - if (amdgpu_sriov_vf(adev)) + if (amdgpu_sriov_vf(adev) || + amdgpu_in_reset(adev)) return 0; if (pp_funcs && pp_funcs->switch_power_profile) { @@ -367,7 +368,8 @@ int amdgpu_dpm_pause_power_profile(struct amdgpu_device *adev, const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs; int ret = 0; - if (amdgpu_sriov_vf(adev)) + if (amdgpu_sriov_vf(adev) || + amdgpu_in_reset(adev)) return 0; if (pp_funcs && pp_funcs->pause_power_profile) { diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c index 6e741ec4a71e..a29e76b03476 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_0_ppt.c @@ -2092,11 +2092,11 @@ static ssize_t smu_v13_0_0_get_gpu_metrics(struct smu_context *smu, gpu_metrics->average_socket_power = metrics->AverageSocketPower; - if ((mp1_ver == IP_VERSION(13, 0, 0) && smu->smc_fw_version <= 0x004e1e00) || - (mp1_ver == IP_VERSION(13, 0, 10) && smu->smc_fw_version <= 0x00500800)) + if ((mp1_ver == IP_VERSION(13, 0, 0) && + (smu->smc_fw_version <= 0x004e1e00 || smu->smc_fw_version >= 0x004e8600)) || + (mp1_ver == IP_VERSION(13, 0, 10) && + smu->smc_fw_version <= 0x00500800)) gpu_metrics->energy_accumulator = metrics->EnergyAccumulator; - else - gpu_metrics->energy_accumulator = UINT_MAX; if (metrics->AverageGfxActivity <= SMU_13_0_0_BUSY_THRESHOLD) gpu_metrics->average_gfxclk_frequency = metrics->AverageGfxclkFrequencyPostDs; diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c index b94ae43586df..5fe409a23772 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_7_ppt.c @@ -2097,8 +2097,8 @@ static ssize_t smu_v13_0_7_get_gpu_metrics(struct smu_context *smu, metrics->Vcn1ActivityPercentage); gpu_metrics->average_socket_power = metrics->AverageSocketPower; - gpu_metrics->energy_accumulator = smu->smc_fw_version <= 0x00521400 ? - metrics->EnergyAccumulator : UINT_MAX; + if (smu->smc_fw_version <= 0x00521400) + gpu_metrics->energy_accumulator = metrics->EnergyAccumulator; if (metrics->AverageGfxActivity <= SMU_13_0_7_BUSY_THRESHOLD) gpu_metrics->average_gfxclk_frequency = metrics->AverageGfxclkFrequencyPostDs; diff --git a/drivers/gpu/drm/ast/ast_cursor.c b/drivers/gpu/drm/ast/ast_cursor.c index fd19c45f2abe..690d4cd1db5e 100644 --- a/drivers/gpu/drm/ast/ast_cursor.c +++ b/drivers/gpu/drm/ast/ast_cursor.c @@ -25,6 +25,7 @@ #include <linux/sizes.h> #include <drm/drm_atomic.h> +#include <drm/drm_blend.h> #include <drm/drm_damage_helper.h> #include <drm/drm_format_helper.h> #include <drm/drm_gem_atomic_helper.h> @@ -355,6 +356,8 @@ int ast_cursor_plane_init(struct ast_device *ast) } drm_plane_helper_add(cursor_plane, &ast_cursor_plane_helper_funcs); drm_plane_enable_fb_damage_clips(cursor_plane); + drm_plane_create_blend_mode_property(cursor_plane, + BIT(DRM_MODE_BLEND_COVERAGE)); return 0; } diff --git a/drivers/gpu/drm/bridge/tc358768.c b/drivers/gpu/drm/bridge/tc358768.c index d1fc6af37cc5..19b43efcf93f 100644 --- a/drivers/gpu/drm/bridge/tc358768.c +++ b/drivers/gpu/drm/bridge/tc358768.c @@ -1263,10 +1263,13 @@ tc358768_atomic_get_input_bus_fmts(struct drm_bridge *bridge, return input_fmts; } -static bool tc358768_mode_fixup(struct drm_bridge *bridge, - const struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) +static int tc358768_bridge_atomic_check(struct drm_bridge *bridge, + struct drm_bridge_state *bridge_state, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state) { + struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode; + /* Default to positive sync */ if (!(adjusted_mode->flags & @@ -1277,13 +1280,15 @@ static bool tc358768_mode_fixup(struct drm_bridge *bridge, (DRM_MODE_FLAG_PVSYNC | DRM_MODE_FLAG_NVSYNC))) adjusted_mode->flags |= DRM_MODE_FLAG_PVSYNC; - return true; + bridge_state->input_bus_cfg.flags = bridge->timings->input_bus_flags; + + return 0; } static const struct drm_bridge_funcs tc358768_bridge_funcs = { .attach = tc358768_bridge_attach, .mode_valid = tc358768_bridge_mode_valid, - .mode_fixup = tc358768_mode_fixup, + .atomic_check = tc358768_bridge_atomic_check, .atomic_pre_enable = tc358768_bridge_atomic_pre_enable, .atomic_enable = tc358768_bridge_atomic_enable, .atomic_disable = tc358768_bridge_atomic_disable, diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi83.c b/drivers/gpu/drm/bridge/ti-sn65dsi83.c index f9fdbf48c6b3..526826ba4524 100644 --- a/drivers/gpu/drm/bridge/ti-sn65dsi83.c +++ b/drivers/gpu/drm/bridge/ti-sn65dsi83.c @@ -403,7 +403,7 @@ retry: drm_modeset_drop_locks(&ctx); drm_modeset_acquire_fini(&ctx); - return 0; + return err; } static void sn65dsi83_reset_work(struct work_struct *ws) @@ -419,11 +419,13 @@ static void sn65dsi83_reset_work(struct work_struct *ws) ret = sn65dsi83_reset_pipe(ctx); if (ret) { dev_err(ctx->dev, "reset pipe failed %pe\n", ERR_PTR(ret)); - return; + goto bridge_exit; } + if (ctx->irq) enable_irq(ctx->irq); +bridge_exit: drm_bridge_exit(idx); } diff --git a/drivers/gpu/drm/drm_exec.c b/drivers/gpu/drm/drm_exec.c index 41034a5996ff..2453ec41360f 100644 --- a/drivers/gpu/drm/drm_exec.c +++ b/drivers/gpu/drm/drm_exec.c @@ -322,6 +322,19 @@ int drm_exec_prepare_array(struct drm_exec *exec, { int ret; + /* + * Make sure to lock a contended object even when no objects are + * given, otherwise drm_exec_retry_on_contention() would loop + * forever on patterns like: + * + * ret = drm_exec_prepare_array(exec, objs, num_objects, ...); + * drm_exec_retry_on_contention(exec); + * + * with num_objects == 0. + */ + if (!num_objects) + return drm_exec_lock_contended(exec); + for (unsigned int i = 0; i < num_objects; ++i) { ret = drm_exec_prepare_obj(exec, objects[i], num_fences); if (unlikely(ret)) diff --git a/drivers/gpu/drm/drm_panic_qr.rs b/drivers/gpu/drm/drm_panic_qr.rs index ac27e86c601c..4d7eb75a3afc 100644 --- a/drivers/gpu/drm/drm_panic_qr.rs +++ b/drivers/gpu/drm/drm_panic_qr.rs @@ -407,8 +407,8 @@ impl DecFifo { for i in (0..self.len).rev() { self.decimals[i + len] = self.decimals[i]; } - for i in 0..len { - self.decimals[i] = (chunk % 10) as u8; + for decimal in &mut self.decimals[..len] { + *decimal = (chunk % 10) as u8; chunk = div10(chunk); } self.len += len; diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index b7cc361fd955..43d53a98dae7 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -1946,6 +1946,8 @@ struct intel_dp { bool colorimetry_support; + bool sst_split_sdp_support; + struct { enum transcoder transcoder; struct mutex lock; diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 113d767e62e9..3152122e6aef 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -3409,12 +3409,22 @@ intel_dp_audio_compute_config(struct intel_encoder *encoder, struct intel_crtc_state *pipe_config, struct drm_connector_state *conn_state) { + struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + pipe_config->has_audio = intel_dp_has_audio(encoder, conn_state) && intel_audio_compute_config(encoder, pipe_config, conn_state); pipe_config->sdp_split_enable = pipe_config->has_audio && intel_dp_is_uhbr(pipe_config); + + /* + * SDP splitting for UHBR audio requires explicit sink capability in + * SST mode, whereas in MST mode it is inherently supported. + */ + if (pipe_config->sdp_split_enable && + !intel_crtc_has_type(pipe_config, INTEL_OUTPUT_DP_MST)) + pipe_config->sdp_split_enable = intel_dp->sst_split_sdp_support; } void @@ -4462,16 +4472,25 @@ void intel_dp_configure_protocol_converter(struct intel_dp *intel_dp, str_enable_disable(tmp)); } -static bool intel_dp_get_colorimetry_status(struct intel_dp *intel_dp) +static u8 intel_dp_read_dprx_feature_enum(struct intel_dp *intel_dp) { u8 dprx = 0; - if (drm_dp_dpcd_readb(&intel_dp->aux, DP_DPRX_FEATURE_ENUMERATION_LIST, - &dprx) != 1) - return false; + drm_dp_dpcd_read_data(&intel_dp->aux, DP_DPRX_FEATURE_ENUMERATION_LIST, + &dprx, sizeof(dprx)); + return dprx; +} + +static bool intel_dp_get_colorimetry_status(u8 dprx) +{ return dprx & DP_VSC_SDP_EXT_FOR_COLORIMETRY_SUPPORTED; } +static bool intel_dp_get_sst_split_sdp_status(u8 dprx) +{ + return dprx & DP_SST_SPLIT_SDP_CAP; +} + static int intel_dp_read_dsc_dpcd(struct drm_dp_aux *aux, u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE]) { @@ -4771,6 +4790,7 @@ intel_edp_init_dpcd(struct intel_dp *intel_dp, struct intel_connector *connector { struct intel_display *display = to_intel_display(intel_dp); int ret; + u8 dprx; /* this function is meant to be called only once */ drm_WARN_ON(display->drm, intel_dp->dpcd[DP_DPCD_REV] != 0); @@ -4782,8 +4802,13 @@ intel_edp_init_dpcd(struct intel_dp *intel_dp, struct intel_connector *connector drm_dp_is_branch(intel_dp->dpcd)); intel_init_dpcd_quirks(intel_dp, &intel_dp->desc.ident); + dprx = intel_dp_read_dprx_feature_enum(intel_dp); + intel_dp->colorimetry_support = - intel_dp_get_colorimetry_status(intel_dp); + intel_dp_get_colorimetry_status(dprx); + + intel_dp->sst_split_sdp_support = + intel_dp_get_sst_split_sdp_status(dprx); /* * Read the eDP display control registers. @@ -4874,13 +4899,20 @@ intel_dp_get_dpcd(struct intel_dp *intel_dp) * the OUI/ID since we know it won't change. */ if (!intel_dp_is_edp(intel_dp)) { + u8 dprx; + drm_dp_read_desc(&intel_dp->aux, &intel_dp->desc, drm_dp_is_branch(intel_dp->dpcd)); intel_init_dpcd_quirks(intel_dp, &intel_dp->desc.ident); + dprx = intel_dp_read_dprx_feature_enum(intel_dp); + intel_dp->colorimetry_support = - intel_dp_get_colorimetry_status(intel_dp); + intel_dp_get_colorimetry_status(dprx); + + intel_dp->sst_split_sdp_support = + intel_dp_get_sst_split_sdp_status(dprx); intel_dp_update_sink_caps(intel_dp); } diff --git a/drivers/gpu/drm/i915/i915_query.c b/drivers/gpu/drm/i915/i915_query.c index 0c55fb6e9727..11157fb14db3 100644 --- a/drivers/gpu/drm/i915/i915_query.c +++ b/drivers/gpu/drm/i915/i915_query.c @@ -403,8 +403,10 @@ static int query_perf_config_list(struct drm_i915_private *i915, ids = krealloc(oa_config_ids, n_configs * sizeof(*oa_config_ids), GFP_KERNEL); - if (!ids) + if (!ids) { + kfree(oa_config_ids); return -ENOMEM; + } alloc = fetch_and_zero(&n_configs); diff --git a/drivers/gpu/drm/logicvc/Kconfig b/drivers/gpu/drm/logicvc/Kconfig index 579a358ed5cf..11aae1626199 100644 --- a/drivers/gpu/drm/logicvc/Kconfig +++ b/drivers/gpu/drm/logicvc/Kconfig @@ -4,7 +4,6 @@ config DRM_LOGICVC depends on OF || COMPILE_TEST select DRM_CLIENT_SELECTION select DRM_KMS_HELPER - select DRM_KMS_DMA_HELPER select DRM_GEM_DMA_HELPER select REGMAP select REGMAP_MMIO diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c index 2fc41fb90aaa..0719fc6a52d5 100644 --- a/drivers/gpu/drm/qxl/qxl_display.c +++ b/drivers/gpu/drm/qxl/qxl_display.c @@ -30,6 +30,7 @@ #include <drm/drm_drv.h> #include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> +#include <drm/drm_blend.h> #include <drm/drm_edid.h> #include <drm/drm_encoder.h> #include <drm/drm_framebuffer.h> @@ -993,6 +994,9 @@ static struct drm_plane *qxl_create_plane(struct qxl_device *qdev, drm_plane_helper_add(plane, helper_funcs); + drm_plane_create_blend_mode_property(plane, + BIT(DRM_MODE_BLEND_PREMULTI)); + return plane; free_plane: diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig index e7f49fe845ea..4e58685f58ff 100644 --- a/drivers/gpu/drm/rockchip/Kconfig +++ b/drivers/gpu/drm/rockchip/Kconfig @@ -68,6 +68,7 @@ config ROCKCHIP_CDN_DP config ROCKCHIP_DW_DP bool "Rockchip specific extensions for Synopsys DW DP" + select DRM_BRIDGE_CONNECTOR help This selects support for Rockchip SoC specific extensions to enable Synopsys DesignWare Cores based DisplayPort transmit @@ -145,6 +146,8 @@ config ROCKCHIP_RGB config ROCKCHIP_RK3066_HDMI bool "Rockchip specific extensions for RK3066 HDMI" depends on DRM_ROCKCHIP + select DRM_DISPLAY_HELPER + select DRM_BRIDGE_CONNECTOR help This selects support for Rockchip SoC specific extensions for the RK3066 HDMI driver. If you want to enable diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c index 587e60232ec7..efd5a98e80bd 100644 --- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c +++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c @@ -241,10 +241,11 @@ static void rockchip_dp_drm_encoder_enable(struct drm_encoder *encoder, of_graph_get_remote_port(endpoint.local_node); of_property_read_u32(remote_port, "reg", &port_id); - sprintf(name, "%s vp%d", remote_port_parent->full_name, port_id); + snprintf(name, sizeof(name), "%s vp%d", + remote_port_parent->full_name, port_id); } else { - sprintf(name, "%s %s", - remote_port_parent->full_name, endpoint.id ? "vopl" : "vopb"); + snprintf(name, sizeof(name), "%s %s", + remote_port_parent->full_name, endpoint.id ? "vopl" : "vopb"); } DRM_DEV_DEBUG(dp->dev, "vop %s output to dp\n", (ret) ? "LIT" : "BIG"); diff --git a/drivers/gpu/drm/scheduler/tests/mock_scheduler.c b/drivers/gpu/drm/scheduler/tests/mock_scheduler.c index 8e9ae7d980eb..2dfa3efef210 100644 --- a/drivers/gpu/drm/scheduler/tests/mock_scheduler.c +++ b/drivers/gpu/drm/scheduler/tests/mock_scheduler.c @@ -1,6 +1,8 @@ // SPDX-License-Identifier: GPL-2.0 /* Copyright (c) 2025 Valve Corporation */ +#include <kunit/device.h> + #include "sched_tests.h" /* @@ -288,6 +290,7 @@ static const struct drm_sched_backend_ops drm_mock_scheduler_ops = { */ struct drm_mock_scheduler *drm_mock_sched_new(struct kunit *test, long timeout) { + static unsigned int instance; struct drm_sched_init_args args = { .ops = &drm_mock_scheduler_ops, .num_rqs = DRM_SCHED_PRIORITY_COUNT, @@ -297,11 +300,19 @@ struct drm_mock_scheduler *drm_mock_sched_new(struct kunit *test, long timeout) .name = "drm-mock-scheduler", }; struct drm_mock_scheduler *sched; + struct device *dev; + char name[64]; int ret; sched = kunit_kzalloc(test, sizeof(*sched), GFP_KERNEL); KUNIT_ASSERT_NOT_NULL(test, sched); + snprintf(name, sizeof(name), "%s-%u", args.name, instance++); + dev = kunit_device_register(test, name); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev); + + args.dev = dev; + ret = drm_sched_init(&sched->base, &args); KUNIT_ASSERT_EQ(test, ret, 0); diff --git a/drivers/gpu/drm/vboxvideo/vbox_mode.c b/drivers/gpu/drm/vboxvideo/vbox_mode.c index 8e4e5fc9d3c5..3c41238a8268 100644 --- a/drivers/gpu/drm/vboxvideo/vbox_mode.c +++ b/drivers/gpu/drm/vboxvideo/vbox_mode.c @@ -15,6 +15,7 @@ #include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> +#include <drm/drm_blend.h> #include <drm/drm_edid.h> #include <drm/drm_fb_helper.h> #include <drm/drm_fourcc.h> @@ -540,6 +541,9 @@ static struct drm_plane *vbox_create_plane(struct vbox_private *vbox, drm_plane_helper_add(plane, helper_funcs); + drm_plane_create_blend_mode_property(plane, + BIT(DRM_MODE_BLEND_COVERAGE)); + return plane; free_plane: diff --git a/drivers/gpu/drm/virtio/virtgpu_plane.c b/drivers/gpu/drm/virtio/virtgpu_plane.c index 1d1b27ece62a..640815af4098 100644 --- a/drivers/gpu/drm/virtio/virtgpu_plane.c +++ b/drivers/gpu/drm/virtio/virtgpu_plane.c @@ -24,6 +24,7 @@ */ #include <drm/drm_atomic_helper.h> +#include <drm/drm_blend.h> #include <drm/drm_damage_helper.h> #include <drm/drm_fourcc.h> #include <drm/drm_gem_atomic_helper.h> @@ -609,6 +610,9 @@ struct drm_plane *virtio_gpu_plane_init(struct virtio_gpu_device *vgdev, if (type == DRM_PLANE_TYPE_PRIMARY) drm_plane_enable_fb_damage_clips(plane); + else if (type == DRM_PLANE_TYPE_CURSOR) + drm_plane_create_blend_mode_property(plane, + BIT(DRM_MODE_BLEND_PREMULTI)); return plane; } diff --git a/drivers/gpu/drm/xe/instructions/xe_gpu_commands.h b/drivers/gpu/drm/xe/instructions/xe_gpu_commands.h index 18d0fde8c98f..faf8d7e2c5c1 100644 --- a/drivers/gpu/drm/xe/instructions/xe_gpu_commands.h +++ b/drivers/gpu/drm/xe/instructions/xe_gpu_commands.h @@ -46,6 +46,7 @@ #define GFX_OP_PIPE_CONTROL(len) ((0x3<<29)|(0x3<<27)|(0x2<<24)|((len)-2)) #define PIPE_CONTROL0_QUEUE_DRAIN_MODE BIT(12) +#define PIPE_CONTROL0_UNTYPED_DATAPORT_CACHE_FLUSH BIT(11) /* gen12 */ #define PIPE_CONTROL0_L3_READ_ONLY_CACHE_INVALIDATE BIT(10) /* gen12 */ #define PIPE_CONTROL0_HDC_PIPELINE_FLUSH BIT(9) /* gen12 */ diff --git a/drivers/gpu/drm/xe/xe_pagefault.c b/drivers/gpu/drm/xe/xe_pagefault.c index dbf8f71d3328..a4986df8328d 100644 --- a/drivers/gpu/drm/xe/xe_pagefault.c +++ b/drivers/gpu/drm/xe/xe_pagefault.c @@ -16,6 +16,7 @@ #include "xe_hw_engine.h" #include "xe_pagefault.h" #include "xe_pagefault_types.h" +#include "xe_pm.h" #include "xe_svm.h" #include "xe_trace_bo.h" #include "xe_vm.h" @@ -292,9 +293,17 @@ static void xe_pagefault_queue_work(struct work_struct *w) { struct xe_pagefault_queue *pf_queue = container_of(w, typeof(*pf_queue), worker); + struct xe_device *xe = pf_queue->xe; struct xe_pagefault pf; unsigned long threshold; + /* + * A live VM holds a PM reference, but a torn-down VM does not. + * Guard the entire worker loop to safely drain stale faults and + * prevent autosuspends from desyncing batched CT flushes. + */ + guard(xe_pm_runtime)(xe); + #define USM_QUEUE_MAX_RUNTIME_MS 20 threshold = jiffies + msecs_to_jiffies(USM_QUEUE_MAX_RUNTIME_MS); @@ -365,6 +374,7 @@ static int xe_pagefault_queue_init(struct xe_device *xe, drm_dbg(&xe->drm, "xe_pagefault_entry_size=%d, total_num_eus=%d, pf_queue->size=%u", xe_pagefault_entry_size(), total_num_eus, pf_queue->size); + pf_queue->xe = xe; spin_lock_init(&pf_queue->lock); INIT_WORK(&pf_queue->worker, xe_pagefault_queue_work); diff --git a/drivers/gpu/drm/xe/xe_pagefault_types.h b/drivers/gpu/drm/xe/xe_pagefault_types.h index c4ee625b93dd..f63a12aa0d4f 100644 --- a/drivers/gpu/drm/xe/xe_pagefault_types.h +++ b/drivers/gpu/drm/xe/xe_pagefault_types.h @@ -8,6 +8,7 @@ #include <linux/workqueue.h> +struct xe_device; struct xe_gt; struct xe_pagefault; @@ -118,6 +119,8 @@ struct xe_pagefault { * queue to absorb the device’s worst-case number of outstanding faults. */ struct xe_pagefault_queue { + /** @xe: Back-pointer to the Xe device */ + struct xe_device *xe; /** * @data: Data in queue containing struct xe_pagefault, protected by * @lock diff --git a/drivers/gpu/drm/xe/xe_ring_ops.c b/drivers/gpu/drm/xe/xe_ring_ops.c index 39a670e91ba7..08b4a4283e96 100644 --- a/drivers/gpu/drm/xe/xe_ring_ops.c +++ b/drivers/gpu/drm/xe/xe_ring_ops.c @@ -212,6 +212,7 @@ static int emit_render_cache_flush(struct xe_sched_job *job, u32 *dw, int i) { struct xe_exec_queue *q = job->q; struct xe_gt *gt = q->gt; + struct xe_device *xe = gt_to_xe(gt); bool lacks_render = !(gt->info.engine_mask & XE_HW_ENGINE_RCS_MASK); u32 flags0, flags1; @@ -220,6 +221,16 @@ static int emit_render_cache_flush(struct xe_sched_job *job, u32 *dw, int i) LRC_PPHWSP_FLUSH_INVAL_SCRATCH_ADDR, 0); flags0 = PIPE_CONTROL0_HDC_PIPELINE_FLUSH; + /* + * Prior to MTL, HDC Pipeline Flush reliably also flushes the LSC + * untyped L1 dataport cache, provided HDC_CHICKEN0 is programmed + * correctly. Starting with MTL that coupling no longer holds + * regardless of how HDC_CHICKEN0 is programmed, but explicitly + * requesting the flush via PIPE_CONTROL is itself only reliable + * from Xe2 onward, so only gate it in on Xe2+. + */ + if (GRAPHICS_VERx100(xe) >= 2000) + flags0 |= PIPE_CONTROL0_UNTYPED_DATAPORT_CACHE_FLUSH; flags1 = (PIPE_CONTROL_TILE_CACHE_FLUSH | PIPE_CONTROL_RENDER_TARGET_CACHE_FLUSH | PIPE_CONTROL_DEPTH_CACHE_FLUSH | diff --git a/drivers/hwmon/applesmc.c b/drivers/hwmon/applesmc.c index 00e603b5e401..d0baa10502f7 100644 --- a/drivers/hwmon/applesmc.c +++ b/drivers/hwmon/applesmc.c @@ -1128,12 +1128,17 @@ static void applesmc_release_light_sensor(void) static int applesmc_create_key_backlight(void) { + int ret; + if (!smcreg.has_key_backlight) return 0; applesmc_led_wq = create_singlethread_workqueue("applesmc-led"); if (!applesmc_led_wq) return -ENOMEM; - return led_classdev_register(&pdev->dev, &applesmc_backlight); + ret = led_classdev_register(&pdev->dev, &applesmc_backlight); + if (ret) + destroy_workqueue(applesmc_led_wq); + return ret; } static void applesmc_release_key_backlight(void) diff --git a/drivers/hwmon/aspeed-pwm-tacho.c b/drivers/hwmon/aspeed-pwm-tacho.c index 1c5945d4ba37..bfce589c3fb1 100644 --- a/drivers/hwmon/aspeed-pwm-tacho.c +++ b/drivers/hwmon/aspeed-pwm-tacho.c @@ -934,7 +934,9 @@ static int aspeed_pwm_tacho_probe(struct platform_device *pdev) "missing or invalid reset controller device tree entry"); return PTR_ERR(priv->rst); } - reset_control_deassert(priv->rst); + ret = reset_control_deassert(priv->rst); + if (ret) + return ret; ret = devm_add_action_or_reset(dev, aspeed_pwm_tacho_remove, priv); if (ret) diff --git a/drivers/hwmon/asus_rog_ryujin.c b/drivers/hwmon/asus_rog_ryujin.c index 702edb831394..e297557ca346 100644 --- a/drivers/hwmon/asus_rog_ryujin.c +++ b/drivers/hwmon/asus_rog_ryujin.c @@ -184,6 +184,7 @@ static int rog_ryujin_write_expanded(struct rog_ryujin_data *priv, const u8 *cmd static int rog_ryujin_execute_cmd(struct rog_ryujin_data *priv, const u8 *cmd, int cmd_length, struct completion *status_completion) { + unsigned long flags; int ret; /* @@ -191,9 +192,9 @@ static int rog_ryujin_execute_cmd(struct rog_ryujin_data *priv, const u8 *cmd, i * completion. Reinit is done because hidraw could have triggered * the raw event parsing and marked the passed in completion as done. */ - spin_lock_bh(&priv->status_report_request_lock); + spin_lock_irqsave(&priv->status_report_request_lock, flags); reinit_completion(status_completion); - spin_unlock_bh(&priv->status_report_request_lock); + spin_unlock_irqrestore(&priv->status_report_request_lock, flags); /* Send command for getting data */ ret = rog_ryujin_write_expanded(priv, cmd, cmd_length); @@ -421,11 +422,19 @@ static int rog_ryujin_raw_event(struct hid_device *hdev, struct hid_report *repo int size) { struct rog_ryujin_data *priv = hid_get_drvdata(hdev); + unsigned long flags; - if (data[0] != RYUJIN_CMD_PREFIX) + if (size < 2 || data[0] != RYUJIN_CMD_PREFIX) return 0; + spin_lock_irqsave(&priv->status_report_request_lock, flags); + if (data[1] == RYUJIN_GET_COOLER_STATUS_CMD_RESPONSE) { + if (size <= priv->info->temp_offset + 1 || + size <= priv->info->pump_speed_offset + 1 || + size <= priv->info->fan_speed_offset + 1) + goto unlock; + /* Received coolant temp and speeds of pump and internal fan */ priv->temp_input[0] = data[priv->info->temp_offset] * 1000 + data[priv->info->temp_offset + 1] * 100; @@ -437,6 +446,9 @@ static int rog_ryujin_raw_event(struct hid_device *hdev, struct hid_report *repo if (!completion_done(&priv->cooler_status_received)) complete_all(&priv->cooler_status_received); } else if (data[1] == RYUJIN_GET_CONTROLLER_SPEED_CMD_RESPONSE) { + if (size <= RYUJIN_CONTROLLER_SPEED_3 + 1) + goto unlock; + /* Received speeds of four fans attached to the controller */ priv->speed_input[2] = get_unaligned_le16(data + RYUJIN_CONTROLLER_SPEED_1); priv->speed_input[3] = get_unaligned_le16(data + RYUJIN_CONTROLLER_SPEED_2); @@ -446,6 +458,9 @@ static int rog_ryujin_raw_event(struct hid_device *hdev, struct hid_report *repo if (!completion_done(&priv->controller_status_received)) complete_all(&priv->controller_status_received); } else if (data[1] == RYUJIN_GET_COOLER_DUTY_CMD_RESPONSE) { + if (size <= RYUJIN_INTERNAL_FAN_DUTY) + goto unlock; + /* Received report for pump and internal fan duties (in %) */ if (data[RYUJIN_PUMP_DUTY] == 0 && data[RYUJIN_INTERNAL_FAN_DUTY] == 0) { /* @@ -463,7 +478,7 @@ static int rog_ryujin_raw_event(struct hid_device *hdev, struct hid_report *repo * We're expecting a report, so parse it. */ goto read_cooler_duty; - return 0; + goto unlock; } read_cooler_duty: priv->duty_input[0] = rog_ryujin_percent_to_pwm(data[RYUJIN_PUMP_DUTY]); @@ -472,6 +487,9 @@ read_cooler_duty: if (!completion_done(&priv->cooler_duty_received)) complete_all(&priv->cooler_duty_received); } else if (data[1] == RYUJIN_GET_CONTROLLER_DUTY_CMD_RESPONSE) { + if (size <= RYUJIN_CONTROLLER_DUTY) + goto unlock; + /* Received report for controller duty for fans (in PWM) */ if (data[RYUJIN_CONTROLLER_DUTY] == 0) { /* @@ -489,7 +507,7 @@ read_cooler_duty: * We're expecting a report, so parse it. */ goto read_controller_duty; - return 0; + goto unlock; } read_controller_duty: priv->duty_input[2] = data[RYUJIN_CONTROLLER_DUTY]; @@ -498,6 +516,8 @@ read_controller_duty: complete_all(&priv->controller_duty_received); } +unlock: + spin_unlock_irqrestore(&priv->status_report_request_lock, flags); return 0; } diff --git a/drivers/hwmon/chipcap2.c b/drivers/hwmon/chipcap2.c index 086571d556b7..9bef767b589e 100644 --- a/drivers/hwmon/chipcap2.c +++ b/drivers/hwmon/chipcap2.c @@ -92,11 +92,6 @@ struct cc2_data { bool process_irqs; }; -enum cc2_chan_addr { - CC2_CHAN_TEMP = 0, - CC2_CHAN_HUMIDITY, -}; - /* %RH as a per cent mille from a register value */ static long cc2_rh_convert(u16 data) { @@ -499,7 +494,7 @@ static irqreturn_t cc2_low_interrupt(int irq, void *data) if (cc2->process_irqs) { hwmon_notify_event(cc2->hwmon, hwmon_humidity, - hwmon_humidity_min_alarm, CC2_CHAN_HUMIDITY); + hwmon_humidity_min_alarm, 0); cc2->rh_alarm.low_alarm = true; } @@ -512,7 +507,7 @@ static irqreturn_t cc2_high_interrupt(int irq, void *data) if (cc2->process_irqs) { hwmon_notify_event(cc2->hwmon, hwmon_humidity, - hwmon_humidity_max_alarm, CC2_CHAN_HUMIDITY); + hwmon_humidity_max_alarm, 0); cc2->rh_alarm.high_alarm = true; } diff --git a/drivers/hwmon/corsair-cpro.c b/drivers/hwmon/corsair-cpro.c index 8354a002f4c5..c09645152613 100644 --- a/drivers/hwmon/corsair-cpro.c +++ b/drivers/hwmon/corsair-cpro.c @@ -566,21 +566,18 @@ static int bootloader_show(struct seq_file *seqf, void *unused) } DEFINE_SHOW_ATTRIBUTE(bootloader); -static void ccp_debugfs_init(struct ccp_device *ccp) +static void ccp_debugfs_init(struct ccp_device *ccp, bool fw_valid, bool bl_valid) { char name[32]; - int ret; scnprintf(name, sizeof(name), "corsaircpro-%s", dev_name(&ccp->hdev->dev)); ccp->debugfs = debugfs_create_dir(name, NULL); - ret = get_fw_version(ccp); - if (!ret) + if (fw_valid) debugfs_create_file("firmware_version", 0444, ccp->debugfs, ccp, &firmware_fops); - ret = get_bl_version(ccp); - if (!ret) + if (bl_valid) debugfs_create_file("bootloader_version", 0444, ccp->debugfs, ccp, &bootloader_fops); } @@ -588,6 +585,7 @@ static void ccp_debugfs_init(struct ccp_device *ccp) static int ccp_probe(struct hid_device *hdev, const struct hid_device_id *id) { struct ccp_device *ccp; + bool fw_valid, bl_valid; int ret; ccp = devm_kzalloc(&hdev->dev, sizeof(*ccp), GFP_KERNEL); @@ -632,17 +630,27 @@ static int ccp_probe(struct hid_device *hdev, const struct hid_device_id *id) if (ret) goto out_hw_close; - ccp_debugfs_init(ccp); + /* + * Query the versions before registering the hwmon device: they send + * USB commands without holding ccp->mutex, which is only safe while + * nothing else can call send_usb_cmd(). + */ + fw_valid = !get_fw_version(ccp); + bl_valid = !get_bl_version(ccp); ccp->hwmon_dev = hwmon_device_register_with_info(&hdev->dev, "corsaircpro", ccp, &ccp_chip_info, NULL); if (IS_ERR(ccp->hwmon_dev)) { ret = PTR_ERR(ccp->hwmon_dev); - goto out_hw_close; + goto out_debugfs_remove; } + ccp_debugfs_init(ccp, fw_valid, bl_valid); + return 0; +out_debugfs_remove: + debugfs_remove_recursive(ccp->debugfs); out_hw_close: hid_hw_close(hdev); hid_device_io_stop(hdev); diff --git a/drivers/hwmon/gpio-fan.c b/drivers/hwmon/gpio-fan.c index 084828e1e281..df8bd9707605 100644 --- a/drivers/hwmon/gpio-fan.c +++ b/drivers/hwmon/gpio-fan.c @@ -12,6 +12,7 @@ #include <linux/slab.h> #include <linux/interrupt.h> #include <linux/irq.h> +#include <linux/devm-helpers.h> #include <linux/platform_device.h> #include <linux/err.h> #include <linux/kstrtox.h> @@ -84,6 +85,7 @@ static DEVICE_ATTR_RO(fan1_alarm); static int fan_alarm_init(struct gpio_fan_data *fan_data) { int alarm_irq; + int err; struct device *dev = fan_data->dev; /* @@ -94,7 +96,11 @@ static int fan_alarm_init(struct gpio_fan_data *fan_data) if (alarm_irq <= 0) return 0; - INIT_WORK(&fan_data->alarm_work, fan_alarm_notify); + err = devm_work_autocancel(dev, &fan_data->alarm_work, + fan_alarm_notify); + if (err) + return err; + irq_set_irq_type(alarm_irq, IRQ_TYPE_EDGE_BOTH); return devm_request_irq(dev, alarm_irq, fan_alarm_irq_handler, IRQF_SHARED, "GPIO fan alarm", fan_data); @@ -606,8 +612,11 @@ static void gpio_fan_shutdown(struct platform_device *pdev) { struct gpio_fan_data *fan_data = platform_get_drvdata(pdev); - if (fan_data->gpios) + if (fan_data->gpios) { + mutex_lock(&fan_data->lock); set_fan_speed(fan_data, 0); + mutex_unlock(&fan_data->lock); + } } static int gpio_fan_runtime_suspend(struct device *dev) diff --git a/drivers/hwmon/hwmon.c b/drivers/hwmon/hwmon.c index 41755910a25a..10d2df3efdfa 100644 --- a/drivers/hwmon/hwmon.c +++ b/drivers/hwmon/hwmon.c @@ -318,6 +318,11 @@ static int hwmon_attr_base(enum hwmon_sensor_types type) return 1; } +static bool is_hwmon_device(struct device *dev) +{ + return dev->class == &hwmon_class; +} + #if IS_REACHABLE(CONFIG_I2C) /* @@ -338,7 +343,7 @@ static int hwmon_attr_base(enum hwmon_sensor_types type) static int hwmon_match_device(struct device *dev, const void *data) { - return dev->class == &hwmon_class; + return is_hwmon_device(dev); } static ssize_t pec_show(struct device *dev, const struct device_attribute *dummy, @@ -371,18 +376,17 @@ static ssize_t pec_store(struct device *dev, const struct device_attribute *deva * handling is not required. */ hwdev = to_hwmon_device(hdev); - guard(mutex)(&hwdev->lock); - if (hwdev->chip->ops->write) { - err = hwdev->chip->ops->write(hdev, hwmon_chip, hwmon_chip_pec, 0, val); - if (err && err != -EOPNOTSUPP) - goto put; + scoped_guard(mutex, &hwdev->lock) { + if (hwdev->chip->ops->write) { + err = hwdev->chip->ops->write(hdev, hwmon_chip, hwmon_chip_pec, 0, val); + if (err && err != -EOPNOTSUPP) + goto put; + } + if (!val) + client->flags &= ~I2C_CLIENT_PEC; + else + client->flags |= I2C_CLIENT_PEC; } - - if (!val) - client->flags &= ~I2C_CLIENT_PEC; - else - client->flags |= I2C_CLIENT_PEC; - err = count; put: put_device(hdev); @@ -782,6 +786,9 @@ int hwmon_notify_event(struct device *dev, enum hwmon_sensor_types type, const char *template; int base; + if (WARN(!is_hwmon_device(dev), "%s is not a hardware monitoring device\n", + dev_name(dev))) + return -EINVAL; if (type >= ARRAY_SIZE(__templates)) return -EINVAL; if (attr >= __templates_size[type]) diff --git a/drivers/hwmon/ina2xx.c b/drivers/hwmon/ina2xx.c index 5c6dc2c370d8..19b35f3bf3a3 100644 --- a/drivers/hwmon/ina2xx.c +++ b/drivers/hwmon/ina2xx.c @@ -8,6 +8,7 @@ */ #include <linux/bitfield.h> +#include <linux/bitops.h> #include <linux/bits.h> #include <linux/delay.h> #include <linux/device.h> @@ -129,6 +130,17 @@ enum ina2xx_ids { sy24655 }; +enum ina2xx_alert_type { + INA2XX_ALERT_NONE, + INA2XX_ALERT_CURRENT_LOW, + INA2XX_ALERT_CURRENT_HIGH, + INA2XX_ALERT_POWER_HIGH, + INA2XX_ALERT_BUS_VOLTAGE_LOW, + INA2XX_ALERT_BUS_VOLTAGE_HIGH, + INA2XX_ALERT_SHUNT_VOLTAGE_LOW, + INA2XX_ALERT_SHUNT_VOLTAGE_HIGH, +}; + struct ina2xx_config { u16 config_default; bool has_alerts; /* chip supports alerts and limits */ @@ -148,6 +160,7 @@ struct ina2xx_data { const struct ina2xx_config *config; enum ina2xx_ids chip; + enum ina2xx_alert_type active_alert; long rshunt; long current_lsb_uA; long power_lsb_uW; @@ -428,16 +441,78 @@ static u16 ina226_alert_to_reg(struct ina2xx_data *data, int reg, long val) } } -static int ina226_alert_limit_read(struct ina2xx_data *data, u32 mask, int reg, long *val) +static u32 ina2xx_alert_type_to_mask(enum ina2xx_alert_type alert) +{ + switch (alert) { + case INA2XX_ALERT_CURRENT_LOW: + case INA2XX_ALERT_SHUNT_VOLTAGE_LOW: + return INA226_SHUNT_UNDER_VOLTAGE_MASK; + case INA2XX_ALERT_CURRENT_HIGH: + case INA2XX_ALERT_SHUNT_VOLTAGE_HIGH: + return INA226_SHUNT_OVER_VOLTAGE_MASK; + case INA2XX_ALERT_BUS_VOLTAGE_LOW: + return INA226_BUS_UNDER_VOLTAGE_MASK; + case INA2XX_ALERT_BUS_VOLTAGE_HIGH: + return INA226_BUS_OVER_VOLTAGE_MASK; + case INA2XX_ALERT_POWER_HIGH: + return INA226_POWER_OVER_LIMIT_MASK; + case INA2XX_ALERT_NONE: + return 0; + default: + /* programmer error */ + WARN_ON_ONCE(1); + return 0; + } +} + +static enum ina2xx_alert_type ina2xx_mask_to_alert_type(u32 mask) +{ + int top_bit = fls(mask & INA226_ALERT_CONFIG_MASK); + + if (!top_bit) + return INA2XX_ALERT_NONE; + + /* + * Multiple bits may be set, with the highest-set function taking + * precedence according to the datasheet. Shunt voltage masks are + * assumed to map to voltage monitoring rather than current monitoring, + * since the latter isn't directly implemented in the hardware. + */ + switch (BIT(top_bit - 1)) { + case INA226_SHUNT_OVER_VOLTAGE_MASK: + return INA2XX_ALERT_SHUNT_VOLTAGE_HIGH; + case INA226_SHUNT_UNDER_VOLTAGE_MASK: + return INA2XX_ALERT_SHUNT_VOLTAGE_LOW; + case INA226_BUS_OVER_VOLTAGE_MASK: + return INA2XX_ALERT_BUS_VOLTAGE_HIGH; + case INA226_BUS_UNDER_VOLTAGE_MASK: + return INA2XX_ALERT_BUS_VOLTAGE_LOW; + case INA226_POWER_OVER_LIMIT_MASK: + return INA2XX_ALERT_POWER_HIGH; + default: + return INA2XX_ALERT_NONE; + } +} + +static int ina226_alert_limit_read(struct ina2xx_data *data, enum ina2xx_alert_type alert, + int reg, long *val) { struct regmap *regmap = data->regmap; int regval; + u32 mask; int ret; + /* Avoid nonzero reads from inactive alerts caused by shared limit register */ + if (data->active_alert != alert) { + *val = 0; + return 0; + } + ret = regmap_read(regmap, INA226_MASK_ENABLE, ®val); if (ret) return ret; + mask = ina2xx_alert_type_to_mask(alert); if (regval & mask) { ret = regmap_read(regmap, INA226_ALERT_LIMIT, ®val); if (ret) @@ -449,9 +524,11 @@ static int ina226_alert_limit_read(struct ina2xx_data *data, u32 mask, int reg, return 0; } -static int ina226_alert_limit_write(struct ina2xx_data *data, u32 mask, int reg, long val) +static int ina226_alert_limit_write(struct ina2xx_data *data, enum ina2xx_alert_type alert, + int reg, long val) { struct regmap *regmap = data->regmap; + u32 mask; int ret; if (val < 0) @@ -466,15 +543,22 @@ static int ina226_alert_limit_write(struct ina2xx_data *data, u32 mask, int reg, INA226_ALERT_CONFIG_MASK, 0); if (ret < 0) return ret; + data->active_alert = INA2XX_ALERT_NONE; ret = regmap_write(regmap, INA226_ALERT_LIMIT, ina226_alert_to_reg(data, reg, val)); if (ret < 0) return ret; - if (val) - return regmap_update_bits(regmap, INA226_MASK_ENABLE, - INA226_ALERT_CONFIG_MASK, mask); + if (val) { + mask = ina2xx_alert_type_to_mask(alert); + ret = regmap_update_bits(regmap, INA226_MASK_ENABLE, + INA226_ALERT_CONFIG_MASK, mask); + if (ret < 0) + return ret; + data->active_alert = alert; + } + return 0; } @@ -498,15 +582,26 @@ static int ina2xx_chip_read(struct device *dev, u32 attr, long *val) return 0; } -static int ina226_alert_read(struct regmap *regmap, u32 mask, long *val) +static int ina226_alert_read(struct ina2xx_data *data, enum ina2xx_alert_type alert, long *val) { unsigned int regval; + u32 mask; int ret; - ret = regmap_read_bypassed(regmap, INA226_MASK_ENABLE, ®val); + /* + * With alert latching, reading alerts from hardware also clears the + * alert, so return early if the alert is inactive. + */ + if (data->active_alert != alert) { + *val = 0; + return 0; + } + + ret = regmap_read_bypassed(data->regmap, INA226_MASK_ENABLE, ®val); if (ret) return ret; + mask = ina2xx_alert_type_to_mask(alert); *val = (regval & mask) && (regval & INA226_ALERT_FUNCTION_FLAG); return 0; @@ -515,10 +610,10 @@ static int ina226_alert_read(struct regmap *regmap, u32 mask, long *val) static int ina2xx_in_read(struct device *dev, u32 attr, int channel, long *val) { int voltage_reg = channel ? INA2XX_BUS_VOLTAGE : INA2XX_SHUNT_VOLTAGE; - u32 under_voltage_mask = channel ? INA226_BUS_UNDER_VOLTAGE_MASK - : INA226_SHUNT_UNDER_VOLTAGE_MASK; - u32 over_voltage_mask = channel ? INA226_BUS_OVER_VOLTAGE_MASK - : INA226_SHUNT_OVER_VOLTAGE_MASK; + enum ina2xx_alert_type under_voltage_alert = channel ? INA2XX_ALERT_BUS_VOLTAGE_LOW + : INA2XX_ALERT_SHUNT_VOLTAGE_LOW; + enum ina2xx_alert_type over_voltage_alert = channel ? INA2XX_ALERT_BUS_VOLTAGE_HIGH + : INA2XX_ALERT_SHUNT_VOLTAGE_HIGH; struct ina2xx_data *data = dev_get_drvdata(dev); struct regmap *regmap = data->regmap; unsigned int regval; @@ -532,15 +627,15 @@ static int ina2xx_in_read(struct device *dev, u32 attr, int channel, long *val) *val = ina2xx_get_value(data, voltage_reg, regval); break; case hwmon_in_lcrit: - return ina226_alert_limit_read(data, under_voltage_mask, + return ina226_alert_limit_read(data, under_voltage_alert, voltage_reg, val); case hwmon_in_crit: - return ina226_alert_limit_read(data, over_voltage_mask, + return ina226_alert_limit_read(data, over_voltage_alert, voltage_reg, val); case hwmon_in_lcrit_alarm: - return ina226_alert_read(regmap, under_voltage_mask, val); + return ina226_alert_read(data, under_voltage_alert, val); case hwmon_in_crit_alarm: - return ina226_alert_read(regmap, over_voltage_mask, val); + return ina226_alert_read(data, over_voltage_alert, val); default: return -EOPNOTSUPP; } @@ -594,10 +689,10 @@ static int ina2xx_power_read(struct device *dev, u32 attr, long *val) case hwmon_power_average: return sy24655_average_power_read(data, SY24655_EIN, val); case hwmon_power_crit: - return ina226_alert_limit_read(data, INA226_POWER_OVER_LIMIT_MASK, + return ina226_alert_limit_read(data, INA2XX_ALERT_POWER_HIGH, INA2XX_POWER, val); case hwmon_power_crit_alarm: - return ina226_alert_read(data->regmap, INA226_POWER_OVER_LIMIT_MASK, val); + return ina226_alert_read(data, INA2XX_ALERT_POWER_HIGH, val); default: return -EOPNOTSUPP; } @@ -633,15 +728,15 @@ static int ina2xx_curr_read(struct device *dev, u32 attr, long *val) *val = ina2xx_get_value(data, INA2XX_CURRENT, regval); return 0; case hwmon_curr_lcrit: - return ina226_alert_limit_read(data, INA226_SHUNT_UNDER_VOLTAGE_MASK, + return ina226_alert_limit_read(data, INA2XX_ALERT_CURRENT_LOW, INA2XX_CURRENT, val); case hwmon_curr_crit: - return ina226_alert_limit_read(data, INA226_SHUNT_OVER_VOLTAGE_MASK, + return ina226_alert_limit_read(data, INA2XX_ALERT_CURRENT_HIGH, INA2XX_CURRENT, val); case hwmon_curr_lcrit_alarm: - return ina226_alert_read(regmap, INA226_SHUNT_UNDER_VOLTAGE_MASK, val); + return ina226_alert_read(data, INA2XX_ALERT_CURRENT_LOW, val); case hwmon_curr_crit_alarm: - return ina226_alert_read(regmap, INA226_SHUNT_OVER_VOLTAGE_MASK, val); + return ina226_alert_read(data, INA2XX_ALERT_CURRENT_HIGH, val); default: return -EOPNOTSUPP; } @@ -685,12 +780,12 @@ static int ina2xx_in_write(struct device *dev, u32 attr, int channel, long val) switch (attr) { case hwmon_in_lcrit: return ina226_alert_limit_write(data, - channel ? INA226_BUS_UNDER_VOLTAGE_MASK : INA226_SHUNT_UNDER_VOLTAGE_MASK, + channel ? INA2XX_ALERT_BUS_VOLTAGE_LOW : INA2XX_ALERT_SHUNT_VOLTAGE_LOW, channel ? INA2XX_BUS_VOLTAGE : INA2XX_SHUNT_VOLTAGE, val); case hwmon_in_crit: return ina226_alert_limit_write(data, - channel ? INA226_BUS_OVER_VOLTAGE_MASK : INA226_SHUNT_OVER_VOLTAGE_MASK, + channel ? INA2XX_ALERT_BUS_VOLTAGE_HIGH : INA2XX_ALERT_SHUNT_VOLTAGE_HIGH, channel ? INA2XX_BUS_VOLTAGE : INA2XX_SHUNT_VOLTAGE, val); default: @@ -705,7 +800,7 @@ static int ina2xx_power_write(struct device *dev, u32 attr, long val) switch (attr) { case hwmon_power_crit: - return ina226_alert_limit_write(data, INA226_POWER_OVER_LIMIT_MASK, + return ina226_alert_limit_write(data, INA2XX_ALERT_POWER_HIGH, INA2XX_POWER, val); default: return -EOPNOTSUPP; @@ -719,10 +814,10 @@ static int ina2xx_curr_write(struct device *dev, u32 attr, long val) switch (attr) { case hwmon_curr_lcrit: - return ina226_alert_limit_write(data, INA226_SHUNT_UNDER_VOLTAGE_MASK, + return ina226_alert_limit_write(data, INA2XX_ALERT_CURRENT_LOW, INA2XX_CURRENT, val); case hwmon_curr_crit: - return ina226_alert_limit_write(data, INA226_SHUNT_OVER_VOLTAGE_MASK, + return ina226_alert_limit_write(data, INA2XX_ALERT_CURRENT_HIGH, INA2XX_CURRENT, val); default: return -EOPNOTSUPP; @@ -883,8 +978,12 @@ static ssize_t shunt_resistor_show(struct device *dev, struct device_attribute *da, char *buf) { struct ina2xx_data *data = dev_get_drvdata(dev); + long rshunt; - return sysfs_emit(buf, "%li\n", data->rshunt); + scoped_guard(hwmon_lock, dev) { + rshunt = data->rshunt; + } + return sysfs_emit(buf, "%li\n", rshunt); } static ssize_t shunt_resistor_store(struct device *dev, @@ -940,6 +1039,16 @@ static int ina2xx_init(struct device *dev, struct ina2xx_data *data) if (data->config->has_alerts) { bool active_high = device_property_read_bool(dev, "ti,alert-polarity-active-high"); + unsigned int mask_enable; + + /* + * Infer active alert from MASK_ENABLE in case it's already + * configured (e.g., by a past probe or firmware) + */ + ret = regmap_read(regmap, INA226_MASK_ENABLE, &mask_enable); + if (ret < 0) + return ret; + data->active_alert = ina2xx_mask_to_alert_type(mask_enable); regmap_update_bits(regmap, INA226_MASK_ENABLE, INA226_ALERT_LATCH_ENABLE | INA226_ALERT_POLARITY, diff --git a/drivers/hwmon/ltc4282.c b/drivers/hwmon/ltc4282.c index b1675dc5b3c7..54ba4b8542e9 100644 --- a/drivers/hwmon/ltc4282.c +++ b/drivers/hwmon/ltc4282.c @@ -1106,7 +1106,7 @@ static const struct clk_ops ltc4282_ops = { static int ltc428_clk_provider_setup(struct ltc4282_state *st, struct device *dev) { - struct clk_init_data init; + struct clk_init_data init = {}; int ret; if (!IS_ENABLED(CONFIG_COMMON_CLK)) diff --git a/drivers/hwmon/mcp9982.c b/drivers/hwmon/mcp9982.c index 9e19e2697e25..3918dc36c946 100644 --- a/drivers/hwmon/mcp9982.c +++ b/drivers/hwmon/mcp9982.c @@ -395,6 +395,8 @@ static int mcp9982_read(struct device *dev, enum hwmon_sensor_types type, u32 at reg_status, !(reg_status & MCP9982_STATUS_BUSY), MCP9982_WAKE_UP_TIME_US, MCP9982_WAKE_UP_TIME_US * 10); + if (ret) + return ret; break; } break; diff --git a/drivers/hwmon/nct6694-hwmon.c b/drivers/hwmon/nct6694-hwmon.c index 6dcf22ca5018..9a9a4db434c4 100644 --- a/drivers/hwmon/nct6694-hwmon.c +++ b/drivers/hwmon/nct6694-hwmon.c @@ -159,6 +159,9 @@ static inline s8 temp_to_reg(long val) #define NCT6694_HWMON_TEMP_CONFIG (HWMON_T_INPUT | HWMON_T_ENABLE | \ HWMON_T_MAX | HWMON_T_MAX_HYST | \ HWMON_T_MAX_ALARM) +#define NCT6694_HWMON_DTIN_CONFIG (HWMON_T_INPUT | \ + HWMON_T_MAX | HWMON_T_MAX_HYST | \ + HWMON_T_MAX_ALARM) #define NCT6694_HWMON_FAN_CONFIG (HWMON_F_INPUT | HWMON_F_ENABLE | \ HWMON_F_MIN | HWMON_F_MIN_ALARM) #define NCT6694_HWMON_PWM_CONFIG (HWMON_PWM_INPUT | HWMON_PWM_ENABLE | \ @@ -193,22 +196,22 @@ static const struct hwmon_channel_info *nct6694_info[] = { NCT6694_HWMON_TEMP_CONFIG, /* TDP2 */ NCT6694_HWMON_TEMP_CONFIG, /* TDP3 */ NCT6694_HWMON_TEMP_CONFIG, /* TDP4 */ - NCT6694_HWMON_TEMP_CONFIG, /* DTIN0 */ - NCT6694_HWMON_TEMP_CONFIG, /* DTIN1 */ - NCT6694_HWMON_TEMP_CONFIG, /* DTIN2 */ - NCT6694_HWMON_TEMP_CONFIG, /* DTIN3 */ - NCT6694_HWMON_TEMP_CONFIG, /* DTIN4 */ - NCT6694_HWMON_TEMP_CONFIG, /* DTIN5 */ - NCT6694_HWMON_TEMP_CONFIG, /* DTIN6 */ - NCT6694_HWMON_TEMP_CONFIG, /* DTIN7 */ - NCT6694_HWMON_TEMP_CONFIG, /* DTIN8 */ - NCT6694_HWMON_TEMP_CONFIG, /* DTIN9 */ - NCT6694_HWMON_TEMP_CONFIG, /* DTIN10 */ - NCT6694_HWMON_TEMP_CONFIG, /* DTIN11 */ - NCT6694_HWMON_TEMP_CONFIG, /* DTIN12 */ - NCT6694_HWMON_TEMP_CONFIG, /* DTIN13 */ - NCT6694_HWMON_TEMP_CONFIG, /* DTIN14 */ - NCT6694_HWMON_TEMP_CONFIG), /* DTIN15 */ + NCT6694_HWMON_DTIN_CONFIG, /* DTIN0 */ + NCT6694_HWMON_DTIN_CONFIG, /* DTIN1 */ + NCT6694_HWMON_DTIN_CONFIG, /* DTIN2 */ + NCT6694_HWMON_DTIN_CONFIG, /* DTIN3 */ + NCT6694_HWMON_DTIN_CONFIG, /* DTIN4 */ + NCT6694_HWMON_DTIN_CONFIG, /* DTIN5 */ + NCT6694_HWMON_DTIN_CONFIG, /* DTIN6 */ + NCT6694_HWMON_DTIN_CONFIG, /* DTIN7 */ + NCT6694_HWMON_DTIN_CONFIG, /* DTIN8 */ + NCT6694_HWMON_DTIN_CONFIG, /* DTIN9 */ + NCT6694_HWMON_DTIN_CONFIG, /* DTIN10 */ + NCT6694_HWMON_DTIN_CONFIG, /* DTIN11 */ + NCT6694_HWMON_DTIN_CONFIG, /* DTIN12 */ + NCT6694_HWMON_DTIN_CONFIG, /* DTIN13 */ + NCT6694_HWMON_DTIN_CONFIG, /* DTIN14 */ + NCT6694_HWMON_DTIN_CONFIG), /* DTIN15 */ HWMON_CHANNEL_INFO(fan, NCT6694_HWMON_FAN_CONFIG, /* FIN0 */ diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c index 806c9a4913bb..5f69c1420b4e 100644 --- a/drivers/hwmon/pmbus/pmbus_core.c +++ b/drivers/hwmon/pmbus/pmbus_core.c @@ -1275,7 +1275,9 @@ static int pmbus_get_boolean(struct i2c_client *client, struct pmbus_boolean *b, regval = status & mask; if (regval) { - if (data->revision >= PMBUS_REV_12) { + /* Generic STATUS_WORD alarms are not individually clearable. */ + if (data->revision >= PMBUS_REV_12 && + reg != PMBUS_STATUS_WORD) { ret = _pmbus_write_byte_data(client, page, reg, regval); if (ret) return ret; diff --git a/drivers/hwmon/sht4x.c b/drivers/hwmon/sht4x.c index 9cace0e8acda..a97dda9e92dc 100644 --- a/drivers/hwmon/sht4x.c +++ b/drivers/hwmon/sht4x.c @@ -277,6 +277,8 @@ static ssize_t heater_enable_store(struct device *dev, heating_time_bound = 1100; } + guard(hwmon_lock)(dev); + if (time_before(jiffies, data->heating_complete)) return -EBUSY; @@ -286,7 +288,7 @@ static ssize_t heater_enable_store(struct device *dev, data->heating_complete = jiffies + msecs_to_jiffies(heating_time_bound); data->data_pending = true; - return 0; + return count; } static ssize_t heater_power_show(struct device *dev, @@ -314,6 +316,8 @@ static ssize_t heater_power_store(struct device *dev, if (power != 20 && power != 110 && power != 200) return -EINVAL; + guard(hwmon_lock)(dev); + data->heater_power = power; return count; @@ -344,6 +348,8 @@ static ssize_t heater_time_store(struct device *dev, if (time != 100 && time != 1000) return -EINVAL; + guard(hwmon_lock)(dev); + data->heater_time = time; return count; diff --git a/drivers/hwmon/yogafan.c b/drivers/hwmon/yogafan.c index 48fa5148d9e2..278cb089b0fd 100644 --- a/drivers/hwmon/yogafan.c +++ b/drivers/hwmon/yogafan.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -/** +/* * yoga_fan.c - Lenovo Yoga/Legion Fan Hardware Monitoring Driver * * Provides fan speed monitoring for Lenovo Yoga, Legion, and IdeaPad diff --git a/drivers/infiniband/core/iwpm_util.c b/drivers/infiniband/core/iwpm_util.c index 990cf928b32a..51af8c1c49f9 100644 --- a/drivers/infiniband/core/iwpm_util.c +++ b/drivers/infiniband/core/iwpm_util.c @@ -314,10 +314,6 @@ struct iwpm_nlmsg_request *iwpm_get_nlmsg_request(__u32 nlmsg_seq, if (!nlmsg_request) return NULL; - spin_lock_irqsave(&iwpm_nlmsg_req_lock, flags); - list_add_tail(&nlmsg_request->inprocess_list, &iwpm_nlmsg_req_list); - spin_unlock_irqrestore(&iwpm_nlmsg_req_lock, flags); - kref_init(&nlmsg_request->kref); kref_get(&nlmsg_request->kref); nlmsg_request->nlmsg_seq = nlmsg_seq; @@ -326,6 +322,11 @@ struct iwpm_nlmsg_request *iwpm_get_nlmsg_request(__u32 nlmsg_seq, nlmsg_request->err_code = 0; sema_init(&nlmsg_request->sem, 1); down(&nlmsg_request->sem); + + spin_lock_irqsave(&iwpm_nlmsg_req_lock, flags); + list_add_tail(&nlmsg_request->inprocess_list, &iwpm_nlmsg_req_list); + spin_unlock_irqrestore(&iwpm_nlmsg_req_lock, flags); + return nlmsg_request; } diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c index e0b3b36b8b14..3c91f00d09c6 100644 --- a/drivers/infiniband/core/mad.c +++ b/drivers/infiniband/core/mad.c @@ -2059,6 +2059,8 @@ static void ib_mad_complete_recv(struct ib_mad_agent_private *mad_agent_priv, int ret; INIT_LIST_HEAD(&mad_recv_wc->rmpp_list); + list_add(&mad_recv_wc->recv_buf.list, &mad_recv_wc->rmpp_list); + ret = ib_mad_enforce_security(mad_agent_priv, mad_recv_wc->wc->pkey_index); if (ret) { @@ -2067,7 +2069,6 @@ static void ib_mad_complete_recv(struct ib_mad_agent_private *mad_agent_priv, return; } - list_add(&mad_recv_wc->recv_buf.list, &mad_recv_wc->rmpp_list); if (is_kernel_rmpp_data_response(mad_agent_priv, mad_recv_wc)) { spin_lock_irqsave(&mad_agent_priv->lock, flags); mad_send_wr = ib_find_send_mad(mad_agent_priv, mad_recv_wc); diff --git a/drivers/infiniband/core/rdma_core.c b/drivers/infiniband/core/rdma_core.c index fd5651c003ae..a7cbe643e33c 100644 --- a/drivers/infiniband/core/rdma_core.c +++ b/drivers/infiniband/core/rdma_core.c @@ -69,7 +69,6 @@ void ib_uverbs_release_file(struct kref *ref) if (file->disassociate_page) __free_pages(file->disassociate_page, 0); - mutex_destroy(&file->disassociation_lock); mutex_destroy(&file->umap_lock); mutex_destroy(&file->ucontext_lock); kfree(file); diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c index 4929636f7c53..a15182f7a7c5 100644 --- a/drivers/infiniband/core/ucma.c +++ b/drivers/infiniband/core/ucma.c @@ -1556,9 +1556,10 @@ static ssize_t ucma_process_join(struct ucma_file *file, mutex_lock(&ctx->mutex); ret = rdma_join_multicast(ctx->cm_id, (struct sockaddr *)&mc->addr, join_state, mc); - mutex_unlock(&ctx->mutex); - if (ret) + if (ret) { + mutex_unlock(&ctx->mutex); goto err_xa_erase; + } resp.id = mc->id; if (copy_to_user(u64_to_user_ptr(cmd->response), @@ -1566,6 +1567,7 @@ static ssize_t ucma_process_join(struct ucma_file *file, ret = -EFAULT; goto err_leave_multicast; } + mutex_unlock(&ctx->mutex); xa_store(&multicast_table, mc->id, mc, 0); @@ -1573,7 +1575,6 @@ static ssize_t ucma_process_join(struct ucma_file *file, return 0; err_leave_multicast: - mutex_lock(&ctx->mutex); rdma_leave_multicast(ctx->cm_id, (struct sockaddr *) &mc->addr); mutex_unlock(&ctx->mutex); ucma_cleanup_mc_events(mc); diff --git a/drivers/infiniband/core/uverbs_flow.c b/drivers/infiniband/core/uverbs_flow.c index 1528a294f7f8..de5a2769f084 100644 --- a/drivers/infiniband/core/uverbs_flow.c +++ b/drivers/infiniband/core/uverbs_flow.c @@ -26,6 +26,7 @@ out: return resources; err: + kfree(resources->collection); kfree(resources->counters); kfree(resources); diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c index 0d88b2ee68ff..2a046c888dfa 100644 --- a/drivers/infiniband/core/uverbs_main.c +++ b/drivers/infiniband/core/uverbs_main.c @@ -644,12 +644,15 @@ static int ib_uverbs_mmap(struct file *filp, struct vm_area_struct *vma) goto out; } - mutex_lock(&file->disassociation_lock); + if (!down_read_trylock(&file->hw_destroy_rwsem)) { + ret = -EIO; + goto out; + } vma->vm_ops = &rdma_umap_ops; ret = ucontext->device->ops.mmap(ucontext, vma); - mutex_unlock(&file->disassociation_lock); + up_read(&file->hw_destroy_rwsem); out: srcu_read_unlock(&file->device->disassociate_srcu, srcu_key); return ret; @@ -671,7 +674,6 @@ static void rdma_umap_open(struct vm_area_struct *vma) /* We are racing with disassociation */ if (!down_read_trylock(&ufile->hw_destroy_rwsem)) goto out_zap; - mutex_lock(&ufile->disassociation_lock); /* * Disassociation already completed, the VMA should already be zapped. @@ -684,12 +686,10 @@ static void rdma_umap_open(struct vm_area_struct *vma) goto out_unlock; rdma_umap_priv_init(priv, vma, opriv->entry); - mutex_unlock(&ufile->disassociation_lock); up_read(&ufile->hw_destroy_rwsem); return; out_unlock: - mutex_unlock(&ufile->disassociation_lock); up_read(&ufile->hw_destroy_rwsem); out_zap: /* @@ -773,7 +773,7 @@ void uverbs_user_mmap_disassociate(struct ib_uverbs_file *ufile) { struct rdma_umap_priv *priv, *next_priv; - mutex_lock(&ufile->disassociation_lock); + lockdep_assert_held_write(&ufile->hw_destroy_rwsem); while (1) { struct mm_struct *mm = NULL; @@ -799,10 +799,8 @@ void uverbs_user_mmap_disassociate(struct ib_uverbs_file *ufile) break; } mutex_unlock(&ufile->umap_lock); - if (!mm) { - mutex_unlock(&ufile->disassociation_lock); + if (!mm) return; - } /* * The umap_lock is nested under mmap_lock since it used within @@ -832,8 +830,6 @@ void uverbs_user_mmap_disassociate(struct ib_uverbs_file *ufile) mmap_read_unlock(mm); mmput(mm); } - - mutex_unlock(&ufile->disassociation_lock); } /** @@ -851,8 +847,11 @@ void rdma_user_mmap_disassociate(struct ib_device *device) mutex_lock(&uverbs_dev->lists_mutex); list_for_each_entry(ufile, &uverbs_dev->uverbs_file_list, list) { - if (ufile->ucontext) + if (ufile->ucontext) { + down_write(&ufile->hw_destroy_rwsem); uverbs_user_mmap_disassociate(ufile); + up_write(&ufile->hw_destroy_rwsem); + } } mutex_unlock(&uverbs_dev->lists_mutex); } @@ -927,8 +926,6 @@ static int ib_uverbs_open(struct inode *inode, struct file *filp) mutex_init(&file->umap_lock); INIT_LIST_HEAD(&file->umaps); - mutex_init(&file->disassociation_lock); - filp->private_data = file; list_add_tail(&file->list, &dev->uverbs_file_list); mutex_unlock(&dev->lists_mutex); diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c index 04abc80c1327..c43e25d37266 100644 --- a/drivers/infiniband/core/verbs.c +++ b/drivers/infiniband/core/verbs.c @@ -2058,11 +2058,13 @@ int ib_get_eth_speed(struct ib_device *dev, u32 port_num, u16 *speed, u8 *width) return -ENODEV; rtnl_lock(); - rc = __ethtool_get_link_ksettings(netdev, &lksettings); - rtnl_unlock(); - - dev_put(netdev); + if (READ_ONCE(netdev->reg_state) != NETREG_REGISTERED) { + dev_put(netdev); + rtnl_unlock(); + return -ENODEV; + } + rc = __ethtool_get_link_ksettings(netdev, &lksettings); if (!rc && lksettings.base.speed != (u32)SPEED_UNKNOWN) { netdev_speed = lksettings.base.speed; } else { @@ -2071,6 +2073,8 @@ int ib_get_eth_speed(struct ib_device *dev, u32 port_num, u16 *speed, u8 *width) pr_warn("%s speed is unknown, defaulting to %u\n", netdev->name, netdev_speed); } + dev_put(netdev); + rtnl_unlock(); ib_get_width_and_speed(netdev_speed, lksettings.lanes, speed, width); diff --git a/drivers/infiniband/hw/bnxt_re/main.c b/drivers/infiniband/hw/bnxt_re/main.c index ce72db1b4bc3..17654a9e23fe 100644 --- a/drivers/infiniband/hw/bnxt_re/main.c +++ b/drivers/infiniband/hw/bnxt_re/main.c @@ -356,9 +356,13 @@ static int bnxt_re_update_qp1_tos_dscp(struct bnxt_re_dev *rdev) return bnxt_qplib_modify_qp(&rdev->qplib_res, &qp->qplib_qp); } -static void bnxt_re_init_dcb_wq(struct bnxt_re_dev *rdev) +static int bnxt_re_init_dcb_wq(struct bnxt_re_dev *rdev) { rdev->dcb_wq = create_singlethread_workqueue("bnxt_re_dcb_wq"); + if (!rdev->dcb_wq) + return -ENOMEM; + + return 0; } static void bnxt_re_uninit_dcb_wq(struct bnxt_re_dev *rdev) @@ -2339,7 +2343,9 @@ static int bnxt_re_dev_init(struct bnxt_re_dev *rdev, u8 op_type) } bnxt_re_debugfs_add_pdev(rdev); - bnxt_re_init_dcb_wq(rdev); + rc = bnxt_re_init_dcb_wq(rdev); + if (rc) + goto fail; bnxt_re_net_register_async_event(rdev); if (!rdev->is_virtfn) diff --git a/drivers/infiniband/hw/bnxt_re/uapi.c b/drivers/infiniband/hw/bnxt_re/uapi.c index feaf98631fc5..a407c6bc469b 100644 --- a/drivers/infiniband/hw/bnxt_re/uapi.c +++ b/drivers/infiniband/hw/bnxt_re/uapi.c @@ -462,7 +462,6 @@ static int UVERBS_HANDLER(BNXT_RE_METHOD_DBR_ALLOC)(struct uverbs_attr_bundle *a uobj->object = obj; uverbs_finalize_uobj_create(attrs, BNXT_RE_ALLOC_DBR_HANDLE); - dbr.umdbr = dpi->umdbr; dbr.dpi = dpi->dpi; ret = uverbs_copy_to_struct_or_zero(attrs, BNXT_RE_ALLOC_DBR_ATTR, &dbr, sizeof(dbr)); @@ -525,7 +524,6 @@ static int UVERBS_HANDLER(BNXT_RE_METHOD_GET_DEFAULT_DBR)(struct uverbs_attr_bun return PTR_ERR(ib_uctx); uctx = container_of(ib_uctx, struct bnxt_re_ucontext, ib_uctx); - dpi.umdbr = uctx->dpi.umdbr; dpi.dpi = uctx->dpi.dpi; ret = uverbs_copy_to_struct_or_zero(attrs, BNXT_RE_DEFAULT_DBR_ATTR, @@ -543,7 +541,7 @@ DECLARE_UVERBS_NAMED_METHOD(BNXT_RE_METHOD_DBR_ALLOC, UA_MANDATORY), UVERBS_ATTR_PTR_OUT(BNXT_RE_ALLOC_DBR_ATTR, UVERBS_ATTR_STRUCT(struct bnxt_re_db_region, - umdbr), + reserved2), UA_MANDATORY), UVERBS_ATTR_PTR_OUT(BNXT_RE_ALLOC_DBR_OFFSET, UVERBS_ATTR_TYPE(u64), @@ -563,7 +561,7 @@ DECLARE_UVERBS_NAMED_OBJECT(BNXT_RE_OBJECT_DBR, DECLARE_UVERBS_NAMED_METHOD(BNXT_RE_METHOD_GET_DEFAULT_DBR, UVERBS_ATTR_PTR_OUT(BNXT_RE_DEFAULT_DBR_ATTR, UVERBS_ATTR_STRUCT(struct bnxt_re_db_region, - umdbr), + reserved2), UA_MANDATORY)); DECLARE_UVERBS_GLOBAL_METHODS(BNXT_RE_OBJECT_DEFAULT_DBR, diff --git a/drivers/infiniband/hw/efa/efa_com.c b/drivers/infiniband/hw/efa/efa_com.c index 583b1cf0d721..04c6d63c449e 100644 --- a/drivers/infiniband/hw/efa/efa_com.c +++ b/drivers/infiniband/hw/efa/efa_com.c @@ -850,7 +850,7 @@ int efa_com_admin_init(struct efa_com_dev *edev, aq->dmadev = edev->dmadev; aq->efa_dev = edev->efa_dev; - set_bit(EFA_AQ_STATE_POLLING_BIT, &aq->state); + efa_com_set_admin_polling_mode(edev, true); sema_init(&aq->avail_cmds, aq->depth); @@ -868,8 +868,6 @@ int efa_com_admin_init(struct efa_com_dev *edev, if (err) goto err_destroy_sq; - efa_com_set_admin_polling_mode(edev, false); - err = efa_com_admin_init_aenq(edev, aenq_handlers); if (err) goto err_destroy_cq; @@ -1254,7 +1252,7 @@ static void efa_com_destroy_eq(struct efa_com_dev *edev, err); } -static void efa_com_arm_eq(struct efa_com_dev *edev, struct efa_com_eq *eeq) +void efa_com_arm_eq(struct efa_com_dev *edev, struct efa_com_eq *eeq) { u32 val = 0; @@ -1343,7 +1341,6 @@ int efa_com_eq_init(struct efa_com_dev *edev, struct efa_com_eq *eeq, eeq->phase = 1; eeq->depth = params.depth; eeq->cb = cb; - efa_com_arm_eq(edev, eeq); return 0; diff --git a/drivers/infiniband/hw/efa/efa_com.h b/drivers/infiniband/hw/efa/efa_com.h index 0341704d0921..98fb6a42a6cb 100644 --- a/drivers/infiniband/hw/efa/efa_com.h +++ b/drivers/infiniband/hw/efa/efa_com.h @@ -169,6 +169,7 @@ int efa_com_admin_init(struct efa_com_dev *edev, void efa_com_admin_destroy(struct efa_com_dev *edev); int efa_com_eq_init(struct efa_com_dev *edev, struct efa_com_eq *eeq, efa_eqe_handler cb, u16 depth, u8 msix_vec); +void efa_com_arm_eq(struct efa_com_dev *edev, struct efa_com_eq *eeq); void efa_com_eq_destroy(struct efa_com_dev *edev, struct efa_com_eq *eeq); int efa_com_dev_reset(struct efa_com_dev *edev, enum efa_regs_reset_reason_types reset_reason); diff --git a/drivers/infiniband/hw/efa/efa_main.c b/drivers/infiniband/hw/efa/efa_main.c index 4cd80727dcd2..753ed8430b69 100644 --- a/drivers/infiniband/hw/efa/efa_main.c +++ b/drivers/infiniband/hw/efa/efa_main.c @@ -302,28 +302,30 @@ static void efa_set_host_info(struct efa_dev *dev) static void efa_destroy_eq(struct efa_dev *dev, struct efa_eq *eq) { - efa_com_eq_destroy(&dev->edev, &eq->eeq); efa_free_irq(dev, &eq->irq); + efa_com_eq_destroy(&dev->edev, &eq->eeq); } static int efa_create_eq(struct efa_dev *dev, struct efa_eq *eq, u32 msix_vec) { int err; - efa_setup_comp_irq(dev, eq, msix_vec); - err = efa_request_irq(dev, &eq->irq); + err = efa_com_eq_init(&dev->edev, &eq->eeq, efa_process_eqe, + dev->dev_attr.max_eq_depth, msix_vec); if (err) return err; - err = efa_com_eq_init(&dev->edev, &eq->eeq, efa_process_eqe, - dev->dev_attr.max_eq_depth, msix_vec); + efa_setup_comp_irq(dev, eq, msix_vec); + err = efa_request_irq(dev, &eq->irq); if (err) - goto err_free_comp_irq; + goto err_destroy_eq; + + efa_com_arm_eq(&dev->edev, &eq->eeq); return 0; -err_free_comp_irq: - efa_free_irq(dev, &eq->irq); +err_destroy_eq: + efa_com_eq_destroy(&dev->edev, &eq->eeq); return err; } @@ -619,18 +621,21 @@ static struct efa_dev *efa_probe_device(struct pci_dev *pdev) edev->aq.msix_vector_idx = dev->admin_msix_vector_idx; edev->aenq.msix_vector_idx = dev->admin_msix_vector_idx; - err = efa_set_mgmnt_irq(dev); + err = efa_com_admin_init(edev, &aenq_handlers); if (err) goto err_disable_msix; - err = efa_com_admin_init(edev, &aenq_handlers); + err = efa_set_mgmnt_irq(dev); if (err) - goto err_free_mgmnt_irq; + goto err_destroy_admin; + + efa_com_set_admin_polling_mode(edev, false); return dev; -err_free_mgmnt_irq: - efa_free_irq(dev, &dev->admin_irq); +err_destroy_admin: + efa_com_dev_reset(edev, EFA_REGS_RESET_INIT_ERR); + efa_com_admin_destroy(edev); err_disable_msix: efa_disable_msix(dev); err_reg_read_destroy: @@ -654,8 +659,8 @@ static void efa_remove_device(struct pci_dev *pdev, edev = &dev->edev; efa_com_dev_reset(edev, reset_reason); - efa_com_admin_destroy(edev); efa_free_irq(dev, &dev->admin_irq); + efa_com_admin_destroy(edev); efa_disable_msix(dev); efa_com_mmio_reg_read_destroy(edev); devm_iounmap(&pdev->dev, edev->reg_bar); diff --git a/drivers/infiniband/hw/erdma/erdma_main.c b/drivers/infiniband/hw/erdma/erdma_main.c index 7e87a815e853..445182c6bc5d 100644 --- a/drivers/infiniband/hw/erdma/erdma_main.c +++ b/drivers/infiniband/hw/erdma/erdma_main.c @@ -572,8 +572,8 @@ static int erdma_ib_device_add(struct pci_dev *pdev) INIT_LIST_HEAD(&dev->cep_list); spin_lock_init(&dev->lock); - xa_init_flags(&dev->qp_xa, XA_FLAGS_ALLOC1); - xa_init_flags(&dev->cq_xa, XA_FLAGS_ALLOC1); + xa_init_flags(&dev->qp_xa, XA_FLAGS_ALLOC1 | XA_FLAGS_LOCK_IRQ); + xa_init_flags(&dev->cq_xa, XA_FLAGS_ALLOC1 | XA_FLAGS_LOCK_IRQ); dev->next_alloc_cqn = 1; dev->next_alloc_qpn = 1; diff --git a/drivers/infiniband/hw/erdma/erdma_verbs.c b/drivers/infiniband/hw/erdma/erdma_verbs.c index 65b1af1e6623..f18b88bba281 100644 --- a/drivers/infiniband/hw/erdma/erdma_verbs.c +++ b/drivers/infiniband/hw/erdma/erdma_verbs.c @@ -1021,15 +1021,15 @@ int erdma_create_qp(struct ib_qp *ibqp, struct ib_qp_init_attr *attrs, init_completion(&qp->safe_free); if (qp->ibqp.qp_type == IB_QPT_GSI) { - old_entry = xa_store(&dev->qp_xa, 1, qp, GFP_KERNEL); + old_entry = xa_store_irq(&dev->qp_xa, 1, qp, GFP_KERNEL); if (xa_is_err(old_entry)) ret = xa_err(old_entry); else qp->ibqp.qp_num = 1; } else { - ret = xa_alloc_cyclic(&dev->qp_xa, &qp->ibqp.qp_num, qp, - XA_LIMIT(1, dev->attrs.max_qp - 1), - &dev->next_alloc_qpn, GFP_KERNEL); + ret = xa_alloc_cyclic_irq(&dev->qp_xa, &qp->ibqp.qp_num, qp, + XA_LIMIT(1, dev->attrs.max_qp - 1), + &dev->next_alloc_qpn, GFP_KERNEL); } if (ret < 0) { @@ -1089,7 +1089,7 @@ err_out_cmd: else free_kernel_qp(qp); err_out_xa: - xa_erase(&dev->qp_xa, QP_ID(qp)); + xa_erase_irq(&dev->qp_xa, QP_ID(qp)); err_out: return ret; } @@ -1993,9 +1993,9 @@ int erdma_create_cq(struct ib_cq *ibcq, const struct ib_cq_init_attr *attr, refcount_set(&cq->refcount, 1); init_completion(&cq->free); - ret = xa_alloc_cyclic(&dev->cq_xa, &cq->cqn, cq, - XA_LIMIT(1, dev->attrs.max_cq - 1), - &dev->next_alloc_cqn, GFP_KERNEL); + ret = xa_alloc_cyclic_irq(&dev->cq_xa, &cq->cqn, cq, + XA_LIMIT(1, dev->attrs.max_cq - 1), + &dev->next_alloc_cqn, GFP_KERNEL); if (ret < 0) return ret; @@ -2041,7 +2041,7 @@ err_free_res: } err_out_xa: - xa_erase(&dev->cq_xa, cq->cqn); + xa_erase_irq(&dev->cq_xa, cq->cqn); return ret; } diff --git a/drivers/infiniband/hw/hfi1/file_ops.c b/drivers/infiniband/hw/hfi1/file_ops.c index dc548e6802e2..1a36f995c4f6 100644 --- a/drivers/infiniband/hw/hfi1/file_ops.c +++ b/drivers/infiniband/hw/hfi1/file_ops.c @@ -326,6 +326,7 @@ static int hfi1_file_mmap(struct file *fp, struct vm_area_struct *vma) void *memvirt = NULL; dma_addr_t memdma = 0; u8 subctxt, mapio = 0, vmf = 0, type; + size_t memdmalen = 0; ssize_t memlen = 0; int ret = 0; u16 ctxt; @@ -371,7 +372,9 @@ static int hfi1_file_mmap(struct file *fp, struct vm_area_struct *vma) mapio = 1; break; case PIO_CRED: { + struct credit_return_base *cr = &dd->cr_base[uctxt->sc->node]; u64 cr_page_offset; + if (flags & VM_WRITE) { ret = -EPERM; goto done; @@ -381,11 +384,18 @@ static int hfi1_file_mmap(struct file *fp, struct vm_area_struct *vma) * second or third page allocated for credit returns (if number * of enabled contexts > 64 and 128 respectively). */ - cr_page_offset = ((u64)uctxt->sc->hw_free - - (u64)dd->cr_base[uctxt->numa_id].va) & - PAGE_MASK; - memvirt = dd->cr_base[uctxt->numa_id].va + cr_page_offset; - memdma = dd->cr_base[uctxt->numa_id].dma + cr_page_offset; + cr_page_offset = ((u64)uctxt->sc->hw_free - (u64)cr->va) & + PAGE_MASK; + /* + * dma_mmap_coherent() describes the whole coherent buffer and + * selects the page within it with vma->vm_pgoff, so pass the + * base of the allocation and its length and let vm_pgoff pick + * the page. + */ + vma->vm_pgoff = cr_page_offset >> PAGE_SHIFT; + memvirt = cr->va; + memdma = cr->dma; + memdmalen = TXE_NUM_CONTEXTS * sizeof(struct credit_return); memlen = PAGE_SIZE; flags &= ~VM_MAYWRITE; flags |= VM_DONTCOPY | VM_DONTEXPAND; @@ -567,7 +577,8 @@ static int hfi1_file_mmap(struct file *fp, struct vm_area_struct *vma) ret = 0; } else if (memdma) { ret = dma_mmap_coherent(&dd->pcidev->dev, vma, - memvirt, memdma, memlen); + memvirt, memdma, + memdmalen ? memdmalen : memlen); } else if (mapio) { ret = io_remap_pfn_range(vma, vma->vm_start, PFN_DOWN(memaddr), diff --git a/drivers/infiniband/hw/irdma/verbs.c b/drivers/infiniband/hw/irdma/verbs.c index 9cfd84dd6869..5d71300da0ff 100644 --- a/drivers/infiniband/hw/irdma/verbs.c +++ b/drivers/infiniband/hw/irdma/verbs.c @@ -4281,7 +4281,7 @@ static int irdma_post_send(struct ib_qp *ibqp, stag_info.total_len = iwmr->ibmr.length; stag_info.reg_addr_pa = *palloc->level1.addr; stag_info.first_pm_pbl_index = palloc->level1.idx; - stag_info.local_fence = ib_wr->send_flags & IB_SEND_FENCE; + stag_info.local_fence = true; if (iwmr->npages > IRDMA_MIN_PAGES_PER_FMR) stag_info.chunk_size = 1; err = irdma_sc_mr_fast_register(&iwqp->sc_qp, &stag_info, diff --git a/drivers/infiniband/hw/mlx4/sysfs.c b/drivers/infiniband/hw/mlx4/sysfs.c index e688ad66a895..5438224bf325 100644 --- a/drivers/infiniband/hw/mlx4/sysfs.c +++ b/drivers/infiniband/hw/mlx4/sysfs.c @@ -751,11 +751,13 @@ err_add: kobject_put(p); } kobject_put(dev->dev_ports_parent[slave]); + dev->dev_ports_parent[slave] = NULL; err_ports: kobject_put(dev->pkeys.device_parent[slave]); /* extra put for the device_parent create_and_add */ kobject_put(dev->pkeys.device_parent[slave]); + dev->pkeys.device_parent[slave] = NULL; fail_dev: kobject_put(dev->iov_parent); @@ -785,6 +787,8 @@ static void unregister_pkey_tree(struct mlx4_ib_dev *device) return; for (slave = device->dev->persist->num_vfs; slave >= 0; --slave) { + if (!device->pkeys.device_parent[slave]) + continue; list_for_each_entry_safe(p, t, &device->pkeys.pkey_port_list[slave], entry) { diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index 373ee1f42d4a..a457647edacd 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -1683,11 +1683,8 @@ static int mlx5_ib_query_port_speed_rep(struct mlx5_ib_dev *dev, u32 port_num, struct mlx5_core_dev *mdev; u16 op_mod; - if (!dev->port[port_num - 1].rep) { - mlx5_ib_warn(dev, "Representor doesn't exist for port %u\n", - port_num); - return -EINVAL; - } + if (!dev->port[port_num - 1].rep) + return -ENODEV; rep = dev->port[port_num - 1].rep; mdev = mlx5_eswitch_get_core_dev(rep->esw); diff --git a/drivers/infiniband/sw/rxe/rxe_mcast.c b/drivers/infiniband/sw/rxe/rxe_mcast.c index acd03bd87794..5ca9211ab33b 100644 --- a/drivers/infiniband/sw/rxe/rxe_mcast.c +++ b/drivers/infiniband/sw/rxe/rxe_mcast.c @@ -175,7 +175,9 @@ struct rxe_mcg *rxe_lookup_mcg(struct rxe_dev *rxe, union ib_gid *mgid) * @mgid: multicast address as a gid * @mcg: new mcg object * - * Context: caller should hold rxe->mcg lock + * Initializes the mcg fields. The mcg is private and not yet visible in + * mcg_tree, so this may run without rxe->mcg_lock; __rxe_publish_mcg() + * makes it visible under the lock once it is ready. */ static void __rxe_init_mcg(struct rxe_dev *rxe, union ib_gid *mgid, struct rxe_mcg *mcg) @@ -184,13 +186,22 @@ static void __rxe_init_mcg(struct rxe_dev *rxe, union ib_gid *mgid, memcpy(&mcg->mgid, mgid, sizeof(mcg->mgid)); INIT_LIST_HEAD(&mcg->qp_list); mcg->rxe = rxe; +} - /* caller holds a ref on mcg but that will be - * dropped when mcg goes out of scope. We need to take a ref - * on the pointer that will be saved in the red-black tree - * by __rxe_insert_mcg and used to lookup mcg from mgid later. - * Inserting mcg makes it visible to outside so this should - * be done last after the object is ready. +/** + * __rxe_publish_mcg - make a fully initialized mcg visible in mcg_tree + * @mcg: the mcg object + * + * Context: caller must hold rxe->mcg_lock and a reference on mcg + */ +static void __rxe_publish_mcg(struct rxe_mcg *mcg) +{ + /* caller holds a ref on mcg but that will be dropped when mcg goes + * out of scope. We need to take a ref on the pointer that will be + * saved in the red-black tree by __rxe_insert_mcg and used to lookup + * mcg from mgid later. Inserting mcg makes it visible to outside so + * this is done last after the object is ready and the multicast + * address has been programmed. */ kref_get(&mcg->ref_cnt); __rxe_insert_mcg(mcg); @@ -228,26 +239,37 @@ static struct rxe_mcg *rxe_get_mcg(struct rxe_dev *rxe, union ib_gid *mgid) err = -ENOMEM; goto err_dec; } + __rxe_init_mcg(rxe, mgid, mcg); + + /* program the multicast address while mcg is still private, before + * it is inserted into mcg_tree. dev_mc_add() may sleep so this must + * run outside mcg_lock. On failure mcg was never published, so a + * plain free is correct and the tree is untouched. + */ + err = rxe_mcast_add(rxe, mgid); + if (err) { + kfree(mcg); + goto err_dec; + } spin_lock_bh(&rxe->mcg_lock); - /* re-check to see if someone else just added it */ + /* re-check to see if someone else just added it while we were adding + * the multicast address; if so use theirs and drop ours + */ tmp = __rxe_lookup_mcg(rxe, mgid); if (tmp) { spin_unlock_bh(&rxe->mcg_lock); + rxe_mcast_del(rxe, mgid); atomic_dec(&rxe->mcg_num); kfree(mcg); return tmp; } - __rxe_init_mcg(rxe, mgid, mcg); + __rxe_publish_mcg(mcg); spin_unlock_bh(&rxe->mcg_lock); - /* add mcast address outside of lock */ - err = rxe_mcast_add(rxe, mgid); - if (!err) - return mcg; + return mcg; - kfree(mcg); err_dec: atomic_dec(&rxe->mcg_num); return ERR_PTR(err); diff --git a/drivers/infiniband/sw/rxe/rxe_mr.c b/drivers/infiniband/sw/rxe/rxe_mr.c index 875eceb55fdf..71d9ea477289 100644 --- a/drivers/infiniband/sw/rxe/rxe_mr.c +++ b/drivers/infiniband/sw/rxe/rxe_mr.c @@ -33,7 +33,8 @@ int mr_check_range(struct rxe_mr *mr, u64 iova, size_t length) case IB_MR_TYPE_USER: case IB_MR_TYPE_MEM_REG: if (iova < mr->ibmr.iova || - iova + length > mr->ibmr.iova + mr->ibmr.length) { + length > mr->ibmr.length || + iova - mr->ibmr.iova > mr->ibmr.length - length) { rxe_dbg_mr(mr, "iova/length out of range\n"); return -EINVAL; } diff --git a/drivers/infiniband/sw/rxe/rxe_odp.c b/drivers/infiniband/sw/rxe/rxe_odp.c index e870efa7a0a3..ab21b620e94c 100644 --- a/drivers/infiniband/sw/rxe/rxe_odp.c +++ b/drivers/infiniband/sw/rxe/rxe_odp.c @@ -120,19 +120,23 @@ int rxe_odp_mr_init_user(struct rxe_dev *rxe, u64 start, u64 length, } static inline bool rxe_check_pagefault(struct ib_umem_odp *umem_odp, u64 iova, - int length) + int length, bool write) { bool need_fault = false; + u64 access = HMM_PFN_VALID; u64 addr; int idx; + if (write) + access |= HMM_PFN_WRITE; + addr = iova & (~(BIT(umem_odp->page_shift) - 1)); /* Skim through all pages that are to be accessed. */ while (addr < iova + length) { idx = (addr - ib_umem_start(umem_odp)) >> umem_odp->page_shift; - if (!(umem_odp->map.pfn_list[idx] & HMM_PFN_VALID)) { + if ((umem_odp->map.pfn_list[idx] & access) != access) { need_fault = true; break; } @@ -155,6 +159,7 @@ static unsigned long rxe_odp_iova_to_page_offset(struct ib_umem_odp *umem_odp, u static int rxe_odp_map_range_and_lock(struct rxe_mr *mr, u64 iova, int length, u32 flags) { struct ib_umem_odp *umem_odp = to_ib_umem_odp(mr->umem); + bool write = !(flags & RXE_PAGEFAULT_RDONLY); bool need_fault; int err; @@ -163,7 +168,7 @@ static int rxe_odp_map_range_and_lock(struct rxe_mr *mr, u64 iova, int length, u mutex_lock(&umem_odp->umem_mutex); - need_fault = rxe_check_pagefault(umem_odp, iova, length); + need_fault = rxe_check_pagefault(umem_odp, iova, length, write); if (need_fault) { mutex_unlock(&umem_odp->umem_mutex); @@ -173,7 +178,7 @@ static int rxe_odp_map_range_and_lock(struct rxe_mr *mr, u64 iova, int length, u if (err < 0) return err; - need_fault = rxe_check_pagefault(umem_odp, iova, length); + need_fault = rxe_check_pagefault(umem_odp, iova, length, write); if (need_fault) { mutex_unlock(&umem_odp->umem_mutex); return -EFAULT; @@ -335,8 +340,9 @@ int rxe_odp_flush_pmem_iova(struct rxe_mr *mr, u64 iova, int err; u8 *va; + /* A flush never modifies memory; read-only access suffices. */ err = rxe_odp_map_range_and_lock(mr, iova, length, - RXE_PAGEFAULT_DEFAULT); + RXE_PAGEFAULT_RDONLY); if (err) return err; diff --git a/drivers/infiniband/sw/rxe/rxe_verbs.c b/drivers/infiniband/sw/rxe/rxe_verbs.c index 96c7716057fe..3864284522eb 100644 --- a/drivers/infiniband/sw/rxe/rxe_verbs.c +++ b/drivers/infiniband/sw/rxe/rxe_verbs.c @@ -1331,19 +1331,20 @@ static struct ib_mr *rxe_rereg_user_mr(struct ib_mr *ibmr, int flags, if (err) return ERR_PTR(err); + if ((flags & IB_MR_REREG_ACCESS) && + (access & ~RXE_ACCESS_SUPPORTED_MR)) { + rxe_err_mr(mr, "access = %#x not supported\n", access); + return ERR_PTR(-EOPNOTSUPP); + } + if (flags & IB_MR_REREG_PD) { rxe_put(old_pd); rxe_get(pd); mr->ibmr.pd = ibpd; } - if (flags & IB_MR_REREG_ACCESS) { - if (access & ~RXE_ACCESS_SUPPORTED_MR) { - rxe_err_mr(mr, "access = %#x not supported\n", access); - return ERR_PTR(-EOPNOTSUPP); - } + if (flags & IB_MR_REREG_ACCESS) mr->access = access; - } return NULL; } diff --git a/drivers/infiniband/sw/siw/siw_cm.c b/drivers/infiniband/sw/siw/siw_cm.c index 0245b25e7271..ed49818793dd 100644 --- a/drivers/infiniband/sw/siw/siw_cm.c +++ b/drivers/infiniband/sw/siw/siw_cm.c @@ -1719,9 +1719,12 @@ int siw_accept(struct iw_cm_id *id, struct iw_cm_conn_param *params) SIW_QP_ATTR_STATE | SIW_QP_ATTR_LLP_HANDLE | SIW_QP_ATTR_ORD | SIW_QP_ATTR_IRD | SIW_QP_ATTR_MPA); + if (rv) { + qp->cep = NULL; + siw_cep_put(cep); + goto error_unlock; + } up_write(&qp->state_lock); - if (rv) - goto error; siw_dbg_cep(cep, "[QP %u]: send mpa reply, %d byte pdata\n", qp_id(qp), params->private_data_len); diff --git a/drivers/infiniband/sw/siw/siw_qp_rx.c b/drivers/infiniband/sw/siw/siw_qp_rx.c index b566d163c5aa..e5b641c8d694 100644 --- a/drivers/infiniband/sw/siw/siw_qp_rx.c +++ b/drivers/infiniband/sw/siw/siw_qp_rx.c @@ -1079,7 +1079,7 @@ static int siw_get_hdr(struct siw_rx_stream *srx) if (iwarp_pktinfo[opcode].hdr_len > sizeof(struct iwarp_ctrl_tagged)) { int hdrlen = iwarp_pktinfo[opcode].hdr_len; - bytes = min_t(int, hdrlen - MIN_DDP_HDR, srx->skb_new); + bytes = min_t(int, hdrlen - srx->fpdu_part_rcvd, srx->skb_new); skb_copy_bits(skb, srx->skb_offset, (char *)c_hdr + srx->fpdu_part_rcvd, bytes); diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h index 91f866e3fb8b..143e03b64902 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib.h +++ b/drivers/infiniband/ulp/ipoib/ipoib.h @@ -87,6 +87,7 @@ enum { IPOIB_FLAG_INITIALIZED = 1, IPOIB_FLAG_ADMIN_UP = 2, IPOIB_PKEY_ASSIGNED = 3, + IPOIB_FLAG_MCAST_FLUSH = 4, IPOIB_FLAG_SUBINTERFACE = 5, IPOIB_STOP_REAPER = 7, IPOIB_FLAG_ADMIN_CM = 9, @@ -414,6 +415,12 @@ struct ipoib_dev_priv { const struct net_device_ops *rn_ops; }; +static inline bool ipoib_mcast_allowed(struct ipoib_dev_priv *priv) +{ + return test_bit(IPOIB_FLAG_OPER_UP, &priv->flags) && + !test_bit(IPOIB_FLAG_MCAST_FLUSH, &priv->flags); +} + struct ipoib_ah { struct net_device *dev; struct ib_ah *ah; diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c index 5061d52a7b12..81bbb3f7c113 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c @@ -1227,17 +1227,19 @@ static void __ipoib_ib_dev_flush(struct ipoib_dev_priv *priv, } if (level == IPOIB_FLUSH_LIGHT) { - int oper_up; ipoib_mark_paths_invalid(dev); - /* Set IPoIB operation as down to prevent races between: + /* Set MCAST_FLUSH to prevent races between: * the flush flow which leaves MCG and on the fly joins * which can happen during that time. mcast restart task * should deal with join requests we missed. + * + * Do not clear OPER_UP for this; restoring it races with + * ipoib_ib_dev_down() and can leave OPER_UP set after the + * device is down. */ - oper_up = test_and_clear_bit(IPOIB_FLAG_OPER_UP, &priv->flags); + set_bit(IPOIB_FLAG_MCAST_FLUSH, &priv->flags); ipoib_mcast_dev_flush(dev); - if (oper_up) - set_bit(IPOIB_FLAG_OPER_UP, &priv->flags); + clear_bit(IPOIB_FLAG_MCAST_FLUSH, &priv->flags); ipoib_reap_dead_ahs(priv); } diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c index 6401af2fd548..379b78374e21 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c @@ -74,7 +74,7 @@ static void __ipoib_mcast_schedule_join_thread(struct ipoib_dev_priv *priv, struct ipoib_mcast *mcast, bool delay) { - if (!test_bit(IPOIB_FLAG_OPER_UP, &priv->flags)) + if (!ipoib_mcast_allowed(priv)) return; /* @@ -469,7 +469,7 @@ static int ipoib_mcast_join(struct net_device *dev, struct ipoib_mcast *mcast) int ret = 0; if (!priv->broadcast || - !test_bit(IPOIB_FLAG_OPER_UP, &priv->flags)) + !ipoib_mcast_allowed(priv)) return -EINVAL; init_completion(&mcast->done); @@ -555,7 +555,7 @@ void ipoib_mcast_join_task(struct work_struct *work) unsigned long delay_until = 0; struct ipoib_mcast *mcast = NULL; - if (!test_bit(IPOIB_FLAG_OPER_UP, &priv->flags)) + if (!ipoib_mcast_allowed(priv)) return; if (ib_query_port(priv->ca, priv->port, &port_attr)) { @@ -577,7 +577,7 @@ void ipoib_mcast_join_task(struct work_struct *work) netif_addr_unlock_bh(dev); spin_lock_irq(&priv->lock); - if (!test_bit(IPOIB_FLAG_OPER_UP, &priv->flags)) + if (!ipoib_mcast_allowed(priv)) goto out; if (!priv->broadcast) { @@ -749,7 +749,7 @@ void ipoib_mcast_send(struct net_device *dev, u8 *daddr, struct sk_buff *skb) spin_lock_irqsave(&priv->lock, flags); - if (!test_bit(IPOIB_FLAG_OPER_UP, &priv->flags) || + if (!ipoib_mcast_allowed(priv) || !priv->broadcast || !test_bit(IPOIB_MCAST_FLAG_ATTACHED, &priv->broadcast->flags)) { ++dev->stats.tx_dropped; @@ -871,7 +871,7 @@ void ipoib_mcast_restart_task(struct work_struct *work) LIST_HEAD(remove_list); struct ib_sa_mcmember_rec rec; - if (!test_bit(IPOIB_FLAG_OPER_UP, &priv->flags)) + if (!ipoib_mcast_allowed(priv)) /* * shortcut...on shutdown flush is called next, just * let it do all the work @@ -965,9 +965,9 @@ void ipoib_mcast_restart_task(struct work_struct *work) ipoib_mcast_remove_list(&remove_list); /* - * Double check that we are still up + * Double check that we are still up and not flushing */ - if (test_bit(IPOIB_FLAG_OPER_UP, &priv->flags)) { + if (ipoib_mcast_allowed(priv)) { spin_lock_irq(&priv->lock); __ipoib_mcast_schedule_join_thread(priv, NULL, 0); spin_unlock_irq(&priv->lock); diff --git a/drivers/infiniband/ulp/iser/iser_initiator.c b/drivers/infiniband/ulp/iser/iser_initiator.c index 12a2d12fef07..7ea6888b479c 100644 --- a/drivers/infiniband/ulp/iser/iser_initiator.c +++ b/drivers/infiniband/ulp/iser/iser_initiator.c @@ -598,11 +598,8 @@ static int iser_check_remote_inv(struct iser_conn *iser_conn, struct ib_wc *wc, iser_dbg("conn %p: remote invalidation for rkey %#x\n", iser_conn, rkey); - if (unlikely(!iser_conn->snd_w_inv)) { - iser_err("conn %p: unexpected remote invalidation, terminating connection\n", - iser_conn); - return -EPROTO; - } + if (unlikely(!iser_conn->snd_w_inv)) + goto bad_inv; task = iscsi_itt_to_ctask(iser_conn->iscsi_conn, hdr->itt); if (likely(task)) { @@ -611,12 +608,16 @@ static int iser_check_remote_inv(struct iser_conn *iser_conn, struct ib_wc *wc, if (iser_task->dir[ISER_DIR_IN]) { desc = iser_task->rdma_reg[ISER_DIR_IN].desc; + if (unlikely(!desc)) + goto bad_inv; if (unlikely(iser_inv_desc(desc, rkey))) return -EINVAL; } if (iser_task->dir[ISER_DIR_OUT]) { desc = iser_task->rdma_reg[ISER_DIR_OUT].desc; + if (unlikely(!desc)) + goto bad_inv; if (unlikely(iser_inv_desc(desc, rkey))) return -EINVAL; } @@ -627,6 +628,11 @@ static int iser_check_remote_inv(struct iser_conn *iser_conn, struct ib_wc *wc, } return 0; + +bad_inv: + iser_err("conn %p: unexpected remote invalidation, terminating connection\n", + iser_conn); + return -EPROTO; } diff --git a/drivers/infiniband/ulp/isert/ib_isert.c b/drivers/infiniband/ulp/isert/ib_isert.c index 5087ea983071..e69db43370ff 100644 --- a/drivers/infiniband/ulp/isert/ib_isert.c +++ b/drivers/infiniband/ulp/isert/ib_isert.c @@ -21,6 +21,7 @@ #include <target/target_core_fabric.h> #include <target/iscsi/iscsi_transport.h> #include <linux/semaphore.h> +#include <linux/wait_bit.h> #include "ib_isert.h" @@ -310,6 +311,7 @@ isert_init_conn(struct isert_conn *isert_conn) init_completion(&isert_conn->login_req_comp); init_waitqueue_head(&isert_conn->rem_wait); kref_init(&isert_conn->kref); + atomic_set(&isert_conn->ctrl_comp_cnt, 0); mutex_init(&isert_conn->mutex); INIT_WORK(&isert_conn->release_work, isert_release_work); } @@ -1694,6 +1696,8 @@ isert_do_control_comp(struct work_struct *work) struct isert_conn *isert_conn = isert_cmd->conn; struct ib_device *ib_dev = isert_conn->cm_id->device; struct iscsit_cmd *cmd = isert_cmd->iscsit_cmd; + /* The switch below may free isert_cmd. */ + bool counted = isert_cmd->ctrl_counted; isert_dbg("Cmd %p i_state %d\n", isert_cmd, cmd->i_state); @@ -1715,6 +1719,14 @@ isert_do_control_comp(struct work_struct *work) dump_stack(); break; } + + /* + * The count is what keeps isert_conn alive, so drop it last. The wait + * queue lives in the global hash table, not in isert_conn, so this is + * safe even if the waiter has already freed the connection. + */ + if (counted && atomic_dec_and_test(&isert_conn->ctrl_comp_cnt)) + wake_up_var(&isert_conn->ctrl_comp_cnt); } static void @@ -1758,6 +1770,12 @@ isert_send_done(struct ib_cq *cq, struct ib_wc *wc) case ISTATE_SEND_TEXTRSP: isert_unmap_tx_desc(tx_desc, ib_dev); + /* Paired with the wait in isert_wait_conn(). */ + isert_cmd->ctrl_counted = + isert_cmd->iscsit_cmd->i_state != ISTATE_SEND_LOGOUTRSP; + if (isert_cmd->ctrl_counted) + atomic_inc(&isert_conn->ctrl_comp_cnt); + INIT_WORK(&isert_cmd->comp_work, isert_do_control_comp); queue_work(isert_comp_wq, &isert_cmd->comp_work); return; @@ -2602,6 +2620,10 @@ static void isert_wait_conn(struct iscsit_conn *conn) isert_wait4cmds(conn); isert_wait4logout(isert_conn); + /* Paired with the count taken in isert_send_done(). */ + wait_var_event(&isert_conn->ctrl_comp_cnt, + !atomic_read(&isert_conn->ctrl_comp_cnt)); + queue_work(isert_release_wq, &isert_conn->release_work); } diff --git a/drivers/infiniband/ulp/isert/ib_isert.h b/drivers/infiniband/ulp/isert/ib_isert.h index 0bac5aa66c80..519b17e54bd3 100644 --- a/drivers/infiniband/ulp/isert/ib_isert.h +++ b/drivers/infiniband/ulp/isert/ib_isert.h @@ -153,6 +153,7 @@ struct isert_cmd { struct work_struct comp_work; struct scatterlist sg; bool ctx_init_done; + bool ctrl_counted; }; static inline struct isert_cmd *tx_desc_to_cmd(struct iser_tx_desc *desc) @@ -187,6 +188,7 @@ struct isert_conn { struct mutex mutex; struct kref kref; struct work_struct release_work; + atomic_t ctrl_comp_cnt; bool logout_posted; bool snd_w_inv; wait_queue_head_t rem_wait; diff --git a/drivers/infiniband/ulp/rtrs/rtrs-clt-trace.h b/drivers/infiniband/ulp/rtrs/rtrs-clt-trace.h index 7738e2676855..29e23404bb7b 100644 --- a/drivers/infiniband/ulp/rtrs/rtrs-clt-trace.h +++ b/drivers/infiniband/ulp/rtrs/rtrs-clt-trace.h @@ -55,7 +55,7 @@ DECLARE_EVENT_CLASS(rtrs_clt_conn_class, __entry->max_reconnect_attempts = clt->max_reconnect_attempts; __entry->fail_cnt = clt_path->stats->reconnects.fail_cnt; __entry->success_cnt = clt_path->stats->reconnects.successful_cnt; - memcpy(__entry->sessname, kobject_name(&clt_path->kobj), NAME_MAX); + strscpy(__entry->sessname, kobject_name(&clt_path->kobj) ?: "", NAME_MAX); ), TP_printk("RTRS-CLT: sess='%s' state=%s attempts='%d' max-attempts='%d' fail='%d' success='%d'", diff --git a/drivers/infiniband/ulp/rtrs/rtrs-clt.c b/drivers/infiniband/ulp/rtrs/rtrs-clt.c index 7b2c51ae614f..eac38b57b00d 100644 --- a/drivers/infiniband/ulp/rtrs/rtrs-clt.c +++ b/drivers/infiniband/ulp/rtrs/rtrs-clt.c @@ -1732,6 +1732,8 @@ static void destroy_con_cq_qp(struct rtrs_clt_con *con) /* * Be careful here: destroy_con_cq_qp() can be called even * create_con_cq_qp() failed, see comments there. + * Caller must set con->destroyed under this lock first so a + * racing ADDR_RESOLVED cannot ib_cq_pool_get() after we PUT/SKIP. */ lockdep_assert_held(&con->con_mutex); rtrs_cq_qp_destroy(&con->c); @@ -1766,6 +1768,10 @@ static int rtrs_rdma_addr_resolved(struct rtrs_clt_con *con) int err; mutex_lock(&con->con_mutex); + if (con->destroyed) { + mutex_unlock(&con->con_mutex); + return -ECONNABORTED; + } err = create_con_cq_qp(con); mutex_unlock(&con->con_mutex); if (err) { @@ -2221,6 +2227,7 @@ static void rtrs_clt_stop_and_destroy_conns(struct rtrs_clt_path *clt_path) break; con = to_clt_con(clt_path->s.con[cid]); mutex_lock(&con->con_mutex); + con->destroyed = true; destroy_con_cq_qp(con); mutex_unlock(&con->con_mutex); destroy_cm(con); @@ -2387,6 +2394,7 @@ destroy: if (con->c.cm_id) { stop_cm(con); mutex_lock(&con->con_mutex); + con->destroyed = true; destroy_con_cq_qp(con); mutex_unlock(&con->con_mutex); destroy_cm(con); diff --git a/drivers/infiniband/ulp/rtrs/rtrs-clt.h b/drivers/infiniband/ulp/rtrs/rtrs-clt.h index 1305601a6251..ad64f4517c4b 100644 --- a/drivers/infiniband/ulp/rtrs/rtrs-clt.h +++ b/drivers/infiniband/ulp/rtrs/rtrs-clt.h @@ -75,6 +75,8 @@ struct rtrs_clt_con { unsigned int cpu; struct mutex con_mutex; int cm_err; + /* Set under con_mutex before CQ/QP teardown. */ + bool destroyed; }; /** diff --git a/drivers/infiniband/ulp/rtrs/rtrs-srv-trace.h b/drivers/infiniband/ulp/rtrs/rtrs-srv-trace.h index 587d3e033081..a7d7b971e6c8 100644 --- a/drivers/infiniband/ulp/rtrs/rtrs-srv-trace.h +++ b/drivers/infiniband/ulp/rtrs/rtrs-srv-trace.h @@ -61,7 +61,7 @@ TRACE_EVENT(send_io_resp_imm, __entry->msg_id = id->msg_id; __entry->wr_cnt = atomic_read(&con->c.wr_cnt); __entry->signal_interval = s->signal_interval; - memcpy(__entry->sessname, kobject_name(&srv_path->kobj), NAME_MAX); + strscpy(__entry->sessname, kobject_name(&srv_path->kobj) ?: "", NAME_MAX); ), TP_printk("sess='%s' state='%s' dir=%s err='%d' inval='%d' glob-inval='%d' msgid='%u' wrcnt='%d' sig-interval='%u'", diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index 6b429ef63f8f..955f36efeebd 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -1038,15 +1038,20 @@ static void srp_del_scsi_host_attr(struct Scsi_Host *shost) static void srp_remove_target(struct srp_target_port *target) { + struct scsi_device *sdev; struct srp_rdma_ch *ch; int i; WARN_ON_ONCE(target->state != SRP_TARGET_REMOVED); srp_del_scsi_host_attr(target->scsi_host); - srp_rport_get(target->rport); - srp_remove_host(target->scsi_host); - scsi_remove_host(target->scsi_host); + /* + * Remove all logical units. This must happen before the + * srp_disconnect_target() call because scsi_remove_device() may trigger + * submission of SCSI commands. See also sd_shutdown(). + */ + shost_for_each_device(sdev, target->scsi_host) + scsi_remove_device(sdev); srp_stop_rport_timers(target->rport); srp_disconnect_target(target); kobj_ns_drop(KOBJ_NS_TYPE_NET, to_ns_common(target->net)); @@ -1055,7 +1060,8 @@ static void srp_remove_target(struct srp_target_port *target) srp_free_ch_ib(target, ch); } cancel_work_sync(&target->tl_err_work); - srp_rport_put(target->rport); + srp_remove_host(target->scsi_host); + scsi_remove_host(target->scsi_host); kfree(target->ch); target->ch = NULL; diff --git a/drivers/iommu/amd/amd_iommu.h b/drivers/iommu/amd/amd_iommu.h index a2fe804b038b..71113e860859 100644 --- a/drivers/iommu/amd/amd_iommu.h +++ b/drivers/iommu/amd/amd_iommu.h @@ -54,9 +54,6 @@ struct protection_domain *protection_domain_alloc(void); struct iommu_domain *amd_iommu_domain_alloc_sva(struct device *dev, struct mm_struct *mm); void amd_iommu_domain_free(struct iommu_domain *dom); -int iommu_sva_set_dev_pasid(struct iommu_domain *domain, - struct device *dev, ioasid_t pasid, - struct iommu_domain *old); void amd_iommu_remove_dev_pasid(struct device *dev, ioasid_t pasid, struct iommu_domain *domain); diff --git a/drivers/iommu/amd/amd_iommu_types.h b/drivers/iommu/amd/amd_iommu_types.h index 3dbe20023456..8241ef922519 100644 --- a/drivers/iommu/amd/amd_iommu_types.h +++ b/drivers/iommu/amd/amd_iommu_types.h @@ -39,18 +39,6 @@ #define MMIO_RANGE_OFFSET 0x0c #define MMIO_MISC_OFFSET 0x10 -/* Masks, shifts and macros to parse the device range capability */ -#define MMIO_RANGE_LD_MASK 0xff000000 -#define MMIO_RANGE_FD_MASK 0x00ff0000 -#define MMIO_RANGE_BUS_MASK 0x0000ff00 -#define MMIO_RANGE_LD_SHIFT 24 -#define MMIO_RANGE_FD_SHIFT 16 -#define MMIO_RANGE_BUS_SHIFT 8 -#define MMIO_GET_LD(x) (((x) & MMIO_RANGE_LD_MASK) >> MMIO_RANGE_LD_SHIFT) -#define MMIO_GET_FD(x) (((x) & MMIO_RANGE_FD_MASK) >> MMIO_RANGE_FD_SHIFT) -#define MMIO_GET_BUS(x) (((x) & MMIO_RANGE_BUS_MASK) >> MMIO_RANGE_BUS_SHIFT) -#define MMIO_MSI_NUM(x) ((x) & 0x1f) - /* Used offsets into the MMIO space */ #define MMIO_DEV_TABLE_OFFSET 0x0000 #define MMIO_CMD_BUF_OFFSET 0x0008 @@ -247,7 +235,6 @@ /* constants to configure the command buffer */ #define CMD_BUFFER_SIZE 8192 -#define CMD_BUFFER_UNINITIALIZED 1 #define CMD_BUFFER_ENTRIES 512 #define MMIO_CMD_SIZE_SHIFT 56 #define MMIO_CMD_SIZE_512 (0x9ULL << MMIO_CMD_SIZE_SHIFT) @@ -434,9 +421,6 @@ struct irq_remap_table { u32 *table; }; -/* Interrupt remapping feature used? */ -extern bool amd_iommu_irq_remap; - extern const struct iommu_ops amd_iommu_ops; /* IVRS indicates that pre-boot remapping was enabled */ diff --git a/drivers/iommu/amd/init.c b/drivers/iommu/amd/init.c index 40726dfef273..8a410d4aa370 100644 --- a/drivers/iommu/amd/init.c +++ b/drivers/iommu/amd/init.c @@ -152,7 +152,7 @@ struct ivmd_header { } __attribute__((packed)); bool amd_iommu_dump; -bool amd_iommu_irq_remap __read_mostly; +static bool amd_iommu_irq_remap __read_mostly; enum protection_domain_mode amd_iommu_pgtable = PD_MODE_V1; /* Virtual address size */ @@ -909,7 +909,9 @@ static void free_ga_log(struct amd_iommu *iommu) { #ifdef CONFIG_IRQ_REMAP iommu_free_pages(iommu->ga_log); + iommu->ga_log = NULL; iommu_free_pages(iommu->ga_log_tail); + iommu->ga_log_tail = NULL; #endif } @@ -956,6 +958,9 @@ static int iommu_init_ga_log(struct amd_iommu *iommu) if (WARN_ON_ONCE(!AMD_IOMMU_GUEST_IR_VAPIC(amd_iommu_guest_ir))) return -EINVAL; + if (iommu->ga_log && iommu->ga_log_tail) + return 0; + iommu->ga_log = iommu_alloc_pages_node_sz(nid, GFP_KERNEL, GA_LOG_SIZE); if (!iommu->ga_log) goto err_out; @@ -1917,19 +1922,20 @@ static int __init init_iommu_one(struct amd_iommu *iommu, struct ivhd_header *h, else iommu->mmio_phys_end = MMIO_CNTR_CONF_OFFSET; + if (h->efr_attr & BIT(IOMMU_IVHD_ATTR_HATDIS_SHIFT)) { + pr_warn_once("Host Address Translation is not supported.\n"); + amd_iommu_hatdis = true; + } + /* XT and GAM require GA mode. */ if ((h->efr_reg & (0x1 << IOMMU_EFR_GASUP_SHIFT)) == 0) { amd_iommu_guest_ir = AMD_IOMMU_GUEST_IR_LEGACY; + break; } else { if (h->efr_reg & BIT(IOMMU_EFR_XTSUP_SHIFT)) amd_iommu_xt_mode = IRQ_REMAP_X2APIC_MODE; } - if (h->efr_attr & BIT(IOMMU_IVHD_ATTR_HATDIS_SHIFT)) { - pr_warn_once("Host Address Translation is not supported.\n"); - amd_iommu_hatdis = true; - } - early_iommu_features_init(iommu, h); break; diff --git a/drivers/iommu/amd/iommu.c b/drivers/iommu/amd/iommu.c index 4dc306a4b5c6..56262f6b1f70 100644 --- a/drivers/iommu/amd/iommu.c +++ b/drivers/iommu/amd/iommu.c @@ -1076,9 +1076,6 @@ static void iommu_poll_ga_log(struct amd_iommu *iommu) { u32 head, tail; - if (iommu->ga_log == NULL) - return; - head = readl(iommu->mmio_base + MMIO_GA_HEAD_OFFSET); tail = readl(iommu->mmio_base + MMIO_GA_TAIL_OFFSET); @@ -3976,9 +3973,6 @@ static int irq_remapping_select(struct irq_domain *d, struct irq_fwspec *fwspec, struct amd_iommu *iommu; int devid = -1; - if (!amd_iommu_irq_remap) - return 0; - if (x86_fwspec_is_ioapic(fwspec)) devid = get_ioapic_devid(fwspec->param[0]); else if (x86_fwspec_is_hpet(fwspec)) diff --git a/drivers/iommu/amd/nested.c b/drivers/iommu/amd/nested.c index 63b53b29e029..f1c7987fc585 100644 --- a/drivers/iommu/amd/nested.c +++ b/drivers/iommu/amd/nested.c @@ -96,7 +96,7 @@ struct iommu_domain * amd_iommu_alloc_domain_nested(struct iommufd_viommu *viommu, u32 flags, const struct iommu_user_data *user_data) { - int ret; + int ret, hdom_id; unsigned long irqflags; struct nested_domain *ndom; struct guest_domain_mapping_info *gdom_info; @@ -161,8 +161,8 @@ amd_iommu_alloc_domain_nested(struct iommufd_viommu *viommu, u32 flags, } /* The gDomID does not exist. We allocate new hdom_id */ - gdom_info->hdom_id = amd_iommu_pdom_id_alloc(); - if (gdom_info->hdom_id <= 0) { + hdom_id = amd_iommu_pdom_id_alloc(); + if (hdom_id <= 0) { __xa_cmpxchg(&aviommu->gdomid_array, ndom->gdom_id, gdom_info, NULL, GFP_ATOMIC); xa_unlock_irqrestore(&aviommu->gdomid_array, irqflags); @@ -170,6 +170,7 @@ amd_iommu_alloc_domain_nested(struct iommufd_viommu *viommu, u32 flags, goto out_err_gdom_info; } + gdom_info->hdom_id = hdom_id; ndom->gdom_info = gdom_info; refcount_set(&gdom_info->users, 1); diff --git a/drivers/iommu/amd/pasid.c b/drivers/iommu/amd/pasid.c index d708c6532480..40be5902087c 100644 --- a/drivers/iommu/amd/pasid.c +++ b/drivers/iommu/amd/pasid.c @@ -99,9 +99,9 @@ static const struct mmu_notifier_ops sva_mn = { .release = sva_mn_release, }; -int iommu_sva_set_dev_pasid(struct iommu_domain *domain, - struct device *dev, ioasid_t pasid, - struct iommu_domain *old) +static int iommu_sva_set_dev_pasid(struct iommu_domain *domain, + struct device *dev, ioasid_t pasid, + struct iommu_domain *old) { struct pdom_dev_data *pdom_dev_data; struct protection_domain *sva_pdom = to_pdomain(domain); diff --git a/drivers/iommu/amd/ppr.c b/drivers/iommu/amd/ppr.c index 76296079bb8b..2039a9dd71ac 100644 --- a/drivers/iommu/amd/ppr.c +++ b/drivers/iommu/amd/ppr.c @@ -165,9 +165,6 @@ void amd_iommu_poll_ppr_log(struct amd_iommu *iommu) { u32 head, tail; - if (iommu->ppr_log == NULL) - return; - head = readl(iommu->mmio_base + MMIO_PPR_HEAD_OFFSET); tail = readl(iommu->mmio_base + MMIO_PPR_TAIL_OFFSET); diff --git a/drivers/iommu/riscv/iommu.c b/drivers/iommu/riscv/iommu.c index cec3ddd7ab10..fe8e6d0f8a23 100644 --- a/drivers/iommu/riscv/iommu.c +++ b/drivers/iommu/riscv/iommu.c @@ -382,78 +382,97 @@ static int riscv_iommu_queue_wait(struct riscv_iommu_queue *queue, (int)(cons - index) > 0, 0, timeout_us); } -/* Enqueue an entry and wait to be processed if timeout_us > 0 - * - * Error handling for IOMMU hardware not responding in reasonable time - * will be added as separate patch series along with other RAS features. - * For now, only report hardware failure and continue. - */ -static unsigned int riscv_iommu_queue_send(struct riscv_iommu_queue *queue, - void *entry, size_t entry_size) +static int riscv_iommu_queue_wait_for_space(struct riscv_iommu_queue *queue, + unsigned int last) { - unsigned int prod; unsigned int head; unsigned int tail; + unsigned int hw_head; unsigned long flags; + int ret; - /* Do not preempt submission flow. */ - local_irq_save(flags); + ret = riscv_iommu_readl_timeout(queue->iommu, Q_HEAD(queue), hw_head, + !(hw_head & ~queue->mask) && hw_head != last, + 0, RISCV_IOMMU_QUEUE_TIMEOUT); + if (ret) + return ret; - /* 1. Allocate some space in the queue */ - prod = atomic_inc_return(&queue->prod) - 1; + raw_spin_lock_irqsave(&queue->lock, flags); head = atomic_read(&queue->head); + tail = atomic_read(&queue->tail); + if ((tail - head) >= queue->mask) { + last = Q_ITEM(queue, head); + /* + * Re-read hw_head under the lock so that it is consistent with + * the freshly computed 'last'. Using the pre-lock snapshot + * could produce a stale value that wraps around relative to the + * new 'last', advancing the shadow head past entries that have + * not yet been consumed by the hardware. + */ + hw_head = riscv_iommu_readl(queue->iommu, Q_HEAD(queue)); + if (!(hw_head & ~queue->mask) && hw_head != last) + atomic_add((hw_head - last) & queue->mask, &queue->head); + } + raw_spin_unlock_irqrestore(&queue->lock, flags); - /* 2. Wait for space availability. */ - if ((prod - head) > queue->mask) { - if (readx_poll_timeout(atomic_read, &queue->head, - head, (prod - head) < queue->mask, - 0, RISCV_IOMMU_QUEUE_TIMEOUT)) - goto err_busy; - } else if ((prod - head) == queue->mask) { - const unsigned int last = Q_ITEM(queue, head); + return 0; +} + +/* Enqueue an entry and publish it to the hardware queue. */ +static int riscv_iommu_queue_send(struct riscv_iommu_queue *queue, + void *entry, size_t entry_size, + unsigned int *out_prod) +{ + unsigned int prod; + unsigned int head; + unsigned long flags; + int ret; + + /* 1. Wait for space availability and reserve the next slot. */ + for (;;) { + raw_spin_lock_irqsave(&queue->lock, flags); + + prod = atomic_read(&queue->tail); + head = atomic_read(&queue->head); + + if ((prod - head) < queue->mask) + break; + + head = Q_ITEM(queue, head); + raw_spin_unlock_irqrestore(&queue->lock, flags); - if (riscv_iommu_readl_timeout(queue->iommu, Q_HEAD(queue), head, - !(head & ~queue->mask) && head != last, - 0, RISCV_IOMMU_QUEUE_TIMEOUT)) + ret = riscv_iommu_queue_wait_for_space(queue, head); + if (ret) goto err_busy; - atomic_add((head - last) & queue->mask, &queue->head); } - /* 3. Store entry in the ring buffer */ + /* 2. Store entry in the ring buffer. */ memcpy(queue->base + Q_ITEM(queue, prod) * entry_size, entry, entry_size); - /* 4. Wait for all previous entries to be ready */ - if (readx_poll_timeout(atomic_read, &queue->tail, tail, prod == tail, - 0, RISCV_IOMMU_QUEUE_TIMEOUT)) - goto err_busy; - - /* - * 5. Make sure the ring buffer update (whether in normal or I/O memory) is - * completed and visible before signaling the tail doorbell to fetch - * the next command. 'fence ow, ow' - */ + /* 3. Make sure the entry is visible before updating the queue tail. */ dma_wmb(); riscv_iommu_writel(queue->iommu, Q_TAIL(queue), Q_ITEM(queue, prod + 1)); /* - * 6. Make sure the doorbell write to the device has finished before updating - * the shadow tail index in normal memory. 'fence o, w' + * 4. Make sure the doorbell write to the device has finished before + * updating the shadow tail index in normal memory. 'fence o, w' */ #ifdef CONFIG_MMIOWB mmiowb(); #endif - atomic_inc(&queue->tail); + atomic_set(&queue->tail, prod + 1); + atomic_set(&queue->prod, prod + 1); - /* 7. Complete submission and restore local interrupts */ - local_irq_restore(flags); + if (out_prod) + *out_prod = prod; - return prod; + raw_spin_unlock_irqrestore(&queue->lock, flags); + return 0; err_busy: - local_irq_restore(flags); + /* Report the failure and continue; full RAS recovery is not implemented. */ dev_err_once(queue->iommu->dev, "Hardware error: command enqueue failed\n"); - - return prod; + return ret; } /* @@ -492,7 +511,7 @@ static irqreturn_t riscv_iommu_cmdq_process(int irq, void *data) static void riscv_iommu_cmd_send(struct riscv_iommu_device *iommu, struct riscv_iommu_command *cmd) { - riscv_iommu_queue_send(&iommu->cmdq, cmd, sizeof(*cmd)); + riscv_iommu_queue_send(&iommu->cmdq, cmd, sizeof(*cmd), NULL); } /* Send IOFENCE.C command and wait for all scheduled commands to complete. */ @@ -501,9 +520,12 @@ static void riscv_iommu_cmd_sync(struct riscv_iommu_device *iommu, { struct riscv_iommu_command cmd; unsigned int prod; + int ret; riscv_iommu_cmd_iofence(&cmd); - prod = riscv_iommu_queue_send(&iommu->cmdq, &cmd, sizeof(cmd)); + ret = riscv_iommu_queue_send(&iommu->cmdq, &cmd, sizeof(cmd), &prod); + if (ret) + return; if (!timeout_us) return; @@ -1560,6 +1582,7 @@ int riscv_iommu_init(struct riscv_iommu_device *iommu) int rc; RISCV_IOMMU_QUEUE_INIT(&iommu->cmdq, CQ); + raw_spin_lock_init(&iommu->cmdq.lock); RISCV_IOMMU_QUEUE_INIT(&iommu->fltq, FQ); rc = riscv_iommu_init_check(iommu); diff --git a/drivers/iommu/riscv/iommu.h b/drivers/iommu/riscv/iommu.h index 46df79dd5495..5676001548cc 100644 --- a/drivers/iommu/riscv/iommu.h +++ b/drivers/iommu/riscv/iommu.h @@ -12,6 +12,7 @@ #define _RISCV_IOMMU_H_ #include <linux/iommu.h> +#include <linux/spinlock.h> #include <linux/types.h> #include <linux/iopoll.h> @@ -23,6 +24,7 @@ struct riscv_iommu_queue { atomic_t prod; /* unbounded producer allocation index */ atomic_t head; /* unbounded shadow ring buffer consumer index */ atomic_t tail; /* unbounded shadow ring buffer producer index */ + raw_spinlock_t lock; /* serialize queue publishing */ unsigned int mask; /* index mask, queue length - 1 */ unsigned int irq; /* allocated interrupt number */ struct riscv_iommu_device *iommu; /* iommu device handling the queue when active */ diff --git a/drivers/iommu/s390-iommu.c b/drivers/iommu/s390-iommu.c index f148f559ac56..58ca7727b7f2 100644 --- a/drivers/iommu/s390-iommu.c +++ b/drivers/iommu/s390-iommu.c @@ -974,6 +974,8 @@ static unsigned long *get_rto_from_iova(struct s390_domain *domain, case ZPCI_TABLE_TYPE_RFX: case ZPCI_TABLE_TYPE_RSX: rso = get_rso_from_iova(domain, iova); + if (!rso) + return NULL; rsx = calc_rsx(iova); rse = READ_ONCE(rso[rsx]); if (!reg_entry_isvalid(rse)) diff --git a/drivers/irqchip/irq-gic-v5.c b/drivers/irqchip/irq-gic-v5.c index ac2d423b1723..5f2551cf077d 100644 --- a/drivers/irqchip/irq-gic-v5.c +++ b/drivers/irqchip/irq-gic-v5.c @@ -974,7 +974,8 @@ static void gicv5_cpu_disable_interrupts(void) { u64 cr0; - cr0 = FIELD_PREP(ICC_CR0_EL1_EN, 0); + cr0 = read_sysreg_s(SYS_ICC_CR0_EL1); + cr0 &= ~ICC_CR0_EL1_EN_MASK; write_sysreg_s(cr0, SYS_ICC_CR0_EL1); isb(); } @@ -991,7 +992,8 @@ static void gicv5_cpu_enable_interrupts(void) pcr = FIELD_PREP(ICC_PCR_EL1_PRIORITY, GICV5_IRQ_PRI_MI); write_sysreg_s(pcr, SYS_ICC_PCR_EL1); - cr0 = FIELD_PREP(ICC_CR0_EL1_EN, 1); + cr0 = read_sysreg_s(SYS_ICC_CR0_EL1); + cr0 |= ICC_CR0_EL1_EN_MASK; write_sysreg_s(cr0, SYS_ICC_CR0_EL1); } diff --git a/drivers/media/pci/intel/ipu-bridge.c b/drivers/media/pci/intel/ipu-bridge.c index 1bb3a3e98d6b..bd64c0400c0d 100644 --- a/drivers/media/pci/intel/ipu-bridge.c +++ b/drivers/media/pci/intel/ipu-bridge.c @@ -232,6 +232,19 @@ static const struct acpi_device_id ivsc_acpi_ids[] = { { "INTC10FA" }, /* NVL */ }; +/* + * The subset of ivsc_acpi_ids[] which are IVSC, rather than CVS, devices. The + * CVS IDs are deliberately not listed here: new ones keep being added, whereas + * this list is complete. + */ +static const struct acpi_device_id ivsc_only_acpi_ids[] = { + { "INTC1059" }, + { "INTC1095" }, + { "INTC100A" }, + { "INTC10CF" }, + { } +}; + static struct acpi_device *ipu_bridge_get_ivsc_acpi_dev(struct acpi_device *adev) { unsigned int i; @@ -283,6 +296,17 @@ static struct device *ipu_bridge_get_ivsc_csi_dev(struct acpi_device *adev) return csi_dev; } + /* + * The lookups below match on the ACPI companion alone. That is fine for + * CVS, which binds a driver to that very device, but not for IVSC: there + * the ACPI device also has a driverless platform device, which would be + * returned instead of the mei-csi client. Return NULL for IVSC so that + * the caller fails and the probe is retried once the IVSC device shows + * up. + */ + if (!acpi_match_device_ids(adev, ivsc_only_acpi_ids)) + return NULL; + /* Try to locate CVS device on the I2C bus */ csi_dev = bus_find_device_by_acpi_dev(&i2c_bus_type, adev); if (csi_dev) diff --git a/drivers/media/platform/dreamchip/rppx1/rpp_params.c b/drivers/media/platform/dreamchip/rppx1/rpp_params.c index a75a27a8afd0..5e6727d58946 100644 --- a/drivers/media/platform/dreamchip/rppx1/rpp_params.c +++ b/drivers/media/platform/dreamchip/rppx1/rpp_params.c @@ -25,6 +25,7 @@ rppx1_ext_params_blocks_info[] = { RPPX1_PARAMS_BLOCK_INFO(LSC_PRE2, lsc), RPPX1_PARAMS_BLOCK_INFO(AWBG_PRE1, awbg), RPPX1_PARAMS_BLOCK_INFO(AWBG_PRE2, awbg), + RPPX1_PARAMS_BLOCK_INFO(AWBG_POST, awbg), RPPX1_PARAMS_BLOCK_INFO(CCOR_POST, ccor), RPPX1_PARAMS_BLOCK_INFO(HIST_PRE1, hist), RPPX1_PARAMS_BLOCK_INFO(HIST_PRE2, hist), diff --git a/drivers/media/platform/dreamchip/rppx1/rppx1_bls.c b/drivers/media/platform/dreamchip/rppx1/rppx1_bls.c index 01a61db279bf..71c5561457d5 100644 --- a/drivers/media/platform/dreamchip/rppx1/rppx1_bls.c +++ b/drivers/media/platform/dreamchip/rppx1/rppx1_bls.c @@ -70,7 +70,7 @@ rppx1_bls_swap_regs(struct rpp_module *mod, const u32 input[4], u32 output[4]) /* Swap to pattern used in our path, PRE1 or PRE2. */ struct rpp_module *acq = mod == &mod->rpp->pre1.bls ? - &mod->rpp->pre1.acq : &mod->rpp->pre2.bls; + &mod->rpp->pre1.acq : &mod->rpp->pre2.acq; enum rpp_raw_pattern pattern = acq->info.acq.raw_pattern; for (unsigned int i = 0; i < 4; ++i) diff --git a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_av1_req_lat_if.c b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_av1_req_lat_if.c index 2d622e85f827..49d9b4a72387 100644 --- a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_av1_req_lat_if.c +++ b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_av1_req_lat_if.c @@ -1299,11 +1299,12 @@ static void vdec_av1_slice_setup_tile(struct vdec_av1_slice_frame *frame, tile->uniform_tile_spacing_flag = BIT_FLAG(ctrl_tile, V4L2_AV1_TILE_INFO_FLAG_UNIFORM_TILE_SPACING); - for (i = 0; i < tile->tile_cols + 1; i++) + /* Bound the copy to the mi_col_starts[]/mi_row_starts[] capacity. */ + for (i = 0; i < tile->tile_cols + 1 && i < V4L2_AV1_MAX_TILE_COLS + 1; i++) tile->mi_col_starts[i] = ALIGN(ctrl_tile->mi_col_starts[i], BIT(mib_size_log2)) >> mib_size_log2; - for (i = 0; i < tile->tile_rows + 1; i++) + for (i = 0; i < tile->tile_rows + 1 && i < V4L2_AV1_MAX_TILE_ROWS + 1; i++) tile->mi_row_starts[i] = ALIGN(ctrl_tile->mi_row_starts[i], BIT(mib_size_log2)) >> mib_size_log2; } diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c index 9c4a6093af32..2b8e04dd1572 100644 --- a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c @@ -16,6 +16,7 @@ */ #include <linux/v4l2-common.h> +#include <media/v4l2-hevc.h> #include <media/v4l2-mem2mem.h> #include "rkvdec.h" @@ -37,15 +38,17 @@ void compute_tiles_uniform(struct rkvdec_hevc_run *run, u16 log2_min_cb_size, s32 pic_in_cts_height, u16 *column_width, u16 *row_height) { const struct v4l2_ctrl_hevc_pps *pps = run->pps; + unsigned int num_cols = v4l2_hevc_pps_num_tile_columns(pps); + unsigned int num_rows = v4l2_hevc_pps_num_tile_rows(pps); int i; - for (i = 0; i < pps->num_tile_columns_minus1 + 1; i++) + for (i = 0; i < num_cols; i++) column_width[i] = ((i + 1) * pic_in_cts_width) / (pps->num_tile_columns_minus1 + 1) - (i * pic_in_cts_width) / (pps->num_tile_columns_minus1 + 1); - for (i = 0; i < pps->num_tile_rows_minus1 + 1; i++) + for (i = 0; i < num_rows; i++) row_height[i] = ((i + 1) * pic_in_cts_height) / (pps->num_tile_rows_minus1 + 1) - (i * pic_in_cts_height) / @@ -57,17 +60,20 @@ void compute_tiles_non_uniform(struct rkvdec_hevc_run *run, u16 log2_min_cb_size s32 pic_in_cts_height, u16 *column_width, u16 *row_height) { const struct v4l2_ctrl_hevc_pps *pps = run->pps; + unsigned int num_cols = v4l2_hevc_pps_num_tile_columns(pps); + unsigned int num_rows = v4l2_hevc_pps_num_tile_rows(pps); s32 sum = 0; int i; - for (i = 0; i < pps->num_tile_columns_minus1; i++) { + /* The last tile entry is written after the loop, so iterate one less. */ + for (i = 0; i < num_cols - 1; i++) { column_width[i] = pps->column_width_minus1[i] + 1; sum += column_width[i]; } column_width[i] = pic_in_cts_width - sum; sum = 0; - for (i = 0; i < pps->num_tile_rows_minus1; i++) { + for (i = 0; i < num_rows - 1; i++) { row_height[i] = pps->row_height_minus1[i] + 1; sum += row_height[i]; } diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c index ff3942f91c5d..88e90c438eb9 100644 --- a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c @@ -12,6 +12,7 @@ * Jeffy Chen <jeffy.chen@rock-chips.com> */ +#include <media/v4l2-hevc.h> #include <media/v4l2-mem2mem.h> #include "rkvdec.h" @@ -135,6 +136,8 @@ static void assemble_hw_pps(struct rkvdec_ctx *ctx, * packet unit). so the driver copy SPS/PPS information to the exact PPS * packet unit for HW accessing. */ + if (pps->pic_parameter_set_id >= ARRAY_SIZE(priv_tbl->param_set)) + return; hw_ps = &priv_tbl->param_set[pps->pic_parameter_set_id]; memset(hw_ps, 0, sizeof(*hw_ps)); @@ -253,9 +256,9 @@ static void assemble_hw_pps(struct rkvdec_ctx *ctx, if (pps->flags & V4L2_HEVC_PPS_FLAG_TILES_ENABLED) { /* Userspace also provide column width and row height for uniform spacing */ - for (i = 0; i <= pps->num_tile_columns_minus1; i++) + for (i = 0; i < v4l2_hevc_pps_num_tile_columns(pps); i++) WRITE_PPS(pps->column_width_minus1[i], COLUMN_WIDTH(i)); - for (i = 0; i <= pps->num_tile_rows_minus1; i++) + for (i = 0; i < v4l2_hevc_pps_num_tile_rows(pps); i++) WRITE_PPS(pps->row_height_minus1[i], ROW_HEIGHT(i)); } else { WRITE_PPS(DIV_ROUND_UP(sps->pic_width_in_luma_samples, ctb_size_y) - 1, diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-hevc.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-hevc.c index d07c74679552..e1936e87f45b 100644 --- a/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-hevc.c +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-hevc.c @@ -145,6 +145,8 @@ static void assemble_hw_pps(struct rkvdec_ctx *ctx, * packet unit). so the driver copy SPS/PPS information to the exact PPS * packet unit for HW accessing. */ + if (pps->pic_parameter_set_id >= ARRAY_SIZE(priv_tbl->param_set)) + return; hw_ps = &priv_tbl->param_set[pps->pic_parameter_set_id]; memset(hw_ps, 0, sizeof(*hw_ps)); diff --git a/drivers/media/platform/verisilicon/hantro_g2_hevc_dec.c b/drivers/media/platform/verisilicon/hantro_g2_hevc_dec.c index e8c2e83379de..e7a7c7a42467 100644 --- a/drivers/media/platform/verisilicon/hantro_g2_hevc_dec.c +++ b/drivers/media/platform/verisilicon/hantro_g2_hevc_dec.c @@ -5,6 +5,8 @@ * Copyright (C) 2020 Safran Passenger Innovations LLC */ +#include <media/v4l2-hevc.h> + #include "hantro_hw.h" #include "hantro_g2_regs.h" @@ -15,8 +17,8 @@ static void prepare_tile_info_buffer(struct hantro_ctx *ctx) const struct v4l2_ctrl_hevc_pps *pps = ctrls->pps; const struct v4l2_ctrl_hevc_sps *sps = ctrls->sps; u16 *p = (u16 *)((u8 *)ctx->hevc_dec.tile_sizes.cpu); - unsigned int num_tile_rows = pps->num_tile_rows_minus1 + 1; - unsigned int num_tile_cols = pps->num_tile_columns_minus1 + 1; + unsigned int num_tile_rows = v4l2_hevc_pps_num_tile_rows(pps); + unsigned int num_tile_cols = v4l2_hevc_pps_num_tile_columns(pps); unsigned int pic_width_in_ctbs, pic_height_in_ctbs; unsigned int max_log2_ctb_size, ctb_size; bool tiles_enabled, uniform_spacing; diff --git a/drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c b/drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c index e4e21ad37323..00aa566a4ccd 100644 --- a/drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c +++ b/drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c @@ -431,20 +431,39 @@ static int rockchip_vpu981_av1_dec_prepare_run(struct hantro_ctx *ctx) { struct hantro_av1_dec_hw_ctx *av1_dec = &ctx->av1_dec; struct hantro_av1_dec_ctrls *ctrls = &av1_dec->ctrls; + const struct v4l2_av1_tile_info *tile_info; + struct v4l2_ctrl *tge; + u32 num_tiles; ctrls->sequence = hantro_get_ctrl(ctx, V4L2_CID_STATELESS_AV1_SEQUENCE); if (WARN_ON(!ctrls->sequence)) return -EINVAL; - ctrls->tile_group_entry = - hantro_get_ctrl(ctx, V4L2_CID_STATELESS_AV1_TILE_GROUP_ENTRY); - if (WARN_ON(!ctrls->tile_group_entry)) + tge = v4l2_ctrl_find(&ctx->ctrl_handler, + V4L2_CID_STATELESS_AV1_TILE_GROUP_ENTRY); + if (WARN_ON(!tge)) return -EINVAL; + ctrls->tile_group_entry = tge->p_cur.p; ctrls->frame = hantro_get_ctrl(ctx, V4L2_CID_STATELESS_AV1_FRAME); if (WARN_ON(!ctrls->frame)) return -EINVAL; + /* + * rockchip_vpu981_av1_dec_set_tile_info() indexes the tile group + * entry array by tile1 * tile_cols + tile0, so it reads up to + * tile_cols * tile_rows entries, and lays out one descriptor per tile + * in the AV1_MAX_TILES tile_info buffer while programming the real + * tile geometry into the hardware. Reject a frame that claims more + * tiles than userspace submitted, or more than the hardware tile + * buffer holds, so the read stays in bounds and the programmed + * geometry matches the descriptors written. + */ + tile_info = &ctrls->frame->tile_info; + num_tiles = (u32)tile_info->tile_cols * tile_info->tile_rows; + if (num_tiles > tge->elems || num_tiles > AV1_MAX_TILES) + return -EINVAL; + ctrls->film_grain = hantro_get_ctrl(ctx, V4L2_CID_STATELESS_AV1_FILM_GRAIN); @@ -578,16 +597,30 @@ static void rockchip_vpu981_av1_dec_set_tile_info(struct hantro_ctx *ctx) const struct v4l2_av1_tile_info *tile_info = &ctrls->frame->tile_info; const struct v4l2_ctrl_av1_tile_group_entry *group_entry = ctrls->tile_group_entry; - int context_update_y = - tile_info->context_update_tile_id / tile_info->tile_cols; - int context_update_x = - tile_info->context_update_tile_id % tile_info->tile_cols; - int context_update_tile_id = - context_update_x * tile_info->tile_rows + context_update_y; + int context_update_y = 0; + int context_update_x = 0; + int context_update_tile_id = 0; u8 *dst = av1_dec->tile_info.cpu; + u8 *dst_end = dst + av1_dec->tile_info.size; struct hantro_dev *vpu = ctx->dev; int tile0, tile1; + /* + * tile_cols and tile_rows are bounded by the V4L2 control validation + * (V4L2_AV1_MAX_TILE_{COLS,ROWS} and V4L2_AV1_MAX_TILE_COUNT). Guard + * the divisor here, and keep the descriptor writes within the + * AV1_MAX_TILES tile_info buffer below; the register values use the + * unmodified tile geometry. + */ + if (tile_info->tile_cols) { + context_update_y = + tile_info->context_update_tile_id / tile_info->tile_cols; + context_update_x = + tile_info->context_update_tile_id % tile_info->tile_cols; + context_update_tile_id = + context_update_x * tile_info->tile_rows + context_update_y; + } + memset(dst, 0, av1_dec->tile_info.size); for (tile0 = 0; tile0 < tile_info->tile_cols; tile0++) { @@ -598,6 +631,10 @@ static void rockchip_vpu981_av1_dec_set_tile_info(struct hantro_ctx *ctx) tile_info->height_in_sbs_minus_1[tile1] + 1; u32 x0 = tile_info->width_in_sbs_minus_1[tile0] + 1; + /* Stop once the tile_info descriptor buffer is full. */ + if (dst + 16 > dst_end) + break; + /* tile size in SB units (width,height) */ *dst++ = x0; *dst++ = 0; @@ -622,6 +659,8 @@ static void rockchip_vpu981_av1_dec_set_tile_info(struct hantro_ctx *ctx) *dst++ = (end >> 16) & 255; *dst++ = (end >> 24) & 255; } + if (dst + 16 > dst_end) + break; } hantro_reg_write(vpu, &av1_multicore_expect_context_update, !!(context_update_x == 0)); diff --git a/drivers/media/v4l2-core/v4l2-ctrls-core.c b/drivers/media/v4l2-core/v4l2-ctrls-core.c index 5b8a594fb9e2..648b88c868bc 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls-core.c +++ b/drivers/media/v4l2-core/v4l2-ctrls-core.c @@ -793,10 +793,30 @@ static int validate_av1_film_grain(struct v4l2_ctrl_av1_film_grain *fg) return 0; } +static int validate_av1_tile_info(struct v4l2_av1_tile_info *t) +{ + /* + * tile_cols and tile_rows index the per-tile descriptor arrays and + * bound the tile loops in the stateless AV1 drivers; the product + * bounds the total tile descriptor count. + */ + if (t->tile_cols > V4L2_AV1_MAX_TILE_COLS || + t->tile_rows > V4L2_AV1_MAX_TILE_ROWS) + return -EINVAL; + + if ((u32)t->tile_cols * t->tile_rows > V4L2_AV1_MAX_TILE_COUNT) + return -EINVAL; + + return 0; +} + static int validate_av1_frame(struct v4l2_ctrl_av1_frame *f) { int ret = 0; + ret = validate_av1_tile_info(&f->tile_info); + if (ret) + return ret; ret = validate_av1_quantization(&f->quantization); if (ret) return ret; @@ -1253,6 +1273,18 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx, p_hevc_pps->flags &= ~V4L2_HEVC_PPS_FLAG_LOOP_FILTER_ACROSS_TILES_ENABLED; + } else { + /* + * These count the entries the stateless HEVC drivers + * read from column_width_minus1[] / row_height_minus1[] + * and use as tile-loop bounds. + */ + if (p_hevc_pps->num_tile_columns_minus1 >= + ARRAY_SIZE(p_hevc_pps->column_width_minus1)) + return -EINVAL; + if (p_hevc_pps->num_tile_rows_minus1 >= + ARRAY_SIZE(p_hevc_pps->row_height_minus1)) + return -EINVAL; } if (p_hevc_pps->flags & diff --git a/drivers/media/v4l2-core/v4l2-h264.c b/drivers/media/v4l2-core/v4l2-h264.c index c00197d095e7..2323f559c6a3 100644 --- a/drivers/media/v4l2-core/v4l2-h264.c +++ b/drivers/media/v4l2-core/v4l2-h264.c @@ -440,7 +440,8 @@ v4l2_h264_build_b_ref_lists(const struct v4l2_h264_reflist_builder *builder, } if (builder->num_valid > 1 && - !memcmp(b1_reflist, b0_reflist, builder->num_valid)) + !memcmp(b1_reflist, b0_reflist, + sizeof(b1_reflist[0]) * builder->num_valid)) swap(b1_reflist[0], b1_reflist[1]); print_ref_list_b(builder, b0_reflist, 0); diff --git a/drivers/net/dsa/mxl862xx/mxl862xx.c b/drivers/net/dsa/mxl862xx/mxl862xx.c index cfa7e3e269a2..e05ad52cd297 100644 --- a/drivers/net/dsa/mxl862xx/mxl862xx.c +++ b/drivers/net/dsa/mxl862xx/mxl862xx.c @@ -685,10 +685,22 @@ static int mxl862xx_setup(struct dsa_switch *ds) if (ret) return ret; + ret = mxl862xx_setup_mdio(ds); + if (ret) + return ret; + schedule_delayed_work(&priv->stats_work, MXL862XX_STATS_POLL_INTERVAL); - return mxl862xx_setup_mdio(ds); + return 0; +} + +static void mxl862xx_teardown(struct dsa_switch *ds) +{ + struct mxl862xx_priv *priv = ds->priv; + + set_bit(MXL862XX_FLAG_WORK_STOPPED, &priv->flags); + disable_delayed_work_sync(&priv->stats_work); } static int mxl862xx_port_state(struct dsa_switch *ds, int port, bool enable) @@ -2047,9 +2059,7 @@ static void mxl862xx_get_stats64(struct dsa_switch *ds, int port, spin_unlock_bh(&priv->ports[port].stats_lock); - /* Trigger a fresh poll so the next read sees up-to-date counters. - * No-op if the work is already pending, running, or teardown started. - */ + /* Trigger a fresh poll so the next read sees up-to-date counters. */ if (!test_bit(MXL862XX_FLAG_WORK_STOPPED, &priv->flags)) schedule_delayed_work(&priv->stats_work, 0); } @@ -2057,6 +2067,7 @@ static void mxl862xx_get_stats64(struct dsa_switch *ds, int port, static const struct dsa_switch_ops mxl862xx_switch_ops = { .get_tag_protocol = mxl862xx_get_tag_protocol, .setup = mxl862xx_setup, + .teardown = mxl862xx_teardown, .port_setup = mxl862xx_port_setup, .port_teardown = mxl862xx_port_teardown, .phylink_get_caps = mxl862xx_phylink_get_caps, @@ -2131,7 +2142,6 @@ static int mxl862xx_probe(struct mdio_device *mdiodev) err = dsa_register_switch(ds); if (err) { set_bit(MXL862XX_FLAG_WORK_STOPPED, &priv->flags); - cancel_delayed_work_sync(&priv->stats_work); mxl862xx_host_shutdown(priv); for (i = 0; i < MXL862XX_MAX_PORTS; i++) cancel_work_sync(&priv->ports[i].host_flood_work); @@ -2152,7 +2162,6 @@ static void mxl862xx_remove(struct mdio_device *mdiodev) priv = ds->priv; set_bit(MXL862XX_FLAG_WORK_STOPPED, &priv->flags); - cancel_delayed_work_sync(&priv->stats_work); dsa_unregister_switch(ds); @@ -2181,7 +2190,7 @@ static void mxl862xx_shutdown(struct mdio_device *mdiodev) dsa_switch_shutdown(ds); set_bit(MXL862XX_FLAG_WORK_STOPPED, &priv->flags); - cancel_delayed_work_sync(&priv->stats_work); + disable_delayed_work_sync(&priv->stats_work); mxl862xx_host_shutdown(priv); diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index a2305e6428d1..b916080f4ff1 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -749,8 +749,17 @@ static void bcmgenet_hfb_init(struct bcmgenet_priv *priv) INIT_LIST_HEAD(&priv->rxnfc_rules[i].list); priv->rxnfc_rules[i].state = BCMGENET_RXNFC_STATE_UNUSED; } +} + +static void bcmgenet_hfb_restore(struct bcmgenet_priv *priv) +{ + struct bcmgenet_rxnfc_rule *rule; bcmgenet_hfb_clear(priv); + + list_for_each_entry(rule, &priv->rxnfc_list, list) + if (rule->state != BCMGENET_RXNFC_STATE_UNUSED) + bcmgenet_hfb_create_rxnfc_filter(priv, rule); } static int bcmgenet_begin(struct net_device *dev) @@ -3376,8 +3385,8 @@ static int bcmgenet_open(struct net_device *dev) bcmgenet_set_hw_addr(priv, dev->dev_addr); - /* HFB init */ - bcmgenet_hfb_init(priv); + /* Restore the filters, the MAC was reset above */ + bcmgenet_hfb_restore(priv); /* Reinitialize TDMA and RDMA and SW housekeeping */ ret = bcmgenet_init_dma(priv, true); @@ -4075,6 +4084,7 @@ static int bcmgenet_probe(struct platform_device *pdev) /* Mii wait queue */ init_waitqueue_head(&priv->wq); + bcmgenet_hfb_init(priv); INIT_WORK(&priv->bcmgenet_irq_work, bcmgenet_irq_task); priv->clk_wol = devm_clk_get_optional(&priv->pdev->dev, "enet-wol"); @@ -4272,10 +4282,7 @@ static int bcmgenet_resume(struct device *d) bcmgenet_set_hw_addr(priv, dev->dev_addr); /* Restore hardware filters */ - bcmgenet_hfb_clear(priv); - list_for_each_entry(rule, &priv->rxnfc_list, list) - if (rule->state != BCMGENET_RXNFC_STATE_UNUSED) - bcmgenet_hfb_create_rxnfc_filter(priv, rule); + bcmgenet_hfb_restore(priv); /* Reinitialize TDMA and RDMA and SW housekeeping */ ret = bcmgenet_init_dma(priv, false); diff --git a/drivers/net/ethernet/cadence/macb_ptp.c b/drivers/net/ethernet/cadence/macb_ptp.c index 6d9166389988..14ae57fa00cb 100644 --- a/drivers/net/ethernet/cadence/macb_ptp.c +++ b/drivers/net/ethernet/cadence/macb_ptp.c @@ -50,7 +50,12 @@ static int gem_tsu_get_time(struct ptp_clock_info *ptp, struct timespec64 *ts, spin_lock_irqsave(&bp->tsu_clk_lock, flags); ptp_read_system_prets(sts); + /* explicit barriers are needed because gem_readl() is relaxed */ + if (sts) + rmb(); first = gem_readl(bp, TN); + if (sts) + rmb(); ptp_read_system_postts(sts); secl = gem_readl(bp, TSL); sech = gem_readl(bp, TSH); @@ -62,7 +67,11 @@ static int gem_tsu_get_time(struct ptp_clock_info *ptp, struct timespec64 *ts, * (assume all done within 1s) */ ptp_read_system_prets(sts); + if (sts) + rmb(); ts->tv_nsec = gem_readl(bp, TN); + if (sts) + rmb(); ptp_read_system_postts(sts); secl = gem_readl(bp, TSL); sech = gem_readl(bp, TSH); diff --git a/drivers/net/ethernet/cortina/gemini.c b/drivers/net/ethernet/cortina/gemini.c index 663d2ce8414f..2fe7fd0202d2 100644 --- a/drivers/net/ethernet/cortina/gemini.c +++ b/drivers/net/ethernet/cortina/gemini.c @@ -1808,7 +1808,7 @@ static irqreturn_t gmac_irq(int irq, void *data) if (val & (GMAC0_RX_OVERRUN_INT_BIT << (netdev->dev_id * 8))) { spin_lock(&geth->irq_lock); - writel(GMAC0_RXDERR_INT_BIT << (netdev->dev_id * 8), + writel(GMAC0_RX_OVERRUN_INT_BIT << (netdev->dev_id * 8), geth->base + GLOBAL_INTERRUPT_STATUS_4_REG); u64_stats_update_begin(&port->ir_stats_syncp); ++port->stats.rx_fifo_errors; diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c index 1c50174c9f1e..317af54369cf 100644 --- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c @@ -5086,7 +5086,8 @@ static int mvpp2_change_mtu(struct net_device *dev, int mtu) netdev_warn(dev, "mtu %d too high, switching to shared buffers", mtu); mvpp2_bm_switch_buffers(priv, false); } - } else { + } else if (priv->hw_version >= MVPP22 && + mvpp2_get_nrxqs(priv) * 2 <= MVPP2_BM_MAX_POOLS) { bool jumbo = false; int i; diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c index 4cf87b39829d..447ec5522499 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c +++ b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c @@ -312,6 +312,29 @@ fbnic_rx_csum(u64 rcd, struct sk_buff *skb, struct fbnic_ring *rcq, } } +static void fbnic_tx_doorbell(struct fbnic_ring *ring, __le64 *meta) +{ + *meta |= cpu_to_le64(FBNIC_TWD_FLAG_REQ_COMPLETION); + ring->deferred_meta = -1; + + /* Force DMA writes to flush before writing to tail */ + dma_wmb(); + + writel(ring->tail, ring->doorbell); +} + +/* Packets handed to us with xmit_more set are left in the ring without a + * doorbell, and without a completion request, in the expectation that the + * packet ending the burst will ring for all of them. If that packet gets + * dropped instead we have to ring here, otherwise the descriptors sit in + * the ring until the next transmit, which may never come. + */ +static void fbnic_tx_flush_doorbell(struct fbnic_ring *ring) +{ + if (ring->deferred_meta >= 0) + fbnic_tx_doorbell(ring, &ring->desc[ring->deferred_meta]); +} + static bool fbnic_tx_map(struct fbnic_ring *ring, struct sk_buff *skb, __le64 *meta) { @@ -379,14 +402,10 @@ fbnic_tx_map(struct fbnic_ring *ring, struct sk_buff *skb, __le64 *meta) /* Verify there is room for another packet */ fbnic_maybe_stop_tx(skb->dev, ring, FBNIC_MAX_SKB_DESC); - if (fbnic_tx_sent_queue(skb, ring)) { - *meta |= cpu_to_le64(FBNIC_TWD_FLAG_REQ_COMPLETION); - - /* Force DMA writes to flush before writing to tail */ - dma_wmb(); - - writel(tail, ring->doorbell); - } + if (fbnic_tx_sent_queue(skb, ring)) + fbnic_tx_doorbell(ring, meta); + else + ring->deferred_meta = meta - ring->desc; return false; dma_error: @@ -426,8 +445,10 @@ fbnic_xmit_frame_ring(struct sk_buff *skb, struct fbnic_ring *ring) * otherwise try next time */ desc_needed = skb_shinfo(skb)->nr_frags + 10; - if (fbnic_maybe_stop_tx(skb->dev, ring, desc_needed)) + if (fbnic_maybe_stop_tx(skb->dev, ring, desc_needed)) { + fbnic_tx_flush_doorbell(ring); return NETDEV_TX_BUSY; + } *meta = cpu_to_le64(FBNIC_TWD_FLAG_DEST_MAC); @@ -448,6 +469,8 @@ fbnic_xmit_frame_ring(struct sk_buff *skb, struct fbnic_ring *ring) err_free: dev_kfree_skb_any(skb); err_count: + fbnic_tx_flush_doorbell(ring); + u64_stats_update_begin(&ring->stats.syncp); ring->stats.dropped++; u64_stats_update_end(&ring->stats.syncp); @@ -2492,6 +2515,7 @@ static void fbnic_enable_twq0(struct fbnic_ring *twq) fbnic_ring_wr32(twq, FBNIC_QUEUE_TWQ0_CTL, FBNIC_QUEUE_TWQ_CTL_RESET); twq->tail = 0; twq->head = 0; + twq->deferred_meta = -1; /* Store descriptor ring address and size */ fbnic_ring_wr32(twq, FBNIC_QUEUE_TWQ0_BAL, lower_32_bits(twq->dma)); diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.h b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.h index 98bb73765587..66c287a5404a 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.h +++ b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.h @@ -138,9 +138,14 @@ struct fbnic_ring { /* Rx BDQs only */ struct page_pool *page_pool; - /* Deferred_head is used to cache the head for TWQ1 if + /* TWQ0 only, index of the meta descriptor of the last packet + * placed in the ring without ringing the doorbell, -1 if the + * doorbell is in sync with the tail. + */ + s32 deferred_meta; + + /* TCQ only, used to cache the head for TWQ1 if * an attempt is made to clean TWQ1 with zero napi_budget. - * We do not use it for any other ring. */ s32 deferred_head; }; diff --git a/drivers/net/ethernet/microchip/lan743x_main.c b/drivers/net/ethernet/microchip/lan743x_main.c index 24ae56a3c9ed..82d3ec20ba25 100644 --- a/drivers/net/ethernet/microchip/lan743x_main.c +++ b/drivers/net/ethernet/microchip/lan743x_main.c @@ -2604,7 +2604,7 @@ process_extension: rx->adapter->netdev); if (rx->adapter->netdev->features & NETIF_F_RXCSUM) { if (!is_ice && !is_tce && !is_icsm) - skb->ip_summed = CHECKSUM_UNNECESSARY; + rx->skb_head->ip_summed = CHECKSUM_UNNECESSARY; } netdev_dbg(netdev, "sending %d byte frame to OS", rx->skb_head->len); diff --git a/drivers/net/ethernet/socionext/netsec.c b/drivers/net/ethernet/socionext/netsec.c index d14a6584473c..79a0a324c921 100644 --- a/drivers/net/ethernet/socionext/netsec.c +++ b/drivers/net/ethernet/socionext/netsec.c @@ -2149,6 +2149,7 @@ pm_disable: pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); free_ndev: + of_node_put(priv->phy_np); free_netdev(ndev); dev_err(&pdev->dev, "init failed\n"); @@ -2166,6 +2167,7 @@ static void netsec_remove(struct platform_device *pdev) netif_napi_del(&priv->napi); pm_runtime_disable(&pdev->dev); + of_node_put(priv->phy_np); free_netdev(priv->ndev); } diff --git a/drivers/net/ethernet/stmicro/stmmac/hwif.h b/drivers/net/ethernet/stmicro/stmmac/hwif.h index fe18f98fae45..8a45afacd15d 100644 --- a/drivers/net/ethernet/stmicro/stmmac/hwif.h +++ b/drivers/net/ethernet/stmicro/stmmac/hwif.h @@ -491,7 +491,7 @@ struct stmmac_ops { #define stmmac_config_l4_filter(__priv, __args...) \ stmmac_do_callback(__priv, mac, config_l4_filter, __args) #define stmmac_fpe_map_preemption_class(__priv, __args...) \ - stmmac_do_void_callback(__priv, mac, fpe_map_preemption_class, __args) + stmmac_do_callback(__priv, mac, fpe_map_preemption_class, __args) /* PTP and HW Timer helpers */ struct stmmac_hwtimestamp { diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c index 154cc0c7623d..1be5310ca766 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c @@ -1016,8 +1016,6 @@ static int stmmac_get_ts_info(struct net_device *dev, if (priv->ptp_clock) info->phc_index = ptp_clock_index(priv->ptp_clock); - else - info->phc_index = 0; info->tx_types = (1 << HWTSTAMP_TX_OFF) | (1 << HWTSTAMP_TX_ON); diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 4dee3542df3b..bc2b1cbe7792 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -4515,16 +4515,16 @@ static int stmmac_tso_get_num_desc(struct stmmac_tx_queue *tx_q, */ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev) { + unsigned int first_entry, entry, tx_packets, proto_hdr_len; struct dma_desc *desc, *first, *mss_desc = NULL; struct stmmac_priv *priv = netdev_priv(dev); - unsigned int first_entry, entry, tx_packets; struct stmmac_txq_stats *txq_stats; int i, first_tx, nfrags, ndesc; struct stmmac_tx_queue *tx_q; bool set_ic, is_last_segment; u32 pay_len, mss, queue; - u8 proto_hdr_len, hdr; dma_addr_t des; + u8 hdr; nfrags = skb_shinfo(skb)->nr_frags; queue = skb_get_queue_mapping(skb); @@ -4572,7 +4572,7 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev) } if (netif_msg_tx_queued(priv)) { - pr_info("%s: hdrlen %d, hdr_len %d, pay_len %d, mss %d\n", + pr_info("%s: hdrlen %d, hdr_len %u, pay_len %d, mss %d\n", __func__, hdr, proto_hdr_len, pay_len, mss); pr_info("\tskb->len %d, skb->data_len %d\n", skb->len, skb->data_len); diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c index 14cabe76e53e..42a00446e9b4 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c @@ -970,7 +970,7 @@ static int tc_taprio_configure(struct stmmac_priv *priv, struct netlink_ext_ack *extack = qopt->mqprio.extack; struct timespec64 time, current_time, qopt_time; ktime_t current_time_ns; - int i, ret = 0; + int err, i, ret = 0; u64 ctr; if (qopt->base_time < 0) @@ -1120,9 +1120,9 @@ disable: mutex_unlock(&priv->est_lock); } - stmmac_fpe_map_preemption_class(priv, priv->dev, extack, 0); + err = stmmac_fpe_map_preemption_class(priv, priv->dev, extack, 0); - return ret; + return qopt->cmd == TAPRIO_CMD_DESTROY ? err : ret; } static void tc_taprio_stats(struct stmmac_priv *priv, @@ -1237,58 +1237,99 @@ static int tc_query_caps(struct stmmac_priv *priv, } } -static void stmmac_reset_tc_mqprio(struct net_device *ndev, - struct netlink_ext_ack *extack) +static int stmmac_set_ndev_tcs(struct net_device *ndev, u8 ntc, + struct netdev_tc_txq *tc_to_txq) +{ + int i, err; + + netdev_reset_tc(ndev); + if (!ntc) + return 0; + + err = netdev_set_num_tc(ndev, ntc); + if (err) + return err; + + for (i = 0; i < ntc; i++) { + u16 count, offset; + + count = tc_to_txq[i].count; + offset = tc_to_txq[i].offset; + netdev_set_tc_queue(ndev, i, count, offset); + } + + return 0; +} + +static int stmmac_reset_tc_mqprio(struct net_device *ndev, + struct netlink_ext_ack *extack) { struct stmmac_priv *priv = netdev_priv(ndev); netdev_reset_tc(ndev); netif_set_real_num_tx_queues(ndev, priv->plat->tx_queues_to_use); - stmmac_fpe_map_preemption_class(priv, ndev, extack, 0); + + return stmmac_fpe_map_preemption_class(priv, ndev, extack, 0); } static int tc_setup_dwmac510_mqprio(struct stmmac_priv *priv, struct tc_mqprio_qopt_offload *mqprio) { + unsigned int ndev_num_tx_queues, num_tx_queues = 0; + struct netdev_tc_txq ndev_tc_to_txq[TC_MAX_QUEUE]; + struct netdev_tc_txq tc_to_txq[TC_MAX_QUEUE] = {}; struct netlink_ext_ack *extack = mqprio->extack; struct tc_mqprio_qopt *qopt = &mqprio->qopt; - u32 offset, count, num_stack_tx_queues = 0; struct net_device *ndev = priv->dev; - u32 num_tc = qopt->num_tc; - int err; - - if (!num_tc) { - stmmac_reset_tc_mqprio(ndev, extack); - return 0; - } + u8 ndev_prio_tc_map[TC_BITMASK + 1]; + int i, err, ndev_ntc; - err = netdev_set_num_tc(ndev, num_tc); - if (err) - return err; + if (!qopt->num_tc) + return stmmac_reset_tc_mqprio(ndev, extack); - for (u32 tc = 0; tc < num_tc; tc++) { - offset = qopt->offset[tc]; - count = qopt->count[tc]; - num_stack_tx_queues += count; + if (qopt->num_tc > ARRAY_SIZE(tc_to_txq)) + return -EINVAL; - err = netdev_set_tc_queue(ndev, tc, count, offset); - if (err) - goto err_reset_tc; + /* save current tc values for reset */ + ndev_ntc = netdev_get_num_tc(ndev); + for (i = 0; i < ARRAY_SIZE(ndev->tc_to_txq); i++) + ndev_tc_to_txq[i].combined = + READ_ONCE(ndev->tc_to_txq[i].combined); + for (i = 0; i < ARRAY_SIZE(ndev_prio_tc_map); i++) + ndev_prio_tc_map[i] = READ_ONCE(ndev->prio_tc_map[i]); + + for (i = 0; i < qopt->num_tc; i++) { + tc_to_txq[i] = (struct netdev_tc_txq) { + .count = qopt->count[i], + .offset = qopt->offset[i], + }; + num_tx_queues += qopt->count[i]; } - err = netif_set_real_num_tx_queues(ndev, num_stack_tx_queues); + err = stmmac_set_ndev_tcs(ndev, qopt->num_tc, tc_to_txq); + if (err) + goto error_reset_tc; + + ndev_num_tx_queues = ndev->real_num_tx_queues; + err = netif_set_real_num_tx_queues(ndev, num_tx_queues); if (err) - goto err_reset_tc; + goto error_reset_tc; err = stmmac_fpe_map_preemption_class(priv, ndev, extack, mqprio->preemptible_tcs); if (err) - goto err_reset_tc; + goto error_reset_num_tx_queues; return 0; -err_reset_tc: - stmmac_reset_tc_mqprio(ndev, extack); +error_reset_num_tx_queues: + if (netif_set_real_num_tx_queues(ndev, ndev_num_tx_queues)) + netdev_warn(ndev, "Failed to restore %u TX queues\n", + ndev_num_tx_queues); +error_reset_tc: + stmmac_set_ndev_tcs(ndev, ndev_ntc, ndev_tc_to_txq); + for (i = 0; i < ARRAY_SIZE(ndev_prio_tc_map); i++) + netdev_set_prio_tc_map(ndev, i, ndev_prio_tc_map[i]); return err; } diff --git a/drivers/net/fddi/skfp/skfddi.c b/drivers/net/fddi/skfp/skfddi.c index a273362c9e70..feea7baa4816 100644 --- a/drivers/net/fddi/skfp/skfddi.c +++ b/drivers/net/fddi/skfp/skfddi.c @@ -928,7 +928,8 @@ static int skfp_ctl_set_mac_address(struct net_device *dev, void *addr) dev_addr_set(dev, p_sockaddr->sa_data); spin_lock_irqsave(&bp->DriverLock, Flags); - ResetAdapter(smc); + if (netif_running(dev)) + ResetAdapter(smc); spin_unlock_irqrestore(&bp->DriverLock, Flags); return 0; /* always return zero */ diff --git a/drivers/net/phy/mediatek/mtk-phy-lib.c b/drivers/net/phy/mediatek/mtk-phy-lib.c index dfd0f4e439a2..608072fbfde9 100644 --- a/drivers/net/phy/mediatek/mtk-phy-lib.c +++ b/drivers/net/phy/mediatek/mtk-phy-lib.c @@ -156,20 +156,27 @@ int mtk_phy_led_hw_ctrl_get(struct phy_device *phydev, u8 index, if (!rules) return 0; - if (on & on_set) + /* TRIGGER_NETDEV_LINK must not be reported together with any of the + * per-speed rules, the netdev trigger rejects that combination. + * on_set holds every speed this LED can indicate and is what + * mtk_phy_led_hw_ctrl_set() programs for TRIGGER_NETDEV_LINK, so + * report the speed independent rule only when they are all on. + */ + if ((on & on_set) == on_set) { *rules |= BIT(TRIGGER_NETDEV_LINK); + } else { + if (on & MTK_PHY_LED_ON_LINK10) + *rules |= BIT(TRIGGER_NETDEV_LINK_10); - if (on & MTK_PHY_LED_ON_LINK10) - *rules |= BIT(TRIGGER_NETDEV_LINK_10); + if (on & MTK_PHY_LED_ON_LINK100) + *rules |= BIT(TRIGGER_NETDEV_LINK_100); - if (on & MTK_PHY_LED_ON_LINK100) - *rules |= BIT(TRIGGER_NETDEV_LINK_100); + if (on & MTK_PHY_LED_ON_LINK1000) + *rules |= BIT(TRIGGER_NETDEV_LINK_1000); - if (on & MTK_PHY_LED_ON_LINK1000) - *rules |= BIT(TRIGGER_NETDEV_LINK_1000); - - if (on & MTK_PHY_LED_ON_LINK2500) - *rules |= BIT(TRIGGER_NETDEV_LINK_2500); + if (on & MTK_PHY_LED_ON_LINK2500) + *rules |= BIT(TRIGGER_NETDEV_LINK_2500); + } if (on & MTK_PHY_LED_ON_FDX) *rules |= BIT(TRIGGER_NETDEV_FULL_DUPLEX); diff --git a/drivers/net/wireless/ath/ath11k/mac.c b/drivers/net/wireless/ath/ath11k/mac.c index 2d55cdc4d165..ae91b57c8422 100644 --- a/drivers/net/wireless/ath/ath11k/mac.c +++ b/drivers/net/wireless/ath/ath11k/mac.c @@ -873,6 +873,22 @@ static int ath11k_mac_set_kickout(struct ath11k_vif *arvif) return 0; } +static void ath11k_mac_station_cleanup(struct ieee80211_sta *sta) +{ + struct ath11k_sta *arsta; + + if (!sta) + return; + + arsta = ath11k_sta_to_arsta(sta); + + kfree(arsta->tx_stats); + arsta->tx_stats = NULL; + + kfree(arsta->rx_stats); + arsta->rx_stats = NULL; +} + void ath11k_mac_peer_cleanup_all(struct ath11k *ar) { struct ath11k_peer *peer, *tmp; @@ -885,6 +901,7 @@ void ath11k_mac_peer_cleanup_all(struct ath11k *ar) list_for_each_entry_safe(peer, tmp, &ab->peers, list) { ath11k_peer_rx_tid_cleanup(ar, peer); ath11k_peer_rhash_delete(ab, peer); + ath11k_mac_station_cleanup(peer->sta); list_del(&peer->list); kfree(peer); } @@ -9892,7 +9909,6 @@ static int ath11k_mac_station_remove(struct ath11k *ar, { struct ath11k_base *ab = ar->ab; struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif); - struct ath11k_sta *arsta = ath11k_sta_to_arsta(sta); int ret; if (ab->hw_params.vdev_start_delay && @@ -9916,12 +9932,7 @@ static int ath11k_mac_station_remove(struct ath11k *ar, sta->addr, arvif->vdev_id); ath11k_mac_dec_num_stations(arvif, sta); - - kfree(arsta->tx_stats); - arsta->tx_stats = NULL; - - kfree(arsta->rx_stats); - arsta->rx_stats = NULL; + ath11k_mac_station_cleanup(sta); return ret; } diff --git a/drivers/net/wireless/ath/ath12k/wifi7/ahb.c b/drivers/net/wireless/ath/ath12k/wifi7/ahb.c index 98a6606ffd76..6e9e9034cba1 100644 --- a/drivers/net/wireless/ath/ath12k/wifi7/ahb.c +++ b/drivers/net/wireless/ath/ath12k/wifi7/ahb.c @@ -15,21 +15,6 @@ #include "dp.h" #include "core.h" -/* - * Node name to UserPD ID mapping - * - * The io_start field is used for additional validation when the reg - * property is present in the device tree. If io_start is 0, only - * node_name matching is performed. - * - * For platforms where not all WiFi nodes have a 'reg' property, set - * io_start to 0 for those entries. The driver will match purely by - * node name in such cases. - */ -static const struct ath12k_ahb_userpd_map ath12k_wifi7_ahb_userpd_map[] = { - { .io_start = 0x0c000000, .node_name = "wifi", .upd_id = ATH12K_AHB_USERPD_ID_0 }, -}; - static const struct ath12k_ahb_desc ath12k_wifi7_ahb_desc[] = { [ATH12K_HW_IPQ5332_HW10] = { .hw_rev = ATH12K_HW_IPQ5332_HW10, @@ -55,40 +40,6 @@ static const struct of_device_id ath12k_wifi7_ahb_of_match[] = { MODULE_DEVICE_TABLE(of, ath12k_wifi7_ahb_of_match); -/* - * ath12k_wifi7_ahb_get_userpd_id - Resolve UserPD ID from DT properties - * @ab: ath12k base structure - * - * Returns: UserPD ID (1-based) on success, 0 on failure - * - * Resolution logic: - * 1. If reg property exist in DT, get userpd_id from io_start - * 2. If reg property is absent, get userpd_id from DT node name - * 3. Return 0 if no match found (probe will fail) - */ -static u32 ath12k_wifi7_ahb_get_userpd_id(struct ath12k_base *ab) -{ - const struct ath12k_ahb_userpd_map *map; - struct resource *res; - size_t i; - - res = platform_get_resource(ab->pdev, IORESOURCE_MEM, 0); - - for (i = 0; i < ARRAY_SIZE(ath12k_wifi7_ahb_userpd_map); i++) { - map = &ath12k_wifi7_ahb_userpd_map[i]; - - if (res) { - if (map->io_start && map->io_start == res->start) - return map->upd_id; - } else if (map->node_name && - of_node_name_eq(ab->dev->of_node, map->node_name)) { - return map->upd_id; - } - } - - return 0; -} - static int ath12k_wifi7_ahb_probe(struct platform_device *pdev) { const struct ath12k_ahb_desc *desc; @@ -106,7 +57,7 @@ static int ath12k_wifi7_ahb_probe(struct platform_device *pdev) ab->hw_rev = desc->hw_rev; ab->hif.ops = desc->ops; ab_ahb->scm_auth_enabled = desc->auth_enabled; - ab_ahb->userpd_id = ath12k_wifi7_ahb_get_userpd_id(ab); + ab_ahb->userpd_id = ATH12K_AHB_USERPD_ID_0; if (!ab_ahb->userpd_id) return -EOPNOTSUPP; diff --git a/drivers/net/wireless/ath/wcn36xx/dxe.c b/drivers/net/wireless/ath/wcn36xx/dxe.c index 44020ec265fb..801f1218ef89 100644 --- a/drivers/net/wireless/ath/wcn36xx/dxe.c +++ b/drivers/net/wireless/ath/wcn36xx/dxe.c @@ -1055,7 +1055,7 @@ void wcn36xx_dxe_deinit(struct wcn36xx *wcn) free_irq(wcn->tx_irq, wcn); free_irq(wcn->rx_irq, wcn); - timer_delete(&wcn->tx_ack_timer); + timer_shutdown_sync(&wcn->tx_ack_timer); if (wcn->tx_ack_skb) { ieee80211_tx_status_irqsafe(wcn->hw, wcn->tx_ack_skb); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c index dad6f4563d14..d2ae67985606 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c @@ -555,6 +555,8 @@ void brcmf_txfinalize(struct brcmf_if *ifp, struct sk_buff *txp, bool success) if (type == ETH_P_PAE) { atomic_dec(&ifp->pend_8021x_cnt); + /* Order the decrement before waitqueue_active() */ + smp_mb__after_atomic(); if (waitqueue_active(&ifp->pend_8021x_wait)) wake_up(&ifp->pend_8021x_wait); } diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/core.c index 545eb9aae966..6d5098f6f00f 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/core.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cyw/core.c @@ -198,7 +198,7 @@ brcmf_cyw_external_auth(struct wiphy *wiphy, struct net_device *dev, { struct brcmf_if *ifp; struct brcmf_pub *drvr; - struct brcmf_auth_req_status_le auth_status; + struct brcmf_auth_req_status_le auth_status = {}; int ret = 0; brcmf_dbg(TRACE, "Enter\n"); @@ -206,6 +206,9 @@ brcmf_cyw_external_auth(struct wiphy *wiphy, struct net_device *dev, ifp = netdev_priv(dev); drvr = ifp->drvr; if (params->status == WLAN_STATUS_SUCCESS) { + if (params->pmkid) + memcpy(auth_status.pmkid, params->pmkid, + WLAN_PMKID_LEN); auth_status.flags = cpu_to_le16(BRCMF_EXTAUTH_SUCCESS); } else { bphy_err(drvr, "External authentication failed: status=%d\n", diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c index 6255d673d2d3..c1a2318d7ea6 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/mac80211_if.c @@ -1571,6 +1571,10 @@ void brcms_free_timer(struct brcms_timer *t) /* delete the timer in case it is active */ brcms_del_timer(t); + /* Ensure the callback has finished before freeing the timer + * structure, since brcms_del_timer() uses non-synchronous cancel. + */ + cancel_delayed_work_sync(&t->dly_wrk); if (wl->timers == t) { wl->timers = wl->timers->next; diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2100.c b/drivers/net/wireless/intel/ipw2x00/ipw2100.c index 2b8a23865bfb..43b4e432956b 100644 --- a/drivers/net/wireless/intel/ipw2x00/ipw2100.c +++ b/drivers/net/wireless/intel/ipw2x00/ipw2100.c @@ -2712,7 +2712,9 @@ static void __ipw2100_rx_process(struct ipw2100_priv *priv) break; } #endif - if (stats.len < sizeof(struct libipw_hdr_3addr)) + if (sq->drv[i].frame_size < + sizeof(struct libipw_hdr_3addr) || + sq->drv[i].frame_size > IPW_RX_NIC_BUFFER_LENGTH) break; switch (WLAN_FC_GET_TYPE(le16_to_cpu(u->rx_data.header.frame_ctl))) { case IEEE80211_FTYPE_MGMT: diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2200.c b/drivers/net/wireless/intel/ipw2x00/ipw2200.c index 4bc9bb406e8e..8249d493ee22 100644 --- a/drivers/net/wireless/intel/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/intel/ipw2x00/ipw2200.c @@ -8322,6 +8322,15 @@ static void ipw_rx(struct ipw_priv *priv) break; } + if (unlikely(le16_to_cpu(pkt->u.frame.length) > + IPW_RX_BUF_SIZE - + IPW_RX_FRAME_SIZE)) { + IPW_DEBUG_DROP("Received oversized packet. Dropping.\n"); + priv->net_dev->stats.rx_errors++; + priv->wstats.discard.misc++; + break; + } + switch (WLAN_FC_GET_TYPE (le16_to_cpu(header->frame_ctl))) { diff --git a/drivers/net/wireless/intel/ipw2x00/libipw_crypto_tkip.c b/drivers/net/wireless/intel/ipw2x00/libipw_crypto_tkip.c index 24bb28ab7a49..2b0cf0ec496a 100644 --- a/drivers/net/wireless/intel/ipw2x00/libipw_crypto_tkip.c +++ b/drivers/net/wireless/intel/ipw2x00/libipw_crypto_tkip.c @@ -474,14 +474,16 @@ static int libipw_michael_mic_verify(struct sk_buff *skb, int keyidx, int hdr_len, void *priv) { struct libipw_tkip_data *tkey = priv; - u8 mic[8]; + u8 mic[MICHAEL_MIC_LEN]; - if (!tkey->key_set) + if (!tkey->key_set || skb->len < hdr_len + MICHAEL_MIC_LEN) return -1; michael_mic(&tkey->key[24], (struct ieee80211_hdr *)skb->data, - skb->data + hdr_len, skb->len - 8 - hdr_len, mic); - if (memcmp(mic, skb->data + skb->len - 8, 8) != 0) { + skb->data + hdr_len, + skb->len - MICHAEL_MIC_LEN - hdr_len, mic); + if (memcmp(mic, skb->data + skb->len - MICHAEL_MIC_LEN, + MICHAEL_MIC_LEN) != 0) { struct ieee80211_hdr *hdr; hdr = (struct ieee80211_hdr *)skb->data; printk(KERN_DEBUG "%s: Michael MIC verification failed for " @@ -499,7 +501,7 @@ static int libipw_michael_mic_verify(struct sk_buff *skb, int keyidx, tkey->rx_iv32 = tkey->rx_iv32_new; tkey->rx_iv16 = tkey->rx_iv16_new; - skb_trim(skb, skb->len - 8); + skb_trim(skb, skb->len - MICHAEL_MIC_LEN); return 0; } diff --git a/drivers/net/wireless/intel/ipw2x00/libipw_rx.c b/drivers/net/wireless/intel/ipw2x00/libipw_rx.c index c8841f9b9ad9..424349a6935e 100644 --- a/drivers/net/wireless/intel/ipw2x00/libipw_rx.c +++ b/drivers/net/wireless/intel/ipw2x00/libipw_rx.c @@ -1209,6 +1209,9 @@ static int libipw_handle_assoc_resp(struct libipw_device *ieee, struct libipw_as struct libipw_network *network = &network_resp; struct net_device *dev = ieee->dev; + if (stats->len < sizeof(*frame)) + return 1; + network->flags = 0; network->qos_data.active = 0; network->qos_data.supported = 0; @@ -1421,6 +1424,9 @@ static void libipw_process_probe_response(struct libipw_device #endif unsigned long flags; + if (stats->len < sizeof(*beacon)) + return; + LIBIPW_DEBUG_SCAN("'%*pE' (%pM): %c%c%c%c %c%c%c%c-%c%c%c%c %c%c%c%c\n", info_element->len, info_element->data, beacon->header.addr3, diff --git a/drivers/net/wireless/intel/iwlegacy/common.c b/drivers/net/wireless/intel/iwlegacy/common.c index 0bb807ff8edf..e5113c6b2d5c 100644 --- a/drivers/net/wireless/intel/iwlegacy/common.c +++ b/drivers/net/wireless/intel/iwlegacy/common.c @@ -2326,7 +2326,7 @@ il_dealloc_bcast_stations(struct il_priv *il) if (!(il->stations[i].used & IL_STA_BCAST)) continue; - il->stations[i].used &= ~IL_STA_UCODE_ACTIVE; + il->stations[i].used = 0; il->num_stations--; if (WARN_ON(il->num_stations < 0)) il->num_stations = 0; diff --git a/drivers/net/wireless/intersil/p54/eeprom.c b/drivers/net/wireless/intersil/p54/eeprom.c index 95580921d933..0475222d54fc 100644 --- a/drivers/net/wireless/intersil/p54/eeprom.c +++ b/drivers/net/wireless/intersil/p54/eeprom.c @@ -414,17 +414,22 @@ free: } static int p54_convert_rev0(struct ieee80211_hw *dev, - struct pda_pa_curve_data *curve_data) + struct pda_pa_curve_data *curve_data, size_t len) { struct p54_common *priv = dev->priv; struct p54_pa_curve_data_sample *dst; struct pda_pa_curve_data_sample_rev0 *src; + size_t needed = curve_data->channels * + (sizeof(*src) * curve_data->points_per_channel + 2); size_t cd_len = sizeof(*curve_data) + (curve_data->points_per_channel*sizeof(*dst) + 2) * curve_data->channels; unsigned int i, j; void *source, *target; + if (len < sizeof(*curve_data) + needed) + return -EINVAL; + priv->curve_data = kmalloc(sizeof(*priv->curve_data) + cd_len, GFP_KERNEL); if (!priv->curve_data) @@ -466,17 +471,22 @@ static int p54_convert_rev0(struct ieee80211_hw *dev, } static int p54_convert_rev1(struct ieee80211_hw *dev, - struct pda_pa_curve_data *curve_data) + struct pda_pa_curve_data *curve_data, size_t len) { struct p54_common *priv = dev->priv; struct p54_pa_curve_data_sample *dst; struct pda_pa_curve_data_sample_rev1 *src; + size_t needed = curve_data->channels * + (sizeof(*src) * curve_data->points_per_channel + 3); size_t cd_len = sizeof(*curve_data) + (curve_data->points_per_channel*sizeof(*dst) + 2) * curve_data->channels; unsigned int i, j; void *source, *target; + if (len < sizeof(*curve_data) + needed) + return -EINVAL; + priv->curve_data = kzalloc(cd_len + sizeof(*priv->curve_data), GFP_KERNEL); if (!priv->curve_data) @@ -763,6 +773,7 @@ int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) case PDR_PRISM_PA_CAL_CURVE_DATA: { struct pda_pa_curve_data *curve_data = (struct pda_pa_curve_data *)entry->data; + if (data_len < sizeof(*curve_data)) { err = -EINVAL; goto err; @@ -770,10 +781,10 @@ int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) switch (curve_data->cal_method_rev) { case 0: - err = p54_convert_rev0(dev, curve_data); + err = p54_convert_rev0(dev, curve_data, data_len); break; case 1: - err = p54_convert_rev1(dev, curve_data); + err = p54_convert_rev1(dev, curve_data, data_len); break; default: wiphy_err(dev->wiphy, @@ -801,7 +812,8 @@ int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) break; case PDR_INTERFACE_LIST: tmp = entry->data; - while ((u8 *)tmp < entry->data + data_len) { + while ((u8 *)tmp + sizeof(struct exp_if) <= + entry->data + data_len) { struct exp_if *exp_if = tmp; if (exp_if->if_id == cpu_to_le16(IF_ID_ISL39000)) synth = le16_to_cpu(exp_if->variant); diff --git a/drivers/net/wireless/marvell/libertas_tf/main.c b/drivers/net/wireless/marvell/libertas_tf/main.c index 42be6fa22f9c..411f075b6186 100644 --- a/drivers/net/wireless/marvell/libertas_tf/main.c +++ b/drivers/net/wireless/marvell/libertas_tf/main.c @@ -173,8 +173,8 @@ static int lbtf_init_adapter(struct lbtf_private *priv) static void lbtf_free_adapter(struct lbtf_private *priv) { lbtf_deb_enter(LBTF_DEB_MAIN); - lbtf_free_cmd_buffer(priv); timer_delete_sync(&priv->command_timer); + lbtf_free_cmd_buffer(priv); lbtf_deb_leave(LBTF_DEB_MAIN); } diff --git a/drivers/net/wireless/marvell/mwifiex/cfg80211.c b/drivers/net/wireless/marvell/mwifiex/cfg80211.c index 7a1ba32f1fb3..936939ea9c47 100644 --- a/drivers/net/wireless/marvell/mwifiex/cfg80211.c +++ b/drivers/net/wireless/marvell/mwifiex/cfg80211.c @@ -4277,6 +4277,7 @@ mwifiex_cfg80211_authenticate(struct wiphy *wiphy, struct mwifiex_adapter *adapter = priv->adapter; struct sk_buff *skb; u16 pkt_len, auth_alg; + size_t frame_len; int ret; struct mwifiex_ieee80211_mgmt *mgmt; struct mwifiex_txinfo *tx_info; @@ -4349,10 +4350,17 @@ mwifiex_cfg80211_authenticate(struct wiphy *wiphy, mwifiex_cancel_scan(adapter); - pkt_len = (u16)req->ie_len + req->auth_data_len + + frame_len = req->ie_len + req->auth_data_len + MWIFIEX_MGMT_HEADER_LEN + MWIFIEX_AUTH_BODY_LEN; if (req->auth_data_len >= 4) - pkt_len -= 4; + frame_len -= 4; + + if (frame_len > U16_MAX) { + mwifiex_dbg(priv->adapter, ERROR, + "auth frame too long: %zu bytes\n", frame_len); + return -EINVAL; + } + pkt_len = frame_len; skb = dev_alloc_skb(MWIFIEX_MIN_DATA_HEADER_LEN + MWIFIEX_MGMT_FRAME_HEADER_SIZE + diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c index a760de191fce..a9425e9a94f4 100644 --- a/drivers/net/wireless/marvell/mwifiex/pcie.c +++ b/drivers/net/wireless/marvell/mwifiex/pcie.c @@ -3068,7 +3068,7 @@ static int mwifiex_pcie_request_irq(struct mwifiex_adapter *adapter) ret); for (j = 0; j < i; j++) free_irq(card->msix_entries[j].vector, - &card->msix_ctx[i]); + &card->msix_ctx[j]); pci_disable_msix(pdev); } else { mwifiex_dbg(adapter, MSG, "MSIx enabled!"); diff --git a/drivers/net/wireless/marvell/mwifiex/scan.c b/drivers/net/wireless/marvell/mwifiex/scan.c index 97c0ec3b822e..bdd4b8465863 100644 --- a/drivers/net/wireless/marvell/mwifiex/scan.c +++ b/drivers/net/wireless/marvell/mwifiex/scan.c @@ -104,12 +104,24 @@ has_vendor_hdr(struct ieee_types_vendor_specific *ie, u8 key) * a given oui in PTK. */ static u8 -mwifiex_search_oui_in_ie(struct ie_body *iebody, u8 *oui) +mwifiex_search_oui_in_ie(struct ie_body *iebody, u8 *oui, int ie_len) { + const size_t ptk_body_offset = offsetof(struct ie_body, ptk_body); u8 count; + /* ie_len is the number of bytes available at iebody. Keep it signed + * and reject a negative (underflowed) length before the unsigned + * comparisons below, so a small or zero IE length cannot wrap. + */ + if (ie_len < 0 || (size_t)ie_len < ptk_body_offset) + return MWIFIEX_OUI_NOT_PRESENT; + count = iebody->ptk_cnt[0]; + /* Reject an OUI count whose list would run past the element. */ + if (ptk_body_offset + count * sizeof(iebody->ptk_body) > (size_t)ie_len) + return MWIFIEX_OUI_NOT_PRESENT; + /* There could be multiple OUIs for PTK hence 1) Take the length. 2) Check all the OUIs for AES. @@ -143,11 +155,14 @@ mwifiex_is_rsn_oui_present(struct mwifiex_bssdescriptor *bss_desc, u32 cipher) u8 ret = MWIFIEX_OUI_NOT_PRESENT; if (has_ieee_hdr(bss_desc->bcn_rsn_ie, WLAN_EID_RSN)) { + int ie_len = (int)bss_desc->bcn_rsn_ie->ieee_hdr.len - + RSN_GTK_OUI_OFFSET; + iebody = (struct ie_body *) (((u8 *) bss_desc->bcn_rsn_ie->data) + RSN_GTK_OUI_OFFSET); oui = &mwifiex_rsn_oui[cipher][0]; - ret = mwifiex_search_oui_in_ie(iebody, oui); + ret = mwifiex_search_oui_in_ie(iebody, oui, ie_len); if (ret) return ret; } @@ -169,10 +184,14 @@ mwifiex_is_wpa_oui_present(struct mwifiex_bssdescriptor *bss_desc, u32 cipher) u8 ret = MWIFIEX_OUI_NOT_PRESENT; if (has_vendor_hdr(bss_desc->bcn_wpa_ie, WLAN_EID_VENDOR_SPECIFIC)) { + int ie_len = (int)bss_desc->bcn_wpa_ie->vend_hdr.len - + (int)sizeof(bss_desc->bcn_wpa_ie->vend_hdr.oui) - + WPA_GTK_OUI_OFFSET; + iebody = (struct ie_body *)((u8 *)bss_desc->bcn_wpa_ie->data + WPA_GTK_OUI_OFFSET); oui = &mwifiex_wpa_oui[cipher][0]; - ret = mwifiex_search_oui_in_ie(iebody, oui); + ret = mwifiex_search_oui_in_ie(iebody, oui, ie_len); if (ret) return ret; } @@ -2096,6 +2115,7 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, u32 bytes_left; u32 idx; u32 tlv_buf_size; + size_t fixed_size; struct mwifiex_ie_types_chan_band_list_param_set *chan_band_tlv; struct chan_band_param_set *chan_band; u8 is_bgscan_resp; @@ -2111,6 +2131,14 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, else scan_rsp = &resp->params.scan_resp; + scan_resp_size = le16_to_cpu(resp->size); + fixed_size = scan_rsp->bss_desc_and_tlv_buffer - (u8 *)resp; + if (scan_resp_size < fixed_size) { + mwifiex_dbg(adapter, ERROR, + "SCAN_RESP: response is too short\n"); + ret = -1; + goto check_next_scan; + } if (scan_rsp->number_of_sets > MWIFIEX_MAX_AP) { mwifiex_dbg(adapter, ERROR, @@ -2128,8 +2156,6 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, "info: SCAN_RESP: bss_descript_size %d\n", bytes_left); - scan_resp_size = le16_to_cpu(resp->size); - mwifiex_dbg(adapter, INFO, "info: SCAN_RESP: returned %d APs before parsing\n", scan_rsp->number_of_sets); @@ -2137,15 +2163,17 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv, bss_info = scan_rsp->bss_desc_and_tlv_buffer; /* - * The size of the TLV buffer is equal to the entire command response - * size (scan_resp_size) minus the fixed fields (sizeof()'s), the - * BSS Descriptions (bss_descript_size as bytesLef) and the command - * response header (S_DS_GEN) + * The TLV buffer follows the command-specific fixed fields and the BSS + * descriptions. Background-scan responses have an additional fixed + * field before scan_rsp, which is included in fixed_size. */ - tlv_buf_size = scan_resp_size - (bytes_left - + sizeof(scan_rsp->bss_descript_size) - + sizeof(scan_rsp->number_of_sets) - + S_DS_GEN); + if (bytes_left > scan_resp_size - fixed_size) { + mwifiex_dbg(adapter, ERROR, + "SCAN_RESP: BSS data exceeds response\n"); + ret = -1; + goto check_next_scan; + } + tlv_buf_size = scan_resp_size - fixed_size - bytes_left; tlv_data = (struct mwifiex_ie_types_data *) (scan_rsp-> bss_desc_and_tlv_buffer + diff --git a/drivers/net/wireless/marvell/mwifiex/util.c b/drivers/net/wireless/marvell/mwifiex/util.c index 7d3631d21223..71305efb77ac 100644 --- a/drivers/net/wireless/marvell/mwifiex/util.c +++ b/drivers/net/wireless/marvell/mwifiex/util.c @@ -317,10 +317,16 @@ mwifiex_parse_mgmt_packet(struct mwifiex_private *priv, u8 *payload, u16 len, switch (stype) { case IEEE80211_STYPE_ACTION: - category = *(payload + sizeof(struct ieee80211_hdr)); + if (len < sizeof(*ieee_hdr) + 1) + return -1; + + category = *(payload + sizeof(*ieee_hdr)); switch (category) { case WLAN_CATEGORY_PUBLIC: - action_code = *(payload + sizeof(struct ieee80211_hdr) + if (len < sizeof(*ieee_hdr) + 2) + return -1; + + action_code = *(payload + sizeof(*ieee_hdr) + 1); if (action_code == WLAN_PUB_ACTION_TDLS_DISCOVER_RES) { addr2 = ieee_hdr->addr2; diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c index a118a301564c..40546005c743 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c @@ -477,18 +477,23 @@ static int mt7921_load_clc(struct mt792x_dev *dev, const char *fw_name) for (offset = 0; offset < len; offset += clc_len) { if (len - offset < sizeof(*clc)) { + dev_err(mdev->dev, "Invalid CLC record\n"); ret = -EINVAL; goto out; } clc = (const struct mt7921_clc *)(clc_base + offset); clc_len = le32_to_cpu(clc->len); - if (clc_len < sizeof(*clc) || clc_len > len - offset || - clc->idx >= ARRAY_SIZE(phy->clc)) { + if (clc_len < sizeof(*clc) || clc_len > len - offset) { + dev_err(mdev->dev, "Invalid CLC record\n"); ret = -EINVAL; goto out; } + /* Newer firmware may add records this driver does not use yet */ + if (clc->idx >= ARRAY_SIZE(phy->clc)) + continue; + /* do not init buf again if chip reset triggered */ if (phy->clc[clc->idx]) continue; diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.c b/drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.c index 946dd7956e4a..b468051fbe68 100644 --- a/drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.c +++ b/drivers/net/wireless/mediatek/mt76/mt792x_acpi_sar.c @@ -323,7 +323,8 @@ int mt792x_init_acpi_sar_power(struct mt792x_phy *phy, bool set_default) const struct cfg80211_sar_capa *capa = phy->mt76->hw->wiphy->sar_capa; int i; - if (!phy->acpisar || !((struct mt792x_acpi_sar *)phy->acpisar)->dyn) + if (!capa || !phy->acpisar || + !((struct mt792x_acpi_sar *)phy->acpisar)->dyn) return 0; /* When ACPI SAR enabled in HW, we should apply rules for .frp diff --git a/drivers/net/wireless/microchip/wilc1000/cfg80211.c b/drivers/net/wireless/microchip/wilc1000/cfg80211.c index bb2748a19329..9ad21d41e999 100644 --- a/drivers/net/wireless/microchip/wilc1000/cfg80211.c +++ b/drivers/net/wireless/microchip/wilc1000/cfg80211.c @@ -1058,6 +1058,13 @@ void wilc_wfi_p2p_rx(struct wilc_vif *vif, u8 *buff, u32 size) if (!ieee80211_is_public_action((struct ieee80211_hdr *)buff, size)) goto out_rx_mgmt; + /* ieee80211_is_public_action() only validates up to the category + * byte, so reject frames too short for the P2P public action header + * before dereferencing it or computing size - ie_offset. + */ + if (size < ie_offset) + goto out_rx_mgmt; + d = (struct wilc_p2p_pub_act_frame *)(&mgmt->u.action); if (d->oui_subtype != GO_NEG_REQ && d->oui_subtype != GO_NEG_RSP && d->oui_subtype != P2P_INV_REQ && d->oui_subtype != P2P_INV_RSP) @@ -1200,6 +1207,13 @@ static int mgmt_tx(struct wiphy *wiphy, goto out_set_timeout; } + /* ieee80211_is_public_action() only validates up to the category + * byte, so reject frames too short for the P2P public action header + * before dereferencing it or computing len - ie_offset. + */ + if (len < ie_offset) + goto out_set_timeout; + d = (struct wilc_p2p_pub_act_frame *)(&mgmt->u.action); if (d->oui_type != WLAN_OUI_TYPE_WFA_P2P || d->oui_subtype != GO_NEG_CONF) { diff --git a/drivers/net/wireless/microchip/wilc1000/wlan.c b/drivers/net/wireless/microchip/wilc1000/wlan.c index 4b116fe6f9ea..55a77a2e3288 100644 --- a/drivers/net/wireless/microchip/wilc1000/wlan.c +++ b/drivers/net/wireless/microchip/wilc1000/wlan.c @@ -1197,6 +1197,15 @@ static void wilc_wlan_handle_isr_ext(struct wilc *wilc, u32 int_status) if (size <= 0) return; + /* A size exceeding the RX buffer is bogus; drop the transfer + * instead of overflowing the buffer. + */ + if (size > WILC_RX_BUFF_SIZE) { + wilc->hif_func->hif_clear_int_ext(wilc, + DATA_INT_CLR | ENABLE_RX_VMM); + return; + } + if (WILC_RX_BUFF_SIZE - offset < size) offset = 0; diff --git a/drivers/net/wireless/rsi/rsi_91x_mgmt.c b/drivers/net/wireless/rsi/rsi_91x_mgmt.c index bb167f03367b..d9dcbb255317 100644 --- a/drivers/net/wireless/rsi/rsi_91x_mgmt.c +++ b/drivers/net/wireless/rsi/rsi_91x_mgmt.c @@ -852,8 +852,6 @@ int rsi_hal_load_key(struct rsi_common *common, memcpy(set_key->tx_mic_key, &data[16], 8); memcpy(set_key->rx_mic_key, &data[24], 8); } - } else { - memset(&set_key[FRAME_DESC_SZ], 0, frame_len - FRAME_DESC_SZ); } skb_put(skb, frame_len); diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index 5595f7a1fc0c..edf6ca23c6c3 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -3724,10 +3724,8 @@ void wlcore_regdomain_config(struct wl1271 *wl) goto out; ret = wlcore_cmd_regdomain_config_locked(wl); - if (ret < 0) { + if (ret < 0) wl12xx_queue_recovery_work(wl); - goto out; - } pm_runtime_put_autosuspend(wl->dev); out: diff --git a/drivers/net/wireless/virtual/mac80211_hwsim_main.c b/drivers/net/wireless/virtual/mac80211_hwsim_main.c index 02b6d81cccd1..b9446577ff49 100644 --- a/drivers/net/wireless/virtual/mac80211_hwsim_main.c +++ b/drivers/net/wireless/virtual/mac80211_hwsim_main.c @@ -2327,7 +2327,12 @@ static void mac80211_hwsim_stop(struct ieee80211_hw *hw, bool suspend) struct sk_buff *skb; int i; - data->started = false; + /* + * Serialise against wmediumd userspace, so no more frames + * can be handed to mac80211 after this returns. + */ + scoped_guard(mutex, &data->mutex) + data->started = false; for (i = 0; i < ARRAY_SIZE(data->link_data); i++) hrtimer_cancel(&data->link_data[i].beacon_timer); @@ -6505,12 +6510,12 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2, if (frame_data_len < sizeof(struct ieee80211_hdr_3addr) || frame_data_len > IEEE80211_MAX_DATA_LEN) - goto err; + goto out; /* Allocate new skb here */ skb = alloc_skb(frame_data_len, GFP_KERNEL); if (skb == NULL) - goto err; + goto out; /* Copy the data */ skb_put_data(skb, frame_data, frame_data_len); @@ -6535,10 +6540,17 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2, goto out; } + /* + * Serialise against mac80211_hwsim_stop() - mac80211 doesn't allow + * frames reported while the HW is down, hence the ->started check + * must be under mutex. + */ + mutex_lock(&data2->mutex); + /* check if radio is configured properly */ if ((data2->idle && !data2->tmp_chan) || !data2->started) - goto out; + goto out_unlock; /* A frame is received from user space */ memset(&rx_status, 0, sizeof(rx_status)); @@ -6557,22 +6569,18 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2, iter_data.channel = ieee80211_get_channel(data2->hw->wiphy, rx_status.freq); if (!iter_data.channel) - goto out; + goto out_unlock; rx_status.band = iter_data.channel->band; - mutex_lock(&data2->mutex); if (!hwsim_chans_compat(iter_data.channel, channel)) { ieee80211_iterate_active_interfaces_atomic( data2->hw, IEEE80211_IFACE_ITER_NORMAL, mac80211_hwsim_tx_iter, &iter_data); - if (!iter_data.receive) { - mutex_unlock(&data2->mutex); - goto out; - } + if (!iter_data.receive) + goto out_unlock; } - mutex_unlock(&data2->mutex); } else if (!channel) { - goto out; + goto out_unlock; } else { rx_status.freq = channel->center_freq; rx_status.band = channel->band; @@ -6580,7 +6588,7 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2, rx_status.rate_idx = nla_get_u32(info->attrs[HWSIM_ATTR_RX_RATE]); if (rx_status.rate_idx >= data2->hw->wiphy->bands[rx_status.band]->n_bitrates) - goto out; + goto out_unlock; rx_status.signal = nla_get_u32(info->attrs[HWSIM_ATTR_SIGNAL]); hdr = (void *)skb->data; @@ -6590,10 +6598,11 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2, rx_status.boottime_ns = ktime_get_boottime_ns(); mac80211_hwsim_rx(data2, &rx_status, skb); + mutex_unlock(&data2->mutex); return 0; -err: - pr_debug("mac80211_hwsim: error occurred in %s\n", __func__); +out_unlock: + mutex_unlock(&data2->mutex); out: dev_kfree_skb(skb); return -EINVAL; diff --git a/drivers/net/wireless/virtual/virt_wifi.c b/drivers/net/wireless/virtual/virt_wifi.c index 2335e45db8b8..48afc2432f93 100644 --- a/drivers/net/wireless/virtual/virt_wifi.c +++ b/drivers/net/wireless/virtual/virt_wifi.c @@ -434,6 +434,7 @@ static netdev_tx_t virt_wifi_start_xmit(struct sk_buff *skb, priv->tx_packets++; if (!priv->is_connected) { priv->tx_failed++; + dev_kfree_skb_any(skb); return NET_XMIT_DROP; } @@ -557,7 +558,6 @@ static int virt_wifi_newlink(struct net_device *dev, } eth_hw_addr_inherit(dev, priv->lowerdev); - netif_stacked_transfer_operstate(priv->lowerdev, dev); dev->ieee80211_ptr = kzalloc_obj(*dev->ieee80211_ptr); @@ -583,6 +583,8 @@ static int virt_wifi_newlink(struct net_device *dev, goto unregister_netdev; } + netif_stacked_transfer_operstate(priv->lowerdev, dev); + dev->priv_destructor = virt_wifi_net_device_destructor; priv->being_deleted = false; priv->is_connected = false; diff --git a/drivers/net/wwan/mhi_wwan_mbim.c b/drivers/net/wwan/mhi_wwan_mbim.c index a94998712597..336f89756f10 100644 --- a/drivers/net/wwan/mhi_wwan_mbim.c +++ b/drivers/net/wwan/mhi_wwan_mbim.c @@ -251,6 +251,14 @@ static int mbim_rx_verify_ndp16(struct sk_buff *skb, struct usb_cdc_ncm_ndp16 *n return ret; } +static void mhi_mbim_rx_drop(struct mhi_mbim_link *link, struct sk_buff *skb) +{ + dev_kfree_skb_any(skb); + u64_stats_update_begin(&link->rx_syncp); + u64_stats_inc(&link->rx_errors); + u64_stats_update_end(&link->rx_syncp); +} + static void mhi_mbim_rx(struct mhi_mbim_context *mbim, struct sk_buff *skb) { int ndpoffset; @@ -320,7 +328,10 @@ static void mhi_mbim_rx(struct mhi_mbim_context *mbim, struct sk_buff *skb) continue; skb_put(skbn, dgram_len); - skb_copy_bits(skb, dgram_offset, skbn->data, dgram_len); + if (skb_copy_bits(skb, dgram_offset, skbn->data, dgram_len)) { + mhi_mbim_rx_drop(link, skbn); + continue; + } switch (skbn->data[0] & 0xf0) { case 0x40: @@ -332,10 +343,7 @@ static void mhi_mbim_rx(struct mhi_mbim_context *mbim, struct sk_buff *skb) default: net_err_ratelimited("%s: unknown protocol\n", link->ndev->name); - dev_kfree_skb_any(skbn); - u64_stats_update_begin(&link->rx_syncp); - u64_stats_inc(&link->rx_errors); - u64_stats_update_end(&link->rx_syncp); + mhi_mbim_rx_drop(link, skbn); continue; } @@ -349,9 +357,13 @@ static void mhi_mbim_rx(struct mhi_mbim_context *mbim, struct sk_buff *skb) unlock: rcu_read_unlock(); next_ndp: - /* Other NDP to process? */ - ndpoffset = (int)le16_to_cpu(ndp16.wNextNdpIndex); - if (!ndpoffset) + /* Other NDP to process? The offsets must advance, or a + * self-referencing NDP keeps the loop spinning forever. + */ + n = (int)le16_to_cpu(ndp16.wNextNdpIndex); + if (n > ndpoffset) + ndpoffset = n; + else break; } diff --git a/drivers/net/wwan/t7xx/t7xx_netdev.c b/drivers/net/wwan/t7xx/t7xx_netdev.c index fc0a7cb181df..8f32c2d26931 100644 --- a/drivers/net/wwan/t7xx/t7xx_netdev.c +++ b/drivers/net/wwan/t7xx/t7xx_netdev.c @@ -420,6 +420,10 @@ static void t7xx_ccmni_recv_skb(struct t7xx_ccmni_ctrl *ccmni_ctlb, struct sk_bu skb_cb = T7XX_SKB_CB(skb); netif_id = skb_cb->netif_idx; + if (netif_id >= NIC_DEV_MAX) { + dev_kfree_skb(skb); + return; + } ccmni = READ_ONCE(ccmni_ctlb->ccmni_inst[netif_id]); if (!ccmni) { dev_kfree_skb(skb); diff --git a/drivers/opp/core.c b/drivers/opp/core.c index 2fafd983de8f..4ccce7b6afcb 100644 --- a/drivers/opp/core.c +++ b/drivers/opp/core.c @@ -453,8 +453,8 @@ int dev_pm_opp_get_opp_count(struct device *dev) _find_opp_table(dev); if (IS_ERR(opp_table)) { - dev_dbg(dev, "%s: OPP table not found (%ld)\n", - __func__, PTR_ERR(opp_table)); + dev_dbg(dev, "%s: OPP table not found (%pe)\n", + __func__, opp_table); return PTR_ERR(opp_table); } @@ -611,8 +611,8 @@ _find_key(struct device *dev, unsigned long *key, int index, bool available, _find_opp_table(dev); if (IS_ERR(opp_table)) { - dev_err(dev, "%s: OPP table not found (%ld)\n", __func__, - PTR_ERR(opp_table)); + dev_err(dev, "%s: OPP table not found (%pe)\n", __func__, + opp_table); return ERR_CAST(opp_table); } @@ -722,8 +722,8 @@ struct dev_pm_opp *dev_pm_opp_find_key_exact(struct device *dev, struct opp_table *opp_table __free(put_opp_table) = _find_opp_table(dev); if (IS_ERR(opp_table)) { - dev_err(dev, "%s: OPP table not found (%ld)\n", __func__, - PTR_ERR(opp_table)); + dev_err(dev, "%s: OPP table not found (%pe)\n", __func__, + opp_table); return ERR_CAST(opp_table); } @@ -1036,8 +1036,8 @@ static int _set_opp_voltage(struct device *dev, struct regulator *reg, /* Regulator not available for device */ if (IS_ERR(reg)) { - dev_dbg(dev, "%s: regulator not available: %ld\n", __func__, - PTR_ERR(reg)); + dev_dbg(dev, "%s: regulator not available: %pe\n", __func__, + reg); return 0; } @@ -1448,8 +1448,8 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq) temp_freq = freq; opp = _find_freq_ceil(opp_table, &temp_freq); if (IS_ERR(opp)) { - dev_err(dev, "%s: failed to find OPP for freq %lu (%ld)\n", - __func__, freq, PTR_ERR(opp)); + dev_err(dev, "%s: failed to find OPP for freq %lu (%pe)\n", + __func__, freq, opp); return PTR_ERR(opp); } @@ -1581,6 +1581,8 @@ static struct opp_table *_update_opp_table_clk(struct device *dev, struct opp_table *opp_table, bool getclk) { + int ret; + /* * Return early if we don't need to get clk or we have already done it * earlier. @@ -1607,9 +1609,9 @@ static struct opp_table *_update_opp_table_clk(struct device *dev, opp_table->clk = clk_get_optional(dev, NULL); if (IS_ERR(opp_table->clk)) { + ret = dev_err_probe(dev, PTR_ERR(opp_table->clk), "Couldn't find clock\n"); dev_pm_opp_put_opp_table(opp_table); - dev_err_probe(dev, PTR_ERR(opp_table->clk), "Couldn't find clock\n"); - return ERR_CAST(opp_table->clk); + return ERR_PTR(ret); } if (opp_table->clk) @@ -2869,8 +2871,8 @@ static int _opp_set_availability(struct device *dev, unsigned long freq, struct dev_pm_opp *opp __free(put_opp) = ERR_PTR(-ENODEV), *tmp_opp; if (IS_ERR(opp_table)) { - dev_warn(dev, "%s: Device OPP not found (%ld)\n", __func__, - PTR_ERR(opp_table)); + dev_warn(dev, "%s: Device OPP not found (%pe)\n", __func__, + opp_table); return PTR_ERR(opp_table); } diff --git a/drivers/opp/of.c b/drivers/opp/of.c index c02e20632fa6..2f3bbde9a9e1 100644 --- a/drivers/opp/of.c +++ b/drivers/opp/of.c @@ -1039,7 +1039,7 @@ static int _of_add_opp_table_v1(struct device *dev, struct opp_table *opp_table) val = prop->value; while (nr) { - unsigned long freq = be32_to_cpup(val++) * 1000; + unsigned long freq = (unsigned long)be32_to_cpup(val++) * 1000; unsigned long volt = be32_to_cpup(val++); struct dev_pm_opp_data data = { .freq = freq, @@ -1345,8 +1345,8 @@ int of_get_required_opp_performance_state(struct device_node *np, int index) _find_table_of_opp_np(required_np); if (IS_ERR(opp_table)) { - pr_err("%s: Failed to find required OPP table %pOF: %ld\n", - __func__, np, PTR_ERR(opp_table)); + pr_err("%s: Failed to find required OPP table %pOF: %pe\n", + __func__, np, opp_table); return PTR_ERR(opp_table); } diff --git a/drivers/perf/riscv_pmu_legacy.c b/drivers/perf/riscv_pmu_legacy.c index 4d6461d6a74f..1b8e4789cb3c 100644 --- a/drivers/perf/riscv_pmu_legacy.c +++ b/drivers/perf/riscv_pmu_legacy.c @@ -110,8 +110,9 @@ static void pmu_legacy_init(struct riscv_pmu *pmu) { pr_info("Legacy PMU implementation is available\n"); - pmu->cmask = BIT(RISCV_PMU_LEGACY_CYCLE) | - BIT(RISCV_PMU_LEGACY_INSTRET); + bitmap_zero(pmu->cmask, RISCV_MAX_COUNTERS); + set_bit(RISCV_PMU_LEGACY_CYCLE, pmu->cmask); + set_bit(RISCV_PMU_LEGACY_INSTRET, pmu->cmask); pmu->ctr_start = pmu_legacy_ctr_start; pmu->ctr_stop = NULL; pmu->event_map = pmu_legacy_event_map; diff --git a/drivers/perf/riscv_pmu_sbi.c b/drivers/perf/riscv_pmu_sbi.c index 50220f7b46d9..2991dd92def2 100644 --- a/drivers/perf/riscv_pmu_sbi.c +++ b/drivers/perf/riscv_pmu_sbi.c @@ -97,7 +97,7 @@ static unsigned int riscv_pmu_irq_mask; static unsigned int riscv_pmu_irq; /* Cache the available counters in a bitmask */ -static unsigned long cmask; +static DECLARE_BITMAP(cmask, RISCV_MAX_COUNTERS); static int pmu_event_find_cache(u64 config); struct sbi_pmu_event_data { @@ -359,16 +359,38 @@ free_mem: return result; } +static struct sbiret pmu_sbi_ctr_cfg_match(unsigned long cbase, + unsigned long ctr_mask, + unsigned long cflags, + unsigned long event_idx, + u64 config) +{ +#if defined(CONFIG_32BIT) + return sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_COUNTER_CFG_MATCH, cbase, + ctr_mask, cflags, event_idx, config, config >> 32); +#else + return sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_COUNTER_CFG_MATCH, cbase, + ctr_mask, cflags, event_idx, config, 0); +#endif +} + static void pmu_sbi_check_event(struct sbi_pmu_event_data *edata) { - struct sbiret ret; + struct sbiret ret = { .error = SBI_ERR_NOT_SUPPORTED }; + int i; - ret = sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_COUNTER_CFG_MATCH, - 0, cmask, 0, edata->event_idx, 0, 0); - if (!ret.error) { - sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_COUNTER_STOP, - ret.value, 0x1, SBI_PMU_STOP_FLAG_RESET, 0, 0, 0); - } else if (ret.error == SBI_ERR_NOT_SUPPORTED) { + for (i = 0; i < BITS_TO_LONGS(RISCV_MAX_COUNTERS); i++) { + if (!cmask[i]) + continue; + ret = pmu_sbi_ctr_cfg_match(i * BITS_PER_LONG, cmask[i], 0, + edata->event_idx, 0); + if (!ret.error) { + sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_COUNTER_STOP, + ret.value, 0x1, SBI_PMU_STOP_FLAG_RESET, 0, 0, 0); + return; + } + } + if (ret.error == SBI_ERR_NOT_SUPPORTED) { /* This event cannot be monitored by any counter */ edata->event_idx = -ENOENT; } @@ -488,10 +510,10 @@ int riscv_pmu_get_hpm_info(u32 *hw_ctr_width, u32 *num_hw_ctr) union sbi_pmu_ctr_info *info; u32 hpm_width = 0, hpm_count = 0; - if (!cmask) + if (bitmap_empty(cmask, RISCV_MAX_COUNTERS)) return -EINVAL; - for_each_set_bit(i, &cmask, RISCV_MAX_COUNTERS) { + for_each_set_bit(i, cmask, RISCV_MAX_COUNTERS) { info = &pmu_ctr_list[i]; if (!info) continue; @@ -540,8 +562,8 @@ static int pmu_sbi_ctr_get_idx(struct perf_event *event) struct riscv_pmu *rvpmu = to_riscv_pmu(event->pmu); struct cpu_hw_events *cpuc = this_cpu_ptr(rvpmu->hw_events); struct sbiret ret; - int idx; - uint64_t cbase = 0, cmask = rvpmu->cmask; + int idx, i; + u64 cbase = 0, cmask = 0; unsigned long cflags = 0; cflags = pmu_sbi_get_filter_flags(event); @@ -562,14 +584,21 @@ static int pmu_sbi_ctr_get_idx(struct perf_event *event) } /* retrieve the available counter index */ -#if defined(CONFIG_32BIT) - ret = sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_COUNTER_CFG_MATCH, cbase, - cmask, cflags, hwc->event_base, hwc->config, - hwc->config >> 32); -#else - ret = sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_COUNTER_CFG_MATCH, cbase, - cmask, cflags, hwc->event_base, hwc->config, 0); -#endif + if (cmask) { + ret = pmu_sbi_ctr_cfg_match(cbase, cmask, cflags, hwc->event_base, + hwc->config); + } else { + ret.error = SBI_ERR_NOT_SUPPORTED; + for (i = 0; i < BITS_TO_LONGS(RISCV_MAX_COUNTERS); i++) { + if (!rvpmu->cmask[i]) + continue; + cbase = i * BITS_PER_LONG; + ret = pmu_sbi_ctr_cfg_match(cbase, rvpmu->cmask[i], cflags, + hwc->event_base, hwc->config); + if (!ret.error) + break; + } + } if (ret.error) { pr_debug("Not able to find a counter for event %lx config %llx\n", hwc->event_base, hwc->config); @@ -577,7 +606,7 @@ static int pmu_sbi_ctr_get_idx(struct perf_event *event) } idx = ret.value; - if (!test_bit(idx, &rvpmu->cmask) || !pmu_ctr_list[idx].value) + if (!test_bit(idx, rvpmu->cmask) || !pmu_ctr_list[idx].value) return -ENOENT; /* Additional sanity check for the counter id */ @@ -881,7 +910,7 @@ static int pmu_sbi_get_ctrinfo(int nctr, unsigned long *mask) /* The logical counter ids are not expected to be contiguous */ continue; - *mask |= BIT(i); + set_bit(i, mask); cinfo.value = ret.value; if (cinfo.type == SBI_PMU_CTR_TYPE_FW) @@ -898,12 +927,19 @@ static int pmu_sbi_get_ctrinfo(int nctr, unsigned long *mask) static inline void pmu_sbi_stop_all(struct riscv_pmu *pmu) { + int i; + /* * No need to check the error because we are disabling all the counters * which may include counters that are not enabled yet. */ - sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_COUNTER_STOP, - 0, pmu->cmask, SBI_PMU_STOP_FLAG_RESET, 0, 0, 0); + for (i = 0; i < BITS_TO_LONGS(RISCV_MAX_COUNTERS); i++) { + if (!pmu->cmask[i]) + continue; + sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_COUNTER_STOP, + i * BITS_PER_LONG, pmu->cmask[i], + SBI_PMU_STOP_FLAG_RESET, 0, 0, 0); + } } static inline void pmu_sbi_stop_hw_ctrs(struct riscv_pmu *pmu) @@ -1002,7 +1038,7 @@ static inline void pmu_sbi_start_ovf_ctrs_snapshot(struct cpu_hw_events *cpu_hw_ struct riscv_pmu_snapshot_data *sdata = cpu_hw_evt->snapshot_addr; for_each_set_bit(idx, cpu_hw_evt->used_hw_ctrs, RISCV_MAX_COUNTERS) { - if (ctr_ovf_mask & BIT(idx)) { + if (ctr_ovf_mask & BIT_ULL(idx)) { event = cpu_hw_evt->events[idx]; hwc = &event->hw; max_period = riscv_pmu_ctr_get_width_mask(event); @@ -1050,11 +1086,13 @@ static irqreturn_t pmu_sbi_ovf_handler(int irq, void *dev) u64 overflowed_ctrs = 0; struct cpu_hw_events *cpu_hw_evt = dev; u64 start_clock = sched_clock(); - struct riscv_pmu_snapshot_data *sdata = cpu_hw_evt->snapshot_addr; + struct riscv_pmu_snapshot_data *sdata; if (WARN_ON_ONCE(!cpu_hw_evt)) return IRQ_NONE; + sdata = cpu_hw_evt->snapshot_addr; + /* Firmware counter don't support overflow yet */ fidx = find_first_bit(cpu_hw_evt->used_hw_ctrs, RISCV_MAX_COUNTERS); if (fidx == RISCV_MAX_COUNTERS) { @@ -1109,14 +1147,14 @@ static irqreturn_t pmu_sbi_ovf_handler(int irq, void *dev) hidx = info->csr - CSR_CYCLE; /* check if the corresponding bit is set in scountovf or overflow mask in shmem */ - if (!(overflow & BIT(hidx))) + if (!(overflow & BIT_ULL(hidx))) continue; /* * Keep a track of overflowed counters so that they can be started * with updated initial value. */ - overflowed_ctrs |= BIT(lidx); + overflowed_ctrs |= BIT_ULL(lidx); hw_evt = &event->hw; /* Update the event states here so that we know the state while reading */ hw_evt->state |= PERF_HES_STOPPED; @@ -1451,7 +1489,7 @@ static int pmu_sbi_device_probe(struct platform_device *pdev) } /* cache all the information about counters now */ - if (pmu_sbi_get_ctrinfo(num_counters, &cmask)) + if (pmu_sbi_get_ctrinfo(num_counters, cmask)) goto out_free; ret = pmu_sbi_setup_irqs(pmu, pdev); @@ -1464,7 +1502,7 @@ static int pmu_sbi_device_probe(struct platform_device *pdev) pmu->pmu.attr_groups = riscv_pmu_attr_groups; pmu->pmu.parent = &pdev->dev; - pmu->cmask = cmask; + bitmap_copy(pmu->cmask, cmask, RISCV_MAX_COUNTERS); pmu->ctr_start = pmu_sbi_ctr_start; pmu->ctr_stop = pmu_sbi_ctr_stop; pmu->event_map = pmu_sbi_event_map; diff --git a/drivers/platform/x86/amd/pmf/spc.c b/drivers/platform/x86/amd/pmf/spc.c index 94355b435a66..592ba4de4c7f 100644 --- a/drivers/platform/x86/amd/pmf/spc.c +++ b/drivers/platform/x86/amd/pmf/spc.c @@ -17,7 +17,6 @@ #include <linux/units.h> #include "pmf.h" -#ifdef CONFIG_AMD_PMF_DEBUG u32 amd_pmf_get_ta_custom_bios_inputs(struct ta_pmf_enact_table *in, int index) { switch (index) { @@ -31,6 +30,7 @@ u32 amd_pmf_get_ta_custom_bios_inputs(struct ta_pmf_enact_table *in, int index) } EXPORT_SYMBOL(amd_pmf_get_ta_custom_bios_inputs); +#ifdef CONFIG_AMD_PMF_DEBUG void amd_pmf_dump_ta_inputs(struct amd_pmf_dev *dev, struct ta_pmf_enact_table *in) { int i; diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index 449addd1ac7a..79a575d0f5b4 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c @@ -1882,7 +1882,7 @@ static int asus_acpi_probe(struct platform_device *pdev) if (result && result != -ENODEV) goto fail_pega_rfkill; - result = acpi_dev_install_notify_handler(device, ACPI_DEVICE_NOTIFY, + result = acpi_dev_install_notify_handler(device, ACPI_ALL_NOTIFY, asus_acpi_notify, asus); if (result) goto fail_pega_rfkill; @@ -1912,7 +1912,7 @@ static void asus_acpi_remove(struct platform_device *pdev) { struct asus_laptop *asus = platform_get_drvdata(pdev); - acpi_dev_remove_notify_handler(asus->device, ACPI_DEVICE_NOTIFY, + acpi_dev_remove_notify_handler(asus->device, ACPI_ALL_NOTIFY, asus_acpi_notify); asus_backlight_exit(asus); asus_rfkill_exit(asus); diff --git a/drivers/platform/x86/hp/hp-wmi.c b/drivers/platform/x86/hp/hp-wmi.c index b2773fc1aca4..615b4cf6fc45 100644 --- a/drivers/platform/x86/hp/hp-wmi.c +++ b/drivers/platform/x86/hp/hp-wmi.c @@ -337,7 +337,7 @@ static const struct dmi_system_id hp_wmi_feature_boards[] __initconst = { }, { .matches = { DMI_MATCH(DMI_BOARD_NAME, "8DD6") }, - .driver_data = (void *)&omen_v1_no_ec_thermal_params, + .driver_data = (void *)&omen_v1_no_ec_board_params, }, { .matches = { DMI_MATCH(DMI_BOARD_NAME, "8E35") }, diff --git a/drivers/platform/x86/x86-android-tablets/core.c b/drivers/platform/x86/x86-android-tablets/core.c index 5db794d65eb5..cfff7f5eac5d 100644 --- a/drivers/platform/x86/x86-android-tablets/core.c +++ b/drivers/platform/x86/x86-android-tablets/core.c @@ -156,7 +156,6 @@ static struct platform_device **pdevs; static struct serdev_device **serdevs; static const struct software_node **gpio_button_swnodes; static const struct software_node **swnode_group; -static const struct software_node **gpiochip_node_group; static void (*exit_handler)(void); static __init struct i2c_adapter * @@ -362,11 +361,21 @@ static const struct software_node *cherryview_gpiochip_node_group[] = { NULL }; +const struct software_node crystalcove_gpiochip_node = { + .name = "INT33FD:00", +}; + +static const struct software_node *crystalcove_gpiochip_node_group[] = { + &crystalcove_gpiochip_node, + NULL +}; + static void gpio_secondary_unset(void *data) { struct device *dev = data; set_secondary_fwnode(dev, NULL); + put_device(dev); } static void gpio_secondary_unregister_node_group(void *data) @@ -376,26 +385,28 @@ static void gpio_secondary_unregister_node_group(void *data) software_node_unregister_node_group(nodes); } -static int gpio_secondary_fwnode_init(struct device *parent) +static int gpio_secondary_fwnode_init(struct device *parent, + const struct software_node * const *node_group) { const struct software_node *const *swnode; struct fwnode_handle *fwnode; + struct device *phys_dev; int ret; - if (!gpiochip_node_group) + if (!node_group) return 0; - ret = software_node_register_node_group(gpiochip_node_group); + ret = software_node_register_node_group(node_group); if (ret) return ret; ret = devm_add_action_or_reset(parent, gpio_secondary_unregister_node_group, - gpiochip_node_group); + (void *)node_group); if (ret) return ret; - for (swnode = gpiochip_node_group; *swnode; swnode++) { + for (swnode = node_group; *swnode; swnode++) { struct device *dev __free(put_device) = acpi_bus_find_device_by_name((*swnode)->name); if (!dev) @@ -407,9 +418,15 @@ static int gpio_secondary_fwnode_init(struct device *parent) if (WARN_ON(!fwnode)) return -ENOENT; - set_secondary_fwnode(dev, fwnode); + phys_dev = acpi_get_first_physical_node(to_acpi_device(dev)); + if (!phys_dev) + return dev_err_probe(parent, -ENODEV, + "No physical device for ACPI GPIO dev: %pfwP\n", + fwnode); + + set_secondary_fwnode(phys_dev, fwnode); - ret = devm_add_action_or_reset(parent, gpio_secondary_unset, dev); + ret = devm_add_action_or_reset(parent, gpio_secondary_unset, get_device(phys_dev)); if (ret) return ret; } @@ -452,6 +469,7 @@ static void x86_android_tablet_remove(struct platform_device *pdev) static __init int x86_android_tablet_probe(struct platform_device *pdev) { + const struct software_node * const *gpiochip_node_group; const struct x86_dev_info *dev_info; const struct dmi_system_id *id; int i, ret = 0; @@ -483,12 +501,20 @@ static __init int x86_android_tablet_probe(struct platform_device *pdev) break; } - ret = gpio_secondary_fwnode_init(&pdev->dev); + ret = gpio_secondary_fwnode_init(&pdev->dev, gpiochip_node_group); if (ret) { x86_android_tablet_remove(pdev); return ret; } + if (dev_info->has_crystalcove) { + ret = gpio_secondary_fwnode_init(&pdev->dev, crystalcove_gpiochip_node_group); + if (ret) { + x86_android_tablet_remove(pdev); + return ret; + } + } + ret = software_node_register_node_group(dev_info->swnode_group); if (ret) { x86_android_tablet_remove(pdev); diff --git a/drivers/platform/x86/x86-android-tablets/lenovo.c b/drivers/platform/x86/x86-android-tablets/lenovo.c index 8d825e0b4661..52d96ae89078 100644 --- a/drivers/platform/x86/x86-android-tablets/lenovo.c +++ b/drivers/platform/x86/x86-android-tablets/lenovo.c @@ -61,13 +61,6 @@ static struct lp855x_platform_data lenovo_lp8557_reg_only_pdata = { .initial_brightness = 128, }; -static const struct software_node arizona_gpiochip_node = { - .name = "arizona", -}; - -static const struct software_node crystalcove_gpiochip_node = { - .name = "gpio_crystalcove", -}; /* Lenovo Yoga Book X90F / X90L's Android factory image has everything hardcoded */ @@ -416,15 +409,17 @@ static const struct platform_device_info lenovo_yoga_tab2_830_1050_pdevs[] __ini #define LENOVO_YOGA_TAB2_830_1050_CODEC_NAME "spi-10WM5102:00" +static const struct software_node lenovo_yoga_tab2_830_1050_wm5102; + static const struct property_entry lenovo_yoga_tab2_830_1050_wm1502_props[] = { PROPERTY_ENTRY_GPIO("reset-gpios", &crystalcove_gpiochip_node, 3, GPIO_ACTIVE_HIGH), PROPERTY_ENTRY_GPIO("wlf,ldoena-gpios", &baytrail_gpiochip_nodes[1], 23, GPIO_ACTIVE_HIGH), PROPERTY_ENTRY_GPIO("wlf,spkvdd-ena-gpios", - &arizona_gpiochip_node, 2, GPIO_ACTIVE_HIGH), + &lenovo_yoga_tab2_830_1050_wm5102, 2, GPIO_ACTIVE_HIGH), PROPERTY_ENTRY_GPIO("wlf,micd-pol-gpios", - &arizona_gpiochip_node, 4, GPIO_ACTIVE_LOW), + &lenovo_yoga_tab2_830_1050_wm5102, 4, GPIO_ACTIVE_LOW), { } }; @@ -432,14 +427,6 @@ static const struct software_node lenovo_yoga_tab2_830_1050_wm5102 = { .properties = lenovo_yoga_tab2_830_1050_wm1502_props, }; -static const struct software_node *lenovo_yoga_tab2_830_1050_swnodes[] = { - &crystalcove_gpiochip_node, - &arizona_gpiochip_node, - &lenovo_yoga_tab2_830_1050_wm5102, - &generic_lipo_hv_4v35_battery_node, - NULL -}; - static int __init lenovo_yoga_tab2_830_1050_init(struct device *dev); static void lenovo_yoga_tab2_830_1050_exit(void); @@ -455,8 +442,9 @@ const struct x86_dev_info lenovo_yoga_tab2_830_1050_info __initconst = { .pdev_info = lenovo_yoga_tab2_830_1050_pdevs, .pdev_count = ARRAY_SIZE(lenovo_yoga_tab2_830_1050_pdevs), .gpio_button_swnodes = lenovo_yoga_tab2_830_1050_lid_swnodes, - .swnode_group = lenovo_yoga_tab2_830_1050_swnodes, + .swnode_group = generic_lipo_hv_4v35_battery_swnodes, .modules = lenovo_yoga_tab2_modules, + .has_crystalcove = true, .gpiochip_type = X86_GPIOCHIP_BAYTRAIL, .init = lenovo_yoga_tab2_830_1050_init, .exit = lenovo_yoga_tab2_830_1050_exit, @@ -800,8 +788,9 @@ const struct x86_dev_info lenovo_yoga_tab2_1380_info __initconst = { .pdev_info = lenovo_yoga_tab2_1380_pdevs, .pdev_count = ARRAY_SIZE(lenovo_yoga_tab2_1380_pdevs), .gpio_button_swnodes = lenovo_yoga_tab2_830_1050_lid_swnodes, - .swnode_group = lenovo_yoga_tab2_830_1050_swnodes, + .swnode_group = generic_lipo_hv_4v35_battery_swnodes, .modules = lenovo_yoga_tab2_modules, + .has_crystalcove = true, .gpiochip_type = X86_GPIOCHIP_BAYTRAIL, .init = lenovo_yoga_tab2_1380_init, .exit = lenovo_yoga_tab2_830_1050_exit, @@ -985,13 +974,15 @@ static struct arizona_pdata lenovo_yt3_wm5102_pdata = { }, }; +static const struct software_node lenovo_yt3_wm5102; + static const struct property_entry lenovo_yt3_wm1502_props[] = { PROPERTY_ENTRY_GPIO("wlf,spkvdd-ena-gpios", &cherryview_gpiochip_nodes[0], 75, GPIO_ACTIVE_HIGH), PROPERTY_ENTRY_GPIO("wlf,ldoena-gpios", &cherryview_gpiochip_nodes[0], 81, GPIO_ACTIVE_HIGH), PROPERTY_ENTRY_GPIO("reset-gpios", &cherryview_gpiochip_nodes[0], 82, GPIO_ACTIVE_HIGH), - PROPERTY_ENTRY_GPIO("wlf,micd-pol-gpios", &arizona_gpiochip_node, 2, GPIO_ACTIVE_HIGH), + PROPERTY_ENTRY_GPIO("wlf,micd-pol-gpios", &lenovo_yt3_wm5102, 2, GPIO_ACTIVE_HIGH), { } }; @@ -1000,11 +991,6 @@ static const struct software_node lenovo_yt3_wm5102 = { .name = "wm5102", }; -static const struct software_node *lenovo_yt3_swnodes[] = { - &arizona_gpiochip_node, - &lenovo_yt3_wm5102, - NULL -}; static const struct x86_spi_dev_info lenovo_yt3_spi_devs[] __initconst = { { @@ -1072,7 +1058,6 @@ const struct x86_dev_info lenovo_yt3_info __initconst = { .i2c_client_count = ARRAY_SIZE(lenovo_yt3_i2c_clients), .spi_dev_info = lenovo_yt3_spi_devs, .spi_dev_count = ARRAY_SIZE(lenovo_yt3_spi_devs), - .swnode_group = lenovo_yt3_swnodes, .modules = lenovo_yt3_modules, .gpiochip_type = X86_GPIOCHIP_CHERRYVIEW, .init = lenovo_yt3_init, diff --git a/drivers/platform/x86/x86-android-tablets/x86-android-tablets.h b/drivers/platform/x86/x86-android-tablets/x86-android-tablets.h index c756961ae5fd..6e6534f8fa6c 100644 --- a/drivers/platform/x86/x86-android-tablets/x86-android-tablets.h +++ b/drivers/platform/x86/x86-android-tablets/x86-android-tablets.h @@ -96,6 +96,7 @@ struct x86_dev_info { int (*init)(struct device *dev); void (*exit)(void); bool use_pci; + bool has_crystalcove; enum x86_gpiochip_type gpiochip_type; }; @@ -107,6 +108,7 @@ int x86_acpi_irq_helper_get(const struct x86_acpi_irq_data *data); /* Software nodes representing GPIO chips used by various tablets */ extern const struct software_node baytrail_gpiochip_nodes[]; extern const struct software_node cherryview_gpiochip_nodes[]; +extern const struct software_node crystalcove_gpiochip_node; /* * Extern declarations of x86_dev_info structs so there can be a single diff --git a/drivers/power/sequencing/Kconfig b/drivers/power/sequencing/Kconfig index 1c5f5820f5b7..226c62704d9b 100644 --- a/drivers/power/sequencing/Kconfig +++ b/drivers/power/sequencing/Kconfig @@ -29,7 +29,8 @@ config POWER_SEQUENCING_QCOM_WCN config POWER_SEQUENCING_TH1520_GPU tristate "T-HEAD TH1520 GPU power sequencing driver" - depends on (ARCH_THEAD && AUXILIARY_BUS) || COMPILE_TEST + depends on ARCH_THEAD || COMPILE_TEST + select AUXILIARY_BUS help Say Y here to enable the power sequencing driver for the TH1520 SoC GPU. This driver handles the complex clock and reset sequence diff --git a/drivers/power/sequencing/core.c b/drivers/power/sequencing/core.c index 0cb71efbb268..3076b3879af9 100644 --- a/drivers/power/sequencing/core.c +++ b/drivers/power/sequencing/core.c @@ -101,6 +101,7 @@ static struct pwrseq_unit *pwrseq_unit_new(const struct pwrseq_unit_data *data) } kref_init(&unit->ref); + INIT_LIST_HEAD(&unit->list); INIT_LIST_HEAD(&unit->deps); unit->enable = data->enable; unit->disable = data->disable; @@ -504,10 +505,6 @@ pwrseq_device_register(const struct pwrseq_config *config) */ device_initialize(&pwrseq->dev); - ret = dev_set_name(&pwrseq->dev, "pwrseq.%d", pwrseq->id); - if (ret) - goto err_put_pwrseq; - pwrseq->owner = config->owner ?: THIS_MODULE; pwrseq->match = config->match; @@ -516,6 +513,10 @@ pwrseq_device_register(const struct pwrseq_config *config) INIT_LIST_HEAD(&pwrseq->targets); INIT_LIST_HEAD(&pwrseq->units); + ret = dev_set_name(&pwrseq->dev, "pwrseq.%d", pwrseq->id); + if (ret) + goto err_put_pwrseq; + ret = pwrseq_setup_targets(config->targets, pwrseq); if (ret) goto err_put_pwrseq; @@ -912,6 +913,8 @@ int pwrseq_enable(struct pwrseq_desc *desc) if (!ret) desc->powered_on = true; } + if (ret) + return ret; if (target->post_enable) { ret = target->post_enable(pwrseq); diff --git a/drivers/regulator/pf1550-regulator.c b/drivers/regulator/pf1550-regulator.c index 610eac9bb9cb..ceee553a84b2 100644 --- a/drivers/regulator/pf1550-regulator.c +++ b/drivers/regulator/pf1550-regulator.c @@ -283,63 +283,61 @@ static struct pf1550_desc pf1550_regulators[] = { PF_LDO1(PF1550, "ldo3", LDO3, 0x1f, pf1550_ldo13_volts), }; +/* + * The _LS interrupts indicate an over-current event. The _HS + * interrupts, which are more accurate and can detect catastrophic + * faults, issue an error event. The current limit FAULT interrupt is + * similar to the _HS. + */ +static const struct pf1550_regulator_irq { + unsigned int event; + u8 id; +} pf1550_regulator_irqs[] = { + [PF1550_PMIC_IRQ_SW1_LS] = { REGULATOR_EVENT_OVER_CURRENT_WARN, PF1550_SW1 }, + [PF1550_PMIC_IRQ_SW2_LS] = { REGULATOR_EVENT_OVER_CURRENT_WARN, PF1550_SW2 }, + [PF1550_PMIC_IRQ_SW3_LS] = { REGULATOR_EVENT_OVER_CURRENT_WARN, PF1550_SW3 }, + [PF1550_PMIC_IRQ_SW1_HS] = { REGULATOR_EVENT_OVER_CURRENT, PF1550_SW1 }, + [PF1550_PMIC_IRQ_SW2_HS] = { REGULATOR_EVENT_OVER_CURRENT, PF1550_SW2 }, + [PF1550_PMIC_IRQ_SW3_HS] = { REGULATOR_EVENT_OVER_CURRENT, PF1550_SW3 }, + [PF1550_PMIC_IRQ_LDO1_FAULT] = { REGULATOR_EVENT_OVER_CURRENT, PF1550_LDO1 }, + [PF1550_PMIC_IRQ_LDO2_FAULT] = { REGULATOR_EVENT_OVER_CURRENT, PF1550_LDO2 }, + [PF1550_PMIC_IRQ_LDO3_FAULT] = { REGULATOR_EVENT_OVER_CURRENT, PF1550_LDO3 }, +}; + static irqreturn_t pf1550_regulator_irq_handler(int irq, void *data) { + const struct pf1550_regulator_irq *map; struct pf1550_regulator_info *info = data; struct device *dev = info->dev; struct platform_device *pdev = to_platform_device(dev); int i, irq_type = -1; - unsigned int event; for (i = 0; i < PF1550_REGULATOR_IRQ_NR; i++) if (irq == platform_get_irq(pdev, i)) irq_type = i; - switch (irq_type) { - /* The _LS interrupts indicate over-current event. The _HS interrupts - * which are more accurate and can detect catastrophic faults, issue - * an error event. The current limit FAULT interrupt is similar to the - * _HS' - */ - case PF1550_PMIC_IRQ_SW1_LS: - case PF1550_PMIC_IRQ_SW2_LS: - case PF1550_PMIC_IRQ_SW3_LS: - event = REGULATOR_EVENT_OVER_CURRENT_WARN; - for (i = 0; i < PF1550_MAX_REGULATOR; i++) - if (!strcmp(rdev_get_name(info->rdevs[i]), "SW3")) - regulator_notifier_call_chain(info->rdevs[i], - event, NULL); - break; - case PF1550_PMIC_IRQ_SW1_HS: - case PF1550_PMIC_IRQ_SW2_HS: - case PF1550_PMIC_IRQ_SW3_HS: - event = REGULATOR_EVENT_OVER_CURRENT; - for (i = 0; i < PF1550_MAX_REGULATOR; i++) - if (!strcmp(rdev_get_name(info->rdevs[i]), "SW3")) - regulator_notifier_call_chain(info->rdevs[i], - event, NULL); - break; - case PF1550_PMIC_IRQ_LDO1_FAULT: - case PF1550_PMIC_IRQ_LDO2_FAULT: - case PF1550_PMIC_IRQ_LDO3_FAULT: - event = REGULATOR_EVENT_OVER_CURRENT; - for (i = 0; i < PF1550_MAX_REGULATOR; i++) - if (!strcmp(rdev_get_name(info->rdevs[i]), "LDO3")) - regulator_notifier_call_chain(info->rdevs[i], - event, NULL); - break; - case PF1550_PMIC_IRQ_TEMP_110: - case PF1550_PMIC_IRQ_TEMP_125: - event = REGULATOR_EVENT_OVER_TEMP; + /* The die temperature concerns every rail. */ + if (irq_type == PF1550_PMIC_IRQ_TEMP_110 || + irq_type == PF1550_PMIC_IRQ_TEMP_125) { for (i = 0; i < PF1550_MAX_REGULATOR; i++) regulator_notifier_call_chain(info->rdevs[i], - event, NULL); - break; - default: - dev_err(dev, "regulator interrupt: irq %d occurred\n", - irq_type); + REGULATOR_EVENT_OVER_TEMP, + NULL); + return IRQ_HANDLED; + } + + if (irq_type < 0 || irq_type >= (int)ARRAY_SIZE(pf1550_regulator_irqs)) { + dev_err(dev, "regulator interrupt: irq %d occurred\n", irq_type); + return IRQ_HANDLED; } + map = &pf1550_regulator_irqs[irq_type]; + + for (i = 0; i < PF1550_MAX_REGULATOR; i++) + if (rdev_get_id(info->rdevs[i]) == map->id) + regulator_notifier_call_chain(info->rdevs[i], + map->event, NULL); + return IRQ_HANDLED; } diff --git a/drivers/thermal/thermal_sysfs.c b/drivers/thermal/thermal_sysfs.c index adbcb2c011e8..96fe5d591a0a 100644 --- a/drivers/thermal/thermal_sysfs.c +++ b/drivers/thermal/thermal_sysfs.c @@ -400,8 +400,8 @@ static int create_trip_attrs(struct thermal_zone_device *tz) struct thermal_trip_attrs *trip_attrs = &td->trip_attrs; /* create trip type attribute */ - snprintf(trip_attrs->type.name, THERMAL_NAME_LENGTH, - "trip_point_%d_type", i); + scnprintf(trip_attrs->type.name, sizeof(trip_attrs->type.name), + "trip_point_%d_type", i); sysfs_attr_init(&trip_attrs->type.attr.attr); trip_attrs->type.attr.attr.name = trip_attrs->type.name; @@ -410,8 +410,8 @@ static int create_trip_attrs(struct thermal_zone_device *tz) attrs[i] = &trip_attrs->type.attr.attr; /* create trip temp attribute */ - snprintf(trip_attrs->temp.name, THERMAL_NAME_LENGTH, - "trip_point_%d_temp", i); + scnprintf(trip_attrs->temp.name, sizeof(trip_attrs->temp.name), + "trip_point_%d_temp", i); sysfs_attr_init(&trip_attrs->temp.attr.attr); trip_attrs->temp.attr.attr.name = trip_attrs->temp.name; @@ -423,8 +423,8 @@ static int create_trip_attrs(struct thermal_zone_device *tz) } attrs[i + tz->num_trips] = &trip_attrs->temp.attr.attr; - snprintf(trip_attrs->hyst.name, THERMAL_NAME_LENGTH, - "trip_point_%d_hyst", i); + scnprintf(trip_attrs->hyst.name, sizeof(trip_attrs->hyst.name), + "trip_point_%d_hyst", i); sysfs_attr_init(&trip_attrs->hyst.attr.attr); trip_attrs->hyst.attr.attr.name = trip_attrs->hyst.name; diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 8f467b22b799..57edf37495a8 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -4986,8 +4986,8 @@ static int con_font_set(struct vc_data *vc, const struct console_font_op *op) if (!vc->vc_sw->con_font_set) return -ENOSYS; - if (vc_is_sel(vc)) - clear_selection(); + /* hide selection and cursor prior font changes */ + hide_cursor(vc); return vc->vc_sw->con_font_set(vc, &font, vpitch, op->flags); } @@ -5011,8 +5011,9 @@ static int con_font_default(struct vc_data *vc, struct console_font_op *op) if (!vc->vc_sw->con_font_default) return -ENOSYS; - if (vc_is_sel(vc)) - clear_selection(); + /* hide selection and cursor prior font changes */ + hide_cursor(vc); + int ret = vc->vc_sw->con_font_default(vc, &font, s); if (ret) return ret; diff --git a/drivers/video/fbdev/atafb.c b/drivers/video/fbdev/atafb.c index 5bca34c45cef..c3011b61a94b 100644 --- a/drivers/video/fbdev/atafb.c +++ b/drivers/video/fbdev/atafb.c @@ -3360,7 +3360,11 @@ static int __init atafb_probe(struct platform_device *pdev) memset (screen_base, 0, external_len); /* framebuffer in SV RAM: enable the SuperBlitter */ - if (external_addr >= 0xa0000000) { + if (external_addr >= 0xa0000000 && + ((external_pmode == FB_TYPE_PACKED_PIXELS && + external_depth == 8) || + (external_pmode == -1 && + (external_depth == 16 || external_depth == 32)))) { svblit_regs = ioremap(SVBLIT_REGS_PHYS, 0x100); if (svblit_regs) { svblit_fw = svblit_rd(SVBLIT_VERSION) & 0x1ff; diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c index 23b3c536d53d..01715873ea49 100644 --- a/drivers/video/fbdev/core/fbcon.c +++ b/drivers/video/fbdev/core/fbcon.c @@ -660,6 +660,13 @@ static void fbcon_prepare_logo(struct vc_data *vc, struct fb_info *info, erase &= ~0x400; logo_height = fb_prepare_logo(info, par->rotate); logo_lines = DIV_ROUND_UP(logo_height, vc->vc_font.height); + logo_lines = min(logo_lines, rows); + logo_lines = min(logo_lines, new_rows - 1); + if (logo_lines <= 0) { + logo_lines = 0; + logo_shown = FBCON_LOGO_DONTSHOW; + return; + } q = (unsigned short *) (vc->vc_origin + vc->vc_size_row * rows); step = logo_lines * cols; diff --git a/drivers/video/fbdev/omap2/omapfb/displays/panel-sony-acx565akm.c b/drivers/video/fbdev/omap2/omapfb/displays/panel-sony-acx565akm.c index 8f430d9e8054..0202ca8cbfc2 100644 --- a/drivers/video/fbdev/omap2/omapfb/displays/panel-sony-acx565akm.c +++ b/drivers/video/fbdev/omap2/omapfb/displays/panel-sony-acx565akm.c @@ -210,12 +210,13 @@ static void set_display_state(struct panel_drv_data *ddata, int enabled) static int panel_enabled(struct panel_drv_data *ddata) { + __be32 disp_status_be; u32 disp_status; int enabled; acx565akm_read(ddata, MIPID_CMD_READ_DISP_STATUS, - (u8 *)&disp_status, 4); - disp_status = __be32_to_cpu(disp_status); + (u8 *)&disp_status_be, 4); + disp_status = __be32_to_cpu(disp_status_be); enabled = (disp_status & (1 << 17)) && (disp_status & (1 << 10)); dev_dbg(&ddata->spi->dev, "LCD panel %senabled by bootloader (status 0x%04x)\n", diff --git a/drivers/video/fbdev/ssd1307fb.c b/drivers/video/fbdev/ssd1307fb.c index c4fdecafd856..4d185c754284 100644 --- a/drivers/video/fbdev/ssd1307fb.c +++ b/drivers/video/fbdev/ssd1307fb.c @@ -665,6 +665,10 @@ static int ssd1307fb_probe(struct i2c_client *client) spin_lock_init(&par->damage_lock); par->device_info = device_get_match_data(dev); + if (!par->device_info) { + ret = -ENODEV; + goto fb_alloc_error; + } par->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(par->reset)) { diff --git a/drivers/video/fbdev/vfb.c b/drivers/video/fbdev/vfb.c index 5b7965f36c5e..de137b2bdaed 100644 --- a/drivers/video/fbdev/vfb.c +++ b/drivers/video/fbdev/vfb.c @@ -78,6 +78,13 @@ static int vfb_pan_display(struct fb_var_screeninfo *var, static int vfb_mmap(struct fb_info *info, struct vm_area_struct *vma); +static void vfb_destroy(struct fb_info *info) +{ + vfree(info->screen_buffer); + fb_dealloc_cmap(&info->cmap); + framebuffer_release(info); +} + static const struct fb_ops vfb_ops = { .owner = THIS_MODULE, __FB_DEFAULT_SYSMEM_OPS_RDWR, @@ -87,6 +94,7 @@ static const struct fb_ops vfb_ops = { .fb_pan_display = vfb_pan_display, __FB_DEFAULT_SYSMEM_OPS_DRAW, .fb_mmap = vfb_mmap, + .fb_destroy = vfb_destroy, }; /* @@ -485,9 +493,6 @@ static void vfb_remove(struct platform_device *dev) if (info) { unregister_framebuffer(info); - vfree(videomemory); - fb_dealloc_cmap(&info->cmap); - framebuffer_release(info); } } |
