diff options
| author | Takashi Iwai <tiwai@suse.de> | 2026-04-09 08:31:21 +0200 |
|---|---|---|
| committer | Takashi Iwai <tiwai@suse.de> | 2026-04-09 08:32:17 +0200 |
| commit | 3f44bccdd6605d5d156c02ea2f861dcd30ef5dcd (patch) | |
| tree | 799286d69c8ea6060573bce2efdc10ea089ed356 /drivers | |
| parent | 292286b2d229fb732421429b027d38ac3f969383 (diff) | |
| parent | 00afb1811fa638dacf125dd1c343b7a181624dfd (diff) | |
| download | linux-3f44bccdd6605d5d156c02ea2f861dcd30ef5dcd.tar.gz linux-3f44bccdd6605d5d156c02ea2f861dcd30ef5dcd.zip | |
Merge branch 'for-linus' into for-next
Pull 7.0-devel branch for further development of HD-audio codec quirks.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'drivers')
365 files changed, 4380 insertions, 1700 deletions
diff --git a/drivers/accel/ivpu/ivpu_drv.h b/drivers/accel/ivpu/ivpu_drv.h index 5b34b6f50e69..f1b6155065ff 100644 --- a/drivers/accel/ivpu/ivpu_drv.h +++ b/drivers/accel/ivpu/ivpu_drv.h @@ -35,6 +35,7 @@ #define IVPU_HW_IP_60XX 60 #define IVPU_HW_IP_REV_LNL_B0 4 +#define IVPU_HW_IP_REV_NVL_A0 0 #define IVPU_HW_BTRS_MTL 1 #define IVPU_HW_BTRS_LNL 2 diff --git a/drivers/accel/ivpu/ivpu_hw.c b/drivers/accel/ivpu/ivpu_hw.c index d69cd0d93569..d4a9bcda4100 100644 --- a/drivers/accel/ivpu/ivpu_hw.c +++ b/drivers/accel/ivpu/ivpu_hw.c @@ -70,8 +70,10 @@ static void wa_init(struct ivpu_device *vdev) if (ivpu_hw_btrs_gen(vdev) == IVPU_HW_BTRS_MTL) vdev->wa.interrupt_clear_with_0 = ivpu_hw_btrs_irqs_clear_with_0_mtl(vdev); - if (ivpu_device_id(vdev) == PCI_DEVICE_ID_LNL && - ivpu_revision(vdev) < IVPU_HW_IP_REV_LNL_B0) + if ((ivpu_device_id(vdev) == PCI_DEVICE_ID_LNL && + ivpu_revision(vdev) < IVPU_HW_IP_REV_LNL_B0) || + (ivpu_device_id(vdev) == PCI_DEVICE_ID_NVL && + ivpu_revision(vdev) == IVPU_HW_IP_REV_NVL_A0)) vdev->wa.disable_clock_relinquish = true; if (ivpu_test_mode & IVPU_TEST_MODE_CLK_RELINQ_ENABLE) diff --git a/drivers/accel/qaic/qaic_control.c b/drivers/accel/qaic/qaic_control.c index f698d5dfd326..43f84d438960 100644 --- a/drivers/accel/qaic/qaic_control.c +++ b/drivers/accel/qaic/qaic_control.c @@ -914,7 +914,7 @@ static int decode_deactivate(struct qaic_device *qdev, void *trans, u32 *msg_len */ return -ENODEV; - if (status) { + if (usr && status) { /* * Releasing resources failed on the device side, which puts * us in a bind since they may still be in use, so enable the @@ -1109,6 +1109,9 @@ static void *msg_xfer(struct qaic_device *qdev, struct wrapper_list *wrappers, u mutex_lock(&qdev->cntl_mutex); if (!list_empty(&elem.list)) list_del(&elem.list); + /* resp_worker() processed the response but the wait was interrupted */ + else if (ret == -ERESTARTSYS) + ret = 0; if (!ret && !elem.buf) ret = -ETIMEDOUT; else if (ret > 0 && !elem.buf) @@ -1419,9 +1422,49 @@ static void resp_worker(struct work_struct *work) } mutex_unlock(&qdev->cntl_mutex); - if (!found) + if (!found) { + /* + * The user might have gone away at this point without waiting + * for QAIC_TRANS_DEACTIVATE_FROM_DEV transaction coming from + * the device. If this is not handled correctly, the host will + * not know that the DBC[n] has been freed on the device. + * Due to this failure in synchronization between the device and + * the host, if another user requests to activate a network, and + * the device assigns DBC[n] again, save_dbc_buf() will hang, + * waiting for dbc[n]->in_use to be set to false, which will not + * happen unless the qaic_dev_reset_clean_local_state() gets + * called by resetting the device (or re-inserting the module). + * + * As a solution, we look for QAIC_TRANS_DEACTIVATE_FROM_DEV + * transactions in the message before disposing of it, then + * handle releasing the DBC resources. + * + * Since the user has gone away, if the device could not + * deactivate the network (status != 0), there is no way to + * enable and reassign the DBC to the user. We can put trust in + * the device that it will release all the active DBCs in + * response to the QAIC_TRANS_TERMINATE_TO_DEV transaction, + * otherwise, the user can issue an soc_reset to the device. + */ + u32 msg_count = le32_to_cpu(msg->hdr.count); + u32 msg_len = le32_to_cpu(msg->hdr.len); + u32 len = 0; + int j; + + for (j = 0; j < msg_count && len < msg_len; ++j) { + struct wire_trans_hdr *trans_hdr; + + trans_hdr = (struct wire_trans_hdr *)(msg->data + len); + if (le32_to_cpu(trans_hdr->type) == QAIC_TRANS_DEACTIVATE_FROM_DEV) { + if (decode_deactivate(qdev, trans_hdr, &len, NULL)) + len += le32_to_cpu(trans_hdr->len); + } else { + len += le32_to_cpu(trans_hdr->len); + } + } /* request must have timed out, drop packet */ kfree(msg); + } kfree(resp); } diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 5f63ed120a2c..6f0065257a77 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -1656,6 +1656,8 @@ static int acpi_ec_setup(struct acpi_ec *ec, struct acpi_device *device, bool ca ret = ec_install_handlers(ec, device, call_reg); if (ret) { + ec_remove_handlers(ec); + if (ec == first_ec) first_ec = NULL; diff --git a/drivers/acpi/riscv/rimt.c b/drivers/acpi/riscv/rimt.c index 229c4a0d47a3..906282b0e63c 100644 --- a/drivers/acpi/riscv/rimt.c +++ b/drivers/acpi/riscv/rimt.c @@ -263,6 +263,13 @@ static int rimt_iommu_xlate(struct device *dev, struct acpi_rimt_node *node, u32 if (!rimt_fwnode) return -EPROBE_DEFER; + /* + * EPROBE_DEFER ensures IOMMU is probed before the devices that + * depend on them. During shutdown, however, the IOMMU may be removed + * first, leading to issues. To avoid this, a device link is added + * which enforces the correct removal order. + */ + device_link_add(dev, rimt_fwnode->dev, DL_FLAG_AUTOREMOVE_CONSUMER); return acpi_iommu_fwspec_init(dev, deviceid, rimt_fwnode); } diff --git a/drivers/android/binder/page_range.rs b/drivers/android/binder/page_range.rs index 9dfc154e5dd4..b57e0c7ba3f1 100644 --- a/drivers/android/binder/page_range.rs +++ b/drivers/android/binder/page_range.rs @@ -13,6 +13,8 @@ // // The shrinker will use trylock methods because it locks them in a different order. +use crate::AssertSync; + use core::{ marker::PhantomPinned, mem::{size_of, size_of_val, MaybeUninit}, @@ -143,14 +145,14 @@ pub(crate) struct ShrinkablePageRange { } // We do not define any ops. For now, used only to check identity of vmas. -static BINDER_VM_OPS: bindings::vm_operations_struct = pin_init::zeroed(); +static BINDER_VM_OPS: AssertSync<bindings::vm_operations_struct> = AssertSync(pin_init::zeroed()); // To ensure that we do not accidentally install pages into or zap pages from the wrong vma, we // check its vm_ops and private data before using it. fn check_vma(vma: &virt::VmaRef, owner: *const ShrinkablePageRange) -> Option<&virt::VmaMixedMap> { // SAFETY: Just reading the vm_ops pointer of any active vma is safe. let vm_ops = unsafe { (*vma.as_ptr()).vm_ops }; - if !ptr::eq(vm_ops, &BINDER_VM_OPS) { + if !ptr::eq(vm_ops, &BINDER_VM_OPS.0) { return None; } @@ -342,7 +344,7 @@ impl ShrinkablePageRange { // SAFETY: We own the vma, and we don't use any methods on VmaNew that rely on // `vm_ops`. - unsafe { (*vma.as_ptr()).vm_ops = &BINDER_VM_OPS }; + unsafe { (*vma.as_ptr()).vm_ops = &BINDER_VM_OPS.0 }; Ok(num_pages) } diff --git a/drivers/android/binder/rust_binder_main.rs b/drivers/android/binder/rust_binder_main.rs index aa5f2a75adb4..014010662df8 100644 --- a/drivers/android/binder/rust_binder_main.rs +++ b/drivers/android/binder/rust_binder_main.rs @@ -306,7 +306,7 @@ impl kernel::Module for BinderModule { /// Makes the inner type Sync. #[repr(transparent)] pub struct AssertSync<T>(T); -// SAFETY: Used only to insert `file_operations` into a global, which is safe. +// SAFETY: Used only to insert C bindings types into globals, which is safe. unsafe impl<T> Sync for AssertSync<T> {} /// File operations that rust_binderfs.c can use. diff --git a/drivers/auxdisplay/lcd2s.c b/drivers/auxdisplay/lcd2s.c index defb0573e43c..c7a962728752 100644 --- a/drivers/auxdisplay/lcd2s.c +++ b/drivers/auxdisplay/lcd2s.c @@ -99,8 +99,13 @@ static int lcd2s_print(struct charlcd *lcd, int c) { struct lcd2s_data *lcd2s = lcd->drvdata; u8 buf[2] = { LCD2S_CMD_WRITE, c }; + int ret; - lcd2s_i2c_master_send(lcd2s->i2c, buf, sizeof(buf)); + ret = lcd2s_i2c_master_send(lcd2s->i2c, buf, sizeof(buf)); + if (ret < 0) + return ret; + if (ret != sizeof(buf)) + return -EIO; return 0; } @@ -108,9 +113,13 @@ static int lcd2s_gotoxy(struct charlcd *lcd, unsigned int x, unsigned int y) { struct lcd2s_data *lcd2s = lcd->drvdata; u8 buf[3] = { LCD2S_CMD_CUR_POS, y + 1, x + 1 }; + int ret; - lcd2s_i2c_master_send(lcd2s->i2c, buf, sizeof(buf)); - + ret = lcd2s_i2c_master_send(lcd2s->i2c, buf, sizeof(buf)); + if (ret < 0) + return ret; + if (ret != sizeof(buf)) + return -EIO; return 0; } diff --git a/drivers/auxdisplay/line-display.c b/drivers/auxdisplay/line-display.c index 81b4aac65807..fb6d9294140d 100644 --- a/drivers/auxdisplay/line-display.c +++ b/drivers/auxdisplay/line-display.c @@ -365,7 +365,7 @@ static DEFINE_IDA(linedisp_id); static void linedisp_release(struct device *dev) { - struct linedisp *linedisp = to_linedisp(dev); + struct linedisp *linedisp = container_of(dev, struct linedisp, dev); kfree(linedisp->map); kfree(linedisp->message); diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 607c1246d994..e388b19850e3 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -1545,6 +1545,7 @@ static int _regmap_select_page(struct regmap *map, unsigned int *reg, unsigned int val_num) { void *orig_work_buf; + unsigned int selector_reg; unsigned int win_offset; unsigned int win_page; bool page_chg; @@ -1563,10 +1564,31 @@ static int _regmap_select_page(struct regmap *map, unsigned int *reg, return -EINVAL; } - /* It is possible to have selector register inside data window. - In that case, selector register is located on every page and - it needs no page switching, when accessed alone. */ + /* + * Calculate the address of the selector register in the corresponding + * data window if it is located on every page. + */ + page_chg = in_range(range->selector_reg, range->window_start, range->window_len); + if (page_chg) + selector_reg = range->range_min + win_page * range->window_len + + range->selector_reg - range->window_start; + + /* + * It is possible to have selector register inside data window. + * In that case, selector register is located on every page and it + * needs no page switching, when accessed alone. + * + * Nevertheless we should synchronize the cache values for it. + * This can't be properly achieved if the selector register is + * the first and the only one to be read inside the data window. + * That's why we update it in that case as well. + * + * However, we specifically avoid updating it for the default page, + * when it's overlapped with the real data window, to prevent from + * infinite looping. + */ if (val_num > 1 || + (page_chg && selector_reg != range->selector_reg) || range->window_start + win_offset != range->selector_reg) { /* Use separate work_buf during page switching */ orig_work_buf = map->work_buf; @@ -1575,7 +1597,7 @@ static int _regmap_select_page(struct regmap *map, unsigned int *reg, ret = _regmap_update_bits(map, range->selector_reg, range->selector_mask, win_page << range->selector_shift, - &page_chg, false); + NULL, false); map->work_buf = orig_work_buf; diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c index a324ede6206d..af679375b193 100644 --- a/drivers/block/zram/zram_drv.c +++ b/drivers/block/zram/zram_drv.c @@ -917,9 +917,8 @@ static void zram_account_writeback_submit(struct zram *zram) static int zram_writeback_complete(struct zram *zram, struct zram_wb_req *req) { - u32 size, index = req->pps->index; - int err, prio; - bool huge; + u32 index = req->pps->index; + int err; err = blk_status_to_errno(req->bio.bi_status); if (err) { @@ -946,28 +945,13 @@ static int zram_writeback_complete(struct zram *zram, struct zram_wb_req *req) goto out; } - if (zram->compressed_wb) { - /* - * ZRAM_WB slots get freed, we need to preserve data required - * for read decompression. - */ - size = get_slot_size(zram, index); - prio = get_slot_comp_priority(zram, index); - huge = test_slot_flag(zram, index, ZRAM_HUGE); - } - - slot_free(zram, index); - set_slot_flag(zram, index, ZRAM_WB); + clear_slot_flag(zram, index, ZRAM_IDLE); + if (test_slot_flag(zram, index, ZRAM_HUGE)) + atomic64_dec(&zram->stats.huge_pages); + atomic64_sub(get_slot_size(zram, index), &zram->stats.compr_data_size); + zs_free(zram->mem_pool, get_slot_handle(zram, index)); set_slot_handle(zram, index, req->blk_idx); - - if (zram->compressed_wb) { - if (huge) - set_slot_flag(zram, index, ZRAM_HUGE); - set_slot_size(zram, index, size); - set_slot_comp_priority(zram, index, prio); - } - - atomic64_inc(&zram->stats.pages_stored); + set_slot_flag(zram, index, ZRAM_WB); out: slot_unlock(zram, index); @@ -2010,8 +1994,13 @@ static void slot_free(struct zram *zram, u32 index) set_slot_comp_priority(zram, index, 0); if (test_slot_flag(zram, index, ZRAM_HUGE)) { + /* + * Writeback completion decrements ->huge_pages but keeps + * ZRAM_HUGE flag for deferred decompression path. + */ + if (!test_slot_flag(zram, index, ZRAM_WB)) + atomic64_dec(&zram->stats.huge_pages); clear_slot_flag(zram, index, ZRAM_HUGE); - atomic64_dec(&zram->stats.huge_pages); } if (test_slot_flag(zram, index, ZRAM_WB)) { diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c index 246b6205c5e0..ab146894ba4e 100644 --- a/drivers/bluetooth/btintel.c +++ b/drivers/bluetooth/btintel.c @@ -251,11 +251,13 @@ void btintel_hw_error(struct hci_dev *hdev, u8 code) bt_dev_err(hdev, "Hardware error 0x%2.2x", code); + hci_req_sync_lock(hdev); + skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT); if (IS_ERR(skb)) { bt_dev_err(hdev, "Reset after hardware error failed (%ld)", PTR_ERR(skb)); - return; + goto unlock; } kfree_skb(skb); @@ -263,18 +265,21 @@ void btintel_hw_error(struct hci_dev *hdev, u8 code) if (IS_ERR(skb)) { bt_dev_err(hdev, "Retrieving Intel exception info failed (%ld)", PTR_ERR(skb)); - return; + goto unlock; } if (skb->len != 13) { bt_dev_err(hdev, "Exception info size mismatch"); kfree_skb(skb); - return; + goto unlock; } bt_dev_err(hdev, "Exception info %s", (char *)(skb->data + 1)); kfree_skb(skb); + +unlock: + hci_req_sync_unlock(hdev); } EXPORT_SYMBOL_GPL(btintel_hw_error); diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index a1c5eb993e47..5c535f3ab722 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -2376,8 +2376,11 @@ static void btusb_work(struct work_struct *work) if (data->air_mode == HCI_NOTIFY_ENABLE_SCO_CVSD) { if (hdev->voice_setting & 0x0020) { static const int alts[3] = { 2, 4, 5 }; + unsigned int sco_idx; - new_alts = alts[data->sco_num - 1]; + sco_idx = min_t(unsigned int, data->sco_num - 1, + ARRAY_SIZE(alts) - 1); + new_alts = alts[sco_idx]; } else { new_alts = data->sco_num; } diff --git a/drivers/bluetooth/hci_h4.c b/drivers/bluetooth/hci_h4.c index 07cc2a79a77b..a889a66a326f 100644 --- a/drivers/bluetooth/hci_h4.c +++ b/drivers/bluetooth/hci_h4.c @@ -109,9 +109,6 @@ static int h4_recv(struct hci_uart *hu, const void *data, int count) { struct h4_struct *h4 = hu->priv; - if (!test_bit(HCI_UART_REGISTERED, &hu->flags)) - return -EUNATCH; - h4->rx_skb = h4_recv_buf(hu, h4->rx_skb, data, count, h4_recv_pkts, ARRAY_SIZE(h4_recv_pkts)); if (IS_ERR(h4->rx_skb)) { diff --git a/drivers/bluetooth/hci_ll.c b/drivers/bluetooth/hci_ll.c index 91acf24f1ef5..91c96ad12342 100644 --- a/drivers/bluetooth/hci_ll.c +++ b/drivers/bluetooth/hci_ll.c @@ -541,6 +541,8 @@ static int download_firmware(struct ll_device *lldev) if (err || !fw->data || !fw->size) { bt_dev_err(lldev->hu.hdev, "request_firmware failed(errno %d) for %s", err, bts_scr_name); + if (!err) + release_firmware(fw); return -EINVAL; } ptr = (void *)fw->data; diff --git a/drivers/comedi/comedi_fops.c b/drivers/comedi/comedi_fops.c index 48a8a607a84c..0df9f4636fb6 100644 --- a/drivers/comedi/comedi_fops.c +++ b/drivers/comedi/comedi_fops.c @@ -793,13 +793,15 @@ static void do_become_nonbusy(struct comedi_device *dev, __comedi_clear_subdevice_runflags(s, COMEDI_SRF_RUNNING | COMEDI_SRF_BUSY); spin_unlock_irqrestore(&s->spin_lock, flags); - if (comedi_is_runflags_busy(runflags)) { + if (async) { /* * "Run active" counter was set to 1 when setting up the * command. Decrement it and wait for it to become 0. */ - comedi_put_is_subdevice_running(s); - wait_for_completion(&async->run_complete); + if (comedi_is_runflags_busy(runflags)) { + comedi_put_is_subdevice_running(s); + wait_for_completion(&async->run_complete); + } comedi_buf_reset(s); async->inttrig = NULL; kfree(async->cmd.chanlist); diff --git a/drivers/comedi/drivers.c b/drivers/comedi/drivers.c index db225a3bf012..5ab96b5eefd1 100644 --- a/drivers/comedi/drivers.c +++ b/drivers/comedi/drivers.c @@ -1063,6 +1063,14 @@ int comedi_device_attach(struct comedi_device *dev, struct comedi_devconfig *it) ret = -EIO; goto out; } + if (IS_ENABLED(CONFIG_LOCKDEP)) { + /* + * dev->spinlock is for private use by the attached low-level + * driver. Reinitialize it to stop lock-dependency tracking + * between attachments to different low-level drivers. + */ + spin_lock_init(&dev->spinlock); + } dev->driver = driv; dev->board_name = dev->board_ptr ? *(const char **)dev->board_ptr : dev->driver->driver_name; diff --git a/drivers/comedi/drivers/dt2815.c b/drivers/comedi/drivers/dt2815.c index 03ba2fd18a21..d066dc303520 100644 --- a/drivers/comedi/drivers/dt2815.c +++ b/drivers/comedi/drivers/dt2815.c @@ -175,6 +175,18 @@ static int dt2815_attach(struct comedi_device *dev, struct comedi_devconfig *it) ? current_range_type : voltage_range_type; } + /* + * Check if hardware is present before attempting any I/O operations. + * Reading 0xff from status register typically indicates no hardware + * on the bus (floating bus reads as all 1s). + */ + if (inb(dev->iobase + DT2815_STATUS) == 0xff) { + dev_err(dev->class_dev, + "No hardware detected at I/O base 0x%lx\n", + dev->iobase); + return -ENODEV; + } + /* Init the 2815 */ outb(0x00, dev->iobase + DT2815_STATUS); for (i = 0; i < 100; i++) { diff --git a/drivers/comedi/drivers/me4000.c b/drivers/comedi/drivers/me4000.c index 7dd3a0071863..effe9fdbbafe 100644 --- a/drivers/comedi/drivers/me4000.c +++ b/drivers/comedi/drivers/me4000.c @@ -315,6 +315,18 @@ static int me4000_xilinx_download(struct comedi_device *dev, unsigned int val; unsigned int i; + /* Get data stream length from header. */ + if (size >= 4) { + file_length = (((unsigned int)data[0] & 0xff) << 24) + + (((unsigned int)data[1] & 0xff) << 16) + + (((unsigned int)data[2] & 0xff) << 8) + + ((unsigned int)data[3] & 0xff); + } + if (size < 16 || file_length > size - 16) { + dev_err(dev->class_dev, "Firmware length inconsistency\n"); + return -EINVAL; + } + if (!xilinx_iobase) return -ENODEV; @@ -346,10 +358,6 @@ static int me4000_xilinx_download(struct comedi_device *dev, outl(val, devpriv->plx_regbase + PLX9052_CNTRL); /* Download Xilinx firmware */ - file_length = (((unsigned int)data[0] & 0xff) << 24) + - (((unsigned int)data[1] & 0xff) << 16) + - (((unsigned int)data[2] & 0xff) << 8) + - ((unsigned int)data[3] & 0xff); usleep_range(10, 1000); for (i = 0; i < file_length; i++) { diff --git a/drivers/comedi/drivers/me_daq.c b/drivers/comedi/drivers/me_daq.c index 076b15097afd..2f2ea029cffc 100644 --- a/drivers/comedi/drivers/me_daq.c +++ b/drivers/comedi/drivers/me_daq.c @@ -344,6 +344,25 @@ static int me2600_xilinx_download(struct comedi_device *dev, unsigned int file_length; unsigned int i; + /* + * Format of the firmware + * Build longs from the byte-wise coded header + * Byte 1-3: length of the array + * Byte 4-7: version + * Byte 8-11: date + * Byte 12-15: reserved + */ + if (size >= 4) { + file_length = (((unsigned int)data[0] & 0xff) << 24) + + (((unsigned int)data[1] & 0xff) << 16) + + (((unsigned int)data[2] & 0xff) << 8) + + ((unsigned int)data[3] & 0xff); + } + if (size < 16 || file_length > size - 16) { + dev_err(dev->class_dev, "Firmware length inconsistency\n"); + return -EINVAL; + } + /* disable irq's on PLX */ writel(0x00, devpriv->plx_regbase + PLX9052_INTCSR); @@ -358,22 +377,6 @@ static int me2600_xilinx_download(struct comedi_device *dev, sleep(1); /* - * Format of the firmware - * Build longs from the byte-wise coded header - * Byte 1-3: length of the array - * Byte 4-7: version - * Byte 8-11: date - * Byte 12-15: reserved - */ - if (size < 16) - return -EINVAL; - - file_length = (((unsigned int)data[0] & 0xff) << 24) + - (((unsigned int)data[1] & 0xff) << 16) + - (((unsigned int)data[2] & 0xff) << 8) + - ((unsigned int)data[3] & 0xff); - - /* * Loop for writing firmware byte by byte to xilinx * Firmware data start at offset 16 */ diff --git a/drivers/comedi/drivers/ni_atmio16d.c b/drivers/comedi/drivers/ni_atmio16d.c index e5e7cc423c87..b057b3b3582e 100644 --- a/drivers/comedi/drivers/ni_atmio16d.c +++ b/drivers/comedi/drivers/ni_atmio16d.c @@ -698,7 +698,8 @@ static int atmio16d_attach(struct comedi_device *dev, static void atmio16d_detach(struct comedi_device *dev) { - reset_atmio16d(dev); + if (dev->private) + reset_atmio16d(dev); comedi_legacy_detach(dev); } diff --git a/drivers/counter/rz-mtu3-cnt.c b/drivers/counter/rz-mtu3-cnt.c index e755d54dfece..7bfb6979193c 100644 --- a/drivers/counter/rz-mtu3-cnt.c +++ b/drivers/counter/rz-mtu3-cnt.c @@ -107,9 +107,9 @@ static bool rz_mtu3_is_counter_invalid(struct counter_device *counter, int id) struct rz_mtu3_cnt *const priv = counter_priv(counter); unsigned long tmdr; - pm_runtime_get_sync(priv->ch->dev); + pm_runtime_get_sync(counter->parent); tmdr = rz_mtu3_shared_reg_read(priv->ch, RZ_MTU3_TMDR3); - pm_runtime_put(priv->ch->dev); + pm_runtime_put(counter->parent); if (id == RZ_MTU3_32_BIT_CH && test_bit(RZ_MTU3_TMDR3_LWA, &tmdr)) return false; @@ -165,12 +165,12 @@ static int rz_mtu3_count_read(struct counter_device *counter, if (ret) return ret; - pm_runtime_get_sync(ch->dev); + pm_runtime_get_sync(counter->parent); if (count->id == RZ_MTU3_32_BIT_CH) *val = rz_mtu3_32bit_ch_read(ch, RZ_MTU3_TCNTLW); else *val = rz_mtu3_16bit_ch_read(ch, RZ_MTU3_TCNT); - pm_runtime_put(ch->dev); + pm_runtime_put(counter->parent); mutex_unlock(&priv->lock); return 0; @@ -187,26 +187,26 @@ static int rz_mtu3_count_write(struct counter_device *counter, if (ret) return ret; - pm_runtime_get_sync(ch->dev); + pm_runtime_get_sync(counter->parent); if (count->id == RZ_MTU3_32_BIT_CH) rz_mtu3_32bit_ch_write(ch, RZ_MTU3_TCNTLW, val); else rz_mtu3_16bit_ch_write(ch, RZ_MTU3_TCNT, val); - pm_runtime_put(ch->dev); + pm_runtime_put(counter->parent); mutex_unlock(&priv->lock); return 0; } static int rz_mtu3_count_function_read_helper(struct rz_mtu3_channel *const ch, - struct rz_mtu3_cnt *const priv, + struct counter_device *const counter, enum counter_function *function) { u8 timer_mode; - pm_runtime_get_sync(ch->dev); + pm_runtime_get_sync(counter->parent); timer_mode = rz_mtu3_8bit_ch_read(ch, RZ_MTU3_TMDR1); - pm_runtime_put(ch->dev); + pm_runtime_put(counter->parent); switch (timer_mode & RZ_MTU3_TMDR1_PH_CNT_MODE_MASK) { case RZ_MTU3_TMDR1_PH_CNT_MODE_1: @@ -240,7 +240,7 @@ static int rz_mtu3_count_function_read(struct counter_device *counter, if (ret) return ret; - ret = rz_mtu3_count_function_read_helper(ch, priv, function); + ret = rz_mtu3_count_function_read_helper(ch, counter, function); mutex_unlock(&priv->lock); return ret; @@ -279,9 +279,9 @@ static int rz_mtu3_count_function_write(struct counter_device *counter, return -EINVAL; } - pm_runtime_get_sync(ch->dev); + pm_runtime_get_sync(counter->parent); rz_mtu3_8bit_ch_write(ch, RZ_MTU3_TMDR1, timer_mode); - pm_runtime_put(ch->dev); + pm_runtime_put(counter->parent); mutex_unlock(&priv->lock); return 0; @@ -300,9 +300,9 @@ static int rz_mtu3_count_direction_read(struct counter_device *counter, if (ret) return ret; - pm_runtime_get_sync(ch->dev); + pm_runtime_get_sync(counter->parent); tsr = rz_mtu3_8bit_ch_read(ch, RZ_MTU3_TSR); - pm_runtime_put(ch->dev); + pm_runtime_put(counter->parent); *direction = (tsr & RZ_MTU3_TSR_TCFD) ? COUNTER_COUNT_DIRECTION_FORWARD : COUNTER_COUNT_DIRECTION_BACKWARD; @@ -377,14 +377,14 @@ static int rz_mtu3_count_ceiling_write(struct counter_device *counter, return -EINVAL; } - pm_runtime_get_sync(ch->dev); + pm_runtime_get_sync(counter->parent); if (count->id == RZ_MTU3_32_BIT_CH) rz_mtu3_32bit_ch_write(ch, RZ_MTU3_TGRALW, ceiling); else rz_mtu3_16bit_ch_write(ch, RZ_MTU3_TGRA, ceiling); rz_mtu3_8bit_ch_write(ch, RZ_MTU3_TCR, RZ_MTU3_TCR_CCLR_TGRA); - pm_runtime_put(ch->dev); + pm_runtime_put(counter->parent); mutex_unlock(&priv->lock); return 0; @@ -495,25 +495,28 @@ static int rz_mtu3_count_enable_read(struct counter_device *counter, static int rz_mtu3_count_enable_write(struct counter_device *counter, struct counter_count *count, u8 enable) { - struct rz_mtu3_channel *const ch = rz_mtu3_get_ch(counter, count->id); struct rz_mtu3_cnt *const priv = counter_priv(counter); int ret = 0; + mutex_lock(&priv->lock); + + if (priv->count_is_enabled[count->id] == enable) + goto exit; + if (enable) { - mutex_lock(&priv->lock); - pm_runtime_get_sync(ch->dev); + pm_runtime_get_sync(counter->parent); ret = rz_mtu3_initialize_counter(counter, count->id); if (ret == 0) priv->count_is_enabled[count->id] = true; - mutex_unlock(&priv->lock); } else { - mutex_lock(&priv->lock); rz_mtu3_terminate_counter(counter, count->id); priv->count_is_enabled[count->id] = false; - pm_runtime_put(ch->dev); - mutex_unlock(&priv->lock); + pm_runtime_put(counter->parent); } +exit: + mutex_unlock(&priv->lock); + return ret; } @@ -540,9 +543,9 @@ static int rz_mtu3_cascade_counts_enable_get(struct counter_device *counter, if (ret) return ret; - pm_runtime_get_sync(priv->ch->dev); + pm_runtime_get_sync(counter->parent); tmdr = rz_mtu3_shared_reg_read(priv->ch, RZ_MTU3_TMDR3); - pm_runtime_put(priv->ch->dev); + pm_runtime_put(counter->parent); *cascade_enable = test_bit(RZ_MTU3_TMDR3_LWA, &tmdr); mutex_unlock(&priv->lock); @@ -559,10 +562,10 @@ static int rz_mtu3_cascade_counts_enable_set(struct counter_device *counter, if (ret) return ret; - pm_runtime_get_sync(priv->ch->dev); + pm_runtime_get_sync(counter->parent); rz_mtu3_shared_reg_update_bit(priv->ch, RZ_MTU3_TMDR3, RZ_MTU3_TMDR3_LWA, cascade_enable); - pm_runtime_put(priv->ch->dev); + pm_runtime_put(counter->parent); mutex_unlock(&priv->lock); return 0; @@ -579,9 +582,9 @@ static int rz_mtu3_ext_input_phase_clock_select_get(struct counter_device *count if (ret) return ret; - pm_runtime_get_sync(priv->ch->dev); + pm_runtime_get_sync(counter->parent); tmdr = rz_mtu3_shared_reg_read(priv->ch, RZ_MTU3_TMDR3); - pm_runtime_put(priv->ch->dev); + pm_runtime_put(counter->parent); *ext_input_phase_clock_select = test_bit(RZ_MTU3_TMDR3_PHCKSEL, &tmdr); mutex_unlock(&priv->lock); @@ -598,11 +601,11 @@ static int rz_mtu3_ext_input_phase_clock_select_set(struct counter_device *count if (ret) return ret; - pm_runtime_get_sync(priv->ch->dev); + pm_runtime_get_sync(counter->parent); rz_mtu3_shared_reg_update_bit(priv->ch, RZ_MTU3_TMDR3, RZ_MTU3_TMDR3_PHCKSEL, ext_input_phase_clock_select); - pm_runtime_put(priv->ch->dev); + pm_runtime_put(counter->parent); mutex_unlock(&priv->lock); return 0; @@ -640,7 +643,7 @@ static int rz_mtu3_action_read(struct counter_device *counter, if (ret) return ret; - ret = rz_mtu3_count_function_read_helper(ch, priv, &function); + ret = rz_mtu3_count_function_read_helper(ch, counter, &function); if (ret) { mutex_unlock(&priv->lock); return ret; diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 277884d91913..1f794524a1d9 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1427,12 +1427,9 @@ static int cpufreq_policy_online(struct cpufreq_policy *policy, * If there is a problem with its frequency table, take it * offline and drop it. */ - if (policy->freq_table_sorted != CPUFREQ_TABLE_SORTED_ASCENDING && - policy->freq_table_sorted != CPUFREQ_TABLE_SORTED_DESCENDING) { - ret = cpufreq_table_validate_and_sort(policy); - if (ret) - goto out_offline_policy; - } + ret = cpufreq_table_validate_and_sort(policy); + if (ret) + goto out_offline_policy; /* related_cpus should at least include policy->cpus. */ cpumask_copy(policy->related_cpus, policy->cpus); diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c index e0e847764511..df01d33993d8 100644 --- a/drivers/cpufreq/cpufreq_conservative.c +++ b/drivers/cpufreq/cpufreq_conservative.c @@ -313,6 +313,17 @@ static void cs_start(struct cpufreq_policy *policy) dbs_info->requested_freq = policy->cur; } +static void cs_limits(struct cpufreq_policy *policy) +{ + struct cs_policy_dbs_info *dbs_info = to_dbs_info(policy->governor_data); + + /* + * The limits have changed, so may have the current frequency. Reset + * requested_freq to avoid any unintended outcomes due to the mismatch. + */ + dbs_info->requested_freq = policy->cur; +} + static struct dbs_governor cs_governor = { .gov = CPUFREQ_DBS_GOVERNOR_INITIALIZER("conservative"), .kobj_type = { .default_groups = cs_groups }, @@ -322,6 +333,7 @@ static struct dbs_governor cs_governor = { .init = cs_init, .exit = cs_exit, .start = cs_start, + .limits = cs_limits, }; #define CPU_FREQ_GOV_CONSERVATIVE (cs_governor.gov) diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c index 36eb7aee4bcd..86f35e451914 100644 --- a/drivers/cpufreq/cpufreq_governor.c +++ b/drivers/cpufreq/cpufreq_governor.c @@ -468,13 +468,13 @@ int cpufreq_dbs_governor_init(struct cpufreq_policy *policy) /* Failure, so roll back. */ pr_err("initialization failed (dbs_data kobject init error %d)\n", ret); - kobject_put(&dbs_data->attr_set.kobj); - policy->governor_data = NULL; if (!have_governor_per_policy()) gov->gdbs_data = NULL; - gov->exit(dbs_data); + + kobject_put(&dbs_data->attr_set.kobj); + goto free_policy_dbs_info; free_dbs_data: kfree(dbs_data); @@ -563,6 +563,7 @@ EXPORT_SYMBOL_GPL(cpufreq_dbs_governor_stop); void cpufreq_dbs_governor_limits(struct cpufreq_policy *policy) { + struct dbs_governor *gov = dbs_governor_of(policy); struct policy_dbs_info *policy_dbs; /* Protect gov->gdbs_data against cpufreq_dbs_governor_exit() */ @@ -574,6 +575,8 @@ void cpufreq_dbs_governor_limits(struct cpufreq_policy *policy) mutex_lock(&policy_dbs->update_mutex); cpufreq_policy_apply_limits(policy); gov_update_sample_delay(policy_dbs, 0); + if (gov->limits) + gov->limits(policy); mutex_unlock(&policy_dbs->update_mutex); out: diff --git a/drivers/cpufreq/cpufreq_governor.h b/drivers/cpufreq/cpufreq_governor.h index 168c23fd7fca..1462d59277bd 100644 --- a/drivers/cpufreq/cpufreq_governor.h +++ b/drivers/cpufreq/cpufreq_governor.h @@ -138,6 +138,7 @@ struct dbs_governor { int (*init)(struct dbs_data *dbs_data); void (*exit)(struct dbs_data *dbs_data); void (*start)(struct cpufreq_policy *policy); + void (*limits)(struct cpufreq_policy *policy); }; static inline struct dbs_governor *dbs_governor_of(struct cpufreq_policy *policy) diff --git a/drivers/cpufreq/freq_table.c b/drivers/cpufreq/freq_table.c index 7f251daf03ce..5b364d8da4f9 100644 --- a/drivers/cpufreq/freq_table.c +++ b/drivers/cpufreq/freq_table.c @@ -360,6 +360,10 @@ int cpufreq_table_validate_and_sort(struct cpufreq_policy *policy) if (policy_has_boost_freq(policy)) policy->boost_supported = true; + if (policy->freq_table_sorted == CPUFREQ_TABLE_SORTED_ASCENDING || + policy->freq_table_sorted == CPUFREQ_TABLE_SORTED_DESCENDING) + return 0; + return set_freq_table_sorted(policy); } diff --git a/drivers/crypto/caam/caamalg_qi2.c b/drivers/crypto/caam/caamalg_qi2.c index 167372936ca7..78964e1712e5 100644 --- a/drivers/crypto/caam/caamalg_qi2.c +++ b/drivers/crypto/caam/caamalg_qi2.c @@ -3326,9 +3326,10 @@ static int ahash_setkey(struct crypto_ahash *ahash, const u8 *key, if (aligned_len < keylen) return -EOVERFLOW; - hashed_key = kmemdup(key, aligned_len, GFP_KERNEL); + hashed_key = kmalloc(aligned_len, GFP_KERNEL); if (!hashed_key) return -ENOMEM; + memcpy(hashed_key, key, keylen); ret = hash_digest_key(ctx, &keylen, hashed_key, digestsize); if (ret) goto bad_free_key; diff --git a/drivers/crypto/caam/caamhash.c b/drivers/crypto/caam/caamhash.c index 628c43a7efc4..44122208f70c 100644 --- a/drivers/crypto/caam/caamhash.c +++ b/drivers/crypto/caam/caamhash.c @@ -441,9 +441,10 @@ static int ahash_setkey(struct crypto_ahash *ahash, if (aligned_len < keylen) return -EOVERFLOW; - hashed_key = kmemdup(key, keylen, GFP_KERNEL); + hashed_key = kmalloc(aligned_len, GFP_KERNEL); if (!hashed_key) return -ENOMEM; + memcpy(hashed_key, key, keylen); ret = hash_digest_key(ctx, &keylen, hashed_key, digestsize); if (ret) goto bad_free_key; diff --git a/drivers/crypto/tegra/tegra-se-aes.c b/drivers/crypto/tegra/tegra-se-aes.c index 0e07d0523291..9210cceb4b7b 100644 --- a/drivers/crypto/tegra/tegra-se-aes.c +++ b/drivers/crypto/tegra/tegra-se-aes.c @@ -529,7 +529,7 @@ static struct tegra_se_alg tegra_aes_algs[] = { .cra_name = "cbc(aes)", .cra_driver_name = "cbc-aes-tegra", .cra_priority = 500, - .cra_flags = CRYPTO_ALG_TYPE_SKCIPHER | CRYPTO_ALG_ASYNC, + .cra_flags = CRYPTO_ALG_ASYNC, .cra_blocksize = AES_BLOCK_SIZE, .cra_ctxsize = sizeof(struct tegra_aes_ctx), .cra_alignmask = 0xf, @@ -550,7 +550,7 @@ static struct tegra_se_alg tegra_aes_algs[] = { .cra_name = "ecb(aes)", .cra_driver_name = "ecb-aes-tegra", .cra_priority = 500, - .cra_flags = CRYPTO_ALG_TYPE_SKCIPHER | CRYPTO_ALG_ASYNC, + .cra_flags = CRYPTO_ALG_ASYNC, .cra_blocksize = AES_BLOCK_SIZE, .cra_ctxsize = sizeof(struct tegra_aes_ctx), .cra_alignmask = 0xf, @@ -572,7 +572,7 @@ static struct tegra_se_alg tegra_aes_algs[] = { .cra_name = "ctr(aes)", .cra_driver_name = "ctr-aes-tegra", .cra_priority = 500, - .cra_flags = CRYPTO_ALG_TYPE_SKCIPHER | CRYPTO_ALG_ASYNC, + .cra_flags = CRYPTO_ALG_ASYNC, .cra_blocksize = 1, .cra_ctxsize = sizeof(struct tegra_aes_ctx), .cra_alignmask = 0xf, @@ -594,6 +594,7 @@ static struct tegra_se_alg tegra_aes_algs[] = { .cra_name = "xts(aes)", .cra_driver_name = "xts-aes-tegra", .cra_priority = 500, + .cra_flags = CRYPTO_ALG_ASYNC, .cra_blocksize = AES_BLOCK_SIZE, .cra_ctxsize = sizeof(struct tegra_aes_ctx), .cra_alignmask = (__alignof__(u64) - 1), @@ -1922,6 +1923,7 @@ static struct tegra_se_alg tegra_aead_algs[] = { .cra_name = "gcm(aes)", .cra_driver_name = "gcm-aes-tegra", .cra_priority = 500, + .cra_flags = CRYPTO_ALG_ASYNC, .cra_blocksize = 1, .cra_ctxsize = sizeof(struct tegra_aead_ctx), .cra_alignmask = 0xf, @@ -1944,6 +1946,7 @@ static struct tegra_se_alg tegra_aead_algs[] = { .cra_name = "ccm(aes)", .cra_driver_name = "ccm-aes-tegra", .cra_priority = 500, + .cra_flags = CRYPTO_ALG_ASYNC, .cra_blocksize = 1, .cra_ctxsize = sizeof(struct tegra_aead_ctx), .cra_alignmask = 0xf, @@ -1971,7 +1974,7 @@ static struct tegra_se_alg tegra_cmac_algs[] = { .cra_name = "cmac(aes)", .cra_driver_name = "tegra-se-cmac", .cra_priority = 300, - .cra_flags = CRYPTO_ALG_TYPE_AHASH, + .cra_flags = CRYPTO_ALG_ASYNC, .cra_blocksize = AES_BLOCK_SIZE, .cra_ctxsize = sizeof(struct tegra_cmac_ctx), .cra_alignmask = 0, diff --git a/drivers/crypto/tegra/tegra-se-hash.c b/drivers/crypto/tegra/tegra-se-hash.c index 4a298ace6e9f..06bb5bf0fa33 100644 --- a/drivers/crypto/tegra/tegra-se-hash.c +++ b/drivers/crypto/tegra/tegra-se-hash.c @@ -761,7 +761,7 @@ static struct tegra_se_alg tegra_hash_algs[] = { .cra_name = "sha1", .cra_driver_name = "tegra-se-sha1", .cra_priority = 300, - .cra_flags = CRYPTO_ALG_TYPE_AHASH, + .cra_flags = CRYPTO_ALG_ASYNC, .cra_blocksize = SHA1_BLOCK_SIZE, .cra_ctxsize = sizeof(struct tegra_sha_ctx), .cra_alignmask = 0, @@ -786,7 +786,7 @@ static struct tegra_se_alg tegra_hash_algs[] = { .cra_name = "sha224", .cra_driver_name = "tegra-se-sha224", .cra_priority = 300, - .cra_flags = CRYPTO_ALG_TYPE_AHASH, + .cra_flags = CRYPTO_ALG_ASYNC, .cra_blocksize = SHA224_BLOCK_SIZE, .cra_ctxsize = sizeof(struct tegra_sha_ctx), .cra_alignmask = 0, @@ -811,7 +811,7 @@ static struct tegra_se_alg tegra_hash_algs[] = { .cra_name = "sha256", .cra_driver_name = "tegra-se-sha256", .cra_priority = 300, - .cra_flags = CRYPTO_ALG_TYPE_AHASH, + .cra_flags = CRYPTO_ALG_ASYNC, .cra_blocksize = SHA256_BLOCK_SIZE, .cra_ctxsize = sizeof(struct tegra_sha_ctx), .cra_alignmask = 0, @@ -836,7 +836,7 @@ static struct tegra_se_alg tegra_hash_algs[] = { .cra_name = "sha384", .cra_driver_name = "tegra-se-sha384", .cra_priority = 300, - .cra_flags = CRYPTO_ALG_TYPE_AHASH, + .cra_flags = CRYPTO_ALG_ASYNC, .cra_blocksize = SHA384_BLOCK_SIZE, .cra_ctxsize = sizeof(struct tegra_sha_ctx), .cra_alignmask = 0, @@ -861,7 +861,7 @@ static struct tegra_se_alg tegra_hash_algs[] = { .cra_name = "sha512", .cra_driver_name = "tegra-se-sha512", .cra_priority = 300, - .cra_flags = CRYPTO_ALG_TYPE_AHASH, + .cra_flags = CRYPTO_ALG_ASYNC, .cra_blocksize = SHA512_BLOCK_SIZE, .cra_ctxsize = sizeof(struct tegra_sha_ctx), .cra_alignmask = 0, @@ -886,7 +886,7 @@ static struct tegra_se_alg tegra_hash_algs[] = { .cra_name = "sha3-224", .cra_driver_name = "tegra-se-sha3-224", .cra_priority = 300, - .cra_flags = CRYPTO_ALG_TYPE_AHASH, + .cra_flags = CRYPTO_ALG_ASYNC, .cra_blocksize = SHA3_224_BLOCK_SIZE, .cra_ctxsize = sizeof(struct tegra_sha_ctx), .cra_alignmask = 0, @@ -911,7 +911,7 @@ static struct tegra_se_alg tegra_hash_algs[] = { .cra_name = "sha3-256", .cra_driver_name = "tegra-se-sha3-256", .cra_priority = 300, - .cra_flags = CRYPTO_ALG_TYPE_AHASH, + .cra_flags = CRYPTO_ALG_ASYNC, .cra_blocksize = SHA3_256_BLOCK_SIZE, .cra_ctxsize = sizeof(struct tegra_sha_ctx), .cra_alignmask = 0, @@ -936,7 +936,7 @@ static struct tegra_se_alg tegra_hash_algs[] = { .cra_name = "sha3-384", .cra_driver_name = "tegra-se-sha3-384", .cra_priority = 300, - .cra_flags = CRYPTO_ALG_TYPE_AHASH, + .cra_flags = CRYPTO_ALG_ASYNC, .cra_blocksize = SHA3_384_BLOCK_SIZE, .cra_ctxsize = sizeof(struct tegra_sha_ctx), .cra_alignmask = 0, @@ -961,7 +961,7 @@ static struct tegra_se_alg tegra_hash_algs[] = { .cra_name = "sha3-512", .cra_driver_name = "tegra-se-sha3-512", .cra_priority = 300, - .cra_flags = CRYPTO_ALG_TYPE_AHASH, + .cra_flags = CRYPTO_ALG_ASYNC, .cra_blocksize = SHA3_512_BLOCK_SIZE, .cra_ctxsize = sizeof(struct tegra_sha_ctx), .cra_alignmask = 0, @@ -988,7 +988,8 @@ static struct tegra_se_alg tegra_hash_algs[] = { .cra_name = "hmac(sha224)", .cra_driver_name = "tegra-se-hmac-sha224", .cra_priority = 300, - .cra_flags = CRYPTO_ALG_TYPE_AHASH | CRYPTO_ALG_NEED_FALLBACK, + .cra_flags = CRYPTO_ALG_ASYNC | + CRYPTO_ALG_NEED_FALLBACK, .cra_blocksize = SHA224_BLOCK_SIZE, .cra_ctxsize = sizeof(struct tegra_sha_ctx), .cra_alignmask = 0, @@ -1015,7 +1016,8 @@ static struct tegra_se_alg tegra_hash_algs[] = { .cra_name = "hmac(sha256)", .cra_driver_name = "tegra-se-hmac-sha256", .cra_priority = 300, - .cra_flags = CRYPTO_ALG_TYPE_AHASH | CRYPTO_ALG_NEED_FALLBACK, + .cra_flags = CRYPTO_ALG_ASYNC | + CRYPTO_ALG_NEED_FALLBACK, .cra_blocksize = SHA256_BLOCK_SIZE, .cra_ctxsize = sizeof(struct tegra_sha_ctx), .cra_alignmask = 0, @@ -1042,7 +1044,8 @@ static struct tegra_se_alg tegra_hash_algs[] = { .cra_name = "hmac(sha384)", .cra_driver_name = "tegra-se-hmac-sha384", .cra_priority = 300, - .cra_flags = CRYPTO_ALG_TYPE_AHASH | CRYPTO_ALG_NEED_FALLBACK, + .cra_flags = CRYPTO_ALG_ASYNC | + CRYPTO_ALG_NEED_FALLBACK, .cra_blocksize = SHA384_BLOCK_SIZE, .cra_ctxsize = sizeof(struct tegra_sha_ctx), .cra_alignmask = 0, @@ -1069,7 +1072,8 @@ static struct tegra_se_alg tegra_hash_algs[] = { .cra_name = "hmac(sha512)", .cra_driver_name = "tegra-se-hmac-sha512", .cra_priority = 300, - .cra_flags = CRYPTO_ALG_TYPE_AHASH | CRYPTO_ALG_NEED_FALLBACK, + .cra_flags = CRYPTO_ALG_ASYNC | + CRYPTO_ALG_NEED_FALLBACK, .cra_blocksize = SHA512_BLOCK_SIZE, .cra_ctxsize = sizeof(struct tegra_sha_ctx), .cra_alignmask = 0, diff --git a/drivers/cxl/Kconfig b/drivers/cxl/Kconfig index 4589bf11d3fe..80aeb0d556bd 100644 --- a/drivers/cxl/Kconfig +++ b/drivers/cxl/Kconfig @@ -59,6 +59,7 @@ config CXL_ACPI tristate "CXL ACPI: Platform Support" depends on ACPI depends on ACPI_NUMA + depends on CXL_PMEM || !CXL_PMEM default CXL_BUS select ACPI_TABLE_LIB select ACPI_HMAT diff --git a/drivers/cxl/core/hdm.c b/drivers/cxl/core/hdm.c index c222e98ae736..cb5d5a047a9d 100644 --- a/drivers/cxl/core/hdm.c +++ b/drivers/cxl/core/hdm.c @@ -94,7 +94,6 @@ static bool should_emulate_decoders(struct cxl_endpoint_dvsec_info *info) struct cxl_hdm *cxlhdm; void __iomem *hdm; u32 ctrl; - int i; if (!info) return false; @@ -113,22 +112,16 @@ static bool should_emulate_decoders(struct cxl_endpoint_dvsec_info *info) return false; /* - * If any decoders are committed already, there should not be any - * emulated DVSEC decoders. + * If HDM decoders are globally enabled, do not fall back to DVSEC + * range emulation. Zeroed decoder registers after region teardown + * do not imply absence of HDM capability. + * + * Falling back to DVSEC here would treat the decoder as AUTO and + * may incorrectly latch default interleave settings. */ - for (i = 0; i < cxlhdm->decoder_count; i++) { - ctrl = readl(hdm + CXL_HDM_DECODER0_CTRL_OFFSET(i)); - dev_dbg(&info->port->dev, - "decoder%d.%d: committed: %ld base: %#x_%.8x size: %#x_%.8x\n", - info->port->id, i, - FIELD_GET(CXL_HDM_DECODER0_CTRL_COMMITTED, ctrl), - readl(hdm + CXL_HDM_DECODER0_BASE_HIGH_OFFSET(i)), - readl(hdm + CXL_HDM_DECODER0_BASE_LOW_OFFSET(i)), - readl(hdm + CXL_HDM_DECODER0_SIZE_HIGH_OFFSET(i)), - readl(hdm + CXL_HDM_DECODER0_SIZE_LOW_OFFSET(i))); - if (FIELD_GET(CXL_HDM_DECODER0_CTRL_COMMITTED, ctrl)) - return false; - } + ctrl = readl(hdm + CXL_HDM_DECODER_CTRL_OFFSET); + if (ctrl & CXL_HDM_DECODER_ENABLE) + return false; return true; } diff --git a/drivers/cxl/core/mbox.c b/drivers/cxl/core/mbox.c index e7a6452bf544..12386d912705 100644 --- a/drivers/cxl/core/mbox.c +++ b/drivers/cxl/core/mbox.c @@ -1301,7 +1301,7 @@ int cxl_mem_sanitize(struct cxl_memdev *cxlmd, u16 cmd) * Require an endpoint to be safe otherwise the driver can not * be sure that the device is unmapped. */ - if (endpoint && cxl_num_decoders_committed(endpoint) == 0) + if (cxlmd->dev.driver && cxl_num_decoders_committed(endpoint) == 0) return __cxl_mem_sanitize(mds, cmd); return -EBUSY; diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c index 0c5957d1d329..c5aacd7054f1 100644 --- a/drivers/cxl/core/port.c +++ b/drivers/cxl/core/port.c @@ -552,10 +552,13 @@ static void cxl_port_release(struct device *dev) xa_destroy(&port->dports); xa_destroy(&port->regions); ida_free(&cxl_port_ida, port->id); - if (is_cxl_root(port)) + + if (is_cxl_root(port)) { kfree(to_cxl_root(port)); - else + } else { + put_device(dev->parent); kfree(port); + } } static ssize_t decoders_committed_show(struct device *dev, @@ -707,6 +710,7 @@ static struct cxl_port *cxl_port_alloc(struct device *uport_dev, struct cxl_port *iter; dev->parent = &parent_port->dev; + get_device(dev->parent); port->depth = parent_port->depth + 1; port->parent_dport = parent_dport; diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c index 42874948b589..c37ae0b28bbb 100644 --- a/drivers/cxl/core/region.c +++ b/drivers/cxl/core/region.c @@ -3854,8 +3854,10 @@ static int __construct_region(struct cxl_region *cxlr, } rc = sysfs_update_group(&cxlr->dev.kobj, &cxl_region_group); - if (rc) + if (rc) { + kfree(res); return rc; + } rc = insert_resource(cxlrd->res, res); if (rc) { diff --git a/drivers/cxl/pmem.c b/drivers/cxl/pmem.c index 082ec0f1c3a0..261dff7ced9f 100644 --- a/drivers/cxl/pmem.c +++ b/drivers/cxl/pmem.c @@ -554,7 +554,7 @@ static __exit void cxl_pmem_exit(void) MODULE_DESCRIPTION("CXL PMEM: Persistent Memory Support"); MODULE_LICENSE("GPL v2"); -module_init(cxl_pmem_init); +subsys_initcall(cxl_pmem_init); module_exit(cxl_pmem_exit); MODULE_IMPORT_NS("CXL"); MODULE_ALIAS_CXL(CXL_DEVICE_NVDIMM_BRIDGE); diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c index e7d698b352d3..5397dbda4f72 100644 --- a/drivers/dma/dw-edma/dw-edma-core.c +++ b/drivers/dma/dw-edma/dw-edma-core.c @@ -844,6 +844,7 @@ static int dw_edma_irq_request(struct dw_edma *dw, { struct dw_edma_chip *chip = dw->chip; struct device *dev = dw->chip->dev; + struct msi_desc *msi_desc; u32 wr_mask = 1; u32 rd_mask = 1; int i, err = 0; @@ -895,9 +896,12 @@ static int dw_edma_irq_request(struct dw_edma *dw, &dw->irq[i]); if (err) goto err_irq_free; - - if (irq_get_msi_desc(irq)) + msi_desc = irq_get_msi_desc(irq); + if (msi_desc) { get_cached_msi_msg(irq, &dw->irq[i].msi); + if (!msi_desc->pci.msi_attrib.is_msix) + dw->irq[i].msi.data = dw->irq[0].msi.data + i; + } } dw->nr_irqs = i; diff --git a/drivers/dma/dw-edma/dw-hdma-v0-core.c b/drivers/dma/dw-edma/dw-hdma-v0-core.c index e3f8db4fe909..ce8f7254bab2 100644 --- a/drivers/dma/dw-edma/dw-hdma-v0-core.c +++ b/drivers/dma/dw-edma/dw-hdma-v0-core.c @@ -252,10 +252,10 @@ static void dw_hdma_v0_core_start(struct dw_edma_chunk *chunk, bool first) lower_32_bits(chunk->ll_region.paddr)); SET_CH_32(dw, chan->dir, chan->id, llp.msb, upper_32_bits(chunk->ll_region.paddr)); + /* Set consumer cycle */ + SET_CH_32(dw, chan->dir, chan->id, cycle_sync, + HDMA_V0_CONSUMER_CYCLE_STAT | HDMA_V0_CONSUMER_CYCLE_BIT); } - /* Set consumer cycle */ - SET_CH_32(dw, chan->dir, chan->id, cycle_sync, - HDMA_V0_CONSUMER_CYCLE_STAT | HDMA_V0_CONSUMER_CYCLE_BIT); dw_hdma_v0_sync_ll_data(chunk); diff --git a/drivers/dma/fsl-edma-main.c b/drivers/dma/fsl-edma-main.c index dbcdd1e68319..b596baa0a182 100644 --- a/drivers/dma/fsl-edma-main.c +++ b/drivers/dma/fsl-edma-main.c @@ -317,10 +317,8 @@ static struct dma_chan *fsl_edma3_xlate(struct of_phandle_args *dma_spec, return NULL; i = fsl_chan - fsl_edma->chans; - fsl_chan->priority = dma_spec->args[1]; - fsl_chan->is_rxchan = dma_spec->args[2] & FSL_EDMA_RX; - fsl_chan->is_remote = dma_spec->args[2] & FSL_EDMA_REMOTE; - fsl_chan->is_multi_fifo = dma_spec->args[2] & FSL_EDMA_MULTI_FIFO; + if (!b_chmux && i != dma_spec->args[0]) + continue; if ((dma_spec->args[2] & FSL_EDMA_EVEN_CH) && (i & 0x1)) continue; @@ -328,17 +326,15 @@ static struct dma_chan *fsl_edma3_xlate(struct of_phandle_args *dma_spec, if ((dma_spec->args[2] & FSL_EDMA_ODD_CH) && !(i & 0x1)) continue; - if (!b_chmux && i == dma_spec->args[0]) { - chan = dma_get_slave_channel(chan); - chan->device->privatecnt++; - return chan; - } else if (b_chmux && !fsl_chan->srcid) { - /* if controller support channel mux, choose a free channel */ - chan = dma_get_slave_channel(chan); - chan->device->privatecnt++; - fsl_chan->srcid = dma_spec->args[0]; - return chan; - } + fsl_chan->srcid = dma_spec->args[0]; + fsl_chan->priority = dma_spec->args[1]; + fsl_chan->is_rxchan = dma_spec->args[2] & FSL_EDMA_RX; + fsl_chan->is_remote = dma_spec->args[2] & FSL_EDMA_REMOTE; + fsl_chan->is_multi_fifo = dma_spec->args[2] & FSL_EDMA_MULTI_FIFO; + + chan = dma_get_slave_channel(chan); + chan->device->privatecnt++; + return chan; } return NULL; } diff --git a/drivers/dma/idxd/cdev.c b/drivers/dma/idxd/cdev.c index c37d233535f9..0366c7cf3502 100644 --- a/drivers/dma/idxd/cdev.c +++ b/drivers/dma/idxd/cdev.c @@ -158,11 +158,7 @@ static const struct device_type idxd_cdev_file_type = { static void idxd_cdev_dev_release(struct device *dev) { struct idxd_cdev *idxd_cdev = dev_to_cdev(dev); - struct idxd_cdev_context *cdev_ctx; - struct idxd_wq *wq = idxd_cdev->wq; - cdev_ctx = &ictx[wq->idxd->data->type]; - ida_free(&cdev_ctx->minor_ida, idxd_cdev->minor); kfree(idxd_cdev); } @@ -582,11 +578,15 @@ int idxd_wq_add_cdev(struct idxd_wq *wq) void idxd_wq_del_cdev(struct idxd_wq *wq) { + struct idxd_cdev_context *cdev_ctx; struct idxd_cdev *idxd_cdev; idxd_cdev = wq->idxd_cdev; wq->idxd_cdev = NULL; cdev_device_del(&idxd_cdev->cdev, cdev_dev(idxd_cdev)); + + cdev_ctx = &ictx[wq->idxd->data->type]; + ida_free(&cdev_ctx->minor_ida, idxd_cdev->minor); put_device(cdev_dev(idxd_cdev)); } diff --git a/drivers/dma/idxd/device.c b/drivers/dma/idxd/device.c index c26128529ff4..131138483b87 100644 --- a/drivers/dma/idxd/device.c +++ b/drivers/dma/idxd/device.c @@ -175,6 +175,7 @@ void idxd_wq_free_resources(struct idxd_wq *wq) free_descs(wq); dma_free_coherent(dev, wq->compls_size, wq->compls, wq->compls_addr); sbitmap_queue_free(&wq->sbq); + wq->type = IDXD_WQT_NONE; } EXPORT_SYMBOL_NS_GPL(idxd_wq_free_resources, "IDXD"); @@ -382,7 +383,6 @@ static void idxd_wq_disable_cleanup(struct idxd_wq *wq) lockdep_assert_held(&wq->wq_lock); wq->state = IDXD_WQ_DISABLED; memset(wq->wqcfg, 0, idxd->wqcfg_size); - wq->type = IDXD_WQT_NONE; wq->threshold = 0; wq->priority = 0; wq->enqcmds_retries = IDXD_ENQCMDS_RETRIES; @@ -831,8 +831,7 @@ static void idxd_device_evl_free(struct idxd_device *idxd) struct device *dev = &idxd->pdev->dev; struct idxd_evl *evl = idxd->evl; - gencfg.bits = ioread32(idxd->reg_base + IDXD_GENCFG_OFFSET); - if (!gencfg.evl_en) + if (!evl) return; mutex_lock(&evl->lock); @@ -1125,7 +1124,11 @@ int idxd_device_config(struct idxd_device *idxd) { int rc; - lockdep_assert_held(&idxd->dev_lock); + guard(spinlock)(&idxd->dev_lock); + + if (!test_bit(IDXD_FLAG_CONFIGURABLE, &idxd->flags)) + return 0; + rc = idxd_wqs_setup(idxd); if (rc < 0) return rc; @@ -1332,6 +1335,11 @@ void idxd_wq_free_irq(struct idxd_wq *wq) free_irq(ie->vector, ie); idxd_flush_pending_descs(ie); + + /* The interrupt might have been already released by FLR */ + if (ie->int_handle == INVALID_INT_HANDLE) + return; + if (idxd->request_int_handles) idxd_device_release_int_handle(idxd, ie->int_handle, IDXD_IRQ_MSIX); idxd_device_clear_perm_entry(idxd, ie); @@ -1340,6 +1348,23 @@ void idxd_wq_free_irq(struct idxd_wq *wq) ie->pasid = IOMMU_PASID_INVALID; } +void idxd_wq_flush_descs(struct idxd_wq *wq) +{ + struct idxd_irq_entry *ie = &wq->ie; + struct idxd_device *idxd = wq->idxd; + + guard(mutex)(&wq->wq_lock); + + if (wq->state != IDXD_WQ_ENABLED || wq->type != IDXD_WQT_KERNEL) + return; + + idxd_flush_pending_descs(ie); + if (idxd->request_int_handles) + idxd_device_release_int_handle(idxd, ie->int_handle, IDXD_IRQ_MSIX); + idxd_device_clear_perm_entry(idxd, ie); + ie->int_handle = INVALID_INT_HANDLE; +} + int idxd_wq_request_irq(struct idxd_wq *wq) { struct idxd_device *idxd = wq->idxd; @@ -1454,11 +1479,7 @@ int idxd_drv_enable_wq(struct idxd_wq *wq) } } - rc = 0; - spin_lock(&idxd->dev_lock); - if (test_bit(IDXD_FLAG_CONFIGURABLE, &idxd->flags)) - rc = idxd_device_config(idxd); - spin_unlock(&idxd->dev_lock); + rc = idxd_device_config(idxd); if (rc < 0) { dev_dbg(dev, "Writing wq %d config failed: %d\n", wq->id, rc); goto err; @@ -1533,7 +1554,6 @@ void idxd_drv_disable_wq(struct idxd_wq *wq) idxd_wq_reset(wq); idxd_wq_free_resources(wq); percpu_ref_exit(&wq->wq_active); - wq->type = IDXD_WQT_NONE; wq->client_count = 0; } EXPORT_SYMBOL_NS_GPL(idxd_drv_disable_wq, "IDXD"); @@ -1554,10 +1574,7 @@ int idxd_device_drv_probe(struct idxd_dev *idxd_dev) } /* Device configuration */ - spin_lock(&idxd->dev_lock); - if (test_bit(IDXD_FLAG_CONFIGURABLE, &idxd->flags)) - rc = idxd_device_config(idxd); - spin_unlock(&idxd->dev_lock); + rc = idxd_device_config(idxd); if (rc < 0) return -ENXIO; diff --git a/drivers/dma/idxd/dma.c b/drivers/dma/idxd/dma.c index dbecd699237e..9937b671f637 100644 --- a/drivers/dma/idxd/dma.c +++ b/drivers/dma/idxd/dma.c @@ -194,6 +194,22 @@ static void idxd_dma_release(struct dma_device *device) kfree(idxd_dma); } +static int idxd_dma_terminate_all(struct dma_chan *c) +{ + struct idxd_wq *wq = to_idxd_wq(c); + + idxd_wq_flush_descs(wq); + + return 0; +} + +static void idxd_dma_synchronize(struct dma_chan *c) +{ + struct idxd_wq *wq = to_idxd_wq(c); + + idxd_wq_drain(wq); +} + int idxd_register_dma_device(struct idxd_device *idxd) { struct idxd_dma_dev *idxd_dma; @@ -224,6 +240,8 @@ int idxd_register_dma_device(struct idxd_device *idxd) dma->device_issue_pending = idxd_dma_issue_pending; dma->device_alloc_chan_resources = idxd_dma_alloc_chan_resources; dma->device_free_chan_resources = idxd_dma_free_chan_resources; + dma->device_terminate_all = idxd_dma_terminate_all; + dma->device_synchronize = idxd_dma_synchronize; rc = dma_async_device_register(dma); if (rc < 0) { diff --git a/drivers/dma/idxd/idxd.h b/drivers/dma/idxd/idxd.h index ea8c4daed38d..ce78b9a7c641 100644 --- a/drivers/dma/idxd/idxd.h +++ b/drivers/dma/idxd/idxd.h @@ -803,6 +803,7 @@ void idxd_wq_quiesce(struct idxd_wq *wq); int idxd_wq_init_percpu_ref(struct idxd_wq *wq); void idxd_wq_free_irq(struct idxd_wq *wq); int idxd_wq_request_irq(struct idxd_wq *wq); +void idxd_wq_flush_descs(struct idxd_wq *wq); /* submission */ int idxd_submit_desc(struct idxd_wq *wq, struct idxd_desc *desc); diff --git a/drivers/dma/idxd/init.c b/drivers/dma/idxd/init.c index fb80803d5b57..f1cfc7790d95 100644 --- a/drivers/dma/idxd/init.c +++ b/drivers/dma/idxd/init.c @@ -973,7 +973,8 @@ static void idxd_device_config_restore(struct idxd_device *idxd, idxd->rdbuf_limit = idxd_saved->saved_idxd.rdbuf_limit; - idxd->evl->size = saved_evl->size; + if (idxd->evl) + idxd->evl->size = saved_evl->size; for (i = 0; i < idxd->max_groups; i++) { struct idxd_group *saved_group, *group; @@ -1104,12 +1105,10 @@ static void idxd_reset_done(struct pci_dev *pdev) idxd_device_config_restore(idxd, idxd->idxd_saved); /* Re-configure IDXD device if allowed. */ - if (test_bit(IDXD_FLAG_CONFIGURABLE, &idxd->flags)) { - rc = idxd_device_config(idxd); - if (rc < 0) { - dev_err(dev, "HALT: %s config fails\n", idxd_name); - goto out; - } + rc = idxd_device_config(idxd); + if (rc < 0) { + dev_err(dev, "HALT: %s config fails\n", idxd_name); + goto out; } /* Bind IDXD device to driver. */ @@ -1147,6 +1146,7 @@ static void idxd_reset_done(struct pci_dev *pdev) } out: kfree(idxd->idxd_saved); + idxd->idxd_saved = NULL; } static const struct pci_error_handlers idxd_error_handler = { diff --git a/drivers/dma/idxd/irq.c b/drivers/dma/idxd/irq.c index 7782f8c51c32..6a25e1fd0e62 100644 --- a/drivers/dma/idxd/irq.c +++ b/drivers/dma/idxd/irq.c @@ -397,6 +397,17 @@ static void idxd_device_flr(struct work_struct *work) dev_err(&idxd->pdev->dev, "FLR failed\n"); } +static void idxd_wqs_flush_descs(struct idxd_device *idxd) +{ + int i; + + for (i = 0; i < idxd->max_wqs; i++) { + struct idxd_wq *wq = idxd->wqs[i]; + + idxd_wq_flush_descs(wq); + } +} + static irqreturn_t idxd_halt(struct idxd_device *idxd) { union gensts_reg gensts; @@ -415,6 +426,11 @@ static irqreturn_t idxd_halt(struct idxd_device *idxd) } else if (gensts.reset_type == IDXD_DEVICE_RESET_FLR) { idxd->state = IDXD_DEV_HALTED; idxd_mask_error_interrupts(idxd); + /* Flush all pending descriptors, and disable + * interrupts, they will be re-enabled when FLR + * concludes. + */ + idxd_wqs_flush_descs(idxd); dev_dbg(&idxd->pdev->dev, "idxd halted, doing FLR. After FLR, configs are restored\n"); INIT_WORK(&idxd->work, idxd_device_flr); diff --git a/drivers/dma/idxd/submit.c b/drivers/dma/idxd/submit.c index 6db1c5fcedc5..03217041b8b3 100644 --- a/drivers/dma/idxd/submit.c +++ b/drivers/dma/idxd/submit.c @@ -138,7 +138,7 @@ static void llist_abort_desc(struct idxd_wq *wq, struct idxd_irq_entry *ie, */ list_for_each_entry_safe(d, t, &flist, list) { list_del_init(&d->list); - idxd_dma_complete_txd(found, IDXD_COMPLETE_ABORT, true, + idxd_dma_complete_txd(d, IDXD_COMPLETE_ABORT, true, NULL, NULL); } } diff --git a/drivers/dma/idxd/sysfs.c b/drivers/dma/idxd/sysfs.c index cc2c83d7f710..6d251095c350 100644 --- a/drivers/dma/idxd/sysfs.c +++ b/drivers/dma/idxd/sysfs.c @@ -1836,6 +1836,7 @@ static void idxd_conf_device_release(struct device *dev) { struct idxd_device *idxd = confdev_to_idxd(dev); + destroy_workqueue(idxd->wq); kfree(idxd->groups); bitmap_free(idxd->wq_enable_map); kfree(idxd->wqs); diff --git a/drivers/dma/sh/rz-dmac.c b/drivers/dma/sh/rz-dmac.c index d84ca551b2bf..f30bdf69c740 100644 --- a/drivers/dma/sh/rz-dmac.c +++ b/drivers/dma/sh/rz-dmac.c @@ -10,6 +10,7 @@ */ #include <linux/bitfield.h> +#include <linux/cleanup.h> #include <linux/dma-mapping.h> #include <linux/dmaengine.h> #include <linux/interrupt.h> @@ -296,13 +297,10 @@ static void rz_dmac_disable_hw(struct rz_dmac_chan *channel) { struct dma_chan *chan = &channel->vc.chan; struct rz_dmac *dmac = to_rz_dmac(chan->device); - unsigned long flags; dev_dbg(dmac->dev, "%s channel %d\n", __func__, channel->index); - local_irq_save(flags); rz_dmac_ch_writel(channel, CHCTRL_DEFAULT, CHCTRL, 1); - local_irq_restore(flags); } static void rz_dmac_set_dmars_register(struct rz_dmac *dmac, int nr, u32 dmars) @@ -447,6 +445,7 @@ static int rz_dmac_alloc_chan_resources(struct dma_chan *chan) if (!desc) break; + /* No need to lock. This is called only for the 1st client. */ list_add_tail(&desc->node, &channel->ld_free); channel->descs_allocated++; } @@ -502,18 +501,21 @@ rz_dmac_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, dev_dbg(dmac->dev, "%s channel: %d src=0x%pad dst=0x%pad len=%zu\n", __func__, channel->index, &src, &dest, len); - if (list_empty(&channel->ld_free)) - return NULL; + scoped_guard(spinlock_irqsave, &channel->vc.lock) { + if (list_empty(&channel->ld_free)) + return NULL; - desc = list_first_entry(&channel->ld_free, struct rz_dmac_desc, node); + desc = list_first_entry(&channel->ld_free, struct rz_dmac_desc, node); - desc->type = RZ_DMAC_DESC_MEMCPY; - desc->src = src; - desc->dest = dest; - desc->len = len; - desc->direction = DMA_MEM_TO_MEM; + desc->type = RZ_DMAC_DESC_MEMCPY; + desc->src = src; + desc->dest = dest; + desc->len = len; + desc->direction = DMA_MEM_TO_MEM; + + list_move_tail(channel->ld_free.next, &channel->ld_queue); + } - list_move_tail(channel->ld_free.next, &channel->ld_queue); return vchan_tx_prep(&channel->vc, &desc->vd, flags); } @@ -529,27 +531,29 @@ rz_dmac_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, int dma_length = 0; int i = 0; - if (list_empty(&channel->ld_free)) - return NULL; + scoped_guard(spinlock_irqsave, &channel->vc.lock) { + if (list_empty(&channel->ld_free)) + return NULL; - desc = list_first_entry(&channel->ld_free, struct rz_dmac_desc, node); + desc = list_first_entry(&channel->ld_free, struct rz_dmac_desc, node); - for_each_sg(sgl, sg, sg_len, i) { - dma_length += sg_dma_len(sg); - } + for_each_sg(sgl, sg, sg_len, i) + dma_length += sg_dma_len(sg); - desc->type = RZ_DMAC_DESC_SLAVE_SG; - desc->sg = sgl; - desc->sgcount = sg_len; - desc->len = dma_length; - desc->direction = direction; + desc->type = RZ_DMAC_DESC_SLAVE_SG; + desc->sg = sgl; + desc->sgcount = sg_len; + desc->len = dma_length; + desc->direction = direction; - if (direction == DMA_DEV_TO_MEM) - desc->src = channel->src_per_address; - else - desc->dest = channel->dst_per_address; + if (direction == DMA_DEV_TO_MEM) + desc->src = channel->src_per_address; + else + desc->dest = channel->dst_per_address; + + list_move_tail(channel->ld_free.next, &channel->ld_queue); + } - list_move_tail(channel->ld_free.next, &channel->ld_queue); return vchan_tx_prep(&channel->vc, &desc->vd, flags); } @@ -561,8 +565,8 @@ static int rz_dmac_terminate_all(struct dma_chan *chan) unsigned int i; LIST_HEAD(head); - rz_dmac_disable_hw(channel); spin_lock_irqsave(&channel->vc.lock, flags); + rz_dmac_disable_hw(channel); for (i = 0; i < DMAC_NR_LMDESC; i++) lmdesc[i].header = 0; @@ -699,7 +703,9 @@ static void rz_dmac_irq_handle_channel(struct rz_dmac_chan *channel) if (chstat & CHSTAT_ER) { dev_err(dmac->dev, "DMAC err CHSTAT_%d = %08X\n", channel->index, chstat); - rz_dmac_ch_writel(channel, CHCTRL_DEFAULT, CHCTRL, 1); + + scoped_guard(spinlock_irqsave, &channel->vc.lock) + rz_dmac_ch_writel(channel, CHCTRL_DEFAULT, CHCTRL, 1); goto done; } diff --git a/drivers/dma/xilinx/xdma.c b/drivers/dma/xilinx/xdma.c index d02a4dac2291..782a55edc55b 100644 --- a/drivers/dma/xilinx/xdma.c +++ b/drivers/dma/xilinx/xdma.c @@ -1234,8 +1234,8 @@ static int xdma_probe(struct platform_device *pdev) xdev->rmap = devm_regmap_init_mmio(&pdev->dev, reg_base, &xdma_regmap_config); - if (!xdev->rmap) { - xdma_err(xdev, "config regmap failed: %d", ret); + if (IS_ERR(xdev->rmap)) { + xdma_err(xdev, "config regmap failed: %pe", xdev->rmap); goto failed; } INIT_LIST_HEAD(&xdev->dma_dev.channels); diff --git a/drivers/dma/xilinx/xilinx_dma.c b/drivers/dma/xilinx/xilinx_dma.c index b53292e02448..e3a18ee42aa2 100644 --- a/drivers/dma/xilinx/xilinx_dma.c +++ b/drivers/dma/xilinx/xilinx_dma.c @@ -997,16 +997,16 @@ static u32 xilinx_dma_get_residue(struct xilinx_dma_chan *chan, struct xilinx_cdma_tx_segment, node); cdma_hw = &cdma_seg->hw; - residue += (cdma_hw->control - cdma_hw->status) & - chan->xdev->max_buffer_len; + residue += (cdma_hw->control & chan->xdev->max_buffer_len) - + (cdma_hw->status & chan->xdev->max_buffer_len); } else if (chan->xdev->dma_config->dmatype == XDMA_TYPE_AXIDMA) { axidma_seg = list_entry(entry, struct xilinx_axidma_tx_segment, node); axidma_hw = &axidma_seg->hw; - residue += (axidma_hw->control - axidma_hw->status) & - chan->xdev->max_buffer_len; + residue += (axidma_hw->control & chan->xdev->max_buffer_len) - + (axidma_hw->status & chan->xdev->max_buffer_len); } else { aximcdma_seg = list_entry(entry, @@ -1014,8 +1014,8 @@ static u32 xilinx_dma_get_residue(struct xilinx_dma_chan *chan, node); aximcdma_hw = &aximcdma_seg->hw; residue += - (aximcdma_hw->control - aximcdma_hw->status) & - chan->xdev->max_buffer_len; + (aximcdma_hw->control & chan->xdev->max_buffer_len) - + (aximcdma_hw->status & chan->xdev->max_buffer_len); } } @@ -1235,14 +1235,6 @@ static int xilinx_dma_alloc_chan_resources(struct dma_chan *dchan) dma_cookie_init(dchan); - if (chan->xdev->dma_config->dmatype == XDMA_TYPE_AXIDMA) { - /* For AXI DMA resetting once channel will reset the - * other channel as well so enable the interrupts here. - */ - dma_ctrl_set(chan, XILINX_DMA_REG_DMACR, - XILINX_DMA_DMAXR_ALL_IRQ_MASK); - } - if ((chan->xdev->dma_config->dmatype == XDMA_TYPE_CDMA) && chan->has_sg) dma_ctrl_set(chan, XILINX_DMA_REG_DMACR, XILINX_CDMA_CR_SGMODE); @@ -1564,8 +1556,29 @@ static void xilinx_dma_start_transfer(struct xilinx_dma_chan *chan) if (chan->err) return; - if (list_empty(&chan->pending_list)) + if (list_empty(&chan->pending_list)) { + if (chan->cyclic) { + struct xilinx_dma_tx_descriptor *desc; + struct list_head *entry; + + desc = list_last_entry(&chan->done_list, + struct xilinx_dma_tx_descriptor, node); + list_for_each(entry, &desc->segments) { + struct xilinx_axidma_tx_segment *axidma_seg; + struct xilinx_axidma_desc_hw *axidma_hw; + axidma_seg = list_entry(entry, + struct xilinx_axidma_tx_segment, + node); + axidma_hw = &axidma_seg->hw; + axidma_hw->status = 0; + } + + list_splice_tail_init(&chan->done_list, &chan->active_list); + chan->desc_pendingcount = 0; + chan->idle = false; + } return; + } if (!chan->idle) return; @@ -1591,6 +1604,7 @@ static void xilinx_dma_start_transfer(struct xilinx_dma_chan *chan) head_desc->async_tx.phys); reg &= ~XILINX_DMA_CR_DELAY_MAX; reg |= chan->irq_delay << XILINX_DMA_CR_DELAY_SHIFT; + reg |= XILINX_DMA_DMAXR_ALL_IRQ_MASK; dma_ctrl_write(chan, XILINX_DMA_REG_DMACR, reg); xilinx_dma_start(chan); @@ -3024,7 +3038,7 @@ static int xilinx_dma_chan_probe(struct xilinx_dma_device *xdev, return -EINVAL; } - xdev->common.directions |= chan->direction; + xdev->common.directions |= BIT(chan->direction); /* Request the interrupt */ chan->irq = of_irq_get(node, chan->tdest); diff --git a/drivers/gpib/Kconfig b/drivers/gpib/Kconfig index eeb50956ce85..d43a28c62ed7 100644 --- a/drivers/gpib/Kconfig +++ b/drivers/gpib/Kconfig @@ -122,6 +122,7 @@ config GPIB_FLUKE depends on OF select GPIB_COMMON select GPIB_NEC7210 + depends on HAS_IOMEM help GPIB driver for Fluke based cda devices. diff --git a/drivers/gpib/common/gpib_os.c b/drivers/gpib/common/gpib_os.c index be757db993a5..97c98f0a7a43 100644 --- a/drivers/gpib/common/gpib_os.c +++ b/drivers/gpib/common/gpib_os.c @@ -888,10 +888,6 @@ static int read_ioctl(struct gpib_file_private *file_priv, struct gpib_board *bo if (read_cmd.completed_transfer_count > read_cmd.requested_transfer_count) return -EINVAL; - desc = handle_to_descriptor(file_priv, read_cmd.handle); - if (!desc) - return -EINVAL; - if (WARN_ON_ONCE(sizeof(userbuf) > sizeof(read_cmd.buffer_ptr))) return -EFAULT; @@ -904,6 +900,17 @@ static int read_ioctl(struct gpib_file_private *file_priv, struct gpib_board *bo if (!access_ok(userbuf, remain)) return -EFAULT; + /* Lock descriptors to prevent concurrent close from freeing descriptor */ + if (mutex_lock_interruptible(&file_priv->descriptors_mutex)) + return -ERESTARTSYS; + desc = handle_to_descriptor(file_priv, read_cmd.handle); + if (!desc) { + mutex_unlock(&file_priv->descriptors_mutex); + return -EINVAL; + } + atomic_inc(&desc->descriptor_busy); + mutex_unlock(&file_priv->descriptors_mutex); + atomic_set(&desc->io_in_progress, 1); /* Read buffer loads till we fill the user supplied buffer */ @@ -937,6 +944,7 @@ static int read_ioctl(struct gpib_file_private *file_priv, struct gpib_board *bo retval = copy_to_user((void __user *)arg, &read_cmd, sizeof(read_cmd)); atomic_set(&desc->io_in_progress, 0); + atomic_dec(&desc->descriptor_busy); wake_up_interruptible(&board->wait); if (retval) @@ -964,10 +972,6 @@ static int command_ioctl(struct gpib_file_private *file_priv, if (cmd.completed_transfer_count > cmd.requested_transfer_count) return -EINVAL; - desc = handle_to_descriptor(file_priv, cmd.handle); - if (!desc) - return -EINVAL; - userbuf = (u8 __user *)(unsigned long)cmd.buffer_ptr; userbuf += cmd.completed_transfer_count; @@ -980,6 +984,17 @@ static int command_ioctl(struct gpib_file_private *file_priv, if (!access_ok(userbuf, remain)) return -EFAULT; + /* Lock descriptors to prevent concurrent close from freeing descriptor */ + if (mutex_lock_interruptible(&file_priv->descriptors_mutex)) + return -ERESTARTSYS; + desc = handle_to_descriptor(file_priv, cmd.handle); + if (!desc) { + mutex_unlock(&file_priv->descriptors_mutex); + return -EINVAL; + } + atomic_inc(&desc->descriptor_busy); + mutex_unlock(&file_priv->descriptors_mutex); + /* * Write buffer loads till we empty the user supplied buffer. * Call drivers at least once, even if remain is zero, in @@ -1003,6 +1018,7 @@ static int command_ioctl(struct gpib_file_private *file_priv, userbuf += bytes_written; if (retval < 0) { atomic_set(&desc->io_in_progress, 0); + atomic_dec(&desc->descriptor_busy); wake_up_interruptible(&board->wait); break; @@ -1022,6 +1038,7 @@ static int command_ioctl(struct gpib_file_private *file_priv, */ if (!no_clear_io_in_prog || fault) atomic_set(&desc->io_in_progress, 0); + atomic_dec(&desc->descriptor_busy); wake_up_interruptible(&board->wait); if (fault) @@ -1047,10 +1064,6 @@ static int write_ioctl(struct gpib_file_private *file_priv, struct gpib_board *b if (write_cmd.completed_transfer_count > write_cmd.requested_transfer_count) return -EINVAL; - desc = handle_to_descriptor(file_priv, write_cmd.handle); - if (!desc) - return -EINVAL; - userbuf = (u8 __user *)(unsigned long)write_cmd.buffer_ptr; userbuf += write_cmd.completed_transfer_count; @@ -1060,6 +1073,17 @@ static int write_ioctl(struct gpib_file_private *file_priv, struct gpib_board *b if (!access_ok(userbuf, remain)) return -EFAULT; + /* Lock descriptors to prevent concurrent close from freeing descriptor */ + if (mutex_lock_interruptible(&file_priv->descriptors_mutex)) + return -ERESTARTSYS; + desc = handle_to_descriptor(file_priv, write_cmd.handle); + if (!desc) { + mutex_unlock(&file_priv->descriptors_mutex); + return -EINVAL; + } + atomic_inc(&desc->descriptor_busy); + mutex_unlock(&file_priv->descriptors_mutex); + atomic_set(&desc->io_in_progress, 1); /* Write buffer loads till we empty the user supplied buffer */ @@ -1094,6 +1118,7 @@ static int write_ioctl(struct gpib_file_private *file_priv, struct gpib_board *b fault = copy_to_user((void __user *)arg, &write_cmd, sizeof(write_cmd)); atomic_set(&desc->io_in_progress, 0); + atomic_dec(&desc->descriptor_busy); wake_up_interruptible(&board->wait); if (fault) @@ -1276,6 +1301,9 @@ static int close_dev_ioctl(struct file *filep, struct gpib_board *board, unsigne { struct gpib_close_dev_ioctl cmd; struct gpib_file_private *file_priv = filep->private_data; + struct gpib_descriptor *desc; + unsigned int pad; + int sad; int retval; retval = copy_from_user(&cmd, (void __user *)arg, sizeof(cmd)); @@ -1284,19 +1312,27 @@ static int close_dev_ioctl(struct file *filep, struct gpib_board *board, unsigne if (cmd.handle >= GPIB_MAX_NUM_DESCRIPTORS) return -EINVAL; - if (!file_priv->descriptors[cmd.handle]) - return -EINVAL; - retval = decrement_open_device_count(board, &board->device_list, - file_priv->descriptors[cmd.handle]->pad, - file_priv->descriptors[cmd.handle]->sad); - if (retval < 0) - return retval; - - kfree(file_priv->descriptors[cmd.handle]); + mutex_lock(&file_priv->descriptors_mutex); + desc = file_priv->descriptors[cmd.handle]; + if (!desc) { + mutex_unlock(&file_priv->descriptors_mutex); + return -EINVAL; + } + if (atomic_read(&desc->descriptor_busy)) { + mutex_unlock(&file_priv->descriptors_mutex); + return -EBUSY; + } + /* Remove from table while holding lock to prevent new IO from starting */ file_priv->descriptors[cmd.handle] = NULL; + pad = desc->pad; + sad = desc->sad; + mutex_unlock(&file_priv->descriptors_mutex); - return 0; + retval = decrement_open_device_count(board, &board->device_list, pad, sad); + + kfree(desc); + return retval; } static int serial_poll_ioctl(struct gpib_board *board, unsigned long arg) @@ -1331,12 +1367,25 @@ static int wait_ioctl(struct gpib_file_private *file_priv, struct gpib_board *bo if (retval) return -EFAULT; + /* + * Lock descriptors to prevent concurrent close from freeing + * descriptor. ibwait() releases big_gpib_mutex when wait_mask + * is non-zero, so desc must be pinned with descriptor_busy. + */ + mutex_lock(&file_priv->descriptors_mutex); desc = handle_to_descriptor(file_priv, wait_cmd.handle); - if (!desc) + if (!desc) { + mutex_unlock(&file_priv->descriptors_mutex); return -EINVAL; + } + atomic_inc(&desc->descriptor_busy); + mutex_unlock(&file_priv->descriptors_mutex); retval = ibwait(board, wait_cmd.wait_mask, wait_cmd.clear_mask, wait_cmd.set_mask, &wait_cmd.ibsta, wait_cmd.usec_timeout, desc); + + atomic_dec(&desc->descriptor_busy); + if (retval < 0) return retval; @@ -2035,6 +2084,7 @@ void init_gpib_descriptor(struct gpib_descriptor *desc) desc->is_board = 0; desc->autopoll_enabled = 0; atomic_set(&desc->io_in_progress, 0); + atomic_set(&desc->descriptor_busy, 0); } int gpib_register_driver(struct gpib_interface *interface, struct module *provider_module) diff --git a/drivers/gpib/include/gpib_types.h b/drivers/gpib/include/gpib_types.h index 5a0978ae27e7..28b73157ffb7 100644 --- a/drivers/gpib/include/gpib_types.h +++ b/drivers/gpib/include/gpib_types.h @@ -364,6 +364,14 @@ struct gpib_descriptor { unsigned int pad; /* primary gpib address */ int sad; /* secondary gpib address (negative means disabled) */ atomic_t io_in_progress; + /* + * Kernel-only reference count to prevent descriptor from being + * freed while IO handlers hold a pointer to it. Incremented + * before each IO operation, decremented when done. Unlike + * io_in_progress, this cannot be modified from userspace via + * general_ibstatus(). + */ + atomic_t descriptor_busy; unsigned is_board : 1; unsigned autopoll_enabled : 1; }; diff --git a/drivers/gpib/lpvo_usb_gpib/lpvo_usb_gpib.c b/drivers/gpib/lpvo_usb_gpib/lpvo_usb_gpib.c index ee781d2f0b8e..0f9d385bc50b 100644 --- a/drivers/gpib/lpvo_usb_gpib/lpvo_usb_gpib.c +++ b/drivers/gpib/lpvo_usb_gpib/lpvo_usb_gpib.c @@ -406,7 +406,7 @@ static int usb_gpib_attach(struct gpib_board *board, const struct gpib_board_con for (j = 0 ; j < MAX_DEV ; j++) { if ((assigned_usb_minors & 1 << j) == 0) continue; - udev = usb_get_dev(interface_to_usbdev(lpvo_usb_interfaces[j])); + udev = interface_to_usbdev(lpvo_usb_interfaces[j]); device_path = kobject_get_path(&udev->dev.kobj, GFP_KERNEL); match = gpib_match_device_path(&lpvo_usb_interfaces[j]->dev, config->device_path); @@ -421,7 +421,7 @@ static int usb_gpib_attach(struct gpib_board *board, const struct gpib_board_con for (j = 0 ; j < MAX_DEV ; j++) { if ((assigned_usb_minors & 1 << j) == 0) continue; - udev = usb_get_dev(interface_to_usbdev(lpvo_usb_interfaces[j])); + udev = interface_to_usbdev(lpvo_usb_interfaces[j]); DIA_LOG(1, "dev. %d: bus %d -> %d dev: %d -> %d\n", j, udev->bus->busnum, config->pci_bus, udev->devnum, config->pci_slot); if (config->pci_bus == udev->bus->busnum && diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c index d7666fe9dbf8..647b6f4861b7 100644 --- a/drivers/gpio/gpio-mxc.c +++ b/drivers/gpio/gpio-mxc.c @@ -584,12 +584,13 @@ static bool mxc_gpio_set_pad_wakeup(struct mxc_gpio_port *port, bool enable) unsigned long config; bool ret = false; int i, type; + bool is_imx8qm = of_device_is_compatible(port->dev->of_node, "fsl,imx8qm-gpio"); static const u32 pad_type_map[] = { IMX_SCU_WAKEUP_OFF, /* 0 */ IMX_SCU_WAKEUP_RISE_EDGE, /* IRQ_TYPE_EDGE_RISING */ IMX_SCU_WAKEUP_FALL_EDGE, /* IRQ_TYPE_EDGE_FALLING */ - IMX_SCU_WAKEUP_FALL_EDGE, /* IRQ_TYPE_EDGE_BOTH */ + IMX_SCU_WAKEUP_RISE_EDGE, /* IRQ_TYPE_EDGE_BOTH */ IMX_SCU_WAKEUP_HIGH_LVL, /* IRQ_TYPE_LEVEL_HIGH */ IMX_SCU_WAKEUP_OFF, /* 5 */ IMX_SCU_WAKEUP_OFF, /* 6 */ @@ -604,6 +605,13 @@ static bool mxc_gpio_set_pad_wakeup(struct mxc_gpio_port *port, bool enable) config = pad_type_map[type]; else config = IMX_SCU_WAKEUP_OFF; + + if (is_imx8qm && config == IMX_SCU_WAKEUP_FALL_EDGE) { + dev_warn_once(port->dev, + "No falling-edge support for wakeup on i.MX8QM\n"); + config = IMX_SCU_WAKEUP_OFF; + } + ret |= mxc_gpio_generic_config(port, i, config); } } diff --git a/drivers/gpio/gpio-qixis-fpga.c b/drivers/gpio/gpio-qixis-fpga.c index 6e67f43ac0bd..3ced47db1521 100644 --- a/drivers/gpio/gpio-qixis-fpga.c +++ b/drivers/gpio/gpio-qixis-fpga.c @@ -60,8 +60,8 @@ static int qixis_cpld_gpio_probe(struct platform_device *pdev) return PTR_ERR(reg); regmap = devm_regmap_init_mmio(&pdev->dev, reg, ®map_config_8r_8v); - if (!regmap) - return -ENODEV; + if (IS_ERR(regmap)) + return PTR_ERR(regmap); /* In this case, the offset of our register is 0 inside the * regmap area that we just created. diff --git a/drivers/gpio/gpiolib-shared.c b/drivers/gpio/gpiolib-shared.c index 17a7128b6bd9..e02d6b93a4ab 100644 --- a/drivers/gpio/gpiolib-shared.c +++ b/drivers/gpio/gpiolib-shared.c @@ -443,8 +443,8 @@ static bool gpio_shared_dev_is_reset_gpio(struct device *consumer, } #endif /* CONFIG_RESET_GPIO */ -int gpio_shared_add_proxy_lookup(struct device *consumer, const char *con_id, - unsigned long lflags) +int gpio_shared_add_proxy_lookup(struct device *consumer, struct fwnode_handle *fwnode, + const char *con_id, unsigned long lflags) { const char *dev_id = dev_name(consumer); struct gpiod_lookup_table *lookup; @@ -458,7 +458,7 @@ int gpio_shared_add_proxy_lookup(struct device *consumer, const char *con_id, if (!ref->fwnode && device_is_compatible(consumer, "reset-gpio")) { if (!gpio_shared_dev_is_reset_gpio(consumer, entry, ref)) continue; - } else if (!device_match_fwnode(consumer, ref->fwnode)) { + } else if (fwnode != ref->fwnode) { continue; } @@ -506,8 +506,9 @@ static void gpio_shared_remove_adev(struct auxiliary_device *adev) auxiliary_device_uninit(adev); } -int gpio_device_setup_shared(struct gpio_device *gdev) +int gpiochip_setup_shared(struct gpio_chip *gc) { + struct gpio_device *gdev = gc->gpiodev; struct gpio_shared_entry *entry; struct gpio_shared_ref *ref; struct gpio_desc *desc; @@ -538,20 +539,42 @@ int gpio_device_setup_shared(struct gpio_device *gdev) if (list_count_nodes(&entry->refs) <= 1) continue; - desc = &gdev->descs[entry->offset]; + scoped_guard(mutex, &entry->lock) { +#if IS_ENABLED(CONFIG_OF) + if (is_of_node(entry->fwnode) && gc->of_xlate) { + /* + * This is the earliest that we can tranlate the + * devicetree offset to the chip offset. + */ + struct of_phandle_args gpiospec = { }; - __set_bit(GPIOD_FLAG_SHARED, &desc->flags); - /* - * Shared GPIOs are not requested via the normal path. Make - * them inaccessible to anyone even before we register the - * chip. - */ - ret = gpiod_request_commit(desc, "shared"); - if (ret) - return ret; + gpiospec.np = to_of_node(entry->fwnode); + gpiospec.args_count = 2; + gpiospec.args[0] = entry->offset; + + ret = gc->of_xlate(gc, &gpiospec, NULL); + if (ret < 0) + return ret; + + entry->offset = ret; + } +#endif /* CONFIG_OF */ + + desc = &gdev->descs[entry->offset]; + + __set_bit(GPIOD_FLAG_SHARED, &desc->flags); + /* + * Shared GPIOs are not requested via the normal path. Make + * them inaccessible to anyone even before we register the + * chip. + */ + ret = gpiod_request_commit(desc, "shared"); + if (ret) + return ret; - pr_debug("GPIO %u owned by %s is shared by multiple consumers\n", - entry->offset, gpio_device_get_label(gdev)); + pr_debug("GPIO %u owned by %s is shared by multiple consumers\n", + entry->offset, gpio_device_get_label(gdev)); + } list_for_each_entry(ref, &entry->refs, list) { pr_debug("Setting up a shared GPIO entry for %s (con_id: '%s')\n", @@ -575,6 +598,8 @@ void gpio_device_teardown_shared(struct gpio_device *gdev) struct gpio_shared_ref *ref; list_for_each_entry(entry, &gpio_shared_list, list) { + guard(mutex)(&entry->lock); + if (!device_match_fwnode(&gdev->dev, entry->fwnode)) continue; diff --git a/drivers/gpio/gpiolib-shared.h b/drivers/gpio/gpiolib-shared.h index 40568ef7364c..15e72a8dcdb1 100644 --- a/drivers/gpio/gpiolib-shared.h +++ b/drivers/gpio/gpiolib-shared.h @@ -11,17 +11,19 @@ struct gpio_device; struct gpio_desc; struct device; +struct fwnode_handle; #if IS_ENABLED(CONFIG_GPIO_SHARED) -int gpio_device_setup_shared(struct gpio_device *gdev); +int gpiochip_setup_shared(struct gpio_chip *gc); void gpio_device_teardown_shared(struct gpio_device *gdev); -int gpio_shared_add_proxy_lookup(struct device *consumer, const char *con_id, - unsigned long lflags); +int gpio_shared_add_proxy_lookup(struct device *consumer, + struct fwnode_handle *fwnode, + const char *con_id, unsigned long lflags); #else -static inline int gpio_device_setup_shared(struct gpio_device *gdev) +static inline int gpiochip_setup_shared(struct gpio_chip *gc) { return 0; } @@ -29,6 +31,7 @@ static inline int gpio_device_setup_shared(struct gpio_device *gdev) static inline void gpio_device_teardown_shared(struct gpio_device *gdev) { } static inline int gpio_shared_add_proxy_lookup(struct device *consumer, + struct fwnode_handle *fwnode, const char *con_id, unsigned long lflags) { diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index ada572aaebd6..300de30fd920 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -892,13 +892,15 @@ static const struct device_type gpio_dev_type = { #define gcdev_unregister(gdev) device_del(&(gdev)->dev) #endif +/* + * An initial reference count has been held in gpiochip_add_data_with_key(). + * The caller should drop the reference via gpio_device_put() on errors. + */ static int gpiochip_setup_dev(struct gpio_device *gdev) { struct fwnode_handle *fwnode = dev_fwnode(&gdev->dev); int ret; - device_initialize(&gdev->dev); - /* * If fwnode doesn't belong to another device, it's safe to clear its * initialized flag. @@ -964,9 +966,11 @@ static void gpiochip_setup_devs(void) list_for_each_entry_srcu(gdev, &gpio_devices, list, srcu_read_lock_held(&gpio_devices_srcu)) { ret = gpiochip_setup_dev(gdev); - if (ret) + if (ret) { + gpio_device_put(gdev); dev_err(&gdev->dev, "Failed to initialize gpio device (%d)\n", ret); + } } } @@ -1047,71 +1051,72 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data, int base = 0; int ret; - /* - * First: allocate and populate the internal stat container, and - * set up the struct device. - */ gdev = kzalloc(sizeof(*gdev), GFP_KERNEL); if (!gdev) return -ENOMEM; - - gdev->dev.type = &gpio_dev_type; - gdev->dev.bus = &gpio_bus_type; - gdev->dev.parent = gc->parent; - rcu_assign_pointer(gdev->chip, gc); - gc->gpiodev = gdev; gpiochip_set_data(gc, data); - device_set_node(&gdev->dev, gpiochip_choose_fwnode(gc)); - ret = ida_alloc(&gpio_ida, GFP_KERNEL); if (ret < 0) goto err_free_gdev; gdev->id = ret; - ret = dev_set_name(&gdev->dev, GPIOCHIP_NAME "%d", gdev->id); + ret = init_srcu_struct(&gdev->srcu); if (ret) goto err_free_ida; + rcu_assign_pointer(gdev->chip, gc); - if (gc->parent && gc->parent->driver) - gdev->owner = gc->parent->driver->owner; - else if (gc->owner) - /* TODO: remove chip->owner */ - gdev->owner = gc->owner; - else - gdev->owner = THIS_MODULE; + ret = init_srcu_struct(&gdev->desc_srcu); + if (ret) + goto err_cleanup_gdev_srcu; + + ret = dev_set_name(&gdev->dev, GPIOCHIP_NAME "%d", gdev->id); + if (ret) + goto err_cleanup_desc_srcu; + + device_initialize(&gdev->dev); + /* + * After this point any allocated resources to `gdev` will be + * free():ed by gpiodev_release(). If you add new resources + * then make sure they get free():ed there. + */ + gdev->dev.type = &gpio_dev_type; + gdev->dev.bus = &gpio_bus_type; + gdev->dev.parent = gc->parent; + device_set_node(&gdev->dev, gpiochip_choose_fwnode(gc)); ret = gpiochip_get_ngpios(gc, &gdev->dev); if (ret) - goto err_free_dev_name; + goto err_put_device; + gdev->ngpio = gc->ngpio; gdev->descs = kcalloc(gc->ngpio, sizeof(*gdev->descs), GFP_KERNEL); if (!gdev->descs) { ret = -ENOMEM; - goto err_free_dev_name; + goto err_put_device; } gdev->label = kstrdup_const(gc->label ?: "unknown", GFP_KERNEL); if (!gdev->label) { ret = -ENOMEM; - goto err_free_descs; + goto err_put_device; } - gdev->ngpio = gc->ngpio; gdev->can_sleep = gc->can_sleep; - rwlock_init(&gdev->line_state_lock); RAW_INIT_NOTIFIER_HEAD(&gdev->line_state_notifier); BLOCKING_INIT_NOTIFIER_HEAD(&gdev->device_notifier); - - ret = init_srcu_struct(&gdev->srcu); - if (ret) - goto err_free_label; - - ret = init_srcu_struct(&gdev->desc_srcu); - if (ret) - goto err_cleanup_gdev_srcu; +#ifdef CONFIG_PINCTRL + INIT_LIST_HEAD(&gdev->pin_ranges); +#endif + if (gc->parent && gc->parent->driver) + gdev->owner = gc->parent->driver->owner; + else if (gc->owner) + /* TODO: remove chip->owner */ + gdev->owner = gc->owner; + else + gdev->owner = THIS_MODULE; scoped_guard(mutex, &gpio_devices_lock) { /* @@ -1127,7 +1132,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data, if (base < 0) { ret = base; base = 0; - goto err_cleanup_desc_srcu; + goto err_put_device; } /* @@ -1147,14 +1152,10 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data, ret = gpiodev_add_to_list_unlocked(gdev); if (ret) { gpiochip_err(gc, "GPIO integer space overlap, cannot add chip\n"); - goto err_cleanup_desc_srcu; + goto err_put_device; } } -#ifdef CONFIG_PINCTRL - INIT_LIST_HEAD(&gdev->pin_ranges); -#endif - if (gc->names) gpiochip_set_desc_names(gc); @@ -1210,7 +1211,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data, if (ret) goto err_remove_irqchip_mask; - ret = gpio_device_setup_shared(gdev); + ret = gpiochip_setup_shared(gc); if (ret) goto err_remove_irqchip; @@ -1248,25 +1249,19 @@ err_remove_from_list: scoped_guard(mutex, &gpio_devices_lock) list_del_rcu(&gdev->list); synchronize_srcu(&gpio_devices_srcu); - if (gdev->dev.release) { - /* release() has been registered by gpiochip_setup_dev() */ - gpio_device_put(gdev); - goto err_print_message; - } +err_put_device: + gpio_device_put(gdev); + goto err_print_message; + err_cleanup_desc_srcu: cleanup_srcu_struct(&gdev->desc_srcu); err_cleanup_gdev_srcu: cleanup_srcu_struct(&gdev->srcu); -err_free_label: - kfree_const(gdev->label); -err_free_descs: - kfree(gdev->descs); -err_free_dev_name: - kfree(dev_name(&gdev->dev)); err_free_ida: ida_free(&gpio_ida, gdev->id); err_free_gdev: kfree(gdev); + err_print_message: /* failures here can mean systems won't boot... */ if (ret != -EPROBE_DEFER) { @@ -2465,8 +2460,10 @@ int gpiod_request_commit(struct gpio_desc *desc, const char *label) return -EBUSY; offset = gpiod_hwgpio(desc); - if (!gpiochip_line_is_valid(guard.gc, offset)) - return -EINVAL; + if (!gpiochip_line_is_valid(guard.gc, offset)) { + ret = -EINVAL; + goto out_clear_bit; + } /* NOTE: gpio_request() can be called in early boot, * before IRQs are enabled, for non-sleeping (SOC) GPIOs. @@ -4717,8 +4714,8 @@ struct gpio_desc *gpiod_find_and_request(struct device *consumer, * lookup table for the proxy device as previously * we only knew the consumer's fwnode. */ - ret = gpio_shared_add_proxy_lookup(consumer, con_id, - lookupflags); + ret = gpio_shared_add_proxy_lookup(consumer, fwnode, + con_id, lookupflags); if (ret) return ERR_PTR(ret); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c index 40c22438b1d2..4f27c75abedb 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c @@ -692,9 +692,9 @@ int amdgpu_amdkfd_submit_ib(struct amdgpu_device *adev, goto err_ib_sched; } - /* Drop the initial kref_init count (see drm_sched_main as example) */ - dma_fence_put(f); ret = dma_fence_wait(f, false); + /* Drop the returned fence reference after the wait completes */ + dma_fence_put(f); err_ib_sched: amdgpu_job_free(job); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index d8296dfc5e8a..6d8531f9b882 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -4207,7 +4207,8 @@ fail: static int amdgpu_device_get_job_timeout_settings(struct amdgpu_device *adev) { - char *input = amdgpu_lockup_timeout; + char buf[AMDGPU_MAX_TIMEOUT_PARAM_LENGTH]; + char *input = buf; char *timeout_setting = NULL; int index = 0; long timeout; @@ -4217,9 +4218,17 @@ static int amdgpu_device_get_job_timeout_settings(struct amdgpu_device *adev) adev->gfx_timeout = adev->compute_timeout = adev->sdma_timeout = adev->video_timeout = msecs_to_jiffies(2000); - if (!strnlen(input, AMDGPU_MAX_TIMEOUT_PARAM_LENGTH)) + if (!strnlen(amdgpu_lockup_timeout, AMDGPU_MAX_TIMEOUT_PARAM_LENGTH)) return 0; + /* + * strsep() destructively modifies its input by replacing delimiters + * with '\0'. Use a stack copy so the global module parameter buffer + * remains intact for multi-GPU systems where this function is called + * once per device. + */ + strscpy(buf, amdgpu_lockup_timeout, sizeof(buf)); + while ((timeout_setting = strsep(&input, ",")) && strnlen(timeout_setting, AMDGPU_MAX_TIMEOUT_PARAM_LENGTH)) { ret = kstrtol(timeout_setting, 0, &timeout); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c index 95d26f086d54..c91638e65174 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c @@ -2703,8 +2703,12 @@ static int amdgpu_pmops_freeze(struct device *dev) if (r) return r; - if (amdgpu_acpi_should_gpu_reset(adev)) - return amdgpu_asic_reset(adev); + if (amdgpu_acpi_should_gpu_reset(adev)) { + amdgpu_device_lock_reset_domain(adev->reset_domain); + r = amdgpu_asic_reset(adev); + amdgpu_device_unlock_reset_domain(adev->reset_domain); + return r; + } return 0; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c index e2d32c29668a..bc772ca3dab7 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c @@ -404,6 +404,50 @@ void amdgpu_gart_map_vram_range(struct amdgpu_device *adev, uint64_t pa, } /** + * amdgpu_gart_map_gfx9_mqd - map mqd and ctrl_stack dma_addresses into GART entries + * + * @adev: amdgpu_device pointer + * @offset: offset into the GPU's gart aperture + * @pages: number of pages to bind + * @dma_addr: DMA addresses of pages + * @flags: page table entry flags + * + * Map the MQD and control stack addresses into GART entries with the correct + * memory types on gfxv9. The MQD occupies the first 4KB and is followed by + * the control stack. The MQD uses UC (uncached) memory, while the control stack + * uses NC (non-coherent) memory. + */ +void amdgpu_gart_map_gfx9_mqd(struct amdgpu_device *adev, uint64_t offset, + int pages, dma_addr_t *dma_addr, uint64_t flags) +{ + uint64_t page_base; + unsigned int i, j, t; + int idx; + uint64_t ctrl_flags = AMDGPU_PTE_MTYPE_VG10(flags, AMDGPU_MTYPE_NC); + void *dst; + + if (!adev->gart.ptr) + return; + + if (!drm_dev_enter(adev_to_drm(adev), &idx)) + return; + + t = offset / AMDGPU_GPU_PAGE_SIZE; + dst = adev->gart.ptr; + for (i = 0; i < pages; i++) { + page_base = dma_addr[i]; + for (j = 0; j < AMDGPU_GPU_PAGES_IN_CPU_PAGE; j++, t++) { + if ((i == 0) && (j == 0)) + amdgpu_gmc_set_pte_pde(adev, dst, t, page_base, flags); + else + amdgpu_gmc_set_pte_pde(adev, dst, t, page_base, ctrl_flags); + page_base += AMDGPU_GPU_PAGE_SIZE; + } + } + drm_dev_exit(idx); +} + +/** * amdgpu_gart_bind - bind pages into the gart page table * * @adev: amdgpu_device pointer diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.h index d3118275ddae..6ebd2da32ea6 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.h @@ -62,6 +62,8 @@ void amdgpu_gart_unbind(struct amdgpu_device *adev, uint64_t offset, void amdgpu_gart_map(struct amdgpu_device *adev, uint64_t offset, int pages, dma_addr_t *dma_addr, uint64_t flags, void *dst); +void amdgpu_gart_map_gfx9_mqd(struct amdgpu_device *adev, uint64_t offset, + int pages, dma_addr_t *dma_addr, uint64_t flags); void amdgpu_gart_bind(struct amdgpu_device *adev, uint64_t offset, int pages, dma_addr_t *dma_addr, uint64_t flags); void amdgpu_gart_map_vram_range(struct amdgpu_device *adev, uint64_t pa, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c index 64c519cd7395..569c5a89ff10 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c @@ -35,10 +35,13 @@ * PASIDs are global address space identifiers that can be shared * between the GPU, an IOMMU and the driver. VMs on different devices * may use the same PASID if they share the same address - * space. Therefore PASIDs are allocated using a global IDA. VMs are - * looked up from the PASID per amdgpu_device. + * space. Therefore PASIDs are allocated using IDR cyclic allocator + * (similar to kernel PID allocation) which naturally delays reuse. + * VMs are looked up from the PASID per amdgpu_device. */ -static DEFINE_IDA(amdgpu_pasid_ida); + +static DEFINE_IDR(amdgpu_pasid_idr); +static DEFINE_SPINLOCK(amdgpu_pasid_idr_lock); /* Helper to free pasid from a fence callback */ struct amdgpu_pasid_cb { @@ -50,8 +53,8 @@ struct amdgpu_pasid_cb { * amdgpu_pasid_alloc - Allocate a PASID * @bits: Maximum width of the PASID in bits, must be at least 1 * - * Allocates a PASID of the given width while keeping smaller PASIDs - * available if possible. + * Uses kernel's IDR cyclic allocator (same as PID allocation). + * Allocates sequentially with automatic wrap-around. * * Returns a positive integer on success. Returns %-EINVAL if bits==0. * Returns %-ENOSPC if no PASID was available. Returns %-ENOMEM on @@ -59,14 +62,18 @@ struct amdgpu_pasid_cb { */ int amdgpu_pasid_alloc(unsigned int bits) { - int pasid = -EINVAL; + int pasid; - for (bits = min(bits, 31U); bits > 0; bits--) { - pasid = ida_alloc_range(&amdgpu_pasid_ida, 1U << (bits - 1), - (1U << bits) - 1, GFP_KERNEL); - if (pasid != -ENOSPC) - break; - } + if (bits == 0) + return -EINVAL; + + spin_lock(&amdgpu_pasid_idr_lock); + /* TODO: Need to replace the idr with an xarry, and then + * handle the internal locking with ATOMIC safe paths. + */ + pasid = idr_alloc_cyclic(&amdgpu_pasid_idr, NULL, 1, + 1U << bits, GFP_ATOMIC); + spin_unlock(&amdgpu_pasid_idr_lock); if (pasid >= 0) trace_amdgpu_pasid_allocated(pasid); @@ -81,7 +88,10 @@ int amdgpu_pasid_alloc(unsigned int bits) void amdgpu_pasid_free(u32 pasid) { trace_amdgpu_pasid_freed(pasid); - ida_free(&amdgpu_pasid_ida, pasid); + + spin_lock(&amdgpu_pasid_idr_lock); + idr_remove(&amdgpu_pasid_idr, pasid); + spin_unlock(&amdgpu_pasid_idr_lock); } static void amdgpu_pasid_free_cb(struct dma_fence *fence, @@ -616,3 +626,15 @@ void amdgpu_vmid_mgr_fini(struct amdgpu_device *adev) } } } + +/** + * amdgpu_pasid_mgr_cleanup - cleanup PASID manager + * + * Cleanup the IDR allocator. + */ +void amdgpu_pasid_mgr_cleanup(void) +{ + spin_lock(&amdgpu_pasid_idr_lock); + idr_destroy(&amdgpu_pasid_idr); + spin_unlock(&amdgpu_pasid_idr_lock); +} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.h index b3649cd3af56..a57919478d3b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.h @@ -74,6 +74,7 @@ int amdgpu_pasid_alloc(unsigned int bits); void amdgpu_pasid_free(u32 pasid); void amdgpu_pasid_free_delayed(struct dma_resv *resv, u32 pasid); +void amdgpu_pasid_mgr_cleanup(void); bool amdgpu_vmid_had_gpu_reset(struct amdgpu_device *adev, struct amdgpu_vmid *id); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index eeaa56c8d129..0ccb31788b20 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -853,25 +853,15 @@ static void amdgpu_ttm_gart_bind_gfx9_mqd(struct amdgpu_device *adev, int num_xcc = max(1U, adev->gfx.num_xcc_per_xcp); uint64_t page_idx, pages_per_xcc; int i; - uint64_t ctrl_flags = AMDGPU_PTE_MTYPE_VG10(flags, AMDGPU_MTYPE_NC); pages_per_xcc = total_pages; do_div(pages_per_xcc, num_xcc); for (i = 0, page_idx = 0; i < num_xcc; i++, page_idx += pages_per_xcc) { - /* MQD page: use default flags */ - amdgpu_gart_bind(adev, + amdgpu_gart_map_gfx9_mqd(adev, gtt->offset + (page_idx << PAGE_SHIFT), - 1, >t->ttm.dma_address[page_idx], flags); - /* - * Ctrl pages - modify the memory type to NC (ctrl_flags) from - * the second page of the BO onward. - */ - amdgpu_gart_bind(adev, - gtt->offset + ((page_idx + 1) << PAGE_SHIFT), - pages_per_xcc - 1, - >t->ttm.dma_address[page_idx + 1], - ctrl_flags); + pages_per_xcc, >t->ttm.dma_address[page_idx], + flags); } } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c index 7c450350847d..0a1b93259887 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c @@ -600,6 +600,13 @@ amdgpu_userq_get_doorbell_index(struct amdgpu_userq_mgr *uq_mgr, goto unpin_bo; } + /* Validate doorbell_offset is within the doorbell BO */ + if ((u64)db_info->doorbell_offset * db_size + db_size > + amdgpu_bo_size(db_obj->obj)) { + r = -EINVAL; + goto unpin_bo; + } + index = amdgpu_doorbell_index_on_bar(uq_mgr->adev, db_obj->obj, db_info->doorbell_offset, db_size); drm_dbg_driver(adev_to_drm(uq_mgr->adev), diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index c60cbce356cf..a677e38a493b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -2898,6 +2898,7 @@ void amdgpu_vm_manager_fini(struct amdgpu_device *adev) xa_destroy(&adev->vm_manager.pasids); amdgpu_vmid_mgr_fini(adev); + amdgpu_pasid_mgr_cleanup(); } /** @@ -2973,14 +2974,14 @@ bool amdgpu_vm_handle_fault(struct amdgpu_device *adev, u32 pasid, if (!root) return false; - addr /= AMDGPU_GPU_PAGE_SIZE; - if (is_compute_context && !svm_range_restore_pages(adev, pasid, vmid, - node_id, addr, ts, write_fault)) { + node_id, addr >> PAGE_SHIFT, ts, write_fault)) { amdgpu_bo_unref(&root); return true; } + addr /= AMDGPU_GPU_PAGE_SIZE; + r = amdgpu_bo_reserve(root, true); if (r) goto error_unref; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h index bb276c0ad06d..d5b7061556ba 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.h @@ -173,7 +173,7 @@ struct amdgpu_bo_vm; #define AMDGPU_VA_RESERVED_SEQ64_SIZE (2ULL << 20) #define AMDGPU_VA_RESERVED_SEQ64_START(adev) (AMDGPU_VA_RESERVED_CSA_START(adev) \ - AMDGPU_VA_RESERVED_SEQ64_SIZE) -#define AMDGPU_VA_RESERVED_TRAP_SIZE (2ULL << 12) +#define AMDGPU_VA_RESERVED_TRAP_SIZE (1ULL << 16) #define AMDGPU_VA_RESERVED_TRAP_START(adev) (AMDGPU_VA_RESERVED_SEQ64_START(adev) \ - AMDGPU_VA_RESERVED_TRAP_SIZE) #define AMDGPU_VA_RESERVED_BOTTOM (1ULL << 16) diff --git a/drivers/gpu/drm/amd/amdgpu/mes_userqueue.c b/drivers/gpu/drm/amd/amdgpu/mes_userqueue.c index 8c74894254f7..faac21ee5739 100644 --- a/drivers/gpu/drm/amd/amdgpu/mes_userqueue.c +++ b/drivers/gpu/drm/amd/amdgpu/mes_userqueue.c @@ -324,8 +324,10 @@ static int mes_userq_mqd_create(struct amdgpu_usermode_queue *queue, r = amdgpu_userq_input_va_validate(adev, queue, compute_mqd->eop_va, 2048); - if (r) + if (r) { + kfree(compute_mqd); goto free_mqd; + } userq_props->eop_gpu_addr = compute_mqd->eop_va; userq_props->hqd_pipe_priority = AMDGPU_GFX_PIPE_PRIO_NORMAL; @@ -365,12 +367,16 @@ static int mes_userq_mqd_create(struct amdgpu_usermode_queue *queue, r = amdgpu_userq_input_va_validate(adev, queue, mqd_gfx_v11->shadow_va, shadow_info.shadow_size); - if (r) + if (r) { + kfree(mqd_gfx_v11); goto free_mqd; + } r = amdgpu_userq_input_va_validate(adev, queue, mqd_gfx_v11->csa_va, shadow_info.csa_size); - if (r) + if (r) { + kfree(mqd_gfx_v11); goto free_mqd; + } kfree(mqd_gfx_v11); } else if (queue->queue_type == AMDGPU_HW_IP_DMA) { @@ -390,8 +396,10 @@ static int mes_userq_mqd_create(struct amdgpu_usermode_queue *queue, } r = amdgpu_userq_input_va_validate(adev, queue, mqd_sdma_v11->csa_va, 32); - if (r) + if (r) { + kfree(mqd_sdma_v11); goto free_mqd; + } userq_props->csa_addr = mqd_sdma_v11->csa_va; kfree(mqd_sdma_v11); diff --git a/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c b/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c index 9aa988982304..fb7aaf5ae05c 100644 --- a/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/psp_v11_0.c @@ -170,7 +170,8 @@ static int psp_v11_0_wait_for_bootloader(struct psp_context *psp) int retry_loop; /* For a reset done at the end of S3, only wait for TOS to be unloaded */ - if (adev->in_s3 && !(adev->flags & AMD_IS_APU) && amdgpu_in_reset(adev)) + if ((adev->in_s4 || adev->in_s3) && !(adev->flags & AMD_IS_APU) && + amdgpu_in_reset(adev)) return psp_v11_wait_for_tos_unload(psp); for (retry_loop = 0; retry_loop < 20; retry_loop++) { diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c index 09dabb3b3297..462a32abf720 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c @@ -3170,11 +3170,11 @@ static int kfd_ioctl_create_process(struct file *filep, struct kfd_process *p, v struct kfd_process *process; int ret; - /* Each FD owns only one kfd_process */ - if (p->context_id != KFD_CONTEXT_ID_PRIMARY) + if (!filep->private_data || !p) return -EINVAL; - if (!filep->private_data || !p) + /* Each FD owns only one kfd_process */ + if (p->context_id != KFD_CONTEXT_ID_PRIMARY) return -EINVAL; mutex_lock(&kfd_processes_mutex); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c index d5c234f30e8d..a535f151cb5f 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c @@ -42,9 +42,16 @@ static uint64_t mqd_stride_v9(struct mqd_manager *mm, struct queue_properties *q) { if (mm->dev->kfd->cwsr_enabled && - q->type == KFD_QUEUE_TYPE_COMPUTE) - return ALIGN(q->ctl_stack_size, PAGE_SIZE) + - ALIGN(sizeof(struct v9_mqd), PAGE_SIZE); + q->type == KFD_QUEUE_TYPE_COMPUTE) { + + /* On gfxv9, the MQD resides in the first 4K page, + * followed by the control stack. Align both to + * AMDGPU_GPU_PAGE_SIZE to maintain the required 4K boundary. + */ + + return ALIGN(ALIGN(q->ctl_stack_size, AMDGPU_GPU_PAGE_SIZE) + + ALIGN(sizeof(struct v9_mqd), AMDGPU_GPU_PAGE_SIZE), PAGE_SIZE); + } return mm->mqd_size; } @@ -151,8 +158,8 @@ static struct kfd_mem_obj *allocate_mqd(struct mqd_manager *mm, if (!mqd_mem_obj) return NULL; retval = amdgpu_amdkfd_alloc_kernel_mem(node->adev, - (ALIGN(q->ctl_stack_size, PAGE_SIZE) + - ALIGN(sizeof(struct v9_mqd), PAGE_SIZE)) * + (ALIGN(ALIGN(q->ctl_stack_size, AMDGPU_GPU_PAGE_SIZE) + + ALIGN(sizeof(struct v9_mqd), AMDGPU_GPU_PAGE_SIZE), PAGE_SIZE)) * NUM_XCC(node->xcc_mask), mqd_on_vram(node->adev) ? AMDGPU_GEM_DOMAIN_VRAM : AMDGPU_GEM_DOMAIN_GTT, @@ -360,7 +367,7 @@ static int get_wave_state(struct mqd_manager *mm, void *mqd, struct kfd_context_save_area_header header; /* Control stack is located one page after MQD. */ - void *mqd_ctl_stack = (void *)((uintptr_t)mqd + PAGE_SIZE); + void *mqd_ctl_stack = (void *)((uintptr_t)mqd + AMDGPU_GPU_PAGE_SIZE); m = get_mqd(mqd); @@ -397,7 +404,7 @@ static void checkpoint_mqd(struct mqd_manager *mm, void *mqd, void *mqd_dst, voi { struct v9_mqd *m; /* Control stack is located one page after MQD. */ - void *ctl_stack = (void *)((uintptr_t)mqd + PAGE_SIZE); + void *ctl_stack = (void *)((uintptr_t)mqd + AMDGPU_GPU_PAGE_SIZE); m = get_mqd(mqd); @@ -443,7 +450,7 @@ static void restore_mqd(struct mqd_manager *mm, void **mqd, *gart_addr = addr; /* Control stack is located one page after MQD. */ - ctl_stack = (void *)((uintptr_t)*mqd + PAGE_SIZE); + ctl_stack = (void *)((uintptr_t)*mqd + AMDGPU_GPU_PAGE_SIZE); memcpy(ctl_stack, ctl_stack_src, ctl_stack_size); m->cp_hqd_pq_doorbell_control = diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h index e5b56412931b..035687a17d89 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h @@ -102,8 +102,8 @@ * The first chunk is the TBA used for the CWSR ISA code. The second * chunk is used as TMA for user-mode trap handler setup in daisy-chain mode. */ -#define KFD_CWSR_TBA_TMA_SIZE (PAGE_SIZE * 2) -#define KFD_CWSR_TMA_OFFSET (PAGE_SIZE + 2048) +#define KFD_CWSR_TBA_TMA_SIZE (AMDGPU_GPU_PAGE_SIZE * 2) +#define KFD_CWSR_TMA_OFFSET (AMDGPU_GPU_PAGE_SIZE + 2048) #define KFD_MAX_NUM_OF_QUEUES_PER_DEVICE \ (KFD_MAX_NUM_OF_PROCESSES * \ diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_queue.c b/drivers/gpu/drm/amd/amdkfd/kfd_queue.c index bbe869ceae3f..28354a4e5dd5 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_queue.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_queue.c @@ -249,10 +249,10 @@ int kfd_queue_acquire_buffers(struct kfd_process_device *pdd, struct queue_prope topo_dev->node_props.gfx_target_version < 90000) /* metadata_queue_size not supported on GFX7/GFX8 */ expected_queue_size = - properties->queue_size / 2; + PAGE_ALIGN(properties->queue_size / 2); else expected_queue_size = - properties->queue_size + properties->metadata_queue_size; + PAGE_ALIGN(properties->queue_size + properties->metadata_queue_size); vm = drm_priv_to_vm(pdd->drm_priv); err = amdgpu_bo_reserve(vm->root.bo, false); @@ -492,10 +492,11 @@ void kfd_queue_ctx_save_restore_size(struct kfd_topology_device *dev) cu_num = props->simd_count / props->simd_per_cu / NUM_XCC(dev->gpu->xcc_mask); wave_num = get_num_waves(props, gfxv, cu_num); - wg_data_size = ALIGN(cu_num * WG_CONTEXT_DATA_SIZE_PER_CU(gfxv, props), PAGE_SIZE); + wg_data_size = ALIGN(cu_num * WG_CONTEXT_DATA_SIZE_PER_CU(gfxv, props), + AMDGPU_GPU_PAGE_SIZE); ctl_stack_size = wave_num * CNTL_STACK_BYTES_PER_WAVE(gfxv) + 8; ctl_stack_size = ALIGN(SIZEOF_HSA_USER_CONTEXT_SAVE_AREA_HEADER + ctl_stack_size, - PAGE_SIZE); + AMDGPU_GPU_PAGE_SIZE); if ((gfxv / 10000 * 10000) == 100000) { /* HW design limits control stack size to 0x7000. @@ -507,7 +508,7 @@ void kfd_queue_ctx_save_restore_size(struct kfd_topology_device *dev) props->ctl_stack_size = ctl_stack_size; props->debug_memory_size = ALIGN(wave_num * DEBUGGER_BYTES_PER_WAVE, DEBUGGER_BYTES_ALIGN); - props->cwsr_size = ctl_stack_size + wg_data_size; + props->cwsr_size = ALIGN(ctl_stack_size + wg_data_size, PAGE_SIZE); if (gfxv == 80002) /* GFX_VERSION_TONGA */ props->eop_buffer_size = 0x8000; 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 085cc98bd875..2328c1aa0ead 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -3909,8 +3909,9 @@ void amdgpu_dm_update_connector_after_detect( aconnector->dc_sink = sink; dc_sink_retain(aconnector->dc_sink); + drm_edid_free(aconnector->drm_edid); + aconnector->drm_edid = NULL; if (sink->dc_edid.length == 0) { - aconnector->drm_edid = NULL; hdmi_cec_unset_edid(aconnector); if (aconnector->dc_link->aux_mode) { drm_dp_cec_unset_edid(&aconnector->dm_dp_aux.aux); @@ -5422,7 +5423,7 @@ static void setup_backlight_device(struct amdgpu_display_manager *dm, caps = &dm->backlight_caps[aconnector->bl_idx]; /* Only offer ABM property when non-OLED and user didn't turn off by module parameter */ - if (!caps->ext_caps->bits.oled && amdgpu_dm_abm_level < 0) + if (caps->ext_caps && !caps->ext_caps->bits.oled && amdgpu_dm_abm_level < 0) drm_object_attach_property(&aconnector->base.base, dm->adev->mode_info.abm_level_property, ABM_SYSFS_CONTROL); @@ -12524,6 +12525,11 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, if (dc_resource_is_dsc_encoding_supported(dc)) { for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { + dm_new_crtc_state = to_dm_crtc_state(new_crtc_state); + dm_new_crtc_state->mode_changed_independent_from_dsc = new_crtc_state->mode_changed; + } + + for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { if (drm_atomic_crtc_needs_modeset(new_crtc_state)) { ret = add_affected_mst_dsc_crtcs(state, crtc); if (ret) { diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h index 800813671748..d15812d51d72 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h @@ -984,6 +984,7 @@ struct dm_crtc_state { bool freesync_vrr_info_changed; + bool mode_changed_independent_from_dsc; bool dsc_force_changed; bool vrr_supported; struct mod_freesync_config freesync_config; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c index 7be50e8c0636..5d8c4c7020b1 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c @@ -1744,9 +1744,11 @@ int pre_validate_dsc(struct drm_atomic_state *state, int ind = find_crtc_index_in_state_by_stream(state, stream); if (ind >= 0) { + struct dm_crtc_state *dm_new_crtc_state = to_dm_crtc_state(state->crtcs[ind].new_state); + DRM_INFO_ONCE("%s:%d MST_DSC no mode changed for stream 0x%p\n", __func__, __LINE__, stream); - state->crtcs[ind].new_state->mode_changed = 0; + dm_new_crtc_state->base.mode_changed = dm_new_crtc_state->mode_changed_independent_from_dsc; } } } diff --git a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c index eb198d52a115..4dfb6c865831 100644 --- a/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c @@ -147,6 +147,7 @@ void dcn401_init_hw(struct dc *dc) int edp_num; uint32_t backlight = MAX_BACKLIGHT_LEVEL; uint32_t user_level = MAX_BACKLIGHT_LEVEL; + bool dchub_ref_freq_changed; int current_dchub_ref_freq = 0; if (dc->clk_mgr && dc->clk_mgr->funcs && dc->clk_mgr->funcs->init_clocks) { @@ -360,14 +361,18 @@ void dcn401_init_hw(struct dc *dc) dc->caps.dmub_caps.psr = dc->ctx->dmub_srv->dmub->feature_caps.psr; dc->caps.dmub_caps.mclk_sw = dc->ctx->dmub_srv->dmub->feature_caps.fw_assisted_mclk_switch_ver > 0; dc->caps.dmub_caps.fams_ver = dc->ctx->dmub_srv->dmub->feature_caps.fw_assisted_mclk_switch_ver; + + /* sw and fw FAMS versions must match for support */ dc->debug.fams2_config.bits.enable &= - dc->caps.dmub_caps.fams_ver == dc->debug.fams_version.ver; // sw & fw fams versions must match for support - if ((!dc->debug.fams2_config.bits.enable && dc->res_pool->funcs->update_bw_bounding_box) - || res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000 != current_dchub_ref_freq) { + dc->caps.dmub_caps.fams_ver == dc->debug.fams_version.ver; + dchub_ref_freq_changed = + res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000 != current_dchub_ref_freq; + if ((!dc->debug.fams2_config.bits.enable || dchub_ref_freq_changed) && + dc->res_pool->funcs->update_bw_bounding_box && + dc->clk_mgr && dc->clk_mgr->bw_params) { /* update bounding box if FAMS2 disabled, or if dchub clk has changed */ - if (dc->clk_mgr) - dc->res_pool->funcs->update_bw_bounding_box(dc, - dc->clk_mgr->bw_params); + dc->res_pool->funcs->update_bw_bounding_box(dc, + dc->clk_mgr->bw_params); } } } diff --git a/drivers/gpu/drm/amd/display/dc/resource/dce100/dce100_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dce100/dce100_resource.c index 92c123aca0c9..fdcf8db6be50 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dce100/dce100_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dce100/dce100_resource.c @@ -650,9 +650,6 @@ static struct link_encoder *dce100_link_encoder_create( return &enc110->base; } - if (enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs)) - return NULL; - link_regs_id = map_transmitter_id_to_phy_instance(enc_init_data->transmitter); @@ -661,7 +658,8 @@ static struct link_encoder *dce100_link_encoder_create( &link_enc_feature, &link_enc_regs[link_regs_id], &link_enc_aux_regs[enc_init_data->channel - 1], - &link_enc_hpd_regs[enc_init_data->hpd_source]); + enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs) ? + NULL : &link_enc_hpd_regs[enc_init_data->hpd_source]); return &enc110->base; } diff --git a/drivers/gpu/drm/amd/display/dc/resource/dce110/dce110_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dce110/dce110_resource.c index 95852d277c22..ab71f645c90e 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dce110/dce110_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dce110/dce110_resource.c @@ -671,7 +671,7 @@ static struct link_encoder *dce110_link_encoder_create( kzalloc_obj(struct dce110_link_encoder); int link_regs_id; - if (!enc110 || enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs)) + if (!enc110) return NULL; link_regs_id = @@ -682,7 +682,8 @@ static struct link_encoder *dce110_link_encoder_create( &link_enc_feature, &link_enc_regs[link_regs_id], &link_enc_aux_regs[enc_init_data->channel - 1], - &link_enc_hpd_regs[enc_init_data->hpd_source]); + enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs) ? + NULL : &link_enc_hpd_regs[enc_init_data->hpd_source]); return &enc110->base; } diff --git a/drivers/gpu/drm/amd/display/dc/resource/dce112/dce112_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dce112/dce112_resource.c index 58c6a00397cf..b7051bfd4326 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dce112/dce112_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dce112/dce112_resource.c @@ -632,7 +632,7 @@ static struct link_encoder *dce112_link_encoder_create( kzalloc_obj(struct dce110_link_encoder); int link_regs_id; - if (!enc110 || enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs)) + if (!enc110) return NULL; link_regs_id = @@ -643,7 +643,8 @@ static struct link_encoder *dce112_link_encoder_create( &link_enc_feature, &link_enc_regs[link_regs_id], &link_enc_aux_regs[enc_init_data->channel - 1], - &link_enc_hpd_regs[enc_init_data->hpd_source]); + enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs) ? + NULL : &link_enc_hpd_regs[enc_init_data->hpd_source]); return &enc110->base; } diff --git a/drivers/gpu/drm/amd/display/dc/resource/dce120/dce120_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dce120/dce120_resource.c index 71d76b021375..7ee70f7b3aa7 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dce120/dce120_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dce120/dce120_resource.c @@ -716,7 +716,7 @@ static struct link_encoder *dce120_link_encoder_create( kzalloc_obj(struct dce110_link_encoder); int link_regs_id; - if (!enc110 || enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs)) + if (!enc110) return NULL; link_regs_id = @@ -727,7 +727,8 @@ static struct link_encoder *dce120_link_encoder_create( &link_enc_feature, &link_enc_regs[link_regs_id], &link_enc_aux_regs[enc_init_data->channel - 1], - &link_enc_hpd_regs[enc_init_data->hpd_source]); + enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs) ? + NULL : &link_enc_hpd_regs[enc_init_data->hpd_source]); return &enc110->base; } diff --git a/drivers/gpu/drm/amd/display/dc/resource/dce60/dce60_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dce60/dce60_resource.c index c27645708286..3d52973dd7f2 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dce60/dce60_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dce60/dce60_resource.c @@ -746,18 +746,16 @@ static struct link_encoder *dce60_link_encoder_create( return &enc110->base; } - if (enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs)) - return NULL; - link_regs_id = map_transmitter_id_to_phy_instance(enc_init_data->transmitter); dce60_link_encoder_construct(enc110, - enc_init_data, - &link_enc_feature, - &link_enc_regs[link_regs_id], - &link_enc_aux_regs[enc_init_data->channel - 1], - &link_enc_hpd_regs[enc_init_data->hpd_source]); + enc_init_data, + &link_enc_feature, + &link_enc_regs[link_regs_id], + &link_enc_aux_regs[enc_init_data->channel - 1], + enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs) ? + NULL : &link_enc_hpd_regs[enc_init_data->hpd_source]); return &enc110->base; } diff --git a/drivers/gpu/drm/amd/display/dc/resource/dce80/dce80_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dce80/dce80_resource.c index d66d8ac6d897..89927727a0d9 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dce80/dce80_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dce80/dce80_resource.c @@ -752,9 +752,6 @@ static struct link_encoder *dce80_link_encoder_create( return &enc110->base; } - if (enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs)) - return NULL; - link_regs_id = map_transmitter_id_to_phy_instance(enc_init_data->transmitter); @@ -763,7 +760,8 @@ static struct link_encoder *dce80_link_encoder_create( &link_enc_feature, &link_enc_regs[link_regs_id], &link_enc_aux_regs[enc_init_data->channel - 1], - &link_enc_hpd_regs[enc_init_data->hpd_source]); + enc_init_data->hpd_source >= ARRAY_SIZE(link_enc_hpd_regs) ? + NULL : &link_enc_hpd_regs[enc_init_data->hpd_source]); return &enc110->base; } diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn10/dcn10_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn10/dcn10_resource.c index bbe185e15eb6..4663456a736a 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn10/dcn10_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn10/dcn10_resource.c @@ -71,6 +71,7 @@ #include "dce/dce_dmcu.h" #include "dce/dce_aux.h" #include "dce/dce_i2c.h" +#include "dio/dcn10/dcn10_dio.h" #ifndef mmDP0_DP_DPHY_INTERNAL_CTRL #define mmDP0_DP_DPHY_INTERNAL_CTRL 0x210f @@ -444,6 +445,33 @@ static const struct dcn_hubbub_mask hubbub_mask = { HUBBUB_MASK_SH_LIST_DCN10(_MASK) }; +static const struct dcn_dio_registers dio_regs = { + DIO_REG_LIST_DCN10() +}; + +#define DIO_MASK_SH_LIST(mask_sh)\ + HWS_SF(, DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh) + +static const struct dcn_dio_shift dio_shift = { + DIO_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn_dio_mask dio_mask = { + DIO_MASK_SH_LIST(_MASK) +}; + +static struct dio *dcn10_dio_create(struct dc_context *ctx) +{ + struct dcn10_dio *dio10 = kzalloc_obj(struct dcn10_dio); + + if (!dio10) + return NULL; + + dcn10_dio_construct(dio10, ctx, &dio_regs, &dio_shift, &dio_mask); + + return &dio10->base; +} + static int map_transmitter_id_to_phy_instance( enum transmitter transmitter) { @@ -917,6 +945,11 @@ static void dcn10_resource_destruct(struct dcn10_resource_pool *pool) kfree(pool->base.hubbub); pool->base.hubbub = NULL; + if (pool->base.dio != NULL) { + kfree(TO_DCN10_DIO(pool->base.dio)); + pool->base.dio = NULL; + } + for (i = 0; i < pool->base.pipe_count; i++) { if (pool->base.opps[i] != NULL) pool->base.opps[i]->funcs->opp_destroy(&pool->base.opps[i]); @@ -1653,6 +1686,14 @@ static bool dcn10_resource_construct( goto fail; } + /* DIO */ + pool->base.dio = dcn10_dio_create(ctx); + if (pool->base.dio == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create dio!\n"); + goto fail; + } + if (!resource_construct(num_virtual_links, dc, &pool->base, &res_create_funcs)) goto fail; diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn20/dcn20_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn20/dcn20_resource.c index 8b555187ac75..74e8d229c9dd 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn20/dcn20_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn20/dcn20_resource.c @@ -82,6 +82,7 @@ #include "dce/dce_dmcu.h" #include "dce/dce_aux.h" #include "dce/dce_i2c.h" +#include "dio/dcn10/dcn10_dio.h" #include "vm_helper.h" #include "link_enc_cfg.h" @@ -550,6 +551,33 @@ static const struct dcn_hubbub_mask hubbub_mask = { HUBBUB_MASK_SH_LIST_DCN20(_MASK) }; +static const struct dcn_dio_registers dio_regs = { + DIO_REG_LIST_DCN10() +}; + +#define DIO_MASK_SH_LIST(mask_sh)\ + HWS_SF(, DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh) + +static const struct dcn_dio_shift dio_shift = { + DIO_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn_dio_mask dio_mask = { + DIO_MASK_SH_LIST(_MASK) +}; + +static struct dio *dcn20_dio_create(struct dc_context *ctx) +{ + struct dcn10_dio *dio10 = kzalloc_obj(struct dcn10_dio); + + if (!dio10) + return NULL; + + dcn10_dio_construct(dio10, ctx, &dio_regs, &dio_shift, &dio_mask); + + return &dio10->base; +} + #define vmid_regs(id)\ [id] = {\ DCN20_VMID_REG_LIST(id)\ @@ -1104,6 +1132,12 @@ static void dcn20_resource_destruct(struct dcn20_resource_pool *pool) kfree(pool->base.hubbub); pool->base.hubbub = NULL; } + + if (pool->base.dio != NULL) { + kfree(TO_DCN10_DIO(pool->base.dio)); + pool->base.dio = NULL; + } + for (i = 0; i < pool->base.pipe_count; i++) { if (pool->base.dpps[i] != NULL) dcn20_dpp_destroy(&pool->base.dpps[i]); @@ -2692,6 +2726,14 @@ static bool dcn20_resource_construct( goto create_fail; } + /* DIO */ + pool->base.dio = dcn20_dio_create(ctx); + if (pool->base.dio == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create dio!\n"); + goto create_fail; + } + for (i = 0; i < pool->base.res_cap->num_dsc; i++) { pool->base.dscs[i] = dcn20_dsc_create(ctx, i); if (pool->base.dscs[i] == NULL) { diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn201/dcn201_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn201/dcn201_resource.c index 4ea76e46ab15..e289be70efb5 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn201/dcn201_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn201/dcn201_resource.c @@ -56,6 +56,7 @@ #include "dce/dce_aux.h" #include "dce/dce_i2c.h" #include "dcn10/dcn10_resource.h" +#include "dio/dcn10/dcn10_dio.h" #include "cyan_skillfish_ip_offset.h" @@ -755,6 +756,33 @@ static struct hubbub *dcn201_hubbub_create(struct dc_context *ctx) return &hubbub->base; } +static const struct dcn_dio_registers dio_regs = { + DIO_REG_LIST_DCN10() +}; + +#define DIO_MASK_SH_LIST(mask_sh)\ + HWS_SF(, DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh) + +static const struct dcn_dio_shift dio_shift = { + DIO_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn_dio_mask dio_mask = { + DIO_MASK_SH_LIST(_MASK) +}; + +static struct dio *dcn201_dio_create(struct dc_context *ctx) +{ + struct dcn10_dio *dio10 = kzalloc_obj(struct dcn10_dio); + + if (!dio10) + return NULL; + + dcn10_dio_construct(dio10, ctx, &dio_regs, &dio_shift, &dio_mask); + + return &dio10->base; +} + static struct timing_generator *dcn201_timing_generator_create( struct dc_context *ctx, uint32_t instance) @@ -930,6 +958,11 @@ static void dcn201_resource_destruct(struct dcn201_resource_pool *pool) pool->base.hubbub = NULL; } + if (pool->base.dio != NULL) { + kfree(TO_DCN10_DIO(pool->base.dio)); + pool->base.dio = NULL; + } + for (i = 0; i < pool->base.pipe_count; i++) { if (pool->base.dpps[i] != NULL) dcn201_dpp_destroy(&pool->base.dpps[i]); @@ -1276,6 +1309,14 @@ static bool dcn201_resource_construct( goto create_fail; } + /* DIO */ + pool->base.dio = dcn201_dio_create(ctx); + if (pool->base.dio == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create dio!\n"); + goto create_fail; + } + if (!resource_construct(num_virtual_links, dc, &pool->base, &res_create_funcs)) goto create_fail; diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn21/dcn21_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn21/dcn21_resource.c index 0f4307f8f3dd..4333baac96ad 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn21/dcn21_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn21/dcn21_resource.c @@ -84,6 +84,7 @@ #include "dce/dce_dmcu.h" #include "dce/dce_aux.h" #include "dce/dce_i2c.h" +#include "dio/dcn10/dcn10_dio.h" #include "dcn21_resource.h" #include "vm_helper.h" #include "dcn20/dcn20_vmid.h" @@ -329,6 +330,25 @@ static const struct dcn_hubbub_mask hubbub_mask = { HUBBUB_MASK_SH_LIST_DCN21(_MASK) }; +static const struct dcn_dio_registers dio_regs = { + DIO_REG_LIST_DCN10() +}; + +static const struct dcn_dio_shift dio_shift = { 0 }; + +static const struct dcn_dio_mask dio_mask = { 0 }; + +static struct dio *dcn21_dio_create(struct dc_context *ctx) +{ + struct dcn10_dio *dio10 = kzalloc_obj(struct dcn10_dio); + + if (!dio10) + return NULL; + + dcn10_dio_construct(dio10, ctx, &dio_regs, &dio_shift, &dio_mask); + + return &dio10->base; +} #define vmid_regs(id)\ [id] = {\ @@ -677,6 +697,12 @@ static void dcn21_resource_destruct(struct dcn21_resource_pool *pool) kfree(pool->base.hubbub); pool->base.hubbub = NULL; } + + if (pool->base.dio != NULL) { + kfree(TO_DCN10_DIO(pool->base.dio)); + pool->base.dio = NULL; + } + for (i = 0; i < pool->base.pipe_count; i++) { if (pool->base.dpps[i] != NULL) dcn20_dpp_destroy(&pool->base.dpps[i]); @@ -1654,6 +1680,14 @@ static bool dcn21_resource_construct( goto create_fail; } + /* DIO */ + pool->base.dio = dcn21_dio_create(ctx); + if (pool->base.dio == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create dio!\n"); + goto create_fail; + } + for (i = 0; i < pool->base.res_cap->num_dsc; i++) { pool->base.dscs[i] = dcn21_dsc_create(ctx, i); if (pool->base.dscs[i] == NULL) { diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn30/dcn30_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn30/dcn30_resource.c index 2fa86b9587ed..87b7b4ee04c6 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn30/dcn30_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn30/dcn30_resource.c @@ -60,6 +60,7 @@ #include "dml/display_mode_vba.h" #include "dcn30/dcn30_dccg.h" #include "dcn10/dcn10_resource.h" +#include "dio/dcn10/dcn10_dio.h" #include "link_service.h" #include "dce/dce_panel_cntl.h" @@ -886,6 +887,33 @@ static struct hubbub *dcn30_hubbub_create(struct dc_context *ctx) return &hubbub3->base; } +static const struct dcn_dio_registers dio_regs = { + DIO_REG_LIST_DCN10() +}; + +#define DIO_MASK_SH_LIST(mask_sh)\ + HWS_SF(, DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh) + +static const struct dcn_dio_shift dio_shift = { + DIO_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn_dio_mask dio_mask = { + DIO_MASK_SH_LIST(_MASK) +}; + +static struct dio *dcn30_dio_create(struct dc_context *ctx) +{ + struct dcn10_dio *dio10 = kzalloc_obj(struct dcn10_dio); + + if (!dio10) + return NULL; + + dcn10_dio_construct(dio10, ctx, &dio_regs, &dio_shift, &dio_mask); + + return &dio10->base; +} + static struct timing_generator *dcn30_timing_generator_create( struct dc_context *ctx, uint32_t instance) @@ -1095,6 +1123,12 @@ static void dcn30_resource_destruct(struct dcn30_resource_pool *pool) kfree(pool->base.hubbub); pool->base.hubbub = NULL; } + + if (pool->base.dio != NULL) { + kfree(TO_DCN10_DIO(pool->base.dio)); + pool->base.dio = NULL; + } + for (i = 0; i < pool->base.pipe_count; i++) { if (pool->base.dpps[i] != NULL) dcn30_dpp_destroy(&pool->base.dpps[i]); @@ -2464,6 +2498,14 @@ static bool dcn30_resource_construct( goto create_fail; } + /* DIO */ + pool->base.dio = dcn30_dio_create(ctx); + if (pool->base.dio == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create dio!\n"); + goto create_fail; + } + /* HUBPs, DPPs, OPPs and TGs */ for (i = 0; i < pool->base.pipe_count; i++) { pool->base.hubps[i] = dcn30_hubp_create(ctx, i); diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn301/dcn301_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn301/dcn301_resource.c index 7842bee57e63..6bb1c62124bb 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn301/dcn301_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn301/dcn301_resource.c @@ -59,6 +59,7 @@ #include "dml/display_mode_vba.h" #include "dcn301/dcn301_dccg.h" #include "dcn10/dcn10_resource.h" +#include "dio/dcn10/dcn10_dio.h" #include "dcn30/dcn30_dio_stream_encoder.h" #include "dcn301/dcn301_dio_link_encoder.h" #include "dcn301/dcn301_panel_cntl.h" @@ -843,6 +844,33 @@ static struct hubbub *dcn301_hubbub_create(struct dc_context *ctx) return &hubbub3->base; } +static const struct dcn_dio_registers dio_regs = { + DIO_REG_LIST_DCN10() +}; + +#define DIO_MASK_SH_LIST(mask_sh)\ + HWS_SF(, DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh) + +static const struct dcn_dio_shift dio_shift = { + DIO_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn_dio_mask dio_mask = { + DIO_MASK_SH_LIST(_MASK) +}; + +static struct dio *dcn301_dio_create(struct dc_context *ctx) +{ + struct dcn10_dio *dio10 = kzalloc_obj(struct dcn10_dio); + + if (!dio10) + return NULL; + + dcn10_dio_construct(dio10, ctx, &dio_regs, &dio_shift, &dio_mask); + + return &dio10->base; +} + static struct timing_generator *dcn301_timing_generator_create( struct dc_context *ctx, uint32_t instance) { @@ -1066,6 +1094,12 @@ static void dcn301_destruct(struct dcn301_resource_pool *pool) kfree(pool->base.hubbub); pool->base.hubbub = NULL; } + + if (pool->base.dio != NULL) { + kfree(TO_DCN10_DIO(pool->base.dio)); + pool->base.dio = NULL; + } + for (i = 0; i < pool->base.pipe_count; i++) { if (pool->base.dpps[i] != NULL) dcn301_dpp_destroy(&pool->base.dpps[i]); @@ -1582,6 +1616,14 @@ static bool dcn301_resource_construct( goto create_fail; } + /* DIO */ + pool->base.dio = dcn301_dio_create(ctx); + if (pool->base.dio == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create dio!\n"); + goto create_fail; + } + j = 0; /* HUBPs, DPPs, OPPs and TGs */ for (i = 0; i < pool->base.pipe_count; i++) { diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn302/dcn302_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn302/dcn302_resource.c index 1874d5d6b782..d02aafd06fd4 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn302/dcn302_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn302/dcn302_resource.c @@ -46,6 +46,7 @@ #include "dml/dcn30/dcn30_fpu.h" #include "dcn10/dcn10_resource.h" +#include "dio/dcn10/dcn10_dio.h" #include "link_service.h" @@ -253,6 +254,33 @@ static const struct dcn20_vmid_mask vmid_masks = { DCN20_VMID_MASK_SH_LIST(_MASK) }; +static const struct dcn_dio_registers dio_regs = { + DIO_REG_LIST_DCN10() +}; + +#define DIO_MASK_SH_LIST(mask_sh)\ + HWS_SF(, DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh) + +static const struct dcn_dio_shift dio_shift = { + DIO_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn_dio_mask dio_mask = { + DIO_MASK_SH_LIST(_MASK) +}; + +static struct dio *dcn302_dio_create(struct dc_context *ctx) +{ + struct dcn10_dio *dio10 = kzalloc_obj(struct dcn10_dio); + + if (!dio10) + return NULL; + + dcn10_dio_construct(dio10, ctx, &dio_regs, &dio_shift, &dio_mask); + + return &dio10->base; +} + static struct hubbub *dcn302_hubbub_create(struct dc_context *ctx) { int i; @@ -1022,6 +1050,11 @@ static void dcn302_resource_destruct(struct resource_pool *pool) pool->hubbub = NULL; } + if (pool->dio != NULL) { + kfree(TO_DCN10_DIO(pool->dio)); + pool->dio = NULL; + } + for (i = 0; i < pool->pipe_count; i++) { if (pool->dpps[i] != NULL) { kfree(TO_DCN20_DPP(pool->dpps[i])); @@ -1372,6 +1405,14 @@ static bool dcn302_resource_construct( goto create_fail; } + /* DIO */ + pool->dio = dcn302_dio_create(ctx); + if (pool->dio == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create dio!\n"); + goto create_fail; + } + /* HUBPs, DPPs, OPPs and TGs */ for (i = 0; i < pool->pipe_count; i++) { pool->hubps[i] = dcn302_hubp_create(ctx, i); diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn303/dcn303_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn303/dcn303_resource.c index d52201cb359f..30b1403112c6 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn303/dcn303_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn303/dcn303_resource.c @@ -46,6 +46,7 @@ #include "dml/dcn30/dcn30_fpu.h" #include "dcn10/dcn10_resource.h" +#include "dio/dcn10/dcn10_dio.h" #include "link_service.h" @@ -249,6 +250,33 @@ static const struct dcn20_vmid_mask vmid_masks = { DCN20_VMID_MASK_SH_LIST(_MASK) }; +static const struct dcn_dio_registers dio_regs = { + DIO_REG_LIST_DCN10() +}; + +#define DIO_MASK_SH_LIST(mask_sh)\ + HWS_SF(, DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh) + +static const struct dcn_dio_shift dio_shift = { + DIO_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn_dio_mask dio_mask = { + DIO_MASK_SH_LIST(_MASK) +}; + +static struct dio *dcn303_dio_create(struct dc_context *ctx) +{ + struct dcn10_dio *dio10 = kzalloc_obj(struct dcn10_dio); + + if (!dio10) + return NULL; + + dcn10_dio_construct(dio10, ctx, &dio_regs, &dio_shift, &dio_mask); + + return &dio10->base; +} + static struct hubbub *dcn303_hubbub_create(struct dc_context *ctx) { int i; @@ -966,6 +994,11 @@ static void dcn303_resource_destruct(struct resource_pool *pool) pool->hubbub = NULL; } + if (pool->dio != NULL) { + kfree(TO_DCN10_DIO(pool->dio)); + pool->dio = NULL; + } + for (i = 0; i < pool->pipe_count; i++) { if (pool->dpps[i] != NULL) { kfree(TO_DCN20_DPP(pool->dpps[i])); @@ -1304,6 +1337,14 @@ static bool dcn303_resource_construct( goto create_fail; } + /* DIO */ + pool->dio = dcn303_dio_create(ctx); + if (pool->dio == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create dio!\n"); + goto create_fail; + } + /* HUBPs, DPPs, OPPs and TGs */ for (i = 0; i < pool->pipe_count; i++) { pool->hubps[i] = dcn303_hubp_create(ctx, i); diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn31/dcn31_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn31/dcn31_resource.c index 2055f1f8af65..4e9c041c707a 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn31/dcn31_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn31/dcn31_resource.c @@ -64,6 +64,7 @@ #include "dce/dce_audio.h" #include "dce/dce_hwseq.h" #include "clk_mgr.h" +#include "dio/dcn10/dcn10_dio.h" #include "dio/virtual/virtual_stream_encoder.h" #include "dce110/dce110_resource.h" #include "dml/display_mode_vba.h" @@ -810,6 +811,21 @@ static const struct dcn20_vmid_mask vmid_masks = { DCN20_VMID_MASK_SH_LIST(_MASK) }; +static const struct dcn_dio_registers dio_regs = { + DIO_REG_LIST_DCN10() +}; + +#define DIO_MASK_SH_LIST(mask_sh)\ + HWS_SF(, DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh) + +static const struct dcn_dio_shift dio_shift = { + DIO_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn_dio_mask dio_mask = { + DIO_MASK_SH_LIST(_MASK) +}; + static const struct resource_caps res_cap_dcn31 = { .num_timing_generator = 4, .num_opp = 4, @@ -1021,6 +1037,18 @@ static struct mpc *dcn31_mpc_create( return &mpc30->base; } +static struct dio *dcn31_dio_create(struct dc_context *ctx) +{ + struct dcn10_dio *dio10 = kzalloc_obj(struct dcn10_dio); + + if (!dio10) + return NULL; + + dcn10_dio_construct(dio10, ctx, &dio_regs, &dio_shift, &dio_mask); + + return &dio10->base; +} + static struct hubbub *dcn31_hubbub_create(struct dc_context *ctx) { int i; @@ -1396,6 +1424,10 @@ static void dcn31_resource_destruct(struct dcn31_resource_pool *pool) kfree(pool->base.hubbub); pool->base.hubbub = NULL; } + if (pool->base.dio != NULL) { + kfree(TO_DCN10_DIO(pool->base.dio)); + pool->base.dio = NULL; + } for (i = 0; i < pool->base.pipe_count; i++) { if (pool->base.dpps[i] != NULL) dcn31_dpp_destroy(&pool->base.dpps[i]); @@ -2063,6 +2095,14 @@ static bool dcn31_resource_construct( goto create_fail; } + /* DIO */ + pool->base.dio = dcn31_dio_create(ctx); + if (pool->base.dio == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create dio!\n"); + goto create_fail; + } + /* HUBPs, DPPs, OPPs and TGs */ for (i = 0; i < pool->base.pipe_count; i++) { pool->base.hubps[i] = dcn31_hubp_create(ctx, i); diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn314/dcn314_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn314/dcn314_resource.c index 1939f720ba29..e26a6427916a 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn314/dcn314_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn314/dcn314_resource.c @@ -66,6 +66,7 @@ #include "dce/dce_audio.h" #include "dce/dce_hwseq.h" #include "clk_mgr.h" +#include "dio/dcn10/dcn10_dio.h" #include "dio/virtual/virtual_stream_encoder.h" #include "dce110/dce110_resource.h" #include "dml/display_mode_vba.h" @@ -822,6 +823,21 @@ static const struct dcn20_vmid_mask vmid_masks = { DCN20_VMID_MASK_SH_LIST(_MASK) }; +static const struct dcn_dio_registers dio_regs = { + DIO_REG_LIST_DCN10() +}; + +#define DIO_MASK_SH_LIST(mask_sh)\ + HWS_SF(, DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh) + +static const struct dcn_dio_shift dio_shift = { + DIO_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn_dio_mask dio_mask = { + DIO_MASK_SH_LIST(_MASK) +}; + static const struct resource_caps res_cap_dcn314 = { .num_timing_generator = 4, .num_opp = 4, @@ -1079,6 +1095,18 @@ static struct mpc *dcn31_mpc_create( return &mpc30->base; } +static struct dio *dcn314_dio_create(struct dc_context *ctx) +{ + struct dcn10_dio *dio10 = kzalloc_obj(struct dcn10_dio); + + if (!dio10) + return NULL; + + dcn10_dio_construct(dio10, ctx, &dio_regs, &dio_shift, &dio_mask); + + return &dio10->base; +} + static struct hubbub *dcn31_hubbub_create(struct dc_context *ctx) { int i; @@ -1455,6 +1483,10 @@ static void dcn314_resource_destruct(struct dcn314_resource_pool *pool) kfree(pool->base.hubbub); pool->base.hubbub = NULL; } + if (pool->base.dio != NULL) { + kfree(TO_DCN10_DIO(pool->base.dio)); + pool->base.dio = NULL; + } for (i = 0; i < pool->base.pipe_count; i++) { if (pool->base.dpps[i] != NULL) dcn31_dpp_destroy(&pool->base.dpps[i]); @@ -1987,6 +2019,14 @@ static bool dcn314_resource_construct( goto create_fail; } + /* DIO */ + pool->base.dio = dcn314_dio_create(ctx); + if (pool->base.dio == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create dio!\n"); + goto create_fail; + } + /* HUBPs, DPPs, OPPs and TGs */ for (i = 0; i < pool->base.pipe_count; i++) { pool->base.hubps[i] = dcn31_hubp_create(ctx, i); diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn315/dcn315_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn315/dcn315_resource.c index e8377c190f63..131a6cd4c735 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn315/dcn315_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn315/dcn315_resource.c @@ -63,6 +63,7 @@ #include "dce/dce_audio.h" #include "dce/dce_hwseq.h" #include "clk_mgr.h" +#include "dio/dcn10/dcn10_dio.h" #include "dio/virtual/virtual_stream_encoder.h" #include "dce110/dce110_resource.h" #include "dml/display_mode_vba.h" @@ -809,6 +810,21 @@ static const struct dcn20_vmid_mask vmid_masks = { DCN20_VMID_MASK_SH_LIST(_MASK) }; +static const struct dcn_dio_registers dio_regs = { + DIO_REG_LIST_DCN10() +}; + +#define DIO_MASK_SH_LIST(mask_sh)\ + HWS_SF(, DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh) + +static const struct dcn_dio_shift dio_shift = { + DIO_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn_dio_mask dio_mask = { + DIO_MASK_SH_LIST(_MASK) +}; + static const struct resource_caps res_cap_dcn31 = { .num_timing_generator = 4, .num_opp = 4, @@ -1020,6 +1036,18 @@ static struct mpc *dcn31_mpc_create( return &mpc30->base; } +static struct dio *dcn315_dio_create(struct dc_context *ctx) +{ + struct dcn10_dio *dio10 = kzalloc_obj(struct dcn10_dio); + + if (!dio10) + return NULL; + + dcn10_dio_construct(dio10, ctx, &dio_regs, &dio_shift, &dio_mask); + + return &dio10->base; +} + static struct hubbub *dcn31_hubbub_create(struct dc_context *ctx) { int i; @@ -1397,6 +1425,10 @@ static void dcn315_resource_destruct(struct dcn315_resource_pool *pool) kfree(pool->base.hubbub); pool->base.hubbub = NULL; } + if (pool->base.dio != NULL) { + kfree(TO_DCN10_DIO(pool->base.dio)); + pool->base.dio = NULL; + } for (i = 0; i < pool->base.pipe_count; i++) { if (pool->base.dpps[i] != NULL) dcn31_dpp_destroy(&pool->base.dpps[i]); @@ -2012,6 +2044,14 @@ static bool dcn315_resource_construct( goto create_fail; } + /* DIO */ + pool->base.dio = dcn315_dio_create(ctx); + if (pool->base.dio == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create dio!\n"); + goto create_fail; + } + /* HUBPs, DPPs, OPPs and TGs */ for (i = 0; i < pool->base.pipe_count; i++) { pool->base.hubps[i] = dcn31_hubp_create(ctx, i); diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn316/dcn316_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn316/dcn316_resource.c index 045ce01bd74e..c8c0ce6efcfd 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn316/dcn316_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn316/dcn316_resource.c @@ -63,6 +63,7 @@ #include "dce/dce_audio.h" #include "dce/dce_hwseq.h" #include "clk_mgr.h" +#include "dio/dcn10/dcn10_dio.h" #include "dio/virtual/virtual_stream_encoder.h" #include "dce110/dce110_resource.h" #include "dml/display_mode_vba.h" @@ -804,6 +805,21 @@ static const struct dcn20_vmid_mask vmid_masks = { DCN20_VMID_MASK_SH_LIST(_MASK) }; +static const struct dcn_dio_registers dio_regs = { + DIO_REG_LIST_DCN10() +}; + +#define DIO_MASK_SH_LIST(mask_sh)\ + HWS_SF(, DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh) + +static const struct dcn_dio_shift dio_shift = { + DIO_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn_dio_mask dio_mask = { + DIO_MASK_SH_LIST(_MASK) +}; + static const struct resource_caps res_cap_dcn31 = { .num_timing_generator = 4, .num_opp = 4, @@ -1013,6 +1029,18 @@ static struct mpc *dcn31_mpc_create( return &mpc30->base; } +static struct dio *dcn316_dio_create(struct dc_context *ctx) +{ + struct dcn10_dio *dio10 = kzalloc_obj(struct dcn10_dio); + + if (!dio10) + return NULL; + + dcn10_dio_construct(dio10, ctx, &dio_regs, &dio_shift, &dio_mask); + + return &dio10->base; +} + static struct hubbub *dcn31_hubbub_create(struct dc_context *ctx) { int i; @@ -1392,6 +1420,10 @@ static void dcn316_resource_destruct(struct dcn316_resource_pool *pool) kfree(pool->base.hubbub); pool->base.hubbub = NULL; } + if (pool->base.dio != NULL) { + kfree(TO_DCN10_DIO(pool->base.dio)); + pool->base.dio = NULL; + } for (i = 0; i < pool->base.pipe_count; i++) { if (pool->base.dpps[i] != NULL) dcn31_dpp_destroy(&pool->base.dpps[i]); @@ -1887,6 +1919,14 @@ static bool dcn316_resource_construct( goto create_fail; } + /* DIO */ + pool->base.dio = dcn316_dio_create(ctx); + if (pool->base.dio == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create dio!\n"); + goto create_fail; + } + /* HUBPs, DPPs, OPPs and TGs */ for (i = 0; i < pool->base.pipe_count; i++) { pool->base.hubps[i] = dcn31_hubp_create(ctx, i); diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c index c7fd604024d6..c3a6ae14de18 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c @@ -66,6 +66,7 @@ #include "dce/dce_hwseq.h" #include "clk_mgr.h" #include "dio/virtual/virtual_stream_encoder.h" +#include "dio/dcn10/dcn10_dio.h" #include "dml/display_mode_vba.h" #include "dcn32/dcn32_dccg.h" #include "dcn10/dcn10_resource.h" @@ -643,6 +644,19 @@ static const struct dcn20_vmid_mask vmid_masks = { DCN20_VMID_MASK_SH_LIST(_MASK) }; +static struct dcn_dio_registers dio_regs; + +#define DIO_MASK_SH_LIST(mask_sh)\ + HWS_SF(, DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh) + +static const struct dcn_dio_shift dio_shift = { + DIO_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn_dio_mask dio_mask = { + DIO_MASK_SH_LIST(_MASK) +}; + static const struct resource_caps res_cap_dcn32 = { .num_timing_generator = 4, .num_opp = 4, @@ -833,6 +847,22 @@ static struct clock_source *dcn32_clock_source_create( return NULL; } +static struct dio *dcn32_dio_create(struct dc_context *ctx) +{ + struct dcn10_dio *dio10 = kzalloc_obj(struct dcn10_dio); + + if (!dio10) + return NULL; + +#undef REG_STRUCT +#define REG_STRUCT dio_regs + DIO_REG_LIST_DCN10(); + + dcn10_dio_construct(dio10, ctx, &dio_regs, &dio_shift, &dio_mask); + + return &dio10->base; +} + static struct hubbub *dcn32_hubbub_create(struct dc_context *ctx) { int i; @@ -1494,6 +1524,11 @@ static void dcn32_resource_destruct(struct dcn32_resource_pool *pool) if (pool->base.dccg != NULL) dcn_dccg_destroy(&pool->base.dccg); + if (pool->base.dio != NULL) { + kfree(TO_DCN10_DIO(pool->base.dio)); + pool->base.dio = NULL; + } + if (pool->base.oem_device != NULL) { struct dc *dc = pool->base.oem_device->ctx->dc; @@ -2373,6 +2408,14 @@ static bool dcn32_resource_construct( goto create_fail; } + /* DIO */ + pool->base.dio = dcn32_dio_create(ctx); + if (pool->base.dio == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create dio!\n"); + goto create_fail; + } + /* HUBPs, DPPs, OPPs, TGs, ABMs */ for (i = 0, j = 0; i < pool->base.res_cap->num_timing_generator; i++) { diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn321/dcn321_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn321/dcn321_resource.c index c1582c27ac87..990aec7eb3d0 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn321/dcn321_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn321/dcn321_resource.c @@ -69,6 +69,7 @@ #include "dce/dce_hwseq.h" #include "clk_mgr.h" #include "dio/virtual/virtual_stream_encoder.h" +#include "dio/dcn10/dcn10_dio.h" #include "dml/display_mode_vba.h" #include "dcn32/dcn32_dccg.h" #include "dcn10/dcn10_resource.h" @@ -639,6 +640,19 @@ static const struct dcn20_vmid_mask vmid_masks = { DCN20_VMID_MASK_SH_LIST(_MASK) }; +static struct dcn_dio_registers dio_regs; + +#define DIO_MASK_SH_LIST(mask_sh)\ + HWS_SF(, DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh) + +static const struct dcn_dio_shift dio_shift = { + DIO_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn_dio_mask dio_mask = { + DIO_MASK_SH_LIST(_MASK) +}; + static const struct resource_caps res_cap_dcn321 = { .num_timing_generator = 4, .num_opp = 4, @@ -827,6 +841,22 @@ static struct clock_source *dcn321_clock_source_create( return NULL; } +static struct dio *dcn321_dio_create(struct dc_context *ctx) +{ + struct dcn10_dio *dio10 = kzalloc_obj(struct dcn10_dio); + + if (!dio10) + return NULL; + +#undef REG_STRUCT +#define REG_STRUCT dio_regs + DIO_REG_LIST_DCN10(); + + dcn10_dio_construct(dio10, ctx, &dio_regs, &dio_shift, &dio_mask); + + return &dio10->base; +} + static struct hubbub *dcn321_hubbub_create(struct dc_context *ctx) { int i; @@ -1474,6 +1504,11 @@ static void dcn321_resource_destruct(struct dcn321_resource_pool *pool) if (pool->base.dccg != NULL) dcn_dccg_destroy(&pool->base.dccg); + if (pool->base.dio != NULL) { + kfree(TO_DCN10_DIO(pool->base.dio)); + pool->base.dio = NULL; + } + if (pool->base.oem_device != NULL) { struct dc *dc = pool->base.oem_device->ctx->dc; @@ -1872,6 +1907,14 @@ static bool dcn321_resource_construct( goto create_fail; } + /* DIO */ + pool->base.dio = dcn321_dio_create(ctx); + if (pool->base.dio == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create dio!\n"); + goto create_fail; + } + /* HUBPs, DPPs, OPPs, TGs, ABMs */ for (i = 0, j = 0; i < pool->base.res_cap->num_timing_generator; i++) { diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c index 3494a40cea99..598b2f25881d 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c @@ -71,6 +71,7 @@ #include "dce/dce_hwseq.h" #include "clk_mgr.h" #include "dio/virtual/virtual_stream_encoder.h" +#include "dio/dcn10/dcn10_dio.h" #include "dce110/dce110_resource.h" #include "dml/display_mode_vba.h" #include "dcn35/dcn35_dccg.h" @@ -664,6 +665,19 @@ static const struct dcn20_vmid_mask vmid_masks = { DCN20_VMID_MASK_SH_LIST(_MASK) }; +static struct dcn_dio_registers dio_regs; + +#define DIO_MASK_SH_LIST(mask_sh)\ + HWS_SF(, DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh) + +static const struct dcn_dio_shift dio_shift = { + DIO_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn_dio_mask dio_mask = { + DIO_MASK_SH_LIST(_MASK) +}; + static const struct resource_caps res_cap_dcn35 = { .num_timing_generator = 4, .num_opp = 4, @@ -973,6 +987,22 @@ static struct mpc *dcn35_mpc_create( return &mpc30->base; } +static struct dio *dcn35_dio_create(struct dc_context *ctx) +{ + struct dcn10_dio *dio10 = kzalloc_obj(struct dcn10_dio); + + if (!dio10) + return NULL; + +#undef REG_STRUCT +#define REG_STRUCT dio_regs + DIO_REG_LIST_DCN10(); + + dcn10_dio_construct(dio10, ctx, &dio_regs, &dio_shift, &dio_mask); + + return &dio10->base; +} + static struct hubbub *dcn35_hubbub_create(struct dc_context *ctx) { int i; @@ -1563,6 +1593,11 @@ static void dcn35_resource_destruct(struct dcn35_resource_pool *pool) if (pool->base.dccg != NULL) dcn_dccg_destroy(&pool->base.dccg); + + if (pool->base.dio != NULL) { + kfree(TO_DCN10_DIO(pool->base.dio)); + pool->base.dio = NULL; + } } static struct hubp *dcn35_hubp_create( @@ -2033,6 +2068,14 @@ static bool dcn35_resource_construct( goto create_fail; } + /* DIO */ + pool->base.dio = dcn35_dio_create(ctx); + if (pool->base.dio == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create dio!\n"); + goto create_fail; + } + /* HUBPs, DPPs, OPPs and TGs */ for (i = 0; i < pool->base.pipe_count; i++) { pool->base.hubps[i] = dcn35_hubp_create(ctx, i); diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn351/dcn351_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn351/dcn351_resource.c index 080bc7f24ffa..7e15d07df7a3 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn351/dcn351_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn351/dcn351_resource.c @@ -50,6 +50,7 @@ #include "dce/dce_hwseq.h" #include "clk_mgr.h" #include "dio/virtual/virtual_stream_encoder.h" +#include "dio/dcn10/dcn10_dio.h" #include "dce110/dce110_resource.h" #include "dml/display_mode_vba.h" #include "dcn35/dcn35_dccg.h" @@ -644,6 +645,19 @@ static const struct dcn20_vmid_mask vmid_masks = { DCN20_VMID_MASK_SH_LIST(_MASK) }; +static struct dcn_dio_registers dio_regs; + +#define DIO_MASK_SH_LIST(mask_sh)\ + HWS_SF(, DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh) + +static const struct dcn_dio_shift dio_shift = { + DIO_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn_dio_mask dio_mask = { + DIO_MASK_SH_LIST(_MASK) +}; + static const struct resource_caps res_cap_dcn351 = { .num_timing_generator = 4, .num_opp = 4, @@ -953,6 +967,22 @@ static struct mpc *dcn35_mpc_create( return &mpc30->base; } +static struct dio *dcn351_dio_create(struct dc_context *ctx) +{ + struct dcn10_dio *dio10 = kzalloc_obj(struct dcn10_dio); + + if (!dio10) + return NULL; + +#undef REG_STRUCT +#define REG_STRUCT dio_regs + DIO_REG_LIST_DCN10(); + + dcn10_dio_construct(dio10, ctx, &dio_regs, &dio_shift, &dio_mask); + + return &dio10->base; +} + static struct hubbub *dcn35_hubbub_create(struct dc_context *ctx) { int i; @@ -1543,6 +1573,11 @@ static void dcn351_resource_destruct(struct dcn351_resource_pool *pool) if (pool->base.dccg != NULL) dcn_dccg_destroy(&pool->base.dccg); + + if (pool->base.dio != NULL) { + kfree(TO_DCN10_DIO(pool->base.dio)); + pool->base.dio = NULL; + } } static struct hubp *dcn35_hubp_create( @@ -2005,6 +2040,14 @@ static bool dcn351_resource_construct( goto create_fail; } + /* DIO */ + pool->base.dio = dcn351_dio_create(ctx); + if (pool->base.dio == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create dio!\n"); + goto create_fail; + } + /* HUBPs, DPPs, OPPs and TGs */ for (i = 0; i < pool->base.pipe_count; i++) { pool->base.hubps[i] = dcn35_hubp_create(ctx, i); diff --git a/drivers/gpu/drm/amd/display/dc/resource/dcn36/dcn36_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dcn36/dcn36_resource.c index af51ac4ea59e..83fee2ca61bf 100644 --- a/drivers/gpu/drm/amd/display/dc/resource/dcn36/dcn36_resource.c +++ b/drivers/gpu/drm/amd/display/dc/resource/dcn36/dcn36_resource.c @@ -50,6 +50,7 @@ #include "dce/dce_hwseq.h" #include "clk_mgr.h" #include "dio/virtual/virtual_stream_encoder.h" +#include "dio/dcn10/dcn10_dio.h" #include "dce110/dce110_resource.h" #include "dml/display_mode_vba.h" #include "dcn35/dcn35_dccg.h" @@ -651,6 +652,19 @@ static const struct dcn20_vmid_mask vmid_masks = { DCN20_VMID_MASK_SH_LIST(_MASK) }; +static struct dcn_dio_registers dio_regs; + +#define DIO_MASK_SH_LIST(mask_sh)\ + HWS_SF(, DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh) + +static const struct dcn_dio_shift dio_shift = { + DIO_MASK_SH_LIST(__SHIFT) +}; + +static const struct dcn_dio_mask dio_mask = { + DIO_MASK_SH_LIST(_MASK) +}; + static const struct resource_caps res_cap_dcn36 = { .num_timing_generator = 4, .num_opp = 4, @@ -960,6 +974,22 @@ static struct mpc *dcn35_mpc_create( return &mpc30->base; } +static struct dio *dcn36_dio_create(struct dc_context *ctx) +{ + struct dcn10_dio *dio10 = kzalloc_obj(struct dcn10_dio); + + if (!dio10) + return NULL; + +#undef REG_STRUCT +#define REG_STRUCT dio_regs + DIO_REG_LIST_DCN10(); + + dcn10_dio_construct(dio10, ctx, &dio_regs, &dio_shift, &dio_mask); + + return &dio10->base; +} + static struct hubbub *dcn35_hubbub_create(struct dc_context *ctx) { int i; @@ -1550,6 +1580,11 @@ static void dcn36_resource_destruct(struct dcn36_resource_pool *pool) if (pool->base.dccg != NULL) dcn_dccg_destroy(&pool->base.dccg); + + if (pool->base.dio != NULL) { + kfree(TO_DCN10_DIO(pool->base.dio)); + pool->base.dio = NULL; + } } static struct hubp *dcn35_hubp_create( @@ -2012,6 +2047,14 @@ static bool dcn36_resource_construct( goto create_fail; } + /* DIO */ + pool->base.dio = dcn36_dio_create(ctx); + if (pool->base.dio == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create dio!\n"); + goto create_fail; + } + /* HUBPs, DPPs, OPPs and TGs */ for (i = 0; i < pool->base.pipe_count; i++) { pool->base.hubps[i] = dcn35_hubp_create(ctx, i); diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c index 12b052d920f5..7ca8fdd23206 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c @@ -262,7 +262,6 @@ int smu_v11_0_check_fw_version(struct smu_context *smu) "smu fw program = %d, version = 0x%08x (%d.%d.%d)\n", smu->smc_driver_if_version, if_version, smu_program, smu_version, smu_major, smu_minor, smu_debug); - dev_info(smu->adev->dev, "SMU driver if version not matched\n"); } return ret; diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu12/smu_v12_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu12/smu_v12_0.c index 2c20624caca4..ac5e44dff6c9 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu12/smu_v12_0.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu12/smu_v12_0.c @@ -101,7 +101,6 @@ int smu_v12_0_check_fw_version(struct smu_context *smu) "smu fw program = %d, smu fw version = 0x%08x (%d.%d.%d)\n", smu->smc_driver_if_version, if_version, smu_program, smu_version, smu_major, smu_minor, smu_debug); - dev_info(smu->adev->dev, "SMU driver if version not matched\n"); } return ret; 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 a8d63d4d1f6e..554f616328c3 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 @@ -59,6 +59,10 @@ #define to_amdgpu_device(x) (container_of(x, struct amdgpu_device, pm.smu_i2c)) +static void smu_v13_0_0_get_od_setting_limits(struct smu_context *smu, + int od_feature_bit, + int32_t *min, int32_t *max); + static const struct smu_feature_bits smu_v13_0_0_dpm_features = { .bits = { SMU_FEATURE_BIT_INIT(FEATURE_DPM_GFXCLK_BIT), @@ -1043,8 +1047,35 @@ static bool smu_v13_0_0_is_od_feature_supported(struct smu_context *smu, PPTable_t *pptable = smu->smu_table.driver_pptable; const OverDriveLimits_t * const overdrive_upperlimits = &pptable->SkuTable.OverDriveLimitsBasicMax; + int32_t min_value, max_value; + bool feature_enabled; - return overdrive_upperlimits->FeatureCtrlMask & (1U << od_feature_bit); + switch (od_feature_bit) { + case PP_OD_FEATURE_FAN_CURVE_BIT: + feature_enabled = !!(overdrive_upperlimits->FeatureCtrlMask & (1U << od_feature_bit)); + if (feature_enabled) { + smu_v13_0_0_get_od_setting_limits(smu, PP_OD_FEATURE_FAN_CURVE_TEMP, + &min_value, &max_value); + if (!min_value && !max_value) { + feature_enabled = false; + goto out; + } + + smu_v13_0_0_get_od_setting_limits(smu, PP_OD_FEATURE_FAN_CURVE_PWM, + &min_value, &max_value); + if (!min_value && !max_value) { + feature_enabled = false; + goto out; + } + } + break; + default: + feature_enabled = !!(overdrive_upperlimits->FeatureCtrlMask & (1U << od_feature_bit)); + break; + } + +out: + return feature_enabled; } static void smu_v13_0_0_get_od_setting_limits(struct smu_context *smu, diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c index 896b51c8a9a7..870bcc86fd79 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu13/smu_v13_0_6_ppt.c @@ -1391,7 +1391,7 @@ static int smu_v13_0_6_emit_clk_levels(struct smu_context *smu, break; case SMU_OD_MCLK: if (!smu_v13_0_6_cap_supported(smu, SMU_CAP(SET_UCLK_MAX))) - return 0; + return -EOPNOTSUPP; size += sysfs_emit_at(buf, size, "%s:\n", "OD_MCLK"); size += sysfs_emit_at(buf, size, "0: %uMhz\n1: %uMhz\n", @@ -2122,6 +2122,7 @@ static int smu_v13_0_6_usr_edit_dpm_table(struct smu_context *smu, { struct smu_dpm_context *smu_dpm = &(smu->smu_dpm); struct smu_13_0_dpm_context *dpm_context = smu_dpm->dpm_context; + struct smu_dpm_table *uclk_table = &dpm_context->dpm_tables.uclk_table; struct smu_umd_pstate_table *pstate_table = &smu->pstate_table; uint32_t min_clk; uint32_t max_clk; @@ -2221,14 +2222,16 @@ static int smu_v13_0_6_usr_edit_dpm_table(struct smu_context *smu, if (ret) return ret; - min_clk = SMU_DPM_TABLE_MIN( - &dpm_context->dpm_tables.uclk_table); - max_clk = SMU_DPM_TABLE_MAX( - &dpm_context->dpm_tables.uclk_table); - ret = smu_v13_0_6_set_soft_freq_limited_range( - smu, SMU_UCLK, min_clk, max_clk, false); - if (ret) - return ret; + if (SMU_DPM_TABLE_MAX(uclk_table) != + pstate_table->uclk_pstate.curr.max) { + min_clk = SMU_DPM_TABLE_MIN(&dpm_context->dpm_tables.uclk_table); + max_clk = SMU_DPM_TABLE_MAX(&dpm_context->dpm_tables.uclk_table); + ret = smu_v13_0_6_set_soft_freq_limited_range(smu, + SMU_UCLK, min_clk, + max_clk, false); + if (ret) + return ret; + } smu_v13_0_reset_custom_level(smu); } break; 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 5500a0f12f0e..f331e87858c9 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 @@ -59,6 +59,10 @@ #define to_amdgpu_device(x) (container_of(x, struct amdgpu_device, pm.smu_i2c)) +static void smu_v13_0_7_get_od_setting_limits(struct smu_context *smu, + int od_feature_bit, + int32_t *min, int32_t *max); + static const struct smu_feature_bits smu_v13_0_7_dpm_features = { .bits = { SMU_FEATURE_BIT_INIT(FEATURE_DPM_GFXCLK_BIT), @@ -1053,8 +1057,35 @@ static bool smu_v13_0_7_is_od_feature_supported(struct smu_context *smu, PPTable_t *pptable = smu->smu_table.driver_pptable; const OverDriveLimits_t * const overdrive_upperlimits = &pptable->SkuTable.OverDriveLimitsBasicMax; + int32_t min_value, max_value; + bool feature_enabled; - return overdrive_upperlimits->FeatureCtrlMask & (1U << od_feature_bit); + switch (od_feature_bit) { + case PP_OD_FEATURE_FAN_CURVE_BIT: + feature_enabled = !!(overdrive_upperlimits->FeatureCtrlMask & (1U << od_feature_bit)); + if (feature_enabled) { + smu_v13_0_7_get_od_setting_limits(smu, PP_OD_FEATURE_FAN_CURVE_TEMP, + &min_value, &max_value); + if (!min_value && !max_value) { + feature_enabled = false; + goto out; + } + + smu_v13_0_7_get_od_setting_limits(smu, PP_OD_FEATURE_FAN_CURVE_PWM, + &min_value, &max_value); + if (!min_value && !max_value) { + feature_enabled = false; + goto out; + } + } + break; + default: + feature_enabled = !!(overdrive_upperlimits->FeatureCtrlMask & (1U << od_feature_bit)); + break; + } + +out: + return feature_enabled; } static void smu_v13_0_7_get_od_setting_limits(struct smu_context *smu, diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c index cec2df1ad0af..e38354c694c9 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c @@ -284,7 +284,6 @@ int smu_v14_0_check_fw_version(struct smu_context *smu) "smu fw program = %d, smu fw version = 0x%08x (%d.%d.%d)\n", smu->smc_driver_if_version, if_version, smu_program, smu_version, smu_major, smu_minor, smu_debug); - dev_info(adev->dev, "SMU driver if version not matched\n"); } return ret; diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c index 73762d9b5969..c3ebfac062a7 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c +++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c @@ -56,6 +56,10 @@ #define to_amdgpu_device(x) (container_of(x, struct amdgpu_device, pm.smu_i2c)) +static void smu_v14_0_2_get_od_setting_limits(struct smu_context *smu, + int od_feature_bit, + int32_t *min, int32_t *max); + static const struct smu_feature_bits smu_v14_0_2_dpm_features = { .bits = { SMU_FEATURE_BIT_INIT(FEATURE_DPM_GFXCLK_BIT), SMU_FEATURE_BIT_INIT(FEATURE_DPM_UCLK_BIT), @@ -922,8 +926,35 @@ static bool smu_v14_0_2_is_od_feature_supported(struct smu_context *smu, PPTable_t *pptable = smu->smu_table.driver_pptable; const OverDriveLimits_t * const overdrive_upperlimits = &pptable->SkuTable.OverDriveLimitsBasicMax; + int32_t min_value, max_value; + bool feature_enabled; - return overdrive_upperlimits->FeatureCtrlMask & (1U << od_feature_bit); + switch (od_feature_bit) { + case PP_OD_FEATURE_FAN_CURVE_BIT: + feature_enabled = !!(overdrive_upperlimits->FeatureCtrlMask & (1U << od_feature_bit)); + if (feature_enabled) { + smu_v14_0_2_get_od_setting_limits(smu, PP_OD_FEATURE_FAN_CURVE_TEMP, + &min_value, &max_value); + if (!min_value && !max_value) { + feature_enabled = false; + goto out; + } + + smu_v14_0_2_get_od_setting_limits(smu, PP_OD_FEATURE_FAN_CURVE_PWM, + &min_value, &max_value); + if (!min_value && !max_value) { + feature_enabled = false; + goto out; + } + } + break; + default: + feature_enabled = !!(overdrive_upperlimits->FeatureCtrlMask & (1U << od_feature_bit)); + break; + } + +out: + return feature_enabled; } static void smu_v14_0_2_get_od_setting_limits(struct smu_context *smu, diff --git a/drivers/gpu/drm/ast/ast_dp501.c b/drivers/gpu/drm/ast/ast_dp501.c index 9e19d8c17730..677c52c0d99a 100644 --- a/drivers/gpu/drm/ast/ast_dp501.c +++ b/drivers/gpu/drm/ast/ast_dp501.c @@ -436,7 +436,7 @@ static void ast_init_analog(struct ast_device *ast) /* Finally, clear bits [17:16] of SCU2c */ data = ast_read32(ast, 0x1202c); data &= 0xfffcffff; - ast_write32(ast, 0, data); + ast_write32(ast, 0x1202c, data); /* Disable DVO */ ast_set_index_reg_mask(ast, AST_IO_VGACRI, 0xa3, 0xcf, 0x00); diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c index d6f11c68bb6a..1987789b258a 100644 --- a/drivers/gpu/drm/drm_bridge.c +++ b/drivers/gpu/drm/drm_bridge.c @@ -1569,11 +1569,17 @@ EXPORT_SYMBOL(devm_drm_put_bridge); static void drm_bridge_debugfs_show_bridge(struct drm_printer *p, struct drm_bridge *bridge, unsigned int idx, - bool lingering) + bool lingering, + bool scoped) { + unsigned int refcount = kref_read(&bridge->refcount); + + if (scoped) + refcount--; + drm_printf(p, "bridge[%u]: %ps\n", idx, bridge->funcs); - drm_printf(p, "\trefcount: %u%s\n", kref_read(&bridge->refcount), + drm_printf(p, "\trefcount: %u%s\n", refcount, lingering ? " [lingering]" : ""); drm_printf(p, "\ttype: [%d] %s\n", @@ -1607,10 +1613,10 @@ static int allbridges_show(struct seq_file *m, void *data) mutex_lock(&bridge_lock); list_for_each_entry(bridge, &bridge_list, list) - drm_bridge_debugfs_show_bridge(&p, bridge, idx++, false); + drm_bridge_debugfs_show_bridge(&p, bridge, idx++, false, false); list_for_each_entry(bridge, &bridge_lingering_list, list) - drm_bridge_debugfs_show_bridge(&p, bridge, idx++, true); + drm_bridge_debugfs_show_bridge(&p, bridge, idx++, true, false); mutex_unlock(&bridge_lock); @@ -1625,7 +1631,7 @@ static int encoder_bridges_show(struct seq_file *m, void *data) unsigned int idx = 0; drm_for_each_bridge_in_chain_scoped(encoder, bridge) - drm_bridge_debugfs_show_bridge(&p, bridge, idx++, false); + drm_bridge_debugfs_show_bridge(&p, bridge, idx++, false, true); return 0; } diff --git a/drivers/gpu/drm/drm_file.c b/drivers/gpu/drm/drm_file.c index f52141f842a1..ec820686b302 100644 --- a/drivers/gpu/drm/drm_file.c +++ b/drivers/gpu/drm/drm_file.c @@ -233,7 +233,6 @@ static void drm_events_release(struct drm_file *file_priv) void drm_file_free(struct drm_file *file) { struct drm_device *dev; - int idx; if (!file) return; @@ -250,11 +249,9 @@ void drm_file_free(struct drm_file *file) drm_events_release(file); - if (drm_core_check_feature(dev, DRIVER_MODESET) && - drm_dev_enter(dev, &idx)) { + if (drm_core_check_feature(dev, DRIVER_MODESET)) { drm_fb_release(file); drm_property_destroy_user_blobs(dev, file); - drm_dev_exit(idx); } if (drm_core_check_feature(dev, DRIVER_SYNCOBJ)) diff --git a/drivers/gpu/drm/drm_gem_shmem_helper.c b/drivers/gpu/drm/drm_gem_shmem_helper.c index 7b5a49935ae4..c549293b5bb6 100644 --- a/drivers/gpu/drm/drm_gem_shmem_helper.c +++ b/drivers/gpu/drm/drm_gem_shmem_helper.c @@ -550,27 +550,27 @@ int drm_gem_shmem_dumb_create(struct drm_file *file, struct drm_device *dev, } EXPORT_SYMBOL_GPL(drm_gem_shmem_dumb_create); -static bool drm_gem_shmem_try_map_pmd(struct vm_fault *vmf, unsigned long addr, - struct page *page) +static vm_fault_t try_insert_pfn(struct vm_fault *vmf, unsigned int order, + unsigned long pfn) { + if (!order) { + return vmf_insert_pfn(vmf->vma, vmf->address, pfn); #ifdef CONFIG_ARCH_SUPPORTS_PMD_PFNMAP - unsigned long pfn = page_to_pfn(page); - unsigned long paddr = pfn << PAGE_SHIFT; - bool aligned = (addr & ~PMD_MASK) == (paddr & ~PMD_MASK); - - if (aligned && - pmd_none(*vmf->pmd) && - folio_test_pmd_mappable(page_folio(page))) { - pfn &= PMD_MASK >> PAGE_SHIFT; - if (vmf_insert_pfn_pmd(vmf, pfn, false) == VM_FAULT_NOPAGE) - return true; - } + } else if (order == PMD_ORDER) { + unsigned long paddr = pfn << PAGE_SHIFT; + bool aligned = (vmf->address & ~PMD_MASK) == (paddr & ~PMD_MASK); + + if (aligned && + folio_test_pmd_mappable(page_folio(pfn_to_page(pfn)))) { + pfn &= PMD_MASK >> PAGE_SHIFT; + return vmf_insert_pfn_pmd(vmf, pfn, false); + } #endif - - return false; + } + return VM_FAULT_FALLBACK; } -static vm_fault_t drm_gem_shmem_fault(struct vm_fault *vmf) +static vm_fault_t drm_gem_shmem_any_fault(struct vm_fault *vmf, unsigned int order) { struct vm_area_struct *vma = vmf->vma; struct drm_gem_object *obj = vma->vm_private_data; @@ -581,6 +581,9 @@ static vm_fault_t drm_gem_shmem_fault(struct vm_fault *vmf) pgoff_t page_offset; unsigned long pfn; + if (order && order != PMD_ORDER) + return VM_FAULT_FALLBACK; + /* Offset to faulty address in the VMA. */ page_offset = vmf->pgoff - vma->vm_pgoff; @@ -593,13 +596,8 @@ static vm_fault_t drm_gem_shmem_fault(struct vm_fault *vmf) goto out; } - if (drm_gem_shmem_try_map_pmd(vmf, vmf->address, pages[page_offset])) { - ret = VM_FAULT_NOPAGE; - goto out; - } - pfn = page_to_pfn(pages[page_offset]); - ret = vmf_insert_pfn(vma, vmf->address, pfn); + ret = try_insert_pfn(vmf, order, pfn); out: dma_resv_unlock(shmem->base.resv); @@ -607,6 +605,11 @@ static vm_fault_t drm_gem_shmem_fault(struct vm_fault *vmf) return ret; } +static vm_fault_t drm_gem_shmem_fault(struct vm_fault *vmf) +{ + return drm_gem_shmem_any_fault(vmf, 0); +} + static void drm_gem_shmem_vm_open(struct vm_area_struct *vma) { struct drm_gem_object *obj = vma->vm_private_data; @@ -643,6 +646,9 @@ static void drm_gem_shmem_vm_close(struct vm_area_struct *vma) const struct vm_operations_struct drm_gem_shmem_vm_ops = { .fault = drm_gem_shmem_fault, +#ifdef CONFIG_ARCH_SUPPORTS_PMD_PFNMAP + .huge_fault = drm_gem_shmem_any_fault, +#endif .open = drm_gem_shmem_vm_open, .close = drm_gem_shmem_vm_close, }; diff --git a/drivers/gpu/drm/drm_ioc32.c b/drivers/gpu/drm/drm_ioc32.c index e6b5b06de148..f3e40d1e6098 100644 --- a/drivers/gpu/drm/drm_ioc32.c +++ b/drivers/gpu/drm/drm_ioc32.c @@ -28,6 +28,7 @@ * IN THE SOFTWARE. */ #include <linux/compat.h> +#include <linux/nospec.h> #include <linux/ratelimit.h> #include <linux/export.h> @@ -374,6 +375,7 @@ long drm_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) if (nr >= ARRAY_SIZE(drm_compat_ioctls)) return drm_ioctl(filp, cmd, arg); + nr = array_index_nospec(nr, ARRAY_SIZE(drm_compat_ioctls)); fn = drm_compat_ioctls[nr].fn; if (!fn) return drm_ioctl(filp, cmd, arg); diff --git a/drivers/gpu/drm/drm_mode_config.c b/drivers/gpu/drm/drm_mode_config.c index 802bc4608abf..d12db9b0bab8 100644 --- a/drivers/gpu/drm/drm_mode_config.c +++ b/drivers/gpu/drm/drm_mode_config.c @@ -577,13 +577,10 @@ void drm_mode_config_cleanup(struct drm_device *dev) */ WARN_ON(!list_empty(&dev->mode_config.fb_list)); list_for_each_entry_safe(fb, fbt, &dev->mode_config.fb_list, head) { - if (list_empty(&fb->filp_head) || drm_framebuffer_read_refcount(fb) > 1) { - struct drm_printer p = drm_dbg_printer(dev, DRM_UT_KMS, "[leaked fb]"); + struct drm_printer p = drm_dbg_printer(dev, DRM_UT_KMS, "[leaked fb]"); - drm_printf(&p, "framebuffer[%u]:\n", fb->base.id); - drm_framebuffer_print_info(&p, 1, fb); - } - list_del_init(&fb->filp_head); + drm_printf(&p, "framebuffer[%u]:\n", fb->base.id); + drm_framebuffer_print_info(&p, 1, fb); drm_framebuffer_free(&fb->base.refcount); } diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c index 250734dee928..8d9fd1917c6e 100644 --- a/drivers/gpu/drm/drm_syncobj.c +++ b/drivers/gpu/drm/drm_syncobj.c @@ -602,7 +602,7 @@ int drm_syncobj_get_handle(struct drm_file *file_private, drm_syncobj_get(syncobj); ret = xa_alloc(&file_private->syncobj_xa, handle, syncobj, xa_limit_32b, - GFP_NOWAIT); + GFP_KERNEL); if (ret) drm_syncobj_put(syncobj); @@ -716,7 +716,7 @@ static int drm_syncobj_fd_to_handle(struct drm_file *file_private, drm_syncobj_get(syncobj); ret = xa_alloc(&file_private->syncobj_xa, handle, syncobj, xa_limit_32b, - GFP_NOWAIT); + GFP_KERNEL); if (ret) drm_syncobj_put(syncobj); diff --git a/drivers/gpu/drm/i915/display/g4x_dp.c b/drivers/gpu/drm/i915/display/g4x_dp.c index 4cb753177fd8..c7fa014e0d50 100644 --- a/drivers/gpu/drm/i915/display/g4x_dp.c +++ b/drivers/gpu/drm/i915/display/g4x_dp.c @@ -137,7 +137,7 @@ static void intel_dp_prepare(struct intel_encoder *encoder, intel_dp->DP |= DP_SYNC_VS_HIGH; intel_dp->DP |= DP_LINK_TRAIN_OFF_CPT; - if (drm_dp_enhanced_frame_cap(intel_dp->dpcd)) + if (pipe_config->enhanced_framing) intel_dp->DP |= DP_ENHANCED_FRAMING; intel_dp->DP |= DP_PIPE_SEL_IVB(crtc->pipe); diff --git a/drivers/gpu/drm/i915/display/icl_dsi.c b/drivers/gpu/drm/i915/display/icl_dsi.c index fc265f71d72b..298b3a48197c 100644 --- a/drivers/gpu/drm/i915/display/icl_dsi.c +++ b/drivers/gpu/drm/i915/display/icl_dsi.c @@ -889,7 +889,7 @@ gen11_dsi_set_transcoder_timings(struct intel_encoder *encoder, * non-compressed link speeds, and simplifies down to the ratio between * compressed and non-compressed bpp. */ - if (crtc_state->dsc.compression_enable) { + if (is_vid_mode(intel_dsi) && crtc_state->dsc.compression_enable) { mul = fxp_q4_to_int(crtc_state->dsc.compressed_bpp_x16); div = mipi_dsi_pixel_format_to_bpp(intel_dsi->pixel_format); } @@ -1503,7 +1503,7 @@ static void gen11_dsi_get_timings(struct intel_encoder *encoder, struct drm_display_mode *adjusted_mode = &pipe_config->hw.adjusted_mode; - if (pipe_config->dsc.compressed_bpp_x16) { + if (is_vid_mode(intel_dsi) && pipe_config->dsc.compressed_bpp_x16) { int div = fxp_q4_to_int(pipe_config->dsc.compressed_bpp_x16); int mul = mipi_dsi_pixel_format_to_bpp(intel_dsi->pixel_format); diff --git a/drivers/gpu/drm/i915/display/intel_cdclk.c b/drivers/gpu/drm/i915/display/intel_cdclk.c index f5946e677c93..3d7b4b0795cd 100644 --- a/drivers/gpu/drm/i915/display/intel_cdclk.c +++ b/drivers/gpu/drm/i915/display/intel_cdclk.c @@ -2971,6 +2971,53 @@ static int intel_cdclk_update_crtc_min_cdclk(struct intel_atomic_state *state, return 0; } +static int intel_cdclk_update_crtc_min_voltage_level(struct intel_atomic_state *state, + struct intel_crtc *crtc, + u8 old_min_voltage_level, + u8 new_min_voltage_level, + bool *need_cdclk_calc) +{ + struct intel_display *display = to_intel_display(state); + struct intel_cdclk_state *cdclk_state; + bool allow_voltage_level_decrease = intel_any_crtc_needs_modeset(state); + int ret; + + if (new_min_voltage_level == old_min_voltage_level) + return 0; + + if (!allow_voltage_level_decrease && + new_min_voltage_level < old_min_voltage_level) + return 0; + + cdclk_state = intel_atomic_get_cdclk_state(state); + if (IS_ERR(cdclk_state)) + return PTR_ERR(cdclk_state); + + old_min_voltage_level = cdclk_state->min_voltage_level[crtc->pipe]; + + if (new_min_voltage_level == old_min_voltage_level) + return 0; + + if (!allow_voltage_level_decrease && + new_min_voltage_level < old_min_voltage_level) + return 0; + + cdclk_state->min_voltage_level[crtc->pipe] = new_min_voltage_level; + + ret = intel_atomic_lock_global_state(&cdclk_state->base); + if (ret) + return ret; + + *need_cdclk_calc = true; + + drm_dbg_kms(display->drm, + "[CRTC:%d:%s] min voltage level: %d -> %d\n", + crtc->base.base.id, crtc->base.name, + old_min_voltage_level, new_min_voltage_level); + + return 0; +} + int intel_cdclk_update_dbuf_bw_min_cdclk(struct intel_atomic_state *state, int old_min_cdclk, int new_min_cdclk, bool *need_cdclk_calc) @@ -3386,6 +3433,13 @@ static int intel_crtcs_calc_min_cdclk(struct intel_atomic_state *state, need_cdclk_calc); if (ret) return ret; + + ret = intel_cdclk_update_crtc_min_voltage_level(state, crtc, + old_crtc_state->min_voltage_level, + new_crtc_state->min_voltage_level, + need_cdclk_calc); + if (ret) + return ret; } return 0; diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index c4246481fc2f..0f82bf771a92 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -4602,6 +4602,7 @@ intel_crtc_prepare_cleared_state(struct intel_atomic_state *state, struct intel_crtc_state *crtc_state = intel_atomic_get_new_crtc_state(state, crtc); struct intel_crtc_state *saved_state; + int err; saved_state = intel_crtc_state_alloc(crtc); if (!saved_state) @@ -4610,7 +4611,12 @@ intel_crtc_prepare_cleared_state(struct intel_atomic_state *state, /* free the old crtc_state->hw members */ intel_crtc_free_hw_state(crtc_state); - intel_dp_tunnel_atomic_clear_stream_bw(state, crtc_state); + err = intel_dp_tunnel_atomic_clear_stream_bw(state, crtc_state); + if (err) { + kfree(saved_state); + + return err; + } /* FIXME: before the switch to atomic started, a new pipe_config was * kzalloc'd. Code that depends on any field being zero should be diff --git a/drivers/gpu/drm/i915/display/intel_dp_tunnel.c b/drivers/gpu/drm/i915/display/intel_dp_tunnel.c index 83865c02d477..55b423fd6b6f 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_tunnel.c +++ b/drivers/gpu/drm/i915/display/intel_dp_tunnel.c @@ -621,19 +621,27 @@ int intel_dp_tunnel_atomic_compute_stream_bw(struct intel_atomic_state *state, * * Clear any DP tunnel stream BW requirement set by * intel_dp_tunnel_atomic_compute_stream_bw(). + * + * Returns 0 in case of success, a negative error code otherwise. */ -void intel_dp_tunnel_atomic_clear_stream_bw(struct intel_atomic_state *state, - struct intel_crtc_state *crtc_state) +int intel_dp_tunnel_atomic_clear_stream_bw(struct intel_atomic_state *state, + struct intel_crtc_state *crtc_state) { struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); + int err; if (!crtc_state->dp_tunnel_ref.tunnel) - return; + return 0; + + err = drm_dp_tunnel_atomic_set_stream_bw(&state->base, + crtc_state->dp_tunnel_ref.tunnel, + crtc->pipe, 0); + if (err) + return err; - drm_dp_tunnel_atomic_set_stream_bw(&state->base, - crtc_state->dp_tunnel_ref.tunnel, - crtc->pipe, 0); drm_dp_tunnel_ref_put(&crtc_state->dp_tunnel_ref); + + return 0; } /** diff --git a/drivers/gpu/drm/i915/display/intel_dp_tunnel.h b/drivers/gpu/drm/i915/display/intel_dp_tunnel.h index 7f0f720e8dca..10ab9eebcef6 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_tunnel.h +++ b/drivers/gpu/drm/i915/display/intel_dp_tunnel.h @@ -40,8 +40,8 @@ int intel_dp_tunnel_atomic_compute_stream_bw(struct intel_atomic_state *state, struct intel_dp *intel_dp, const struct intel_connector *connector, struct intel_crtc_state *crtc_state); -void intel_dp_tunnel_atomic_clear_stream_bw(struct intel_atomic_state *state, - struct intel_crtc_state *crtc_state); +int intel_dp_tunnel_atomic_clear_stream_bw(struct intel_atomic_state *state, + struct intel_crtc_state *crtc_state); int intel_dp_tunnel_atomic_add_state_for_crtc(struct intel_atomic_state *state, struct intel_crtc *crtc); @@ -88,9 +88,12 @@ intel_dp_tunnel_atomic_compute_stream_bw(struct intel_atomic_state *state, return 0; } -static inline void +static inline int intel_dp_tunnel_atomic_clear_stream_bw(struct intel_atomic_state *state, - struct intel_crtc_state *crtc_state) {} + struct intel_crtc_state *crtc_state) +{ + return 0; +} static inline int intel_dp_tunnel_atomic_add_state_for_crtc(struct intel_atomic_state *state, diff --git a/drivers/gpu/drm/i915/display/intel_gmbus.c b/drivers/gpu/drm/i915/display/intel_gmbus.c index a7bce0c6a17e..264e6843bff1 100644 --- a/drivers/gpu/drm/i915/display/intel_gmbus.c +++ b/drivers/gpu/drm/i915/display/intel_gmbus.c @@ -496,8 +496,10 @@ gmbus_xfer_read_chunk(struct intel_display *display, val = intel_de_read_fw(display, GMBUS3(display)); do { - if (extra_byte_added && len == 1) + if (extra_byte_added && len == 1) { + len--; break; + } *buf++ = val & 0xff; val >>= 8; diff --git a/drivers/gpu/drm/i915/display/intel_plane.c b/drivers/gpu/drm/i915/display/intel_plane.c index e06a0618b4c6..076b9b356481 100644 --- a/drivers/gpu/drm/i915/display/intel_plane.c +++ b/drivers/gpu/drm/i915/display/intel_plane.c @@ -436,11 +436,16 @@ void intel_plane_copy_hw_state(struct intel_plane_state *plane_state, drm_framebuffer_get(plane_state->hw.fb); } +static void unlink_nv12_plane(struct intel_crtc_state *crtc_state, + struct intel_plane_state *plane_state); + void intel_plane_set_invisible(struct intel_crtc_state *crtc_state, struct intel_plane_state *plane_state) { struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane); + unlink_nv12_plane(crtc_state, plane_state); + crtc_state->active_planes &= ~BIT(plane->id); crtc_state->scaled_planes &= ~BIT(plane->id); crtc_state->nv12_planes &= ~BIT(plane->id); @@ -1513,6 +1518,9 @@ static void unlink_nv12_plane(struct intel_crtc_state *crtc_state, struct intel_display *display = to_intel_display(plane_state); struct intel_plane *plane = to_intel_plane(plane_state->uapi.plane); + if (!plane_state->planar_linked_plane) + return; + plane_state->planar_linked_plane = NULL; if (!plane_state->is_y_plane) @@ -1550,8 +1558,7 @@ static int icl_check_nv12_planes(struct intel_atomic_state *state, if (plane->pipe != crtc->pipe) continue; - if (plane_state->planar_linked_plane) - unlink_nv12_plane(crtc_state, plane_state); + unlink_nv12_plane(crtc_state, plane_state); } if (!crtc_state->nv12_planes) diff --git a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c index e7918f896a26..942f4eed817f 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c @@ -898,6 +898,8 @@ static struct i915_vma *eb_lookup_vma(struct i915_execbuffer *eb, u32 handle) vma = radix_tree_lookup(&eb->gem_context->handles_vma, handle); if (likely(vma && vma->vm == vm)) vma = i915_vma_tryget(vma); + else + vma = NULL; rcu_read_unlock(); if (likely(vma)) return vma; diff --git a/drivers/gpu/drm/i915/i915_wait_util.h b/drivers/gpu/drm/i915/i915_wait_util.h index 7376898e3bf8..e1ed7921ec70 100644 --- a/drivers/gpu/drm/i915/i915_wait_util.h +++ b/drivers/gpu/drm/i915/i915_wait_util.h @@ -25,9 +25,9 @@ might_sleep(); \ for (;;) { \ const bool expired__ = ktime_after(ktime_get_raw(), end__); \ - OP; \ /* Guarantee COND check prior to timeout */ \ barrier(); \ + OP; \ if (COND) { \ ret__ = 0; \ break; \ diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c index 17c67f02016b..aaf6c9ebd319 100644 --- a/drivers/gpu/drm/mediatek/mtk_dsi.c +++ b/drivers/gpu/drm/mediatek/mtk_dsi.c @@ -1236,6 +1236,11 @@ static int mtk_dsi_probe(struct platform_device *pdev) dsi->host.ops = &mtk_dsi_ops; dsi->host.dev = dev; + + init_waitqueue_head(&dsi->irq_wait_queue); + + platform_set_drvdata(pdev, dsi); + ret = mipi_dsi_host_register(&dsi->host); if (ret < 0) return dev_err_probe(dev, ret, "Failed to register DSI host\n"); @@ -1247,10 +1252,6 @@ static int mtk_dsi_probe(struct platform_device *pdev) return dev_err_probe(&pdev->dev, ret, "Failed to request DSI irq\n"); } - init_waitqueue_head(&dsi->irq_wait_queue); - - platform_set_drvdata(pdev, dsi); - dsi->bridge.of_node = dev->of_node; dsi->bridge.type = DRM_MODE_CONNECTOR_DSI; diff --git a/drivers/gpu/drm/sysfb/efidrm.c b/drivers/gpu/drm/sysfb/efidrm.c index 50e0aeef709c..9d84caf69627 100644 --- a/drivers/gpu/drm/sysfb/efidrm.c +++ b/drivers/gpu/drm/sysfb/efidrm.c @@ -151,7 +151,6 @@ static struct efidrm_device *efidrm_device_create(struct drm_driver *drv, struct drm_sysfb_device *sysfb; struct drm_device *dev; struct resource *mem = NULL; - void __iomem *screen_base = NULL; struct drm_plane *primary_plane; struct drm_crtc *crtc; struct drm_encoder *encoder; @@ -238,21 +237,38 @@ static struct efidrm_device *efidrm_device_create(struct drm_driver *drv, mem_flags = efidrm_get_mem_flags(dev, res->start, vsize); - if (mem_flags & EFI_MEMORY_WC) - screen_base = devm_ioremap_wc(&pdev->dev, mem->start, resource_size(mem)); - else if (mem_flags & EFI_MEMORY_UC) - screen_base = devm_ioremap(&pdev->dev, mem->start, resource_size(mem)); - else if (mem_flags & EFI_MEMORY_WT) - screen_base = devm_memremap(&pdev->dev, mem->start, resource_size(mem), - MEMREMAP_WT); - else if (mem_flags & EFI_MEMORY_WB) - screen_base = devm_memremap(&pdev->dev, mem->start, resource_size(mem), - MEMREMAP_WB); - else + if (mem_flags & EFI_MEMORY_WC) { + void __iomem *screen_base = devm_ioremap_wc(&pdev->dev, mem->start, + resource_size(mem)); + + if (!screen_base) + return ERR_PTR(-ENXIO); + iosys_map_set_vaddr_iomem(&sysfb->fb_addr, screen_base); + } else if (mem_flags & EFI_MEMORY_UC) { + void __iomem *screen_base = devm_ioremap(&pdev->dev, mem->start, + resource_size(mem)); + + if (!screen_base) + return ERR_PTR(-ENXIO); + iosys_map_set_vaddr_iomem(&sysfb->fb_addr, screen_base); + } else if (mem_flags & EFI_MEMORY_WT) { + void *screen_base = devm_memremap(&pdev->dev, mem->start, + resource_size(mem), MEMREMAP_WT); + + if (IS_ERR(screen_base)) + return ERR_CAST(screen_base); + iosys_map_set_vaddr(&sysfb->fb_addr, screen_base); + } else if (mem_flags & EFI_MEMORY_WB) { + void *screen_base = devm_memremap(&pdev->dev, mem->start, + resource_size(mem), MEMREMAP_WB); + + if (IS_ERR(screen_base)) + return ERR_CAST(screen_base); + iosys_map_set_vaddr(&sysfb->fb_addr, screen_base); + } else { drm_err(dev, "invalid mem_flags: 0x%llx\n", mem_flags); - if (!screen_base) - return ERR_PTR(-ENOMEM); - iosys_map_set_vaddr_iomem(&sysfb->fb_addr, screen_base); + return ERR_PTR(-EINVAL); + } /* * Modesetting diff --git a/drivers/gpu/drm/xe/regs/xe_gt_regs.h b/drivers/gpu/drm/xe/regs/xe_gt_regs.h index 24fc64fc832e..9d66f168ab8a 100644 --- a/drivers/gpu/drm/xe/regs/xe_gt_regs.h +++ b/drivers/gpu/drm/xe/regs/xe_gt_regs.h @@ -553,6 +553,7 @@ #define ENABLE_SMP_LD_RENDER_SURFACE_CONTROL REG_BIT(44 - 32) #define FORCE_SLM_FENCE_SCOPE_TO_TILE REG_BIT(42 - 32) #define FORCE_UGM_FENCE_SCOPE_TO_TILE REG_BIT(41 - 32) +#define L3_128B_256B_WRT_DIS REG_BIT(40 - 32) #define MAXREQS_PER_BANK REG_GENMASK(39 - 32, 37 - 32) #define DISABLE_128B_EVICTION_COMMAND_UDW REG_BIT(36 - 32) diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c index 52ee24e9cd3a..3eb06b27db7e 100644 --- a/drivers/gpu/drm/xe/xe_device.c +++ b/drivers/gpu/drm/xe/xe_device.c @@ -837,6 +837,14 @@ static void detect_preproduction_hw(struct xe_device *xe) } } +static void xe_device_wedged_fini(struct drm_device *drm, void *arg) +{ + struct xe_device *xe = arg; + + if (atomic_read(&xe->wedged.flag)) + xe_pm_runtime_put(xe); +} + int xe_device_probe(struct xe_device *xe) { struct xe_tile *tile; @@ -1013,6 +1021,10 @@ int xe_device_probe(struct xe_device *xe) detect_preproduction_hw(xe); + err = drmm_add_action_or_reset(&xe->drm, xe_device_wedged_fini, xe); + if (err) + goto err_unregister_display; + return devm_add_action_or_reset(xe->drm.dev, xe_device_sanitize, xe); err_unregister_display: @@ -1216,13 +1228,6 @@ u64 xe_device_uncanonicalize_addr(struct xe_device *xe, u64 address) return address & GENMASK_ULL(xe->info.va_bits - 1, 0); } -static void xe_device_wedged_fini(struct drm_device *drm, void *arg) -{ - struct xe_device *xe = arg; - - xe_pm_runtime_put(xe); -} - /** * DOC: Xe Device Wedging * @@ -1300,15 +1305,9 @@ void xe_device_declare_wedged(struct xe_device *xe) return; } - xe_pm_runtime_get_noresume(xe); - - if (drmm_add_action_or_reset(&xe->drm, xe_device_wedged_fini, xe)) { - drm_err(&xe->drm, "Failed to register xe_device_wedged_fini clean-up. Although device is wedged.\n"); - return; - } - if (!atomic_xchg(&xe->wedged.flag, 1)) { xe->needs_flr_on_fini = true; + xe_pm_runtime_get_noresume(xe); drm_err(&xe->drm, "CRITICAL: Xe has declared device %s as wedged.\n" "IOCTLs and executions are blocked. Only a rebind may clear the failure\n" diff --git a/drivers/gpu/drm/xe/xe_pagefault.c b/drivers/gpu/drm/xe/xe_pagefault.c index 6bee53d6ffc3..922a4f3344b1 100644 --- a/drivers/gpu/drm/xe/xe_pagefault.c +++ b/drivers/gpu/drm/xe/xe_pagefault.c @@ -187,6 +187,12 @@ static int xe_pagefault_service(struct xe_pagefault *pf) goto unlock_vm; } + if (xe_vma_read_only(vma) && + pf->consumer.access_type != XE_PAGEFAULT_ACCESS_TYPE_READ) { + err = -EPERM; + goto unlock_vm; + } + atomic = xe_pagefault_access_is_atomic(pf->consumer.access_type); if (xe_vma_is_cpu_addr_mirror(vma)) diff --git a/drivers/gpu/drm/xe/xe_pt.c b/drivers/gpu/drm/xe/xe_pt.c index 2d9ce2c4cb4f..713a303c9053 100644 --- a/drivers/gpu/drm/xe/xe_pt.c +++ b/drivers/gpu/drm/xe/xe_pt.c @@ -1442,9 +1442,9 @@ static int op_check_svm_userptr(struct xe_vm *vm, struct xe_vma_op *op, err = vma_check_userptr(vm, op->map.vma, pt_update); break; case DRM_GPUVA_OP_REMAP: - if (op->remap.prev) + if (op->remap.prev && !op->remap.skip_prev) err = vma_check_userptr(vm, op->remap.prev, pt_update); - if (!err && op->remap.next) + if (!err && op->remap.next && !op->remap.skip_next) err = vma_check_userptr(vm, op->remap.next, pt_update); break; case DRM_GPUVA_OP_UNMAP: @@ -2198,12 +2198,12 @@ static int op_prepare(struct xe_vm *vm, err = unbind_op_prepare(tile, pt_update_ops, old); - if (!err && op->remap.prev) { + if (!err && op->remap.prev && !op->remap.skip_prev) { err = bind_op_prepare(vm, tile, pt_update_ops, op->remap.prev, false); pt_update_ops->wait_vm_bookkeep = true; } - if (!err && op->remap.next) { + if (!err && op->remap.next && !op->remap.skip_next) { err = bind_op_prepare(vm, tile, pt_update_ops, op->remap.next, false); pt_update_ops->wait_vm_bookkeep = true; @@ -2428,10 +2428,10 @@ static void op_commit(struct xe_vm *vm, unbind_op_commit(vm, tile, pt_update_ops, old, fence, fence2); - if (op->remap.prev) + if (op->remap.prev && !op->remap.skip_prev) bind_op_commit(vm, tile, pt_update_ops, op->remap.prev, fence, fence2, false); - if (op->remap.next) + if (op->remap.next && !op->remap.skip_next) bind_op_commit(vm, tile, pt_update_ops, op->remap.next, fence, fence2, false); break; diff --git a/drivers/gpu/drm/xe/xe_pxp.c b/drivers/gpu/drm/xe/xe_pxp.c index d61446bf9c19..872217f30375 100644 --- a/drivers/gpu/drm/xe/xe_pxp.c +++ b/drivers/gpu/drm/xe/xe_pxp.c @@ -380,6 +380,18 @@ int xe_pxp_init(struct xe_device *xe) return 0; } + /* + * On PTL, older GSC FWs have a bug that can cause them to crash during + * PXP invalidation events, which leads to a complete loss of power + * management on the media GT. Therefore, we can't use PXP on FWs that + * have this bug, which was fixed in PTL GSC build 1396. + */ + if (xe->info.platform == XE_PANTHERLAKE && + gt->uc.gsc.fw.versions.found[XE_UC_FW_VER_RELEASE].build < 1396) { + drm_info(&xe->drm, "PXP requires PTL GSC build 1396 or newer\n"); + return 0; + } + pxp = drmm_kzalloc(&xe->drm, sizeof(struct xe_pxp), GFP_KERNEL); if (!pxp) { err = -ENOMEM; @@ -512,7 +524,7 @@ static int __exec_queue_add(struct xe_pxp *pxp, struct xe_exec_queue *q) static int pxp_start(struct xe_pxp *pxp, u8 type) { int ret = 0; - bool restart = false; + bool restart; if (!xe_pxp_is_enabled(pxp)) return -ENODEV; @@ -541,6 +553,8 @@ wait_for_idle: msecs_to_jiffies(PXP_ACTIVATION_TIMEOUT_MS))) return -ETIMEDOUT; + restart = false; + mutex_lock(&pxp->mutex); /* If PXP is not already active, turn it on */ @@ -583,6 +597,7 @@ wait_for_idle: drm_err(&pxp->xe->drm, "PXP termination failed before start\n"); mutex_lock(&pxp->mutex); pxp->status = XE_PXP_ERROR; + complete_all(&pxp->termination); goto out_unlock; } @@ -870,11 +885,6 @@ wait_for_activation: pxp->key_instance++; needs_queue_inval = true; break; - default: - drm_err(&pxp->xe->drm, "unexpected state during PXP suspend: %u", - pxp->status); - ret = -EIO; - goto out; } /* @@ -899,7 +909,6 @@ wait_for_activation: pxp->last_suspend_key_instance = pxp->key_instance; -out: return ret; } diff --git a/drivers/gpu/drm/xe/xe_sriov_packet.c b/drivers/gpu/drm/xe/xe_sriov_packet.c index 968f32496282..2ae9eff2a7c0 100644 --- a/drivers/gpu/drm/xe/xe_sriov_packet.c +++ b/drivers/gpu/drm/xe/xe_sriov_packet.c @@ -341,6 +341,8 @@ ssize_t xe_sriov_packet_write_single(struct xe_device *xe, unsigned int vfid, ret = xe_sriov_pf_migration_restore_produce(xe, vfid, *data); if (ret) { xe_sriov_packet_free(*data); + *data = NULL; + return ret; } diff --git a/drivers/gpu/drm/xe/xe_svm.c b/drivers/gpu/drm/xe/xe_svm.c index ca67d0bdbfac..c6b92d4ea6f4 100644 --- a/drivers/gpu/drm/xe/xe_svm.c +++ b/drivers/gpu/drm/xe/xe_svm.c @@ -903,7 +903,7 @@ int xe_svm_init(struct xe_vm *vm) void xe_svm_close(struct xe_vm *vm) { xe_assert(vm->xe, xe_vm_is_closed(vm)); - flush_work(&vm->svm.garbage_collector.work); + disable_work_sync(&vm->svm.garbage_collector.work); xe_svm_put_pagemaps(vm); drm_pagemap_release_owner(&vm->svm.peer); } diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c index a82e3a4fb389..ffdbab106a58 100644 --- a/drivers/gpu/drm/xe/xe_vm.c +++ b/drivers/gpu/drm/xe/xe_vm.c @@ -2554,7 +2554,6 @@ static int xe_vma_op_commit(struct xe_vm *vm, struct xe_vma_op *op) if (!err && op->remap.skip_prev) { op->remap.prev->tile_present = tile_present; - op->remap.prev = NULL; } } if (op->remap.next) { @@ -2564,11 +2563,13 @@ static int xe_vma_op_commit(struct xe_vm *vm, struct xe_vma_op *op) if (!err && op->remap.skip_next) { op->remap.next->tile_present = tile_present; - op->remap.next = NULL; } } - /* Adjust for partial unbind after removing VMA from VM */ + /* + * Adjust for partial unbind after removing VMA from VM. In case + * of unwind we might need to undo this later. + */ if (!err) { op->base.remap.unmap->va->va.addr = op->remap.start; op->base.remap.unmap->va->va.range = op->remap.range; @@ -2687,6 +2688,8 @@ static int vm_bind_ioctl_ops_parse(struct xe_vm *vm, struct drm_gpuva_ops *ops, op->remap.start = xe_vma_start(old); op->remap.range = xe_vma_size(old); + op->remap.old_start = op->remap.start; + op->remap.old_range = op->remap.range; flags |= op->base.remap.unmap->va->flags & XE_VMA_CREATE_MASK; if (op->base.remap.prev) { @@ -2835,8 +2838,19 @@ static void xe_vma_op_unwind(struct xe_vm *vm, struct xe_vma_op *op, xe_svm_notifier_lock(vm); vma->gpuva.flags &= ~XE_VMA_DESTROYED; xe_svm_notifier_unlock(vm); - if (post_commit) + if (post_commit) { + /* + * Restore the old va range, in case of the + * prev/next skip optimisation. Otherwise what + * we re-insert here could be smaller than the + * original range. + */ + op->base.remap.unmap->va->va.addr = + op->remap.old_start; + op->base.remap.unmap->va->va.range = + op->remap.old_range; xe_vm_insert_vma(vm, vma); + } } break; } diff --git a/drivers/gpu/drm/xe/xe_vm_madvise.c b/drivers/gpu/drm/xe/xe_vm_madvise.c index bc39a9a9790c..b4086129a364 100644 --- a/drivers/gpu/drm/xe/xe_vm_madvise.c +++ b/drivers/gpu/drm/xe/xe_vm_madvise.c @@ -408,8 +408,15 @@ int xe_vm_madvise_ioctl(struct drm_device *dev, void *data, struct drm_file *fil struct xe_device *xe = to_xe_device(dev); struct xe_file *xef = to_xe_file(file); struct drm_xe_madvise *args = data; - struct xe_vmas_in_madvise_range madvise_range = {.addr = args->start, - .range = args->range, }; + struct xe_vmas_in_madvise_range madvise_range = { + /* + * Userspace may pass canonical (sign-extended) addresses. + * Strip the sign extension to get the internal non-canonical + * form used by the GPUVM, matching xe_vm_bind_ioctl() behavior. + */ + .addr = xe_device_uncanonicalize_addr(xe, args->start), + .range = args->range, + }; struct xe_madvise_details details; struct xe_vm *vm; struct drm_exec exec; @@ -439,7 +446,7 @@ int xe_vm_madvise_ioctl(struct drm_device *dev, void *data, struct drm_file *fil if (err) goto unlock_vm; - err = xe_vm_alloc_madvise_vma(vm, args->start, args->range); + err = xe_vm_alloc_madvise_vma(vm, madvise_range.addr, args->range); if (err) goto madv_fini; @@ -482,7 +489,8 @@ int xe_vm_madvise_ioctl(struct drm_device *dev, void *data, struct drm_file *fil madvise_funcs[attr_type](xe, vm, madvise_range.vmas, madvise_range.num_vmas, args, &details); - err = xe_vm_invalidate_madvise_range(vm, args->start, args->start + args->range); + err = xe_vm_invalidate_madvise_range(vm, madvise_range.addr, + madvise_range.addr + args->range); if (madvise_range.has_svm_userptr_vmas) xe_svm_notifier_unlock(vm); diff --git a/drivers/gpu/drm/xe/xe_vm_types.h b/drivers/gpu/drm/xe/xe_vm_types.h index 437f64202f3b..e2946e311d7a 100644 --- a/drivers/gpu/drm/xe/xe_vm_types.h +++ b/drivers/gpu/drm/xe/xe_vm_types.h @@ -373,6 +373,10 @@ struct xe_vma_op_remap { u64 start; /** @range: range of the VMA unmap */ u64 range; + /** @old_start: Original start of the VMA we unmap */ + u64 old_start; + /** @old_range: Original range of the VMA we unmap */ + u64 old_range; /** @skip_prev: skip prev rebind */ bool skip_prev; /** @skip_next: skip next rebind */ diff --git a/drivers/gpu/drm/xe/xe_wa.c b/drivers/gpu/drm/xe/xe_wa.c index 462c2fa712e0..d7e309ad9aba 100644 --- a/drivers/gpu/drm/xe/xe_wa.c +++ b/drivers/gpu/drm/xe/xe_wa.c @@ -247,7 +247,8 @@ static const struct xe_rtp_entry_sr gt_was[] = { LSN_DIM_Z_WGT_MASK, LSN_LNI_WGT(1) | LSN_LNE_WGT(1) | LSN_DIM_X_WGT(1) | LSN_DIM_Y_WGT(1) | - LSN_DIM_Z_WGT(1))) + LSN_DIM_Z_WGT(1)), + SET(LSC_CHICKEN_BIT_0_UDW, L3_128B_256B_WRT_DIS)) }, /* Xe2_HPM */ diff --git a/drivers/hwmon/adm1177.c b/drivers/hwmon/adm1177.c index 8b2c965480e3..7888afe8dafd 100644 --- a/drivers/hwmon/adm1177.c +++ b/drivers/hwmon/adm1177.c @@ -10,6 +10,8 @@ #include <linux/hwmon.h> #include <linux/i2c.h> #include <linux/init.h> +#include <linux/math64.h> +#include <linux/minmax.h> #include <linux/module.h> #include <linux/regulator/consumer.h> @@ -33,7 +35,7 @@ struct adm1177_state { struct i2c_client *client; u32 r_sense_uohm; - u32 alert_threshold_ua; + u64 alert_threshold_ua; bool vrange_high; }; @@ -48,7 +50,7 @@ static int adm1177_write_cmd(struct adm1177_state *st, u8 cmd) } static int adm1177_write_alert_thr(struct adm1177_state *st, - u32 alert_threshold_ua) + u64 alert_threshold_ua) { u64 val; int ret; @@ -91,8 +93,8 @@ static int adm1177_read(struct device *dev, enum hwmon_sensor_types type, *val = div_u64((105840000ull * dummy), 4096 * st->r_sense_uohm); return 0; - case hwmon_curr_max_alarm: - *val = st->alert_threshold_ua; + case hwmon_curr_max: + *val = div_u64(st->alert_threshold_ua, 1000); return 0; default: return -EOPNOTSUPP; @@ -126,9 +128,10 @@ static int adm1177_write(struct device *dev, enum hwmon_sensor_types type, switch (type) { case hwmon_curr: switch (attr) { - case hwmon_curr_max_alarm: - adm1177_write_alert_thr(st, val); - return 0; + case hwmon_curr_max: + val = clamp_val(val, 0, + div_u64(105840000ULL, st->r_sense_uohm)); + return adm1177_write_alert_thr(st, (u64)val * 1000); default: return -EOPNOTSUPP; } @@ -156,7 +159,7 @@ static umode_t adm1177_is_visible(const void *data, if (st->r_sense_uohm) return 0444; return 0; - case hwmon_curr_max_alarm: + case hwmon_curr_max: if (st->r_sense_uohm) return 0644; return 0; @@ -170,7 +173,7 @@ static umode_t adm1177_is_visible(const void *data, static const struct hwmon_channel_info * const adm1177_info[] = { HWMON_CHANNEL_INFO(curr, - HWMON_C_INPUT | HWMON_C_MAX_ALARM), + HWMON_C_INPUT | HWMON_C_MAX), HWMON_CHANNEL_INFO(in, HWMON_I_INPUT), NULL @@ -192,7 +195,8 @@ static int adm1177_probe(struct i2c_client *client) struct device *dev = &client->dev; struct device *hwmon_dev; struct adm1177_state *st; - u32 alert_threshold_ua; + u64 alert_threshold_ua; + u32 prop; int ret; st = devm_kzalloc(dev, sizeof(*st), GFP_KERNEL); @@ -208,22 +212,26 @@ static int adm1177_probe(struct i2c_client *client) if (device_property_read_u32(dev, "shunt-resistor-micro-ohms", &st->r_sense_uohm)) st->r_sense_uohm = 0; - if (device_property_read_u32(dev, "adi,shutdown-threshold-microamp", - &alert_threshold_ua)) { - if (st->r_sense_uohm) - /* - * set maximum default value from datasheet based on - * shunt-resistor - */ - alert_threshold_ua = div_u64(105840000000, - st->r_sense_uohm); - else - alert_threshold_ua = 0; + if (!device_property_read_u32(dev, "adi,shutdown-threshold-microamp", + &prop)) { + alert_threshold_ua = prop; + } else if (st->r_sense_uohm) { + /* + * set maximum default value from datasheet based on + * shunt-resistor + */ + alert_threshold_ua = div_u64(105840000000ULL, + st->r_sense_uohm); + } else { + alert_threshold_ua = 0; } st->vrange_high = device_property_read_bool(dev, "adi,vrange-high-enable"); - if (alert_threshold_ua && st->r_sense_uohm) - adm1177_write_alert_thr(st, alert_threshold_ua); + if (alert_threshold_ua && st->r_sense_uohm) { + ret = adm1177_write_alert_thr(st, alert_threshold_ua); + if (ret) + return ret; + } ret = adm1177_write_cmd(st, ADM1177_CMD_V_CONT | ADM1177_CMD_I_CONT | diff --git a/drivers/hwmon/asus-ec-sensors.c b/drivers/hwmon/asus-ec-sensors.c index 86f444498650..adedaf0db10e 100644 --- a/drivers/hwmon/asus-ec-sensors.c +++ b/drivers/hwmon/asus-ec-sensors.c @@ -111,6 +111,8 @@ enum ec_sensors { ec_sensor_temp_mb, /* "T_Sensor" temperature sensor reading [℃] */ ec_sensor_temp_t_sensor, + /* like ec_sensor_temp_t_sensor, but at an alternate address [℃] */ + ec_sensor_temp_t_sensor_alt1, /* VRM temperature [℃] */ ec_sensor_temp_vrm, /* VRM east (right) temperature [℃] */ @@ -160,6 +162,7 @@ enum ec_sensors { #define SENSOR_TEMP_CPU_PACKAGE BIT(ec_sensor_temp_cpu_package) #define SENSOR_TEMP_MB BIT(ec_sensor_temp_mb) #define SENSOR_TEMP_T_SENSOR BIT(ec_sensor_temp_t_sensor) +#define SENSOR_TEMP_T_SENSOR_ALT1 BIT(ec_sensor_temp_t_sensor_alt1) #define SENSOR_TEMP_VRM BIT(ec_sensor_temp_vrm) #define SENSOR_TEMP_VRME BIT(ec_sensor_temp_vrme) #define SENSOR_TEMP_VRMW BIT(ec_sensor_temp_vrmw) @@ -279,6 +282,8 @@ static const struct ec_sensor_info sensors_family_amd_600[] = { EC_SENSOR("VRM", hwmon_temp, 1, 0x00, 0x33), [ec_sensor_temp_t_sensor] = EC_SENSOR("T_Sensor", hwmon_temp, 1, 0x00, 0x36), + [ec_sensor_temp_t_sensor_alt1] = + EC_SENSOR("T_Sensor", hwmon_temp, 1, 0x00, 0x37), [ec_sensor_fan_cpu_opt] = EC_SENSOR("CPU_Opt", hwmon_fan, 2, 0x00, 0xb0), [ec_sensor_temp_water_in] = @@ -519,7 +524,7 @@ static const struct ec_board_info board_info_prime_x570_pro = { static const struct ec_board_info board_info_prime_x670e_pro_wifi = { .sensors = SENSOR_TEMP_CPU | SENSOR_TEMP_CPU_PACKAGE | SENSOR_TEMP_MB | SENSOR_TEMP_VRM | - SENSOR_TEMP_T_SENSOR | SENSOR_FAN_CPU_OPT, + SENSOR_TEMP_T_SENSOR_ALT1 | SENSOR_FAN_CPU_OPT, .mutex_path = ACPI_GLOBAL_LOCK_PSEUDO_PATH, .family = family_amd_600_series, }; diff --git a/drivers/hwmon/occ/common.c b/drivers/hwmon/occ/common.c index 89928d38831b..42cc6068bb08 100644 --- a/drivers/hwmon/occ/common.c +++ b/drivers/hwmon/occ/common.c @@ -420,6 +420,12 @@ static ssize_t occ_show_freq_2(struct device *dev, return sysfs_emit(buf, "%u\n", val); } +static u64 occ_get_powr_avg(u64 accum, u32 samples) +{ + return (samples == 0) ? 0 : + mul_u64_u32_div(accum, 1000000UL, samples); +} + static ssize_t occ_show_power_1(struct device *dev, struct device_attribute *attr, char *buf) { @@ -441,9 +447,8 @@ static ssize_t occ_show_power_1(struct device *dev, val = get_unaligned_be16(&power->sensor_id); break; case 1: - val = get_unaligned_be32(&power->accumulator) / - get_unaligned_be32(&power->update_tag); - val *= 1000000ULL; + val = occ_get_powr_avg(get_unaligned_be32(&power->accumulator), + get_unaligned_be32(&power->update_tag)); break; case 2: val = (u64)get_unaligned_be32(&power->update_tag) * @@ -459,12 +464,6 @@ static ssize_t occ_show_power_1(struct device *dev, return sysfs_emit(buf, "%llu\n", val); } -static u64 occ_get_powr_avg(u64 accum, u32 samples) -{ - return (samples == 0) ? 0 : - mul_u64_u32_div(accum, 1000000UL, samples); -} - static ssize_t occ_show_power_2(struct device *dev, struct device_attribute *attr, char *buf) { @@ -725,7 +724,7 @@ static ssize_t occ_show_extended(struct device *dev, switch (sattr->nr) { case 0: if (extn->flags & EXTN_FLAG_SENSOR_ID) { - rc = sysfs_emit(buf, "%u", + rc = sysfs_emit(buf, "%u\n", get_unaligned_be32(&extn->sensor_id)); } else { rc = sysfs_emit(buf, "%4phN\n", extn->name); diff --git a/drivers/hwmon/peci/cputemp.c b/drivers/hwmon/peci/cputemp.c index b2fc936851e1..457089c561b4 100644 --- a/drivers/hwmon/peci/cputemp.c +++ b/drivers/hwmon/peci/cputemp.c @@ -131,7 +131,7 @@ static int get_temp_target(struct peci_cputemp *priv, enum peci_temp_target_type *val = priv->temp.target.tjmax; break; case crit_hyst_type: - *val = priv->temp.target.tjmax - priv->temp.target.tcontrol; + *val = priv->temp.target.tcontrol; break; default: ret = -EOPNOTSUPP; @@ -319,7 +319,7 @@ static umode_t cputemp_is_visible(const void *data, enum hwmon_sensor_types type { const struct peci_cputemp *priv = data; - if (channel > CPUTEMP_CHANNEL_NUMS) + if (channel >= CPUTEMP_CHANNEL_NUMS) return 0; if (channel < channel_core) diff --git a/drivers/hwmon/pmbus/ina233.c b/drivers/hwmon/pmbus/ina233.c index 2d8b5a5347ed..7aebd854763a 100644 --- a/drivers/hwmon/pmbus/ina233.c +++ b/drivers/hwmon/pmbus/ina233.c @@ -72,7 +72,8 @@ static int ina233_read_word_data(struct i2c_client *client, int page, /* Adjust returned value to match VIN coefficients */ /* VIN: 1.25 mV VSHUNT: 2.5 uV LSB */ - ret = DIV_ROUND_CLOSEST(ret * 25, 12500); + ret = clamp_val(DIV_ROUND_CLOSEST((s16)ret * 25, 12500), + S16_MIN, S16_MAX) & 0xffff; break; default: ret = -ENODATA; diff --git a/drivers/hwmon/pmbus/isl68137.c b/drivers/hwmon/pmbus/isl68137.c index e7dac26b5be6..3e3a887aad05 100644 --- a/drivers/hwmon/pmbus/isl68137.c +++ b/drivers/hwmon/pmbus/isl68137.c @@ -96,7 +96,15 @@ static ssize_t isl68137_avs_enable_show_page(struct i2c_client *client, int page, char *buf) { - int val = pmbus_read_byte_data(client, page, PMBUS_OPERATION); + int val; + + val = pmbus_lock_interruptible(client); + if (val) + return val; + + val = pmbus_read_byte_data(client, page, PMBUS_OPERATION); + + pmbus_unlock(client); if (val < 0) return val; @@ -118,6 +126,10 @@ static ssize_t isl68137_avs_enable_store_page(struct i2c_client *client, op_val = result ? ISL68137_VOUT_AVS : 0; + rc = pmbus_lock_interruptible(client); + if (rc) + return rc; + /* * Writes to VOUT setpoint over AVSBus will persist after the VRM is * switched to PMBus control. Switching back to AVSBus control @@ -129,17 +141,20 @@ static ssize_t isl68137_avs_enable_store_page(struct i2c_client *client, rc = pmbus_read_word_data(client, page, 0xff, PMBUS_VOUT_COMMAND); if (rc < 0) - return rc; + goto unlock; rc = pmbus_write_word_data(client, page, PMBUS_VOUT_COMMAND, rc); if (rc < 0) - return rc; + goto unlock; } rc = pmbus_update_byte_data(client, page, PMBUS_OPERATION, ISL68137_VOUT_AVS, op_val); +unlock: + pmbus_unlock(client); + return (rc < 0) ? rc : count; } diff --git a/drivers/hwmon/pmbus/ltc4286.c b/drivers/hwmon/pmbus/ltc4286.c index aabd0bcdfeee..8715d380784a 100644 --- a/drivers/hwmon/pmbus/ltc4286.c +++ b/drivers/hwmon/pmbus/ltc4286.c @@ -173,3 +173,4 @@ module_i2c_driver(ltc4286_driver); MODULE_AUTHOR("Delphine CC Chiu <Delphine_CC_Chiu@wiwynn.com>"); MODULE_DESCRIPTION("PMBUS driver for LTC4286 and compatibles"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("PMBUS"); diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c index be6d05def115..572be3ebc03d 100644 --- a/drivers/hwmon/pmbus/pmbus_core.c +++ b/drivers/hwmon/pmbus/pmbus_core.c @@ -6,6 +6,7 @@ * Copyright (c) 2012 Guenter Roeck */ +#include <linux/atomic.h> #include <linux/debugfs.h> #include <linux/delay.h> #include <linux/dcache.h> @@ -21,8 +22,8 @@ #include <linux/pmbus.h> #include <linux/regulator/driver.h> #include <linux/regulator/machine.h> -#include <linux/of.h> #include <linux/thermal.h> +#include <linux/workqueue.h> #include "pmbus.h" /* @@ -112,6 +113,11 @@ struct pmbus_data { struct mutex update_lock; +#if IS_ENABLED(CONFIG_REGULATOR) + atomic_t regulator_events[PMBUS_PAGES]; + struct work_struct regulator_notify_work; +#endif + bool has_status_word; /* device uses STATUS_WORD register */ int (*read_status)(struct i2c_client *client, int page); @@ -1209,6 +1215,12 @@ static ssize_t pmbus_show_boolean(struct device *dev, return sysfs_emit(buf, "%d\n", val); } +static ssize_t pmbus_show_zero(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + return sysfs_emit(buf, "0\n"); +} + static ssize_t pmbus_show_sensor(struct device *dev, struct device_attribute *devattr, char *buf) { @@ -1407,7 +1419,7 @@ static struct pmbus_sensor *pmbus_add_sensor(struct pmbus_data *data, int reg, enum pmbus_sensor_classes class, bool update, bool readonly, - bool convert) + bool writeonly, bool convert) { struct pmbus_sensor *sensor; struct device_attribute *a; @@ -1436,7 +1448,8 @@ static struct pmbus_sensor *pmbus_add_sensor(struct pmbus_data *data, sensor->data = -ENODATA; pmbus_dev_attr_init(a, sensor->name, readonly ? 0444 : 0644, - pmbus_show_sensor, pmbus_set_sensor); + writeonly ? pmbus_show_zero : pmbus_show_sensor, + pmbus_set_sensor); if (pmbus_add_attribute(data, &a->attr)) return NULL; @@ -1495,8 +1508,10 @@ static int pmbus_add_label(struct pmbus_data *data, struct pmbus_limit_attr { u16 reg; /* Limit register */ u16 sbit; /* Alarm attribute status bit */ - bool update; /* True if register needs updates */ - bool low; /* True if low limit; for limits with compare functions only */ + bool readonly:1; /* True if the attribute is read-only */ + bool writeonly:1; /* True if the attribute is write-only */ + bool update:1; /* True if register needs updates */ + bool low:1; /* True if low limit; for limits with compare functions only */ const char *attr; /* Attribute name */ const char *alarm; /* Alarm attribute name */ }; @@ -1511,9 +1526,9 @@ struct pmbus_sensor_attr { u8 nlimit; /* # of limit registers */ enum pmbus_sensor_classes class;/* sensor class */ const char *label; /* sensor label */ - bool paged; /* true if paged sensor */ - bool update; /* true if update needed */ - bool compare; /* true if compare function needed */ + bool paged:1; /* true if paged sensor */ + bool update:1; /* true if update needed */ + bool compare:1; /* true if compare function needed */ u32 func; /* sensor mask */ u32 sfunc; /* sensor status mask */ int sreg; /* status register */ @@ -1544,7 +1559,7 @@ static int pmbus_add_limit_attrs(struct i2c_client *client, curr = pmbus_add_sensor(data, name, l->attr, index, page, 0xff, l->reg, attr->class, attr->update || l->update, - false, true); + l->readonly, l->writeonly, true); if (!curr) return -ENOMEM; if (l->sbit && (info->func[page] & attr->sfunc)) { @@ -1584,7 +1599,7 @@ static int pmbus_add_sensor_attrs_one(struct i2c_client *client, return ret; } base = pmbus_add_sensor(data, name, "input", index, page, phase, - attr->reg, attr->class, true, true, true); + attr->reg, attr->class, true, true, false, true); if (!base) return -ENOMEM; /* No limit and alarm attributes for phase specific sensors */ @@ -1707,23 +1722,29 @@ static const struct pmbus_limit_attr vin_limit_attrs[] = { }, { .reg = PMBUS_VIRT_READ_VIN_AVG, .update = true, + .readonly = true, .attr = "average", }, { .reg = PMBUS_VIRT_READ_VIN_MIN, .update = true, + .readonly = true, .attr = "lowest", }, { .reg = PMBUS_VIRT_READ_VIN_MAX, .update = true, + .readonly = true, .attr = "highest", }, { .reg = PMBUS_VIRT_RESET_VIN_HISTORY, + .writeonly = true, .attr = "reset_history", }, { .reg = PMBUS_MFR_VIN_MIN, + .readonly = true, .attr = "rated_min", }, { .reg = PMBUS_MFR_VIN_MAX, + .readonly = true, .attr = "rated_max", }, }; @@ -1776,23 +1797,29 @@ static const struct pmbus_limit_attr vout_limit_attrs[] = { }, { .reg = PMBUS_VIRT_READ_VOUT_AVG, .update = true, + .readonly = true, .attr = "average", }, { .reg = PMBUS_VIRT_READ_VOUT_MIN, .update = true, + .readonly = true, .attr = "lowest", }, { .reg = PMBUS_VIRT_READ_VOUT_MAX, .update = true, + .readonly = true, .attr = "highest", }, { .reg = PMBUS_VIRT_RESET_VOUT_HISTORY, + .writeonly = true, .attr = "reset_history", }, { .reg = PMBUS_MFR_VOUT_MIN, + .readonly = true, .attr = "rated_min", }, { .reg = PMBUS_MFR_VOUT_MAX, + .readonly = true, .attr = "rated_max", }, }; @@ -1852,20 +1879,25 @@ static const struct pmbus_limit_attr iin_limit_attrs[] = { }, { .reg = PMBUS_VIRT_READ_IIN_AVG, .update = true, + .readonly = true, .attr = "average", }, { .reg = PMBUS_VIRT_READ_IIN_MIN, .update = true, + .readonly = true, .attr = "lowest", }, { .reg = PMBUS_VIRT_READ_IIN_MAX, .update = true, + .readonly = true, .attr = "highest", }, { .reg = PMBUS_VIRT_RESET_IIN_HISTORY, + .writeonly = true, .attr = "reset_history", }, { .reg = PMBUS_MFR_IIN_MAX, + .readonly = true, .attr = "rated_max", }, }; @@ -1889,20 +1921,25 @@ static const struct pmbus_limit_attr iout_limit_attrs[] = { }, { .reg = PMBUS_VIRT_READ_IOUT_AVG, .update = true, + .readonly = true, .attr = "average", }, { .reg = PMBUS_VIRT_READ_IOUT_MIN, .update = true, + .readonly = true, .attr = "lowest", }, { .reg = PMBUS_VIRT_READ_IOUT_MAX, .update = true, + .readonly = true, .attr = "highest", }, { .reg = PMBUS_VIRT_RESET_IOUT_HISTORY, + .writeonly = true, .attr = "reset_history", }, { .reg = PMBUS_MFR_IOUT_MAX, + .readonly = true, .attr = "rated_max", }, }; @@ -1943,20 +1980,25 @@ static const struct pmbus_limit_attr pin_limit_attrs[] = { }, { .reg = PMBUS_VIRT_READ_PIN_AVG, .update = true, + .readonly = true, .attr = "average", }, { .reg = PMBUS_VIRT_READ_PIN_MIN, .update = true, + .readonly = true, .attr = "input_lowest", }, { .reg = PMBUS_VIRT_READ_PIN_MAX, .update = true, + .readonly = true, .attr = "input_highest", }, { .reg = PMBUS_VIRT_RESET_PIN_HISTORY, + .writeonly = true, .attr = "reset_history", }, { .reg = PMBUS_MFR_PIN_MAX, + .readonly = true, .attr = "rated_max", }, }; @@ -1980,20 +2022,25 @@ static const struct pmbus_limit_attr pout_limit_attrs[] = { }, { .reg = PMBUS_VIRT_READ_POUT_AVG, .update = true, + .readonly = true, .attr = "average", }, { .reg = PMBUS_VIRT_READ_POUT_MIN, .update = true, + .readonly = true, .attr = "input_lowest", }, { .reg = PMBUS_VIRT_READ_POUT_MAX, .update = true, + .readonly = true, .attr = "input_highest", }, { .reg = PMBUS_VIRT_RESET_POUT_HISTORY, + .writeonly = true, .attr = "reset_history", }, { .reg = PMBUS_MFR_POUT_MAX, + .readonly = true, .attr = "rated_max", }, }; @@ -2049,18 +2096,23 @@ static const struct pmbus_limit_attr temp_limit_attrs[] = { .sbit = PB_TEMP_OT_FAULT, }, { .reg = PMBUS_VIRT_READ_TEMP_MIN, + .readonly = true, .attr = "lowest", }, { .reg = PMBUS_VIRT_READ_TEMP_AVG, + .readonly = true, .attr = "average", }, { .reg = PMBUS_VIRT_READ_TEMP_MAX, + .readonly = true, .attr = "highest", }, { .reg = PMBUS_VIRT_RESET_TEMP_HISTORY, + .writeonly = true, .attr = "reset_history", }, { .reg = PMBUS_MFR_MAX_TEMP_1, + .readonly = true, .attr = "rated_max", }, }; @@ -2090,18 +2142,23 @@ static const struct pmbus_limit_attr temp_limit_attrs2[] = { .sbit = PB_TEMP_OT_FAULT, }, { .reg = PMBUS_VIRT_READ_TEMP2_MIN, + .readonly = true, .attr = "lowest", }, { .reg = PMBUS_VIRT_READ_TEMP2_AVG, + .readonly = true, .attr = "average", }, { .reg = PMBUS_VIRT_READ_TEMP2_MAX, + .readonly = true, .attr = "highest", }, { .reg = PMBUS_VIRT_RESET_TEMP2_HISTORY, + .writeonly = true, .attr = "reset_history", }, { .reg = PMBUS_MFR_MAX_TEMP_2, + .readonly = true, .attr = "rated_max", }, }; @@ -2131,6 +2188,7 @@ static const struct pmbus_limit_attr temp_limit_attrs3[] = { .sbit = PB_TEMP_OT_FAULT, }, { .reg = PMBUS_MFR_MAX_TEMP_3, + .readonly = true, .attr = "rated_max", }, }; @@ -2214,7 +2272,7 @@ static int pmbus_add_fan_ctrl(struct i2c_client *client, sensor = pmbus_add_sensor(data, "fan", "target", index, page, 0xff, PMBUS_VIRT_FAN_TARGET_1 + id, PSC_FAN, - false, false, true); + false, false, false, true); if (!sensor) return -ENOMEM; @@ -2225,14 +2283,14 @@ static int pmbus_add_fan_ctrl(struct i2c_client *client, sensor = pmbus_add_sensor(data, "pwm", NULL, index, page, 0xff, PMBUS_VIRT_PWM_1 + id, PSC_PWM, - false, false, true); + false, false, false, true); if (!sensor) return -ENOMEM; sensor = pmbus_add_sensor(data, "pwm", "enable", index, page, 0xff, PMBUS_VIRT_PWM_ENABLE_1 + id, PSC_PWM, - true, false, false); + true, false, false, false); if (!sensor) return -ENOMEM; @@ -2274,7 +2332,7 @@ static int pmbus_add_fan_attributes(struct i2c_client *client, if (pmbus_add_sensor(data, "fan", "input", index, page, 0xff, pmbus_fan_registers[f], - PSC_FAN, true, true, true) == NULL) + PSC_FAN, true, true, false, true) == NULL) return -ENOMEM; /* Fan control */ @@ -3176,12 +3234,19 @@ static int pmbus_regulator_get_voltage(struct regulator_dev *rdev) .class = PSC_VOLTAGE_OUT, .convert = true, }; + int ret; + mutex_lock(&data->update_lock); s.data = _pmbus_read_word_data(client, s.page, 0xff, PMBUS_READ_VOUT); - if (s.data < 0) - return s.data; + if (s.data < 0) { + ret = s.data; + goto unlock; + } - return (int)pmbus_reg2data(data, &s) * 1000; /* unit is uV */ + ret = (int)pmbus_reg2data(data, &s) * 1000; /* unit is uV */ +unlock: + mutex_unlock(&data->update_lock); + return ret; } static int pmbus_regulator_set_voltage(struct regulator_dev *rdev, int min_uv, @@ -3198,16 +3263,22 @@ static int pmbus_regulator_set_voltage(struct regulator_dev *rdev, int min_uv, }; int val = DIV_ROUND_CLOSEST(min_uv, 1000); /* convert to mV */ int low, high; + int ret; *selector = 0; + mutex_lock(&data->update_lock); low = pmbus_regulator_get_low_margin(client, s.page); - if (low < 0) - return low; + if (low < 0) { + ret = low; + goto unlock; + } high = pmbus_regulator_get_high_margin(client, s.page); - if (high < 0) - return high; + if (high < 0) { + ret = high; + goto unlock; + } /* Make sure we are within margins */ if (low > val) @@ -3217,7 +3288,10 @@ static int pmbus_regulator_set_voltage(struct regulator_dev *rdev, int min_uv, val = pmbus_data2reg(data, &s, val); - return _pmbus_write_word_data(client, s.page, PMBUS_VOUT_COMMAND, (u16)val); + ret = _pmbus_write_word_data(client, s.page, PMBUS_VOUT_COMMAND, (u16)val); +unlock: + mutex_unlock(&data->update_lock); + return ret; } static int pmbus_regulator_list_voltage(struct regulator_dev *rdev, @@ -3227,6 +3301,7 @@ static int pmbus_regulator_list_voltage(struct regulator_dev *rdev, struct i2c_client *client = to_i2c_client(dev->parent); struct pmbus_data *data = i2c_get_clientdata(client); int val, low, high; + int ret; if (data->flags & PMBUS_VOUT_PROTECTED) return 0; @@ -3239,18 +3314,29 @@ static int pmbus_regulator_list_voltage(struct regulator_dev *rdev, val = DIV_ROUND_CLOSEST(rdev->desc->min_uV + (rdev->desc->uV_step * selector), 1000); /* convert to mV */ + mutex_lock(&data->update_lock); + low = pmbus_regulator_get_low_margin(client, rdev_get_id(rdev)); - if (low < 0) - return low; + if (low < 0) { + ret = low; + goto unlock; + } high = pmbus_regulator_get_high_margin(client, rdev_get_id(rdev)); - if (high < 0) - return high; + if (high < 0) { + ret = high; + goto unlock; + } - if (val >= low && val <= high) - return val * 1000; /* unit is uV */ + if (val >= low && val <= high) { + ret = val * 1000; /* unit is uV */ + goto unlock; + } - return 0; + ret = 0; +unlock: + mutex_unlock(&data->update_lock); + return ret; } const struct regulator_ops pmbus_regulator_ops = { @@ -3281,12 +3367,42 @@ int pmbus_regulator_init_cb(struct regulator_dev *rdev, } EXPORT_SYMBOL_NS_GPL(pmbus_regulator_init_cb, "PMBUS"); +static void pmbus_regulator_notify_work_cancel(void *data) +{ + struct pmbus_data *pdata = data; + + cancel_work_sync(&pdata->regulator_notify_work); +} + +static void pmbus_regulator_notify_worker(struct work_struct *work) +{ + struct pmbus_data *data = + container_of(work, struct pmbus_data, regulator_notify_work); + int i, j; + + for (i = 0; i < data->info->pages; i++) { + int event; + + event = atomic_xchg(&data->regulator_events[i], 0); + if (!event) + continue; + + for (j = 0; j < data->info->num_regulators; j++) { + if (i == rdev_get_id(data->rdevs[j])) { + regulator_notifier_call_chain(data->rdevs[j], + event, NULL); + break; + } + } + } +} + static int pmbus_regulator_register(struct pmbus_data *data) { struct device *dev = data->dev; const struct pmbus_driver_info *info = data->info; const struct pmbus_platform_data *pdata = dev_get_platdata(dev); - int i; + int i, ret; data->rdevs = devm_kzalloc(dev, sizeof(struct regulator_dev *) * info->num_regulators, GFP_KERNEL); @@ -3310,19 +3426,19 @@ static int pmbus_regulator_register(struct pmbus_data *data) info->reg_desc[i].name); } + INIT_WORK(&data->regulator_notify_work, pmbus_regulator_notify_worker); + + ret = devm_add_action_or_reset(dev, pmbus_regulator_notify_work_cancel, data); + if (ret) + return ret; + return 0; } static void pmbus_regulator_notify(struct pmbus_data *data, int page, int event) { - int j; - - for (j = 0; j < data->info->num_regulators; j++) { - if (page == rdev_get_id(data->rdevs[j])) { - regulator_notifier_call_chain(data->rdevs[j], event, NULL); - break; - } - } + atomic_or(event, &data->regulator_events[page]); + schedule_work(&data->regulator_notify_work); } #else static int pmbus_regulator_register(struct pmbus_data *data) diff --git a/drivers/hwmon/pmbus/pxe1610.c b/drivers/hwmon/pmbus/pxe1610.c index 6a4a978eca7e..24c1f961c766 100644 --- a/drivers/hwmon/pmbus/pxe1610.c +++ b/drivers/hwmon/pmbus/pxe1610.c @@ -104,7 +104,10 @@ static int pxe1610_probe(struct i2c_client *client) * By default this device doesn't boot to page 0, so set page 0 * to access all pmbus registers. */ - i2c_smbus_write_byte_data(client, PMBUS_PAGE, 0); + ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, 0); + if (ret < 0) + return dev_err_probe(&client->dev, ret, + "Failed to set page 0\n"); /* Read Manufacturer id */ ret = i2c_smbus_read_block_data(client, PMBUS_MFR_ID, buf); diff --git a/drivers/hwmon/pmbus/tps53679.c b/drivers/hwmon/pmbus/tps53679.c index ca2bfa25eb04..249974c13aa3 100644 --- a/drivers/hwmon/pmbus/tps53679.c +++ b/drivers/hwmon/pmbus/tps53679.c @@ -103,10 +103,10 @@ static int tps53679_identify_chip(struct i2c_client *client, } ret = i2c_smbus_read_block_data(client, PMBUS_IC_DEVICE_ID, buf); - if (ret < 0) - return ret; + if (ret <= 0) + return ret < 0 ? ret : -EIO; - /* Adjust length if null terminator if present */ + /* Adjust length if null terminator is present */ buf_len = (buf[ret - 1] != '\x00' ? ret : ret - 1); id_len = strlen(id); @@ -175,8 +175,8 @@ static int tps53676_identify(struct i2c_client *client, ret = i2c_smbus_read_block_data(client, PMBUS_IC_DEVICE_ID, buf); if (ret < 0) return ret; - if (strncmp("TI\x53\x67\x60", buf, 5)) { - dev_err(&client->dev, "Unexpected device ID: %s\n", buf); + if (ret != 6 || memcmp(buf, "TI\x53\x67\x60\x00", 6)) { + dev_err(&client->dev, "Unexpected device ID: %*ph\n", ret, buf); return -ENODEV; } diff --git a/drivers/i2c/busses/i2c-designware-amdisp.c b/drivers/i2c/busses/i2c-designware-amdisp.c index c48728ad9f6f..9f0ec0fae6f2 100644 --- a/drivers/i2c/busses/i2c-designware-amdisp.c +++ b/drivers/i2c/busses/i2c-designware-amdisp.c @@ -7,6 +7,7 @@ #include <linux/module.h> #include <linux/platform_device.h> +#include <linux/pm_domain.h> #include <linux/pm_runtime.h> #include <linux/soc/amd/isp4_misc.h> @@ -76,22 +77,20 @@ static int amd_isp_dw_i2c_plat_probe(struct platform_device *pdev) device_enable_async_suspend(&pdev->dev); - pm_runtime_enable(&pdev->dev); - pm_runtime_get_sync(&pdev->dev); - + dev_pm_genpd_resume(&pdev->dev); ret = i2c_dw_probe(isp_i2c_dev); if (ret) { dev_err_probe(&pdev->dev, ret, "i2c_dw_probe failed\n"); goto error_release_rpm; } - - pm_runtime_put_sync(&pdev->dev); + dev_pm_genpd_suspend(&pdev->dev); + pm_runtime_set_suspended(&pdev->dev); + pm_runtime_enable(&pdev->dev); return 0; error_release_rpm: amd_isp_dw_i2c_plat_pm_cleanup(isp_i2c_dev); - pm_runtime_put_sync(&pdev->dev); return ret; } diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index 85f554044cf1..452d120a210b 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -1018,8 +1018,9 @@ static inline int i2c_imx_isr_read(struct imx_i2c_struct *i2c_imx) return 0; } -static inline void i2c_imx_isr_read_continue(struct imx_i2c_struct *i2c_imx) +static inline enum imx_i2c_state i2c_imx_isr_read_continue(struct imx_i2c_struct *i2c_imx) { + enum imx_i2c_state next_state = IMX_I2C_STATE_READ_CONTINUE; unsigned int temp; if ((i2c_imx->msg->len - 1) == i2c_imx->msg_buf_idx) { @@ -1033,18 +1034,20 @@ static inline void i2c_imx_isr_read_continue(struct imx_i2c_struct *i2c_imx) i2c_imx->stopped = 1; temp &= ~(I2CR_MSTA | I2CR_MTX); imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); - } else { - /* - * For i2c master receiver repeat restart operation like: - * read -> repeat MSTA -> read/write - * The controller must set MTX before read the last byte in - * the first read operation, otherwise the first read cost - * one extra clock cycle. - */ - temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR); - temp |= I2CR_MTX; - imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); + + return IMX_I2C_STATE_DONE; } + /* + * For i2c master receiver repeat restart operation like: + * read -> repeat MSTA -> read/write + * The controller must set MTX before read the last byte in + * the first read operation, otherwise the first read cost + * one extra clock cycle. + */ + temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR); + temp |= I2CR_MTX; + imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); + next_state = IMX_I2C_STATE_DONE; } else if (i2c_imx->msg_buf_idx == (i2c_imx->msg->len - 2)) { temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR); temp |= I2CR_TXAK; @@ -1052,6 +1055,7 @@ static inline void i2c_imx_isr_read_continue(struct imx_i2c_struct *i2c_imx) } i2c_imx->msg->buf[i2c_imx->msg_buf_idx++] = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR); + return next_state; } static inline void i2c_imx_isr_read_block_data_len(struct imx_i2c_struct *i2c_imx) @@ -1088,11 +1092,9 @@ static irqreturn_t i2c_imx_master_isr(struct imx_i2c_struct *i2c_imx, unsigned i break; case IMX_I2C_STATE_READ_CONTINUE: - i2c_imx_isr_read_continue(i2c_imx); - if (i2c_imx->msg_buf_idx == i2c_imx->msg->len) { - i2c_imx->state = IMX_I2C_STATE_DONE; + i2c_imx->state = i2c_imx_isr_read_continue(i2c_imx); + if (i2c_imx->state == IMX_I2C_STATE_DONE) wake_up(&i2c_imx->queue); - } break; case IMX_I2C_STATE_READ_BLOCK_DATA: @@ -1490,6 +1492,7 @@ static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs, bool is_lastmsg) { int block_data = msgs->flags & I2C_M_RECV_LEN; + int ret = 0; dev_dbg(&i2c_imx->adapter.dev, "<%s> write slave address: addr=0x%x\n", @@ -1522,10 +1525,20 @@ static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs, dev_err(&i2c_imx->adapter.dev, "<%s> read timedout\n", __func__); return -ETIMEDOUT; } - if (!i2c_imx->stopped) - return i2c_imx_bus_busy(i2c_imx, 0, false); + if (i2c_imx->is_lastmsg) { + if (!i2c_imx->stopped) + ret = i2c_imx_bus_busy(i2c_imx, 0, false); + /* + * Only read the last byte of the last message after the bus is + * not busy. Else the controller generates another clock which + * might confuse devices. + */ + if (!ret) + i2c_imx->msg->buf[i2c_imx->msg_buf_idx++] = imx_i2c_read_reg(i2c_imx, + IMX_I2C_I2DR); + } - return 0; + return ret; } static int i2c_imx_xfer_common(struct i2c_adapter *adapter, diff --git a/drivers/iio/accel/adxl313_core.c b/drivers/iio/accel/adxl313_core.c index 9f5d4d2cb325..83dcac17a042 100644 --- a/drivers/iio/accel/adxl313_core.c +++ b/drivers/iio/accel/adxl313_core.c @@ -998,6 +998,8 @@ static int adxl313_buffer_predisable(struct iio_dev *indio_dev) ret = regmap_write(data->regmap, ADXL313_REG_FIFO_CTL, FIELD_PREP(ADXL313_REG_FIFO_CTL_MODE_MSK, ADXL313_FIFO_BYPASS)); + if (ret) + return ret; ret = regmap_write(data->regmap, ADXL313_REG_INT_ENABLE, 0); if (ret) diff --git a/drivers/iio/accel/adxl355_core.c b/drivers/iio/accel/adxl355_core.c index 1c1d64d5cbcb..8f90c58f4100 100644 --- a/drivers/iio/accel/adxl355_core.c +++ b/drivers/iio/accel/adxl355_core.c @@ -745,7 +745,7 @@ static const struct iio_chan_spec adxl355_channels[] = { BIT(IIO_CHAN_INFO_OFFSET), .scan_index = 3, .scan_type = { - .sign = 's', + .sign = 'u', .realbits = 12, .storagebits = 16, .endianness = IIO_BE, diff --git a/drivers/iio/accel/adxl380.c b/drivers/iio/accel/adxl380.c index 8fab2fdbe147..a51d1d61c412 100644 --- a/drivers/iio/accel/adxl380.c +++ b/drivers/iio/accel/adxl380.c @@ -877,7 +877,7 @@ static int adxl380_set_fifo_samples(struct adxl380_state *st) ret = regmap_update_bits(st->regmap, ADXL380_FIFO_CONFIG_0_REG, ADXL380_FIFO_SAMPLES_8_MSK, FIELD_PREP(ADXL380_FIFO_SAMPLES_8_MSK, - (fifo_samples & BIT(8)))); + !!(fifo_samples & BIT(8)))); if (ret) return ret; diff --git a/drivers/iio/adc/ad4062.c b/drivers/iio/adc/ad4062.c index dd4ad32aa6f5..8b03736d55fc 100644 --- a/drivers/iio/adc/ad4062.c +++ b/drivers/iio/adc/ad4062.c @@ -719,10 +719,8 @@ static int ad4062_request_irq(struct iio_dev *indio_dev) } st->gpo_irq[1] = true; - return devm_request_threaded_irq(dev, ret, - ad4062_irq_handler_drdy, - NULL, IRQF_ONESHOT, indio_dev->name, - indio_dev); + return devm_request_irq(dev, ret, ad4062_irq_handler_drdy, + IRQF_NO_THREAD, indio_dev->name, indio_dev); } static const struct iio_trigger_ops ad4062_trigger_ops = { @@ -955,7 +953,7 @@ static int ad4062_write_raw_dispatch(struct ad4062_state *st, int val, int val2, default: return -EINVAL; } -}; +} static int ad4062_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, diff --git a/drivers/iio/adc/ade9000.c b/drivers/iio/adc/ade9000.c index db085dc5e526..1abbfdfcd554 100644 --- a/drivers/iio/adc/ade9000.c +++ b/drivers/iio/adc/ade9000.c @@ -787,7 +787,7 @@ static int ade9000_iio_push_streaming(struct iio_dev *indio_dev) ADE9000_MIDDLE_PAGE_BIT); if (ret) { dev_err_ratelimited(dev, "IRQ0 WFB write fail"); - return IRQ_HANDLED; + return ret; } ade9000_configure_scan(indio_dev, ADE9000_REG_WF_BUFF); @@ -1123,7 +1123,7 @@ static int ade9000_write_raw(struct iio_dev *indio_dev, tmp &= ~ADE9000_PHASE_C_POS_BIT; switch (tmp) { - case ADE9000_REG_AWATTOS: + case ADE9000_REG_AWATT: return regmap_write(st->regmap, ADE9000_ADDR_ADJUST(ADE9000_REG_AWATTOS, chan->channel), val); @@ -1706,19 +1706,19 @@ static int ade9000_probe(struct spi_device *spi) init_completion(&st->reset_completion); - ret = ade9000_request_irq(dev, "irq0", ade9000_irq0_thread, indio_dev); + ret = devm_mutex_init(dev, &st->lock); if (ret) return ret; - ret = ade9000_request_irq(dev, "irq1", ade9000_irq1_thread, indio_dev); + ret = ade9000_request_irq(dev, "irq0", ade9000_irq0_thread, indio_dev); if (ret) return ret; - ret = ade9000_request_irq(dev, "dready", ade9000_dready_thread, indio_dev); + ret = ade9000_request_irq(dev, "irq1", ade9000_irq1_thread, indio_dev); if (ret) return ret; - ret = devm_mutex_init(dev, &st->lock); + ret = ade9000_request_irq(dev, "dready", ade9000_dready_thread, indio_dev); if (ret) return ret; diff --git a/drivers/iio/adc/aspeed_adc.c b/drivers/iio/adc/aspeed_adc.c index 4be44c524b4d..83a9885b9ae4 100644 --- a/drivers/iio/adc/aspeed_adc.c +++ b/drivers/iio/adc/aspeed_adc.c @@ -415,6 +415,7 @@ static int aspeed_adc_vref_config(struct iio_dev *indio_dev) } adc_engine_control_reg_val = readl(data->base + ASPEED_REG_ENGINE_CONTROL); + adc_engine_control_reg_val &= ~ASPEED_ADC_REF_VOLTAGE; ret = devm_regulator_get_enable_read_voltage(data->dev, "vref"); if (ret < 0 && ret != -ENODEV) diff --git a/drivers/iio/adc/nxp-sar-adc.c b/drivers/iio/adc/nxp-sar-adc.c index 9efa883c277d..58103bf16aff 100644 --- a/drivers/iio/adc/nxp-sar-adc.c +++ b/drivers/iio/adc/nxp-sar-adc.c @@ -718,6 +718,10 @@ static int nxp_sar_adc_buffer_software_do_postenable(struct iio_dev *indio_dev) struct nxp_sar_adc *info = iio_priv(indio_dev); int ret; + info->dma_chan = dma_request_chan(indio_dev->dev.parent, "rx"); + if (IS_ERR(info->dma_chan)) + return PTR_ERR(info->dma_chan); + nxp_sar_adc_dma_channels_enable(info, *indio_dev->active_scan_mask); nxp_sar_adc_dma_cfg(info, true); @@ -738,6 +742,7 @@ out_stop_cyclic_dma: out_dma_channels_disable: nxp_sar_adc_dma_cfg(info, false); nxp_sar_adc_dma_channels_disable(info, *indio_dev->active_scan_mask); + dma_release_channel(info->dma_chan); return ret; } @@ -765,10 +770,6 @@ static int nxp_sar_adc_buffer_postenable(struct iio_dev *indio_dev) unsigned long channel; int ret; - info->dma_chan = dma_request_chan(indio_dev->dev.parent, "rx"); - if (IS_ERR(info->dma_chan)) - return PTR_ERR(info->dma_chan); - info->channels_used = 0; /* diff --git a/drivers/iio/adc/ti-adc161s626.c b/drivers/iio/adc/ti-adc161s626.c index 28aa6b80160c..be1cc2e77862 100644 --- a/drivers/iio/adc/ti-adc161s626.c +++ b/drivers/iio/adc/ti-adc161s626.c @@ -15,6 +15,7 @@ #include <linux/init.h> #include <linux/err.h> #include <linux/spi/spi.h> +#include <linux/unaligned.h> #include <linux/iio/iio.h> #include <linux/iio/trigger.h> #include <linux/iio/buffer.h> @@ -70,8 +71,7 @@ struct ti_adc_data { u8 read_size; u8 shift; - - u8 buffer[16] __aligned(IIO_DMA_MINALIGN); + u8 buf[3] __aligned(IIO_DMA_MINALIGN); }; static int ti_adc_read_measurement(struct ti_adc_data *data, @@ -80,26 +80,20 @@ static int ti_adc_read_measurement(struct ti_adc_data *data, int ret; switch (data->read_size) { - case 2: { - __be16 buf; - - ret = spi_read(data->spi, (void *) &buf, 2); + case 2: + ret = spi_read(data->spi, data->buf, 2); if (ret) return ret; - *val = be16_to_cpu(buf); + *val = get_unaligned_be16(data->buf); break; - } - case 3: { - __be32 buf; - - ret = spi_read(data->spi, (void *) &buf, 3); + case 3: + ret = spi_read(data->spi, data->buf, 3); if (ret) return ret; - *val = be32_to_cpu(buf) >> 8; + *val = get_unaligned_be24(data->buf); break; - } default: return -EINVAL; } @@ -114,15 +108,20 @@ static irqreturn_t ti_adc_trigger_handler(int irq, void *private) struct iio_poll_func *pf = private; struct iio_dev *indio_dev = pf->indio_dev; struct ti_adc_data *data = iio_priv(indio_dev); - int ret; + struct { + s16 data; + aligned_s64 timestamp; + } scan = { }; + int ret, val; + + ret = ti_adc_read_measurement(data, &indio_dev->channels[0], &val); + if (ret) + goto exit_notify_done; - ret = ti_adc_read_measurement(data, &indio_dev->channels[0], - (int *) &data->buffer); - if (!ret) - iio_push_to_buffers_with_timestamp(indio_dev, - data->buffer, - iio_get_time_ns(indio_dev)); + scan.data = val; + iio_push_to_buffers_with_timestamp(indio_dev, &scan, iio_get_time_ns(indio_dev)); + exit_notify_done: iio_trigger_notify_done(indio_dev->trig); return IRQ_HANDLED; diff --git a/drivers/iio/adc/ti-ads1018.c b/drivers/iio/adc/ti-ads1018.c index 6246b3cab71f..0780abd0d0db 100644 --- a/drivers/iio/adc/ti-ads1018.c +++ b/drivers/iio/adc/ti-ads1018.c @@ -249,7 +249,7 @@ static int ads1018_single_shot(struct ads1018 *ads1018, struct iio_chan_spec const *chan, u16 *cnv) { u8 max_drate_mode = ads1018->chip_info->num_data_rate_mode_to_hz - 1; - u8 drate = ads1018->chip_info->data_rate_mode_to_hz[max_drate_mode]; + u32 drate = ads1018->chip_info->data_rate_mode_to_hz[max_drate_mode]; u8 pga_mode = ads1018->chan_data[chan->scan_index].pga_mode; struct spi_transfer xfer[2] = { { diff --git a/drivers/iio/adc/ti-ads1119.c b/drivers/iio/adc/ti-ads1119.c index c9cedc59cdcd..79be71b4de96 100644 --- a/drivers/iio/adc/ti-ads1119.c +++ b/drivers/iio/adc/ti-ads1119.c @@ -274,12 +274,15 @@ static int ads1119_single_conversion(struct ads1119_state *st, ret = pm_runtime_resume_and_get(dev); if (ret) - goto pdown; + return ret; ret = ads1119_configure_channel(st, mux, gain, datarate); if (ret) goto pdown; + if (st->client->irq) + reinit_completion(&st->completion); + ret = i2c_smbus_write_byte(st->client, ADS1119_CMD_START_SYNC); if (ret) goto pdown; @@ -735,10 +738,8 @@ static int ads1119_probe(struct i2c_client *client) return dev_err_probe(dev, ret, "Failed to setup IIO buffer\n"); if (client->irq > 0) { - ret = devm_request_threaded_irq(dev, client->irq, - ads1119_irq_handler, - NULL, IRQF_ONESHOT, - "ads1119", indio_dev); + ret = devm_request_irq(dev, client->irq, ads1119_irq_handler, + IRQF_NO_THREAD, "ads1119", indio_dev); if (ret) return dev_err_probe(dev, ret, "Failed to allocate irq\n"); diff --git a/drivers/iio/adc/ti-ads7950.c b/drivers/iio/adc/ti-ads7950.c index bbe1ce577789..cdc624889559 100644 --- a/drivers/iio/adc/ti-ads7950.c +++ b/drivers/iio/adc/ti-ads7950.c @@ -427,13 +427,15 @@ static int ti_ads7950_set(struct gpio_chip *chip, unsigned int offset, static int ti_ads7950_get(struct gpio_chip *chip, unsigned int offset) { struct ti_ads7950_state *st = gpiochip_get_data(chip); + bool state; int ret; mutex_lock(&st->slock); /* If set as output, return the output */ if (st->gpio_cmd_settings_bitmask & BIT(offset)) { - ret = st->cmd_settings_bitmask & BIT(offset); + state = st->cmd_settings_bitmask & BIT(offset); + ret = 0; goto out; } @@ -444,7 +446,7 @@ static int ti_ads7950_get(struct gpio_chip *chip, unsigned int offset) if (ret) goto out; - ret = ((st->single_rx >> 12) & BIT(offset)) ? 1 : 0; + state = (st->single_rx >> 12) & BIT(offset); /* Revert back to original settings */ st->cmd_settings_bitmask &= ~TI_ADS7950_CR_GPIO_DATA; @@ -456,7 +458,7 @@ static int ti_ads7950_get(struct gpio_chip *chip, unsigned int offset) out: mutex_unlock(&st->slock); - return ret; + return ret ?: state; } static int ti_ads7950_get_direction(struct gpio_chip *chip, diff --git a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c index 5540e2d28f4a..417c4ab8c1b2 100644 --- a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c +++ b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c @@ -14,6 +14,7 @@ #include <linux/iio/triggered_buffer.h> #include <linux/iio/trigger_consumer.h> #include <linux/iio/sysfs.h> +#include <linux/iio/kfifo_buf.h> #include "hid-sensor-trigger.h" static ssize_t _hid_sensor_set_report_latency(struct device *dev, @@ -202,12 +203,21 @@ static void hid_sensor_set_power_work(struct work_struct *work) _hid_sensor_power_state(attrb, true); } -static int hid_sensor_data_rdy_trigger_set_state(struct iio_trigger *trig, - bool state) +static int buffer_postenable(struct iio_dev *indio_dev) { - return hid_sensor_power_state(iio_trigger_get_drvdata(trig), state); + return hid_sensor_power_state(iio_device_get_drvdata(indio_dev), 1); } +static int buffer_predisable(struct iio_dev *indio_dev) +{ + return hid_sensor_power_state(iio_device_get_drvdata(indio_dev), 0); +} + +static const struct iio_buffer_setup_ops hid_sensor_buffer_ops = { + .postenable = buffer_postenable, + .predisable = buffer_predisable, +}; + void hid_sensor_remove_trigger(struct iio_dev *indio_dev, struct hid_sensor_common *attrb) { @@ -219,14 +229,9 @@ void hid_sensor_remove_trigger(struct iio_dev *indio_dev, cancel_work_sync(&attrb->work); iio_trigger_unregister(attrb->trigger); iio_trigger_free(attrb->trigger); - iio_triggered_buffer_cleanup(indio_dev); } EXPORT_SYMBOL_NS(hid_sensor_remove_trigger, "IIO_HID"); -static const struct iio_trigger_ops hid_sensor_trigger_ops = { - .set_trigger_state = &hid_sensor_data_rdy_trigger_set_state, -}; - int hid_sensor_setup_trigger(struct iio_dev *indio_dev, const char *name, struct hid_sensor_common *attrb) { @@ -239,25 +244,34 @@ int hid_sensor_setup_trigger(struct iio_dev *indio_dev, const char *name, else fifo_attrs = NULL; - ret = iio_triggered_buffer_setup_ext(indio_dev, - &iio_pollfunc_store_time, NULL, - IIO_BUFFER_DIRECTION_IN, - NULL, fifo_attrs); + indio_dev->modes = INDIO_DIRECT_MODE | INDIO_HARDWARE_TRIGGERED; + + ret = devm_iio_kfifo_buffer_setup_ext(&indio_dev->dev, indio_dev, + &hid_sensor_buffer_ops, + fifo_attrs); if (ret) { - dev_err(&indio_dev->dev, "Triggered Buffer Setup Failed\n"); + dev_err(&indio_dev->dev, "Kfifo Buffer Setup Failed\n"); return ret; } + /* + * The current user space in distro "iio-sensor-proxy" is not working in + * trigerless mode and it expects + * /sys/bus/iio/devices/iio:device0/trigger/current_trigger. + * The change replacing iio_triggered_buffer_setup_ext() with + * devm_iio_kfifo_buffer_setup_ext() will not create attribute without + * registering a trigger with INDIO_HARDWARE_TRIGGERED. + * So the below code fragment is still required. + */ + trig = iio_trigger_alloc(indio_dev->dev.parent, "%s-dev%d", name, iio_device_id(indio_dev)); if (trig == NULL) { dev_err(&indio_dev->dev, "Trigger Allocate Failed\n"); - ret = -ENOMEM; - goto error_triggered_buffer_cleanup; + return -ENOMEM; } iio_trigger_set_drvdata(trig, attrb); - trig->ops = &hid_sensor_trigger_ops; ret = iio_trigger_register(trig); if (ret) { @@ -284,8 +298,6 @@ error_unreg_trigger: iio_trigger_unregister(trig); error_free_trig: iio_trigger_free(trig); -error_triggered_buffer_cleanup: - iio_triggered_buffer_cleanup(indio_dev); return ret; } EXPORT_SYMBOL_NS(hid_sensor_setup_trigger, "IIO_HID"); diff --git a/drivers/iio/dac/ad5770r.c b/drivers/iio/dac/ad5770r.c index cd47cb1c685c..6027e8d88b27 100644 --- a/drivers/iio/dac/ad5770r.c +++ b/drivers/iio/dac/ad5770r.c @@ -322,7 +322,7 @@ static int ad5770r_read_raw(struct iio_dev *indio_dev, chan->address, st->transf_buf, 2); if (ret) - return 0; + return ret; buf16 = get_unaligned_le16(st->transf_buf); *val = buf16 >> 2; diff --git a/drivers/iio/dac/mcp47feb02.c b/drivers/iio/dac/mcp47feb02.c index b218f0c3a0bd..faccb804a5ed 100644 --- a/drivers/iio/dac/mcp47feb02.c +++ b/drivers/iio/dac/mcp47feb02.c @@ -65,7 +65,7 @@ #define MCP47FEB02_MAX_SCALES_CH 3 #define MCP47FEB02_DAC_WIPER_UNLOCKED 0 #define MCP47FEB02_NORMAL_OPERATION 0 -#define MCP47FEB02_INTERNAL_BAND_GAP_mV 2440 +#define MCP47FEB02_INTERNAL_BAND_GAP_uV 2440000 #define NV_DAC_ADDR_OFFSET 0x10 enum mcp47feb02_vref_mode { @@ -697,44 +697,40 @@ static const struct iio_chan_spec mcp47febxx_ch_template = { }; static void mcp47feb02_init_scale(struct mcp47feb02_data *data, enum mcp47feb02_scale scale, - int vref_mV, int scale_avail[]) + int vref_uV, int scale_avail[]) { u32 value_micro, value_int; u64 tmp; - /* vref_mV should not be negative */ - tmp = (u64)vref_mV * MICRO >> data->chip_features->resolution; + /* vref_uV should not be negative */ + tmp = (u64)vref_uV * MILLI >> data->chip_features->resolution; value_int = div_u64_rem(tmp, MICRO, &value_micro); scale_avail[scale * 2] = value_int; scale_avail[scale * 2 + 1] = value_micro; } -static int mcp47feb02_init_scales_avail(struct mcp47feb02_data *data, int vdd_mV, - int vref_mV, int vref1_mV) +static int mcp47feb02_init_scales_avail(struct mcp47feb02_data *data, int vdd_uV, + int vref_uV, int vref1_uV) { - struct device *dev = regmap_get_device(data->regmap); int tmp_vref; - mcp47feb02_init_scale(data, MCP47FEB02_SCALE_VDD, vdd_mV, data->scale); + mcp47feb02_init_scale(data, MCP47FEB02_SCALE_VDD, vdd_uV, data->scale); if (data->use_vref) - tmp_vref = vref_mV; + tmp_vref = vref_uV; else - tmp_vref = MCP47FEB02_INTERNAL_BAND_GAP_mV; + tmp_vref = MCP47FEB02_INTERNAL_BAND_GAP_uV; mcp47feb02_init_scale(data, MCP47FEB02_SCALE_GAIN_X1, tmp_vref, data->scale); mcp47feb02_init_scale(data, MCP47FEB02_SCALE_GAIN_X2, tmp_vref * 2, data->scale); if (data->phys_channels >= 4) { - mcp47feb02_init_scale(data, MCP47FEB02_SCALE_VDD, vdd_mV, data->scale_1); - - if (data->use_vref1 && vref1_mV <= 0) - return dev_err_probe(dev, vref1_mV, "Invalid voltage for Vref1\n"); + mcp47feb02_init_scale(data, MCP47FEB02_SCALE_VDD, vdd_uV, data->scale_1); if (data->use_vref1) - tmp_vref = vref1_mV; + tmp_vref = vref1_uV; else - tmp_vref = MCP47FEB02_INTERNAL_BAND_GAP_mV; + tmp_vref = MCP47FEB02_INTERNAL_BAND_GAP_uV; mcp47feb02_init_scale(data, MCP47FEB02_SCALE_GAIN_X1, tmp_vref, data->scale_1); @@ -955,8 +951,6 @@ static int mcp47feb02_parse_fw(struct iio_dev *indio_dev, u32 num_channels; u8 chan_idx = 0; - guard(mutex)(&data->lock); - num_channels = device_get_child_node_count(dev); if (num_channels > chip_features->phys_channels) return dev_err_probe(dev, -EINVAL, "More channels than the chip supports\n"); @@ -1080,8 +1074,8 @@ static int mcp47feb02_init_ctrl_regs(struct mcp47feb02_data *data) return 0; } -static int mcp47feb02_init_ch_scales(struct mcp47feb02_data *data, int vdd_mV, - int vref_mV, int vref1_mV) +static int mcp47feb02_init_ch_scales(struct mcp47feb02_data *data, int vdd_uV, + int vref_uV, int vref1_uV) { unsigned int i; @@ -1089,7 +1083,7 @@ static int mcp47feb02_init_ch_scales(struct mcp47feb02_data *data, int vdd_mV, struct device *dev = regmap_get_device(data->regmap); int ret; - ret = mcp47feb02_init_scales_avail(data, vdd_mV, vref_mV, vref1_mV); + ret = mcp47feb02_init_scales_avail(data, vdd_uV, vref_uV, vref1_uV); if (ret) return dev_err_probe(dev, ret, "failed to init scales for ch %u\n", i); } @@ -1103,10 +1097,7 @@ static int mcp47feb02_probe(struct i2c_client *client) struct device *dev = &client->dev; struct mcp47feb02_data *data; struct iio_dev *indio_dev; - int vref1_mV = 0; - int vref_mV = 0; - int vdd_mV; - int ret; + int vref1_uV, vref_uV, vdd_uV, ret; indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); if (!indio_dev) @@ -1143,13 +1134,14 @@ static int mcp47feb02_probe(struct i2c_client *client) if (ret < 0) return ret; - vdd_mV = ret / MILLI; + vdd_uV = ret; ret = devm_regulator_get_enable_read_voltage(dev, "vref"); if (ret > 0) { - vref_mV = ret / MILLI; + vref_uV = ret; data->use_vref = true; } else { + vref_uV = 0; dev_dbg(dev, "using internal band gap as voltage reference.\n"); dev_dbg(dev, "Vref is unavailable.\n"); } @@ -1157,9 +1149,10 @@ static int mcp47feb02_probe(struct i2c_client *client) if (chip_features->have_ext_vref1) { ret = devm_regulator_get_enable_read_voltage(dev, "vref1"); if (ret > 0) { - vref1_mV = ret / MILLI; + vref1_uV = ret; data->use_vref1 = true; } else { + vref1_uV = 0; dev_dbg(dev, "using internal band gap as voltage reference 1.\n"); dev_dbg(dev, "Vref1 is unavailable.\n"); } @@ -1169,7 +1162,7 @@ static int mcp47feb02_probe(struct i2c_client *client) if (ret) return dev_err_probe(dev, ret, "Error initialising vref register\n"); - ret = mcp47feb02_init_ch_scales(data, vdd_mV, vref_mV, vref1_mV); + ret = mcp47feb02_init_ch_scales(data, vdd_uV, vref_uV, vref1_uV); if (ret) return ret; diff --git a/drivers/iio/gyro/mpu3050-core.c b/drivers/iio/gyro/mpu3050-core.c index 317e7b217ec6..d84e04e4b431 100644 --- a/drivers/iio/gyro/mpu3050-core.c +++ b/drivers/iio/gyro/mpu3050-core.c @@ -1129,11 +1129,16 @@ static int mpu3050_trigger_probe(struct iio_dev *indio_dev, int irq) ret = iio_trigger_register(mpu3050->trig); if (ret) - return ret; + goto err_iio_trigger; indio_dev->trig = iio_trigger_get(mpu3050->trig); return 0; + +err_iio_trigger: + free_irq(mpu3050->irq, mpu3050->trig); + + return ret; } int mpu3050_common_probe(struct device *dev, @@ -1221,12 +1226,6 @@ int mpu3050_common_probe(struct device *dev, goto err_power_down; } - ret = iio_device_register(indio_dev); - if (ret) { - dev_err(dev, "device register failed\n"); - goto err_cleanup_buffer; - } - dev_set_drvdata(dev, indio_dev); /* Check if we have an assigned IRQ to use as trigger */ @@ -1249,9 +1248,20 @@ int mpu3050_common_probe(struct device *dev, pm_runtime_use_autosuspend(dev); pm_runtime_put(dev); + ret = iio_device_register(indio_dev); + if (ret) { + dev_err(dev, "device register failed\n"); + goto err_iio_device_register; + } + return 0; -err_cleanup_buffer: +err_iio_device_register: + pm_runtime_get_sync(dev); + pm_runtime_put_noidle(dev); + pm_runtime_disable(dev); + if (irq) + free_irq(mpu3050->irq, mpu3050->trig); iio_triggered_buffer_cleanup(indio_dev); err_power_down: mpu3050_power_down(mpu3050); @@ -1264,13 +1274,13 @@ void mpu3050_common_remove(struct device *dev) struct iio_dev *indio_dev = dev_get_drvdata(dev); struct mpu3050 *mpu3050 = iio_priv(indio_dev); + iio_device_unregister(indio_dev); pm_runtime_get_sync(dev); pm_runtime_put_noidle(dev); pm_runtime_disable(dev); - iio_triggered_buffer_cleanup(indio_dev); if (mpu3050->irq) - free_irq(mpu3050->irq, mpu3050); - iio_device_unregister(indio_dev); + free_irq(mpu3050->irq, mpu3050->trig); + iio_triggered_buffer_cleanup(indio_dev); mpu3050_power_down(mpu3050); } diff --git a/drivers/iio/imu/adis16550.c b/drivers/iio/imu/adis16550.c index 28f0dbd0226c..1f2af506f4bd 100644 --- a/drivers/iio/imu/adis16550.c +++ b/drivers/iio/imu/adis16550.c @@ -643,12 +643,12 @@ static int adis16550_read_raw(struct iio_dev *indio_dev, case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: switch (chan->type) { case IIO_ANGL_VEL: - ret = adis16550_get_accl_filter_freq(st, val); + ret = adis16550_get_gyro_filter_freq(st, val); if (ret) return ret; return IIO_VAL_INT; case IIO_ACCEL: - ret = adis16550_get_gyro_filter_freq(st, val); + ret = adis16550_get_accl_filter_freq(st, val); if (ret) return ret; return IIO_VAL_INT; @@ -681,9 +681,9 @@ static int adis16550_write_raw(struct iio_dev *indio_dev, case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: switch (chan->type) { case IIO_ANGL_VEL: - return adis16550_set_accl_filter_freq(st, val); - case IIO_ACCEL: return adis16550_set_gyro_filter_freq(st, val); + case IIO_ACCEL: + return adis16550_set_accl_filter_freq(st, val); default: return -EINVAL; } diff --git a/drivers/iio/imu/bmi160/bmi160_core.c b/drivers/iio/imu/bmi160/bmi160_core.c index 5f47708b4c5d..4abb83b75e2e 100644 --- a/drivers/iio/imu/bmi160/bmi160_core.c +++ b/drivers/iio/imu/bmi160/bmi160_core.c @@ -573,12 +573,16 @@ static int bmi160_config_pin(struct regmap *regmap, enum bmi160_int_pin pin, int_out_ctrl_shift = BMI160_INT1_OUT_CTRL_SHIFT; int_latch_mask = BMI160_INT1_LATCH_MASK; int_map_mask = BMI160_INT1_MAP_DRDY_EN; + pin_name = "INT1"; break; case BMI160_PIN_INT2: int_out_ctrl_shift = BMI160_INT2_OUT_CTRL_SHIFT; int_latch_mask = BMI160_INT2_LATCH_MASK; int_map_mask = BMI160_INT2_MAP_DRDY_EN; + pin_name = "INT2"; break; + default: + return -EINVAL; } int_out_ctrl_mask = BMI160_INT_OUT_CTRL_MASK << int_out_ctrl_shift; @@ -612,17 +616,8 @@ static int bmi160_config_pin(struct regmap *regmap, enum bmi160_int_pin pin, ret = bmi160_write_conf_reg(regmap, BMI160_REG_INT_MAP, int_map_mask, int_map_mask, write_usleep); - if (ret) { - switch (pin) { - case BMI160_PIN_INT1: - pin_name = "INT1"; - break; - case BMI160_PIN_INT2: - pin_name = "INT2"; - break; - } + if (ret) dev_err(dev, "Failed to configure %s IRQ pin", pin_name); - } return ret; } diff --git a/drivers/iio/imu/bno055/bno055.c b/drivers/iio/imu/bno055/bno055.c index 303bc308f80a..c96fec2ebb3e 100644 --- a/drivers/iio/imu/bno055/bno055.c +++ b/drivers/iio/imu/bno055/bno055.c @@ -64,7 +64,7 @@ #define BNO055_GRAVITY_DATA_X_LSB_REG 0x2E #define BNO055_GRAVITY_DATA_Y_LSB_REG 0x30 #define BNO055_GRAVITY_DATA_Z_LSB_REG 0x32 -#define BNO055_SCAN_CH_COUNT ((BNO055_GRAVITY_DATA_Z_LSB_REG - BNO055_ACC_DATA_X_LSB_REG) / 2) +#define BNO055_SCAN_CH_COUNT ((BNO055_GRAVITY_DATA_Z_LSB_REG - BNO055_ACC_DATA_X_LSB_REG) / 2 + 1) #define BNO055_TEMP_REG 0x34 #define BNO055_CALIB_STAT_REG 0x35 #define BNO055_CALIB_STAT_MAGN_SHIFT 0 diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c index 55d877745575..5b28a3ffcc3d 100644 --- a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c +++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c @@ -225,6 +225,10 @@ static int st_lsm6dsx_set_fifo_odr(struct st_lsm6dsx_sensor *sensor, const struct st_lsm6dsx_reg *batch_reg; u8 data; + /* Only internal sensors have a FIFO ODR configuration register. */ + if (sensor->id >= ARRAY_SIZE(hw->settings->batch)) + return 0; + batch_reg = &hw->settings->batch[sensor->id]; if (batch_reg->addr) { int val; @@ -858,12 +862,21 @@ int st_lsm6dsx_fifo_setup(struct st_lsm6dsx_hw *hw) int i, ret; for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) { + const struct iio_dev_attr **attrs; + if (!hw->iio_devs[i]) continue; + /* + * For the accelerometer, allow setting FIFO sampling frequency + * values different from the sensor sampling frequency, which + * may be needed to keep FIFO data rate low while sampling + * acceleration data at high rates for accurate event detection. + */ + attrs = i == ST_LSM6DSX_ID_ACC ? st_lsm6dsx_buffer_attrs : NULL; ret = devm_iio_kfifo_buffer_setup_ext(hw->dev, hw->iio_devs[i], &st_lsm6dsx_buffer_ops, - st_lsm6dsx_buffer_attrs); + attrs); if (ret) return ret; } diff --git a/drivers/iio/light/vcnl4035.c b/drivers/iio/light/vcnl4035.c index 963747927425..16aeb17067bc 100644 --- a/drivers/iio/light/vcnl4035.c +++ b/drivers/iio/light/vcnl4035.c @@ -103,17 +103,23 @@ static irqreturn_t vcnl4035_trigger_consumer_handler(int irq, void *p) struct iio_dev *indio_dev = pf->indio_dev; struct vcnl4035_data *data = iio_priv(indio_dev); /* Ensure naturally aligned timestamp */ - u8 buffer[ALIGN(sizeof(u16), sizeof(s64)) + sizeof(s64)] __aligned(8) = { }; + struct { + u16 als_data; + aligned_s64 timestamp; + } buffer = { }; + unsigned int val; int ret; - ret = regmap_read(data->regmap, VCNL4035_ALS_DATA, (int *)buffer); + ret = regmap_read(data->regmap, VCNL4035_ALS_DATA, &val); if (ret < 0) { dev_err(&data->client->dev, "Trigger consumer can't read from sensor.\n"); goto fail_read; } - iio_push_to_buffers_with_timestamp(indio_dev, buffer, - iio_get_time_ns(indio_dev)); + + buffer.als_data = val; + iio_push_to_buffers_with_timestamp(indio_dev, &buffer, + iio_get_time_ns(indio_dev)); fail_read: iio_trigger_notify_done(indio_dev->trig); @@ -381,7 +387,7 @@ static const struct iio_chan_spec vcnl4035_channels[] = { .sign = 'u', .realbits = 16, .storagebits = 16, - .endianness = IIO_LE, + .endianness = IIO_CPU, }, }, { @@ -395,7 +401,7 @@ static const struct iio_chan_spec vcnl4035_channels[] = { .sign = 'u', .realbits = 16, .storagebits = 16, - .endianness = IIO_LE, + .endianness = IIO_CPU, }, }, }; diff --git a/drivers/iio/light/veml6070.c b/drivers/iio/light/veml6070.c index 6d4483c85f30..74d7246e5225 100644 --- a/drivers/iio/light/veml6070.c +++ b/drivers/iio/light/veml6070.c @@ -134,9 +134,7 @@ static int veml6070_read(struct veml6070_data *data) if (ret < 0) return ret; - ret = (msb << 8) | lsb; - - return 0; + return (msb << 8) | lsb; } static const struct iio_chan_spec veml6070_channels[] = { diff --git a/drivers/iio/orientation/hid-sensor-rotation.c b/drivers/iio/orientation/hid-sensor-rotation.c index e759f91a710a..5a5e6e4fbe34 100644 --- a/drivers/iio/orientation/hid-sensor-rotation.c +++ b/drivers/iio/orientation/hid-sensor-rotation.c @@ -19,8 +19,13 @@ struct dev_rot_state { struct hid_sensor_common common_attributes; struct hid_sensor_hub_attribute_info quaternion; struct { - s32 sampled_vals[4]; - aligned_s64 timestamp; + IIO_DECLARE_QUATERNION(s32, sampled_vals); + /* + * ABI regression avoidance: There are two copies of the same + * timestamp in case of userspace depending on broken alignment + * from older kernels. + */ + aligned_s64 timestamp[2]; } scan; int scale_pre_decml; int scale_post_decml; @@ -154,8 +159,19 @@ static int dev_rot_proc_event(struct hid_sensor_hub_device *hsdev, if (!rot_state->timestamp) rot_state->timestamp = iio_get_time_ns(indio_dev); - iio_push_to_buffers_with_timestamp(indio_dev, &rot_state->scan, - rot_state->timestamp); + /* + * ABI regression avoidance: IIO previously had an incorrect + * implementation of iio_push_to_buffers_with_timestamp() that + * put the timestamp in the last 8 bytes of the buffer, which + * was incorrect according to the IIO ABI. To avoid breaking + * userspace that may be depending on this broken behavior, we + * put the timestamp in both the correct place [0] and the old + * incorrect place [1]. + */ + rot_state->scan.timestamp[0] = rot_state->timestamp; + rot_state->scan.timestamp[1] = rot_state->timestamp; + + iio_push_to_buffers(indio_dev, &rot_state->scan); rot_state->timestamp = 0; } diff --git a/drivers/iio/pressure/abp2030pa.c b/drivers/iio/pressure/abp2030pa.c index 4ca056a73cef..b44f1bf4c633 100644 --- a/drivers/iio/pressure/abp2030pa.c +++ b/drivers/iio/pressure/abp2030pa.c @@ -520,7 +520,7 @@ int abp2_common_probe(struct device *dev, const struct abp2_ops *ops, int irq) data->p_offset = div_s64(odelta * data->pmin, pdelta) - data->outmin; if (data->irq > 0) { - ret = devm_request_irq(dev, irq, abp2_eoc_handler, IRQF_ONESHOT, + ret = devm_request_irq(dev, irq, abp2_eoc_handler, 0, dev_name(dev), data); if (ret) return ret; diff --git a/drivers/iio/proximity/rfd77402.c b/drivers/iio/proximity/rfd77402.c index 6afdbfca3e5a..81b8daf17a54 100644 --- a/drivers/iio/proximity/rfd77402.c +++ b/drivers/iio/proximity/rfd77402.c @@ -173,10 +173,8 @@ static int rfd77402_wait_for_result(struct rfd77402_data *data) struct i2c_client *client = data->client; int val, ret; - if (data->irq_en) { - reinit_completion(&data->completion); + if (data->irq_en) return rfd77402_wait_for_irq(data); - } /* * As per RFD77402 datasheet section '3.1.1 Single Measure', the @@ -204,6 +202,9 @@ static int rfd77402_measure(struct rfd77402_data *data) if (ret < 0) return ret; + if (data->irq_en) + reinit_completion(&data->completion); + ret = i2c_smbus_write_byte_data(client, RFD77402_CMD_R, RFD77402_CMD_SINGLE | RFD77402_CMD_VALID); diff --git a/drivers/infiniband/core/rw.c b/drivers/infiniband/core/rw.c index fc45c384833f..4fafe393a48c 100644 --- a/drivers/infiniband/core/rw.c +++ b/drivers/infiniband/core/rw.c @@ -608,14 +608,29 @@ int rdma_rw_ctx_init(struct rdma_rw_ctx *ctx, struct ib_qp *qp, u32 port_num, if (rdma_rw_io_needs_mr(qp->device, port_num, dir, sg_cnt)) { ret = rdma_rw_init_mr_wrs(ctx, qp, port_num, sg, sg_cnt, sg_offset, remote_addr, rkey, dir); - } else if (sg_cnt > 1) { + /* + * If MR init succeeded or failed for a reason other + * than pool exhaustion, that result is final. + * + * Pool exhaustion (-EAGAIN) from the max_sgl_rd + * optimization is recoverable: fall back to + * direct SGE posting. iWARP and force_mr require + * MRs unconditionally, so -EAGAIN is terminal. + */ + if (ret != -EAGAIN || + rdma_protocol_iwarp(qp->device, port_num) || + unlikely(rdma_rw_force_mr)) + goto out; + } + + if (sg_cnt > 1) ret = rdma_rw_init_map_wrs(ctx, qp, sg, sg_cnt, sg_offset, remote_addr, rkey, dir); - } else { + else ret = rdma_rw_init_single_wr(ctx, qp, sg, sg_offset, remote_addr, rkey, dir); - } +out: if (ret < 0) goto out_unmap_sg; return ret; @@ -686,14 +701,16 @@ int rdma_rw_ctx_init_bvec(struct rdma_rw_ctx *ctx, struct ib_qp *qp, return ret; /* - * IOVA mapping not available. Check if MR registration provides - * better performance than multiple SGE entries. + * IOVA not available; fall back to the map_wrs path, which maps + * each bvec as a direct SGE. This is always correct: the MR path + * is a throughput optimization, not a correctness requirement. + * (iWARP, which does require MRs, is handled by the check above.) + * + * The rdma_rw_io_needs_mr() gate is not used here because nr_bvec + * is a raw page count that overstates DMA entry demand -- the bvec + * caller has no post-DMA-coalescing segment count, and feeding the + * inflated count into the MR path exhausts the pool on RDMA READs. */ - if (rdma_rw_io_needs_mr(dev, port_num, dir, nr_bvec)) - return rdma_rw_init_mr_wrs_bvec(ctx, qp, port_num, bvecs, - nr_bvec, &iter, remote_addr, - rkey, dir); - return rdma_rw_init_map_wrs_bvec(ctx, qp, bvecs, nr_bvec, &iter, remote_addr, rkey, dir); } diff --git a/drivers/infiniband/core/umem.c b/drivers/infiniband/core/umem.c index cff4fcca2c34..edc34c69f0f2 100644 --- a/drivers/infiniband/core/umem.c +++ b/drivers/infiniband/core/umem.c @@ -55,7 +55,8 @@ static void __ib_umem_release(struct ib_device *dev, struct ib_umem *umem, int d if (dirty) ib_dma_unmap_sgtable_attrs(dev, &umem->sgt_append.sgt, - DMA_BIDIRECTIONAL, 0); + DMA_BIDIRECTIONAL, + DMA_ATTR_REQUIRE_COHERENT); for_each_sgtable_sg(&umem->sgt_append.sgt, sg, i) { unpin_user_page_range_dirty_lock(sg_page(sg), @@ -169,7 +170,7 @@ struct ib_umem *ib_umem_get(struct ib_device *device, unsigned long addr, unsigned long lock_limit; unsigned long new_pinned; unsigned long cur_base; - unsigned long dma_attr = 0; + unsigned long dma_attr = DMA_ATTR_REQUIRE_COHERENT; struct mm_struct *mm; unsigned long npages; int pinned, ret; diff --git a/drivers/infiniband/hw/bng_re/bng_dev.c b/drivers/infiniband/hw/bng_re/bng_dev.c index d34b5f88cd40..71a7ca2196ad 100644 --- a/drivers/infiniband/hw/bng_re/bng_dev.c +++ b/drivers/infiniband/hw/bng_re/bng_dev.c @@ -210,7 +210,7 @@ static int bng_re_stats_ctx_alloc(struct bng_re_dev *rdev) return rc; } -static void bng_re_query_hwrm_version(struct bng_re_dev *rdev) +static int bng_re_query_hwrm_version(struct bng_re_dev *rdev) { struct bnge_auxr_dev *aux_dev = rdev->aux_dev; struct hwrm_ver_get_output ver_get_resp = {}; @@ -230,7 +230,7 @@ static void bng_re_query_hwrm_version(struct bng_re_dev *rdev) if (rc) { ibdev_err(&rdev->ibdev, "Failed to query HW version, rc = 0x%x", rc); - return; + return rc; } cctx = rdev->chip_ctx; @@ -244,6 +244,8 @@ static void bng_re_query_hwrm_version(struct bng_re_dev *rdev) if (!cctx->hwrm_cmd_max_timeout) cctx->hwrm_cmd_max_timeout = BNG_ROCE_FW_MAX_TIMEOUT; + + return 0; } static void bng_re_dev_uninit(struct bng_re_dev *rdev) @@ -306,13 +308,15 @@ static int bng_re_dev_init(struct bng_re_dev *rdev) goto msix_ctx_fail; } - bng_re_query_hwrm_version(rdev); + rc = bng_re_query_hwrm_version(rdev); + if (rc) + goto destroy_chip_ctx; rc = bng_re_alloc_fw_channel(&rdev->bng_res, &rdev->rcfw); if (rc) { ibdev_err(&rdev->ibdev, "Failed to allocate RCFW Channel: %#x\n", rc); - goto alloc_fw_chl_fail; + goto destroy_chip_ctx; } /* Allocate nq record memory */ @@ -391,7 +395,7 @@ free_rcfw: kfree(rdev->nqr); nq_alloc_fail: bng_re_free_rcfw_channel(&rdev->rcfw); -alloc_fw_chl_fail: +destroy_chip_ctx: bng_re_destroy_chip_ctx(rdev); msix_ctx_fail: bnge_unregister_dev(rdev->aux_dev); diff --git a/drivers/infiniband/hw/efa/efa_com.c b/drivers/infiniband/hw/efa/efa_com.c index 229b0ad3b0cb..e97b5f0d7003 100644 --- a/drivers/infiniband/hw/efa/efa_com.c +++ b/drivers/infiniband/hw/efa/efa_com.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause /* - * Copyright 2018-2025 Amazon.com, Inc. or its affiliates. All rights reserved. + * Copyright 2018-2026 Amazon.com, Inc. or its affiliates. All rights reserved. */ #include <linux/log2.h> @@ -310,23 +310,19 @@ static inline struct efa_comp_ctx *efa_com_get_comp_ctx_by_cmd_id(struct efa_com return &aq->comp_ctx[ctx_id]; } -static struct efa_comp_ctx *__efa_com_submit_admin_cmd(struct efa_com_admin_queue *aq, - struct efa_admin_aq_entry *cmd, - size_t cmd_size_in_bytes, - struct efa_admin_acq_entry *comp, - size_t comp_size_in_bytes) +static void __efa_com_submit_admin_cmd(struct efa_com_admin_queue *aq, + struct efa_comp_ctx *comp_ctx, + struct efa_admin_aq_entry *cmd, + size_t cmd_size_in_bytes, + struct efa_admin_acq_entry *comp, + size_t comp_size_in_bytes) { struct efa_admin_aq_entry *aqe; - struct efa_comp_ctx *comp_ctx; u16 queue_size_mask; u16 cmd_id; u16 ctx_id; u16 pi; - comp_ctx = efa_com_alloc_comp_ctx(aq); - if (!comp_ctx) - return ERR_PTR(-EINVAL); - queue_size_mask = aq->depth - 1; pi = aq->sq.pc & queue_size_mask; ctx_id = efa_com_get_comp_ctx_id(aq, comp_ctx); @@ -360,8 +356,6 @@ static struct efa_comp_ctx *__efa_com_submit_admin_cmd(struct efa_com_admin_queu /* barrier not needed in case of writel */ writel(aq->sq.pc, aq->sq.db_addr); - - return comp_ctx; } static inline int efa_com_init_comp_ctxt(struct efa_com_admin_queue *aq) @@ -394,28 +388,25 @@ static inline int efa_com_init_comp_ctxt(struct efa_com_admin_queue *aq) return 0; } -static struct efa_comp_ctx *efa_com_submit_admin_cmd(struct efa_com_admin_queue *aq, - struct efa_admin_aq_entry *cmd, - size_t cmd_size_in_bytes, - struct efa_admin_acq_entry *comp, - size_t comp_size_in_bytes) +static int efa_com_submit_admin_cmd(struct efa_com_admin_queue *aq, + struct efa_comp_ctx *comp_ctx, + struct efa_admin_aq_entry *cmd, + size_t cmd_size_in_bytes, + struct efa_admin_acq_entry *comp, + size_t comp_size_in_bytes) { - struct efa_comp_ctx *comp_ctx; - spin_lock(&aq->sq.lock); if (!test_bit(EFA_AQ_STATE_RUNNING_BIT, &aq->state)) { ibdev_err_ratelimited(aq->efa_dev, "Admin queue is closed\n"); spin_unlock(&aq->sq.lock); - return ERR_PTR(-ENODEV); + return -ENODEV; } - comp_ctx = __efa_com_submit_admin_cmd(aq, cmd, cmd_size_in_bytes, comp, - comp_size_in_bytes); + __efa_com_submit_admin_cmd(aq, comp_ctx, cmd, cmd_size_in_bytes, comp, + comp_size_in_bytes); spin_unlock(&aq->sq.lock); - if (IS_ERR(comp_ctx)) - clear_bit(EFA_AQ_STATE_RUNNING_BIT, &aq->state); - return comp_ctx; + return 0; } static int efa_com_handle_single_admin_completion(struct efa_com_admin_queue *aq, @@ -512,7 +503,6 @@ static int efa_com_wait_and_process_admin_cq_polling(struct efa_comp_ctx *comp_c { unsigned long timeout; unsigned long flags; - int err; timeout = jiffies + usecs_to_jiffies(aq->completion_timeout); @@ -532,24 +522,20 @@ static int efa_com_wait_and_process_admin_cq_polling(struct efa_comp_ctx *comp_c atomic64_inc(&aq->stats.no_completion); clear_bit(EFA_AQ_STATE_RUNNING_BIT, &aq->state); - err = -ETIME; - goto out; + return -ETIME; } msleep(aq->poll_interval); } - err = efa_com_comp_status_to_errno(comp_ctx->user_cqe->acq_common_descriptor.status); -out: - efa_com_dealloc_comp_ctx(aq, comp_ctx); - return err; + return efa_com_comp_status_to_errno( + comp_ctx->user_cqe->acq_common_descriptor.status); } static int efa_com_wait_and_process_admin_cq_interrupts(struct efa_comp_ctx *comp_ctx, struct efa_com_admin_queue *aq) { unsigned long flags; - int err; wait_for_completion_timeout(&comp_ctx->wait_event, usecs_to_jiffies(aq->completion_timeout)); @@ -585,14 +571,11 @@ static int efa_com_wait_and_process_admin_cq_interrupts(struct efa_comp_ctx *com aq->cq.cc); clear_bit(EFA_AQ_STATE_RUNNING_BIT, &aq->state); - err = -ETIME; - goto out; + return -ETIME; } - err = efa_com_comp_status_to_errno(comp_ctx->user_cqe->acq_common_descriptor.status); -out: - efa_com_dealloc_comp_ctx(aq, comp_ctx); - return err; + return efa_com_comp_status_to_errno( + comp_ctx->user_cqe->acq_common_descriptor.status); } /* @@ -642,30 +625,39 @@ int efa_com_cmd_exec(struct efa_com_admin_queue *aq, ibdev_dbg(aq->efa_dev, "%s (opcode %d)\n", efa_com_cmd_str(cmd->aq_common_descriptor.opcode), cmd->aq_common_descriptor.opcode); - comp_ctx = efa_com_submit_admin_cmd(aq, cmd, cmd_size, comp, comp_size); - if (IS_ERR(comp_ctx)) { + + comp_ctx = efa_com_alloc_comp_ctx(aq); + if (!comp_ctx) { + clear_bit(EFA_AQ_STATE_RUNNING_BIT, &aq->state); + up(&aq->avail_cmds); + return -EINVAL; + } + + err = efa_com_submit_admin_cmd(aq, comp_ctx, cmd, cmd_size, comp, comp_size); + if (err) { ibdev_err_ratelimited( aq->efa_dev, - "Failed to submit command %s (opcode %u) err %pe\n", + "Failed to submit command %s (opcode %u) err %d\n", efa_com_cmd_str(cmd->aq_common_descriptor.opcode), - cmd->aq_common_descriptor.opcode, comp_ctx); + cmd->aq_common_descriptor.opcode, err); + efa_com_dealloc_comp_ctx(aq, comp_ctx); up(&aq->avail_cmds); atomic64_inc(&aq->stats.cmd_err); - return PTR_ERR(comp_ctx); + return err; } err = efa_com_wait_and_process_admin_cq(comp_ctx, aq); if (err) { ibdev_err_ratelimited( aq->efa_dev, - "Failed to process command %s (opcode %u) comp_status %d err %d\n", + "Failed to process command %s (opcode %u) err %d\n", efa_com_cmd_str(cmd->aq_common_descriptor.opcode), - cmd->aq_common_descriptor.opcode, - comp_ctx->user_cqe->acq_common_descriptor.status, err); + cmd->aq_common_descriptor.opcode, err); atomic64_inc(&aq->stats.cmd_err); } + efa_com_dealloc_comp_ctx(aq, comp_ctx); up(&aq->avail_cmds); return err; diff --git a/drivers/infiniband/hw/ionic/ionic_controlpath.c b/drivers/infiniband/hw/ionic/ionic_controlpath.c index 4842931f5316..a5671da3db64 100644 --- a/drivers/infiniband/hw/ionic/ionic_controlpath.c +++ b/drivers/infiniband/hw/ionic/ionic_controlpath.c @@ -508,6 +508,7 @@ static int ionic_build_hdr(struct ionic_ibdev *dev, { const struct ib_global_route *grh; enum rdma_network_type net; + u8 smac[ETH_ALEN]; u16 vlan; int rc; @@ -518,7 +519,7 @@ static int ionic_build_hdr(struct ionic_ibdev *dev, grh = rdma_ah_read_grh(attr); - rc = rdma_read_gid_l2_fields(grh->sgid_attr, &vlan, &hdr->eth.smac_h[0]); + rc = rdma_read_gid_l2_fields(grh->sgid_attr, &vlan, smac); if (rc) return rc; @@ -536,6 +537,7 @@ static int ionic_build_hdr(struct ionic_ibdev *dev, if (rc) return rc; + ether_addr_copy(hdr->eth.smac_h, smac); ether_addr_copy(hdr->eth.dmac_h, attr->roce.dmac); if (net == RDMA_NETWORK_IPV4) { diff --git a/drivers/infiniband/hw/irdma/cm.c b/drivers/infiniband/hw/irdma/cm.c index 3d084d4ff577..91c0e7298283 100644 --- a/drivers/infiniband/hw/irdma/cm.c +++ b/drivers/infiniband/hw/irdma/cm.c @@ -2241,11 +2241,12 @@ irdma_make_cm_node(struct irdma_cm_core *cm_core, struct irdma_device *iwdev, int oldarpindex; int arpindex; struct net_device *netdev = iwdev->netdev; + int ret; /* create an hte and cm_node for this instance */ cm_node = kzalloc_obj(*cm_node, GFP_ATOMIC); if (!cm_node) - return NULL; + return ERR_PTR(-ENOMEM); /* set our node specific transport info */ cm_node->ipv4 = cm_info->ipv4; @@ -2348,8 +2349,10 @@ irdma_make_cm_node(struct irdma_cm_core *cm_core, struct irdma_device *iwdev, arpindex = -EINVAL; } - if (arpindex < 0) + if (arpindex < 0) { + ret = -EINVAL; goto err; + } ether_addr_copy(cm_node->rem_mac, iwdev->rf->arp_table[arpindex].mac_addr); @@ -2360,7 +2363,7 @@ irdma_make_cm_node(struct irdma_cm_core *cm_core, struct irdma_device *iwdev, err: kfree(cm_node); - return NULL; + return ERR_PTR(ret); } static void irdma_destroy_connection(struct irdma_cm_node *cm_node) @@ -3021,8 +3024,8 @@ static int irdma_create_cm_node(struct irdma_cm_core *cm_core, /* create a CM connection node */ cm_node = irdma_make_cm_node(cm_core, iwdev, cm_info, NULL); - if (!cm_node) - return -ENOMEM; + if (IS_ERR(cm_node)) + return PTR_ERR(cm_node); /* set our node side to client (active) side */ cm_node->tcp_cntxt.client = 1; @@ -3219,9 +3222,9 @@ void irdma_receive_ilq(struct irdma_sc_vsi *vsi, struct irdma_puda_buf *rbuf) cm_info.cm_id = listener->cm_id; cm_node = irdma_make_cm_node(cm_core, iwdev, &cm_info, listener); - if (!cm_node) { + if (IS_ERR(cm_node)) { ibdev_dbg(&cm_core->iwdev->ibdev, - "CM: allocate node failed\n"); + "CM: allocate node failed ret=%ld\n", PTR_ERR(cm_node)); refcount_dec(&listener->refcnt); return; } @@ -4239,21 +4242,21 @@ static void irdma_cm_event_handler(struct work_struct *work) irdma_cm_event_reset(event); break; case IRDMA_CM_EVENT_CONNECTED: - if (!event->cm_node->cm_id || - event->cm_node->state != IRDMA_CM_STATE_OFFLOADED) + if (!cm_node->cm_id || + cm_node->state != IRDMA_CM_STATE_OFFLOADED) break; irdma_cm_event_connected(event); break; case IRDMA_CM_EVENT_MPA_REJECT: - if (!event->cm_node->cm_id || + if (!cm_node->cm_id || cm_node->state == IRDMA_CM_STATE_OFFLOADED) break; irdma_send_cm_event(cm_node, cm_node->cm_id, IW_CM_EVENT_CONNECT_REPLY, -ECONNREFUSED); break; case IRDMA_CM_EVENT_ABORTED: - if (!event->cm_node->cm_id || - event->cm_node->state == IRDMA_CM_STATE_OFFLOADED) + if (!cm_node->cm_id || + cm_node->state == IRDMA_CM_STATE_OFFLOADED) break; irdma_event_connect_error(event); break; @@ -4263,7 +4266,7 @@ static void irdma_cm_event_handler(struct work_struct *work) break; } - irdma_rem_ref_cm_node(event->cm_node); + irdma_rem_ref_cm_node(cm_node); kfree(event); } diff --git a/drivers/infiniband/hw/irdma/uk.c b/drivers/infiniband/hw/irdma/uk.c index ac3721a5747a..4718acf6c6fd 100644 --- a/drivers/infiniband/hw/irdma/uk.c +++ b/drivers/infiniband/hw/irdma/uk.c @@ -1438,7 +1438,7 @@ exit: * irdma_round_up_wq - return round up qp wq depth * @wqdepth: wq depth in quanta to round up */ -static int irdma_round_up_wq(u32 wqdepth) +static u64 irdma_round_up_wq(u64 wqdepth) { int scount = 1; @@ -1491,15 +1491,16 @@ void irdma_get_wqe_shift(struct irdma_uk_attrs *uk_attrs, u32 sge, int irdma_get_sqdepth(struct irdma_uk_attrs *uk_attrs, u32 sq_size, u8 shift, u32 *sqdepth) { - u32 min_size = (u32)uk_attrs->min_hw_wq_size << shift; + u32 min_hw_quanta = (u32)uk_attrs->min_hw_wq_size << shift; + u64 hw_quanta = + irdma_round_up_wq(((u64)sq_size << shift) + IRDMA_SQ_RSVD); - *sqdepth = irdma_round_up_wq((sq_size << shift) + IRDMA_SQ_RSVD); - - if (*sqdepth < min_size) - *sqdepth = min_size; - else if (*sqdepth > uk_attrs->max_hw_wq_quanta) + if (hw_quanta < min_hw_quanta) + hw_quanta = min_hw_quanta; + else if (hw_quanta > uk_attrs->max_hw_wq_quanta) return -EINVAL; + *sqdepth = hw_quanta; return 0; } @@ -1513,15 +1514,16 @@ int irdma_get_sqdepth(struct irdma_uk_attrs *uk_attrs, u32 sq_size, u8 shift, int irdma_get_rqdepth(struct irdma_uk_attrs *uk_attrs, u32 rq_size, u8 shift, u32 *rqdepth) { - u32 min_size = (u32)uk_attrs->min_hw_wq_size << shift; - - *rqdepth = irdma_round_up_wq((rq_size << shift) + IRDMA_RQ_RSVD); + u32 min_hw_quanta = (u32)uk_attrs->min_hw_wq_size << shift; + u64 hw_quanta = + irdma_round_up_wq(((u64)rq_size << shift) + IRDMA_RQ_RSVD); - if (*rqdepth < min_size) - *rqdepth = min_size; - else if (*rqdepth > uk_attrs->max_hw_rq_quanta) + if (hw_quanta < min_hw_quanta) + hw_quanta = min_hw_quanta; + else if (hw_quanta > uk_attrs->max_hw_rq_quanta) return -EINVAL; + *rqdepth = hw_quanta; return 0; } @@ -1535,13 +1537,16 @@ int irdma_get_rqdepth(struct irdma_uk_attrs *uk_attrs, u32 rq_size, u8 shift, int irdma_get_srqdepth(struct irdma_uk_attrs *uk_attrs, u32 srq_size, u8 shift, u32 *srqdepth) { - *srqdepth = irdma_round_up_wq((srq_size << shift) + IRDMA_RQ_RSVD); + u32 min_hw_quanta = (u32)uk_attrs->min_hw_wq_size << shift; + u64 hw_quanta = + irdma_round_up_wq(((u64)srq_size << shift) + IRDMA_RQ_RSVD); - if (*srqdepth < ((u32)uk_attrs->min_hw_wq_size << shift)) - *srqdepth = uk_attrs->min_hw_wq_size << shift; - else if (*srqdepth > uk_attrs->max_hw_srq_quanta) + if (hw_quanta < min_hw_quanta) + hw_quanta = min_hw_quanta; + else if (hw_quanta > uk_attrs->max_hw_srq_quanta) return -EINVAL; + *srqdepth = hw_quanta; return 0; } diff --git a/drivers/infiniband/hw/irdma/utils.c b/drivers/infiniband/hw/irdma/utils.c index ab8c5284d4be..495e5daff4b4 100644 --- a/drivers/infiniband/hw/irdma/utils.c +++ b/drivers/infiniband/hw/irdma/utils.c @@ -2322,8 +2322,6 @@ void irdma_modify_qp_to_err(struct irdma_sc_qp *sc_qp) struct irdma_qp *qp = sc_qp->qp_uk.back_qp; struct ib_qp_attr attr; - if (qp->iwdev->rf->reset) - return; attr.qp_state = IB_QPS_ERR; if (rdma_protocol_roce(qp->ibqp.device, 1)) diff --git a/drivers/infiniband/hw/irdma/verbs.c b/drivers/infiniband/hw/irdma/verbs.c index 7251cd7a2147..95f590c10c05 100644 --- a/drivers/infiniband/hw/irdma/verbs.c +++ b/drivers/infiniband/hw/irdma/verbs.c @@ -558,7 +558,8 @@ static int irdma_destroy_qp(struct ib_qp *ibqp, struct ib_udata *udata) } irdma_qp_rem_ref(&iwqp->ibqp); - wait_for_completion(&iwqp->free_qp); + if (!iwdev->rf->reset) + wait_for_completion(&iwqp->free_qp); irdma_free_lsmm_rsrc(iwqp); irdma_cqp_qp_destroy_cmd(&iwdev->rf->sc_dev, &iwqp->sc_qp); @@ -1105,6 +1106,7 @@ static int irdma_create_qp(struct ib_qp *ibqp, spin_lock_init(&iwqp->sc_qp.pfpdu.lock); iwqp->sig_all = init_attr->sq_sig_type == IB_SIGNAL_ALL_WR; rf->qp_table[qp_num] = iwqp; + init_completion(&iwqp->free_qp); if (udata) { /* GEN_1 legacy support with libi40iw does not have expanded uresp struct */ @@ -1129,7 +1131,6 @@ static int irdma_create_qp(struct ib_qp *ibqp, } } - init_completion(&iwqp->free_qp); return 0; error: @@ -1462,8 +1463,6 @@ int irdma_modify_qp_roce(struct ib_qp *ibqp, struct ib_qp_attr *attr, ctx_info->remote_atomics_en = true; } - wait_event(iwqp->mod_qp_waitq, !atomic_read(&iwqp->hw_mod_qp_pend)); - ibdev_dbg(&iwdev->ibdev, "VERBS: caller: %pS qp_id=%d to_ibqpstate=%d ibqpstate=%d irdma_qpstate=%d attr_mask=0x%x\n", __builtin_return_address(0), ibqp->qp_num, attr->qp_state, @@ -1540,6 +1539,7 @@ int irdma_modify_qp_roce(struct ib_qp *ibqp, struct ib_qp_attr *attr, case IB_QPS_ERR: case IB_QPS_RESET: if (iwqp->iwarp_state == IRDMA_QP_STATE_ERROR) { + iwqp->ibqp_state = attr->qp_state; spin_unlock_irqrestore(&iwqp->lock, flags); if (udata && udata->inlen) { if (ib_copy_from_udata(&ureq, udata, @@ -1745,6 +1745,7 @@ int irdma_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask, case IB_QPS_ERR: case IB_QPS_RESET: if (iwqp->iwarp_state == IRDMA_QP_STATE_ERROR) { + iwqp->ibqp_state = attr->qp_state; spin_unlock_irqrestore(&iwqp->lock, flags); if (udata && udata->inlen) { if (ib_copy_from_udata(&ureq, udata, @@ -3723,6 +3724,7 @@ static int irdma_rereg_mr_trans(struct irdma_mr *iwmr, u64 start, u64 len, err: ib_umem_release(region); + iwmr->region = NULL; return err; } diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index bf4accf3f581..d6fc3d6006bb 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c @@ -313,6 +313,8 @@ static const struct xpad_device { { 0x1532, 0x0a00, "Razer Atrox Arcade Stick", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOXONE }, { 0x1532, 0x0a03, "Razer Wildcat", 0, XTYPE_XBOXONE }, { 0x1532, 0x0a29, "Razer Wolverine V2", 0, XTYPE_XBOXONE }, + { 0x1532, 0x0a57, "Razer Wolverine V3 Pro (Wired)", 0, XTYPE_XBOX360 }, + { 0x1532, 0x0a59, "Razer Wolverine V3 Pro (2.4 GHz Dongle)", 0, XTYPE_XBOX360 }, { 0x15e4, 0x3f00, "Power A Mini Pro Elite", 0, XTYPE_XBOX360 }, { 0x15e4, 0x3f0a, "Xbox Airflo wired controller", 0, XTYPE_XBOX360 }, { 0x15e4, 0x3f10, "Batarang Xbox 360 controller", 0, XTYPE_XBOX360 }, @@ -360,6 +362,8 @@ static const struct xpad_device { { 0x1bad, 0xfd00, "Razer Onza TE", 0, XTYPE_XBOX360 }, { 0x1bad, 0xfd01, "Razer Onza", 0, XTYPE_XBOX360 }, { 0x1ee9, 0x1590, "ZOTAC Gaming Zone", 0, XTYPE_XBOX360 }, + { 0x20bc, 0x5134, "BETOP BTP-KP50B Xinput Dongle", 0, XTYPE_XBOX360 }, + { 0x20bc, 0x514a, "BETOP BTP-KP50C Xinput Dongle", 0, XTYPE_XBOX360 }, { 0x20d6, 0x2001, "BDA Xbox Series X Wired Controller", 0, XTYPE_XBOXONE }, { 0x20d6, 0x2009, "PowerA Enhanced Wired Controller for Xbox Series X|S", 0, XTYPE_XBOXONE }, { 0x20d6, 0x2064, "PowerA Wired Controller for Xbox", MAP_SHARE_BUTTON, XTYPE_XBOXONE }, @@ -562,6 +566,7 @@ static const struct usb_device_id xpad_table[] = { XPAD_XBOX360_VENDOR(0x1a86), /* Nanjing Qinheng Microelectronics (WCH) */ XPAD_XBOX360_VENDOR(0x1bad), /* Harmonix Rock Band guitar and drums */ XPAD_XBOX360_VENDOR(0x1ee9), /* ZOTAC Technology Limited */ + XPAD_XBOX360_VENDOR(0x20bc), /* BETOP wireless dongles */ XPAD_XBOX360_VENDOR(0x20d6), /* PowerA controllers */ XPAD_XBOXONE_VENDOR(0x20d6), /* PowerA controllers */ XPAD_XBOX360_VENDOR(0x2345), /* Machenike Controllers */ diff --git a/drivers/input/mouse/bcm5974.c b/drivers/input/mouse/bcm5974.c index 8e3cea9db365..e772bac3b64c 100644 --- a/drivers/input/mouse/bcm5974.c +++ b/drivers/input/mouse/bcm5974.c @@ -286,6 +286,8 @@ struct bcm5974 { const struct tp_finger *index[MAX_FINGERS]; /* finger index data */ struct input_mt_pos pos[MAX_FINGERS]; /* position array */ int slots[MAX_FINGERS]; /* slot assignments */ + struct work_struct mode_reset_work; + unsigned long last_mode_reset; }; /* trackpad finger block data, le16-aligned */ @@ -696,6 +698,32 @@ static int bcm5974_wellspring_mode(struct bcm5974 *dev, bool on) return retval; } +/* + * Mode switches sent before the control response are ignored. + * Fixing this state requires switching to normal mode and waiting + * about 1ms before switching back to wellspring mode. + */ +static void bcm5974_mode_reset_work(struct work_struct *work) +{ + struct bcm5974 *dev = container_of(work, struct bcm5974, mode_reset_work); + int error; + + guard(mutex)(&dev->pm_mutex); + dev->last_mode_reset = jiffies; + + error = bcm5974_wellspring_mode(dev, false); + if (error) { + dev_err(&dev->intf->dev, "reset to normal mode failed\n"); + return; + } + + fsleep(1000); + + error = bcm5974_wellspring_mode(dev, true); + if (error) + dev_err(&dev->intf->dev, "mode switch after reset failed\n"); +} + static void bcm5974_irq_button(struct urb *urb) { struct bcm5974 *dev = urb->context; @@ -752,10 +780,20 @@ static void bcm5974_irq_trackpad(struct urb *urb) if (dev->tp_urb->actual_length == 2) goto exit; - if (report_tp_state(dev, dev->tp_urb->actual_length)) + if (report_tp_state(dev, dev->tp_urb->actual_length)) { dprintk(1, "bcm5974: bad trackpad package, length: %d\n", dev->tp_urb->actual_length); + /* + * Receiving a HID packet means we aren't in wellspring mode. + * If we haven't tried a reset in the last second, try now. + */ + if (dev->tp_urb->actual_length == 8 && + time_after(jiffies, dev->last_mode_reset + msecs_to_jiffies(1000))) { + schedule_work(&dev->mode_reset_work); + } + } + exit: error = usb_submit_urb(dev->tp_urb, GFP_ATOMIC); if (error) @@ -906,6 +944,7 @@ static int bcm5974_probe(struct usb_interface *iface, dev->intf = iface; dev->input = input_dev; dev->cfg = *cfg; + INIT_WORK(&dev->mode_reset_work, bcm5974_mode_reset_work); mutex_init(&dev->pm_mutex); /* setup urbs */ @@ -998,6 +1037,7 @@ static void bcm5974_disconnect(struct usb_interface *iface) { struct bcm5974 *dev = usb_get_intfdata(iface); + disable_work_sync(&dev->mode_reset_work); usb_set_intfdata(iface, NULL); input_unregister_device(dev->input); diff --git a/drivers/input/rmi4/rmi_f54.c b/drivers/input/rmi4/rmi_f54.c index ac4041a69fcd..61909e1a39e2 100644 --- a/drivers/input/rmi4/rmi_f54.c +++ b/drivers/input/rmi4/rmi_f54.c @@ -538,6 +538,8 @@ static void rmi_f54_work(struct work_struct *work) int error; int i; + mutex_lock(&f54->data_mutex); + report_size = rmi_f54_get_report_size(f54); if (report_size == 0) { dev_err(&fn->dev, "Bad report size, report type=%d\n", @@ -546,8 +548,6 @@ static void rmi_f54_work(struct work_struct *work) goto error; /* retry won't help */ } - mutex_lock(&f54->data_mutex); - /* * Need to check if command has completed. * If not try again later. diff --git a/drivers/input/serio/i8042-acpipnpio.h b/drivers/input/serio/i8042-acpipnpio.h index d2cf940b105a..8ebdf4fb9030 100644 --- a/drivers/input/serio/i8042-acpipnpio.h +++ b/drivers/input/serio/i8042-acpipnpio.h @@ -1189,6 +1189,13 @@ static const struct dmi_system_id i8042_dmi_quirk_table[] __initconst = { }, { .matches = { + DMI_MATCH(DMI_BOARD_NAME, "X6KK45xU_X6SP45xU"), + }, + .driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS | + SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP) + }, + { + .matches = { DMI_MATCH(DMI_BOARD_NAME, "WUJIE Series-X5SP4NAG"), }, .driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS | diff --git a/drivers/interconnect/qcom/sm8450.c b/drivers/interconnect/qcom/sm8450.c index 669a638bf3ef..c88327d200ac 100644 --- a/drivers/interconnect/qcom/sm8450.c +++ b/drivers/interconnect/qcom/sm8450.c @@ -800,7 +800,7 @@ static struct qcom_icc_node qhs_compute_cfg = { .channels = 1, .buswidth = 4, .num_links = 1, - .link_nodes = { MASTER_CDSP_NOC_CFG }, + .link_nodes = { &qhm_nsp_noc_config }, }; static struct qcom_icc_node qhs_cpr_cx = { @@ -874,7 +874,7 @@ static struct qcom_icc_node qhs_lpass_cfg = { .channels = 1, .buswidth = 4, .num_links = 1, - .link_nodes = { MASTER_CNOC_LPASS_AG_NOC }, + .link_nodes = { &qhm_config_noc }, }; static struct qcom_icc_node qhs_mss_cfg = { diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c index 5dac64be61bb..94d514169642 100644 --- a/drivers/iommu/dma-iommu.c +++ b/drivers/iommu/dma-iommu.c @@ -1211,7 +1211,7 @@ dma_addr_t iommu_dma_map_phys(struct device *dev, phys_addr_t phys, size_t size, */ if (dev_use_swiotlb(dev, size, dir) && iova_unaligned(iovad, phys, size)) { - if (attrs & DMA_ATTR_MMIO) + if (attrs & (DMA_ATTR_MMIO | DMA_ATTR_REQUIRE_COHERENT)) return DMA_MAPPING_ERROR; phys = iommu_dma_map_swiotlb(dev, phys, size, dir, attrs); @@ -1223,7 +1223,8 @@ dma_addr_t iommu_dma_map_phys(struct device *dev, phys_addr_t phys, size_t size, arch_sync_dma_for_device(phys, size, dir); iova = __iommu_dma_map(dev, phys, size, prot, dma_mask); - if (iova == DMA_MAPPING_ERROR && !(attrs & DMA_ATTR_MMIO)) + if (iova == DMA_MAPPING_ERROR && + !(attrs & (DMA_ATTR_MMIO | DMA_ATTR_REQUIRE_COHERENT))) swiotlb_tbl_unmap_single(dev, phys, size, dir, attrs); return iova; } @@ -1233,7 +1234,7 @@ void iommu_dma_unmap_phys(struct device *dev, dma_addr_t dma_handle, { phys_addr_t phys; - if (attrs & DMA_ATTR_MMIO) { + if (attrs & (DMA_ATTR_MMIO | DMA_ATTR_REQUIRE_COHERENT)) { __iommu_dma_unmap(dev, dma_handle, size); return; } @@ -1945,9 +1946,21 @@ int dma_iova_link(struct device *dev, struct dma_iova_state *state, if (WARN_ON_ONCE(iova_start_pad && offset > 0)) return -EIO; + /* + * DMA_IOVA_USE_SWIOTLB is set on state after some entry + * took SWIOTLB path, which we were supposed to prevent + * for DMA_ATTR_REQUIRE_COHERENT attribute. + */ + if (WARN_ON_ONCE((state->__size & DMA_IOVA_USE_SWIOTLB) && + (attrs & DMA_ATTR_REQUIRE_COHERENT))) + return -EOPNOTSUPP; + + if (!dev_is_dma_coherent(dev) && (attrs & DMA_ATTR_REQUIRE_COHERENT)) + return -EOPNOTSUPP; + if (dev_use_swiotlb(dev, size, dir) && iova_unaligned(iovad, phys, size)) { - if (attrs & DMA_ATTR_MMIO) + if (attrs & (DMA_ATTR_MMIO | DMA_ATTR_REQUIRE_COHERENT)) return -EPERM; return iommu_dma_iova_link_swiotlb(dev, state, phys, offset, diff --git a/drivers/iommu/generic_pt/fmt/amdv1.h b/drivers/iommu/generic_pt/fmt/amdv1.h index 3b2c41d9654d..8d11b08291d7 100644 --- a/drivers/iommu/generic_pt/fmt/amdv1.h +++ b/drivers/iommu/generic_pt/fmt/amdv1.h @@ -191,7 +191,7 @@ static inline enum pt_entry_type amdv1pt_load_entry_raw(struct pt_state *pts) } #define pt_load_entry_raw amdv1pt_load_entry_raw -static inline void +static __always_inline void amdv1pt_install_leaf_entry(struct pt_state *pts, pt_oaddr_t oa, unsigned int oasz_lg2, const struct pt_write_attrs *attrs) diff --git a/drivers/iommu/generic_pt/iommu_pt.h b/drivers/iommu/generic_pt/iommu_pt.h index 3e33fe64feab..7e7a6e7abdee 100644 --- a/drivers/iommu/generic_pt/iommu_pt.h +++ b/drivers/iommu/generic_pt/iommu_pt.h @@ -1057,7 +1057,7 @@ size_t DOMAIN_NS(unmap_pages)(struct iommu_domain *domain, unsigned long iova, pt_walk_range(&range, __unmap_range, &unmap); - gather_range_pages(iotlb_gather, iommu_table, iova, len, + gather_range_pages(iotlb_gather, iommu_table, iova, unmap.unmapped, &unmap.free_list); return unmap.unmapped; diff --git a/drivers/irqchip/irq-qcom-mpm.c b/drivers/irqchip/irq-qcom-mpm.c index 83f31ea657b7..181320528a47 100644 --- a/drivers/irqchip/irq-qcom-mpm.c +++ b/drivers/irqchip/irq-qcom-mpm.c @@ -306,6 +306,8 @@ static int mpm_pd_power_off(struct generic_pm_domain *genpd) if (ret < 0) return ret; + mbox_client_txdone(priv->mbox_chan, 0); + return 0; } @@ -434,6 +436,7 @@ static int qcom_mpm_probe(struct platform_device *pdev, struct device_node *pare } priv->mbox_client.dev = dev; + priv->mbox_client.knows_txdone = true; priv->mbox_chan = mbox_request_channel(&priv->mbox_client, 0); if (IS_ERR(priv->mbox_chan)) { ret = PTR_ERR(priv->mbox_chan); diff --git a/drivers/irqchip/irq-renesas-rzv2h.c b/drivers/irqchip/irq-renesas-rzv2h.c index da2bc43a0e12..03e93b061edd 100644 --- a/drivers/irqchip/irq-renesas-rzv2h.c +++ b/drivers/irqchip/irq-renesas-rzv2h.c @@ -621,7 +621,7 @@ static int rzv2h_icu_probe_common(struct platform_device *pdev, struct device_no return 0; pm_put: - pm_runtime_put(&pdev->dev); + pm_runtime_put_sync(&pdev->dev); return ret; } diff --git a/drivers/irqchip/irq-riscv-aplic-main.c b/drivers/irqchip/irq-riscv-aplic-main.c index 9f53979b6962..d9afb6ae98cf 100644 --- a/drivers/irqchip/irq-riscv-aplic-main.c +++ b/drivers/irqchip/irq-riscv-aplic-main.c @@ -150,7 +150,7 @@ static void aplic_pm_remove(void *data) struct device *dev = priv->dev; list_del(&priv->head); - if (dev->pm_domain) + if (dev->pm_domain && dev->of_node) dev_pm_genpd_remove_notifier(dev); } @@ -165,7 +165,7 @@ static int aplic_pm_add(struct device *dev, struct aplic_priv *priv) priv->saved_hw_regs.srcs = srcs; list_add(&priv->head, &aplics); - if (dev->pm_domain) { + if (dev->pm_domain && dev->of_node) { priv->genpd_nb.notifier_call = aplic_pm_notifier; ret = dev_pm_genpd_add_notifier(dev, &priv->genpd_nb); if (ret) diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c index aa4dd7e7cf5a..8e25f970fd12 100644 --- a/drivers/media/i2c/ccs/ccs-core.c +++ b/drivers/media/i2c/ccs/ccs-core.c @@ -3080,8 +3080,6 @@ static int ccs_init_state(struct v4l2_subdev *sd, struct v4l2_rect *crop = v4l2_subdev_state_get_crop(sd_state, pad); - guard(mutex)(&sensor->mutex); - ccs_get_native_size(ssd, crop); fmt->width = crop->width; diff --git a/drivers/media/mc/mc-request.c b/drivers/media/mc/mc-request.c index c7c7d4a86c6b..13e77648807c 100644 --- a/drivers/media/mc/mc-request.c +++ b/drivers/media/mc/mc-request.c @@ -192,6 +192,8 @@ static long media_request_ioctl_reinit(struct media_request *req) struct media_device *mdev = req->mdev; unsigned long flags; + mutex_lock(&mdev->req_queue_mutex); + spin_lock_irqsave(&req->lock, flags); if (req->state != MEDIA_REQUEST_STATE_IDLE && req->state != MEDIA_REQUEST_STATE_COMPLETE) { @@ -199,6 +201,7 @@ static long media_request_ioctl_reinit(struct media_request *req) "request: %s not in idle or complete state, cannot reinit\n", req->debug_str); spin_unlock_irqrestore(&req->lock, flags); + mutex_unlock(&mdev->req_queue_mutex); return -EBUSY; } if (req->access_count) { @@ -206,6 +209,7 @@ static long media_request_ioctl_reinit(struct media_request *req) "request: %s is being accessed, cannot reinit\n", req->debug_str); spin_unlock_irqrestore(&req->lock, flags); + mutex_unlock(&mdev->req_queue_mutex); return -EBUSY; } req->state = MEDIA_REQUEST_STATE_CLEANING; @@ -216,6 +220,7 @@ static long media_request_ioctl_reinit(struct media_request *req) spin_lock_irqsave(&req->lock, flags); req->state = MEDIA_REQUEST_STATE_IDLE; spin_unlock_irqrestore(&req->lock, flags); + mutex_unlock(&mdev->req_queue_mutex); return 0; } diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c index 28267ee30190..3119f3bc9f98 100644 --- a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc-common.c @@ -500,11 +500,15 @@ void rkvdec_hevc_run_preamble(struct rkvdec_ctx *ctx, ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl, V4L2_CID_STATELESS_HEVC_EXT_SPS_ST_RPS); run->ext_sps_st_rps = ctrl ? ctrl->p_cur.p : NULL; + } else { + run->ext_sps_st_rps = NULL; } if (ctx->has_sps_lt_rps) { ctrl = v4l2_ctrl_find(&ctx->ctrl_hdl, V4L2_CID_STATELESS_HEVC_EXT_SPS_LT_RPS); run->ext_sps_lt_rps = ctrl ? ctrl->p_cur.p : NULL; + } else { + run->ext_sps_lt_rps = NULL; } rkvdec_run_preamble(ctx, &run->base); diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-h264.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-h264.c index 97f1efde2e47..fb4f849d7366 100644 --- a/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-h264.c +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-h264.c @@ -130,7 +130,7 @@ struct rkvdec_h264_ctx { struct vdpu383_regs_h26x regs; }; -static void set_field_order_cnt(struct rkvdec_pps *pps, const struct v4l2_h264_dpb_entry *dpb) +static noinline_for_stack void set_field_order_cnt(struct rkvdec_pps *pps, const struct v4l2_h264_dpb_entry *dpb) { pps->top_field_order_cnt0 = dpb[0].top_field_order_cnt; pps->bot_field_order_cnt0 = dpb[0].bottom_field_order_cnt; @@ -166,6 +166,31 @@ static void set_field_order_cnt(struct rkvdec_pps *pps, const struct v4l2_h264_d pps->bot_field_order_cnt15 = dpb[15].bottom_field_order_cnt; } +static noinline_for_stack void set_dec_params(struct rkvdec_pps *pps, const struct v4l2_ctrl_h264_decode_params *dec_params) +{ + const struct v4l2_h264_dpb_entry *dpb = dec_params->dpb; + + for (int i = 0; i < ARRAY_SIZE(dec_params->dpb); i++) { + if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM) + pps->is_longterm |= (1 << i); + pps->ref_field_flags |= + (!!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_FIELD)) << i; + pps->ref_colmv_use_flag |= + (!!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE)) << i; + pps->ref_topfield_used |= + (!!(dpb[i].fields & V4L2_H264_TOP_FIELD_REF)) << i; + pps->ref_botfield_used |= + (!!(dpb[i].fields & V4L2_H264_BOTTOM_FIELD_REF)) << i; + } + pps->pic_field_flag = + !!(dec_params->flags & V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC); + pps->pic_associated_flag = + !!(dec_params->flags & V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD); + + pps->cur_top_field = dec_params->top_field_order_cnt; + pps->cur_bot_field = dec_params->bottom_field_order_cnt; +} + static void assemble_hw_pps(struct rkvdec_ctx *ctx, struct rkvdec_h264_run *run) { @@ -177,7 +202,6 @@ static void assemble_hw_pps(struct rkvdec_ctx *ctx, struct rkvdec_h264_priv_tbl *priv_tbl = h264_ctx->priv_tbl.cpu; struct rkvdec_sps_pps *hw_ps; u32 pic_width, pic_height; - u32 i; /* * HW read the SPS/PPS information from PPS packet index by PPS id. @@ -261,28 +285,8 @@ static void assemble_hw_pps(struct rkvdec_ctx *ctx, !!(pps->flags & V4L2_H264_PPS_FLAG_SCALING_MATRIX_PRESENT); set_field_order_cnt(&hw_ps->pps, dpb); + set_dec_params(&hw_ps->pps, dec_params); - for (i = 0; i < ARRAY_SIZE(dec_params->dpb); i++) { - if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM) - hw_ps->pps.is_longterm |= (1 << i); - - hw_ps->pps.ref_field_flags |= - (!!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_FIELD)) << i; - hw_ps->pps.ref_colmv_use_flag |= - (!!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE)) << i; - hw_ps->pps.ref_topfield_used |= - (!!(dpb[i].fields & V4L2_H264_TOP_FIELD_REF)) << i; - hw_ps->pps.ref_botfield_used |= - (!!(dpb[i].fields & V4L2_H264_BOTTOM_FIELD_REF)) << i; - } - - hw_ps->pps.pic_field_flag = - !!(dec_params->flags & V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC); - hw_ps->pps.pic_associated_flag = - !!(dec_params->flags & V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD); - - hw_ps->pps.cur_top_field = dec_params->top_field_order_cnt; - hw_ps->pps.cur_bot_field = dec_params->bottom_field_order_cnt; } static void rkvdec_write_regs(struct rkvdec_ctx *ctx) diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-vp9.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-vp9.c index e4cdd2122873..2751f5396ee8 100644 --- a/drivers/media/platform/rockchip/rkvdec/rkvdec-vp9.c +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-vp9.c @@ -893,7 +893,8 @@ out_update_last: update_ctx_last_info(vp9_ctx); } -static void rkvdec_init_v4l2_vp9_count_tbl(struct rkvdec_ctx *ctx) +static noinline_for_stack void +rkvdec_init_v4l2_vp9_count_tbl(struct rkvdec_ctx *ctx) { struct rkvdec_vp9_ctx *vp9_ctx = ctx->priv; struct rkvdec_vp9_intra_frame_symbol_counts *intra_cnts = vp9_ctx->count_tbl.cpu; diff --git a/drivers/media/platform/synopsys/Kconfig b/drivers/media/platform/synopsys/Kconfig index e798ec00b189..bf2ac092fbb3 100644 --- a/drivers/media/platform/synopsys/Kconfig +++ b/drivers/media/platform/synopsys/Kconfig @@ -7,6 +7,7 @@ config VIDEO_DW_MIPI_CSI2RX depends on VIDEO_DEV depends on V4L_PLATFORM_DRIVERS depends on PM && COMMON_CLK + select GENERIC_PHY_MIPI_DPHY select MEDIA_CONTROLLER select V4L2_FWNODE select VIDEO_V4L2_SUBDEV_API diff --git a/drivers/media/platform/synopsys/dw-mipi-csi2rx.c b/drivers/media/platform/synopsys/dw-mipi-csi2rx.c index 170346ae1a59..4d96171a650b 100644 --- a/drivers/media/platform/synopsys/dw-mipi-csi2rx.c +++ b/drivers/media/platform/synopsys/dw-mipi-csi2rx.c @@ -301,7 +301,7 @@ dw_mipi_csi2rx_enum_mbus_code(struct v4l2_subdev *sd, return 0; case DW_MIPI_CSI2RX_PAD_SINK: - if (code->index > csi2->formats_num) + if (code->index >= csi2->formats_num) return -EINVAL; code->code = csi2->formats[code->index].code; diff --git a/drivers/media/platform/verisilicon/imx8m_vpu_hw.c b/drivers/media/platform/verisilicon/imx8m_vpu_hw.c index 6f8e43b7f157..fa4224de4b99 100644 --- a/drivers/media/platform/verisilicon/imx8m_vpu_hw.c +++ b/drivers/media/platform/verisilicon/imx8m_vpu_hw.c @@ -343,7 +343,7 @@ const struct hantro_variant imx8mq_vpu_variant = { .num_regs = ARRAY_SIZE(imx8mq_reg_names) }; -static const struct of_device_id imx8mq_vpu_shared_resources[] __initconst = { +static const struct of_device_id imx8mq_vpu_shared_resources[] = { { .compatible = "nxp,imx8mq-vpu-g1", }, { .compatible = "nxp,imx8mq-vpu-g2", }, { /* sentinel */ } diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c index 40c76c051da2..f6c8e3223796 100644 --- a/drivers/media/usb/uvc/uvc_video.c +++ b/drivers/media/usb/uvc/uvc_video.c @@ -1751,7 +1751,8 @@ static void uvc_video_complete(struct urb *urb) /* * Free transfer buffers. */ -static void uvc_free_urb_buffers(struct uvc_streaming *stream) +static void uvc_free_urb_buffers(struct uvc_streaming *stream, + unsigned int size) { struct usb_device *udev = stream->dev->udev; struct uvc_urb *uvc_urb; @@ -1760,7 +1761,7 @@ static void uvc_free_urb_buffers(struct uvc_streaming *stream) if (!uvc_urb->buffer) continue; - usb_free_noncoherent(udev, stream->urb_size, uvc_urb->buffer, + usb_free_noncoherent(udev, size, uvc_urb->buffer, uvc_stream_dir(stream), uvc_urb->sgt); uvc_urb->buffer = NULL; uvc_urb->sgt = NULL; @@ -1820,7 +1821,7 @@ static int uvc_alloc_urb_buffers(struct uvc_streaming *stream, if (!uvc_alloc_urb_buffer(stream, uvc_urb, urb_size, gfp_flags)) { - uvc_free_urb_buffers(stream); + uvc_free_urb_buffers(stream, urb_size); break; } @@ -1868,7 +1869,7 @@ static void uvc_video_stop_transfer(struct uvc_streaming *stream, } if (free_buffers) - uvc_free_urb_buffers(stream); + uvc_free_urb_buffers(stream, stream->urb_size); } /* diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 37d33d4a363d..a2b650f4ec3c 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -3082,13 +3082,14 @@ static long __video_do_ioctl(struct file *file, } /* - * We need to serialize streamon/off with queueing new requests. + * We need to serialize streamon/off/reqbufs with queueing new requests. * These ioctls may trigger the cancellation of a streaming * operation, and that should not be mixed with queueing a new * request at the same time. */ if (v4l2_device_supports_requests(vfd->v4l2_dev) && - (cmd == VIDIOC_STREAMON || cmd == VIDIOC_STREAMOFF)) { + (cmd == VIDIOC_STREAMON || cmd == VIDIOC_STREAMOFF || + cmd == VIDIOC_REQBUFS)) { req_queue_lock = &vfd->v4l2_dev->mdev->req_queue_mutex; if (mutex_lock_interruptible(req_queue_lock)) diff --git a/drivers/misc/fastrpc.c b/drivers/misc/fastrpc.c index 47356a5d5804..1080f9acf70a 100644 --- a/drivers/misc/fastrpc.c +++ b/drivers/misc/fastrpc.c @@ -1401,6 +1401,7 @@ err_invoke: } err_map: fastrpc_buf_free(fl->cctx->remote_heap); + fl->cctx->remote_heap = NULL; err_name: kfree(name); err: @@ -2389,8 +2390,10 @@ static int fastrpc_rpmsg_probe(struct rpmsg_device *rpdev) if (!err) { src_perms = BIT(QCOM_SCM_VMID_HLOS); - qcom_scm_assign_mem(res.start, resource_size(&res), &src_perms, + err = qcom_scm_assign_mem(res.start, resource_size(&res), &src_perms, data->vmperms, data->vmcount); + if (err) + goto err_free_data; } } diff --git a/drivers/misc/lis3lv02d/lis3lv02d.c b/drivers/misc/lis3lv02d/lis3lv02d.c index 9c68f8b1d5d6..21e8ad0a7444 100644 --- a/drivers/misc/lis3lv02d/lis3lv02d.c +++ b/drivers/misc/lis3lv02d/lis3lv02d.c @@ -1230,10 +1230,12 @@ int lis3lv02d_init_device(struct lis3lv02d *lis3) else thread_fn = NULL; + if (thread_fn) + irq_flags |= IRQF_ONESHOT; + err = request_threaded_irq(lis3->irq, lis302dl_interrupt, thread_fn, - IRQF_TRIGGER_RISING | IRQF_ONESHOT | - irq_flags, + irq_flags | IRQF_TRIGGER_RISING, DRIVER_NAME, lis3); if (err < 0) { diff --git a/drivers/misc/mei/Kconfig b/drivers/misc/mei/Kconfig index 5902dd1ee44b..094fb1dde0fe 100644 --- a/drivers/misc/mei/Kconfig +++ b/drivers/misc/mei/Kconfig @@ -3,6 +3,7 @@ config INTEL_MEI tristate "Intel Management Engine Interface" depends on PCI + depends on X86 || DRM_XE!=n || COMPILE_TEST default X86_64 || MATOM help The Intel Management Engine (Intel ME) provides Manageability, diff --git a/drivers/misc/mei/hw-me.c b/drivers/misc/mei/hw-me.c index d4612c659784..1e4a41ac428f 100644 --- a/drivers/misc/mei/hw-me.c +++ b/drivers/misc/mei/hw-me.c @@ -1337,19 +1337,13 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id) /* check if we need to start the dev */ if (!mei_host_is_ready(dev)) { if (mei_hw_is_ready(dev)) { - /* synchronized by dev mutex */ - if (waitqueue_active(&dev->wait_hw_ready)) { - dev_dbg(&dev->dev, "we need to start the dev.\n"); - dev->recvd_hw_ready = true; - wake_up(&dev->wait_hw_ready); - } else if (dev->dev_state != MEI_DEV_UNINITIALIZED && - dev->dev_state != MEI_DEV_POWERING_DOWN && - dev->dev_state != MEI_DEV_POWER_DOWN) { + if (dev->dev_state == MEI_DEV_ENABLED) { dev_dbg(&dev->dev, "Force link reset.\n"); schedule_work(&dev->reset_work); } else { - dev_dbg(&dev->dev, "Ignore this interrupt in state = %d\n", - dev->dev_state); + dev_dbg(&dev->dev, "we need to start the dev.\n"); + dev->recvd_hw_ready = true; + wake_up(&dev->wait_hw_ready); } } else { dev_dbg(&dev->dev, "Spurious Interrupt\n"); diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 33f414d03ab9..a5484d11553d 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -5326,7 +5326,7 @@ static netdev_tx_t bond_xmit_broadcast(struct sk_buff *skb, if (!(bond_slave_is_up(slave) && slave->link == BOND_LINK_UP)) continue; - if (bond_is_last_slave(bond, slave)) { + if (i + 1 == slaves_count) { skb2 = skb; skb_used = true; } else { diff --git a/drivers/net/can/dev/netlink.c b/drivers/net/can/dev/netlink.c index 0498198a4696..766d455950f5 100644 --- a/drivers/net/can/dev/netlink.c +++ b/drivers/net/can/dev/netlink.c @@ -601,7 +601,9 @@ static int can_changelink(struct net_device *dev, struct nlattr *tb[], /* We need synchronization with dev->stop() */ ASSERT_RTNL(); - can_ctrlmode_changelink(dev, data, extack); + err = can_ctrlmode_changelink(dev, data, extack); + if (err) + return err; if (data[IFLA_CAN_BITTIMING]) { struct can_bittiming bt; diff --git a/drivers/net/can/spi/mcp251x.c b/drivers/net/can/spi/mcp251x.c index bb7782582f40..0d0190ae094a 100644 --- a/drivers/net/can/spi/mcp251x.c +++ b/drivers/net/can/spi/mcp251x.c @@ -1225,7 +1225,11 @@ static int mcp251x_open(struct net_device *net) } mutex_lock(&priv->mcp_lock); - mcp251x_power_enable(priv->transceiver, 1); + ret = mcp251x_power_enable(priv->transceiver, 1); + if (ret) { + dev_err(&spi->dev, "failed to enable transceiver power: %pe\n", ERR_PTR(ret)); + goto out_close_candev; + } priv->force_quit = 0; priv->tx_skb = NULL; @@ -1272,6 +1276,7 @@ out_free_irq: mcp251x_hw_sleep(spi); out_close: mcp251x_power_enable(priv->transceiver, 0); +out_close_candev: close_candev(net); mutex_unlock(&priv->mcp_lock); if (release_irq) @@ -1516,11 +1521,25 @@ static int __maybe_unused mcp251x_can_resume(struct device *dev) { struct spi_device *spi = to_spi_device(dev); struct mcp251x_priv *priv = spi_get_drvdata(spi); + int ret = 0; - if (priv->after_suspend & AFTER_SUSPEND_POWER) - mcp251x_power_enable(priv->power, 1); - if (priv->after_suspend & AFTER_SUSPEND_UP) - mcp251x_power_enable(priv->transceiver, 1); + if (priv->after_suspend & AFTER_SUSPEND_POWER) { + ret = mcp251x_power_enable(priv->power, 1); + if (ret) { + dev_err(dev, "failed to restore power: %pe\n", ERR_PTR(ret)); + return ret; + } + } + + if (priv->after_suspend & AFTER_SUSPEND_UP) { + ret = mcp251x_power_enable(priv->transceiver, 1); + if (ret) { + dev_err(dev, "failed to restore transceiver power: %pe\n", ERR_PTR(ret)); + if (priv->after_suspend & AFTER_SUSPEND_POWER) + mcp251x_power_enable(priv->power, 0); + return ret; + } + } if (priv->after_suspend & (AFTER_SUSPEND_POWER | AFTER_SUSPEND_UP)) queue_work(priv->wq, &priv->restart_work); diff --git a/drivers/net/ethernet/airoha/airoha_eth.c b/drivers/net/ethernet/airoha/airoha_eth.c index 56cf9a926a83..95ba99b89428 100644 --- a/drivers/net/ethernet/airoha/airoha_eth.c +++ b/drivers/net/ethernet/airoha/airoha_eth.c @@ -794,18 +794,34 @@ static int airoha_qdma_init_rx_queue(struct airoha_queue *q, static void airoha_qdma_cleanup_rx_queue(struct airoha_queue *q) { - struct airoha_eth *eth = q->qdma->eth; + struct airoha_qdma *qdma = q->qdma; + struct airoha_eth *eth = qdma->eth; + int qid = q - &qdma->q_rx[0]; while (q->queued) { struct airoha_queue_entry *e = &q->entry[q->tail]; + struct airoha_qdma_desc *desc = &q->desc[q->tail]; struct page *page = virt_to_head_page(e->buf); dma_sync_single_for_cpu(eth->dev, e->dma_addr, e->dma_len, page_pool_get_dma_dir(q->page_pool)); page_pool_put_full_page(q->page_pool, page, false); + /* Reset DMA descriptor */ + WRITE_ONCE(desc->ctrl, 0); + WRITE_ONCE(desc->addr, 0); + WRITE_ONCE(desc->data, 0); + WRITE_ONCE(desc->msg0, 0); + WRITE_ONCE(desc->msg1, 0); + WRITE_ONCE(desc->msg2, 0); + WRITE_ONCE(desc->msg3, 0); + q->tail = (q->tail + 1) % q->ndesc; q->queued--; } + + q->head = q->tail; + airoha_qdma_rmw(qdma, REG_RX_DMA_IDX(qid), RX_RING_DMA_IDX_MASK, + FIELD_PREP(RX_RING_DMA_IDX_MASK, q->tail)); } static int airoha_qdma_init_rx(struct airoha_qdma *qdma) @@ -2946,6 +2962,8 @@ static int airoha_register_gdm_devices(struct airoha_eth *eth) return err; } + set_bit(DEV_STATE_REGISTERED, ð->state); + return 0; } diff --git a/drivers/net/ethernet/airoha/airoha_eth.h b/drivers/net/ethernet/airoha/airoha_eth.h index 20e602d61e61..a97903569335 100644 --- a/drivers/net/ethernet/airoha/airoha_eth.h +++ b/drivers/net/ethernet/airoha/airoha_eth.h @@ -88,6 +88,7 @@ enum { enum { DEV_STATE_INITIALIZED, + DEV_STATE_REGISTERED, }; enum { diff --git a/drivers/net/ethernet/airoha/airoha_ppe.c b/drivers/net/ethernet/airoha/airoha_ppe.c index 42dbe8f93231..c2c32b6833df 100644 --- a/drivers/net/ethernet/airoha/airoha_ppe.c +++ b/drivers/net/ethernet/airoha/airoha_ppe.c @@ -227,7 +227,9 @@ static int airoha_ppe_get_wdma_info(struct net_device *dev, const u8 *addr, if (!dev) return -ENODEV; + rcu_read_lock(); err = dev_fill_forward_path(dev, addr, &stack); + rcu_read_unlock(); if (err) return err; @@ -1366,6 +1368,13 @@ int airoha_ppe_setup_tc_block_cb(struct airoha_ppe_dev *dev, void *type_data) struct airoha_eth *eth = ppe->eth; int err = 0; + /* Netfilter flowtable can try to offload flower rules while not all + * the net_devices are registered or initialized. Delay offloading + * until all net_devices are registered in the system. + */ + if (!test_bit(DEV_STATE_REGISTERED, ð->state)) + return -EBUSY; + mutex_lock(&flow_offload_mutex); if (!eth->npu) diff --git a/drivers/net/ethernet/broadcom/Kconfig b/drivers/net/ethernet/broadcom/Kconfig index cd7dddeb91dd..9787c1857e13 100644 --- a/drivers/net/ethernet/broadcom/Kconfig +++ b/drivers/net/ethernet/broadcom/Kconfig @@ -25,7 +25,7 @@ config B44 select SSB select MII select PHYLIB - select FIXED_PHY if BCM47XX + select FIXED_PHY help If you have a network (Ethernet) controller of this type, say Y or M here. diff --git a/drivers/net/ethernet/broadcom/asp2/bcmasp.c b/drivers/net/ethernet/broadcom/asp2/bcmasp.c index aa6d8606849f..972474893a6b 100644 --- a/drivers/net/ethernet/broadcom/asp2/bcmasp.c +++ b/drivers/net/ethernet/broadcom/asp2/bcmasp.c @@ -1152,12 +1152,6 @@ void bcmasp_enable_wol(struct bcmasp_intf *intf, bool en) } } -static void bcmasp_wol_irq_destroy(struct bcmasp_priv *priv) -{ - if (priv->wol_irq > 0) - free_irq(priv->wol_irq, priv); -} - static void bcmasp_eee_fixup(struct bcmasp_intf *intf, bool en) { u32 reg, phy_lpi_overwrite; @@ -1255,7 +1249,7 @@ static int bcmasp_probe(struct platform_device *pdev) if (priv->irq <= 0) return -EINVAL; - priv->clk = devm_clk_get_optional_enabled(dev, "sw_asp"); + priv->clk = devm_clk_get_optional(dev, "sw_asp"); if (IS_ERR(priv->clk)) return dev_err_probe(dev, PTR_ERR(priv->clk), "failed to request clock\n"); @@ -1283,6 +1277,10 @@ static int bcmasp_probe(struct platform_device *pdev) bcmasp_set_pdata(priv, pdata); + ret = clk_prepare_enable(priv->clk); + if (ret) + return dev_err_probe(dev, ret, "failed to start clock\n"); + /* Enable all clocks to ensure successful probing */ bcmasp_core_clock_set(priv, ASP_CTRL_CLOCK_CTRL_ASP_ALL_DISABLE, 0); @@ -1294,8 +1292,10 @@ static int bcmasp_probe(struct platform_device *pdev) ret = devm_request_irq(&pdev->dev, priv->irq, bcmasp_isr, 0, pdev->name, priv); - if (ret) - return dev_err_probe(dev, ret, "failed to request ASP interrupt: %d", ret); + if (ret) { + dev_err(dev, "Failed to request ASP interrupt: %d", ret); + goto err_clock_disable; + } /* Register mdio child nodes */ of_platform_populate(dev->of_node, bcmasp_mdio_of_match, NULL, dev); @@ -1307,13 +1307,17 @@ static int bcmasp_probe(struct platform_device *pdev) priv->mda_filters = devm_kcalloc(dev, priv->num_mda_filters, sizeof(*priv->mda_filters), GFP_KERNEL); - if (!priv->mda_filters) - return -ENOMEM; + if (!priv->mda_filters) { + ret = -ENOMEM; + goto err_clock_disable; + } priv->net_filters = devm_kcalloc(dev, priv->num_net_filters, sizeof(*priv->net_filters), GFP_KERNEL); - if (!priv->net_filters) - return -ENOMEM; + if (!priv->net_filters) { + ret = -ENOMEM; + goto err_clock_disable; + } bcmasp_core_init_filters(priv); @@ -1322,7 +1326,8 @@ static int bcmasp_probe(struct platform_device *pdev) ports_node = of_find_node_by_name(dev->of_node, "ethernet-ports"); if (!ports_node) { dev_warn(dev, "No ports found\n"); - return -EINVAL; + ret = -EINVAL; + goto err_clock_disable; } i = 0; @@ -1344,8 +1349,6 @@ static int bcmasp_probe(struct platform_device *pdev) */ bcmasp_core_clock_set(priv, 0, ASP_CTRL_CLOCK_CTRL_ASP_ALL_DISABLE); - clk_disable_unprepare(priv->clk); - /* Now do the registration of the network ports which will take care * of managing the clock properly. */ @@ -1358,13 +1361,16 @@ static int bcmasp_probe(struct platform_device *pdev) count++; } + clk_disable_unprepare(priv->clk); + dev_info(dev, "Initialized %d port(s)\n", count); return ret; err_cleanup: - bcmasp_wol_irq_destroy(priv); bcmasp_remove_intfs(priv); +err_clock_disable: + clk_disable_unprepare(priv->clk); return ret; } @@ -1376,7 +1382,6 @@ static void bcmasp_remove(struct platform_device *pdev) if (!priv) return; - bcmasp_wol_irq_destroy(priv); bcmasp_remove_intfs(priv); } diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 0751c0e4581a..3f775196ef81 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -8045,6 +8045,8 @@ static int __bnxt_reserve_rings(struct bnxt *bp) ulp_msix = bnxt_get_avail_msix(bp, bp->ulp_num_msix_want); if (!ulp_msix) bnxt_set_ulp_stat_ctxs(bp, 0); + else + bnxt_set_dflt_ulp_stat_ctxs(bp); if (ulp_msix > bp->ulp_num_msix_want) ulp_msix = bp->ulp_num_msix_want; @@ -8671,7 +8673,7 @@ static int bnxt_hwrm_func_backing_store_qcaps_v2(struct bnxt *bp) struct hwrm_func_backing_store_qcaps_v2_output *resp; struct hwrm_func_backing_store_qcaps_v2_input *req; struct bnxt_ctx_mem_info *ctx = bp->ctx; - u16 type; + u16 type, next_type = 0; int rc; rc = hwrm_req_init(bp, req, HWRM_FUNC_BACKING_STORE_QCAPS_V2); @@ -8687,7 +8689,7 @@ static int bnxt_hwrm_func_backing_store_qcaps_v2(struct bnxt *bp) resp = hwrm_req_hold(bp, req); - for (type = 0; type < BNXT_CTX_V2_MAX; ) { + for (type = 0; type < BNXT_CTX_V2_MAX; type = next_type) { struct bnxt_ctx_mem_type *ctxm = &ctx->ctx_arr[type]; u8 init_val, init_off, i; u32 max_entries; @@ -8700,7 +8702,7 @@ static int bnxt_hwrm_func_backing_store_qcaps_v2(struct bnxt *bp) if (rc) goto ctx_done; flags = le32_to_cpu(resp->flags); - type = le16_to_cpu(resp->next_valid_type); + next_type = le16_to_cpu(resp->next_valid_type); if (!(flags & BNXT_CTX_MEM_TYPE_VALID)) { bnxt_free_one_ctx_mem(bp, ctxm, true); continue; @@ -8715,7 +8717,7 @@ static int bnxt_hwrm_func_backing_store_qcaps_v2(struct bnxt *bp) else continue; } - ctxm->type = le16_to_cpu(resp->type); + ctxm->type = type; ctxm->entry_size = entry_size; ctxm->flags = flags; ctxm->instance_bmap = le32_to_cpu(resp->instance_bit_map); @@ -12992,6 +12994,21 @@ static int bnxt_tx_nr_rings_per_tc(struct bnxt *bp) return bp->num_tc ? bp->tx_nr_rings / bp->num_tc : bp->tx_nr_rings; } +static void bnxt_set_xdp_tx_rings(struct bnxt *bp) +{ + bp->tx_nr_rings_xdp = bp->tx_nr_rings_per_tc; + bp->tx_nr_rings += bp->tx_nr_rings_xdp; +} + +static void bnxt_adj_tx_rings(struct bnxt *bp) +{ + /* Make adjustments if reserved TX rings are less than requested */ + bp->tx_nr_rings -= bp->tx_nr_rings_xdp; + bp->tx_nr_rings_per_tc = bnxt_tx_nr_rings_per_tc(bp); + if (bp->tx_nr_rings_xdp) + bnxt_set_xdp_tx_rings(bp); +} + static int __bnxt_open_nic(struct bnxt *bp, bool irq_re_init, bool link_re_init) { int rc = 0; @@ -13009,13 +13026,7 @@ static int __bnxt_open_nic(struct bnxt *bp, bool irq_re_init, bool link_re_init) if (rc) return rc; - /* Make adjustments if reserved TX rings are less than requested */ - bp->tx_nr_rings -= bp->tx_nr_rings_xdp; - bp->tx_nr_rings_per_tc = bnxt_tx_nr_rings_per_tc(bp); - if (bp->tx_nr_rings_xdp) { - bp->tx_nr_rings_xdp = bp->tx_nr_rings_per_tc; - bp->tx_nr_rings += bp->tx_nr_rings_xdp; - } + bnxt_adj_tx_rings(bp); rc = bnxt_alloc_mem(bp, irq_re_init); if (rc) { netdev_err(bp->dev, "bnxt_alloc_mem err: %x\n", rc); @@ -15436,11 +15447,19 @@ static int bnxt_change_mtu(struct net_device *dev, int new_mtu) return 0; } +void bnxt_set_cp_rings(struct bnxt *bp, bool sh) +{ + int tx_cp = bnxt_num_tx_to_cp(bp, bp->tx_nr_rings); + + bp->cp_nr_rings = sh ? max_t(int, tx_cp, bp->rx_nr_rings) : + tx_cp + bp->rx_nr_rings; +} + int bnxt_setup_mq_tc(struct net_device *dev, u8 tc) { struct bnxt *bp = netdev_priv(dev); bool sh = false; - int rc, tx_cp; + int rc; if (tc > bp->max_tc) { netdev_err(dev, "Too many traffic classes requested: %d. Max supported is %d.\n", @@ -15473,9 +15492,7 @@ int bnxt_setup_mq_tc(struct net_device *dev, u8 tc) bp->num_tc = 0; } bp->tx_nr_rings += bp->tx_nr_rings_xdp; - tx_cp = bnxt_num_tx_to_cp(bp, bp->tx_nr_rings); - bp->cp_nr_rings = sh ? max_t(int, tx_cp, bp->rx_nr_rings) : - tx_cp + bp->rx_nr_rings; + bnxt_set_cp_rings(bp, sh); if (netif_running(bp->dev)) return bnxt_open_nic(bp, true, false); @@ -16525,6 +16542,19 @@ static void bnxt_trim_dflt_sh_rings(struct bnxt *bp) bp->tx_nr_rings = bnxt_tx_nr_rings(bp); } +static void bnxt_adj_dflt_rings(struct bnxt *bp, bool sh) +{ + if (sh) + bnxt_trim_dflt_sh_rings(bp); + else + bp->cp_nr_rings = bp->tx_nr_rings_per_tc + bp->rx_nr_rings; + bp->tx_nr_rings = bnxt_tx_nr_rings(bp); + if (sh && READ_ONCE(bp->xdp_prog)) { + bnxt_set_xdp_tx_rings(bp); + bnxt_set_cp_rings(bp, true); + } +} + static int bnxt_set_dflt_rings(struct bnxt *bp, bool sh) { int dflt_rings, max_rx_rings, max_tx_rings, rc; @@ -16550,11 +16580,8 @@ static int bnxt_set_dflt_rings(struct bnxt *bp, bool sh) return rc; bp->rx_nr_rings = min_t(int, dflt_rings, max_rx_rings); bp->tx_nr_rings_per_tc = min_t(int, dflt_rings, max_tx_rings); - if (sh) - bnxt_trim_dflt_sh_rings(bp); - else - bp->cp_nr_rings = bp->tx_nr_rings_per_tc + bp->rx_nr_rings; - bp->tx_nr_rings = bnxt_tx_nr_rings(bp); + + bnxt_adj_dflt_rings(bp, sh); avail_msix = bnxt_get_max_func_irqs(bp) - bp->cp_nr_rings; if (avail_msix >= BNXT_MIN_ROCE_CP_RINGS) { @@ -16567,16 +16594,17 @@ static int bnxt_set_dflt_rings(struct bnxt *bp, bool sh) rc = __bnxt_reserve_rings(bp); if (rc && rc != -ENODEV) netdev_warn(bp->dev, "Unable to reserve tx rings\n"); - bp->tx_nr_rings_per_tc = bnxt_tx_nr_rings_per_tc(bp); + + bnxt_adj_tx_rings(bp); if (sh) - bnxt_trim_dflt_sh_rings(bp); + bnxt_adj_dflt_rings(bp, true); /* Rings may have been trimmed, re-reserve the trimmed rings. */ if (bnxt_need_reserve_rings(bp)) { rc = __bnxt_reserve_rings(bp); if (rc && rc != -ENODEV) netdev_warn(bp->dev, "2nd rings reservation failed.\n"); - bp->tx_nr_rings_per_tc = bnxt_tx_nr_rings_per_tc(bp); + bnxt_adj_tx_rings(bp); } if (BNXT_CHIP_TYPE_NITRO_A0(bp)) { bp->rx_nr_rings++; @@ -16610,7 +16638,7 @@ static int bnxt_init_dflt_ring_mode(struct bnxt *bp) if (rc) goto init_dflt_ring_err; - bp->tx_nr_rings_per_tc = bnxt_tx_nr_rings_per_tc(bp); + bnxt_adj_tx_rings(bp); bnxt_set_dflt_rfs(bp); diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index a97d651130df..4bc7f7aeaab3 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -2985,6 +2985,7 @@ int bnxt_check_rings(struct bnxt *bp, int tx, int rx, bool sh, int tcs, int tx_xdp); int bnxt_fw_init_one(struct bnxt *bp); bool bnxt_hwrm_reset_permitted(struct bnxt *bp); +void bnxt_set_cp_rings(struct bnxt *bp, bool sh); int bnxt_setup_mq_tc(struct net_device *dev, u8 tc); struct bnxt_ntuple_filter *bnxt_lookup_ntp_filter_from_idx(struct bnxt *bp, struct bnxt_ntuple_filter *fltr, u32 idx); diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c index 28d0ece2e7b1..0407aa1b3190 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_ethtool.c @@ -945,7 +945,6 @@ static int bnxt_set_channels(struct net_device *dev, bool sh = false; int tx_xdp = 0; int rc = 0; - int tx_cp; if (channel->other_count) return -EINVAL; @@ -1013,9 +1012,7 @@ static int bnxt_set_channels(struct net_device *dev, if (tcs > 1) bp->tx_nr_rings = bp->tx_nr_rings_per_tc * tcs + tx_xdp; - tx_cp = bnxt_num_tx_to_cp(bp, bp->tx_nr_rings); - bp->cp_nr_rings = sh ? max_t(int, tx_cp, bp->rx_nr_rings) : - tx_cp + bp->rx_nr_rings; + bnxt_set_cp_rings(bp, sh); /* After changing number of rx channels, update NTUPLE feature. */ netdev_update_features(dev); diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c index 85cbeb35681c..bebe37e139c9 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c @@ -384,7 +384,7 @@ int bnxt_xdp_xmit(struct net_device *dev, int num_frames, static int bnxt_xdp_set(struct bnxt *bp, struct bpf_prog *prog) { struct net_device *dev = bp->dev; - int tx_xdp = 0, tx_cp, rc, tc; + int tx_xdp = 0, rc, tc; struct bpf_prog *old; netdev_assert_locked(dev); @@ -431,8 +431,7 @@ static int bnxt_xdp_set(struct bnxt *bp, struct bpf_prog *prog) } bp->tx_nr_rings_xdp = tx_xdp; bp->tx_nr_rings = bp->tx_nr_rings_per_tc * tc + tx_xdp; - tx_cp = bnxt_num_tx_to_cp(bp, bp->tx_nr_rings); - bp->cp_nr_rings = max_t(int, tx_cp, bp->rx_nr_rings); + bnxt_set_cp_rings(bp, true); bnxt_set_tpa_flags(bp); bnxt_set_ring_params(bp); diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index 21a5dd342724..73a4b569b03e 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -12299,7 +12299,7 @@ static int tg3_get_link_ksettings(struct net_device *dev, ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.advertising, advertising); - if (netif_running(dev) && tp->link_up) { + if (netif_running(dev) && netif_carrier_ok(dev)) { cmd->base.speed = tp->link_config.active_speed; cmd->base.duplex = tp->link_config.active_duplex; ethtool_convert_legacy_u32_to_link_mode( diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c index c16ac9c76aa3..99e7d5cf3786 100644 --- a/drivers/net/ethernet/cadence/macb_main.c +++ b/drivers/net/ethernet/cadence/macb_main.c @@ -1071,7 +1071,7 @@ static void macb_tx_unmap(struct macb *bp, struct macb_tx_skb *tx_skb, int budge } if (tx_skb->skb) { - napi_consume_skb(tx_skb->skb, budget); + dev_consume_skb_any(tx_skb->skb); tx_skb->skb = NULL; } } @@ -3224,7 +3224,7 @@ static void gem_get_ethtool_stats(struct net_device *dev, spin_lock_irq(&bp->stats_lock); gem_update_stats(bp); memcpy(data, &bp->ethtool_stats, sizeof(u64) - * (GEM_STATS_LEN + QUEUE_STATS_LEN * MACB_MAX_QUEUES)); + * (GEM_STATS_LEN + QUEUE_STATS_LEN * bp->num_queues)); spin_unlock_irq(&bp->stats_lock); } @@ -5776,9 +5776,9 @@ static int __maybe_unused macb_suspend(struct device *dev) struct macb_queue *queue; struct in_device *idev; unsigned long flags; + u32 tmp, ifa_local; unsigned int q; int err; - u32 tmp; if (!device_may_wakeup(&bp->dev->dev)) phy_exit(bp->phy); @@ -5787,14 +5787,21 @@ static int __maybe_unused macb_suspend(struct device *dev) return 0; if (bp->wol & MACB_WOL_ENABLED) { - /* Check for IP address in WOL ARP mode */ - idev = __in_dev_get_rcu(bp->dev); - if (idev) - ifa = rcu_dereference(idev->ifa_list); - if ((bp->wolopts & WAKE_ARP) && !ifa) { - netdev_err(netdev, "IP address not assigned as required by WoL walk ARP\n"); - return -EOPNOTSUPP; + if (bp->wolopts & WAKE_ARP) { + /* Check for IP address in WOL ARP mode */ + rcu_read_lock(); + idev = __in_dev_get_rcu(bp->dev); + if (idev) + ifa = rcu_dereference(idev->ifa_list); + if (!ifa) { + rcu_read_unlock(); + netdev_err(netdev, "IP address not assigned as required by WoL walk ARP\n"); + return -EOPNOTSUPP; + } + ifa_local = be32_to_cpu(ifa->ifa_local); + rcu_read_unlock(); } + spin_lock_irqsave(&bp->lock, flags); /* Disable Tx and Rx engines before disabling the queues, @@ -5833,8 +5840,9 @@ static int __maybe_unused macb_suspend(struct device *dev) if (bp->wolopts & WAKE_ARP) { tmp |= MACB_BIT(ARP); /* write IP address into register */ - tmp |= MACB_BFEXT(IP, be32_to_cpu(ifa->ifa_local)); + tmp |= MACB_BFEXT(IP, ifa_local); } + spin_unlock_irqrestore(&bp->lock, flags); /* Change interrupt handler and * Enable WoL IRQ on queue 0 @@ -5847,11 +5855,12 @@ static int __maybe_unused macb_suspend(struct device *dev) dev_err(dev, "Unable to request IRQ %d (error %d)\n", bp->queues[0].irq, err); - spin_unlock_irqrestore(&bp->lock, flags); return err; } + spin_lock_irqsave(&bp->lock, flags); queue_writel(bp->queues, IER, GEM_BIT(WOL)); gem_writel(bp, WOL, tmp); + spin_unlock_irqrestore(&bp->lock, flags); } else { err = devm_request_irq(dev, bp->queues[0].irq, macb_wol_interrupt, IRQF_SHARED, netdev->name, bp->queues); @@ -5859,13 +5868,13 @@ static int __maybe_unused macb_suspend(struct device *dev) dev_err(dev, "Unable to request IRQ %d (error %d)\n", bp->queues[0].irq, err); - spin_unlock_irqrestore(&bp->lock, flags); return err; } + spin_lock_irqsave(&bp->lock, flags); queue_writel(bp->queues, IER, MACB_BIT(WOL)); macb_writel(bp, WOL, tmp); + spin_unlock_irqrestore(&bp->lock, flags); } - spin_unlock_irqrestore(&bp->lock, flags); enable_irq_wake(bp->queues[0].irq); } @@ -5932,6 +5941,8 @@ static int __maybe_unused macb_resume(struct device *dev) queue_readl(bp->queues, ISR); if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE) queue_writel(bp->queues, ISR, -1); + spin_unlock_irqrestore(&bp->lock, flags); + /* Replace interrupt handler on queue 0 */ devm_free_irq(dev, bp->queues[0].irq, bp->queues); err = devm_request_irq(dev, bp->queues[0].irq, macb_interrupt, @@ -5940,10 +5951,8 @@ static int __maybe_unused macb_resume(struct device *dev) dev_err(dev, "Unable to request IRQ %d (error %d)\n", bp->queues[0].irq, err); - spin_unlock_irqrestore(&bp->lock, flags); return err; } - spin_unlock_irqrestore(&bp->lock, flags); disable_irq_wake(bp->queues[0].irq); diff --git a/drivers/net/ethernet/cadence/macb_pci.c b/drivers/net/ethernet/cadence/macb_pci.c index fc4f5aee6ab3..b79dec17e6b0 100644 --- a/drivers/net/ethernet/cadence/macb_pci.c +++ b/drivers/net/ethernet/cadence/macb_pci.c @@ -96,10 +96,10 @@ static int macb_probe(struct pci_dev *pdev, const struct pci_device_id *id) return 0; err_plat_dev_register: - clk_unregister(plat_data.hclk); + clk_unregister_fixed_rate(plat_data.hclk); err_hclk_register: - clk_unregister(plat_data.pclk); + clk_unregister_fixed_rate(plat_data.pclk); err_pclk_register: return err; @@ -109,10 +109,12 @@ static void macb_remove(struct pci_dev *pdev) { struct platform_device *plat_dev = pci_get_drvdata(pdev); struct macb_platform_data *plat_data = dev_get_platdata(&plat_dev->dev); + struct clk *pclk = plat_data->pclk; + struct clk *hclk = plat_data->hclk; - clk_unregister(plat_data->pclk); - clk_unregister(plat_data->hclk); platform_device_unregister(plat_dev); + clk_unregister_fixed_rate(pclk); + clk_unregister_fixed_rate(hclk); } static const struct pci_device_id dev_id_table[] = { diff --git a/drivers/net/ethernet/faraday/ftgmac100.c b/drivers/net/ethernet/faraday/ftgmac100.c index 1e91e79c8134..6d2fe5c2f390 100644 --- a/drivers/net/ethernet/faraday/ftgmac100.c +++ b/drivers/net/ethernet/faraday/ftgmac100.c @@ -977,19 +977,19 @@ static int ftgmac100_alloc_rings(struct ftgmac100 *priv) priv->tx_skbs = kcalloc(MAX_TX_QUEUE_ENTRIES, sizeof(void *), GFP_KERNEL); if (!priv->tx_skbs) - return -ENOMEM; + goto err_free_rx_skbs; /* Allocate descriptors */ priv->rxdes = dma_alloc_coherent(priv->dev, MAX_RX_QUEUE_ENTRIES * sizeof(struct ftgmac100_rxdes), &priv->rxdes_dma, GFP_KERNEL); if (!priv->rxdes) - return -ENOMEM; + goto err_free_tx_skbs; priv->txdes = dma_alloc_coherent(priv->dev, MAX_TX_QUEUE_ENTRIES * sizeof(struct ftgmac100_txdes), &priv->txdes_dma, GFP_KERNEL); if (!priv->txdes) - return -ENOMEM; + goto err_free_rxdes; /* Allocate scratch packet buffer */ priv->rx_scratch = dma_alloc_coherent(priv->dev, @@ -997,9 +997,29 @@ static int ftgmac100_alloc_rings(struct ftgmac100 *priv) &priv->rx_scratch_dma, GFP_KERNEL); if (!priv->rx_scratch) - return -ENOMEM; + goto err_free_txdes; return 0; + +err_free_txdes: + dma_free_coherent(priv->dev, + MAX_TX_QUEUE_ENTRIES * + sizeof(struct ftgmac100_txdes), + priv->txdes, priv->txdes_dma); + priv->txdes = NULL; +err_free_rxdes: + dma_free_coherent(priv->dev, + MAX_RX_QUEUE_ENTRIES * + sizeof(struct ftgmac100_rxdes), + priv->rxdes, priv->rxdes_dma); + priv->rxdes = NULL; +err_free_tx_skbs: + kfree(priv->tx_skbs); + priv->tx_skbs = NULL; +err_free_rx_skbs: + kfree(priv->rx_skbs); + priv->rx_skbs = NULL; + return -ENOMEM; } static void ftgmac100_init_rings(struct ftgmac100 *priv) diff --git a/drivers/net/ethernet/freescale/enetc/enetc.c b/drivers/net/ethernet/freescale/enetc/enetc.c index a146ceaf2ed6..aa8a87124b10 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc.c +++ b/drivers/net/ethernet/freescale/enetc/enetc.c @@ -2578,6 +2578,7 @@ EXPORT_SYMBOL_GPL(enetc_free_si_resources); static void enetc_setup_txbdr(struct enetc_hw *hw, struct enetc_bdr *tx_ring) { + struct enetc_si *si = container_of(hw, struct enetc_si, hw); int idx = tx_ring->index; u32 tbmr; @@ -2591,10 +2592,20 @@ static void enetc_setup_txbdr(struct enetc_hw *hw, struct enetc_bdr *tx_ring) enetc_txbdr_wr(hw, idx, ENETC_TBLENR, ENETC_RTBLENR_LEN(tx_ring->bd_count)); - /* clearing PI/CI registers for Tx not supported, adjust sw indexes */ + /* For ENETC v1, clearing PI/CI registers for Tx not supported, + * adjust sw indexes + */ tx_ring->next_to_use = enetc_txbdr_rd(hw, idx, ENETC_TBPIR); tx_ring->next_to_clean = enetc_txbdr_rd(hw, idx, ENETC_TBCIR); + if (tx_ring->next_to_use != tx_ring->next_to_clean && + !is_enetc_rev1(si)) { + tx_ring->next_to_use = 0; + tx_ring->next_to_clean = 0; + enetc_txbdr_wr(hw, idx, ENETC_TBPIR, 0); + enetc_txbdr_wr(hw, idx, ENETC_TBCIR, 0); + } + /* enable Tx ints by setting pkt thr to 1 */ enetc_txbdr_wr(hw, idx, ENETC_TBICR0, ENETC_TBICR0_ICEN | 0x1); diff --git a/drivers/net/ethernet/freescale/enetc/enetc4_hw.h b/drivers/net/ethernet/freescale/enetc/enetc4_hw.h index 3ed0f7a02767..719c88ceb801 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc4_hw.h +++ b/drivers/net/ethernet/freescale/enetc/enetc4_hw.h @@ -134,6 +134,12 @@ /* Port operational register */ #define ENETC4_POR 0x4100 +#define POR_TXDIS BIT(0) +#define POR_RXDIS BIT(1) + +/* Port status register */ +#define ENETC4_PSR 0x4104 +#define PSR_RX_BUSY BIT(1) /* Port traffic class a transmit maximum SDU register */ #define ENETC4_PTCTMSDUR(a) ((a) * 0x20 + 0x4208) @@ -173,6 +179,11 @@ /* Port internal MDIO base address, use to access PCS */ #define ENETC4_PM_IMDIO_BASE 0x5030 +/* Port MAC 0/1 Interrupt Event Register */ +#define ENETC4_PM_IEVENT(mac) (0x5040 + (mac) * 0x400) +#define PM_IEVENT_TX_EMPTY BIT(5) +#define PM_IEVENT_RX_EMPTY BIT(6) + /* Port MAC 0/1 Pause Quanta Register */ #define ENETC4_PM_PAUSE_QUANTA(mac) (0x5054 + (mac) * 0x400) diff --git a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c index 689b9f13c5eb..56899f2254aa 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc4_pf.c +++ b/drivers/net/ethernet/freescale/enetc/enetc4_pf.c @@ -444,20 +444,11 @@ static void enetc4_set_trx_frame_size(struct enetc_pf *pf) enetc4_pf_reset_tc_msdu(&si->hw); } -static void enetc4_enable_trx(struct enetc_pf *pf) -{ - struct enetc_hw *hw = &pf->si->hw; - - /* Enable port transmit/receive */ - enetc_port_wr(hw, ENETC4_POR, 0); -} - static void enetc4_configure_port(struct enetc_pf *pf) { enetc4_configure_port_si(pf); enetc4_set_trx_frame_size(pf); enetc_set_default_rss_key(pf); - enetc4_enable_trx(pf); } static int enetc4_init_ntmp_user(struct enetc_si *si) @@ -801,15 +792,112 @@ static void enetc4_set_tx_pause(struct enetc_pf *pf, int num_rxbdr, bool tx_paus enetc_port_wr(hw, ENETC4_PPAUOFFTR, pause_off_thresh); } -static void enetc4_enable_mac(struct enetc_pf *pf, bool en) +static void enetc4_mac_wait_tx_empty(struct enetc_si *si, int mac) +{ + u32 val; + + if (read_poll_timeout(enetc_port_rd, val, + val & PM_IEVENT_TX_EMPTY, + 100, 10000, false, &si->hw, + ENETC4_PM_IEVENT(mac))) + dev_warn(&si->pdev->dev, + "MAC %d TX is not empty\n", mac); +} + +static void enetc4_mac_tx_graceful_stop(struct enetc_pf *pf) +{ + struct enetc_hw *hw = &pf->si->hw; + struct enetc_si *si = pf->si; + u32 val; + + val = enetc_port_rd(hw, ENETC4_POR); + val |= POR_TXDIS; + enetc_port_wr(hw, ENETC4_POR, val); + + if (enetc_is_pseudo_mac(si)) + return; + + enetc4_mac_wait_tx_empty(si, 0); + if (si->hw_features & ENETC_SI_F_QBU) + enetc4_mac_wait_tx_empty(si, 1); + + val = enetc_port_mac_rd(si, ENETC4_PM_CMD_CFG(0)); + val &= ~PM_CMD_CFG_TX_EN; + enetc_port_mac_wr(si, ENETC4_PM_CMD_CFG(0), val); +} + +static void enetc4_mac_tx_enable(struct enetc_pf *pf) { + struct enetc_hw *hw = &pf->si->hw; struct enetc_si *si = pf->si; u32 val; val = enetc_port_mac_rd(si, ENETC4_PM_CMD_CFG(0)); - val &= ~(PM_CMD_CFG_TX_EN | PM_CMD_CFG_RX_EN); - val |= en ? (PM_CMD_CFG_TX_EN | PM_CMD_CFG_RX_EN) : 0; + val |= PM_CMD_CFG_TX_EN; + enetc_port_mac_wr(si, ENETC4_PM_CMD_CFG(0), val); + val = enetc_port_rd(hw, ENETC4_POR); + val &= ~POR_TXDIS; + enetc_port_wr(hw, ENETC4_POR, val); +} + +static void enetc4_mac_wait_rx_empty(struct enetc_si *si, int mac) +{ + u32 val; + + if (read_poll_timeout(enetc_port_rd, val, + val & PM_IEVENT_RX_EMPTY, + 100, 10000, false, &si->hw, + ENETC4_PM_IEVENT(mac))) + dev_warn(&si->pdev->dev, + "MAC %d RX is not empty\n", mac); +} + +static void enetc4_mac_rx_graceful_stop(struct enetc_pf *pf) +{ + struct enetc_hw *hw = &pf->si->hw; + struct enetc_si *si = pf->si; + u32 val; + + if (enetc_is_pseudo_mac(si)) + goto check_rx_busy; + + if (si->hw_features & ENETC_SI_F_QBU) { + val = enetc_port_rd(hw, ENETC4_PM_CMD_CFG(1)); + val &= ~PM_CMD_CFG_RX_EN; + enetc_port_wr(hw, ENETC4_PM_CMD_CFG(1), val); + enetc4_mac_wait_rx_empty(si, 1); + } + + val = enetc_port_rd(hw, ENETC4_PM_CMD_CFG(0)); + val &= ~PM_CMD_CFG_RX_EN; + enetc_port_wr(hw, ENETC4_PM_CMD_CFG(0), val); + enetc4_mac_wait_rx_empty(si, 0); + +check_rx_busy: + if (read_poll_timeout(enetc_port_rd, val, + !(val & PSR_RX_BUSY), + 100, 10000, false, hw, + ENETC4_PSR)) + dev_warn(&si->pdev->dev, "Port RX busy\n"); + + val = enetc_port_rd(hw, ENETC4_POR); + val |= POR_RXDIS; + enetc_port_wr(hw, ENETC4_POR, val); +} + +static void enetc4_mac_rx_enable(struct enetc_pf *pf) +{ + struct enetc_hw *hw = &pf->si->hw; + struct enetc_si *si = pf->si; + u32 val; + + val = enetc_port_rd(hw, ENETC4_POR); + val &= ~POR_RXDIS; + enetc_port_wr(hw, ENETC4_POR, val); + + val = enetc_port_mac_rd(si, ENETC4_PM_CMD_CFG(0)); + val |= PM_CMD_CFG_RX_EN; enetc_port_mac_wr(si, ENETC4_PM_CMD_CFG(0), val); } @@ -853,7 +941,8 @@ static void enetc4_pl_mac_link_up(struct phylink_config *config, enetc4_set_hd_flow_control(pf, hd_fc); enetc4_set_tx_pause(pf, priv->num_rx_rings, tx_pause); enetc4_set_rx_pause(pf, rx_pause); - enetc4_enable_mac(pf, true); + enetc4_mac_tx_enable(pf); + enetc4_mac_rx_enable(pf); } static void enetc4_pl_mac_link_down(struct phylink_config *config, @@ -862,7 +951,8 @@ static void enetc4_pl_mac_link_down(struct phylink_config *config, { struct enetc_pf *pf = phylink_to_enetc_pf(config); - enetc4_enable_mac(pf, false); + enetc4_mac_rx_graceful_stop(pf); + enetc4_mac_tx_graceful_stop(pf); } static const struct phylink_mac_ops enetc_pl_mac_ops = { diff --git a/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c b/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c index fed89d4f1e1d..7c17acaf7a38 100644 --- a/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c +++ b/drivers/net/ethernet/freescale/enetc/enetc_ethtool.c @@ -795,9 +795,17 @@ static int enetc_set_rxfh(struct net_device *ndev, struct enetc_si *si = priv->si; int err = 0; + if (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE && + rxfh->hfunc != ETH_RSS_HASH_TOP) + return -EOPNOTSUPP; + /* set hash key, if PF */ - if (rxfh->key && enetc_si_is_pf(si)) + if (rxfh->key) { + if (!enetc_si_is_pf(si)) + return -EOPNOTSUPP; + enetc_set_rss_key(si, rxfh->key); + } /* set RSS table */ if (rxfh->indir) @@ -813,6 +821,8 @@ static void enetc_get_ringparam(struct net_device *ndev, { struct enetc_ndev_priv *priv = netdev_priv(ndev); + ring->rx_max_pending = priv->rx_bd_count; + ring->tx_max_pending = priv->tx_bd_count; ring->rx_pending = priv->rx_bd_count; ring->tx_pending = priv->tx_bd_count; diff --git a/drivers/net/ethernet/freescale/fec_ptp.c b/drivers/net/ethernet/freescale/fec_ptp.c index 4b7bad9a485d..56801c2009d5 100644 --- a/drivers/net/ethernet/freescale/fec_ptp.c +++ b/drivers/net/ethernet/freescale/fec_ptp.c @@ -545,9 +545,6 @@ static int fec_ptp_enable(struct ptp_clock_info *ptp, if (rq->perout.flags) return -EOPNOTSUPP; - if (rq->perout.index != fep->pps_channel) - return -EOPNOTSUPP; - period.tv_sec = rq->perout.period.sec; period.tv_nsec = rq->perout.period.nsec; period_ns = timespec64_to_ns(&period); diff --git a/drivers/net/ethernet/intel/iavf/iavf_ethtool.c b/drivers/net/ethernet/intel/iavf/iavf_ethtool.c index ab67c709d5a0..1cd1f3f2930a 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_ethtool.c +++ b/drivers/net/ethernet/intel/iavf/iavf_ethtool.c @@ -313,14 +313,13 @@ static int iavf_get_sset_count(struct net_device *netdev, int sset) { /* Report the maximum number queues, even if not every queue is * currently configured. Since allocation of queues is in pairs, - * use netdev->real_num_tx_queues * 2. The real_num_tx_queues is set - * at device creation and never changes. + * use netdev->num_tx_queues * 2. The num_tx_queues is set at + * device creation and never changes. */ if (sset == ETH_SS_STATS) return IAVF_STATS_LEN + - (IAVF_QUEUE_STATS_LEN * 2 * - netdev->real_num_tx_queues); + (IAVF_QUEUE_STATS_LEN * 2 * netdev->num_tx_queues); else return -EINVAL; } @@ -345,19 +344,19 @@ static void iavf_get_ethtool_stats(struct net_device *netdev, iavf_add_ethtool_stats(&data, adapter, iavf_gstrings_stats); rcu_read_lock(); - /* As num_active_queues describe both tx and rx queues, we can use - * it to iterate over rings' stats. + /* Use num_tx_queues to report stats for the maximum number of queues. + * Queues beyond num_active_queues will report zero. */ - for (i = 0; i < adapter->num_active_queues; i++) { - struct iavf_ring *ring; + for (i = 0; i < netdev->num_tx_queues; i++) { + struct iavf_ring *tx_ring = NULL, *rx_ring = NULL; - /* Tx rings stats */ - ring = &adapter->tx_rings[i]; - iavf_add_queue_stats(&data, ring); + if (i < adapter->num_active_queues) { + tx_ring = &adapter->tx_rings[i]; + rx_ring = &adapter->rx_rings[i]; + } - /* Rx rings stats */ - ring = &adapter->rx_rings[i]; - iavf_add_queue_stats(&data, ring); + iavf_add_queue_stats(&data, tx_ring); + iavf_add_queue_stats(&data, rx_ring); } rcu_read_unlock(); } @@ -376,9 +375,9 @@ static void iavf_get_stat_strings(struct net_device *netdev, u8 *data) iavf_add_stat_strings(&data, iavf_gstrings_stats); /* Queues are always allocated in pairs, so we just use - * real_num_tx_queues for both Tx and Rx queues. + * num_tx_queues for both Tx and Rx queues. */ - for (i = 0; i < netdev->real_num_tx_queues; i++) { + for (i = 0; i < netdev->num_tx_queues; i++) { iavf_add_stat_strings(&data, iavf_gstrings_queue_stats, "tx", i); iavf_add_stat_strings(&data, iavf_gstrings_queue_stats, diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h index 2b2b22af42be..eb3a48330cc1 100644 --- a/drivers/net/ethernet/intel/ice/ice.h +++ b/drivers/net/ethernet/intel/ice/ice.h @@ -840,6 +840,28 @@ static inline void ice_tx_xsk_pool(struct ice_vsi *vsi, u16 qid) } /** + * ice_get_max_txq - return the maximum number of Tx queues for in a PF + * @pf: PF structure + * + * Return: maximum number of Tx queues + */ +static inline int ice_get_max_txq(struct ice_pf *pf) +{ + return min(num_online_cpus(), pf->hw.func_caps.common_cap.num_txq); +} + +/** + * ice_get_max_rxq - return the maximum number of Rx queues for in a PF + * @pf: PF structure + * + * Return: maximum number of Rx queues + */ +static inline int ice_get_max_rxq(struct ice_pf *pf) +{ + return min(num_online_cpus(), pf->hw.func_caps.common_cap.num_rxq); +} + +/** * ice_get_main_vsi - Get the PF VSI * @pf: PF instance * diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool.c b/drivers/net/ethernet/intel/ice/ice_ethtool.c index 301947d53ede..e6a20af6f63d 100644 --- a/drivers/net/ethernet/intel/ice/ice_ethtool.c +++ b/drivers/net/ethernet/intel/ice/ice_ethtool.c @@ -1930,6 +1930,17 @@ __ice_get_ethtool_stats(struct net_device *netdev, int i = 0; char *p; + if (ice_is_port_repr_netdev(netdev)) { + ice_update_eth_stats(vsi); + + for (j = 0; j < ICE_VSI_STATS_LEN; j++) { + p = (char *)vsi + ice_gstrings_vsi_stats[j].stat_offset; + data[i++] = (ice_gstrings_vsi_stats[j].sizeof_stat == + sizeof(u64)) ? *(u64 *)p : *(u32 *)p; + } + return; + } + ice_update_pf_stats(pf); ice_update_vsi_stats(vsi); @@ -1939,9 +1950,6 @@ __ice_get_ethtool_stats(struct net_device *netdev, sizeof(u64)) ? *(u64 *)p : *(u32 *)p; } - if (ice_is_port_repr_netdev(netdev)) - return; - /* populate per queue stats */ rcu_read_lock(); @@ -3774,24 +3782,6 @@ ice_get_ts_info(struct net_device *dev, struct kernel_ethtool_ts_info *info) } /** - * ice_get_max_txq - return the maximum number of Tx queues for in a PF - * @pf: PF structure - */ -static int ice_get_max_txq(struct ice_pf *pf) -{ - return min(num_online_cpus(), pf->hw.func_caps.common_cap.num_txq); -} - -/** - * ice_get_max_rxq - return the maximum number of Rx queues for in a PF - * @pf: PF structure - */ -static int ice_get_max_rxq(struct ice_pf *pf) -{ - return min(num_online_cpus(), pf->hw.func_caps.common_cap.num_rxq); -} - -/** * ice_get_combined_cnt - return the current number of combined channels * @vsi: PF VSI pointer * diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index e7308e381e2f..3c36e3641b9e 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -4699,8 +4699,8 @@ static int ice_cfg_netdev(struct ice_vsi *vsi) struct net_device *netdev; u8 mac_addr[ETH_ALEN]; - netdev = alloc_etherdev_mqs(sizeof(*np), vsi->alloc_txq, - vsi->alloc_rxq); + netdev = alloc_etherdev_mqs(sizeof(*np), ice_get_max_txq(vsi->back), + ice_get_max_rxq(vsi->back)); if (!netdev) return -ENOMEM; diff --git a/drivers/net/ethernet/intel/ice/ice_repr.c b/drivers/net/ethernet/intel/ice/ice_repr.c index 90f99443a922..096566c697f4 100644 --- a/drivers/net/ethernet/intel/ice/ice_repr.c +++ b/drivers/net/ethernet/intel/ice/ice_repr.c @@ -2,6 +2,7 @@ /* Copyright (C) 2019-2021, Intel Corporation. */ #include "ice.h" +#include "ice_lib.h" #include "ice_eswitch.h" #include "devlink/devlink.h" #include "devlink/port.h" @@ -67,7 +68,7 @@ ice_repr_get_stats64(struct net_device *netdev, struct rtnl_link_stats64 *stats) return; vsi = repr->src_vsi; - ice_update_vsi_stats(vsi); + ice_update_eth_stats(vsi); eth_stats = &vsi->eth_stats; stats->tx_packets = eth_stats->tx_unicast + eth_stats->tx_broadcast + @@ -315,7 +316,7 @@ ice_repr_reg_netdev(struct net_device *netdev, const struct net_device_ops *ops) static int ice_repr_ready_vf(struct ice_repr *repr) { - return !ice_check_vf_ready_for_cfg(repr->vf); + return ice_check_vf_ready_for_cfg(repr->vf); } static int ice_repr_ready_sf(struct ice_repr *repr) diff --git a/drivers/net/ethernet/intel/idpf/idpf.h b/drivers/net/ethernet/intel/idpf/idpf.h index b206fba092c8..ec1b75f039bb 100644 --- a/drivers/net/ethernet/intel/idpf/idpf.h +++ b/drivers/net/ethernet/intel/idpf/idpf.h @@ -1066,7 +1066,7 @@ bool idpf_vport_set_hsplit(const struct idpf_vport *vport, u8 val); int idpf_idc_init(struct idpf_adapter *adapter); int idpf_idc_init_aux_core_dev(struct idpf_adapter *adapter, enum iidc_function_type ftype); -void idpf_idc_deinit_core_aux_device(struct iidc_rdma_core_dev_info *cdev_info); +void idpf_idc_deinit_core_aux_device(struct idpf_adapter *adapter); void idpf_idc_deinit_vport_aux_device(struct iidc_rdma_vport_dev_info *vdev_info); void idpf_idc_issue_reset_event(struct iidc_rdma_core_dev_info *cdev_info); void idpf_idc_vdev_mtu_event(struct iidc_rdma_vport_dev_info *vdev_info, diff --git a/drivers/net/ethernet/intel/idpf/idpf_idc.c b/drivers/net/ethernet/intel/idpf/idpf_idc.c index bd4785fb8d3e..7e4f4ac92653 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_idc.c +++ b/drivers/net/ethernet/intel/idpf/idpf_idc.c @@ -470,10 +470,11 @@ err_privd_alloc: /** * idpf_idc_deinit_core_aux_device - de-initialize Auxiliary Device(s) - * @cdev_info: IDC core device info pointer + * @adapter: driver private data structure */ -void idpf_idc_deinit_core_aux_device(struct iidc_rdma_core_dev_info *cdev_info) +void idpf_idc_deinit_core_aux_device(struct idpf_adapter *adapter) { + struct iidc_rdma_core_dev_info *cdev_info = adapter->cdev_info; struct iidc_rdma_priv_dev_info *privd; if (!cdev_info) @@ -485,6 +486,7 @@ void idpf_idc_deinit_core_aux_device(struct iidc_rdma_core_dev_info *cdev_info) kfree(privd->mapped_mem_regions); kfree(privd); kfree(cdev_info); + adapter->cdev_info = NULL; } /** diff --git a/drivers/net/ethernet/intel/idpf/idpf_txrx.c b/drivers/net/ethernet/intel/idpf/idpf_txrx.c index 252259993022..f6b3b15364ff 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_txrx.c +++ b/drivers/net/ethernet/intel/idpf/idpf_txrx.c @@ -1860,13 +1860,13 @@ static int idpf_rxq_group_alloc(struct idpf_vport *vport, idpf_queue_assign(HSPLIT_EN, q, hs); idpf_queue_assign(RSC_EN, q, rsc); - bufq_set->num_refillqs = num_rxq; bufq_set->refillqs = kcalloc(num_rxq, swq_size, GFP_KERNEL); if (!bufq_set->refillqs) { err = -ENOMEM; goto err_alloc; } + bufq_set->num_refillqs = num_rxq; for (unsigned int k = 0; k < bufq_set->num_refillqs; k++) { struct idpf_sw_queue *refillq = &bufq_set->refillqs[k]; diff --git a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c index d5a877e1fef8..113ecfc16dd7 100644 --- a/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c +++ b/drivers/net/ethernet/intel/idpf/idpf_virtchnl.c @@ -3668,7 +3668,7 @@ void idpf_vc_core_deinit(struct idpf_adapter *adapter) idpf_ptp_release(adapter); idpf_deinit_task(adapter); - idpf_idc_deinit_core_aux_device(adapter->cdev_info); + idpf_idc_deinit_core_aux_device(adapter); idpf_rel_rx_pt_lkup(adapter); idpf_intr_rel(adapter); diff --git a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c index cb30108f2bf6..cc8c4ef8038f 100644 --- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c +++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c @@ -244,6 +244,25 @@ out: return 0; } +static bool +mtk_flow_is_valid_idev(const struct mtk_eth *eth, const struct net_device *idev) +{ + size_t i; + + if (!idev) + return false; + + for (i = 0; i < ARRAY_SIZE(eth->netdev); i++) { + if (!eth->netdev[i]) + continue; + + if (idev->netdev_ops == eth->netdev[i]->netdev_ops) + return true; + } + + return false; +} + static int mtk_flow_offload_replace(struct mtk_eth *eth, struct flow_cls_offload *f, int ppe_index) @@ -270,7 +289,7 @@ mtk_flow_offload_replace(struct mtk_eth *eth, struct flow_cls_offload *f, flow_rule_match_meta(rule, &match); if (mtk_is_netsys_v2_or_greater(eth)) { idev = __dev_get_by_index(&init_net, match.key->ingress_ifindex); - if (idev && idev->netdev_ops == eth->netdev[0]->netdev_ops) { + if (mtk_flow_is_valid_idev(eth, idev)) { struct mtk_mac *mac = netdev_priv(idev); if (WARN_ON(mac->ppe_idx >= eth->soc->ppe_num)) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/devlink.c b/drivers/net/ethernet/mellanox/mlx5/core/devlink.c index 6698ac55a4bf..73cf0321bb86 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/devlink.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/devlink.c @@ -107,9 +107,7 @@ mlx5_devlink_info_get(struct devlink *devlink, struct devlink_info_req *req, if (err) return err; - err = mlx5_fw_version_query(dev, &running_fw, &stored_fw); - if (err) - return err; + mlx5_fw_version_query(dev, &running_fw, &stored_fw); snprintf(version_str, sizeof(version_str), "%d.%d.%04d", mlx5_fw_ver_major(running_fw), mlx5_fw_ver_minor(running_fw), diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c index 7a9ee36b8dca..01f6aecc4fcc 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c @@ -3761,6 +3761,8 @@ int esw_offloads_enable(struct mlx5_eswitch *esw) return 0; err_vports: + /* rollback to legacy, indicates don't unregister the uplink netdev */ + esw->dev->priv.flags |= MLX5_PRIV_FLAGS_SWITCH_LEGACY; mlx5_esw_offloads_rep_unload(esw, MLX5_VPORT_UPLINK); err_uplink: esw_offloads_steering_cleanup(esw); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fw.c b/drivers/net/ethernet/mellanox/mlx5/core/fw.c index eeb4437975f2..c1f220e5fe18 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fw.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fw.c @@ -822,48 +822,63 @@ mlx5_fw_image_pending(struct mlx5_core_dev *dev, return 0; } -int mlx5_fw_version_query(struct mlx5_core_dev *dev, - u32 *running_ver, u32 *pending_ver) +void mlx5_fw_version_query(struct mlx5_core_dev *dev, + u32 *running_ver, u32 *pending_ver) { u32 reg_mcqi_version[MLX5_ST_SZ_DW(mcqi_version)] = {}; bool pending_version_exists; int component_index; int err; + *running_ver = 0; + *pending_ver = 0; + if (!MLX5_CAP_GEN(dev, mcam_reg) || !MLX5_CAP_MCAM_REG(dev, mcqi) || !MLX5_CAP_MCAM_REG(dev, mcqs)) { mlx5_core_warn(dev, "fw query isn't supported by the FW\n"); - return -EOPNOTSUPP; + return; } component_index = mlx5_get_boot_img_component_index(dev); - if (component_index < 0) - return component_index; + if (component_index < 0) { + mlx5_core_warn(dev, "fw query failed to find boot img component index, err %d\n", + component_index); + return; + } + *running_ver = U32_MAX; /* indicate failure */ err = mlx5_reg_mcqi_version_query(dev, component_index, MCQI_FW_RUNNING_VERSION, reg_mcqi_version); - if (err) - return err; - - *running_ver = MLX5_GET(mcqi_version, reg_mcqi_version, version); - + if (!err) + *running_ver = MLX5_GET(mcqi_version, reg_mcqi_version, + version); + else + mlx5_core_warn(dev, "failed to query running version, err %d\n", + err); + + *pending_ver = U32_MAX; /* indicate failure */ err = mlx5_fw_image_pending(dev, component_index, &pending_version_exists); - if (err) - return err; + if (err) { + mlx5_core_warn(dev, "failed to query pending image, err %d\n", + err); + return; + } if (!pending_version_exists) { *pending_ver = 0; - return 0; + return; } err = mlx5_reg_mcqi_version_query(dev, component_index, MCQI_FW_STORED_VERSION, reg_mcqi_version); - if (err) - return err; - - *pending_ver = MLX5_GET(mcqi_version, reg_mcqi_version, version); - - return 0; + if (!err) + *pending_ver = MLX5_GET(mcqi_version, reg_mcqi_version, + version); + else + mlx5_core_warn(dev, "failed to query pending version, err %d\n", + err); + + return; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/debugfs.c b/drivers/net/ethernet/mellanox/mlx5/core/lag/debugfs.c index 62b6faa4276a..b8d5f6a44d26 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lag/debugfs.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/debugfs.c @@ -160,8 +160,11 @@ DEFINE_SHOW_ATTRIBUTE(members); void mlx5_ldev_add_debugfs(struct mlx5_core_dev *dev) { + struct mlx5_lag *ldev = mlx5_lag_dev(dev); struct dentry *dbg; + if (!ldev) + return; dbg = debugfs_create_dir("lag", mlx5_debugfs_get_dev_root(dev)); dev->priv.dbg.lag_debugfs = dbg; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h index b635b423d972..1507e881d962 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/mlx5_core.h @@ -393,8 +393,8 @@ int mlx5_port_max_linkspeed(struct mlx5_core_dev *mdev, u32 *speed); int mlx5_firmware_flash(struct mlx5_core_dev *dev, const struct firmware *fw, struct netlink_ext_ack *extack); -int mlx5_fw_version_query(struct mlx5_core_dev *dev, - u32 *running_ver, u32 *stored_ver); +void mlx5_fw_version_query(struct mlx5_core_dev *dev, u32 *running_ver, + u32 *stored_ver); #ifdef CONFIG_MLX5_CORE_EN int mlx5e_init(void); diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_debugfs.c b/drivers/net/ethernet/meta/fbnic/fbnic_debugfs.c index 08270db2dee8..3c4563c8f403 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_debugfs.c +++ b/drivers/net/ethernet/meta/fbnic/fbnic_debugfs.c @@ -197,7 +197,7 @@ static int fbnic_dbg_bdq_desc_seq_show(struct seq_file *s, void *v) return 0; } - for (i = 0; i <= ring->size_mask; i++) { + for (i = 0; i < (ring->size_mask + 1) * FBNIC_BD_FRAG_COUNT; i++) { u64 bd = le64_to_cpu(ring->desc[i]); seq_printf(s, "%04x %#04llx %#014llx\n", i, diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c index 9fb91d4f3971..9cd85a0d0c3a 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c +++ b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.c @@ -927,7 +927,7 @@ static void fbnic_fill_bdq(struct fbnic_ring *bdq) /* Force DMA writes to flush before writing to tail */ dma_wmb(); - writel(i, bdq->doorbell); + writel(i * FBNIC_BD_FRAG_COUNT, bdq->doorbell); } } @@ -2564,7 +2564,7 @@ static void fbnic_enable_bdq(struct fbnic_ring *hpq, struct fbnic_ring *ppq) hpq->tail = 0; hpq->head = 0; - log_size = fls(hpq->size_mask); + log_size = fls(hpq->size_mask) + ilog2(FBNIC_BD_FRAG_COUNT); /* Store descriptor ring address and size */ fbnic_ring_wr32(hpq, FBNIC_QUEUE_BDQ_HPQ_BAL, lower_32_bits(hpq->dma)); @@ -2576,7 +2576,7 @@ static void fbnic_enable_bdq(struct fbnic_ring *hpq, struct fbnic_ring *ppq) if (!ppq->size_mask) goto write_ctl; - log_size = fls(ppq->size_mask); + log_size = fls(ppq->size_mask) + ilog2(FBNIC_BD_FRAG_COUNT); /* Add enabling of PPQ to BDQ control */ bdq_ctl |= FBNIC_QUEUE_BDQ_CTL_PPQ_ENABLE; diff --git a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.h b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.h index 980965274079..e03c9d2c38dc 100644 --- a/drivers/net/ethernet/meta/fbnic/fbnic_txrx.h +++ b/drivers/net/ethernet/meta/fbnic/fbnic_txrx.h @@ -38,7 +38,7 @@ struct fbnic_net; #define FBNIC_MAX_XDPQS 128u /* These apply to TWQs, TCQ, RCQ */ -#define FBNIC_QUEUE_SIZE_MIN 16u +#define FBNIC_QUEUE_SIZE_MIN 64u #define FBNIC_QUEUE_SIZE_MAX SZ_64K #define FBNIC_TXQ_SIZE_DEFAULT 1024 diff --git a/drivers/net/ethernet/microchip/lan743x_main.c b/drivers/net/ethernet/microchip/lan743x_main.c index a3845edf0e48..f0b5dd752f08 100644 --- a/drivers/net/ethernet/microchip/lan743x_main.c +++ b/drivers/net/ethernet/microchip/lan743x_main.c @@ -3053,6 +3053,11 @@ static void lan743x_phylink_mac_link_up(struct phylink_config *config, else if (speed == SPEED_100) mac_cr |= MAC_CR_CFG_L_; + if (duplex == DUPLEX_FULL) + mac_cr |= MAC_CR_DPX_; + else + mac_cr &= ~MAC_CR_DPX_; + lan743x_csr_write(adapter, MAC_CR, mac_cr); lan743x_ptp_update_latency(adapter, speed); diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c index 9017e806ecda..09a53c977545 100644 --- a/drivers/net/ethernet/microsoft/mana/mana_en.c +++ b/drivers/net/ethernet/microsoft/mana/mana_en.c @@ -766,6 +766,13 @@ static void mana_get_rxbuf_cfg(struct mana_port_context *apc, } *frag_count = 1; + + /* In the single-buffer path, napi_build_skb() must see the + * actual backing allocation size so skb->truesize reflects + * the full page (or higher-order page), not just the usable + * packet area. + */ + *alloc_size = PAGE_SIZE << get_order(*alloc_size); return; } @@ -3425,6 +3432,7 @@ static int add_adev(struct gdma_dev *gd, const char *name) struct auxiliary_device *adev; struct mana_adev *madev; int ret; + int id; madev = kzalloc_obj(*madev); if (!madev) @@ -3434,7 +3442,8 @@ static int add_adev(struct gdma_dev *gd, const char *name) ret = mana_adev_idx_alloc(); if (ret < 0) goto idx_fail; - adev->id = ret; + id = ret; + adev->id = id; adev->name = name; adev->dev.parent = gd->gdma_context->dev; @@ -3460,7 +3469,7 @@ add_fail: auxiliary_device_uninit(adev); init_fail: - mana_adev_idx_free(adev->id); + mana_adev_idx_free(id); idx_fail: kfree(madev); diff --git a/drivers/net/ethernet/pensando/ionic/ionic_lif.c b/drivers/net/ethernet/pensando/ionic/ionic_lif.c index 8d040e611d5a..637e635bbf03 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_lif.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.c @@ -1719,13 +1719,18 @@ static int ionic_set_mac_address(struct net_device *netdev, void *sa) if (ether_addr_equal(netdev->dev_addr, mac)) return 0; - err = ionic_program_mac(lif, mac); - if (err < 0) - return err; + /* Only program macs for virtual functions to avoid losing the permanent + * Mac across warm reset/reboot. + */ + if (lif->ionic->pdev->is_virtfn) { + err = ionic_program_mac(lif, mac); + if (err < 0) + return err; - if (err > 0) - netdev_dbg(netdev, "%s: SET and GET ATTR Mac are not equal-due to old FW running\n", - __func__); + if (err > 0) + netdev_dbg(netdev, "%s: SET and GET ATTR Mac are not equal-due to old FW running\n", + __func__); + } err = eth_prepare_mac_addr_change(netdev, addr); if (err) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 6827c99bde8c..13d3cac056be 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -156,7 +156,7 @@ static void stmmac_tx_timer_arm(struct stmmac_priv *priv, u32 queue); static void stmmac_flush_tx_descriptors(struct stmmac_priv *priv, int queue); static void stmmac_set_dma_operation_mode(struct stmmac_priv *priv, u32 txmode, u32 rxmode, u32 chan); -static int stmmac_vlan_restore(struct stmmac_priv *priv); +static void stmmac_vlan_restore(struct stmmac_priv *priv); #ifdef CONFIG_DEBUG_FS static const struct net_device_ops stmmac_netdev_ops; @@ -6859,21 +6859,15 @@ del_vlan_error: return ret; } -static int stmmac_vlan_restore(struct stmmac_priv *priv) +static void stmmac_vlan_restore(struct stmmac_priv *priv) { - int ret; - if (!(priv->dev->features & NETIF_F_VLAN_FEATURES)) - return 0; + return; if (priv->hw->num_vlan) stmmac_restore_hw_vlan_rx_fltr(priv, priv->dev, priv->hw); - ret = stmmac_vlan_update(priv, priv->num_double_vlans); - if (ret) - netdev_err(priv->dev, "Failed to restore VLANs\n"); - - return ret; + stmmac_vlan_update(priv, priv->num_double_vlans); } static int stmmac_bpf(struct net_device *dev, struct netdev_bpf *bpf) diff --git a/drivers/net/ethernet/ti/icssg/icssg_common.c b/drivers/net/ethernet/ti/icssg/icssg_common.c index 0a3cf2f848a5..a28a608f9bf4 100644 --- a/drivers/net/ethernet/ti/icssg/icssg_common.c +++ b/drivers/net/ethernet/ti/icssg/icssg_common.c @@ -902,6 +902,7 @@ static void emac_dispatch_skb_zc(struct prueth_emac *emac, struct xdp_buff *xdp, skb_reserve(skb, headroom); skb_put(skb, pkt_len); + skb_copy_to_linear_data(skb, xdp->data, pkt_len); skb->dev = ndev; /* RX HW timestamp */ @@ -912,7 +913,6 @@ static void emac_dispatch_skb_zc(struct prueth_emac *emac, struct xdp_buff *xdp, skb->offload_fwd_mark = emac->offload_fwd_mark; skb->protocol = eth_type_trans(skb, ndev); - skb_mark_for_recycle(skb); napi_gro_receive(&emac->napi_rx, skb); ndev->stats.rx_bytes += pkt_len; ndev->stats.rx_packets++; @@ -962,7 +962,6 @@ static int emac_rx_packet_zc(struct prueth_emac *emac, u32 flow_id, pkt_len -= 4; cppi5_desc_get_tags_ids(&desc_rx->hdr, &port_id, NULL); psdata = cppi5_hdesc_get_psdata(desc_rx); - k3_cppi_desc_pool_free(rx_chn->desc_pool, desc_rx); count++; xsk_buff_set_size(xdp, pkt_len); xsk_buff_dma_sync_for_cpu(xdp); @@ -988,6 +987,7 @@ static int emac_rx_packet_zc(struct prueth_emac *emac, u32 flow_id, emac_dispatch_skb_zc(emac, xdp, psdata); xsk_buff_free(xdp); } + k3_cppi_desc_pool_free(rx_chn->desc_pool, desc_rx); } if (xdp_status & ICSSG_XDP_REDIR) @@ -1057,7 +1057,6 @@ static int emac_rx_packet(struct prueth_emac *emac, u32 flow_id, u32 *xdp_state) /* firmware adds 4 CRC bytes, strip them */ pkt_len -= 4; cppi5_desc_get_tags_ids(&desc_rx->hdr, &port_id, NULL); - k3_cppi_desc_pool_free(rx_chn->desc_pool, desc_rx); /* if allocation fails we drop the packet but push the * descriptor back to the ring with old page to prevent a stall @@ -1115,6 +1114,7 @@ static int emac_rx_packet(struct prueth_emac *emac, u32 flow_id, u32 *xdp_state) ndev->stats.rx_packets++; requeue: + k3_cppi_desc_pool_free(rx_chn->desc_pool, desc_rx); /* queue another RX DMA */ ret = prueth_dma_rx_push_mapped(emac, &emac->rx_chns, new_page, PRUETH_MAX_PKT_SIZE); diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet.h b/drivers/net/ethernet/xilinx/xilinx_axienet.h index 5ff742103beb..fcd3aaef27fc 100644 --- a/drivers/net/ethernet/xilinx/xilinx_axienet.h +++ b/drivers/net/ethernet/xilinx/xilinx_axienet.h @@ -105,7 +105,7 @@ #define XAXIDMA_BD_HAS_DRE_MASK 0xF00 /* Whether has DRE mask */ #define XAXIDMA_BD_WORDLEN_MASK 0xFF /* Whether has DRE mask */ -#define XAXIDMA_BD_CTRL_LENGTH_MASK 0x007FFFFF /* Requested len */ +#define XAXIDMA_BD_CTRL_LENGTH_MASK GENMASK(25, 0) /* Requested len */ #define XAXIDMA_BD_CTRL_TXSOF_MASK 0x08000000 /* First tx packet */ #define XAXIDMA_BD_CTRL_TXEOF_MASK 0x04000000 /* Last tx packet */ #define XAXIDMA_BD_CTRL_ALL_MASK 0x0C000000 /* All control bits */ @@ -130,7 +130,7 @@ #define XAXIDMA_BD_CTRL_TXEOF_MASK 0x04000000 /* Last tx packet */ #define XAXIDMA_BD_CTRL_ALL_MASK 0x0C000000 /* All control bits */ -#define XAXIDMA_BD_STS_ACTUAL_LEN_MASK 0x007FFFFF /* Actual len */ +#define XAXIDMA_BD_STS_ACTUAL_LEN_MASK GENMASK(25, 0) /* Actual len */ #define XAXIDMA_BD_STS_COMPLETE_MASK 0x80000000 /* Completed */ #define XAXIDMA_BD_STS_DEC_ERR_MASK 0x40000000 /* Decode error */ #define XAXIDMA_BD_STS_SLV_ERR_MASK 0x20000000 /* Slave error */ diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c index b06e4c37ff61..263c4b67fd5a 100644 --- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c +++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c @@ -770,8 +770,8 @@ static int axienet_device_reset(struct net_device *ndev) * @first_bd: Index of first descriptor to clean up * @nr_bds: Max number of descriptors to clean up * @force: Whether to clean descriptors even if not complete - * @sizep: Pointer to a u32 filled with the total sum of all bytes - * in all cleaned-up descriptors. Ignored if NULL. + * @sizep: Pointer to a u32 accumulating the total byte count of + * completed packets (using skb->len). Ignored if NULL. * @budget: NAPI budget (use 0 when not called from NAPI poll) * * Would either be called after a successful transmit operation, or after @@ -805,6 +805,8 @@ static int axienet_free_tx_chain(struct axienet_local *lp, u32 first_bd, DMA_TO_DEVICE); if (cur_p->skb && (status & XAXIDMA_BD_STS_COMPLETE_MASK)) { + if (sizep) + *sizep += cur_p->skb->len; napi_consume_skb(cur_p->skb, budget); packets++; } @@ -818,9 +820,6 @@ static int axienet_free_tx_chain(struct axienet_local *lp, u32 first_bd, wmb(); cur_p->cntrl = 0; cur_p->status = 0; - - if (sizep) - *sizep += status & XAXIDMA_BD_STS_ACTUAL_LEN_MASK; } if (!force) { diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c index 5db841377199..ce8924613363 100644 --- a/drivers/net/phy/sfp.c +++ b/drivers/net/phy/sfp.c @@ -480,11 +480,16 @@ static void sfp_quirk_ubnt_uf_instant(const struct sfp_eeprom_id *id, { /* Ubiquiti U-Fiber Instant module claims that support all transceiver * types including 10G Ethernet which is not truth. So clear all claimed - * modes and set only one mode which module supports: 1000baseX_Full. + * modes and set only one mode which module supports: 1000baseX_Full, + * along with the Autoneg and pause bits. */ linkmode_zero(caps->link_modes); linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT, caps->link_modes); + linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, caps->link_modes); + linkmode_set_bit(ETHTOOL_LINK_MODE_Pause_BIT, caps->link_modes); + linkmode_set_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, caps->link_modes); + phy_interface_zero(caps->interfaces); __set_bit(PHY_INTERFACE_MODE_1000BASEX, caps->interfaces); } diff --git a/drivers/net/team/team_core.c b/drivers/net/team/team_core.c index b7282f5c9632..120aeb539d9f 100644 --- a/drivers/net/team/team_core.c +++ b/drivers/net/team/team_core.c @@ -2058,6 +2058,68 @@ static const struct ethtool_ops team_ethtool_ops = { * rt netlink interface ***********************/ +/* For tx path we need a linkup && enabled port and for parse any port + * suffices. + */ +static struct team_port *team_header_port_get_rcu(struct team *team, + bool txable) +{ + struct team_port *port; + + list_for_each_entry_rcu(port, &team->port_list, list) { + if (!txable || team_port_txable(port)) + return port; + } + + return NULL; +} + +static int team_header_create(struct sk_buff *skb, struct net_device *team_dev, + unsigned short type, const void *daddr, + const void *saddr, unsigned int len) +{ + struct team *team = netdev_priv(team_dev); + const struct header_ops *port_ops; + struct team_port *port; + int ret = 0; + + rcu_read_lock(); + port = team_header_port_get_rcu(team, true); + if (port) { + port_ops = READ_ONCE(port->dev->header_ops); + if (port_ops && port_ops->create) + ret = port_ops->create(skb, port->dev, + type, daddr, saddr, len); + } + rcu_read_unlock(); + return ret; +} + +static int team_header_parse(const struct sk_buff *skb, + const struct net_device *team_dev, + unsigned char *haddr) +{ + struct team *team = netdev_priv(team_dev); + const struct header_ops *port_ops; + struct team_port *port; + int ret = 0; + + rcu_read_lock(); + port = team_header_port_get_rcu(team, false); + if (port) { + port_ops = READ_ONCE(port->dev->header_ops); + if (port_ops && port_ops->parse) + ret = port_ops->parse(skb, port->dev, haddr); + } + rcu_read_unlock(); + return ret; +} + +static const struct header_ops team_header_ops = { + .create = team_header_create, + .parse = team_header_parse, +}; + static void team_setup_by_port(struct net_device *dev, struct net_device *port_dev) { @@ -2066,7 +2128,8 @@ static void team_setup_by_port(struct net_device *dev, if (port_dev->type == ARPHRD_ETHER) dev->header_ops = team->header_ops_cache; else - dev->header_ops = port_dev->header_ops; + dev->header_ops = port_dev->header_ops ? + &team_header_ops : NULL; dev->type = port_dev->type; dev->hard_header_len = port_dev->hard_header_len; dev->needed_headroom = port_dev->needed_headroom; diff --git a/drivers/net/tun_vnet.h b/drivers/net/tun_vnet.h index a5f93b6c4482..fa5cab9d3e55 100644 --- a/drivers/net/tun_vnet.h +++ b/drivers/net/tun_vnet.h @@ -244,7 +244,7 @@ tun_vnet_hdr_tnl_from_skb(unsigned int flags, if (virtio_net_hdr_tnl_from_skb(skb, tnl_hdr, has_tnl_offload, tun_vnet_is_little_endian(flags), - vlan_hlen, true)) { + vlan_hlen, true, false)) { struct virtio_net_hdr_v1 *hdr = &tnl_hdr->hash_hdr.hdr; struct skb_shared_info *sinfo = skb_shinfo(skb); diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 72d6a9c6a5a2..c0b9bc5574e2 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -381,8 +381,6 @@ struct receive_queue { struct xdp_buff **xsk_buffs; }; -#define VIRTIO_NET_RSS_MAX_KEY_SIZE 40 - /* Control VQ buffers: protected by the rtnl lock */ struct control_buf { struct virtio_net_ctrl_hdr hdr; @@ -486,7 +484,7 @@ struct virtnet_info { /* Must be last as it ends in a flexible-array member. */ TRAILING_OVERLAP(struct virtio_net_rss_config_trailer, rss_trailer, hash_key_data, - u8 rss_hash_key_data[VIRTIO_NET_RSS_MAX_KEY_SIZE]; + u8 rss_hash_key_data[NETDEV_RSS_KEY_LEN]; ); }; static_assert(offsetof(struct virtnet_info, rss_trailer.hash_key_data) == @@ -3267,8 +3265,12 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb, bool orphan) struct virtio_net_hdr_v1_hash_tunnel *hdr; int num_sg; unsigned hdr_len = vi->hdr_len; + bool feature_hdrlen; bool can_push; + feature_hdrlen = virtio_has_feature(vi->vdev, + VIRTIO_NET_F_GUEST_HDRLEN); + pr_debug("%s: xmit %p %pM\n", vi->dev->name, skb, dest); /* Make sure it's safe to cast between formats */ @@ -3288,7 +3290,7 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb, bool orphan) if (virtio_net_hdr_tnl_from_skb(skb, hdr, vi->tx_tnl, virtio_is_little_endian(vi->vdev), 0, - false)) + false, feature_hdrlen)) return -EPROTO; if (vi->mergeable_rx_bufs) @@ -3351,6 +3353,7 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev) /* Don't wait up for transmitted skbs to be freed. */ if (!use_napi) { skb_orphan(skb); + skb_dst_drop(skb); nf_reset_ct(skb); } @@ -6703,6 +6706,7 @@ static int virtnet_probe(struct virtio_device *vdev) struct virtnet_info *vi; u16 max_queue_pairs; int mtu = 0; + u16 key_sz; /* Find if host supports multiqueue/rss virtio_net device */ max_queue_pairs = 1; @@ -6837,14 +6841,13 @@ static int virtnet_probe(struct virtio_device *vdev) } if (vi->has_rss || vi->has_rss_hash_report) { - vi->rss_key_size = - virtio_cread8(vdev, offsetof(struct virtio_net_config, rss_max_key_size)); - if (vi->rss_key_size > VIRTIO_NET_RSS_MAX_KEY_SIZE) { - dev_err(&vdev->dev, "rss_max_key_size=%u exceeds the limit %u.\n", - vi->rss_key_size, VIRTIO_NET_RSS_MAX_KEY_SIZE); - err = -EINVAL; - goto free; - } + key_sz = virtio_cread8(vdev, offsetof(struct virtio_net_config, rss_max_key_size)); + + vi->rss_key_size = min_t(u16, key_sz, NETDEV_RSS_KEY_LEN); + if (key_sz > vi->rss_key_size) + dev_warn(&vdev->dev, + "rss_max_key_size=%u exceeds driver limit %u, clamping\n", + key_sz, vi->rss_key_size); vi->rss_hash_types_supported = virtio_cread32(vdev, offsetof(struct virtio_net_config, supported_hash_types)); diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c index 17c941aac32d..a94ac82a6136 100644 --- a/drivers/net/vxlan/vxlan_core.c +++ b/drivers/net/vxlan/vxlan_core.c @@ -1965,12 +1965,14 @@ static struct sk_buff *vxlan_na_create(struct sk_buff *request, ns_olen = request->len - skb_network_offset(request) - sizeof(struct ipv6hdr) - sizeof(*ns); for (i = 0; i < ns_olen-1; i += (ns->opt[i+1]<<3)) { - if (!ns->opt[i + 1]) { + if (!ns->opt[i + 1] || i + (ns->opt[i + 1] << 3) > ns_olen) { kfree_skb(reply); return NULL; } if (ns->opt[i] == ND_OPT_SOURCE_LL_ADDR) { - daddr = ns->opt + i + sizeof(struct nd_opt_hdr); + if ((ns->opt[i + 1] << 3) >= + sizeof(struct nd_opt_hdr) + ETH_ALEN) + daddr = ns->opt + i + sizeof(struct nd_opt_hdr); break; } } diff --git a/drivers/net/wireless/ath/ath11k/dp_rx.c b/drivers/net/wireless/ath/ath11k/dp_rx.c index 49d959b2e148..85defe11750d 100644 --- a/drivers/net/wireless/ath/ath11k/dp_rx.c +++ b/drivers/net/wireless/ath/ath11k/dp_rx.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #include <linux/ieee80211.h> @@ -1110,9 +1110,8 @@ int ath11k_dp_rx_ampdu_stop(struct ath11k *ar, struct ath11k_base *ab = ar->ab; struct ath11k_peer *peer; struct ath11k_sta *arsta = ath11k_sta_to_arsta(params->sta); + struct dp_rx_tid *rx_tid; int vdev_id = arsta->arvif->vdev_id; - dma_addr_t paddr; - bool active; int ret; spin_lock_bh(&ab->base_lock); @@ -1124,15 +1123,14 @@ int ath11k_dp_rx_ampdu_stop(struct ath11k *ar, return -ENOENT; } - paddr = peer->rx_tid[params->tid].paddr; - active = peer->rx_tid[params->tid].active; + rx_tid = &peer->rx_tid[params->tid]; - if (!active) { + if (!rx_tid->active) { spin_unlock_bh(&ab->base_lock); return 0; } - ret = ath11k_peer_rx_tid_reo_update(ar, peer, peer->rx_tid, 1, 0, false); + ret = ath11k_peer_rx_tid_reo_update(ar, peer, rx_tid, 1, 0, false); spin_unlock_bh(&ab->base_lock); if (ret) { ath11k_warn(ab, "failed to update reo for rx tid %d: %d\n", @@ -1141,7 +1139,8 @@ int ath11k_dp_rx_ampdu_stop(struct ath11k *ar, } ret = ath11k_wmi_peer_rx_reorder_queue_setup(ar, vdev_id, - params->sta->addr, paddr, + params->sta->addr, + rx_tid->paddr, params->tid, 1, 1); if (ret) ath11k_warn(ab, "failed to send wmi to delete rx tid %d\n", diff --git a/drivers/net/wireless/ath/ath12k/dp_rx.c b/drivers/net/wireless/ath/ath12k/dp_rx.c index 5a82ede65dd3..244d5230a5bd 100644 --- a/drivers/net/wireless/ath/ath12k/dp_rx.c +++ b/drivers/net/wireless/ath/ath12k/dp_rx.c @@ -735,6 +735,7 @@ int ath12k_dp_rx_ampdu_stop(struct ath12k *ar, struct ath12k_dp *dp = ath12k_ab_to_dp(ab); struct ath12k_dp_link_peer *peer; struct ath12k_sta *ahsta = ath12k_sta_to_ahsta(params->sta); + struct ath12k_dp_rx_tid *rx_tid; struct ath12k_link_sta *arsta; int vdev_id; bool active; @@ -770,7 +771,8 @@ int ath12k_dp_rx_ampdu_stop(struct ath12k *ar, return 0; } - ret = ath12k_dp_arch_peer_rx_tid_reo_update(dp, peer, peer->dp_peer->rx_tid, + rx_tid = &peer->dp_peer->rx_tid[params->tid]; + ret = ath12k_dp_arch_peer_rx_tid_reo_update(dp, peer, rx_tid, 1, 0, false); spin_unlock_bh(&dp->dp_lock); if (ret) { diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h b/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h index 8d64a271bb94..36159a769916 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h @@ -297,6 +297,11 @@ enum iwl_legacy_cmds { SCAN_OFFLOAD_UPDATE_PROFILES_CMD = 0x6E, /** + * @SCAN_START_NOTIFICATION_UMAC: uses &struct iwl_umac_scan_start + */ + SCAN_START_NOTIFICATION_UMAC = 0xb2, + + /** * @MATCH_FOUND_NOTIFICATION: scan match found */ MATCH_FOUND_NOTIFICATION = 0xd9, diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h b/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h index 60f0a4924ddf..46fcc32608e3 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h @@ -1157,6 +1157,16 @@ enum iwl_umac_scan_abort_status { }; /** + * struct iwl_umac_scan_start - scan start notification + * @uid: scan id, &enum iwl_umac_scan_uid_offsets + * @reserved: for future use + */ +struct iwl_umac_scan_start { + __le32 uid; + __le32 reserved; +} __packed; /* SCAN_START_UMAC_API_S_VER_1 */ + +/** * struct iwl_umac_scan_complete - scan complete notification * @uid: scan id, &enum iwl_umac_scan_uid_offsets * @last_schedule: last scheduling line diff --git a/drivers/net/wireless/intel/iwlwifi/mld/iface.c b/drivers/net/wireless/intel/iwlwifi/mld/iface.c index 29df747c8938..9215fc7e2eca 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/iface.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/iface.c @@ -111,14 +111,75 @@ static bool iwl_mld_is_nic_ack_enabled(struct iwl_mld *mld, IEEE80211_HE_MAC_CAP2_ACK_EN); } -static void iwl_mld_set_he_support(struct iwl_mld *mld, - struct ieee80211_vif *vif, - struct iwl_mac_config_cmd *cmd) +struct iwl_mld_mac_wifi_gen_sta_iter_data { + struct ieee80211_vif *vif; + struct iwl_mac_wifi_gen_support *support; +}; + +static void iwl_mld_mac_wifi_gen_sta_iter(void *_data, + struct ieee80211_sta *sta) { - if (vif->type == NL80211_IFTYPE_AP) - cmd->wifi_gen.he_ap_support = 1; - else - cmd->wifi_gen.he_support = 1; + struct iwl_mld_sta *mld_sta = iwl_mld_sta_from_mac80211(sta); + struct iwl_mld_mac_wifi_gen_sta_iter_data *data = _data; + struct ieee80211_link_sta *link_sta; + unsigned int link_id; + + if (mld_sta->vif != data->vif) + return; + + for_each_sta_active_link(data->vif, sta, link_sta, link_id) { + if (link_sta->he_cap.has_he) + data->support->he_support = 1; + if (link_sta->eht_cap.has_eht) + data->support->eht_support = 1; + } +} + +static void iwl_mld_set_wifi_gen(struct iwl_mld *mld, + struct ieee80211_vif *vif, + struct iwl_mac_wifi_gen_support *support) +{ + struct iwl_mld_mac_wifi_gen_sta_iter_data sta_iter_data = { + .vif = vif, + .support = support, + }; + struct ieee80211_bss_conf *link_conf; + unsigned int link_id; + + switch (vif->type) { + case NL80211_IFTYPE_MONITOR: + /* for sniffer, set to HW capabilities */ + support->he_support = 1; + support->eht_support = mld->trans->cfg->eht_supported; + break; + case NL80211_IFTYPE_AP: + /* for AP set according to the link configs */ + for_each_vif_active_link(vif, link_conf, link_id) { + support->he_ap_support |= link_conf->he_support; + support->eht_support |= link_conf->eht_support; + } + break; + default: + /* + * If we have MLO enabled, then the firmware needs to enable + * address translation for the station(s) we add. That depends + * on having EHT enabled in firmware, which in turn depends on + * mac80211 in the iteration below. + * However, mac80211 doesn't enable capabilities on the AP STA + * until it has parsed the association response successfully, + * so set EHT (and HE as a pre-requisite for EHT) when the vif + * is an MLD. + */ + if (ieee80211_vif_is_mld(vif)) { + support->he_support = 1; + support->eht_support = 1; + } + + ieee80211_iterate_stations_mtx(mld->hw, + iwl_mld_mac_wifi_gen_sta_iter, + &sta_iter_data); + break; + } } /* fill the common part for all interface types */ @@ -128,8 +189,6 @@ static void iwl_mld_mac_cmd_fill_common(struct iwl_mld *mld, u32 action) { struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif); - struct ieee80211_bss_conf *link_conf; - unsigned int link_id; lockdep_assert_wiphy(mld->wiphy); @@ -147,29 +206,7 @@ static void iwl_mld_mac_cmd_fill_common(struct iwl_mld *mld, cmd->nic_not_ack_enabled = cpu_to_le32(!iwl_mld_is_nic_ack_enabled(mld, vif)); - /* If we have MLO enabled, then the firmware needs to enable - * address translation for the station(s) we add. That depends - * on having EHT enabled in firmware, which in turn depends on - * mac80211 in the code below. - * However, mac80211 doesn't enable HE/EHT until it has parsed - * the association response successfully, so just skip all that - * and enable both when we have MLO. - */ - if (ieee80211_vif_is_mld(vif)) { - iwl_mld_set_he_support(mld, vif, cmd); - cmd->wifi_gen.eht_support = 1; - return; - } - - for_each_vif_active_link(vif, link_conf, link_id) { - if (!link_conf->he_support) - continue; - - iwl_mld_set_he_support(mld, vif, cmd); - - /* EHT, if supported, was already set above */ - break; - } + iwl_mld_set_wifi_gen(mld, vif, &cmd->wifi_gen); } static void iwl_mld_fill_mac_cmd_sta(struct iwl_mld *mld, diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c index 0c53d6bd9651..71a9a72c9ac0 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c @@ -1761,6 +1761,16 @@ static int iwl_mld_move_sta_state_up(struct iwl_mld *mld, if (vif->type == NL80211_IFTYPE_STATION) iwl_mld_link_set_2mhz_block(mld, vif, sta); + + if (sta->tdls) { + /* + * update MAC since wifi generation flags may change, + * we also update MAC on association to the AP via the + * vif assoc change + */ + iwl_mld_mac_fw_action(mld, vif, FW_CTXT_ACTION_MODIFY); + } + /* Now the link_sta's capabilities are set, update the FW */ iwl_mld_config_tlc(mld, vif, sta); @@ -1873,6 +1883,15 @@ static int iwl_mld_move_sta_state_down(struct iwl_mld *mld, /* just removed last TDLS STA, so enable PM */ iwl_mld_update_mac_power(mld, vif, false); } + + if (sta->tdls) { + /* + * update MAC since wifi generation flags may change, + * we also update MAC on disassociation to the AP via + * the vif assoc change + */ + iwl_mld_mac_fw_action(mld, vif, FW_CTXT_ACTION_MODIFY); + } } else { return -EINVAL; } diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mld.c b/drivers/net/wireless/intel/iwlwifi/mld/mld.c index 495e9d8f3af6..9af79297c3b6 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/mld.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/mld.c @@ -171,6 +171,7 @@ static const struct iwl_hcmd_names iwl_mld_legacy_names[] = { HCMD_NAME(MISSED_BEACONS_NOTIFICATION), HCMD_NAME(MAC_PM_POWER_TABLE), HCMD_NAME(MFUART_LOAD_NOTIFICATION), + HCMD_NAME(SCAN_START_NOTIFICATION_UMAC), HCMD_NAME(RSS_CONFIG_CMD), HCMD_NAME(SCAN_ITERATION_COMPLETE_UMAC), HCMD_NAME(REPLY_RX_MPDU_CMD), diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mlo.c b/drivers/net/wireless/intel/iwlwifi/mld/mlo.c index f842f5183223..fbff5915f7fd 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/mlo.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/mlo.c @@ -739,7 +739,7 @@ iwl_mld_set_link_sel_data(struct iwl_mld *mld, /* Ignore any BSS that was not seen in the last MLO scan */ if (ktime_before(link_conf->bss->ts_boottime, - mld->scan.last_mlo_scan_time)) + mld->scan.last_mlo_scan_start_time)) continue; data[n_data].link_id = link_id; @@ -945,7 +945,7 @@ static void _iwl_mld_select_links(struct iwl_mld *mld, if (!mld_vif->authorized || hweight16(usable_links) <= 1) return; - if (WARN(ktime_before(mld->scan.last_mlo_scan_time, + if (WARN(ktime_before(mld->scan.last_mlo_scan_start_time, ktime_sub_ns(ktime_get_boottime_ns(), 5ULL * NSEC_PER_SEC)), "Last MLO scan was too long ago, can't select links\n")) diff --git a/drivers/net/wireless/intel/iwlwifi/mld/notif.c b/drivers/net/wireless/intel/iwlwifi/mld/notif.c index 240526d8b632..9c88a8579a75 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/notif.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/notif.c @@ -287,6 +287,8 @@ static void iwl_mld_handle_beacon_notification(struct iwl_mld *mld, * at least enough bytes to cover the structure listed in the CMD_VER_ENTRY. */ +CMD_VERSIONS(scan_start_notif, + CMD_VER_ENTRY(1, iwl_umac_scan_start)) CMD_VERSIONS(scan_complete_notif, CMD_VER_ENTRY(1, iwl_umac_scan_complete)) CMD_VERSIONS(scan_iter_complete_notif, @@ -360,6 +362,7 @@ DEFINE_SIMPLE_CANCELLATION(datapath_monitor, iwl_datapath_monitor_notif, link_id) DEFINE_SIMPLE_CANCELLATION(roc, iwl_roc_notif, activity) DEFINE_SIMPLE_CANCELLATION(scan_complete, iwl_umac_scan_complete, uid) +DEFINE_SIMPLE_CANCELLATION(scan_start, iwl_umac_scan_start, uid) DEFINE_SIMPLE_CANCELLATION(probe_resp_data, iwl_probe_resp_data_notif, mac_id) DEFINE_SIMPLE_CANCELLATION(uapsd_misbehaving_ap, iwl_uapsd_misbehaving_ap_notif, @@ -402,6 +405,8 @@ const struct iwl_rx_handler iwl_mld_rx_handlers[] = { RX_HANDLER_SYNC) RX_HANDLER_NO_OBJECT(LEGACY_GROUP, BA_NOTIF, compressed_ba_notif, RX_HANDLER_SYNC) + RX_HANDLER_OF_SCAN(LEGACY_GROUP, SCAN_START_NOTIFICATION_UMAC, + scan_start_notif) RX_HANDLER_OF_SCAN(LEGACY_GROUP, SCAN_COMPLETE_UMAC, scan_complete_notif) RX_HANDLER_NO_OBJECT(LEGACY_GROUP, SCAN_ITERATION_COMPLETE_UMAC, diff --git a/drivers/net/wireless/intel/iwlwifi/mld/scan.c b/drivers/net/wireless/intel/iwlwifi/mld/scan.c index a1a4cf3ab3d3..abd4281b4b0e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/scan.c @@ -473,6 +473,9 @@ iwl_mld_scan_get_cmd_gen_flags(struct iwl_mld *mld, params->flags & NL80211_SCAN_FLAG_COLOCATED_6GHZ) flags |= IWL_UMAC_SCAN_GEN_FLAGS_V2_TRIGGER_UHB_SCAN; + if (scan_status == IWL_MLD_SCAN_INT_MLO) + flags |= IWL_UMAC_SCAN_GEN_FLAGS_V2_NTF_START; + if (params->enable_6ghz_passive) flags |= IWL_UMAC_SCAN_GEN_FLAGS_V2_6GHZ_PASSIVE_SCAN; @@ -1817,9 +1820,6 @@ static void iwl_mld_int_mlo_scan_start(struct iwl_mld *mld, ret = _iwl_mld_single_scan_start(mld, vif, req, &ies, IWL_MLD_SCAN_INT_MLO); - if (!ret) - mld->scan.last_mlo_scan_time = ktime_get_boottime_ns(); - IWL_DEBUG_SCAN(mld, "Internal MLO scan: ret=%d\n", ret); } @@ -1904,6 +1904,30 @@ void iwl_mld_handle_match_found_notif(struct iwl_mld *mld, ieee80211_sched_scan_results(mld->hw); } +void iwl_mld_handle_scan_start_notif(struct iwl_mld *mld, + struct iwl_rx_packet *pkt) +{ + struct iwl_umac_scan_complete *notif = (void *)pkt->data; + u32 uid = le32_to_cpu(notif->uid); + + if (IWL_FW_CHECK(mld, uid >= ARRAY_SIZE(mld->scan.uid_status), + "FW reports out-of-range scan UID %d\n", uid)) + return; + + if (IWL_FW_CHECK(mld, !(mld->scan.uid_status[uid] & mld->scan.status), + "FW reports scan UID %d we didn't trigger\n", uid)) + return; + + IWL_DEBUG_SCAN(mld, "Scan started: uid=%u type=%u\n", uid, + mld->scan.uid_status[uid]); + if (IWL_FW_CHECK(mld, mld->scan.uid_status[uid] != IWL_MLD_SCAN_INT_MLO, + "FW reports scan start notification %d we didn't trigger\n", + mld->scan.uid_status[uid])) + return; + + mld->scan.last_mlo_scan_start_time = ktime_get_boottime_ns(); +} + void iwl_mld_handle_scan_complete_notif(struct iwl_mld *mld, struct iwl_rx_packet *pkt) { diff --git a/drivers/net/wireless/intel/iwlwifi/mld/scan.h b/drivers/net/wireless/intel/iwlwifi/mld/scan.h index 69110f0cfc8e..de5620e7f463 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/scan.h +++ b/drivers/net/wireless/intel/iwlwifi/mld/scan.h @@ -27,6 +27,9 @@ int iwl_mld_sched_scan_start(struct iwl_mld *mld, void iwl_mld_handle_match_found_notif(struct iwl_mld *mld, struct iwl_rx_packet *pkt); +void iwl_mld_handle_scan_start_notif(struct iwl_mld *mld, + struct iwl_rx_packet *pkt); + void iwl_mld_handle_scan_complete_notif(struct iwl_mld *mld, struct iwl_rx_packet *pkt); @@ -114,8 +117,8 @@ enum iwl_mld_traffic_load { * in jiffies. * @last_start_time_jiffies: stores the last start time in jiffies * (interface up/reset/resume). - * @last_mlo_scan_time: start time of the last MLO scan in nanoseconds since - * boot. + * @last_mlo_scan_start_time: start time of the last MLO scan in nanoseconds + * since boot. */ struct iwl_mld_scan { /* Add here fields that need clean up on restart */ @@ -136,7 +139,7 @@ struct iwl_mld_scan { void *cmd; unsigned long last_6ghz_passive_jiffies; unsigned long last_start_time_jiffies; - u64 last_mlo_scan_time; + u64 last_mlo_scan_start_time; }; /** diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index a19f9d2e9346..9a74f60c9185 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -2807,7 +2807,7 @@ static void iwl_mvm_nd_match_info_handler(struct iwl_mvm *mvm, if (IS_ERR_OR_NULL(vif)) return; - if (len < sizeof(struct iwl_scan_offload_match_info)) { + if (len < sizeof(struct iwl_scan_offload_match_info) + matches_len) { IWL_ERR(mvm, "Invalid scan match info notification\n"); return; } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 43cf94c9a36b..6cc78661116e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -470,7 +470,8 @@ static void iwl_mvm_uats_init(struct iwl_mvm *mvm) .dataflags[0] = IWL_HCMD_DFL_NOCOPY, }; - if (mvm->trans->mac_cfg->device_family < IWL_DEVICE_FAMILY_AX210) { + if (mvm->trans->mac_cfg->device_family < IWL_DEVICE_FAMILY_AX210 || + !mvm->trans->cfg->uhb_supported) { IWL_DEBUG_RADIO(mvm, "UATS feature is not supported\n"); return; } diff --git a/drivers/net/wireless/microchip/wilc1000/hif.c b/drivers/net/wireless/microchip/wilc1000/hif.c index f354b11cb919..944b2a812b63 100644 --- a/drivers/net/wireless/microchip/wilc1000/hif.c +++ b/drivers/net/wireless/microchip/wilc1000/hif.c @@ -163,7 +163,7 @@ int wilc_scan(struct wilc_vif *vif, u8 scan_source, u32 index = 0; u32 i, scan_timeout; u8 *buffer; - u8 valuesize = 0; + u32 valuesize = 0; u8 *search_ssid_vals = NULL; const u8 ch_list_len = request->n_channels; struct host_if_drv *hif_drv = vif->hif_drv; diff --git a/drivers/net/wireless/ti/wl1251/tx.c b/drivers/net/wireless/ti/wl1251/tx.c index 2da8c0d5105b..4489aa77bb0f 100644 --- a/drivers/net/wireless/ti/wl1251/tx.c +++ b/drivers/net/wireless/ti/wl1251/tx.c @@ -402,12 +402,14 @@ static void wl1251_tx_packet_cb(struct wl1251 *wl, int hdrlen; u8 *frame; - skb = wl->tx_frames[result->id]; - if (skb == NULL) { - wl1251_error("SKB for packet %d is NULL", result->id); + if (unlikely(result->id >= ARRAY_SIZE(wl->tx_frames) || + wl->tx_frames[result->id] == NULL)) { + wl1251_error("invalid packet id %u", result->id); return; } + skb = wl->tx_frames[result->id]; + info = IEEE80211_SKB_CB(skb); if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && diff --git a/drivers/net/wireless/virtual/virt_wifi.c b/drivers/net/wireless/virtual/virt_wifi.c index 885dc7243e8d..97bd39d89e98 100644 --- a/drivers/net/wireless/virtual/virt_wifi.c +++ b/drivers/net/wireless/virtual/virt_wifi.c @@ -557,7 +557,6 @@ static int virt_wifi_newlink(struct net_device *dev, eth_hw_addr_inherit(dev, priv->lowerdev); netif_stacked_transfer_operstate(priv->lowerdev, dev); - SET_NETDEV_DEV(dev, &priv->lowerdev->dev); dev->ieee80211_ptr = kzalloc_obj(*dev->ieee80211_ptr); if (!dev->ieee80211_ptr) { diff --git a/drivers/nfc/pn533/uart.c b/drivers/nfc/pn533/uart.c index 6d2f520a5bc8..1b82b7b2a5fa 100644 --- a/drivers/nfc/pn533/uart.c +++ b/drivers/nfc/pn533/uart.c @@ -211,6 +211,9 @@ static size_t pn532_receive_buf(struct serdev_device *serdev, timer_delete(&dev->cmd_timeout); for (i = 0; i < count; i++) { + if (unlikely(!skb_tailroom(dev->recv_skb))) + skb_trim(dev->recv_skb, 0); + skb_put_u8(dev->recv_skb, *data++); if (!pn532_uart_rx_is_frame(dev->recv_skb)) continue; diff --git a/drivers/nvmem/imx-ocotp-ele.c b/drivers/nvmem/imx-ocotp-ele.c index 7cf7e809a8f5..a0d2985c6d03 100644 --- a/drivers/nvmem/imx-ocotp-ele.c +++ b/drivers/nvmem/imx-ocotp-ele.c @@ -131,6 +131,7 @@ static int imx_ocotp_cell_pp(void *context, const char *id, int index, static void imx_ocotp_fixup_dt_cell_info(struct nvmem_device *nvmem, struct nvmem_cell_info *cell) { + cell->raw_len = round_up(cell->bytes, 4); cell->read_post_process = imx_ocotp_cell_pp; } diff --git a/drivers/nvmem/imx-ocotp.c b/drivers/nvmem/imx-ocotp.c index 7bf7656d4f96..108d78d7f6cb 100644 --- a/drivers/nvmem/imx-ocotp.c +++ b/drivers/nvmem/imx-ocotp.c @@ -589,6 +589,7 @@ MODULE_DEVICE_TABLE(of, imx_ocotp_dt_ids); static void imx_ocotp_fixup_dt_cell_info(struct nvmem_device *nvmem, struct nvmem_cell_info *cell) { + cell->raw_len = round_up(cell->bytes, 4); cell->read_post_process = imx_ocotp_cell_pp; } diff --git a/drivers/nvmem/zynqmp_nvmem.c b/drivers/nvmem/zynqmp_nvmem.c index 7da717d6c7fa..d297ff150dc0 100644 --- a/drivers/nvmem/zynqmp_nvmem.c +++ b/drivers/nvmem/zynqmp_nvmem.c @@ -66,7 +66,7 @@ static int zynqmp_efuse_access(void *context, unsigned int offset, dma_addr_t dma_buf; size_t words = bytes / WORD_INBYTES; int ret; - int value; + unsigned int value; char *data; if (bytes % WORD_INBYTES != 0) { @@ -80,7 +80,7 @@ static int zynqmp_efuse_access(void *context, unsigned int offset, } if (pufflag == 1 && flag == EFUSE_WRITE) { - memcpy(&value, val, bytes); + memcpy(&value, val, sizeof(value)); if ((offset == EFUSE_PUF_START_OFFSET || offset == EFUSE_PUF_MID_OFFSET) && value & P_USER_0_64_UPPER_MASK) { @@ -100,7 +100,7 @@ static int zynqmp_efuse_access(void *context, unsigned int offset, if (!efuse) return -ENOMEM; - data = dma_alloc_coherent(dev, sizeof(bytes), + data = dma_alloc_coherent(dev, bytes, &dma_buf, GFP_KERNEL); if (!data) { ret = -ENOMEM; @@ -134,7 +134,7 @@ static int zynqmp_efuse_access(void *context, unsigned int offset, if (flag == EFUSE_READ) memcpy(val, data, bytes); efuse_access_err: - dma_free_coherent(dev, sizeof(bytes), + dma_free_coherent(dev, bytes, data, dma_buf); efuse_data_fail: dma_free_coherent(dev, sizeof(struct xilinx_efuse), diff --git a/drivers/pci/pwrctrl/core.c b/drivers/pci/pwrctrl/core.c index 7754baed67f2..97cff5b8ca88 100644 --- a/drivers/pci/pwrctrl/core.c +++ b/drivers/pci/pwrctrl/core.c @@ -299,8 +299,10 @@ static bool pci_pwrctrl_is_required(struct device_node *np) struct device_node *remote __free(device_node) = of_graph_get_remote_port_parent(endpoint); if (remote) { - if (of_pci_supply_present(remote)) + if (of_pci_supply_present(remote)) { + of_node_put(endpoint); return true; + } } } } diff --git a/drivers/pci/pwrctrl/pci-pwrctrl-pwrseq.c b/drivers/pci/pwrctrl/pci-pwrctrl-pwrseq.c index 0d0377283c37..c7e4beec160a 100644 --- a/drivers/pci/pwrctrl/pci-pwrctrl-pwrseq.c +++ b/drivers/pci/pwrctrl/pci-pwrctrl-pwrseq.c @@ -68,13 +68,6 @@ static int pwrseq_pwrctrl_power_off(struct pci_pwrctrl *pwrctrl) return pwrseq_power_off(pwrseq->pwrseq); } -static void devm_pwrseq_pwrctrl_power_off(void *data) -{ - struct pwrseq_pwrctrl *pwrseq = data; - - pwrseq_pwrctrl_power_off(&pwrseq->pwrctrl); -} - static int pwrseq_pwrctrl_probe(struct platform_device *pdev) { const struct pwrseq_pwrctrl_pdata *pdata; @@ -101,11 +94,6 @@ static int pwrseq_pwrctrl_probe(struct platform_device *pdev) return dev_err_probe(dev, PTR_ERR(pwrseq->pwrseq), "Failed to get the power sequencer\n"); - ret = devm_add_action_or_reset(dev, devm_pwrseq_pwrctrl_power_off, - pwrseq); - if (ret) - return ret; - pwrseq->pwrctrl.power_on = pwrseq_pwrctrl_power_on; pwrseq->pwrctrl.power_off = pwrseq_pwrctrl_power_off; diff --git a/drivers/pci/pwrctrl/slot.c b/drivers/pci/pwrctrl/slot.c index 082af81efe25..b87639253ae2 100644 --- a/drivers/pci/pwrctrl/slot.c +++ b/drivers/pci/pwrctrl/slot.c @@ -63,7 +63,6 @@ static void devm_slot_pwrctrl_release(void *data) { struct slot_pwrctrl *slot = data; - slot_pwrctrl_power_off(&slot->pwrctrl); regulator_bulk_free(slot->num_supplies, slot->supplies); } diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index 02467dfd4fb0..1875d5b784f6 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -6,7 +6,7 @@ menu "PHY Subsystem" config PHY_COMMON_PROPS - bool + bool "PHY common properties" if KUNIT_ALL_TESTS help This parses properties common between generic PHYs and Ethernet PHYs. @@ -16,8 +16,7 @@ config PHY_COMMON_PROPS config PHY_COMMON_PROPS_TEST tristate "KUnit tests for PHY common props" if !KUNIT_ALL_TESTS - select PHY_COMMON_PROPS - depends on KUNIT + depends on KUNIT && PHY_COMMON_PROPS default KUNIT_ALL_TESTS help This builds KUnit tests for the PHY common property API. diff --git a/drivers/phy/freescale/phy-fsl-lynx-28g.c b/drivers/phy/freescale/phy-fsl-lynx-28g.c index 2b0fd95ba62f..63427fc34e26 100644 --- a/drivers/phy/freescale/phy-fsl-lynx-28g.c +++ b/drivers/phy/freescale/phy-fsl-lynx-28g.c @@ -1069,6 +1069,8 @@ static void lynx_28g_cdr_lock_check(struct work_struct *work) for (i = 0; i < LYNX_28G_NUM_LANE; i++) { lane = &priv->lane[i]; + if (!lane->phy) + continue; mutex_lock(&lane->phy->mutex); diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c index df138a5442eb..771bc7c2ab50 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c @@ -990,6 +990,7 @@ static const struct qmp_phy_init_tbl sm8650_ufsphy_pcs[] = { QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_MULTI_LANE_CTRL1, 0x02), QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_MID_TERM_CTRL1, 0x43), QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_PCS_CTRL1, 0xc1), + QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_PLL_CNTL, 0x33), QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_LARGE_AMP_DRV_LVL, 0x0f), QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_RX_SIGDET_CTRL2, 0x68), QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_POST_EMP_LVL_S4, 0x0e), @@ -999,13 +1000,11 @@ static const struct qmp_phy_init_tbl sm8650_ufsphy_pcs[] = { }; static const struct qmp_phy_init_tbl sm8650_ufsphy_g4_pcs[] = { - QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_PLL_CNTL, 0x13), QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_HSGEAR_CAPABILITY, 0x04), QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_RX_HSGEAR_CAPABILITY, 0x04), }; static const struct qmp_phy_init_tbl sm8650_ufsphy_g5_pcs[] = { - QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_PLL_CNTL, 0x33), QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_TX_HSGEAR_CAPABILITY, 0x05), QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_RX_HSGEAR_CAPABILITY, 0x05), QMP_PHY_INIT_CFG(QPHY_V6_PCS_UFS_RX_HS_G5_SYNC_LENGTH_CAPABILITY, 0x4d), diff --git a/drivers/phy/spacemit/phy-k1-usb2.c b/drivers/phy/spacemit/phy-k1-usb2.c index 342061380012..9215d0b223b2 100644 --- a/drivers/phy/spacemit/phy-k1-usb2.c +++ b/drivers/phy/spacemit/phy-k1-usb2.c @@ -48,6 +48,9 @@ #define PHY_CLK_HSTXP_EN BIT(3) /* clock hstxp enable */ #define PHY_HSTXP_MODE BIT(4) /* 0: force en_txp to be 1; 1: no force */ +#define PHY_K1_HS_HOST_DISC 0x40 +#define PHY_K1_HS_HOST_DISC_CLR BIT(0) + #define PHY_PLL_DIV_CFG 0x98 #define PHY_FDIV_FRACT_8_15 GENMASK(7, 0) #define PHY_FDIV_FRACT_16_19 GENMASK(11, 8) @@ -142,9 +145,20 @@ static int spacemit_usb2phy_exit(struct phy *phy) return 0; } +static int spacemit_usb2phy_disconnect(struct phy *phy, int port) +{ + struct spacemit_usb2phy *sphy = phy_get_drvdata(phy); + + regmap_update_bits(sphy->regmap_base, PHY_K1_HS_HOST_DISC, + PHY_K1_HS_HOST_DISC_CLR, PHY_K1_HS_HOST_DISC_CLR); + + return 0; +} + static const struct phy_ops spacemit_usb2phy_ops = { .init = spacemit_usb2phy_init, .exit = spacemit_usb2phy_exit, + .disconnect = spacemit_usb2phy_disconnect, .owner = THIS_MODULE, }; diff --git a/drivers/phy/ti/phy-j721e-wiz.c b/drivers/phy/ti/phy-j721e-wiz.c index 6e9ecb88dc8b..6b584706b913 100644 --- a/drivers/phy/ti/phy-j721e-wiz.c +++ b/drivers/phy/ti/phy-j721e-wiz.c @@ -1425,6 +1425,7 @@ static int wiz_get_lane_phy_types(struct device *dev, struct wiz *wiz) dev_err(dev, "%s: Reading \"reg\" from \"%s\" failed: %d\n", __func__, subnode->name, ret); + of_node_put(serdes); return ret; } of_property_read_u32(subnode, "cdns,num-lanes", &num_lanes); @@ -1439,6 +1440,7 @@ static int wiz_get_lane_phy_types(struct device *dev, struct wiz *wiz) } } + of_node_put(serdes); return 0; } diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c index d6a46fe0cda8..3f518dce6d23 100644 --- a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c +++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c @@ -1135,9 +1135,12 @@ int mtk_pctrl_init(struct platform_device *pdev, goto chip_error; } - ret = mtk_eint_init(pctl, pdev); - if (ret) - goto chip_error; + /* Only initialize EINT if we have EINT pins */ + if (data->eint_hw.ap_num > 0) { + ret = mtk_eint_init(pctl, pdev); + if (ret) + goto chip_error; + } return 0; diff --git a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c index 83f940fe30b2..d02d42513ebb 100644 --- a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c +++ b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c @@ -723,6 +723,21 @@ static const struct pinconf_ops pmic_gpio_pinconf_ops = { .pin_config_group_dbg_show = pmic_gpio_config_dbg_show, }; +static int pmic_gpio_get_direction(struct gpio_chip *chip, unsigned pin) +{ + struct pmic_gpio_state *state = gpiochip_get_data(chip); + struct pmic_gpio_pad *pad; + + pad = state->ctrl->desc->pins[pin].drv_data; + + if (!pad->is_enabled || pad->analog_pass || + (!pad->input_enabled && !pad->output_enabled)) + return -EINVAL; + + /* Make sure the state is aligned on what pmic_gpio_get() returns */ + return pad->input_enabled ? GPIO_LINE_DIRECTION_IN : GPIO_LINE_DIRECTION_OUT; +} + static int pmic_gpio_direction_input(struct gpio_chip *chip, unsigned pin) { struct pmic_gpio_state *state = gpiochip_get_data(chip); @@ -801,6 +816,7 @@ static void pmic_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) } static const struct gpio_chip pmic_gpio_gpio_template = { + .get_direction = pmic_gpio_get_direction, .direction_input = pmic_gpio_direction_input, .direction_output = pmic_gpio_direction_output, .get = pmic_gpio_get, diff --git a/drivers/pinctrl/renesas/pinctrl-rza1.c b/drivers/pinctrl/renesas/pinctrl-rza1.c index bc8b9b9ad05b..d2949e4dbaf7 100644 --- a/drivers/pinctrl/renesas/pinctrl-rza1.c +++ b/drivers/pinctrl/renesas/pinctrl-rza1.c @@ -589,7 +589,7 @@ static inline unsigned int rza1_get_bit(struct rza1_port *port, { void __iomem *mem = RZA1_ADDR(port->base, reg, port->id); - return ioread16(mem) & BIT(bit); + return !!(ioread16(mem) & BIT(bit)); } /** diff --git a/drivers/pinctrl/renesas/pinctrl-rzt2h.c b/drivers/pinctrl/renesas/pinctrl-rzt2h.c index 9949108a35bb..5927744c7a96 100644 --- a/drivers/pinctrl/renesas/pinctrl-rzt2h.c +++ b/drivers/pinctrl/renesas/pinctrl-rzt2h.c @@ -85,7 +85,7 @@ struct rzt2h_pinctrl { struct gpio_chip gpio_chip; struct pinctrl_gpio_range gpio_range; DECLARE_BITMAP(used_irqs, RZT2H_INTERRUPTS_NUM); - spinlock_t lock; /* lock read/write registers */ + raw_spinlock_t lock; /* lock read/write registers */ struct mutex mutex; /* serialize adding groups and functions */ bool safety_port_enabled; atomic_t wakeup_path; @@ -145,7 +145,7 @@ static void rzt2h_pinctrl_set_pfc_mode(struct rzt2h_pinctrl *pctrl, u64 reg64; u16 reg16; - guard(spinlock_irqsave)(&pctrl->lock); + guard(raw_spinlock_irqsave)(&pctrl->lock); /* Set pin to 'Non-use (Hi-Z input protection)' */ reg16 = rzt2h_pinctrl_readw(pctrl, port, PM(port)); @@ -474,7 +474,7 @@ static int rzt2h_gpio_request(struct gpio_chip *chip, unsigned int offset) if (ret) return ret; - guard(spinlock_irqsave)(&pctrl->lock); + guard(raw_spinlock_irqsave)(&pctrl->lock); /* Select GPIO mode in PMC Register */ rzt2h_pinctrl_set_gpio_en(pctrl, port, bit, true); @@ -487,7 +487,7 @@ static void rzt2h_gpio_set_direction(struct rzt2h_pinctrl *pctrl, u32 port, { u16 reg; - guard(spinlock_irqsave)(&pctrl->lock); + guard(raw_spinlock_irqsave)(&pctrl->lock); reg = rzt2h_pinctrl_readw(pctrl, port, PM(port)); reg &= ~PM_PIN_MASK(bit); @@ -509,7 +509,7 @@ static int rzt2h_gpio_get_direction(struct gpio_chip *chip, unsigned int offset) if (ret) return ret; - guard(spinlock_irqsave)(&pctrl->lock); + guard(raw_spinlock_irqsave)(&pctrl->lock); if (rzt2h_pinctrl_readb(pctrl, port, PMC(port)) & BIT(bit)) { /* @@ -547,7 +547,7 @@ static int rzt2h_gpio_set(struct gpio_chip *chip, unsigned int offset, u8 bit = RZT2H_PIN_ID_TO_PIN(offset); u8 reg; - guard(spinlock_irqsave)(&pctrl->lock); + guard(raw_spinlock_irqsave)(&pctrl->lock); reg = rzt2h_pinctrl_readb(pctrl, port, P(port)); if (value) @@ -833,6 +833,7 @@ static int rzt2h_gpio_register(struct rzt2h_pinctrl *pctrl) if (ret) return dev_err_probe(dev, ret, "Unable to parse gpio-ranges\n"); + of_node_put(of_args.np); if (of_args.args[0] != 0 || of_args.args[1] != 0 || of_args.args[2] != pctrl->data->n_port_pins) return dev_err_probe(dev, -EINVAL, @@ -964,7 +965,7 @@ static int rzt2h_pinctrl_probe(struct platform_device *pdev) if (ret) return ret; - spin_lock_init(&pctrl->lock); + raw_spin_lock_init(&pctrl->lock); mutex_init(&pctrl->mutex); platform_set_drvdata(pdev, pctrl); diff --git a/drivers/pinctrl/stm32/Kconfig b/drivers/pinctrl/stm32/Kconfig index 5f67e1ee66dd..d6a171523012 100644 --- a/drivers/pinctrl/stm32/Kconfig +++ b/drivers/pinctrl/stm32/Kconfig @@ -65,6 +65,7 @@ config PINCTRL_STM32_HDP select PINMUX select GENERIC_PINCONF select GPIOLIB + select GPIO_GENERIC help The Hardware Debug Port allows the observation of internal signals. It uses configurable multiplexer to route signals in a dedicated observation register. diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c index c990b6118172..d3042e0c9712 100644 --- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c @@ -157,6 +157,7 @@ sunxi_pinctrl_desc_find_function_by_name(struct sunxi_pinctrl *pctl, const char *pin_name, const char *func_name) { + unsigned long variant = pctl->flags & SUNXI_PINCTRL_VARIANT_MASK; int i; for (i = 0; i < pctl->desc->npins; i++) { @@ -168,7 +169,7 @@ sunxi_pinctrl_desc_find_function_by_name(struct sunxi_pinctrl *pctl, while (func->name) { if (!strcmp(func->name, func_name) && (!func->variant || - func->variant & pctl->variant)) + func->variant & variant)) return func; func++; @@ -209,6 +210,8 @@ sunxi_pinctrl_desc_find_function_by_pin_and_mux(struct sunxi_pinctrl *pctl, const u16 pin_num, const u8 muxval) { + unsigned long variant = pctl->flags & SUNXI_PINCTRL_VARIANT_MASK; + for (unsigned int i = 0; i < pctl->desc->npins; i++) { const struct sunxi_desc_pin *pin = pctl->desc->pins + i; struct sunxi_desc_function *func = pin->functions; @@ -216,7 +219,7 @@ sunxi_pinctrl_desc_find_function_by_pin_and_mux(struct sunxi_pinctrl *pctl, if (pin->pin.number != pin_num) continue; - if (pin->variant && !(pctl->variant & pin->variant)) + if (pin->variant && !(variant & pin->variant)) continue; while (func->name) { @@ -1089,6 +1092,9 @@ static int sunxi_pinctrl_irq_request_resources(struct irq_data *d) { struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d); struct sunxi_desc_function *func; + unsigned int offset; + u32 reg, shift, mask; + u8 disabled_mux, muxval; int ret; func = sunxi_pinctrl_desc_find_function_by_pin(pctl, @@ -1096,8 +1102,21 @@ static int sunxi_pinctrl_irq_request_resources(struct irq_data *d) if (!func) return -EINVAL; - ret = gpiochip_lock_as_irq(pctl->chip, - pctl->irq_array[d->hwirq] - pctl->desc->pin_base); + offset = pctl->irq_array[d->hwirq] - pctl->desc->pin_base; + sunxi_mux_reg(pctl, offset, ®, &shift, &mask); + muxval = (readl(pctl->membase + reg) & mask) >> shift; + + /* Change muxing to GPIO INPUT mode if at reset value */ + if (pctl->flags & SUNXI_PINCTRL_NEW_REG_LAYOUT) + disabled_mux = SUN4I_FUNC_DISABLED_NEW; + else + disabled_mux = SUN4I_FUNC_DISABLED_OLD; + + if (muxval == disabled_mux) + sunxi_pmx_set(pctl->pctl_dev, pctl->irq_array[d->hwirq], + SUN4I_FUNC_INPUT); + + ret = gpiochip_lock_as_irq(pctl->chip, offset); if (ret) { dev_err(pctl->dev, "unable to lock HW IRQ %lu for IRQ\n", irqd_to_hwirq(d)); @@ -1338,6 +1357,7 @@ static int sunxi_pinctrl_add_function(struct sunxi_pinctrl *pctl, static int sunxi_pinctrl_build_state(struct platform_device *pdev) { struct sunxi_pinctrl *pctl = platform_get_drvdata(pdev); + unsigned long variant = pctl->flags & SUNXI_PINCTRL_VARIANT_MASK; void *ptr; int i; @@ -1362,7 +1382,7 @@ static int sunxi_pinctrl_build_state(struct platform_device *pdev) const struct sunxi_desc_pin *pin = pctl->desc->pins + i; struct sunxi_pinctrl_group *group = pctl->groups + pctl->ngroups; - if (pin->variant && !(pctl->variant & pin->variant)) + if (pin->variant && !(variant & pin->variant)) continue; group->name = pin->pin.name; @@ -1387,11 +1407,11 @@ static int sunxi_pinctrl_build_state(struct platform_device *pdev) const struct sunxi_desc_pin *pin = pctl->desc->pins + i; struct sunxi_desc_function *func; - if (pin->variant && !(pctl->variant & pin->variant)) + if (pin->variant && !(variant & pin->variant)) continue; for (func = pin->functions; func->name; func++) { - if (func->variant && !(pctl->variant & func->variant)) + if (func->variant && !(variant & func->variant)) continue; /* Create interrupt mapping while we're at it */ @@ -1419,14 +1439,14 @@ static int sunxi_pinctrl_build_state(struct platform_device *pdev) const struct sunxi_desc_pin *pin = pctl->desc->pins + i; struct sunxi_desc_function *func; - if (pin->variant && !(pctl->variant & pin->variant)) + if (pin->variant && !(variant & pin->variant)) continue; for (func = pin->functions; func->name; func++) { struct sunxi_pinctrl_function *func_item; const char **func_grp; - if (func->variant && !(pctl->variant & func->variant)) + if (func->variant && !(variant & func->variant)) continue; func_item = sunxi_pinctrl_find_function_by_name(pctl, @@ -1568,7 +1588,7 @@ int sunxi_pinctrl_init_with_flags(struct platform_device *pdev, pctl->dev = &pdev->dev; pctl->desc = desc; - pctl->variant = flags & SUNXI_PINCTRL_VARIANT_MASK; + pctl->flags = flags; if (flags & SUNXI_PINCTRL_NEW_REG_LAYOUT) { pctl->bank_mem_size = D1_BANK_MEM_SIZE; pctl->pull_regs_offset = D1_PULL_REGS_OFFSET; @@ -1604,8 +1624,9 @@ int sunxi_pinctrl_init_with_flags(struct platform_device *pdev, for (i = 0, pin_idx = 0; i < pctl->desc->npins; i++) { const struct sunxi_desc_pin *pin = pctl->desc->pins + i; + unsigned long variant = pctl->flags & SUNXI_PINCTRL_VARIANT_MASK; - if (pin->variant && !(pctl->variant & pin->variant)) + if (pin->variant && !(variant & pin->variant)) continue; pins[pin_idx++] = pin->pin; diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.h b/drivers/pinctrl/sunxi/pinctrl-sunxi.h index ad26e4de16a8..0daf7600e2fb 100644 --- a/drivers/pinctrl/sunxi/pinctrl-sunxi.h +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.h @@ -86,6 +86,8 @@ #define SUN4I_FUNC_INPUT 0 #define SUN4I_FUNC_IRQ 6 +#define SUN4I_FUNC_DISABLED_OLD 7 +#define SUN4I_FUNC_DISABLED_NEW 15 #define SUNXI_PINCTRL_VARIANT_MASK GENMASK(7, 0) #define SUNXI_PINCTRL_NEW_REG_LAYOUT BIT(8) @@ -174,7 +176,7 @@ struct sunxi_pinctrl { unsigned *irq_array; raw_spinlock_t lock; struct pinctrl_dev *pctl_dev; - unsigned long variant; + unsigned long flags; u32 bank_mem_size; u32 pull_regs_offset; u32 dlevel_field_width; diff --git a/drivers/platform/olpc/olpc-xo175-ec.c b/drivers/platform/olpc/olpc-xo175-ec.c index fa7b3bda688a..bee271a4fda1 100644 --- a/drivers/platform/olpc/olpc-xo175-ec.c +++ b/drivers/platform/olpc/olpc-xo175-ec.c @@ -482,7 +482,7 @@ static int olpc_xo175_ec_cmd(u8 cmd, u8 *inbuf, size_t inlen, u8 *resp, dev_dbg(dev, "CMD %x, %zd bytes expected\n", cmd, resp_len); if (inlen > 5) { - dev_err(dev, "command len %zd too big!\n", resp_len); + dev_err(dev, "command len %zd too big!\n", inlen); return -EOVERFLOW; } diff --git a/drivers/platform/x86/amd/hsmp/hsmp.c b/drivers/platform/x86/amd/hsmp/hsmp.c index 19f82c1d3090..631ffc0978d1 100644 --- a/drivers/platform/x86/amd/hsmp/hsmp.c +++ b/drivers/platform/x86/amd/hsmp/hsmp.c @@ -117,7 +117,7 @@ static int __hsmp_send_message(struct hsmp_socket *sock, struct hsmp_message *ms } if (unlikely(mbox_status == HSMP_STATUS_NOT_READY)) { - dev_err(sock->dev, "Message ID 0x%X failure : SMU tmeout (status = 0x%X)\n", + dev_err(sock->dev, "Message ID 0x%X failure : SMU timeout (status = 0x%X)\n", msg->msg_id, mbox_status); return -ETIMEDOUT; } else if (unlikely(mbox_status == HSMP_ERR_INVALID_MSG)) { diff --git a/drivers/platform/x86/asus-armoury.h b/drivers/platform/x86/asus-armoury.h index 208f6fe16168..569743746347 100644 --- a/drivers/platform/x86/asus-armoury.h +++ b/drivers/platform/x86/asus-armoury.h @@ -1082,6 +1082,20 @@ static const struct dmi_system_id power_limits[] = { }, { .matches = { + DMI_MATCH(DMI_BOARD_NAME, "GA503QM"), + }, + .driver_data = &(struct power_data) { + .ac_data = &(struct power_limits) { + .ppt_pl1_spl_min = 15, + .ppt_pl1_spl_def = 35, + .ppt_pl1_spl_max = 80, + .ppt_pl2_sppt_min = 65, + .ppt_pl2_sppt_max = 80, + }, + }, + }, + { + .matches = { DMI_MATCH(DMI_BOARD_NAME, "GA503QR"), }, .driver_data = &(struct power_data) { @@ -1520,6 +1534,35 @@ static const struct dmi_system_id power_limits[] = { }, { .matches = { + DMI_MATCH(DMI_BOARD_NAME, "GZ302EA"), + }, + .driver_data = &(struct power_data) { + .ac_data = &(struct power_limits) { + .ppt_pl1_spl_min = 28, + .ppt_pl1_spl_def = 60, + .ppt_pl1_spl_max = 80, + .ppt_pl2_sppt_min = 32, + .ppt_pl2_sppt_def = 75, + .ppt_pl2_sppt_max = 92, + .ppt_pl3_fppt_min = 45, + .ppt_pl3_fppt_def = 86, + .ppt_pl3_fppt_max = 93, + }, + .dc_data = &(struct power_limits) { + .ppt_pl1_spl_min = 28, + .ppt_pl1_spl_def = 45, + .ppt_pl1_spl_max = 80, + .ppt_pl2_sppt_min = 32, + .ppt_pl2_sppt_def = 52, + .ppt_pl2_sppt_max = 92, + .ppt_pl3_fppt_min = 45, + .ppt_pl3_fppt_def = 71, + .ppt_pl3_fppt_max = 93, + }, + }, + }, + { + .matches = { DMI_MATCH(DMI_BOARD_NAME, "G513I"), }, .driver_data = &(struct power_data) { @@ -1598,6 +1641,40 @@ static const struct dmi_system_id power_limits[] = { }, { .matches = { + DMI_MATCH(DMI_BOARD_NAME, "G614FP"), + }, + .driver_data = &(struct power_data) { + .ac_data = &(struct power_limits) { + .ppt_pl1_spl_min = 30, + .ppt_pl1_spl_max = 120, + .ppt_pl2_sppt_min = 65, + .ppt_pl2_sppt_def = 140, + .ppt_pl2_sppt_max = 165, + .ppt_pl3_fppt_min = 65, + .ppt_pl3_fppt_def = 140, + .ppt_pl3_fppt_max = 165, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + .nv_dynamic_boost_min = 5, + .nv_dynamic_boost_max = 15, + .nv_tgp_min = 50, + .nv_tgp_max = 100, + }, + .dc_data = &(struct power_limits) { + .ppt_pl1_spl_min = 25, + .ppt_pl1_spl_max = 65, + .ppt_pl2_sppt_min = 25, + .ppt_pl2_sppt_max = 65, + .ppt_pl3_fppt_min = 35, + .ppt_pl3_fppt_max = 75, + .nv_temp_target_min = 75, + .nv_temp_target_max = 87, + }, + .requires_fan_curve = true, + }, + }, + { + .matches = { DMI_MATCH(DMI_BOARD_NAME, "G614J"), }, .driver_data = &(struct power_data) { diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c index a38a65f5c550..b4677c5bba5b 100644 --- a/drivers/platform/x86/asus-nb-wmi.c +++ b/drivers/platform/x86/asus-nb-wmi.c @@ -548,7 +548,7 @@ static const struct dmi_system_id asus_quirks[] = { .callback = dmi_matched, .ident = "ASUS ROG Z13", .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_SYS_VENDOR, "ASUS"), DMI_MATCH(DMI_PRODUCT_NAME, "ROG Flow Z13"), }, .driver_data = &quirk_asus_z13, diff --git a/drivers/platform/x86/hp/hp-wmi.c b/drivers/platform/x86/hp/hp-wmi.c index 68ede7e5757a..988a0acc9622 100644 --- a/drivers/platform/x86/hp/hp-wmi.c +++ b/drivers/platform/x86/hp/hp-wmi.c @@ -120,6 +120,13 @@ static const struct thermal_profile_params omen_v1_thermal_params = { .ec_tp_offset = HP_VICTUS_S_EC_THERMAL_PROFILE_OFFSET, }; +static const struct thermal_profile_params omen_v1_legacy_thermal_params = { + .performance = HP_OMEN_V1_THERMAL_PROFILE_PERFORMANCE, + .balanced = HP_OMEN_V1_THERMAL_PROFILE_DEFAULT, + .low_power = HP_OMEN_V1_THERMAL_PROFILE_DEFAULT, + .ec_tp_offset = HP_OMEN_EC_THERMAL_PROFILE_OFFSET, +}; + /* * A generic pointer for the currently-active board's thermal profile * parameters. @@ -176,6 +183,10 @@ static const char * const victus_thermal_profile_boards[] = { /* DMI Board names of Victus 16-r and Victus 16-s laptops */ static const struct dmi_system_id victus_s_thermal_profile_boards[] __initconst = { { + .matches = { DMI_MATCH(DMI_BOARD_NAME, "8A4D") }, + .driver_data = (void *)&omen_v1_legacy_thermal_params, + }, + { .matches = { DMI_MATCH(DMI_BOARD_NAME, "8BAB") }, .driver_data = (void *)&omen_v1_thermal_params, }, @@ -184,6 +195,10 @@ static const struct dmi_system_id victus_s_thermal_profile_boards[] __initconst .driver_data = (void *)&victus_s_thermal_params, }, { + .matches = { DMI_MATCH(DMI_BOARD_NAME, "8BCA") }, + .driver_data = (void *)&omen_v1_thermal_params, + }, + { .matches = { DMI_MATCH(DMI_BOARD_NAME, "8BCD") }, .driver_data = (void *)&omen_v1_thermal_params, }, @@ -196,6 +211,10 @@ static const struct dmi_system_id victus_s_thermal_profile_boards[] __initconst .driver_data = (void *)&victus_s_thermal_params, }, { + .matches = { DMI_MATCH(DMI_BOARD_NAME, "8C76") }, + .driver_data = (void *)&omen_v1_thermal_params, + }, + { .matches = { DMI_MATCH(DMI_BOARD_NAME, "8C78") }, .driver_data = (void *)&omen_v1_thermal_params, }, diff --git a/drivers/platform/x86/intel/hid.c b/drivers/platform/x86/intel/hid.c index 95c405c8bac0..2ddd8af8c1ce 100644 --- a/drivers/platform/x86/intel/hid.c +++ b/drivers/platform/x86/intel/hid.c @@ -438,6 +438,14 @@ static int intel_hid_pl_suspend_handler(struct device *device) return 0; } +static int intel_hid_pl_freeze_handler(struct device *device) +{ + struct intel_hid_priv *priv = dev_get_drvdata(device); + + priv->wakeup_mode = false; + return intel_hid_pl_suspend_handler(device); +} + static int intel_hid_pl_resume_handler(struct device *device) { intel_hid_pm_complete(device); @@ -452,7 +460,7 @@ static int intel_hid_pl_resume_handler(struct device *device) static const struct dev_pm_ops intel_hid_pl_pm_ops = { .prepare = intel_hid_pm_prepare, .complete = intel_hid_pm_complete, - .freeze = intel_hid_pl_suspend_handler, + .freeze = intel_hid_pl_freeze_handler, .thaw = intel_hid_pl_resume_handler, .restore = intel_hid_pl_resume_handler, .suspend = intel_hid_pl_suspend_handler, diff --git a/drivers/platform/x86/intel/speed_select_if/isst_tpmi_core.c b/drivers/platform/x86/intel/speed_select_if/isst_tpmi_core.c index b8cdaa233ea9..e238c3105c78 100644 --- a/drivers/platform/x86/intel/speed_select_if/isst_tpmi_core.c +++ b/drivers/platform/x86/intel/speed_select_if/isst_tpmi_core.c @@ -558,6 +558,9 @@ static bool disable_dynamic_sst_features(void) { u64 value; + if (!static_cpu_has(X86_FEATURE_HWP)) + return true; + rdmsrq(MSR_PM_ENABLE, value); return !(value & 0x1); } @@ -869,7 +872,7 @@ static int isst_if_get_perf_level(void __user *argp) _read_pp_info("current_level", perf_level.current_level, SST_PP_STATUS_OFFSET, SST_PP_LEVEL_START, SST_PP_LEVEL_WIDTH, SST_MUL_FACTOR_NONE) _read_pp_info("locked", perf_level.locked, SST_PP_STATUS_OFFSET, - SST_PP_LOCK_START, SST_PP_LEVEL_WIDTH, SST_MUL_FACTOR_NONE) + SST_PP_LOCK_START, SST_PP_LOCK_WIDTH, SST_MUL_FACTOR_NONE) _read_pp_info("feature_state", perf_level.feature_state, SST_PP_STATUS_OFFSET, SST_PP_FEATURE_STATE_START, SST_PP_FEATURE_STATE_WIDTH, SST_MUL_FACTOR_NONE) perf_level.enabled = !!(power_domain_info->sst_header.cap_mask & BIT(1)); diff --git a/drivers/platform/x86/lenovo/wmi-gamezone.c b/drivers/platform/x86/lenovo/wmi-gamezone.c index 381836d29a96..c7fe7e3c9f17 100644 --- a/drivers/platform/x86/lenovo/wmi-gamezone.c +++ b/drivers/platform/x86/lenovo/wmi-gamezone.c @@ -31,8 +31,6 @@ #define LWMI_GZ_METHOD_ID_SMARTFAN_SET 44 #define LWMI_GZ_METHOD_ID_SMARTFAN_GET 45 -static BLOCKING_NOTIFIER_HEAD(gz_chain_head); - struct lwmi_gz_priv { enum thermal_mode current_mode; struct notifier_block event_nb; diff --git a/drivers/s390/crypto/zcrypt_msgtype6.c b/drivers/s390/crypto/zcrypt_msgtype6.c index a0dcab5dc4f2..23a32221e41a 100644 --- a/drivers/s390/crypto/zcrypt_msgtype6.c +++ b/drivers/s390/crypto/zcrypt_msgtype6.c @@ -953,6 +953,10 @@ static atomic_t zcrypt_step = ATOMIC_INIT(0); /* * The request distributor calls this function if it picked the CEXxC * device to handle a modexpo request. + * This function assumes that ap_msg has been initialized with + * ap_init_apmsg() and thus a valid buffer with the size of + * ap_msg->bufsize is available within ap_msg. Also the caller has + * to make sure ap_release_apmsg() is always called even on failure. * @zq: pointer to zcrypt_queue structure that identifies the * CEXxC device to the request distributor * @mex: pointer to the modexpo request buffer @@ -964,21 +968,17 @@ static long zcrypt_msgtype6_modexpo(struct zcrypt_queue *zq, struct ap_response_type *resp_type = &ap_msg->response; int rc; - ap_msg->msg = (void *)get_zeroed_page(GFP_KERNEL); - if (!ap_msg->msg) - return -ENOMEM; - ap_msg->bufsize = PAGE_SIZE; ap_msg->receive = zcrypt_msgtype6_receive; ap_msg->psmid = (((unsigned long)current->pid) << 32) + atomic_inc_return(&zcrypt_step); rc = icamex_msg_to_type6mex_msgx(zq, ap_msg, mex); if (rc) - goto out_free; + goto out; resp_type->type = CEXXC_RESPONSE_TYPE_ICA; init_completion(&resp_type->work); rc = ap_queue_message(zq->queue, ap_msg); if (rc) - goto out_free; + goto out; rc = wait_for_completion_interruptible(&resp_type->work); if (rc == 0) { rc = ap_msg->rc; @@ -991,15 +991,17 @@ static long zcrypt_msgtype6_modexpo(struct zcrypt_queue *zq, ap_cancel_message(zq->queue, ap_msg); } -out_free: - free_page((unsigned long)ap_msg->msg); - ap_msg->msg = NULL; +out: return rc; } /* * The request distributor calls this function if it picked the CEXxC * device to handle a modexpo_crt request. + * This function assumes that ap_msg has been initialized with + * ap_init_apmsg() and thus a valid buffer with the size of + * ap_msg->bufsize is available within ap_msg. Also the caller has + * to make sure ap_release_apmsg() is always called even on failure. * @zq: pointer to zcrypt_queue structure that identifies the * CEXxC device to the request distributor * @crt: pointer to the modexpoc_crt request buffer @@ -1011,21 +1013,17 @@ static long zcrypt_msgtype6_modexpo_crt(struct zcrypt_queue *zq, struct ap_response_type *resp_type = &ap_msg->response; int rc; - ap_msg->msg = (void *)get_zeroed_page(GFP_KERNEL); - if (!ap_msg->msg) - return -ENOMEM; - ap_msg->bufsize = PAGE_SIZE; ap_msg->receive = zcrypt_msgtype6_receive; ap_msg->psmid = (((unsigned long)current->pid) << 32) + atomic_inc_return(&zcrypt_step); rc = icacrt_msg_to_type6crt_msgx(zq, ap_msg, crt); if (rc) - goto out_free; + goto out; resp_type->type = CEXXC_RESPONSE_TYPE_ICA; init_completion(&resp_type->work); rc = ap_queue_message(zq->queue, ap_msg); if (rc) - goto out_free; + goto out; rc = wait_for_completion_interruptible(&resp_type->work); if (rc == 0) { rc = ap_msg->rc; @@ -1038,9 +1036,7 @@ static long zcrypt_msgtype6_modexpo_crt(struct zcrypt_queue *zq, ap_cancel_message(zq->queue, ap_msg); } -out_free: - free_page((unsigned long)ap_msg->msg); - ap_msg->msg = NULL; +out: return rc; } diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c index a20fce04fe79..3dd2adda195e 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.c +++ b/drivers/scsi/ibmvscsi/ibmvfc.c @@ -4966,7 +4966,8 @@ static void ibmvfc_discover_targets_done(struct ibmvfc_event *evt) switch (mad_status) { case IBMVFC_MAD_SUCCESS: ibmvfc_dbg(vhost, "Discover Targets succeeded\n"); - vhost->num_targets = be32_to_cpu(rsp->num_written); + vhost->num_targets = min_t(u32, be32_to_cpu(rsp->num_written), + max_targets); ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_ALLOC_TGTS); break; case IBMVFC_MAD_FAILED: diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c index 12124f9d5ccd..13412702188e 100644 --- a/drivers/scsi/scsi_transport_sas.c +++ b/drivers/scsi/scsi_transport_sas.c @@ -1734,7 +1734,7 @@ static int sas_user_scan(struct Scsi_Host *shost, uint channel, break; default: - if (channel < shost->max_channel) { + if (channel <= shost->max_channel) { res = scsi_scan_host_selected(shost, channel, id, lun, SCSI_SCAN_MANUAL); } else { diff --git a/drivers/scsi/ses.c b/drivers/scsi/ses.c index 8e1686358e25..4c348645b04e 100644 --- a/drivers/scsi/ses.c +++ b/drivers/scsi/ses.c @@ -215,7 +215,7 @@ static unsigned char *ses_get_page2_descriptor(struct enclosure_device *edev, unsigned char *type_ptr = ses_dev->page1_types; unsigned char *desc_ptr = ses_dev->page2 + 8; - if (ses_recv_diag(sdev, 2, ses_dev->page2, ses_dev->page2_len) < 0) + if (ses_recv_diag(sdev, 2, ses_dev->page2, ses_dev->page2_len)) return NULL; for (i = 0; i < ses_dev->page1_num_types; i++, type_ptr += 4) { diff --git a/drivers/spi/spi-amlogic-spifc-a4.c b/drivers/spi/spi-amlogic-spifc-a4.c index 1aabafa36e48..16346f50c7d9 100644 --- a/drivers/spi/spi-amlogic-spifc-a4.c +++ b/drivers/spi/spi-amlogic-spifc-a4.c @@ -1066,6 +1066,13 @@ static const struct nand_ecc_engine_ops aml_sfc_ecc_engine_ops = { .finish_io_req = aml_sfc_ecc_finish_io_req, }; +static void aml_sfc_unregister_ecc_engine(void *data) +{ + struct nand_ecc_engine *eng = data; + + nand_ecc_unregister_on_host_hw_engine(eng); +} + static int aml_sfc_clk_init(struct aml_sfc *sfc) { sfc->gate_clk = devm_clk_get_enabled(sfc->dev, "gate"); @@ -1149,6 +1156,11 @@ static int aml_sfc_probe(struct platform_device *pdev) if (ret) return dev_err_probe(&pdev->dev, ret, "failed to register Aml host ecc engine.\n"); + ret = devm_add_action_or_reset(dev, aml_sfc_unregister_ecc_engine, + &sfc->ecc_eng); + if (ret) + return dev_err_probe(dev, ret, "failed to add ECC unregister action\n"); + ret = of_property_read_u32(np, "amlogic,rx-adj", &val); if (!ret) sfc->rx_adj = val; diff --git a/drivers/spi/spi-cadence-quadspi.c b/drivers/spi/spi-cadence-quadspi.c index 5fb0cb07c110..2ead419e896e 100644 --- a/drivers/spi/spi-cadence-quadspi.c +++ b/drivers/spi/spi-cadence-quadspi.c @@ -1483,14 +1483,6 @@ static int cqspi_exec_mem_op(struct spi_mem *mem, const struct spi_mem_op *op) if (refcount_read(&cqspi->inflight_ops) == 0) return -ENODEV; - if (!(ddata && (ddata->quirks & CQSPI_DISABLE_RUNTIME_PM))) { - ret = pm_runtime_resume_and_get(dev); - if (ret) { - dev_err(&mem->spi->dev, "resume failed with %d\n", ret); - return ret; - } - } - if (!refcount_read(&cqspi->refcount)) return -EBUSY; @@ -1502,6 +1494,14 @@ static int cqspi_exec_mem_op(struct spi_mem *mem, const struct spi_mem_op *op) return -EBUSY; } + if (!(ddata && (ddata->quirks & CQSPI_DISABLE_RUNTIME_PM))) { + ret = pm_runtime_resume_and_get(dev); + if (ret) { + dev_err(&mem->spi->dev, "resume failed with %d\n", ret); + goto dec_inflight_refcount; + } + } + ret = cqspi_mem_process(mem, op); if (!(ddata && (ddata->quirks & CQSPI_DISABLE_RUNTIME_PM))) @@ -1510,6 +1510,7 @@ static int cqspi_exec_mem_op(struct spi_mem *mem, const struct spi_mem_op *op) if (ret) dev_err(&mem->spi->dev, "operation failed with %d\n", ret); +dec_inflight_refcount: if (refcount_read(&cqspi->inflight_ops) > 1) refcount_dec(&cqspi->inflight_ops); diff --git a/drivers/spi/spi-fsl-lpspi.c b/drivers/spi/spi-fsl-lpspi.c index b361c1bb3e43..45390e9b8cae 100644 --- a/drivers/spi/spi-fsl-lpspi.c +++ b/drivers/spi/spi-fsl-lpspi.c @@ -1009,7 +1009,7 @@ static int fsl_lpspi_probe(struct platform_device *pdev) enable_irq(irq); } - ret = devm_spi_register_controller(&pdev->dev, controller); + ret = spi_register_controller(controller); if (ret < 0) { dev_err_probe(&pdev->dev, ret, "spi_register_controller error\n"); goto free_dma; @@ -1035,6 +1035,7 @@ static void fsl_lpspi_remove(struct platform_device *pdev) struct fsl_lpspi_data *fsl_lpspi = spi_controller_get_devdata(controller); + spi_unregister_controller(controller); fsl_lpspi_dma_exit(controller); pm_runtime_dont_use_autosuspend(fsl_lpspi->dev); diff --git a/drivers/spi/spi-meson-spicc.c b/drivers/spi/spi-meson-spicc.c index a7001b9e36e6..57768da3205d 100644 --- a/drivers/spi/spi-meson-spicc.c +++ b/drivers/spi/spi-meson-spicc.c @@ -1101,8 +1101,6 @@ static void meson_spicc_remove(struct platform_device *pdev) /* Disable SPI */ writel(0, spicc->base + SPICC_CONREG); - - spi_controller_put(spicc->host); } static const struct meson_spicc_data meson_spicc_gx_data = { diff --git a/drivers/spi/spi-sn-f-ospi.c b/drivers/spi/spi-sn-f-ospi.c index bfcc140df810..3c61c799723b 100644 --- a/drivers/spi/spi-sn-f-ospi.c +++ b/drivers/spi/spi-sn-f-ospi.c @@ -612,7 +612,7 @@ static int f_ospi_probe(struct platform_device *pdev) u32 num_cs = OSPI_NUM_CS; int ret; - ctlr = spi_alloc_host(dev, sizeof(*ospi)); + ctlr = devm_spi_alloc_host(dev, sizeof(*ospi)); if (!ctlr) return -ENOMEM; @@ -635,43 +635,22 @@ static int f_ospi_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ospi); ospi->base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(ospi->base)) { - ret = PTR_ERR(ospi->base); - goto err_put_ctlr; - } + if (IS_ERR(ospi->base)) + return PTR_ERR(ospi->base); ospi->clk = devm_clk_get_enabled(dev, NULL); - if (IS_ERR(ospi->clk)) { - ret = PTR_ERR(ospi->clk); - goto err_put_ctlr; - } + if (IS_ERR(ospi->clk)) + return PTR_ERR(ospi->clk); - mutex_init(&ospi->mlock); - - ret = f_ospi_init(ospi); + ret = devm_mutex_init(dev, &ospi->mlock); if (ret) - goto err_destroy_mutex; + return ret; - ret = devm_spi_register_controller(dev, ctlr); + ret = f_ospi_init(ospi); if (ret) - goto err_destroy_mutex; - - return 0; - -err_destroy_mutex: - mutex_destroy(&ospi->mlock); - -err_put_ctlr: - spi_controller_put(ctlr); - - return ret; -} - -static void f_ospi_remove(struct platform_device *pdev) -{ - struct f_ospi *ospi = platform_get_drvdata(pdev); + return ret; - mutex_destroy(&ospi->mlock); + return devm_spi_register_controller(dev, ctlr); } static const struct of_device_id f_ospi_dt_ids[] = { @@ -686,7 +665,6 @@ static struct platform_driver f_ospi_driver = { .of_match_table = f_ospi_dt_ids, }, .probe = f_ospi_probe, - .remove = f_ospi_remove, }; module_platform_driver(f_ospi_driver); diff --git a/drivers/spi/spi-stm32-ospi.c b/drivers/spi/spi-stm32-ospi.c index c98afe02a1b6..38405f8f547f 100644 --- a/drivers/spi/spi-stm32-ospi.c +++ b/drivers/spi/spi-stm32-ospi.c @@ -928,7 +928,7 @@ static int stm32_ospi_probe(struct platform_device *pdev) dma_cfg.dst_addr = ospi->regs_phys_base + OSPI_DR; ret = stm32_ospi_dma_setup(ospi, &dma_cfg); if (ret) - return ret; + goto err_dma_free; mutex_init(&ospi->lock); @@ -965,19 +965,22 @@ static int stm32_ospi_probe(struct platform_device *pdev) if (ret) { /* Disable ospi */ writel_relaxed(0, ospi->regs_base + OSPI_CR); - goto err_pm_resume; + goto err_reset_control; } pm_runtime_put_autosuspend(ospi->dev); return 0; +err_reset_control: + reset_control_release(ospi->rstc); err_pm_resume: pm_runtime_put_sync_suspend(ospi->dev); err_pm_enable: pm_runtime_force_suspend(ospi->dev); mutex_destroy(&ospi->lock); +err_dma_free: if (ospi->dma_chtx) dma_release_channel(ospi->dma_chtx); if (ospi->dma_chrx) @@ -989,11 +992,8 @@ err_pm_enable: static void stm32_ospi_remove(struct platform_device *pdev) { struct stm32_ospi *ospi = platform_get_drvdata(pdev); - int ret; - ret = pm_runtime_resume_and_get(ospi->dev); - if (ret < 0) - return; + pm_runtime_resume_and_get(ospi->dev); spi_unregister_controller(ospi->ctrl); /* Disable ospi */ diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 53dee314d76a..9b1125556d29 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -50,7 +50,6 @@ static void spidev_release(struct device *dev) struct spi_device *spi = to_spi_device(dev); spi_controller_put(spi->controller); - kfree(spi->driver_override); free_percpu(spi->pcpu_statistics); kfree(spi); } @@ -73,10 +72,9 @@ static ssize_t driver_override_store(struct device *dev, struct device_attribute *a, const char *buf, size_t count) { - struct spi_device *spi = to_spi_device(dev); int ret; - ret = driver_set_override(dev, &spi->driver_override, buf, count); + ret = __device_set_driver_override(dev, buf, count); if (ret) return ret; @@ -86,13 +84,8 @@ static ssize_t driver_override_store(struct device *dev, static ssize_t driver_override_show(struct device *dev, struct device_attribute *a, char *buf) { - const struct spi_device *spi = to_spi_device(dev); - ssize_t len; - - device_lock(dev); - len = sysfs_emit(buf, "%s\n", spi->driver_override ? : ""); - device_unlock(dev); - return len; + guard(spinlock)(&dev->driver_override.lock); + return sysfs_emit(buf, "%s\n", dev->driver_override.name ?: ""); } static DEVICE_ATTR_RW(driver_override); @@ -376,10 +369,12 @@ static int spi_match_device(struct device *dev, const struct device_driver *drv) { const struct spi_device *spi = to_spi_device(dev); const struct spi_driver *sdrv = to_spi_driver(drv); + int ret; /* Check override first, and if set, only use the named driver */ - if (spi->driver_override) - return strcmp(spi->driver_override, drv->name) == 0; + ret = device_match_driver_override(dev, drv); + if (ret >= 0) + return ret; /* Attempt an OF style match */ if (of_driver_match_device(dev, drv)) @@ -3539,8 +3534,19 @@ int devm_spi_register_controller(struct device *dev, if (ret) return ret; - return devm_add_action_or_reset(dev, devm_spi_unregister_controller, ctlr); + /* + * Prevent controller from being freed by spi_unregister_controller() + * if devm_add_action_or_reset() fails for a non-devres allocated + * controller. + */ + spi_controller_get(ctlr); + + ret = devm_add_action_or_reset(dev, devm_spi_unregister_controller, ctlr); + if (ret == 0 || ctlr->devm_allocated) + spi_controller_put(ctlr); + + return ret; } EXPORT_SYMBOL_GPL(devm_spi_register_controller); diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c index d668bd19fd4a..528883d989b8 100644 --- a/drivers/target/loopback/tcm_loop.c +++ b/drivers/target/loopback/tcm_loop.c @@ -26,6 +26,7 @@ #include <linux/slab.h> #include <linux/types.h> #include <linux/configfs.h> +#include <linux/blk-mq.h> #include <scsi/scsi.h> #include <scsi/scsi_tcq.h> #include <scsi/scsi_host.h> @@ -269,15 +270,27 @@ static int tcm_loop_device_reset(struct scsi_cmnd *sc) return (ret == TMR_FUNCTION_COMPLETE) ? SUCCESS : FAILED; } +static bool tcm_loop_flush_work_iter(struct request *rq, void *data) +{ + struct scsi_cmnd *sc = blk_mq_rq_to_pdu(rq); + struct tcm_loop_cmd *tl_cmd = scsi_cmd_priv(sc); + struct se_cmd *se_cmd = &tl_cmd->tl_se_cmd; + + flush_work(&se_cmd->work); + return true; +} + static int tcm_loop_target_reset(struct scsi_cmnd *sc) { struct tcm_loop_hba *tl_hba; struct tcm_loop_tpg *tl_tpg; + struct Scsi_Host *sh = sc->device->host; + int ret; /* * Locate the tcm_loop_hba_t pointer */ - tl_hba = *(struct tcm_loop_hba **)shost_priv(sc->device->host); + tl_hba = *(struct tcm_loop_hba **)shost_priv(sh); if (!tl_hba) { pr_err("Unable to perform device reset without active I_T Nexus\n"); return FAILED; @@ -286,11 +299,38 @@ static int tcm_loop_target_reset(struct scsi_cmnd *sc) * Locate the tl_tpg pointer from TargetID in sc->device->id */ tl_tpg = &tl_hba->tl_hba_tpgs[sc->device->id]; - if (tl_tpg) { - tl_tpg->tl_transport_status = TCM_TRANSPORT_ONLINE; - return SUCCESS; - } - return FAILED; + if (!tl_tpg) + return FAILED; + + /* + * Issue a LUN_RESET to drain all commands that the target core + * knows about. This handles commands not yet marked CMD_T_COMPLETE. + */ + ret = tcm_loop_issue_tmr(tl_tpg, sc->device->lun, 0, TMR_LUN_RESET); + if (ret != TMR_FUNCTION_COMPLETE) + return FAILED; + + /* + * Flush any deferred target core completion work that may still be + * queued. Commands that already had CMD_T_COMPLETE set before the TMR + * are skipped by the TMR drain, but their async completion work + * (transport_lun_remove_cmd → percpu_ref_put, release_cmd → scsi_done) + * may still be pending in target_completion_wq. + * + * The SCSI EH will reuse in-flight scsi_cmnd structures for recovery + * commands (e.g. TUR) immediately after this handler returns SUCCESS — + * if deferred work is still pending, the memset in queuecommand would + * zero the se_cmd while the work accesses it, leaking the LUN + * percpu_ref and hanging configfs unlink forever. + * + * Use blk_mq_tagset_busy_iter() to find all started requests and + * flush_work() on each — the same pattern used by mpi3mr, scsi_debug, + * and other SCSI drivers to drain outstanding commands during reset. + */ + blk_mq_tagset_busy_iter(&sh->tag_set, tcm_loop_flush_work_iter, NULL); + + tl_tpg->tl_transport_status = TCM_TRANSPORT_ONLINE; + return SUCCESS; } static const struct scsi_host_template tcm_loop_driver_template = { diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c index 3ae1f7137d9d..3d593af30aa5 100644 --- a/drivers/target/target_core_file.c +++ b/drivers/target/target_core_file.c @@ -276,7 +276,7 @@ fd_execute_rw_aio(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents, ssize_t len = 0; int ret = 0, i; - aio_cmd = kmalloc_flex(*aio_cmd, bvecs, sgl_nents); + aio_cmd = kzalloc_flex(*aio_cmd, bvecs, sgl_nents); if (!aio_cmd) return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; diff --git a/drivers/thermal/intel/int340x_thermal/processor_thermal_soc_slider.c b/drivers/thermal/intel/int340x_thermal/processor_thermal_soc_slider.c index 49ff3bae7271..91f291627132 100644 --- a/drivers/thermal/intel/int340x_thermal/processor_thermal_soc_slider.c +++ b/drivers/thermal/intel/int340x_thermal/processor_thermal_soc_slider.c @@ -176,15 +176,21 @@ static inline void write_soc_slider(struct proc_thermal_device *proc_priv, u64 v static void set_soc_power_profile(struct proc_thermal_device *proc_priv, int slider) { + u8 offset; u64 val; val = read_soc_slider(proc_priv); val &= ~SLIDER_MASK; val |= FIELD_PREP(SLIDER_MASK, slider) | BIT(SLIDER_ENABLE_BIT); + if (slider == SOC_SLIDER_VALUE_MINIMUM || slider == SOC_SLIDER_VALUE_MAXIMUM) + offset = 0; + else + offset = slider_offset; + /* Set the slider offset from module params */ val &= ~SLIDER_OFFSET_MASK; - val |= FIELD_PREP(SLIDER_OFFSET_MASK, slider_offset); + val |= FIELD_PREP(SLIDER_OFFSET_MASK, offset); write_soc_slider(proc_priv, val); } diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c index b7d706ed7ed9..d1beee9e15f8 100644 --- a/drivers/thermal/thermal_core.c +++ b/drivers/thermal/thermal_core.c @@ -41,6 +41,8 @@ static struct thermal_governor *def_governor; static bool thermal_pm_suspended; +static struct workqueue_struct *thermal_wq __ro_after_init; + /* * Governor section: set of functions to handle thermal governors * @@ -313,7 +315,7 @@ static void thermal_zone_device_set_polling(struct thermal_zone_device *tz, if (delay > HZ) delay = round_jiffies_relative(delay); - mod_delayed_work(system_freezable_power_efficient_wq, &tz->poll_queue, delay); + mod_delayed_work(thermal_wq, &tz->poll_queue, delay); } static void thermal_zone_recheck(struct thermal_zone_device *tz, int error) @@ -1640,6 +1642,7 @@ unregister: device_del(&tz->device); release_device: put_device(&tz->device); + wait_for_completion(&tz->removal); remove_id: ida_free(&thermal_tz_ida, id); free_tzp: @@ -1785,6 +1788,10 @@ static void thermal_zone_device_resume(struct work_struct *work) guard(thermal_zone)(tz); + /* If the thermal zone is going away, there's nothing to do. */ + if (tz->state & TZ_STATE_FLAG_EXIT) + return; + tz->state &= ~(TZ_STATE_FLAG_SUSPENDED | TZ_STATE_FLAG_RESUMING); thermal_debug_tz_resume(tz); @@ -1811,6 +1818,9 @@ static void thermal_zone_pm_prepare(struct thermal_zone_device *tz) } tz->state |= TZ_STATE_FLAG_SUSPENDED; + + /* Prevent new work from getting to the workqueue subsequently. */ + cancel_delayed_work(&tz->poll_queue); } static void thermal_pm_notify_prepare(void) @@ -1829,8 +1839,6 @@ static void thermal_zone_pm_complete(struct thermal_zone_device *tz) { guard(thermal_zone)(tz); - cancel_delayed_work(&tz->poll_queue); - reinit_completion(&tz->resume); tz->state |= TZ_STATE_FLAG_RESUMING; @@ -1840,7 +1848,7 @@ static void thermal_zone_pm_complete(struct thermal_zone_device *tz) */ INIT_DELAYED_WORK(&tz->poll_queue, thermal_zone_device_resume); /* Queue up the work without a delay. */ - mod_delayed_work(system_freezable_power_efficient_wq, &tz->poll_queue, 0); + mod_delayed_work(thermal_wq, &tz->poll_queue, 0); } static void thermal_pm_notify_complete(void) @@ -1863,6 +1871,11 @@ static int thermal_pm_notify(struct notifier_block *nb, case PM_RESTORE_PREPARE: case PM_SUSPEND_PREPARE: thermal_pm_notify_prepare(); + /* + * Allow any leftover thermal work items already on the + * worqueue to complete so they don't get in the way later. + */ + flush_workqueue(thermal_wq); break; case PM_POST_HIBERNATION: case PM_POST_RESTORE: @@ -1895,9 +1908,16 @@ static int __init thermal_init(void) if (result) goto error; + thermal_wq = alloc_workqueue("thermal_events", + WQ_FREEZABLE | WQ_POWER_EFFICIENT | WQ_PERCPU, 0); + if (!thermal_wq) { + result = -ENOMEM; + goto unregister_netlink; + } + result = thermal_register_governors(); if (result) - goto unregister_netlink; + goto destroy_workqueue; thermal_class = kzalloc_obj(*thermal_class); if (!thermal_class) { @@ -1924,6 +1944,8 @@ static int __init thermal_init(void) unregister_governors: thermal_unregister_governors(); +destroy_workqueue: + destroy_workqueue(thermal_wq); unregister_netlink: thermal_netlink_exit(); error: diff --git a/drivers/thunderbolt/nhi.c b/drivers/thunderbolt/nhi.c index ccce020a2432..2bb2e79ca3cb 100644 --- a/drivers/thunderbolt/nhi.c +++ b/drivers/thunderbolt/nhi.c @@ -1020,7 +1020,7 @@ static bool nhi_wake_supported(struct pci_dev *pdev) * If power rails are sustainable for wakeup from S4 this * property is set by the BIOS. */ - if (device_property_read_u8(&pdev->dev, "WAKE_SUPPORTED", &val)) + if (!device_property_read_u8(&pdev->dev, "WAKE_SUPPORTED", &val)) return !!val; return true; diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index e2df99e3d458..b4b19157f05c 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -1909,6 +1909,24 @@ static void leave_alt_screen(struct vc_data *vc) dest = ((u16 *)vc->vc_origin) + r * vc->vc_cols; memcpy(dest, src, 2 * cols); } + /* + * If the console was resized while in the alternate screen, + * resize the saved unicode buffer to the current dimensions. + * On allocation failure new_uniscr is NULL, causing the old + * buffer to be freed and vc_uni_lines to be lazily rebuilt + * via vc_uniscr_check() when next needed. + */ + if (vc->vc_saved_uni_lines && + (vc->vc_saved_rows != vc->vc_rows || + vc->vc_saved_cols != vc->vc_cols)) { + u32 **new_uniscr = vc_uniscr_alloc(vc->vc_cols, vc->vc_rows); + + if (new_uniscr) + vc_uniscr_copy_area(new_uniscr, vc->vc_cols, vc->vc_rows, + vc->vc_saved_uni_lines, cols, 0, rows); + vc_uniscr_free(vc->vc_saved_uni_lines); + vc->vc_saved_uni_lines = new_uniscr; + } vc_uniscr_set(vc, vc->vc_saved_uni_lines); vc->vc_saved_uni_lines = NULL; restore_cur(vc); diff --git a/drivers/usb/cdns3/cdns3-gadget.c b/drivers/usb/cdns3/cdns3-gadget.c index d59a60a16ec7..8382231af357 100644 --- a/drivers/usb/cdns3/cdns3-gadget.c +++ b/drivers/usb/cdns3/cdns3-gadget.c @@ -2589,6 +2589,9 @@ static int __cdns3_gadget_ep_queue(struct usb_ep *ep, struct cdns3_request *priv_req; int ret = 0; + if (!ep->desc) + return -ESHUTDOWN; + request->actual = 0; request->status = -EINPROGRESS; priv_req = to_cdns3_request(request); @@ -3428,6 +3431,7 @@ static int __cdns3_gadget_init(struct cdns *cdns) ret = cdns3_gadget_start(cdns); if (ret) { pm_runtime_put_sync(cdns->dev); + cdns_drd_gadget_off(cdns); return ret; } diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index 7ede29d4c7c1..cf3c3eede1a5 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -1225,6 +1225,12 @@ static int acm_probe(struct usb_interface *intf, if (!data_interface || !control_interface) return -ENODEV; goto skip_normal_probe; + } else if (quirks == NO_UNION_12) { + data_interface = usb_ifnum_to_if(usb_dev, 2); + control_interface = usb_ifnum_to_if(usb_dev, 1); + if (!data_interface || !control_interface) + return -ENODEV; + goto skip_normal_probe; } /* normal probing*/ @@ -1748,6 +1754,9 @@ static const struct usb_device_id acm_ids[] = { { USB_DEVICE(0x045b, 0x024D), /* Renesas R-Car E3 USB Download mode */ .driver_info = DISABLE_ECHO, /* Don't echo banner */ }, + { USB_DEVICE(0x04b8, 0x0d12), /* EPSON HMD Com&Sens */ + .driver_info = NO_UNION_12, /* union descriptor is garbage */ + }, { USB_DEVICE(0x0e8d, 0x0003), /* FIREFLY, MediaTek Inc; andrey.arapov@gmail.com */ .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ }, diff --git a/drivers/usb/class/cdc-acm.h b/drivers/usb/class/cdc-acm.h index 76f73853a60b..25fd5329a878 100644 --- a/drivers/usb/class/cdc-acm.h +++ b/drivers/usb/class/cdc-acm.h @@ -114,3 +114,4 @@ struct acm { #define SEND_ZERO_PACKET BIT(6) #define DISABLE_ECHO BIT(7) #define MISSING_CAP_BRK BIT(8) +#define NO_UNION_12 BIT(9) diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c index d39bbfd7fd18..bd9347804dec 100644 --- a/drivers/usb/class/usbtmc.c +++ b/drivers/usb/class/usbtmc.c @@ -254,6 +254,9 @@ static int usbtmc_release(struct inode *inode, struct file *file) list_del(&file_data->file_elem); spin_unlock_irq(&file_data->data->dev_lock); + + /* flush anchored URBs */ + usbtmc_draw_down(file_data); mutex_unlock(&file_data->data->io_mutex); kref_put(&file_data->data->kref, usbtmc_delete); diff --git a/drivers/usb/common/ulpi.c b/drivers/usb/common/ulpi.c index 56c9bfaf2ea3..b34fb65813c4 100644 --- a/drivers/usb/common/ulpi.c +++ b/drivers/usb/common/ulpi.c @@ -331,10 +331,9 @@ struct ulpi *ulpi_register_interface(struct device *dev, ulpi->ops = ops; ret = ulpi_register(dev, ulpi); - if (ret) { - kfree(ulpi); + if (ret) return ERR_PTR(ret); - } + return ulpi; } diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 2574e65bc640..f63004417058 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -1415,14 +1415,16 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg) int status = 0; int i = 0, n = 0; struct usb_interface *intf; + bool offload_active = false; if (udev->state == USB_STATE_NOTATTACHED || udev->state == USB_STATE_SUSPENDED) goto done; + usb_offload_set_pm_locked(udev, true); if (msg.event == PM_EVENT_SUSPEND && usb_offload_check(udev)) { dev_dbg(&udev->dev, "device offloaded, skip suspend.\n"); - udev->offload_at_suspend = 1; + offload_active = true; } /* Suspend all the interfaces and then udev itself */ @@ -1436,8 +1438,7 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg) * interrupt urbs, allowing interrupt events to be * handled during system suspend. */ - if (udev->offload_at_suspend && - intf->needs_remote_wakeup) { + if (offload_active && intf->needs_remote_wakeup) { dev_dbg(&intf->dev, "device offloaded, skip suspend.\n"); continue; @@ -1452,7 +1453,7 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg) } } if (status == 0) { - if (!udev->offload_at_suspend) + if (!offload_active) status = usb_suspend_device(udev, msg); /* @@ -1498,7 +1499,7 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg) */ } else { udev->can_submit = 0; - if (!udev->offload_at_suspend) { + if (!offload_active) { for (i = 0; i < 16; ++i) { usb_hcd_flush_endpoint(udev, udev->ep_out[i]); usb_hcd_flush_endpoint(udev, udev->ep_in[i]); @@ -1507,6 +1508,8 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg) } done: + if (status != 0) + usb_offload_set_pm_locked(udev, false); dev_vdbg(&udev->dev, "%s: status %d\n", __func__, status); return status; } @@ -1536,16 +1539,19 @@ static int usb_resume_both(struct usb_device *udev, pm_message_t msg) int status = 0; int i; struct usb_interface *intf; + bool offload_active = false; if (udev->state == USB_STATE_NOTATTACHED) { status = -ENODEV; goto done; } udev->can_submit = 1; + if (msg.event == PM_EVENT_RESUME) + offload_active = usb_offload_check(udev); /* Resume the device */ if (udev->state == USB_STATE_SUSPENDED || udev->reset_resume) { - if (!udev->offload_at_suspend) + if (!offload_active) status = usb_resume_device(udev, msg); else dev_dbg(&udev->dev, @@ -1562,8 +1568,7 @@ static int usb_resume_both(struct usb_device *udev, pm_message_t msg) * pending interrupt urbs, allowing interrupt events * to be handled during system suspend. */ - if (udev->offload_at_suspend && - intf->needs_remote_wakeup) { + if (offload_active && intf->needs_remote_wakeup) { dev_dbg(&intf->dev, "device offloaded, skip resume.\n"); continue; @@ -1572,11 +1577,11 @@ static int usb_resume_both(struct usb_device *udev, pm_message_t msg) udev->reset_resume); } } - udev->offload_at_suspend = 0; usb_mark_last_busy(udev); done: dev_vdbg(&udev->dev, "%s: status %d\n", __func__, status); + usb_offload_set_pm_locked(udev, false); if (!status) udev->reset_resume = 0; return status; diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index dee842ea6931..89221f1ce769 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -2403,7 +2403,7 @@ void usb_hcd_resume_root_hub (struct usb_hcd *hcd) if (hcd->rh_registered) { pm_wakeup_event(&hcd->self.root_hub->dev, 0); set_bit(HCD_FLAG_WAKEUP_PENDING, &hcd->flags); - queue_work(pm_wq, &hcd->wakeup_work); + queue_work(system_freezable_wq, &hcd->wakeup_work); } spin_unlock_irqrestore (&hcd_root_hub_lock, flags); } diff --git a/drivers/usb/core/offload.c b/drivers/usb/core/offload.c index 7c699f1b8d2b..9db3cfedd29c 100644 --- a/drivers/usb/core/offload.c +++ b/drivers/usb/core/offload.c @@ -25,33 +25,30 @@ */ int usb_offload_get(struct usb_device *udev) { - int ret; + int ret = 0; - usb_lock_device(udev); - if (udev->state == USB_STATE_NOTATTACHED) { - usb_unlock_device(udev); + if (!usb_get_dev(udev)) return -ENODEV; - } - if (udev->state == USB_STATE_SUSPENDED || - udev->offload_at_suspend) { - usb_unlock_device(udev); - return -EBUSY; + if (pm_runtime_get_if_active(&udev->dev) != 1) { + ret = -EBUSY; + goto err_rpm; } - /* - * offload_usage could only be modified when the device is active, since - * it will alter the suspend flow of the device. - */ - ret = usb_autoresume_device(udev); - if (ret < 0) { - usb_unlock_device(udev); - return ret; + spin_lock(&udev->offload_lock); + + if (udev->offload_pm_locked) { + ret = -EAGAIN; + goto err; } udev->offload_usage++; - usb_autosuspend_device(udev); - usb_unlock_device(udev); + +err: + spin_unlock(&udev->offload_lock); + pm_runtime_put_autosuspend(&udev->dev); +err_rpm: + usb_put_dev(udev); return ret; } @@ -69,35 +66,32 @@ EXPORT_SYMBOL_GPL(usb_offload_get); */ int usb_offload_put(struct usb_device *udev) { - int ret; + int ret = 0; - usb_lock_device(udev); - if (udev->state == USB_STATE_NOTATTACHED) { - usb_unlock_device(udev); + if (!usb_get_dev(udev)) return -ENODEV; - } - if (udev->state == USB_STATE_SUSPENDED || - udev->offload_at_suspend) { - usb_unlock_device(udev); - return -EBUSY; + if (pm_runtime_get_if_active(&udev->dev) != 1) { + ret = -EBUSY; + goto err_rpm; } - /* - * offload_usage could only be modified when the device is active, since - * it will alter the suspend flow of the device. - */ - ret = usb_autoresume_device(udev); - if (ret < 0) { - usb_unlock_device(udev); - return ret; + spin_lock(&udev->offload_lock); + + if (udev->offload_pm_locked) { + ret = -EAGAIN; + goto err; } /* Drop the count when it wasn't 0, ignore the operation otherwise. */ if (udev->offload_usage) udev->offload_usage--; - usb_autosuspend_device(udev); - usb_unlock_device(udev); + +err: + spin_unlock(&udev->offload_lock); + pm_runtime_put_autosuspend(&udev->dev); +err_rpm: + usb_put_dev(udev); return ret; } @@ -112,25 +106,47 @@ EXPORT_SYMBOL_GPL(usb_offload_put); * management. * * The caller must hold @udev's device lock. In addition, the caller should - * ensure downstream usb devices are all either suspended or marked as - * "offload_at_suspend" to ensure the correctness of the return value. + * ensure the device itself and the downstream usb devices are all marked as + * "offload_pm_locked" to ensure the correctness of the return value. * * Returns true on any offload activity, false otherwise. */ bool usb_offload_check(struct usb_device *udev) __must_hold(&udev->dev->mutex) { struct usb_device *child; - bool active; + bool active = false; int port1; + if (udev->offload_usage) + return true; + usb_hub_for_each_child(udev, port1, child) { usb_lock_device(child); active = usb_offload_check(child); usb_unlock_device(child); + if (active) - return true; + break; } - return !!udev->offload_usage; + return active; } EXPORT_SYMBOL_GPL(usb_offload_check); + +/** + * usb_offload_set_pm_locked - set the PM lock state of a USB device + * @udev: the USB device to modify + * @locked: the new lock state + * + * Setting @locked to true prevents offload_usage from being modified. This + * ensures that offload activities cannot be started or stopped during critical + * power management transitions, maintaining a stable state for the duration + * of the transition. + */ +void usb_offload_set_pm_locked(struct usb_device *udev, bool locked) +{ + spin_lock(&udev->offload_lock); + udev->offload_pm_locked = locked; + spin_unlock(&udev->offload_lock); +} +EXPORT_SYMBOL_GPL(usb_offload_set_pm_locked); diff --git a/drivers/usb/core/phy.c b/drivers/usb/core/phy.c index 4bba1c275740..4d966cc9cdc9 100644 --- a/drivers/usb/core/phy.c +++ b/drivers/usb/core/phy.c @@ -114,7 +114,7 @@ EXPORT_SYMBOL_GPL(usb_phy_roothub_alloc); struct usb_phy_roothub *usb_phy_roothub_alloc_usb3_phy(struct device *dev) { struct usb_phy_roothub *phy_roothub; - int num_phys; + int num_phys, usb2_phy_index; if (!IS_ENABLED(CONFIG_GENERIC_PHY)) return NULL; @@ -124,6 +124,16 @@ struct usb_phy_roothub *usb_phy_roothub_alloc_usb3_phy(struct device *dev) if (num_phys <= 0) return NULL; + /* + * If 'usb2-phy' is not present, usb_phy_roothub_alloc() added + * all PHYs to the primary HCD's phy_roothub already, so skip + * adding 'usb3-phy' here to avoid double use of that. + */ + usb2_phy_index = of_property_match_string(dev->of_node, "phy-names", + "usb2-phy"); + if (usb2_phy_index < 0) + return NULL; + phy_roothub = devm_kzalloc(dev, sizeof(*phy_roothub), GFP_KERNEL); if (!phy_roothub) return ERR_PTR(-ENOMEM); diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index 5523a8e29021..0ffdaefba508 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -401,6 +401,7 @@ static const struct usb_device_id usb_quirk_list[] = { /* Silicon Motion Flash Drive */ { USB_DEVICE(0x090c, 0x1000), .driver_info = USB_QUIRK_DELAY_INIT }, + { USB_DEVICE(0x090c, 0x2000), .driver_info = USB_QUIRK_DELAY_INIT }, /* Sound Devices USBPre2 */ { USB_DEVICE(0x0926, 0x0202), .driver_info = @@ -492,6 +493,8 @@ static const struct usb_device_id usb_quirk_list[] = { /* Razer - Razer Blade Keyboard */ { USB_DEVICE(0x1532, 0x0116), .driver_info = USB_QUIRK_LINEAR_UFRAME_INTR_BINTERVAL }, + /* Razer - Razer Kiyo Pro Webcam */ + { USB_DEVICE(0x1532, 0x0e05), .driver_info = USB_QUIRK_NO_LPM }, /* Lenovo ThinkPad OneLink+ Dock twin hub controllers (VIA Labs VL812) */ { USB_DEVICE(0x17ef, 0x1018), .driver_info = USB_QUIRK_RESET_RESUME }, diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index e9a10a33534c..df166cafe106 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -671,6 +671,7 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent, set_dev_node(&dev->dev, dev_to_node(bus->sysdev)); dev->state = USB_STATE_ATTACHED; dev->lpm_disable_count = 1; + spin_lock_init(&dev->offload_lock); dev->offload_usage = 0; atomic_set(&dev->urbnum, 0); diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index d216e26c787b..c8b02c27d27d 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -4607,7 +4607,9 @@ static int dwc2_hsotg_udc_stop(struct usb_gadget *gadget) /* Exit clock gating when driver is stopped. */ if (hsotg->params.power_down == DWC2_POWER_DOWN_PARAM_NONE && hsotg->bus_suspended && !hsotg->params.no_clock_gating) { + spin_lock_irqsave(&hsotg->lock, flags); dwc2_gadget_exit_clock_gating(hsotg, 0); + spin_unlock_irqrestore(&hsotg->lock, flags); } /* all endpoints should be shutdown */ diff --git a/drivers/usb/dwc3/dwc3-google.c b/drivers/usb/dwc3/dwc3-google.c index 2105c72af753..4ca567ec01d0 100644 --- a/drivers/usb/dwc3/dwc3-google.c +++ b/drivers/usb/dwc3/dwc3-google.c @@ -385,8 +385,9 @@ static int dwc3_google_probe(struct platform_device *pdev) "google,usb-cfg-csr", ARRAY_SIZE(args), args); if (IS_ERR(google->usb_cfg_regmap)) { - return dev_err_probe(dev, PTR_ERR(google->usb_cfg_regmap), - "invalid usb cfg csr\n"); + ret = dev_err_probe(dev, PTR_ERR(google->usb_cfg_regmap), + "invalid usb cfg csr\n"); + goto err_deinit_pdom; } google->host_cfg_offset = args[0]; diff --git a/drivers/usb/dwc3/dwc3-imx8mp.c b/drivers/usb/dwc3/dwc3-imx8mp.c index b3d7252bd910..1cf96540b66e 100644 --- a/drivers/usb/dwc3/dwc3-imx8mp.c +++ b/drivers/usb/dwc3/dwc3-imx8mp.c @@ -263,7 +263,7 @@ static int dwc3_imx8mp_probe(struct platform_device *pdev) dwc3 = platform_get_drvdata(dwc3_imx->dwc3_pdev); if (!dwc3) { err = dev_err_probe(dev, -EPROBE_DEFER, "failed to get dwc3 platform data\n"); - goto depopulate; + goto put_dwc3; } dwc3->glue_ops = &dwc3_imx_glue_ops; diff --git a/drivers/usb/gadget/function/f_ecm.c b/drivers/usb/gadget/function/f_ecm.c index e0c02121374e..e495bac4efeb 100644 --- a/drivers/usb/gadget/function/f_ecm.c +++ b/drivers/usb/gadget/function/f_ecm.c @@ -681,6 +681,7 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f) struct usb_ep *ep; struct f_ecm_opts *ecm_opts; + struct net_device *net __free(detach_gadget) = NULL; struct usb_request *request __free(free_usb_request) = NULL; if (!can_support_ecm(cdev->gadget)) @@ -688,18 +689,18 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f) ecm_opts = container_of(f->fi, struct f_ecm_opts, func_inst); - mutex_lock(&ecm_opts->lock); - - gether_set_gadget(ecm_opts->net, cdev->gadget); - - if (!ecm_opts->bound) { - status = gether_register_netdev(ecm_opts->net); - ecm_opts->bound = true; - } - - mutex_unlock(&ecm_opts->lock); - if (status) - return status; + scoped_guard(mutex, &ecm_opts->lock) + if (ecm_opts->bind_count == 0 && !ecm_opts->bound) { + if (!device_is_registered(&ecm_opts->net->dev)) { + gether_set_gadget(ecm_opts->net, cdev->gadget); + status = gether_register_netdev(ecm_opts->net); + } else + status = gether_attach_gadget(ecm_opts->net, cdev->gadget); + + if (status) + return status; + net = ecm_opts->net; + } ecm_string_defs[1].s = ecm->ethaddr; @@ -790,6 +791,9 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f) ecm->notify_req = no_free_ptr(request); + ecm_opts->bind_count++; + retain_and_null_ptr(net); + DBG(cdev, "CDC Ethernet: IN/%s OUT/%s NOTIFY/%s\n", ecm->port.in_ep->name, ecm->port.out_ep->name, ecm->notify->name); @@ -836,7 +840,7 @@ static void ecm_free_inst(struct usb_function_instance *f) struct f_ecm_opts *opts; opts = container_of(f, struct f_ecm_opts, func_inst); - if (opts->bound) + if (device_is_registered(&opts->net->dev)) gether_cleanup(netdev_priv(opts->net)); else free_netdev(opts->net); @@ -906,9 +910,12 @@ static void ecm_free(struct usb_function *f) static void ecm_unbind(struct usb_configuration *c, struct usb_function *f) { struct f_ecm *ecm = func_to_ecm(f); + struct f_ecm_opts *ecm_opts; DBG(c->cdev, "ecm unbind\n"); + ecm_opts = container_of(f->fi, struct f_ecm_opts, func_inst); + usb_free_all_descriptors(f); if (atomic_read(&ecm->notify_count)) { @@ -918,6 +925,10 @@ static void ecm_unbind(struct usb_configuration *c, struct usb_function *f) kfree(ecm->notify_req->buf); usb_ep_free_request(ecm->notify, ecm->notify_req); + + ecm_opts->bind_count--; + if (ecm_opts->bind_count == 0 && !ecm_opts->bound) + gether_detach_gadget(ecm_opts->net); } static struct usb_function *ecm_alloc(struct usb_function_instance *fi) diff --git a/drivers/usb/gadget/function/f_eem.c b/drivers/usb/gadget/function/f_eem.c index 0142a0e487ee..ac37d7c1d168 100644 --- a/drivers/usb/gadget/function/f_eem.c +++ b/drivers/usb/gadget/function/f_eem.c @@ -7,6 +7,7 @@ * Copyright (C) 2009 EF Johnson Technologies */ +#include <linux/cleanup.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/device.h> @@ -251,24 +252,22 @@ static int eem_bind(struct usb_configuration *c, struct usb_function *f) struct usb_ep *ep; struct f_eem_opts *eem_opts; + struct net_device *net __free(detach_gadget) = NULL; eem_opts = container_of(f->fi, struct f_eem_opts, func_inst); - /* - * in drivers/usb/gadget/configfs.c:configfs_composite_bind() - * configurations are bound in sequence with list_for_each_entry, - * in each configuration its functions are bound in sequence - * with list_for_each_entry, so we assume no race condition - * with regard to eem_opts->bound access - */ - if (!eem_opts->bound) { - mutex_lock(&eem_opts->lock); - gether_set_gadget(eem_opts->net, cdev->gadget); - status = gether_register_netdev(eem_opts->net); - mutex_unlock(&eem_opts->lock); - if (status) - return status; - eem_opts->bound = true; - } + + scoped_guard(mutex, &eem_opts->lock) + if (eem_opts->bind_count == 0 && !eem_opts->bound) { + if (!device_is_registered(&eem_opts->net->dev)) { + gether_set_gadget(eem_opts->net, cdev->gadget); + status = gether_register_netdev(eem_opts->net); + } else + status = gether_attach_gadget(eem_opts->net, cdev->gadget); + + if (status) + return status; + net = eem_opts->net; + } us = usb_gstrings_attach(cdev, eem_strings, ARRAY_SIZE(eem_string_defs)); @@ -279,21 +278,19 @@ static int eem_bind(struct usb_configuration *c, struct usb_function *f) /* allocate instance-specific interface IDs */ status = usb_interface_id(c, f); if (status < 0) - goto fail; + return status; eem->ctrl_id = status; eem_intf.bInterfaceNumber = status; - status = -ENODEV; - /* allocate instance-specific endpoints */ ep = usb_ep_autoconfig(cdev->gadget, &eem_fs_in_desc); if (!ep) - goto fail; + return -ENODEV; eem->port.in_ep = ep; ep = usb_ep_autoconfig(cdev->gadget, &eem_fs_out_desc); if (!ep) - goto fail; + return -ENODEV; eem->port.out_ep = ep; /* support all relevant hardware speeds... we expect that when @@ -309,16 +306,14 @@ static int eem_bind(struct usb_configuration *c, struct usb_function *f) status = usb_assign_descriptors(f, eem_fs_function, eem_hs_function, eem_ss_function, eem_ss_function); if (status) - goto fail; + return status; + + eem_opts->bind_count++; + retain_and_null_ptr(net); DBG(cdev, "CDC Ethernet (EEM): IN/%s OUT/%s\n", eem->port.in_ep->name, eem->port.out_ep->name); return 0; - -fail: - ERROR(cdev, "%s: can't bind, err %d\n", f->name, status); - - return status; } static void eem_cmd_complete(struct usb_ep *ep, struct usb_request *req) @@ -597,7 +592,7 @@ static void eem_free_inst(struct usb_function_instance *f) struct f_eem_opts *opts; opts = container_of(f, struct f_eem_opts, func_inst); - if (opts->bound) + if (device_is_registered(&opts->net->dev)) gether_cleanup(netdev_priv(opts->net)); else free_netdev(opts->net); @@ -640,9 +635,17 @@ static void eem_free(struct usb_function *f) static void eem_unbind(struct usb_configuration *c, struct usb_function *f) { + struct f_eem_opts *opts; + DBG(c->cdev, "eem unbind\n"); + opts = container_of(f->fi, struct f_eem_opts, func_inst); + usb_free_all_descriptors(f); + + opts->bind_count--; + if (opts->bind_count == 0 && !opts->bound) + gether_detach_gadget(opts->net); } static struct usb_function *eem_alloc(struct usb_function_instance *fi) diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c index 8812ebf33d14..e5ccaec7750c 100644 --- a/drivers/usb/gadget/function/f_hid.c +++ b/drivers/usb/gadget/function/f_hid.c @@ -1262,17 +1262,8 @@ static int hidg_bind(struct usb_configuration *c, struct usb_function *f) if (status) goto fail; - spin_lock_init(&hidg->write_spinlock); hidg->write_pending = 1; hidg->req = NULL; - spin_lock_init(&hidg->read_spinlock); - spin_lock_init(&hidg->get_report_spinlock); - init_waitqueue_head(&hidg->write_queue); - init_waitqueue_head(&hidg->read_queue); - init_waitqueue_head(&hidg->get_queue); - init_waitqueue_head(&hidg->get_id_queue); - INIT_LIST_HEAD(&hidg->completed_out_req); - INIT_LIST_HEAD(&hidg->report_list); INIT_WORK(&hidg->work, get_report_workqueue_handler); hidg->workqueue = alloc_workqueue("report_work", @@ -1608,6 +1599,16 @@ static struct usb_function *hidg_alloc(struct usb_function_instance *fi) mutex_lock(&opts->lock); + spin_lock_init(&hidg->write_spinlock); + spin_lock_init(&hidg->read_spinlock); + spin_lock_init(&hidg->get_report_spinlock); + init_waitqueue_head(&hidg->write_queue); + init_waitqueue_head(&hidg->read_queue); + init_waitqueue_head(&hidg->get_queue); + init_waitqueue_head(&hidg->get_id_queue); + INIT_LIST_HEAD(&hidg->completed_out_req); + INIT_LIST_HEAD(&hidg->report_list); + device_initialize(&hidg->dev); hidg->dev.release = hidg_release; hidg->dev.class = &hidg_class; diff --git a/drivers/usb/gadget/function/f_rndis.c b/drivers/usb/gadget/function/f_rndis.c index 8b11d8d6d89c..7de1c5f8e326 100644 --- a/drivers/usb/gadget/function/f_rndis.c +++ b/drivers/usb/gadget/function/f_rndis.c @@ -11,6 +11,7 @@ /* #define VERBOSE_DEBUG */ +#include <linux/cleanup.h> #include <linux/slab.h> #include <linux/kernel.h> #include <linux/module.h> @@ -665,6 +666,7 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f) struct f_rndis_opts *rndis_opts; struct usb_os_desc_table *os_desc_table __free(kfree) = NULL; + struct net_device *net __free(detach_gadget) = NULL; struct usb_request *request __free(free_usb_request) = NULL; if (!can_support_rndis(c)) @@ -678,23 +680,22 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f) return -ENOMEM; } - rndis_iad_descriptor.bFunctionClass = rndis_opts->class; - rndis_iad_descriptor.bFunctionSubClass = rndis_opts->subclass; - rndis_iad_descriptor.bFunctionProtocol = rndis_opts->protocol; - - /* - * in drivers/usb/gadget/configfs.c:configfs_composite_bind() - * configurations are bound in sequence with list_for_each_entry, - * in each configuration its functions are bound in sequence - * with list_for_each_entry, so we assume no race condition - * with regard to rndis_opts->bound access - */ - if (!rndis_opts->bound) { - gether_set_gadget(rndis_opts->net, cdev->gadget); - status = gether_register_netdev(rndis_opts->net); - if (status) - return status; - rndis_opts->bound = true; + scoped_guard(mutex, &rndis_opts->lock) { + rndis_iad_descriptor.bFunctionClass = rndis_opts->class; + rndis_iad_descriptor.bFunctionSubClass = rndis_opts->subclass; + rndis_iad_descriptor.bFunctionProtocol = rndis_opts->protocol; + + if (rndis_opts->bind_count == 0 && !rndis_opts->borrowed_net) { + if (!device_is_registered(&rndis_opts->net->dev)) { + gether_set_gadget(rndis_opts->net, cdev->gadget); + status = gether_register_netdev(rndis_opts->net); + } else + status = gether_attach_gadget(rndis_opts->net, cdev->gadget); + + if (status) + return status; + net = rndis_opts->net; + } } us = usb_gstrings_attach(cdev, rndis_strings, @@ -793,6 +794,9 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f) } rndis->notify_req = no_free_ptr(request); + rndis_opts->bind_count++; + retain_and_null_ptr(net); + /* NOTE: all that is done without knowing or caring about * the network link ... which is unavailable to this code * until we're activated via set_alt(). @@ -809,11 +813,11 @@ void rndis_borrow_net(struct usb_function_instance *f, struct net_device *net) struct f_rndis_opts *opts; opts = container_of(f, struct f_rndis_opts, func_inst); - if (opts->bound) + if (device_is_registered(&opts->net->dev)) gether_cleanup(netdev_priv(opts->net)); else free_netdev(opts->net); - opts->borrowed_net = opts->bound = true; + opts->borrowed_net = true; opts->net = net; } EXPORT_SYMBOL_GPL(rndis_borrow_net); @@ -871,7 +875,7 @@ static void rndis_free_inst(struct usb_function_instance *f) opts = container_of(f, struct f_rndis_opts, func_inst); if (!opts->borrowed_net) { - if (opts->bound) + if (device_is_registered(&opts->net->dev)) gether_cleanup(netdev_priv(opts->net)); else free_netdev(opts->net); @@ -940,6 +944,9 @@ static void rndis_free(struct usb_function *f) static void rndis_unbind(struct usb_configuration *c, struct usb_function *f) { struct f_rndis *rndis = func_to_rndis(f); + struct f_rndis_opts *rndis_opts; + + rndis_opts = container_of(f->fi, struct f_rndis_opts, func_inst); kfree(f->os_desc_table); f->os_desc_n = 0; @@ -947,6 +954,10 @@ static void rndis_unbind(struct usb_configuration *c, struct usb_function *f) kfree(rndis->notify_req->buf); usb_ep_free_request(rndis->notify, rndis->notify_req); + + rndis_opts->bind_count--; + if (rndis_opts->bind_count == 0 && !rndis_opts->borrowed_net) + gether_detach_gadget(rndis_opts->net); } static struct usb_function *rndis_alloc(struct usb_function_instance *fi) diff --git a/drivers/usb/gadget/function/f_subset.c b/drivers/usb/gadget/function/f_subset.c index 076072386e5e..6e3265b8a3a0 100644 --- a/drivers/usb/gadget/function/f_subset.c +++ b/drivers/usb/gadget/function/f_subset.c @@ -6,6 +6,7 @@ * Copyright (C) 2008 Nokia Corporation */ +#include <linux/cleanup.h> #include <linux/slab.h> #include <linux/kernel.h> #include <linux/module.h> @@ -298,25 +299,22 @@ geth_bind(struct usb_configuration *c, struct usb_function *f) struct usb_ep *ep; struct f_gether_opts *gether_opts; + struct net_device *net __free(detach_gadget) = NULL; gether_opts = container_of(f->fi, struct f_gether_opts, func_inst); - /* - * in drivers/usb/gadget/configfs.c:configfs_composite_bind() - * configurations are bound in sequence with list_for_each_entry, - * in each configuration its functions are bound in sequence - * with list_for_each_entry, so we assume no race condition - * with regard to gether_opts->bound access - */ - if (!gether_opts->bound) { - mutex_lock(&gether_opts->lock); - gether_set_gadget(gether_opts->net, cdev->gadget); - status = gether_register_netdev(gether_opts->net); - mutex_unlock(&gether_opts->lock); - if (status) - return status; - gether_opts->bound = true; - } + scoped_guard(mutex, &gether_opts->lock) + if (gether_opts->bind_count == 0 && !gether_opts->bound) { + if (!device_is_registered(&gether_opts->net->dev)) { + gether_set_gadget(gether_opts->net, cdev->gadget); + status = gether_register_netdev(gether_opts->net); + } else + status = gether_attach_gadget(gether_opts->net, cdev->gadget); + + if (status) + return status; + net = gether_opts->net; + } us = usb_gstrings_attach(cdev, geth_strings, ARRAY_SIZE(geth_string_defs)); @@ -329,20 +327,18 @@ geth_bind(struct usb_configuration *c, struct usb_function *f) /* allocate instance-specific interface IDs */ status = usb_interface_id(c, f); if (status < 0) - goto fail; + return status; subset_data_intf.bInterfaceNumber = status; - status = -ENODEV; - /* allocate instance-specific endpoints */ ep = usb_ep_autoconfig(cdev->gadget, &fs_subset_in_desc); if (!ep) - goto fail; + return -ENODEV; geth->port.in_ep = ep; ep = usb_ep_autoconfig(cdev->gadget, &fs_subset_out_desc); if (!ep) - goto fail; + return -ENODEV; geth->port.out_ep = ep; /* support all relevant hardware speeds... we expect that when @@ -360,21 +356,19 @@ geth_bind(struct usb_configuration *c, struct usb_function *f) status = usb_assign_descriptors(f, fs_eth_function, hs_eth_function, ss_eth_function, ss_eth_function); if (status) - goto fail; + return status; /* NOTE: all that is done without knowing or caring about * the network link ... which is unavailable to this code * until we're activated via set_alt(). */ + gether_opts->bind_count++; + retain_and_null_ptr(net); + DBG(cdev, "CDC Subset: IN/%s OUT/%s\n", geth->port.in_ep->name, geth->port.out_ep->name); return 0; - -fail: - ERROR(cdev, "%s: can't bind, err %d\n", f->name, status); - - return status; } static inline struct f_gether_opts *to_f_gether_opts(struct config_item *item) @@ -417,7 +411,7 @@ static void geth_free_inst(struct usb_function_instance *f) struct f_gether_opts *opts; opts = container_of(f, struct f_gether_opts, func_inst); - if (opts->bound) + if (device_is_registered(&opts->net->dev)) gether_cleanup(netdev_priv(opts->net)); else free_netdev(opts->net); @@ -449,15 +443,28 @@ static struct usb_function_instance *geth_alloc_inst(void) static void geth_free(struct usb_function *f) { struct f_gether *eth; + struct f_gether_opts *opts; + + opts = container_of(f->fi, struct f_gether_opts, func_inst); eth = func_to_geth(f); + scoped_guard(mutex, &opts->lock) + opts->refcnt--; kfree(eth); } static void geth_unbind(struct usb_configuration *c, struct usb_function *f) { + struct f_gether_opts *opts; + + opts = container_of(f->fi, struct f_gether_opts, func_inst); + geth_string_defs[0].id = 0; usb_free_all_descriptors(f); + + opts->bind_count--; + if (opts->bind_count == 0 && !opts->bound) + gether_detach_gadget(opts->net); } static struct usb_function *geth_alloc(struct usb_function_instance *fi) diff --git a/drivers/usb/gadget/function/f_uac1_legacy.c b/drivers/usb/gadget/function/f_uac1_legacy.c index a0c953a99727..5d201a2e30e7 100644 --- a/drivers/usb/gadget/function/f_uac1_legacy.c +++ b/drivers/usb/gadget/function/f_uac1_legacy.c @@ -360,19 +360,46 @@ static int f_audio_out_ep_complete(struct usb_ep *ep, struct usb_request *req) static void f_audio_complete(struct usb_ep *ep, struct usb_request *req) { struct f_audio *audio = req->context; - int status = req->status; - u32 data = 0; struct usb_ep *out_ep = audio->out_ep; - switch (status) { - - case 0: /* normal completion? */ - if (ep == out_ep) + switch (req->status) { + case 0: + if (ep == out_ep) { f_audio_out_ep_complete(ep, req); - else if (audio->set_con) { - memcpy(&data, req->buf, req->length); - audio->set_con->set(audio->set_con, audio->set_cmd, - le16_to_cpu(data)); + } else if (audio->set_con) { + struct usb_audio_control *con = audio->set_con; + u8 type = con->type; + u32 data; + bool valid_request = false; + + switch (type) { + case UAC_FU_MUTE: { + u8 value; + + if (req->actual == sizeof(value)) { + memcpy(&value, req->buf, sizeof(value)); + data = value; + valid_request = true; + } + break; + } + case UAC_FU_VOLUME: { + __le16 value; + + if (req->actual == sizeof(value)) { + memcpy(&value, req->buf, sizeof(value)); + data = le16_to_cpu(value); + valid_request = true; + } + break; + } + } + + if (valid_request) + con->set(con, audio->set_cmd, data); + else + usb_ep_set_halt(ep); + audio->set_con = NULL; } break; diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c index 494fdbc4e85b..8d404d88391c 100644 --- a/drivers/usb/gadget/function/f_uvc.c +++ b/drivers/usb/gadget/function/f_uvc.c @@ -413,6 +413,12 @@ uvc_function_disconnect(struct uvc_device *uvc) { int ret; + guard(mutex)(&uvc->lock); + if (uvc->func_unbound) { + dev_dbg(&uvc->vdev.dev, "skipping function deactivate (unbound)\n"); + return; + } + if ((ret = usb_function_deactivate(&uvc->func)) < 0) uvcg_info(&uvc->func, "UVC disconnect failed with %d\n", ret); } @@ -431,6 +437,15 @@ static ssize_t function_name_show(struct device *dev, static DEVICE_ATTR_RO(function_name); +static void uvc_vdev_release(struct video_device *vdev) +{ + struct uvc_device *uvc = video_get_drvdata(vdev); + + /* Signal uvc_function_unbind() that the video device has been released */ + if (uvc->vdev_release_done) + complete(uvc->vdev_release_done); +} + static int uvc_register_video(struct uvc_device *uvc) { @@ -443,7 +458,7 @@ uvc_register_video(struct uvc_device *uvc) uvc->vdev.v4l2_dev->dev = &cdev->gadget->dev; uvc->vdev.fops = &uvc_v4l2_fops; uvc->vdev.ioctl_ops = &uvc_v4l2_ioctl_ops; - uvc->vdev.release = video_device_release_empty; + uvc->vdev.release = uvc_vdev_release; uvc->vdev.vfl_dir = VFL_DIR_TX; uvc->vdev.lock = &uvc->video.mutex; uvc->vdev.device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING; @@ -659,6 +674,8 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f) int ret = -EINVAL; uvcg_info(f, "%s()\n", __func__); + scoped_guard(mutex, &uvc->lock) + uvc->func_unbound = false; opts = fi_to_f_uvc_opts(f->fi); /* Sanity check the streaming endpoint module parameters. */ @@ -988,12 +1005,19 @@ static void uvc_free(struct usb_function *f) static void uvc_function_unbind(struct usb_configuration *c, struct usb_function *f) { + DECLARE_COMPLETION_ONSTACK(vdev_release_done); struct usb_composite_dev *cdev = c->cdev; struct uvc_device *uvc = to_uvc(f); struct uvc_video *video = &uvc->video; long wait_ret = 1; + bool connected; uvcg_info(f, "%s()\n", __func__); + scoped_guard(mutex, &uvc->lock) { + uvc->func_unbound = true; + uvc->vdev_release_done = &vdev_release_done; + connected = uvc->func_connected; + } kthread_cancel_work_sync(&video->hw_submit); @@ -1006,7 +1030,7 @@ static void uvc_function_unbind(struct usb_configuration *c, * though the video device removal uevent. Allow some time for the * application to close out before things get deleted. */ - if (uvc->func_connected) { + if (connected) { uvcg_dbg(f, "waiting for clean disconnect\n"); wait_ret = wait_event_interruptible_timeout(uvc->func_connected_queue, uvc->func_connected == false, msecs_to_jiffies(500)); @@ -1017,7 +1041,10 @@ static void uvc_function_unbind(struct usb_configuration *c, video_unregister_device(&uvc->vdev); v4l2_device_unregister(&uvc->v4l2_dev); - if (uvc->func_connected) { + scoped_guard(mutex, &uvc->lock) + connected = uvc->func_connected; + + if (connected) { /* * Wait for the release to occur to ensure there are no longer any * pending operations that may cause panics when resources are cleaned @@ -1029,6 +1056,10 @@ static void uvc_function_unbind(struct usb_configuration *c, uvcg_dbg(f, "done waiting for release with ret: %ld\n", wait_ret); } + /* Wait for the video device to be released */ + wait_for_completion(&vdev_release_done); + uvc->vdev_release_done = NULL; + usb_ep_free_request(cdev->gadget->ep0, uvc->control_req); kfree(uvc->control_buf); @@ -1047,6 +1078,8 @@ static struct usb_function *uvc_alloc(struct usb_function_instance *fi) return ERR_PTR(-ENOMEM); mutex_init(&uvc->video.mutex); + mutex_init(&uvc->lock); + uvc->func_unbound = true; uvc->state = UVC_STATE_DISCONNECTED; init_waitqueue_head(&uvc->func_connected_queue); opts = fi_to_f_uvc_opts(fi); diff --git a/drivers/usb/gadget/function/u_ecm.h b/drivers/usb/gadget/function/u_ecm.h index 77cfb89932be..7f666b9dea02 100644 --- a/drivers/usb/gadget/function/u_ecm.h +++ b/drivers/usb/gadget/function/u_ecm.h @@ -15,17 +15,26 @@ #include <linux/usb/composite.h> +/** + * struct f_ecm_opts - ECM function options + * @func_inst: USB function instance. + * @net: The net_device associated with the ECM function. + * @bound: True if the net_device is shared and pre-registered during the + * legacy composite driver's bind phase (e.g., multi.c). If false, + * the ECM function will register the net_device during its own + * bind phase. + * @bind_count: Tracks the number of configurations the ECM function is + * bound to, preventing double-registration of the @net device. + * @lock: Protects the data from concurrent access by configfs read/write + * and create symlink/remove symlink operations. + * @refcnt: Reference counter for the function instance. + */ struct f_ecm_opts { struct usb_function_instance func_inst; struct net_device *net; bool bound; + int bind_count; - /* - * Read/write access to configfs attributes is handled by configfs. - * - * This is to protect the data from concurrent access by read/write - * and create symlink/remove symlink. - */ struct mutex lock; int refcnt; }; diff --git a/drivers/usb/gadget/function/u_eem.h b/drivers/usb/gadget/function/u_eem.h index 3bd85dfcd71c..78ef55815219 100644 --- a/drivers/usb/gadget/function/u_eem.h +++ b/drivers/usb/gadget/function/u_eem.h @@ -15,17 +15,26 @@ #include <linux/usb/composite.h> +/** + * struct f_eem_opts - EEM function options + * @func_inst: USB function instance. + * @net: The net_device associated with the EEM function. + * @bound: True if the net_device is shared and pre-registered during the + * legacy composite driver's bind phase (e.g., multi.c). If false, + * the EEM function will register the net_device during its own + * bind phase. + * @bind_count: Tracks the number of configurations the EEM function is + * bound to, preventing double-registration of the @net device. + * @lock: Protects the data from concurrent access by configfs read/write + * and create symlink/remove symlink operations. + * @refcnt: Reference counter for the function instance. + */ struct f_eem_opts { struct usb_function_instance func_inst; struct net_device *net; bool bound; + int bind_count; - /* - * Read/write access to configfs attributes is handled by configfs. - * - * This is to protect the data from concurrent access by read/write - * and create symlink/remove symlink. - */ struct mutex lock; int refcnt; }; diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/function/u_ether.c index 1a9e7c495e2e..59d85d6a84a8 100644 --- a/drivers/usb/gadget/function/u_ether.c +++ b/drivers/usb/gadget/function/u_ether.c @@ -113,8 +113,10 @@ static void eth_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *p) strscpy(p->driver, "g_ether", sizeof(p->driver)); strscpy(p->version, UETH__VERSION, sizeof(p->version)); - strscpy(p->fw_version, dev->gadget->name, sizeof(p->fw_version)); - strscpy(p->bus_info, dev_name(&dev->gadget->dev), sizeof(p->bus_info)); + if (dev->gadget) { + strscpy(p->fw_version, dev->gadget->name, sizeof(p->fw_version)); + strscpy(p->bus_info, dev_name(&dev->gadget->dev), sizeof(p->bus_info)); + } } /* REVISIT can also support: @@ -1223,6 +1225,11 @@ void gether_disconnect(struct gether *link) DBG(dev, "%s\n", __func__); + spin_lock(&dev->lock); + dev->port_usb = NULL; + link->is_suspend = false; + spin_unlock(&dev->lock); + netif_stop_queue(dev->net); netif_carrier_off(dev->net); @@ -1260,11 +1267,6 @@ void gether_disconnect(struct gether *link) dev->header_len = 0; dev->unwrap = NULL; dev->wrap = NULL; - - spin_lock(&dev->lock); - dev->port_usb = NULL; - link->is_suspend = false; - spin_unlock(&dev->lock); } EXPORT_SYMBOL_GPL(gether_disconnect); diff --git a/drivers/usb/gadget/function/u_gether.h b/drivers/usb/gadget/function/u_gether.h index 2f7a373ed449..e7b6b51f69c1 100644 --- a/drivers/usb/gadget/function/u_gether.h +++ b/drivers/usb/gadget/function/u_gether.h @@ -15,17 +15,25 @@ #include <linux/usb/composite.h> +/** + * struct f_gether_opts - subset function options + * @func_inst: USB function instance. + * @net: The net_device associated with the subset function. + * @bound: True if the net_device is shared and pre-registered during the + * legacy composite driver's bind phase (e.g., multi.c). If false, + * the subset function will register the net_device during its own + * bind phase. + * @bind_count: Tracks the number of configurations the subset function is + * bound to, preventing double-registration of the @net device. + * @lock: Protects the data from concurrent access by configfs read/write + * and create symlink/remove symlink operations. + * @refcnt: Reference counter for the function instance. + */ struct f_gether_opts { struct usb_function_instance func_inst; struct net_device *net; bool bound; - - /* - * Read/write access to configfs attributes is handled by configfs. - * - * This is to protect the data from concurrent access by read/write - * and create symlink/remove symlink. - */ + int bind_count; struct mutex lock; int refcnt; }; diff --git a/drivers/usb/gadget/function/u_ncm.h b/drivers/usb/gadget/function/u_ncm.h index b1f3db8b68c1..ce2f6358688a 100644 --- a/drivers/usb/gadget/function/u_ncm.h +++ b/drivers/usb/gadget/function/u_ncm.h @@ -15,6 +15,20 @@ #include <linux/usb/composite.h> +/** + * struct f_ncm_opts - NCM function options + * @func_inst: USB function instance. + * @net: The net_device associated with the NCM function. + * @bind_count: Tracks the number of configurations the NCM function is + * bound to, preventing double-registration of the @net device. + * @ncm_interf_group: ConfigFS group for NCM interface. + * @ncm_os_desc: USB OS descriptor for NCM. + * @ncm_ext_compat_id: Extended compatibility ID. + * @lock: Protects the data from concurrent access by configfs read/write + * and create symlink/remove symlink operations. + * @refcnt: Reference counter for the function instance. + * @max_segment_size: Maximum segment size. + */ struct f_ncm_opts { struct usb_function_instance func_inst; struct net_device *net; @@ -23,12 +37,7 @@ struct f_ncm_opts { struct config_group *ncm_interf_group; struct usb_os_desc ncm_os_desc; char ncm_ext_compat_id[16]; - /* - * Read/write access to configfs attributes is handled by configfs. - * - * This is to protect the data from concurrent access by read/write - * and create symlink/remove symlink. - */ + struct mutex lock; int refcnt; diff --git a/drivers/usb/gadget/function/u_rndis.h b/drivers/usb/gadget/function/u_rndis.h index a8c409b2f52f..4e64619714dc 100644 --- a/drivers/usb/gadget/function/u_rndis.h +++ b/drivers/usb/gadget/function/u_rndis.h @@ -15,12 +15,34 @@ #include <linux/usb/composite.h> +/** + * struct f_rndis_opts - RNDIS function options + * @func_inst: USB function instance. + * @vendor_id: Vendor ID. + * @manufacturer: Manufacturer string. + * @net: The net_device associated with the RNDIS function. + * @bind_count: Tracks the number of configurations the RNDIS function is + * bound to, preventing double-registration of the @net device. + * @borrowed_net: True if the net_device is shared and pre-registered during + * the legacy composite driver's bind phase (e.g., multi.c). + * If false, the RNDIS function will register the net_device + * during its own bind phase. + * @rndis_interf_group: ConfigFS group for RNDIS interface. + * @rndis_os_desc: USB OS descriptor for RNDIS. + * @rndis_ext_compat_id: Extended compatibility ID. + * @class: USB class. + * @subclass: USB subclass. + * @protocol: USB protocol. + * @lock: Protects the data from concurrent access by configfs read/write + * and create symlink/remove symlink operations. + * @refcnt: Reference counter for the function instance. + */ struct f_rndis_opts { struct usb_function_instance func_inst; u32 vendor_id; const char *manufacturer; struct net_device *net; - bool bound; + int bind_count; bool borrowed_net; struct config_group *rndis_interf_group; @@ -30,13 +52,6 @@ struct f_rndis_opts { u8 class; u8 subclass; u8 protocol; - - /* - * Read/write access to configfs attributes is handled by configfs. - * - * This is to protect the data from concurrent access by read/write - * and create symlink/remove symlink. - */ struct mutex lock; int refcnt; }; diff --git a/drivers/usb/gadget/function/uvc.h b/drivers/usb/gadget/function/uvc.h index 676419a04976..7abfdd5e1eef 100644 --- a/drivers/usb/gadget/function/uvc.h +++ b/drivers/usb/gadget/function/uvc.h @@ -155,6 +155,9 @@ struct uvc_device { enum uvc_state state; struct usb_function func; struct uvc_video video; + struct completion *vdev_release_done; + struct mutex lock; /* protects func_unbound and func_connected */ + bool func_unbound; bool func_connected; wait_queue_head_t func_connected_queue; diff --git a/drivers/usb/gadget/function/uvc_v4l2.c b/drivers/usb/gadget/function/uvc_v4l2.c index ed48d38498fb..514e5930b9ca 100644 --- a/drivers/usb/gadget/function/uvc_v4l2.c +++ b/drivers/usb/gadget/function/uvc_v4l2.c @@ -574,6 +574,8 @@ uvc_v4l2_subscribe_event(struct v4l2_fh *fh, if (sub->type < UVC_EVENT_FIRST || sub->type > UVC_EVENT_LAST) return -EINVAL; + guard(mutex)(&uvc->lock); + if (sub->type == UVC_EVENT_SETUP && uvc->func_connected) return -EBUSY; @@ -595,7 +597,8 @@ static void uvc_v4l2_disable(struct uvc_device *uvc) uvc_function_disconnect(uvc); uvcg_video_disable(&uvc->video); uvcg_free_buffers(&uvc->video.queue); - uvc->func_connected = false; + scoped_guard(mutex, &uvc->lock) + uvc->func_connected = false; wake_up_interruptible(&uvc->func_connected_queue); } diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c index c9eca90376e2..f094491b1041 100644 --- a/drivers/usb/gadget/udc/dummy_hcd.c +++ b/drivers/usb/gadget/udc/dummy_hcd.c @@ -462,8 +462,13 @@ static void set_link_state(struct dummy_hcd *dum_hcd) /* Report reset and disconnect events to the driver */ if (dum->ints_enabled && (disconnect || reset)) { - stop_activity(dum); ++dum->callback_usage; + /* + * stop_activity() can drop dum->lock, so it must + * not come between the dum->ints_enabled test + * and the ++dum->callback_usage. + */ + stop_activity(dum); spin_unlock(&dum->lock); if (reset) usb_gadget_udc_reset(&dum->gadget, dum->driver); @@ -908,21 +913,6 @@ static int dummy_pullup(struct usb_gadget *_gadget, int value) spin_lock_irqsave(&dum->lock, flags); dum->pullup = (value != 0); set_link_state(dum_hcd); - if (value == 0) { - /* - * Emulate synchronize_irq(): wait for callbacks to finish. - * This seems to be the best place to emulate the call to - * synchronize_irq() that's in usb_gadget_remove_driver(). - * Doing it in dummy_udc_stop() would be too late since it - * is called after the unbind callback and unbind shouldn't - * be invoked until all the other callbacks are finished. - */ - while (dum->callback_usage > 0) { - spin_unlock_irqrestore(&dum->lock, flags); - usleep_range(1000, 2000); - spin_lock_irqsave(&dum->lock, flags); - } - } spin_unlock_irqrestore(&dum->lock, flags); usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum_hcd)); @@ -945,6 +935,20 @@ static void dummy_udc_async_callbacks(struct usb_gadget *_gadget, bool enable) spin_lock_irq(&dum->lock); dum->ints_enabled = enable; + if (!enable) { + /* + * Emulate synchronize_irq(): wait for callbacks to finish. + * This has to happen after emulated interrupts are disabled + * (dum->ints_enabled is clear) and before the unbind callback, + * just like the call to synchronize_irq() in + * gadget/udc/core:gadget_unbind_driver(). + */ + while (dum->callback_usage > 0) { + spin_unlock_irq(&dum->lock); + usleep_range(1000, 2000); + spin_lock_irq(&dum->lock); + } + } spin_unlock_irq(&dum->lock); } @@ -1534,6 +1538,12 @@ top: /* rescan to continue with any other queued i/o */ if (rescan) goto top; + + /* request not fully transferred; stop iterating to + * preserve data ordering across queued requests. + */ + if (req->req.actual < req->req.length) + break; } return sent; } diff --git a/drivers/usb/host/ehci-brcm.c b/drivers/usb/host/ehci-brcm.c index 888e8f6670d2..5e3156f94cc6 100644 --- a/drivers/usb/host/ehci-brcm.c +++ b/drivers/usb/host/ehci-brcm.c @@ -31,8 +31,8 @@ static inline void ehci_brcm_wait_for_sof(struct ehci_hcd *ehci, u32 delay) int res; /* Wait for next microframe (every 125 usecs) */ - res = readl_relaxed_poll_timeout(&ehci->regs->frame_index, val, - val != frame_idx, 1, 130); + res = readl_relaxed_poll_timeout_atomic(&ehci->regs->frame_index, + val, val != frame_idx, 1, 130); if (res) ehci_err(ehci, "Error waiting for SOF\n"); udelay(delay); diff --git a/drivers/usb/host/xhci-sideband.c b/drivers/usb/host/xhci-sideband.c index abbcc0e44f1b..23153e136d4b 100644 --- a/drivers/usb/host/xhci-sideband.c +++ b/drivers/usb/host/xhci-sideband.c @@ -93,8 +93,6 @@ __xhci_sideband_remove_endpoint(struct xhci_sideband *sb, struct xhci_virt_ep *e static void __xhci_sideband_remove_interrupter(struct xhci_sideband *sb) { - struct usb_device *udev; - lockdep_assert_held(&sb->mutex); if (!sb->ir) @@ -102,10 +100,6 @@ __xhci_sideband_remove_interrupter(struct xhci_sideband *sb) xhci_remove_secondary_interrupter(xhci_to_hcd(sb->xhci), sb->ir); sb->ir = NULL; - udev = sb->vdev->udev; - - if (udev->state != USB_STATE_NOTATTACHED) - usb_offload_put(udev); } /* sideband api functions */ @@ -291,8 +285,8 @@ EXPORT_SYMBOL_GPL(xhci_sideband_get_event_buffer); * Allow other drivers, such as usb controller driver, to check if there are * any sideband activity on the host controller. This information could be used * for power management or other forms of resource management. The caller should - * ensure downstream usb devices are all either suspended or marked as - * "offload_at_suspend" to ensure the correctness of the return value. + * ensure downstream usb devices are all marked as "offload_pm_locked" to ensure + * the correctness of the return value. * * Returns true on any active sideband existence, false otherwise. */ @@ -328,9 +322,6 @@ int xhci_sideband_create_interrupter(struct xhci_sideband *sb, int num_seg, bool ip_autoclear, u32 imod_interval, int intr_num) { - int ret = 0; - struct usb_device *udev; - if (!sb || !sb->xhci) return -ENODEV; @@ -348,12 +339,9 @@ xhci_sideband_create_interrupter(struct xhci_sideband *sb, int num_seg, if (!sb->ir) return -ENOMEM; - udev = sb->vdev->udev; - ret = usb_offload_get(udev); - sb->ir->ip_autoclear = ip_autoclear; - return ret; + return 0; } EXPORT_SYMBOL_GPL(xhci_sideband_create_interrupter); diff --git a/drivers/usb/misc/usbio.c b/drivers/usb/misc/usbio.c index 2e68d48a2cc0..02d1e0760f0c 100644 --- a/drivers/usb/misc/usbio.c +++ b/drivers/usb/misc/usbio.c @@ -614,8 +614,10 @@ static int usbio_probe(struct usb_interface *intf, const struct usb_device_id *i usb_fill_bulk_urb(usbio->urb, udev, usbio->rx_pipe, usbio->rxbuf, usbio->rxbuf_len, usbio_bulk_recv, usbio); ret = usb_submit_urb(usbio->urb, GFP_KERNEL); - if (ret) - return dev_err_probe(dev, ret, "Submitting usb urb\n"); + if (ret) { + dev_err_probe(dev, ret, "Submitting usb urb\n"); + goto err_free_urb; + } mutex_lock(&usbio->ctrl_mutex); @@ -663,6 +665,7 @@ static int usbio_probe(struct usb_interface *intf, const struct usb_device_id *i err_unlock: mutex_unlock(&usbio->ctrl_mutex); usb_kill_urb(usbio->urb); +err_free_urb: usb_free_urb(usbio->urb); return ret; diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c index 58694b8943d1..3f5889145e51 100644 --- a/drivers/usb/serial/io_edgeport.c +++ b/drivers/usb/serial/io_edgeport.c @@ -73,6 +73,7 @@ static const struct usb_device_id edgeport_4port_id_table[] = { { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_22I) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_412_4) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_COMPATIBLE) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BLACKBOX_IC135A) }, { } }; @@ -121,6 +122,7 @@ static const struct usb_device_id id_table_combined[] = { { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8R) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8RR) }, { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_412_8) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_BLACKBOX_IC135A) }, { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0202) }, { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0203) }, { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0310) }, @@ -470,6 +472,7 @@ static void get_product_info(struct edgeport_serial *edge_serial) case ION_DEVICE_ID_EDGEPORT_2_DIN: case ION_DEVICE_ID_EDGEPORT_4_DIN: case ION_DEVICE_ID_EDGEPORT_16_DUAL_CPU: + case ION_DEVICE_ID_BLACKBOX_IC135A: product_info->IsRS232 = 1; break; diff --git a/drivers/usb/serial/io_usbvend.h b/drivers/usb/serial/io_usbvend.h index 9a6f742ad3ab..c82a275e8e76 100644 --- a/drivers/usb/serial/io_usbvend.h +++ b/drivers/usb/serial/io_usbvend.h @@ -211,6 +211,7 @@ // // Definitions for other product IDs +#define ION_DEVICE_ID_BLACKBOX_IC135A 0x0801 // OEM device (rebranded Edgeport/4) #define ION_DEVICE_ID_MT4X56USB 0x1403 // OEM device #define ION_DEVICE_ID_E5805A 0x1A01 // OEM device (rebranded Edgeport/4) diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index e349ed66d2ac..313612114db9 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -2441,6 +2441,9 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d22, 0xff, 0xff, 0x30) }, /* MeiG Smart SRM815 and SRM825L */ { USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d22, 0xff, 0xff, 0x40) }, /* MeiG Smart SRM825L */ { USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d22, 0xff, 0xff, 0x60) }, /* MeiG Smart SRM825L */ + { USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d38, 0xff, 0xff, 0x30) }, /* MeiG Smart SRM825WN (Diag) */ + { USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d38, 0xff, 0xff, 0x40) }, /* MeiG Smart SRM825WN (AT) */ + { USB_DEVICE_AND_INTERFACE_INFO(0x2dee, 0x4d38, 0xff, 0xff, 0x60) }, /* MeiG Smart SRM825WN (NMEA) */ { USB_DEVICE_INTERFACE_CLASS(0x2df3, 0x9d03, 0xff) }, /* LongSung M5710 */ { USB_DEVICE_INTERFACE_CLASS(0x305a, 0x1404, 0xff) }, /* GosunCn GM500 RNDIS */ { USB_DEVICE_INTERFACE_CLASS(0x305a, 0x1405, 0xff) }, /* GosunCn GM500 MBIM */ @@ -2461,6 +2464,7 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_INTERFACE_CLASS(0x33f8, 0x0302, 0xff) }, /* Rolling RW101R-GL (laptop MBIM) */ { USB_DEVICE_INTERFACE_CLASS(0x33f8, 0x0802, 0xff), /* Rolling RW350-GL (laptop MBIM) */ .driver_info = RSVD(5) }, + { USB_DEVICE_INTERFACE_CLASS(0x33f8, 0x1003, 0xff) }, /* Rolling RW135R-GL (laptop MBIM) */ { USB_DEVICE_AND_INTERFACE_INFO(0x3731, 0x0100, 0xff, 0xff, 0x30) }, /* NetPrisma LCUK54-WWD for Global */ { USB_DEVICE_AND_INTERFACE_INFO(0x3731, 0x0100, 0xff, 0x00, 0x40) }, { USB_DEVICE_AND_INTERFACE_INFO(0x3731, 0x0100, 0xff, 0xff, 0x40) }, diff --git a/drivers/usb/typec/altmodes/thunderbolt.c b/drivers/usb/typec/altmodes/thunderbolt.c index c4c5da6154da..32250b94262a 100644 --- a/drivers/usb/typec/altmodes/thunderbolt.c +++ b/drivers/usb/typec/altmodes/thunderbolt.c @@ -39,28 +39,7 @@ static bool tbt_ready(struct typec_altmode *alt); static int tbt_enter_mode(struct tbt_altmode *tbt) { - struct typec_altmode *plug = tbt->plug[TYPEC_PLUG_SOP_P]; - u32 vdo; - - vdo = tbt->alt->vdo & (TBT_VENDOR_SPECIFIC_B0 | TBT_VENDOR_SPECIFIC_B1); - vdo |= tbt->alt->vdo & TBT_INTEL_SPECIFIC_B0; - vdo |= TBT_MODE; - - if (plug) { - if (typec_cable_is_active(tbt->cable)) - vdo |= TBT_ENTER_MODE_ACTIVE_CABLE; - - vdo |= TBT_ENTER_MODE_CABLE_SPEED(TBT_CABLE_SPEED(plug->vdo)); - vdo |= plug->vdo & TBT_CABLE_ROUNDED; - vdo |= plug->vdo & TBT_CABLE_OPTICAL; - vdo |= plug->vdo & TBT_CABLE_RETIMER; - vdo |= plug->vdo & TBT_CABLE_LINK_TRAINING; - } else { - vdo |= TBT_ENTER_MODE_CABLE_SPEED(TBT_CABLE_USB3_PASSIVE); - } - - tbt->enter_vdo = vdo; - return typec_altmode_enter(tbt->alt, &vdo); + return typec_altmode_enter(tbt->alt, &tbt->enter_vdo); } static void tbt_altmode_work(struct work_struct *work) @@ -337,6 +316,7 @@ static bool tbt_ready(struct typec_altmode *alt) { struct tbt_altmode *tbt = typec_altmode_get_drvdata(alt); struct typec_altmode *plug; + u32 vdo; if (tbt->cable) return true; @@ -364,6 +344,26 @@ static bool tbt_ready(struct typec_altmode *alt) tbt->plug[i] = plug; } + vdo = tbt->alt->vdo & (TBT_VENDOR_SPECIFIC_B0 | TBT_VENDOR_SPECIFIC_B1); + vdo |= tbt->alt->vdo & TBT_INTEL_SPECIFIC_B0; + vdo |= TBT_MODE; + plug = tbt->plug[TYPEC_PLUG_SOP_P]; + + if (plug) { + if (typec_cable_is_active(tbt->cable)) + vdo |= TBT_ENTER_MODE_ACTIVE_CABLE; + + vdo |= TBT_ENTER_MODE_CABLE_SPEED(TBT_CABLE_SPEED(plug->vdo)); + vdo |= plug->vdo & TBT_CABLE_ROUNDED; + vdo |= plug->vdo & TBT_CABLE_OPTICAL; + vdo |= plug->vdo & TBT_CABLE_RETIMER; + vdo |= plug->vdo & TBT_CABLE_LINK_TRAINING; + } else { + vdo |= TBT_ENTER_MODE_CABLE_SPEED(TBT_CABLE_USB3_PASSIVE); + } + + tbt->enter_vdo = vdo; + return true; } diff --git a/drivers/usb/typec/class.c b/drivers/usb/typec/class.c index 831430909471..0977581ad1b6 100644 --- a/drivers/usb/typec/class.c +++ b/drivers/usb/typec/class.c @@ -686,10 +686,6 @@ typec_register_altmode(struct device *parent, alt->adev.dev.bus = &typec_bus; - /* Plug alt modes need a class to generate udev events. */ - if (is_typec_plug(parent)) - alt->adev.dev.class = &typec_class; - ret = device_register(&alt->adev.dev); if (ret) { dev_err(parent, "failed to register alternate mode (%d)\n", diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c index f38a4d7ebc42..8333bdaf5566 100644 --- a/drivers/usb/typec/ucsi/ucsi.c +++ b/drivers/usb/typec/ucsi/ucsi.c @@ -43,8 +43,13 @@ void ucsi_notify_common(struct ucsi *ucsi, u32 cci) if (cci & UCSI_CCI_BUSY) return; - if (UCSI_CCI_CONNECTOR(cci)) - ucsi_connector_change(ucsi, UCSI_CCI_CONNECTOR(cci)); + if (UCSI_CCI_CONNECTOR(cci)) { + if (UCSI_CCI_CONNECTOR(cci) <= ucsi->cap.num_connectors) + ucsi_connector_change(ucsi, UCSI_CCI_CONNECTOR(cci)); + else + dev_err(ucsi->dev, "bogus connector number in CCI: %lu\n", + UCSI_CCI_CONNECTOR(cci)); + } if (cci & UCSI_CCI_ACK_COMPLETE && test_and_clear_bit(ACK_PENDING, &ucsi->flags)) diff --git a/drivers/vfio/pci/vfio_pci_dmabuf.c b/drivers/vfio/pci/vfio_pci_dmabuf.c index 478beafc6ac3..b1d658b8f7b5 100644 --- a/drivers/vfio/pci/vfio_pci_dmabuf.c +++ b/drivers/vfio/pci/vfio_pci_dmabuf.c @@ -301,11 +301,10 @@ int vfio_pci_core_feature_dma_buf(struct vfio_pci_core_device *vdev, u32 flags, */ ret = dma_buf_fd(priv->dmabuf, get_dma_buf.open_flags); if (ret < 0) - goto err_dma_buf; + dma_buf_put(priv->dmabuf); + return ret; -err_dma_buf: - dma_buf_put(priv->dmabuf); err_dev_put: vfio_device_put_registration(&vdev->vdev); err_free_phys: diff --git a/drivers/virt/coco/tdx-guest/tdx-guest.c b/drivers/virt/coco/tdx-guest/tdx-guest.c index 4252b147593a..7cee97559ba2 100644 --- a/drivers/virt/coco/tdx-guest/tdx-guest.c +++ b/drivers/virt/coco/tdx-guest/tdx-guest.c @@ -171,6 +171,8 @@ static void tdx_mr_deinit(const struct attribute_group *mr_grp) #define GET_QUOTE_SUCCESS 0 #define GET_QUOTE_IN_FLIGHT 0xffffffffffffffff +#define TDX_QUOTE_MAX_LEN (GET_QUOTE_BUF_SIZE - sizeof(struct tdx_quote_buf)) + /* struct tdx_quote_buf: Format of Quote request buffer. * @version: Quote format version, filled by TD. * @status: Status code of Quote request, filled by VMM. @@ -269,6 +271,7 @@ static int tdx_report_new_locked(struct tsm_report *report, void *data) u8 *buf; struct tdx_quote_buf *quote_buf = quote_data; struct tsm_report_desc *desc = &report->desc; + u32 out_len; int ret; u64 err; @@ -306,12 +309,17 @@ static int tdx_report_new_locked(struct tsm_report *report, void *data) return ret; } - buf = kvmemdup(quote_buf->data, quote_buf->out_len, GFP_KERNEL); + out_len = READ_ONCE(quote_buf->out_len); + + if (out_len > TDX_QUOTE_MAX_LEN) + return -EFBIG; + + buf = kvmemdup(quote_buf->data, out_len, GFP_KERNEL); if (!buf) return -ENOMEM; report->outblob = buf; - report->outblob_len = quote_buf->out_len; + report->outblob_len = out_len; /* * TODO: parse the PEM-formatted cert chain out of the quote buffer when diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c index 335692d41617..fbca7ce1c6bf 100644 --- a/drivers/virtio/virtio_ring.c +++ b/drivers/virtio/virtio_ring.c @@ -2912,10 +2912,10 @@ EXPORT_SYMBOL_GPL(virtqueue_add_inbuf); * @data: the token identifying the buffer. * @gfp: how to do memory allocations (if necessary). * - * Same as virtqueue_add_inbuf but passes DMA_ATTR_CPU_CACHE_CLEAN to indicate - * that the CPU will not dirty any cacheline overlapping this buffer while it - * is available, and to suppress overlapping cacheline warnings in DMA debug - * builds. + * Same as virtqueue_add_inbuf but passes DMA_ATTR_DEBUGGING_IGNORE_CACHELINES + * to indicate that the CPU will not dirty any cacheline overlapping this buffer + * while it is available, and to suppress overlapping cacheline warnings in DMA + * debug builds. * * Caller must ensure we don't call this with other virtqueue operations * at the same time (except where noted). @@ -2928,7 +2928,7 @@ int virtqueue_add_inbuf_cache_clean(struct virtqueue *vq, gfp_t gfp) { return virtqueue_add(vq, &sg, num, 0, 1, data, NULL, false, gfp, - DMA_ATTR_CPU_CACHE_CLEAN); + DMA_ATTR_DEBUGGING_IGNORE_CACHELINES); } EXPORT_SYMBOL_GPL(virtqueue_add_inbuf_cache_clean); diff --git a/drivers/xen/privcmd.c b/drivers/xen/privcmd.c index 1759cc18753f..15ba592236e8 100644 --- a/drivers/xen/privcmd.c +++ b/drivers/xen/privcmd.c @@ -12,6 +12,7 @@ #include <linux/eventfd.h> #include <linux/file.h> #include <linux/kernel.h> +#include <linux/kstrtox.h> #include <linux/module.h> #include <linux/mutex.h> #include <linux/poll.h> @@ -30,7 +31,10 @@ #include <linux/seq_file.h> #include <linux/miscdevice.h> #include <linux/moduleparam.h> +#include <linux/notifier.h> +#include <linux/security.h> #include <linux/virtio_mmio.h> +#include <linux/wait.h> #include <asm/xen/hypervisor.h> #include <asm/xen/hypercall.h> @@ -46,6 +50,7 @@ #include <xen/page.h> #include <xen/xen-ops.h> #include <xen/balloon.h> +#include <xen/xenbus.h> #ifdef CONFIG_XEN_ACPI #include <xen/acpi.h> #endif @@ -68,10 +73,20 @@ module_param_named(dm_op_buf_max_size, privcmd_dm_op_buf_max_size, uint, MODULE_PARM_DESC(dm_op_buf_max_size, "Maximum size of a dm_op hypercall buffer"); +static bool unrestricted; +module_param(unrestricted, bool, 0); +MODULE_PARM_DESC(unrestricted, + "Don't restrict hypercalls to target domain if running in a domU"); + struct privcmd_data { domid_t domid; }; +/* DOMID_INVALID implies no restriction */ +static domid_t target_domain = DOMID_INVALID; +static bool restrict_wait; +static DECLARE_WAIT_QUEUE_HEAD(restrict_wait_wq); + static int privcmd_vma_range_is_mapped( struct vm_area_struct *vma, unsigned long addr, @@ -1563,13 +1578,16 @@ static long privcmd_ioctl(struct file *file, static int privcmd_open(struct inode *ino, struct file *file) { - struct privcmd_data *data = kzalloc_obj(*data); + struct privcmd_data *data; + if (wait_event_interruptible(restrict_wait_wq, !restrict_wait) < 0) + return -EINTR; + + data = kzalloc_obj(*data); if (!data) return -ENOMEM; - /* DOMID_INVALID implies no restriction */ - data->domid = DOMID_INVALID; + data->domid = target_domain; file->private_data = data; return 0; @@ -1662,6 +1680,52 @@ static struct miscdevice privcmd_dev = { .fops = &xen_privcmd_fops, }; +static int init_restrict(struct notifier_block *notifier, + unsigned long event, + void *data) +{ + char *target; + unsigned int domid; + + /* Default to an guaranteed unused domain-id. */ + target_domain = DOMID_IDLE; + + target = xenbus_read(XBT_NIL, "target", "", NULL); + if (IS_ERR(target) || kstrtouint(target, 10, &domid)) { + pr_err("No target domain found, blocking all hypercalls\n"); + goto out; + } + + target_domain = domid; + + out: + if (!IS_ERR(target)) + kfree(target); + + restrict_wait = false; + wake_up_all(&restrict_wait_wq); + + return NOTIFY_DONE; +} + +static struct notifier_block xenstore_notifier = { + .notifier_call = init_restrict, +}; + +static void __init restrict_driver(void) +{ + if (unrestricted) { + if (security_locked_down(LOCKDOWN_XEN_USER_ACTIONS)) + pr_warn("Kernel is locked down, parameter \"unrestricted\" ignored\n"); + else + return; + } + + restrict_wait = true; + + register_xenstore_notifier(&xenstore_notifier); +} + static int __init privcmd_init(void) { int err; @@ -1669,6 +1733,9 @@ static int __init privcmd_init(void) if (!xen_domain()) return -ENODEV; + if (!xen_initial_domain()) + restrict_driver(); + err = misc_register(&privcmd_dev); if (err != 0) { pr_err("Could not register Xen privcmd device\n"); @@ -1698,6 +1765,9 @@ err_privcmdbuf: static void __exit privcmd_exit(void) { + if (!xen_initial_domain()) + unregister_xenstore_notifier(&xenstore_notifier); + privcmd_ioeventfd_exit(); privcmd_irqfd_exit(); misc_deregister(&privcmd_dev); |
