diff options
Diffstat (limited to 'drivers')
478 files changed, 6683 insertions, 2390 deletions
diff --git a/drivers/Makefile b/drivers/Makefile index cb0afca2e4a0..1bec7819a837 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -46,7 +46,7 @@ obj-$(CONFIG_DMADEVICES) += dma/ # SOC specific infrastructure drivers. obj-y += soc/ -obj-$(CONFIG_PM_GENERIC_DOMAINS) += genpd/ +obj-$(CONFIG_PM_GENERIC_DOMAINS) += pmdomain/ obj-y += virtio/ obj-$(CONFIG_VDPA) += vdpa/ diff --git a/drivers/accel/ivpu/ivpu_drv.c b/drivers/accel/ivpu/ivpu_drv.c index ba79f397c9e8..467a60235370 100644 --- a/drivers/accel/ivpu/ivpu_drv.c +++ b/drivers/accel/ivpu/ivpu_drv.c @@ -327,7 +327,7 @@ static int ivpu_wait_for_ready(struct ivpu_device *vdev) } if (!ret) - ivpu_info(vdev, "VPU ready message received successfully\n"); + ivpu_dbg(vdev, PM, "VPU ready message received successfully\n"); else ivpu_hw_diagnose_failure(vdev); @@ -634,6 +634,7 @@ static void ivpu_dev_fini(struct ivpu_device *vdev) static struct pci_device_id ivpu_pci_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_MTL) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_ARL) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_LNL) }, { } }; diff --git a/drivers/accel/ivpu/ivpu_drv.h b/drivers/accel/ivpu/ivpu_drv.h index 9e8c075fe9ef..03b3d6532fb6 100644 --- a/drivers/accel/ivpu/ivpu_drv.h +++ b/drivers/accel/ivpu/ivpu_drv.h @@ -23,6 +23,7 @@ #define DRIVER_DATE "20230117" #define PCI_DEVICE_ID_MTL 0x7d1d +#define PCI_DEVICE_ID_ARL 0xad1d #define PCI_DEVICE_ID_LNL 0x643e #define IVPU_HW_37XX 37 @@ -165,6 +166,7 @@ static inline int ivpu_hw_gen(struct ivpu_device *vdev) { switch (ivpu_device_id(vdev)) { case PCI_DEVICE_ID_MTL: + case PCI_DEVICE_ID_ARL: return IVPU_HW_37XX; case PCI_DEVICE_ID_LNL: return IVPU_HW_40XX; diff --git a/drivers/accel/ivpu/ivpu_fw.c b/drivers/accel/ivpu/ivpu_fw.c index 9827ea4d7b83..0191cf8e5964 100644 --- a/drivers/accel/ivpu/ivpu_fw.c +++ b/drivers/accel/ivpu/ivpu_fw.c @@ -220,7 +220,8 @@ static int ivpu_fw_mem_init(struct ivpu_device *vdev) if (ret) return ret; - fw->mem = ivpu_bo_alloc_internal(vdev, fw->runtime_addr, fw->runtime_size, DRM_IVPU_BO_WC); + fw->mem = ivpu_bo_alloc_internal(vdev, fw->runtime_addr, fw->runtime_size, + DRM_IVPU_BO_CACHED | DRM_IVPU_BO_NOSNOOP); if (!fw->mem) { ivpu_err(vdev, "Failed to allocate firmware runtime memory\n"); return -ENOMEM; @@ -330,7 +331,7 @@ int ivpu_fw_load(struct ivpu_device *vdev) memset(start, 0, size); } - wmb(); /* Flush WC buffers after writing fw->mem */ + clflush_cache_range(fw->mem->kvaddr, fw->mem->base.size); return 0; } @@ -432,6 +433,7 @@ void ivpu_fw_boot_params_setup(struct ivpu_device *vdev, struct vpu_boot_params if (!ivpu_fw_is_cold_boot(vdev)) { boot_params->save_restore_ret_address = 0; vdev->pm->is_warmboot = true; + clflush_cache_range(vdev->fw->mem->kvaddr, SZ_4K); return; } @@ -493,7 +495,7 @@ void ivpu_fw_boot_params_setup(struct ivpu_device *vdev, struct vpu_boot_params boot_params->punit_telemetry_sram_size = ivpu_hw_reg_telemetry_size_get(vdev); boot_params->vpu_telemetry_enable = ivpu_hw_reg_telemetry_enable_get(vdev); - wmb(); /* Flush WC buffers after writing bootparams */ + clflush_cache_range(vdev->fw->mem->kvaddr, SZ_4K); ivpu_fw_boot_params_print(vdev, boot_params); } diff --git a/drivers/accel/ivpu/ivpu_gem.h b/drivers/accel/ivpu/ivpu_gem.h index 6b0ceda5f253..f4130586ff1b 100644 --- a/drivers/accel/ivpu/ivpu_gem.h +++ b/drivers/accel/ivpu/ivpu_gem.h @@ -8,6 +8,8 @@ #include <drm/drm_gem.h> #include <drm/drm_mm.h> +#define DRM_IVPU_BO_NOSNOOP 0x10000000 + struct dma_buf; struct ivpu_bo_ops; struct ivpu_file_priv; @@ -83,6 +85,9 @@ static inline u32 ivpu_bo_cache_mode(struct ivpu_bo *bo) static inline bool ivpu_bo_is_snooped(struct ivpu_bo *bo) { + if (bo->flags & DRM_IVPU_BO_NOSNOOP) + return false; + return ivpu_bo_cache_mode(bo) == DRM_IVPU_BO_CACHED; } diff --git a/drivers/accel/ivpu/ivpu_hw_40xx.c b/drivers/accel/ivpu/ivpu_hw_40xx.c index 34626d66fa10..8bdb59a45da6 100644 --- a/drivers/accel/ivpu/ivpu_hw_40xx.c +++ b/drivers/accel/ivpu/ivpu_hw_40xx.c @@ -57,8 +57,7 @@ #define ICB_0_1_IRQ_MASK ((((u64)ICB_1_IRQ_MASK) << 32) | ICB_0_IRQ_MASK) -#define BUTTRESS_IRQ_MASK ((REG_FLD(VPU_40XX_BUTTRESS_INTERRUPT_STAT, FREQ_CHANGE)) | \ - (REG_FLD(VPU_40XX_BUTTRESS_INTERRUPT_STAT, ATS_ERR)) | \ +#define BUTTRESS_IRQ_MASK ((REG_FLD(VPU_40XX_BUTTRESS_INTERRUPT_STAT, ATS_ERR)) | \ (REG_FLD(VPU_40XX_BUTTRESS_INTERRUPT_STAT, CFI0_ERR)) | \ (REG_FLD(VPU_40XX_BUTTRESS_INTERRUPT_STAT, CFI1_ERR)) | \ (REG_FLD(VPU_40XX_BUTTRESS_INTERRUPT_STAT, IMR0_ERR)) | \ @@ -196,6 +195,14 @@ static int ivpu_pll_wait_for_status_ready(struct ivpu_device *vdev) return REGB_POLL_FLD(VPU_40XX_BUTTRESS_VPU_STATUS, READY, 1, PLL_TIMEOUT_US); } +static int ivpu_wait_for_clock_own_resource_ack(struct ivpu_device *vdev) +{ + if (ivpu_is_simics(vdev)) + return 0; + + return REGB_POLL_FLD(VPU_40XX_BUTTRESS_VPU_STATUS, CLOCK_RESOURCE_OWN_ACK, 1, TIMEOUT_US); +} + static void ivpu_pll_init_frequency_ratios(struct ivpu_device *vdev) { struct ivpu_hw_info *hw = vdev->hw; @@ -556,6 +563,12 @@ static int ivpu_boot_pwr_domain_enable(struct ivpu_device *vdev) { int ret; + ret = ivpu_wait_for_clock_own_resource_ack(vdev); + if (ret) { + ivpu_err(vdev, "Timed out waiting for clock own resource ACK\n"); + return ret; + } + ivpu_boot_pwr_island_trickle_drive(vdev, true); ivpu_boot_pwr_island_drive(vdev, true); @@ -1046,8 +1059,6 @@ static irqreturn_t ivpu_hw_40xx_irqb_handler(struct ivpu_device *vdev, int irq) if (status == 0) return IRQ_NONE; - REGB_WR32(VPU_40XX_BUTTRESS_INTERRUPT_STAT, status); - if (REG_TEST_FLD(VPU_40XX_BUTTRESS_INTERRUPT_STAT, FREQ_CHANGE, status)) ivpu_dbg(vdev, IRQ, "FREQ_CHANGE"); @@ -1092,6 +1103,9 @@ static irqreturn_t ivpu_hw_40xx_irqb_handler(struct ivpu_device *vdev, int irq) schedule_recovery = true; } + /* This must be done after interrupts are cleared at the source. */ + REGB_WR32(VPU_40XX_BUTTRESS_INTERRUPT_STAT, status); + if (schedule_recovery) ivpu_pm_schedule_recovery(vdev); @@ -1103,9 +1117,14 @@ static irqreturn_t ivpu_hw_40xx_irq_handler(int irq, void *ptr) struct ivpu_device *vdev = ptr; irqreturn_t ret = IRQ_NONE; + REGB_WR32(VPU_40XX_BUTTRESS_GLOBAL_INT_MASK, 0x1); + ret |= ivpu_hw_40xx_irqv_handler(vdev, irq); ret |= ivpu_hw_40xx_irqb_handler(vdev, irq); + /* Re-enable global interrupts to re-trigger MSI for pending interrupts */ + REGB_WR32(VPU_40XX_BUTTRESS_GLOBAL_INT_MASK, 0x0); + if (ret & IRQ_WAKE_THREAD) return IRQ_WAKE_THREAD; diff --git a/drivers/accel/ivpu/ivpu_hw_40xx_reg.h b/drivers/accel/ivpu/ivpu_hw_40xx_reg.h index 5139cfe88532..ff4a5d4f5821 100644 --- a/drivers/accel/ivpu/ivpu_hw_40xx_reg.h +++ b/drivers/accel/ivpu/ivpu_hw_40xx_reg.h @@ -70,6 +70,8 @@ #define VPU_40XX_BUTTRESS_VPU_STATUS_READY_MASK BIT_MASK(0) #define VPU_40XX_BUTTRESS_VPU_STATUS_IDLE_MASK BIT_MASK(1) #define VPU_40XX_BUTTRESS_VPU_STATUS_DUP_IDLE_MASK BIT_MASK(2) +#define VPU_40XX_BUTTRESS_VPU_STATUS_CLOCK_RESOURCE_OWN_ACK_MASK BIT_MASK(6) +#define VPU_40XX_BUTTRESS_VPU_STATUS_POWER_RESOURCE_OWN_ACK_MASK BIT_MASK(7) #define VPU_40XX_BUTTRESS_VPU_STATUS_PERF_CLK_MASK BIT_MASK(11) #define VPU_40XX_BUTTRESS_VPU_STATUS_DISABLE_CLK_RELINQUISH_MASK BIT_MASK(12) diff --git a/drivers/accel/ivpu/ivpu_ipc.c b/drivers/accel/ivpu/ivpu_ipc.c index fa0af59e39ab..295c0d7b5039 100644 --- a/drivers/accel/ivpu/ivpu_ipc.c +++ b/drivers/accel/ivpu/ivpu_ipc.c @@ -209,10 +209,10 @@ int ivpu_ipc_receive(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons, struct ivpu_ipc_rx_msg *rx_msg; int wait_ret, ret = 0; - wait_ret = wait_event_interruptible_timeout(cons->rx_msg_wq, - (IS_KTHREAD() && kthread_should_stop()) || - !list_empty(&cons->rx_msg_list), - msecs_to_jiffies(timeout_ms)); + wait_ret = wait_event_timeout(cons->rx_msg_wq, + (IS_KTHREAD() && kthread_should_stop()) || + !list_empty(&cons->rx_msg_list), + msecs_to_jiffies(timeout_ms)); if (IS_KTHREAD() && kthread_should_stop()) return -EINTR; @@ -220,9 +220,6 @@ int ivpu_ipc_receive(struct ivpu_device *vdev, struct ivpu_ipc_consumer *cons, if (wait_ret == 0) return -ETIMEDOUT; - if (wait_ret < 0) - return -ERESTARTSYS; - spin_lock_irq(&cons->rx_msg_lock); rx_msg = list_first_entry_or_null(&cons->rx_msg_list, struct ivpu_ipc_rx_msg, link); if (!rx_msg) { diff --git a/drivers/acpi/acpi_video.c b/drivers/acpi/acpi_video.c index 948e31f7ce6e..b411948594ff 100644 --- a/drivers/acpi/acpi_video.c +++ b/drivers/acpi/acpi_video.c @@ -2057,7 +2057,9 @@ static int acpi_video_bus_add(struct acpi_device *device) !auto_detect) acpi_video_bus_register_backlight(video); - acpi_video_bus_add_notify_handler(video); + error = acpi_video_bus_add_notify_handler(video); + if (error) + goto err_del; error = acpi_dev_install_notify_handler(device, ACPI_DEVICE_NOTIFY, acpi_video_bus_notify); @@ -2067,10 +2069,11 @@ static int acpi_video_bus_add(struct acpi_device *device) return 0; err_remove: + acpi_video_bus_remove_notify_handler(video); +err_del: mutex_lock(&video_list_lock); list_del(&video->entry); mutex_unlock(&video_list_lock); - acpi_video_bus_remove_notify_handler(video); acpi_video_bus_unregister_backlight(video); err_put_video: acpi_video_bus_put_devices(video); diff --git a/drivers/acpi/processor_pdc.c b/drivers/acpi/processor_pdc.c index 1a8591e9a9bf..994091bd52de 100644 --- a/drivers/acpi/processor_pdc.c +++ b/drivers/acpi/processor_pdc.c @@ -19,6 +19,7 @@ static void acpi_set_pdc_bits(u32 *buf) { buf[0] = ACPI_PDC_REVISION_ID; buf[1] = 1; + buf[2] = 0; /* Twiddle arch-specific bits needed for _PDC */ arch_acpi_set_proc_cap_bits(&buf[2]); diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index f14e68266ccd..312730f8272e 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -492,7 +492,7 @@ static int thermal_get_temp(struct thermal_zone_device *thermal, int *temp) } static int thermal_get_trend(struct thermal_zone_device *thermal, - struct thermal_trip *trip, + const struct thermal_trip *trip, enum thermal_trend *trend) { struct acpi_thermal *tz = thermal_zone_device_priv(thermal); diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index abb5911c9d09..08745e7db820 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -1883,6 +1883,15 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) else dev_info(&pdev->dev, "SSS flag set, parallel bus scan disabled\n"); + if (!(hpriv->cap & HOST_CAP_PART)) + host->flags |= ATA_HOST_NO_PART; + + if (!(hpriv->cap & HOST_CAP_SSC)) + host->flags |= ATA_HOST_NO_SSC; + + if (!(hpriv->cap2 & HOST_CAP2_SDS)) + host->flags |= ATA_HOST_NO_DEVSLP; + if (pi.flags & ATA_FLAG_EM) ahci_reset_em(host); diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index e2bacedf28ef..f1263364fa97 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -1256,6 +1256,26 @@ static ssize_t ahci_activity_show(struct ata_device *dev, char *buf) return sprintf(buf, "%d\n", emp->blink_policy); } +static void ahci_port_clear_pending_irq(struct ata_port *ap) +{ + struct ahci_host_priv *hpriv = ap->host->private_data; + void __iomem *port_mmio = ahci_port_base(ap); + u32 tmp; + + /* clear SError */ + tmp = readl(port_mmio + PORT_SCR_ERR); + dev_dbg(ap->host->dev, "PORT_SCR_ERR 0x%x\n", tmp); + writel(tmp, port_mmio + PORT_SCR_ERR); + + /* clear port IRQ */ + tmp = readl(port_mmio + PORT_IRQ_STAT); + dev_dbg(ap->host->dev, "PORT_IRQ_STAT 0x%x\n", tmp); + if (tmp) + writel(tmp, port_mmio + PORT_IRQ_STAT); + + writel(1 << ap->port_no, hpriv->mmio + HOST_IRQ_STAT); +} + static void ahci_port_init(struct device *dev, struct ata_port *ap, int port_no, void __iomem *mmio, void __iomem *port_mmio) @@ -1270,18 +1290,7 @@ static void ahci_port_init(struct device *dev, struct ata_port *ap, if (rc) dev_warn(dev, "%s (%d)\n", emsg, rc); - /* clear SError */ - tmp = readl(port_mmio + PORT_SCR_ERR); - dev_dbg(dev, "PORT_SCR_ERR 0x%x\n", tmp); - writel(tmp, port_mmio + PORT_SCR_ERR); - - /* clear port IRQ */ - tmp = readl(port_mmio + PORT_IRQ_STAT); - dev_dbg(dev, "PORT_IRQ_STAT 0x%x\n", tmp); - if (tmp) - writel(tmp, port_mmio + PORT_IRQ_STAT); - - writel(1 << port_no, mmio + HOST_IRQ_STAT); + ahci_port_clear_pending_irq(ap); /* mark esata ports */ tmp = readl(port_mmio + PORT_CMD); @@ -1603,6 +1612,8 @@ int ahci_do_hardreset(struct ata_link *link, unsigned int *class, tf.status = ATA_BUSY; ata_tf_to_fis(&tf, 0, 0, d2h_fis); + ahci_port_clear_pending_irq(ap); + rc = sata_link_hardreset(link, timing, deadline, online, ahci_check_ready); diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 74314311295f..d8cc1e27a125 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -1973,6 +1973,96 @@ retry: } /** + * ata_dev_power_set_standby - Set a device power mode to standby + * @dev: target device + * + * Issue a STANDBY IMMEDIATE command to set a device power mode to standby. + * For an HDD device, this spins down the disks. + * + * LOCKING: + * Kernel thread context (may sleep). + */ +void ata_dev_power_set_standby(struct ata_device *dev) +{ + unsigned long ap_flags = dev->link->ap->flags; + struct ata_taskfile tf; + unsigned int err_mask; + + /* Issue STANDBY IMMEDIATE command only if supported by the device */ + if (dev->class != ATA_DEV_ATA && dev->class != ATA_DEV_ZAC) + return; + + /* + * Some odd clown BIOSes issue spindown on power off (ACPI S4 or S5) + * causing some drives to spin up and down again. For these, do nothing + * if we are being called on shutdown. + */ + if ((ap_flags & ATA_FLAG_NO_POWEROFF_SPINDOWN) && + system_state == SYSTEM_POWER_OFF) + return; + + if ((ap_flags & ATA_FLAG_NO_HIBERNATE_SPINDOWN) && + system_entering_hibernation()) + return; + + ata_tf_init(dev, &tf); + tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR; + tf.protocol = ATA_PROT_NODATA; + tf.command = ATA_CMD_STANDBYNOW1; + + ata_dev_notice(dev, "Entering standby power mode\n"); + + err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0); + if (err_mask) + ata_dev_err(dev, "STANDBY IMMEDIATE failed (err_mask=0x%x)\n", + err_mask); +} + +/** + * ata_dev_power_set_active - Set a device power mode to active + * @dev: target device + * + * Issue a VERIFY command to enter to ensure that the device is in the + * active power mode. For a spun-down HDD (standby or idle power mode), + * the VERIFY command will complete after the disk spins up. + * + * LOCKING: + * Kernel thread context (may sleep). + */ +void ata_dev_power_set_active(struct ata_device *dev) +{ + struct ata_taskfile tf; + unsigned int err_mask; + + /* + * Issue READ VERIFY SECTORS command for 1 sector at lba=0 only + * if supported by the device. + */ + if (dev->class != ATA_DEV_ATA && dev->class != ATA_DEV_ZAC) + return; + + ata_tf_init(dev, &tf); + tf.flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR; + tf.protocol = ATA_PROT_NODATA; + tf.command = ATA_CMD_VERIFY; + tf.nsect = 1; + if (dev->flags & ATA_DFLAG_LBA) { + tf.flags |= ATA_TFLAG_LBA; + tf.device |= ATA_LBA; + } else { + /* CHS */ + tf.lbal = 0x1; /* sect */ + } + + ata_dev_notice(dev, "Entering active power mode\n"); + + err_mask = ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0); + if (err_mask) + ata_dev_err(dev, "VERIFY failed (err_mask=0x%x)\n", + err_mask); +} + +/** * ata_read_log_page - read a specific log page * @dev: target device * @log: log to read @@ -2529,7 +2619,7 @@ static int ata_dev_config_lba(struct ata_device *dev) { const u16 *id = dev->id; const char *lba_desc; - char ncq_desc[24]; + char ncq_desc[32]; int ret; dev->flags |= ATA_DFLAG_LBA; @@ -4783,11 +4873,8 @@ void ata_qc_complete(struct ata_queued_cmd *qc) * been aborted by the device due to a limit timeout using the policy * 0xD. For these commands, invoke EH to get the command sense data. */ - if (qc->result_tf.status & ATA_SENSE && - ((ata_is_ncq(qc->tf.protocol) && - dev->flags & ATA_DFLAG_CDL_ENABLED) || - (!ata_is_ncq(qc->tf.protocol) && - ata_id_sense_reporting_enabled(dev->id)))) { + if (qc->flags & ATA_QCFLAG_HAS_CDL && + qc->result_tf.status & ATA_SENSE) { /* * Tell SCSI EH to not overwrite scmd->result even if this * command is finished with result SAM_STAT_GOOD. @@ -5040,17 +5127,19 @@ static void ata_port_request_pm(struct ata_port *ap, pm_message_t mesg, struct ata_link *link; unsigned long flags; - /* Previous resume operation might still be in - * progress. Wait for PM_PENDING to clear. + spin_lock_irqsave(ap->lock, flags); + + /* + * A previous PM operation might still be in progress. Wait for + * ATA_PFLAG_PM_PENDING to clear. */ if (ap->pflags & ATA_PFLAG_PM_PENDING) { + spin_unlock_irqrestore(ap->lock, flags); ata_port_wait_eh(ap); - WARN_ON(ap->pflags & ATA_PFLAG_PM_PENDING); + spin_lock_irqsave(ap->lock, flags); } - /* request PM ops to EH */ - spin_lock_irqsave(ap->lock, flags); - + /* Request PM operation to EH */ ap->pm_mesg = mesg; ap->pflags |= ATA_PFLAG_PM_PENDING; ata_for_each_link(link, ap, HOST_FIRST) { @@ -5062,10 +5151,8 @@ static void ata_port_request_pm(struct ata_port *ap, pm_message_t mesg, spin_unlock_irqrestore(ap->lock, flags); - if (!async) { + if (!async) ata_port_wait_eh(ap); - WARN_ON(ap->pflags & ATA_PFLAG_PM_PENDING); - } } /* @@ -5081,11 +5168,27 @@ static const unsigned int ata_port_suspend_ehi = ATA_EHI_QUIET static void ata_port_suspend(struct ata_port *ap, pm_message_t mesg) { + /* + * We are about to suspend the port, so we do not care about + * scsi_rescan_device() calls scheduled by previous resume operations. + * The next resume will schedule the rescan again. So cancel any rescan + * that is not done yet. + */ + cancel_delayed_work_sync(&ap->scsi_rescan_task); + ata_port_request_pm(ap, mesg, 0, ata_port_suspend_ehi, false); } static void ata_port_suspend_async(struct ata_port *ap, pm_message_t mesg) { + /* + * We are about to suspend the port, so we do not care about + * scsi_rescan_device() calls scheduled by previous resume operations. + * The next resume will schedule the rescan again. So cancel any rescan + * that is not done yet. + */ + cancel_delayed_work_sync(&ap->scsi_rescan_task); + ata_port_request_pm(ap, mesg, 0, ata_port_suspend_ehi, true); } @@ -5232,7 +5335,7 @@ EXPORT_SYMBOL_GPL(ata_host_resume); #endif const struct device_type ata_port_type = { - .name = "ata_port", + .name = ATA_PORT_TYPE_NAME, #ifdef CONFIG_PM .pm = &ata_port_pm_ops, #endif @@ -5951,11 +6054,30 @@ static void ata_port_detach(struct ata_port *ap) struct ata_link *link; struct ata_device *dev; - /* tell EH we're leaving & flush EH */ + /* Wait for any ongoing EH */ + ata_port_wait_eh(ap); + + mutex_lock(&ap->scsi_scan_mutex); spin_lock_irqsave(ap->lock, flags); + + /* Remove scsi devices */ + ata_for_each_link(link, ap, HOST_FIRST) { + ata_for_each_dev(dev, link, ALL) { + if (dev->sdev) { + spin_unlock_irqrestore(ap->lock, flags); + scsi_remove_device(dev->sdev); + spin_lock_irqsave(ap->lock, flags); + dev->sdev = NULL; + } + } + } + + /* Tell EH to disable all devices */ ap->pflags |= ATA_PFLAG_UNLOADING; ata_port_schedule_eh(ap); + spin_unlock_irqrestore(ap->lock, flags); + mutex_unlock(&ap->scsi_scan_mutex); /* wait till EH commits suicide */ ata_port_wait_eh(ap); diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 159ba6ba19eb..5686353e442c 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -147,6 +147,8 @@ ata_eh_cmd_timeout_table[ATA_EH_CMD_TIMEOUT_TABLE_SIZE] = { .timeouts = ata_eh_other_timeouts, }, { .commands = CMDS(ATA_CMD_FLUSH, ATA_CMD_FLUSH_EXT), .timeouts = ata_eh_flush_timeouts }, + { .commands = CMDS(ATA_CMD_VERIFY), + .timeouts = ata_eh_reset_timeouts }, }; #undef CMDS @@ -498,7 +500,19 @@ static void ata_eh_unload(struct ata_port *ap) struct ata_device *dev; unsigned long flags; - /* Restore SControl IPM and SPD for the next driver and + /* + * Unless we are restarting, transition all enabled devices to + * standby power mode. + */ + if (system_state != SYSTEM_RESTART) { + ata_for_each_link(link, ap, PMP_FIRST) { + ata_for_each_dev(dev, link, ENABLED) + ata_dev_power_set_standby(dev); + } + } + + /* + * Restore SControl IPM and SPD for the next driver and * disable attached devices. */ ata_for_each_link(link, ap, PMP_FIRST) { @@ -684,6 +698,10 @@ void ata_scsi_port_error_handler(struct Scsi_Host *host, struct ata_port *ap) ehc->saved_xfer_mode[devno] = dev->xfer_mode; if (ata_ncq_enabled(dev)) ehc->saved_ncq_enabled |= 1 << devno; + + /* If we are resuming, wake up the device */ + if (ap->pflags & ATA_PFLAG_RESUMING) + ehc->i.dev_action[devno] |= ATA_EH_SET_ACTIVE; } } @@ -743,6 +761,8 @@ void ata_scsi_port_error_handler(struct Scsi_Host *host, struct ata_port *ap) /* clean up */ spin_lock_irqsave(ap->lock, flags); + ap->pflags &= ~ATA_PFLAG_RESUMING; + if (ap->pflags & ATA_PFLAG_LOADING) ap->pflags &= ~ATA_PFLAG_LOADING; else if ((ap->pflags & ATA_PFLAG_SCSI_HOTPLUG) && @@ -1218,6 +1238,13 @@ void ata_eh_detach_dev(struct ata_device *dev) struct ata_eh_context *ehc = &link->eh_context; unsigned long flags; + /* + * If the device is still enabled, transition it to standby power mode + * (i.e. spin down HDDs). + */ + if (ata_dev_enabled(dev)) + ata_dev_power_set_standby(dev); + ata_dev_disable(dev); spin_lock_irqsave(ap->lock, flags); @@ -2305,7 +2332,7 @@ static void ata_eh_link_report(struct ata_link *link) struct ata_eh_context *ehc = &link->eh_context; struct ata_queued_cmd *qc; const char *frozen, *desc; - char tries_buf[6] = ""; + char tries_buf[16] = ""; int tag, nr_failed = 0; if (ehc->i.flags & ATA_EHI_QUIET) @@ -2796,23 +2823,13 @@ int ata_eh_reset(struct ata_link *link, int classify, } } - /* - * Some controllers can't be frozen very well and may set spurious - * error conditions during reset. Clear accumulated error - * information and re-thaw the port if frozen. As reset is the - * final recovery action and we cross check link onlineness against - * device classification later, no hotplug event is lost by this. - */ + /* clear cached SError */ spin_lock_irqsave(link->ap->lock, flags); - memset(&link->eh_info, 0, sizeof(link->eh_info)); + link->eh_info.serror = 0; if (slave) - memset(&slave->eh_info, 0, sizeof(link->eh_info)); - ap->pflags &= ~ATA_PFLAG_EH_PENDING; + slave->eh_info.serror = 0; spin_unlock_irqrestore(link->ap->lock, flags); - if (ata_port_is_frozen(ap)) - ata_eh_thaw_port(ap); - /* * Make sure onlineness and classification result correspond. * Hotplug could have happened during reset and some @@ -3026,6 +3043,15 @@ static int ata_eh_revalidate_and_attach(struct ata_link *link, if (ehc->i.flags & ATA_EHI_DID_RESET) readid_flags |= ATA_READID_POSTRESET; + /* + * When resuming, before executing any command, make sure to + * transition the device to the active power mode. + */ + if ((action & ATA_EH_SET_ACTIVE) && ata_dev_enabled(dev)) { + ata_dev_power_set_active(dev); + ata_eh_done(link, dev, ATA_EH_SET_ACTIVE); + } + if ((action & ATA_EH_REVALIDATE) && ata_dev_enabled(dev)) { WARN_ON(dev->class == ATA_DEV_PMP); @@ -3999,6 +4025,7 @@ static void ata_eh_handle_port_suspend(struct ata_port *ap) unsigned long flags; int rc = 0; struct ata_device *dev; + struct ata_link *link; /* are we suspending? */ spin_lock_irqsave(ap->lock, flags); @@ -4011,6 +4038,12 @@ static void ata_eh_handle_port_suspend(struct ata_port *ap) WARN_ON(ap->pflags & ATA_PFLAG_SUSPENDED); + /* Set all devices attached to the port in standby mode */ + ata_for_each_link(link, ap, HOST_FIRST) { + ata_for_each_dev(dev, link, ENABLED) + ata_dev_power_set_standby(dev); + } + /* * If we have a ZPODD attached, check its zero * power ready status before the port is frozen. @@ -4093,6 +4126,7 @@ static void ata_eh_handle_port_resume(struct ata_port *ap) /* update the flags */ spin_lock_irqsave(ap->lock, flags); ap->pflags &= ~(ATA_PFLAG_PM_PENDING | ATA_PFLAG_SUSPENDED); + ap->pflags |= ATA_PFLAG_RESUMING; spin_unlock_irqrestore(ap->lock, flags); } #endif /* CONFIG_PM */ diff --git a/drivers/ata/libata-sata.c b/drivers/ata/libata-sata.c index 5d31c08be013..a701e1538482 100644 --- a/drivers/ata/libata-sata.c +++ b/drivers/ata/libata-sata.c @@ -396,10 +396,23 @@ int sata_link_scr_lpm(struct ata_link *link, enum ata_lpm_policy policy, case ATA_LPM_MED_POWER_WITH_DIPM: case ATA_LPM_MIN_POWER_WITH_PARTIAL: case ATA_LPM_MIN_POWER: - if (ata_link_nr_enabled(link) > 0) - /* no restrictions on LPM transitions */ + if (ata_link_nr_enabled(link) > 0) { + /* assume no restrictions on LPM transitions */ scontrol &= ~(0x7 << 8); - else { + + /* + * If the controller does not support partial, slumber, + * or devsleep, then disallow these transitions. + */ + if (link->ap->host->flags & ATA_HOST_NO_PART) + scontrol |= (0x1 << 8); + + if (link->ap->host->flags & ATA_HOST_NO_SSC) + scontrol |= (0x2 << 8); + + if (link->ap->host->flags & ATA_HOST_NO_DEVSLP) + scontrol |= (0x4 << 8); + } else { /* empty port, power off */ scontrol &= ~0xf; scontrol |= (0x1 << 2); diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index d3f28b82c97b..a371b497035e 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -1050,14 +1050,13 @@ int ata_scsi_dev_config(struct scsi_device *sdev, struct ata_device *dev) } } else { sdev->sector_size = ata_id_logical_sector_size(dev->id); + /* - * Stop the drive on suspend but do not issue START STOP UNIT - * on resume as this is not necessary and may fail: the device - * will be woken up by ata_port_pm_resume() with a port reset - * and device revalidation. + * Ask the sd driver to issue START STOP UNIT on runtime suspend + * and resume only. For system level suspend/resume, devices + * power state is handled directly by libata EH. */ - sdev->manage_start_stop = 1; - sdev->no_start_on_resume = 1; + sdev->manage_runtime_start_stop = true; } /* @@ -1090,6 +1089,42 @@ int ata_scsi_dev_config(struct scsi_device *sdev, struct ata_device *dev) } /** + * ata_scsi_slave_alloc - Early setup of SCSI device + * @sdev: SCSI device to examine + * + * This is called from scsi_alloc_sdev() when the scsi device + * associated with an ATA device is scanned on a port. + * + * LOCKING: + * Defined by SCSI layer. We don't really care. + */ + +int ata_scsi_slave_alloc(struct scsi_device *sdev) +{ + struct ata_port *ap = ata_shost_to_port(sdev->host); + struct device_link *link; + + ata_scsi_sdev_config(sdev); + + /* + * Create a link from the ata_port device to the scsi device to ensure + * that PM does suspend/resume in the correct order: the scsi device is + * consumer (child) and the ata port the supplier (parent). + */ + link = device_link_add(&sdev->sdev_gendev, &ap->tdev, + DL_FLAG_STATELESS | + DL_FLAG_PM_RUNTIME | DL_FLAG_RPM_ACTIVE); + if (!link) { + ata_port_err(ap, "Failed to create link to scsi device %s\n", + dev_name(&sdev->sdev_gendev)); + return -ENODEV; + } + + return 0; +} +EXPORT_SYMBOL_GPL(ata_scsi_slave_alloc); + +/** * ata_scsi_slave_config - Set SCSI device attributes * @sdev: SCSI device to examine * @@ -1105,14 +1140,11 @@ int ata_scsi_slave_config(struct scsi_device *sdev) { struct ata_port *ap = ata_shost_to_port(sdev->host); struct ata_device *dev = __ata_scsi_find_dev(ap, sdev); - int rc = 0; - - ata_scsi_sdev_config(sdev); if (dev) - rc = ata_scsi_dev_config(sdev, dev); + return ata_scsi_dev_config(sdev, dev); - return rc; + return 0; } EXPORT_SYMBOL_GPL(ata_scsi_slave_config); @@ -1136,6 +1168,8 @@ void ata_scsi_slave_destroy(struct scsi_device *sdev) unsigned long flags; struct ata_device *dev; + device_link_remove(&sdev->sdev_gendev, &ap->tdev); + spin_lock_irqsave(ap->lock, flags); dev = __ata_scsi_find_dev(ap, sdev); if (dev && dev->sdev) { @@ -1195,7 +1229,7 @@ static unsigned int ata_scsi_start_stop_xlat(struct ata_queued_cmd *qc) } if (cdb[4] & 0x1) { - tf->nsect = 1; /* 1 sector, lba=0 */ + tf->nsect = 1; /* 1 sector, lba=0 */ if (qc->dev->flags & ATA_DFLAG_LBA) { tf->flags |= ATA_TFLAG_LBA; @@ -1211,7 +1245,7 @@ static unsigned int ata_scsi_start_stop_xlat(struct ata_queued_cmd *qc) tf->lbah = 0x0; /* cyl high */ } - tf->command = ATA_CMD_VERIFY; /* READ VERIFY */ + tf->command = ATA_CMD_VERIFY; /* READ VERIFY */ } else { /* Some odd clown BIOSen issue spindown on power off (ACPI S4 * or S5) causing some drives to spin up and down again. @@ -1221,7 +1255,7 @@ static unsigned int ata_scsi_start_stop_xlat(struct ata_queued_cmd *qc) goto skip; if ((qc->ap->flags & ATA_FLAG_NO_HIBERNATE_SPINDOWN) && - system_entering_hibernation()) + system_entering_hibernation()) goto skip; /* Issue ATA STANDBY IMMEDIATE command */ @@ -1835,6 +1869,9 @@ static unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf) hdr[2] = 0x7; /* claim SPC-5 version compatibility */ } + if (args->dev->flags & ATA_DFLAG_CDL) + hdr[2] = 0xd; /* claim SPC-6 version compatibility */ + memcpy(rbuf, hdr, sizeof(hdr)); memcpy(&rbuf[8], "ATA ", 8); ata_id_string(args->id, &rbuf[16], ATA_ID_PROD, 16); @@ -4312,7 +4349,7 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd) break; case MAINTENANCE_IN: - if (scsicmd[1] == MI_REPORT_SUPPORTED_OPERATION_CODES) + if ((scsicmd[1] & 0x1f) == MI_REPORT_SUPPORTED_OPERATION_CODES) ata_scsi_rbuf_fill(&args, ata_scsiop_maint_in); else ata_scsi_set_invalid_field(dev, cmd, 1, 0xff); @@ -4722,7 +4759,7 @@ void ata_scsi_dev_rescan(struct work_struct *work) struct ata_link *link; struct ata_device *dev; unsigned long flags; - bool delay_rescan = false; + int ret = 0; mutex_lock(&ap->scsi_scan_mutex); spin_lock_irqsave(ap->lock, flags); @@ -4731,37 +4768,34 @@ void ata_scsi_dev_rescan(struct work_struct *work) ata_for_each_dev(dev, link, ENABLED) { struct scsi_device *sdev = dev->sdev; + /* + * If the port was suspended before this was scheduled, + * bail out. + */ + if (ap->pflags & ATA_PFLAG_SUSPENDED) + goto unlock; + if (!sdev) continue; if (scsi_device_get(sdev)) continue; - /* - * If the rescan work was scheduled because of a resume - * event, the port is already fully resumed, but the - * SCSI device may not yet be fully resumed. In such - * case, executing scsi_rescan_device() may cause a - * deadlock with the PM code on device_lock(). Prevent - * this by giving up and retrying rescan after a short - * delay. - */ - delay_rescan = sdev->sdev_gendev.power.is_suspended; - if (delay_rescan) { - scsi_device_put(sdev); - break; - } - spin_unlock_irqrestore(ap->lock, flags); - scsi_rescan_device(sdev); + ret = scsi_rescan_device(sdev); scsi_device_put(sdev); spin_lock_irqsave(ap->lock, flags); + + if (ret) + goto unlock; } } +unlock: spin_unlock_irqrestore(ap->lock, flags); mutex_unlock(&ap->scsi_scan_mutex); - if (delay_rescan) + /* Reschedule with a delay if scsi_rescan_device() returned an error */ + if (ret) schedule_delayed_work(&ap->scsi_rescan_task, msecs_to_jiffies(5)); } diff --git a/drivers/ata/libata-transport.c b/drivers/ata/libata-transport.c index e4fb9d1b9b39..3e49a877500e 100644 --- a/drivers/ata/libata-transport.c +++ b/drivers/ata/libata-transport.c @@ -266,6 +266,10 @@ void ata_tport_delete(struct ata_port *ap) put_device(dev); } +static const struct device_type ata_port_sas_type = { + .name = ATA_PORT_TYPE_NAME, +}; + /** ata_tport_add - initialize a transport ATA port structure * * @parent: parent device @@ -283,7 +287,10 @@ int ata_tport_add(struct device *parent, struct device *dev = &ap->tdev; device_initialize(dev); - dev->type = &ata_port_type; + if (ap->flags & ATA_FLAG_SAS_HOST) + dev->type = &ata_port_sas_type; + else + dev->type = &ata_port_type; dev->parent = parent; ata_host_get(ap->host); diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h index 6e7d352803bd..05ac80da8ebc 100644 --- a/drivers/ata/libata.h +++ b/drivers/ata/libata.h @@ -30,6 +30,8 @@ enum { ATA_DNXFER_QUIET = (1 << 31), }; +#define ATA_PORT_TYPE_NAME "ata_port" + extern atomic_t ata_print_id; extern int atapi_passthru16; extern int libata_fua; @@ -60,6 +62,8 @@ extern int ata_dev_reread_id(struct ata_device *dev, unsigned int readid_flags); extern int ata_dev_revalidate(struct ata_device *dev, unsigned int new_class, unsigned int readid_flags); extern int ata_dev_configure(struct ata_device *dev); +extern void ata_dev_power_set_standby(struct ata_device *dev); +extern void ata_dev_power_set_active(struct ata_device *dev); extern int sata_down_spd_limit(struct ata_link *link, u32 spd_limit); extern int ata_down_xfermask_limit(struct ata_device *dev, unsigned int sel); extern unsigned int ata_dev_set_feature(struct ata_device *dev, diff --git a/drivers/ata/pata_parport/comm.c b/drivers/ata/pata_parport/comm.c index 4839becbbd56..94b8d352102e 100644 --- a/drivers/ata/pata_parport/comm.c +++ b/drivers/ata/pata_parport/comm.c @@ -37,7 +37,7 @@ static int comm_read_regr(struct pi_adapter *pi, int cont, int regr) { int l, h, r; - r = regr + cont_map[cont]; + r = regr + cont_map[cont]; switch (pi->mode) { case 0: @@ -90,7 +90,6 @@ static void comm_connect(struct pi_adapter *pi) } static void comm_disconnect(struct pi_adapter *pi) - { w2(0); w2(0); w2(0); w2(4); w0(pi->saved_r0); @@ -172,12 +171,12 @@ static void comm_write_block(struct pi_adapter *pi, char *buf, int count) w4l(swab16(((u16 *)buf)[2 * k]) | swab16(((u16 *)buf)[2 * k + 1]) << 16); break; - } + } } static void comm_log_adapter(struct pi_adapter *pi) - -{ char *mode_string[5] = { "4-bit", "8-bit", "EPP-8", "EPP-16", "EPP-32" }; +{ + char *mode_string[5] = { "4-bit", "8-bit", "EPP-8", "EPP-16", "EPP-32" }; dev_info(&pi->dev, "DataStor Commuter at 0x%x, mode %d (%s), delay %d\n", diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index d105db5c7d81..45e48d653c60 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -1255,8 +1255,8 @@ static void mv_dump_mem(struct device *dev, void __iomem *start, unsigned bytes) for (b = 0; b < bytes; ) { for (w = 0, o = 0; b < bytes && w < 4; w++) { - o += snprintf(linebuf + o, sizeof(linebuf) - o, - "%08x ", readl(start + b)); + o += scnprintf(linebuf + o, sizeof(linebuf) - o, + "%08x ", readl(start + b)); b += sizeof(u32); } dev_dbg(dev, "%s: %p: %s\n", diff --git a/drivers/base/core.c b/drivers/base/core.c index b7d7f410c256..4d8b315c48a1 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -3537,6 +3537,8 @@ int device_add(struct device *dev) /* subsystems can specify simple device enumeration */ else if (dev->bus && dev->bus->dev_name) error = dev_set_name(dev, "%s%u", dev->bus->dev_name, dev->id); + else + error = -EINVAL; if (error) goto name_error; diff --git a/drivers/base/power/common.c b/drivers/base/power/common.c index 72115917e0bd..44ec20918a4d 100644 --- a/drivers/base/power/common.c +++ b/drivers/base/power/common.c @@ -228,3 +228,24 @@ void dev_pm_domain_set(struct device *dev, struct dev_pm_domain *pd) device_pm_check_callbacks(dev); } EXPORT_SYMBOL_GPL(dev_pm_domain_set); + +/** + * dev_pm_domain_set_performance_state - Request a new performance state. + * @dev: The device to make the request for. + * @state: Target performance state for the device. + * + * This function should be called when a new performance state needs to be + * requested for a device that is attached to a PM domain. Note that, the + * support for performance scaling for PM domains is optional. + * + * Returns 0 on success and when performance scaling isn't supported, negative + * error code on failure. + */ +int dev_pm_domain_set_performance_state(struct device *dev, unsigned int state) +{ + if (dev->pm_domain && dev->pm_domain->set_performance_state) + return dev->pm_domain->set_performance_state(dev, state); + + return 0; +} +EXPORT_SYMBOL_GPL(dev_pm_domain_set_performance_state); diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 5cb2023581d4..da1777e39eaa 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -130,6 +130,7 @@ static const struct genpd_lock_ops genpd_spin_ops = { #define genpd_is_active_wakeup(genpd) (genpd->flags & GENPD_FLAG_ACTIVE_WAKEUP) #define genpd_is_cpu_domain(genpd) (genpd->flags & GENPD_FLAG_CPU_DOMAIN) #define genpd_is_rpm_always_on(genpd) (genpd->flags & GENPD_FLAG_RPM_ALWAYS_ON) +#define genpd_is_opp_table_fw(genpd) (genpd->flags & GENPD_FLAG_OPP_TABLE_FW) static inline bool irq_safe_dev_in_sleep_domain(struct device *dev, const struct generic_pm_domain *genpd) @@ -419,6 +420,25 @@ static void genpd_restore_performance_state(struct device *dev, genpd_set_performance_state(dev, state); } +static int genpd_dev_pm_set_performance_state(struct device *dev, + unsigned int state) +{ + struct generic_pm_domain *genpd = dev_to_genpd(dev); + int ret = 0; + + genpd_lock(genpd); + if (pm_runtime_suspended(dev)) { + dev_gpd_data(dev)->rpm_pstate = state; + } else { + ret = genpd_set_performance_state(dev, state); + if (!ret) + dev_gpd_data(dev)->rpm_pstate = 0; + } + genpd_unlock(genpd); + + return ret; +} + /** * dev_pm_genpd_set_performance_state- Set performance state of device's power * domain. @@ -437,7 +457,6 @@ static void genpd_restore_performance_state(struct device *dev, int dev_pm_genpd_set_performance_state(struct device *dev, unsigned int state) { struct generic_pm_domain *genpd; - int ret = 0; genpd = dev_to_genpd_safe(dev); if (!genpd) @@ -447,17 +466,7 @@ int dev_pm_genpd_set_performance_state(struct device *dev, unsigned int state) !dev->power.subsys_data->domain_data)) return -EINVAL; - genpd_lock(genpd); - if (pm_runtime_suspended(dev)) { - dev_gpd_data(dev)->rpm_pstate = state; - } else { - ret = genpd_set_performance_state(dev, state); - if (!ret) - dev_gpd_data(dev)->rpm_pstate = 0; - } - genpd_unlock(genpd); - - return ret; + return genpd_dev_pm_set_performance_state(dev, state); } EXPORT_SYMBOL_GPL(dev_pm_genpd_set_performance_state); @@ -2079,6 +2088,7 @@ int pm_genpd_init(struct generic_pm_domain *genpd, genpd->domain.ops.restore_noirq = genpd_restore_noirq; genpd->domain.ops.complete = genpd_complete; genpd->domain.start = genpd_dev_pm_start; + genpd->domain.set_performance_state = genpd_dev_pm_set_performance_state; if (genpd->flags & GENPD_FLAG_PM_CLK) { genpd->dev_ops.stop = pm_clk_suspend; @@ -2328,7 +2338,7 @@ int of_genpd_add_provider_simple(struct device_node *np, genpd->dev.of_node = np; /* Parse genpd OPP table */ - if (genpd->set_performance_state) { + if (!genpd_is_opp_table_fw(genpd) && genpd->set_performance_state) { ret = dev_pm_opp_of_add_table(&genpd->dev); if (ret) return dev_err_probe(&genpd->dev, ret, "Failed to add OPP table\n"); @@ -2343,7 +2353,7 @@ int of_genpd_add_provider_simple(struct device_node *np, ret = genpd_add_provider(np, genpd_xlate_simple, genpd); if (ret) { - if (genpd->set_performance_state) { + if (!genpd_is_opp_table_fw(genpd) && genpd->set_performance_state) { dev_pm_opp_put_opp_table(genpd->opp_table); dev_pm_opp_of_remove_table(&genpd->dev); } @@ -2387,7 +2397,7 @@ int of_genpd_add_provider_onecell(struct device_node *np, genpd->dev.of_node = np; /* Parse genpd OPP table */ - if (genpd->set_performance_state) { + if (!genpd_is_opp_table_fw(genpd) && genpd->set_performance_state) { ret = dev_pm_opp_of_add_table_indexed(&genpd->dev, i); if (ret) { dev_err_probe(&genpd->dev, ret, @@ -2423,7 +2433,7 @@ error: genpd->provider = NULL; genpd->has_provider = false; - if (genpd->set_performance_state) { + if (!genpd_is_opp_table_fw(genpd) && genpd->set_performance_state) { dev_pm_opp_put_opp_table(genpd->opp_table); dev_pm_opp_of_remove_table(&genpd->dev); } @@ -2455,7 +2465,7 @@ void of_genpd_del_provider(struct device_node *np) if (gpd->provider == &np->fwnode) { gpd->has_provider = false; - if (!gpd->set_performance_state) + if (genpd_is_opp_table_fw(gpd) || !gpd->set_performance_state) continue; dev_pm_opp_put_opp_table(gpd->opp_table); diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 3de11f077144..a999b698b131 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -632,9 +632,8 @@ void rbd_warn(struct rbd_device *rbd_dev, const char *fmt, ...) static void rbd_dev_remove_parent(struct rbd_device *rbd_dev); static int rbd_dev_refresh(struct rbd_device *rbd_dev); -static int rbd_dev_v2_header_onetime(struct rbd_device *rbd_dev); -static int rbd_dev_header_info(struct rbd_device *rbd_dev); -static int rbd_dev_v2_parent_info(struct rbd_device *rbd_dev); +static int rbd_dev_v2_header_onetime(struct rbd_device *rbd_dev, + struct rbd_image_header *header); static const char *rbd_dev_v2_snap_name(struct rbd_device *rbd_dev, u64 snap_id); static int _rbd_dev_v2_snap_size(struct rbd_device *rbd_dev, u64 snap_id, @@ -995,15 +994,24 @@ static void rbd_init_layout(struct rbd_device *rbd_dev) RCU_INIT_POINTER(rbd_dev->layout.pool_ns, NULL); } +static void rbd_image_header_cleanup(struct rbd_image_header *header) +{ + kfree(header->object_prefix); + ceph_put_snap_context(header->snapc); + kfree(header->snap_sizes); + kfree(header->snap_names); + + memset(header, 0, sizeof(*header)); +} + /* * Fill an rbd image header with information from the given format 1 * on-disk header. */ -static int rbd_header_from_disk(struct rbd_device *rbd_dev, - struct rbd_image_header_ondisk *ondisk) +static int rbd_header_from_disk(struct rbd_image_header *header, + struct rbd_image_header_ondisk *ondisk, + bool first_time) { - struct rbd_image_header *header = &rbd_dev->header; - bool first_time = header->object_prefix == NULL; struct ceph_snap_context *snapc; char *object_prefix = NULL; char *snap_names = NULL; @@ -1070,11 +1078,6 @@ static int rbd_header_from_disk(struct rbd_device *rbd_dev, if (first_time) { header->object_prefix = object_prefix; header->obj_order = ondisk->options.order; - rbd_init_layout(rbd_dev); - } else { - ceph_put_snap_context(header->snapc); - kfree(header->snap_names); - kfree(header->snap_sizes); } /* The remaining fields always get updated (when we refresh) */ @@ -4859,7 +4862,9 @@ out_req: * return, the rbd_dev->header field will contain up-to-date * information about the image. */ -static int rbd_dev_v1_header_info(struct rbd_device *rbd_dev) +static int rbd_dev_v1_header_info(struct rbd_device *rbd_dev, + struct rbd_image_header *header, + bool first_time) { struct rbd_image_header_ondisk *ondisk = NULL; u32 snap_count = 0; @@ -4907,7 +4912,7 @@ static int rbd_dev_v1_header_info(struct rbd_device *rbd_dev) snap_count = le32_to_cpu(ondisk->snap_count); } while (snap_count != want_count); - ret = rbd_header_from_disk(rbd_dev, ondisk); + ret = rbd_header_from_disk(header, ondisk, first_time); out: kfree(ondisk); @@ -4931,39 +4936,6 @@ static void rbd_dev_update_size(struct rbd_device *rbd_dev) } } -static int rbd_dev_refresh(struct rbd_device *rbd_dev) -{ - u64 mapping_size; - int ret; - - down_write(&rbd_dev->header_rwsem); - mapping_size = rbd_dev->mapping.size; - - ret = rbd_dev_header_info(rbd_dev); - if (ret) - goto out; - - /* - * If there is a parent, see if it has disappeared due to the - * mapped image getting flattened. - */ - if (rbd_dev->parent) { - ret = rbd_dev_v2_parent_info(rbd_dev); - if (ret) - goto out; - } - - rbd_assert(!rbd_is_snap(rbd_dev)); - rbd_dev->mapping.size = rbd_dev->header.image_size; - -out: - up_write(&rbd_dev->header_rwsem); - if (!ret && mapping_size != rbd_dev->mapping.size) - rbd_dev_update_size(rbd_dev); - - return ret; -} - static const struct blk_mq_ops rbd_mq_ops = { .queue_rq = rbd_queue_rq, }; @@ -5503,17 +5475,12 @@ static int _rbd_dev_v2_snap_size(struct rbd_device *rbd_dev, u64 snap_id, return 0; } -static int rbd_dev_v2_image_size(struct rbd_device *rbd_dev) -{ - return _rbd_dev_v2_snap_size(rbd_dev, CEPH_NOSNAP, - &rbd_dev->header.obj_order, - &rbd_dev->header.image_size); -} - -static int rbd_dev_v2_object_prefix(struct rbd_device *rbd_dev) +static int rbd_dev_v2_object_prefix(struct rbd_device *rbd_dev, + char **pobject_prefix) { size_t size; void *reply_buf; + char *object_prefix; int ret; void *p; @@ -5531,16 +5498,16 @@ static int rbd_dev_v2_object_prefix(struct rbd_device *rbd_dev) goto out; p = reply_buf; - rbd_dev->header.object_prefix = ceph_extract_encoded_string(&p, - p + ret, NULL, GFP_NOIO); + object_prefix = ceph_extract_encoded_string(&p, p + ret, NULL, + GFP_NOIO); + if (IS_ERR(object_prefix)) { + ret = PTR_ERR(object_prefix); + goto out; + } ret = 0; - if (IS_ERR(rbd_dev->header.object_prefix)) { - ret = PTR_ERR(rbd_dev->header.object_prefix); - rbd_dev->header.object_prefix = NULL; - } else { - dout(" object_prefix = %s\n", rbd_dev->header.object_prefix); - } + *pobject_prefix = object_prefix; + dout(" object_prefix = %s\n", object_prefix); out: kfree(reply_buf); @@ -5591,13 +5558,6 @@ static int _rbd_dev_v2_snap_features(struct rbd_device *rbd_dev, u64 snap_id, return 0; } -static int rbd_dev_v2_features(struct rbd_device *rbd_dev) -{ - return _rbd_dev_v2_snap_features(rbd_dev, CEPH_NOSNAP, - rbd_is_ro(rbd_dev), - &rbd_dev->header.features); -} - /* * These are generic image flags, but since they are used only for * object map, store them in rbd_dev->object_map_flags. @@ -5634,6 +5594,14 @@ struct parent_image_info { u64 overlap; }; +static void rbd_parent_info_cleanup(struct parent_image_info *pii) +{ + kfree(pii->pool_ns); + kfree(pii->image_id); + + memset(pii, 0, sizeof(*pii)); +} + /* * The caller is responsible for @pii. */ @@ -5703,6 +5671,9 @@ static int __get_parent_info(struct rbd_device *rbd_dev, if (pii->has_overlap) ceph_decode_64_safe(&p, end, pii->overlap, e_inval); + dout("%s pool_id %llu pool_ns %s image_id %s snap_id %llu has_overlap %d overlap %llu\n", + __func__, pii->pool_id, pii->pool_ns, pii->image_id, pii->snap_id, + pii->has_overlap, pii->overlap); return 0; e_inval: @@ -5741,14 +5712,17 @@ static int __get_parent_info_legacy(struct rbd_device *rbd_dev, pii->has_overlap = true; ceph_decode_64_safe(&p, end, pii->overlap, e_inval); + dout("%s pool_id %llu pool_ns %s image_id %s snap_id %llu has_overlap %d overlap %llu\n", + __func__, pii->pool_id, pii->pool_ns, pii->image_id, pii->snap_id, + pii->has_overlap, pii->overlap); return 0; e_inval: return -EINVAL; } -static int get_parent_info(struct rbd_device *rbd_dev, - struct parent_image_info *pii) +static int rbd_dev_v2_parent_info(struct rbd_device *rbd_dev, + struct parent_image_info *pii) { struct page *req_page, *reply_page; void *p; @@ -5776,7 +5750,7 @@ static int get_parent_info(struct rbd_device *rbd_dev, return ret; } -static int rbd_dev_v2_parent_info(struct rbd_device *rbd_dev) +static int rbd_dev_setup_parent(struct rbd_device *rbd_dev) { struct rbd_spec *parent_spec; struct parent_image_info pii = { 0 }; @@ -5786,37 +5760,12 @@ static int rbd_dev_v2_parent_info(struct rbd_device *rbd_dev) if (!parent_spec) return -ENOMEM; - ret = get_parent_info(rbd_dev, &pii); + ret = rbd_dev_v2_parent_info(rbd_dev, &pii); if (ret) goto out_err; - dout("%s pool_id %llu pool_ns %s image_id %s snap_id %llu has_overlap %d overlap %llu\n", - __func__, pii.pool_id, pii.pool_ns, pii.image_id, pii.snap_id, - pii.has_overlap, pii.overlap); - - if (pii.pool_id == CEPH_NOPOOL || !pii.has_overlap) { - /* - * Either the parent never existed, or we have - * record of it but the image got flattened so it no - * longer has a parent. When the parent of a - * layered image disappears we immediately set the - * overlap to 0. The effect of this is that all new - * requests will be treated as if the image had no - * parent. - * - * If !pii.has_overlap, the parent image spec is not - * applicable. It's there to avoid duplication in each - * snapshot record. - */ - if (rbd_dev->parent_overlap) { - rbd_dev->parent_overlap = 0; - rbd_dev_parent_put(rbd_dev); - pr_info("%s: clone image has been flattened\n", - rbd_dev->disk->disk_name); - } - + if (pii.pool_id == CEPH_NOPOOL || !pii.has_overlap) goto out; /* No parent? No problem. */ - } /* The ceph file layout needs to fit pool id in 32 bits */ @@ -5828,58 +5777,46 @@ static int rbd_dev_v2_parent_info(struct rbd_device *rbd_dev) } /* - * The parent won't change (except when the clone is - * flattened, already handled that). So we only need to - * record the parent spec we have not already done so. + * The parent won't change except when the clone is flattened, + * so we only need to record the parent image spec once. */ - if (!rbd_dev->parent_spec) { - parent_spec->pool_id = pii.pool_id; - if (pii.pool_ns && *pii.pool_ns) { - parent_spec->pool_ns = pii.pool_ns; - pii.pool_ns = NULL; - } - parent_spec->image_id = pii.image_id; - pii.image_id = NULL; - parent_spec->snap_id = pii.snap_id; - - rbd_dev->parent_spec = parent_spec; - parent_spec = NULL; /* rbd_dev now owns this */ + parent_spec->pool_id = pii.pool_id; + if (pii.pool_ns && *pii.pool_ns) { + parent_spec->pool_ns = pii.pool_ns; + pii.pool_ns = NULL; } + parent_spec->image_id = pii.image_id; + pii.image_id = NULL; + parent_spec->snap_id = pii.snap_id; + + rbd_assert(!rbd_dev->parent_spec); + rbd_dev->parent_spec = parent_spec; + parent_spec = NULL; /* rbd_dev now owns this */ /* - * We always update the parent overlap. If it's zero we issue - * a warning, as we will proceed as if there was no parent. + * Record the parent overlap. If it's zero, issue a warning as + * we will proceed as if there is no parent. */ - if (!pii.overlap) { - if (parent_spec) { - /* refresh, careful to warn just once */ - if (rbd_dev->parent_overlap) - rbd_warn(rbd_dev, - "clone now standalone (overlap became 0)"); - } else { - /* initial probe */ - rbd_warn(rbd_dev, "clone is standalone (overlap 0)"); - } - } + if (!pii.overlap) + rbd_warn(rbd_dev, "clone is standalone (overlap 0)"); rbd_dev->parent_overlap = pii.overlap; out: ret = 0; out_err: - kfree(pii.pool_ns); - kfree(pii.image_id); + rbd_parent_info_cleanup(&pii); rbd_spec_put(parent_spec); return ret; } -static int rbd_dev_v2_striping_info(struct rbd_device *rbd_dev) +static int rbd_dev_v2_striping_info(struct rbd_device *rbd_dev, + u64 *stripe_unit, u64 *stripe_count) { struct { __le64 stripe_unit; __le64 stripe_count; } __attribute__ ((packed)) striping_info_buf = { 0 }; size_t size = sizeof (striping_info_buf); - void *p; int ret; ret = rbd_obj_method_sync(rbd_dev, &rbd_dev->header_oid, @@ -5891,27 +5828,33 @@ static int rbd_dev_v2_striping_info(struct rbd_device *rbd_dev) if (ret < size) return -ERANGE; - p = &striping_info_buf; - rbd_dev->header.stripe_unit = ceph_decode_64(&p); - rbd_dev->header.stripe_count = ceph_decode_64(&p); + *stripe_unit = le64_to_cpu(striping_info_buf.stripe_unit); + *stripe_count = le64_to_cpu(striping_info_buf.stripe_count); + dout(" stripe_unit = %llu stripe_count = %llu\n", *stripe_unit, + *stripe_count); + return 0; } -static int rbd_dev_v2_data_pool(struct rbd_device *rbd_dev) +static int rbd_dev_v2_data_pool(struct rbd_device *rbd_dev, s64 *data_pool_id) { - __le64 data_pool_id; + __le64 data_pool_buf; int ret; ret = rbd_obj_method_sync(rbd_dev, &rbd_dev->header_oid, &rbd_dev->header_oloc, "get_data_pool", - NULL, 0, &data_pool_id, sizeof(data_pool_id)); + NULL, 0, &data_pool_buf, + sizeof(data_pool_buf)); + dout("%s: rbd_obj_method_sync returned %d\n", __func__, ret); if (ret < 0) return ret; - if (ret < sizeof(data_pool_id)) + if (ret < sizeof(data_pool_buf)) return -EBADMSG; - rbd_dev->header.data_pool_id = le64_to_cpu(data_pool_id); - WARN_ON(rbd_dev->header.data_pool_id == CEPH_NOPOOL); + *data_pool_id = le64_to_cpu(data_pool_buf); + dout(" data_pool_id = %lld\n", *data_pool_id); + WARN_ON(*data_pool_id == CEPH_NOPOOL); + return 0; } @@ -6103,7 +6046,8 @@ out_err: return ret; } -static int rbd_dev_v2_snap_context(struct rbd_device *rbd_dev) +static int rbd_dev_v2_snap_context(struct rbd_device *rbd_dev, + struct ceph_snap_context **psnapc) { size_t size; int ret; @@ -6164,9 +6108,7 @@ static int rbd_dev_v2_snap_context(struct rbd_device *rbd_dev) for (i = 0; i < snap_count; i++) snapc->snaps[i] = ceph_decode_64(&p); - ceph_put_snap_context(rbd_dev->header.snapc); - rbd_dev->header.snapc = snapc; - + *psnapc = snapc; dout(" snap context seq = %llu, snap_count = %u\n", (unsigned long long)seq, (unsigned int)snap_count); out: @@ -6215,38 +6157,42 @@ out: return snap_name; } -static int rbd_dev_v2_header_info(struct rbd_device *rbd_dev) +static int rbd_dev_v2_header_info(struct rbd_device *rbd_dev, + struct rbd_image_header *header, + bool first_time) { - bool first_time = rbd_dev->header.object_prefix == NULL; int ret; - ret = rbd_dev_v2_image_size(rbd_dev); + ret = _rbd_dev_v2_snap_size(rbd_dev, CEPH_NOSNAP, + first_time ? &header->obj_order : NULL, + &header->image_size); if (ret) return ret; if (first_time) { - ret = rbd_dev_v2_header_onetime(rbd_dev); + ret = rbd_dev_v2_header_onetime(rbd_dev, header); if (ret) return ret; } - ret = rbd_dev_v2_snap_context(rbd_dev); - if (ret && first_time) { - kfree(rbd_dev->header.object_prefix); - rbd_dev->header.object_prefix = NULL; - } + ret = rbd_dev_v2_snap_context(rbd_dev, &header->snapc); + if (ret) + return ret; - return ret; + return 0; } -static int rbd_dev_header_info(struct rbd_device *rbd_dev) +static int rbd_dev_header_info(struct rbd_device *rbd_dev, + struct rbd_image_header *header, + bool first_time) { rbd_assert(rbd_image_format_valid(rbd_dev->image_format)); + rbd_assert(!header->object_prefix && !header->snapc); if (rbd_dev->image_format == 1) - return rbd_dev_v1_header_info(rbd_dev); + return rbd_dev_v1_header_info(rbd_dev, header, first_time); - return rbd_dev_v2_header_info(rbd_dev); + return rbd_dev_v2_header_info(rbd_dev, header, first_time); } /* @@ -6734,60 +6680,49 @@ out: */ static void rbd_dev_unprobe(struct rbd_device *rbd_dev) { - struct rbd_image_header *header; - rbd_dev_parent_put(rbd_dev); rbd_object_map_free(rbd_dev); rbd_dev_mapping_clear(rbd_dev); /* Free dynamic fields from the header, then zero it out */ - header = &rbd_dev->header; - ceph_put_snap_context(header->snapc); - kfree(header->snap_sizes); - kfree(header->snap_names); - kfree(header->object_prefix); - memset(header, 0, sizeof (*header)); + rbd_image_header_cleanup(&rbd_dev->header); } -static int rbd_dev_v2_header_onetime(struct rbd_device *rbd_dev) +static int rbd_dev_v2_header_onetime(struct rbd_device *rbd_dev, + struct rbd_image_header *header) { int ret; - ret = rbd_dev_v2_object_prefix(rbd_dev); + ret = rbd_dev_v2_object_prefix(rbd_dev, &header->object_prefix); if (ret) - goto out_err; + return ret; /* * Get the and check features for the image. Currently the * features are assumed to never change. */ - ret = rbd_dev_v2_features(rbd_dev); + ret = _rbd_dev_v2_snap_features(rbd_dev, CEPH_NOSNAP, + rbd_is_ro(rbd_dev), &header->features); if (ret) - goto out_err; + return ret; /* If the image supports fancy striping, get its parameters */ - if (rbd_dev->header.features & RBD_FEATURE_STRIPINGV2) { - ret = rbd_dev_v2_striping_info(rbd_dev); - if (ret < 0) - goto out_err; + if (header->features & RBD_FEATURE_STRIPINGV2) { + ret = rbd_dev_v2_striping_info(rbd_dev, &header->stripe_unit, + &header->stripe_count); + if (ret) + return ret; } - if (rbd_dev->header.features & RBD_FEATURE_DATA_POOL) { - ret = rbd_dev_v2_data_pool(rbd_dev); + if (header->features & RBD_FEATURE_DATA_POOL) { + ret = rbd_dev_v2_data_pool(rbd_dev, &header->data_pool_id); if (ret) - goto out_err; + return ret; } - rbd_init_layout(rbd_dev); return 0; - -out_err: - rbd_dev->header.features = 0; - kfree(rbd_dev->header.object_prefix); - rbd_dev->header.object_prefix = NULL; - return ret; } /* @@ -6982,13 +6917,15 @@ static int rbd_dev_image_probe(struct rbd_device *rbd_dev, int depth) if (!depth) down_write(&rbd_dev->header_rwsem); - ret = rbd_dev_header_info(rbd_dev); + ret = rbd_dev_header_info(rbd_dev, &rbd_dev->header, true); if (ret) { if (ret == -ENOENT && !need_watch) rbd_print_dne(rbd_dev, false); goto err_out_probe; } + rbd_init_layout(rbd_dev); + /* * If this image is the one being mapped, we have pool name and * id, image name and id, and snap name - need to fill snap id. @@ -7017,7 +6954,7 @@ static int rbd_dev_image_probe(struct rbd_device *rbd_dev, int depth) } if (rbd_dev->header.features & RBD_FEATURE_LAYERING) { - ret = rbd_dev_v2_parent_info(rbd_dev); + ret = rbd_dev_setup_parent(rbd_dev); if (ret) goto err_out_probe; } @@ -7043,6 +6980,107 @@ err_out_format: return ret; } +static void rbd_dev_update_header(struct rbd_device *rbd_dev, + struct rbd_image_header *header) +{ + rbd_assert(rbd_image_format_valid(rbd_dev->image_format)); + rbd_assert(rbd_dev->header.object_prefix); /* !first_time */ + + if (rbd_dev->header.image_size != header->image_size) { + rbd_dev->header.image_size = header->image_size; + + if (!rbd_is_snap(rbd_dev)) { + rbd_dev->mapping.size = header->image_size; + rbd_dev_update_size(rbd_dev); + } + } + + ceph_put_snap_context(rbd_dev->header.snapc); + rbd_dev->header.snapc = header->snapc; + header->snapc = NULL; + + if (rbd_dev->image_format == 1) { + kfree(rbd_dev->header.snap_names); + rbd_dev->header.snap_names = header->snap_names; + header->snap_names = NULL; + + kfree(rbd_dev->header.snap_sizes); + rbd_dev->header.snap_sizes = header->snap_sizes; + header->snap_sizes = NULL; + } +} + +static void rbd_dev_update_parent(struct rbd_device *rbd_dev, + struct parent_image_info *pii) +{ + if (pii->pool_id == CEPH_NOPOOL || !pii->has_overlap) { + /* + * Either the parent never existed, or we have + * record of it but the image got flattened so it no + * longer has a parent. When the parent of a + * layered image disappears we immediately set the + * overlap to 0. The effect of this is that all new + * requests will be treated as if the image had no + * parent. + * + * If !pii.has_overlap, the parent image spec is not + * applicable. It's there to avoid duplication in each + * snapshot record. + */ + if (rbd_dev->parent_overlap) { + rbd_dev->parent_overlap = 0; + rbd_dev_parent_put(rbd_dev); + pr_info("%s: clone has been flattened\n", + rbd_dev->disk->disk_name); + } + } else { + rbd_assert(rbd_dev->parent_spec); + + /* + * Update the parent overlap. If it became zero, issue + * a warning as we will proceed as if there is no parent. + */ + if (!pii->overlap && rbd_dev->parent_overlap) + rbd_warn(rbd_dev, + "clone has become standalone (overlap 0)"); + rbd_dev->parent_overlap = pii->overlap; + } +} + +static int rbd_dev_refresh(struct rbd_device *rbd_dev) +{ + struct rbd_image_header header = { 0 }; + struct parent_image_info pii = { 0 }; + int ret; + + dout("%s rbd_dev %p\n", __func__, rbd_dev); + + ret = rbd_dev_header_info(rbd_dev, &header, false); + if (ret) + goto out; + + /* + * If there is a parent, see if it has disappeared due to the + * mapped image getting flattened. + */ + if (rbd_dev->parent) { + ret = rbd_dev_v2_parent_info(rbd_dev, &pii); + if (ret) + goto out; + } + + down_write(&rbd_dev->header_rwsem); + rbd_dev_update_header(rbd_dev, &header); + if (rbd_dev->parent) + rbd_dev_update_parent(rbd_dev, &pii); + up_write(&rbd_dev->header_rwsem); + +out: + rbd_parent_info_cleanup(&pii); + rbd_image_header_cleanup(&header); + return ret; +} + static ssize_t do_rbd_add(const char *buf, size_t count) { struct rbd_device *rbd_dev = NULL; diff --git a/drivers/bus/ti-sysc.c b/drivers/bus/ti-sysc.c index eb4e7bee1e20..d57bc066dce6 100644 --- a/drivers/bus/ti-sysc.c +++ b/drivers/bus/ti-sysc.c @@ -38,6 +38,7 @@ enum sysc_soc { SOC_2420, SOC_2430, SOC_3430, + SOC_AM35, SOC_3630, SOC_4430, SOC_4460, @@ -1097,6 +1098,11 @@ static int sysc_enable_module(struct device *dev) if (ddata->cfg.quirks & (SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_SWSUP_SIDLE_ACT)) { best_mode = SYSC_IDLE_NO; + + /* Clear WAKEUP */ + if (regbits->enwkup_shift >= 0 && + ddata->cfg.sysc_val & BIT(regbits->enwkup_shift)) + reg &= ~BIT(regbits->enwkup_shift); } else { best_mode = fls(ddata->cfg.sidlemodes) - 1; if (best_mode > SYSC_IDLE_MASK) { @@ -1224,6 +1230,13 @@ set_sidle: } } + if (ddata->cfg.quirks & SYSC_QUIRK_SWSUP_SIDLE_ACT) { + /* Set WAKEUP */ + if (regbits->enwkup_shift >= 0 && + ddata->cfg.sysc_val & BIT(regbits->enwkup_shift)) + reg |= BIT(regbits->enwkup_shift); + } + reg &= ~(SYSC_IDLE_MASK << regbits->sidle_shift); reg |= best_mode << regbits->sidle_shift; if (regbits->autoidle_shift >= 0 && @@ -1518,16 +1531,16 @@ struct sysc_revision_quirk { static const struct sysc_revision_quirk sysc_revision_quirks[] = { /* These drivers need to be fixed to not use pm_runtime_irq_safe() */ SYSC_QUIRK("uart", 0, 0x50, 0x54, 0x58, 0x00000046, 0xffffffff, - SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_LEGACY_IDLE), + SYSC_QUIRK_SWSUP_SIDLE_ACT | SYSC_QUIRK_LEGACY_IDLE), SYSC_QUIRK("uart", 0, 0x50, 0x54, 0x58, 0x00000052, 0xffffffff, - SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_LEGACY_IDLE), + SYSC_QUIRK_SWSUP_SIDLE_ACT | SYSC_QUIRK_LEGACY_IDLE), /* Uarts on omap4 and later */ SYSC_QUIRK("uart", 0, 0x50, 0x54, 0x58, 0x50411e03, 0xffff00ff, - SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_LEGACY_IDLE), + SYSC_QUIRK_SWSUP_SIDLE_ACT | SYSC_QUIRK_LEGACY_IDLE), SYSC_QUIRK("uart", 0, 0x50, 0x54, 0x58, 0x47422e03, 0xffffffff, - SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_LEGACY_IDLE), + SYSC_QUIRK_SWSUP_SIDLE_ACT | SYSC_QUIRK_LEGACY_IDLE), SYSC_QUIRK("uart", 0, 0x50, 0x54, 0x58, 0x47424e03, 0xffffffff, - SYSC_QUIRK_SWSUP_SIDLE | SYSC_QUIRK_LEGACY_IDLE), + SYSC_QUIRK_SWSUP_SIDLE_ACT | SYSC_QUIRK_LEGACY_IDLE), /* Quirks that need to be set based on the module address */ SYSC_QUIRK("mcpdm", 0x40132000, 0, 0x10, -ENODEV, 0x50000800, 0xffffffff, @@ -1862,7 +1875,7 @@ static void sysc_pre_reset_quirk_dss(struct sysc *ddata) dev_warn(ddata->dev, "%s: timed out %08x !+ %08x\n", __func__, val, irq_mask); - if (sysc_soc->soc == SOC_3430) { + if (sysc_soc->soc == SOC_3430 || sysc_soc->soc == SOC_AM35) { /* Clear DSS_SDI_CONTROL */ sysc_write(ddata, 0x44, 0); @@ -2150,8 +2163,7 @@ static int sysc_reset(struct sysc *ddata) } if (ddata->cfg.srst_udelay) - usleep_range(ddata->cfg.srst_udelay, - ddata->cfg.srst_udelay * 2); + fsleep(ddata->cfg.srst_udelay); if (ddata->post_reset_quirk) ddata->post_reset_quirk(ddata); @@ -3025,6 +3037,7 @@ static void ti_sysc_idle(struct work_struct *work) static const struct soc_device_attribute sysc_soc_match[] = { SOC_FLAG("OMAP242*", SOC_2420), SOC_FLAG("OMAP243*", SOC_2430), + SOC_FLAG("AM35*", SOC_AM35), SOC_FLAG("OMAP3[45]*", SOC_3430), SOC_FLAG("OMAP3[67]*", SOC_3630), SOC_FLAG("OMAP443*", SOC_4430), @@ -3229,7 +3242,7 @@ static int sysc_check_active_timer(struct sysc *ddata) * can be dropped if we stop supporting old beagleboard revisions * A to B4 at some point. */ - if (sysc_soc->soc == SOC_3430) + if (sysc_soc->soc == SOC_3430 || sysc_soc->soc == SOC_AM35) error = -ENXIO; else error = -EBUSY; diff --git a/drivers/bus/vexpress-config.c b/drivers/bus/vexpress-config.c index c4e1becbb2d2..d2c7ada90186 100644 --- a/drivers/bus/vexpress-config.c +++ b/drivers/bus/vexpress-config.c @@ -54,7 +54,7 @@ struct vexpress_syscfg_func { struct vexpress_syscfg *syscfg; struct regmap *regmap; int num_templates; - u32 template[]; /* Keep it last! */ + u32 template[] __counted_by(num_templates); /* Keep it last! */ }; struct vexpress_config_bridge_ops { diff --git a/drivers/char/agp/parisc-agp.c b/drivers/char/agp/parisc-agp.c index 514f9f287a78..c6f181702b9a 100644 --- a/drivers/char/agp/parisc-agp.c +++ b/drivers/char/agp/parisc-agp.c @@ -394,8 +394,6 @@ find_quicksilver(struct device *dev, void *data) static int __init parisc_agp_init(void) { - extern struct sba_device *sba_list; - int err = -1; struct parisc_device *sba = NULL, *lba = NULL; struct lba_device *lbadev = NULL; diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c index 23f6f2eda84c..42b1062e33cd 100644 --- a/drivers/char/tpm/tpm-chip.c +++ b/drivers/char/tpm/tpm-chip.c @@ -33,7 +33,7 @@ const struct class tpm_class = { .shutdown_pre = tpm_class_shutdown, }; const struct class tpmrm_class = { - .name = "tmprm", + .name = "tpmrm", }; dev_t tpm_devt; diff --git a/drivers/clk/clk-scmi.c b/drivers/clk/clk-scmi.c index 2c7a830ce308..8cbe24789c24 100644 --- a/drivers/clk/clk-scmi.c +++ b/drivers/clk/clk-scmi.c @@ -13,13 +13,18 @@ #include <linux/scmi_protocol.h> #include <asm/div64.h> +#define NOT_ATOMIC false +#define ATOMIC true + static const struct scmi_clk_proto_ops *scmi_proto_clk_ops; struct scmi_clk { u32 id; + struct device *dev; struct clk_hw hw; const struct scmi_clock_info *info; const struct scmi_protocol_handle *ph; + struct clk_parent_data *parent_data; }; #define to_scmi_clk(clk) container_of(clk, struct scmi_clk, hw) @@ -74,38 +79,89 @@ static int scmi_clk_set_rate(struct clk_hw *hw, unsigned long rate, return scmi_proto_clk_ops->rate_set(clk->ph, clk->id, rate); } +static int scmi_clk_set_parent(struct clk_hw *hw, u8 parent_index) +{ + struct scmi_clk *clk = to_scmi_clk(hw); + + return scmi_proto_clk_ops->parent_set(clk->ph, clk->id, parent_index); +} + +static u8 scmi_clk_get_parent(struct clk_hw *hw) +{ + struct scmi_clk *clk = to_scmi_clk(hw); + u32 parent_id, p_idx; + int ret; + + ret = scmi_proto_clk_ops->parent_get(clk->ph, clk->id, &parent_id); + if (ret) + return 0; + + for (p_idx = 0; p_idx < clk->info->num_parents; p_idx++) { + if (clk->parent_data[p_idx].index == parent_id) + break; + } + + if (p_idx == clk->info->num_parents) + return 0; + + return p_idx; +} + +static int scmi_clk_determine_rate(struct clk_hw *hw, struct clk_rate_request *req) +{ + /* + * Suppose all the requested rates are supported, and let firmware + * to handle the left work. + */ + return 0; +} + static int scmi_clk_enable(struct clk_hw *hw) { struct scmi_clk *clk = to_scmi_clk(hw); - return scmi_proto_clk_ops->enable(clk->ph, clk->id); + return scmi_proto_clk_ops->enable(clk->ph, clk->id, NOT_ATOMIC); } static void scmi_clk_disable(struct clk_hw *hw) { struct scmi_clk *clk = to_scmi_clk(hw); - scmi_proto_clk_ops->disable(clk->ph, clk->id); + scmi_proto_clk_ops->disable(clk->ph, clk->id, NOT_ATOMIC); } static int scmi_clk_atomic_enable(struct clk_hw *hw) { struct scmi_clk *clk = to_scmi_clk(hw); - return scmi_proto_clk_ops->enable_atomic(clk->ph, clk->id); + return scmi_proto_clk_ops->enable(clk->ph, clk->id, ATOMIC); } static void scmi_clk_atomic_disable(struct clk_hw *hw) { struct scmi_clk *clk = to_scmi_clk(hw); - scmi_proto_clk_ops->disable_atomic(clk->ph, clk->id); + scmi_proto_clk_ops->disable(clk->ph, clk->id, ATOMIC); +} + +static int scmi_clk_atomic_is_enabled(struct clk_hw *hw) +{ + int ret; + bool enabled = false; + struct scmi_clk *clk = to_scmi_clk(hw); + + ret = scmi_proto_clk_ops->state_get(clk->ph, clk->id, &enabled, ATOMIC); + if (ret) + dev_warn(clk->dev, + "Failed to get state for clock ID %d\n", clk->id); + + return !!enabled; } /* - * We can provide enable/disable atomic callbacks only if the underlying SCMI - * transport for an SCMI instance is configured to handle SCMI commands in an - * atomic manner. + * We can provide enable/disable/is_enabled atomic callbacks only if the + * underlying SCMI transport for an SCMI instance is configured to handle + * SCMI commands in an atomic manner. * * When no SCMI atomic transport support is available we instead provide only * the prepare/unprepare API, as allowed by the clock framework when atomic @@ -121,6 +177,9 @@ static const struct clk_ops scmi_clk_ops = { .set_rate = scmi_clk_set_rate, .prepare = scmi_clk_enable, .unprepare = scmi_clk_disable, + .set_parent = scmi_clk_set_parent, + .get_parent = scmi_clk_get_parent, + .determine_rate = scmi_clk_determine_rate, }; static const struct clk_ops scmi_atomic_clk_ops = { @@ -129,6 +188,10 @@ static const struct clk_ops scmi_atomic_clk_ops = { .set_rate = scmi_clk_set_rate, .enable = scmi_clk_atomic_enable, .disable = scmi_clk_atomic_disable, + .is_enabled = scmi_clk_atomic_is_enabled, + .set_parent = scmi_clk_set_parent, + .get_parent = scmi_clk_get_parent, + .determine_rate = scmi_clk_determine_rate, }; static int scmi_clk_ops_init(struct device *dev, struct scmi_clk *sclk, @@ -139,9 +202,10 @@ static int scmi_clk_ops_init(struct device *dev, struct scmi_clk *sclk, struct clk_init_data init = { .flags = CLK_GET_RATE_NOCACHE, - .num_parents = 0, + .num_parents = sclk->info->num_parents, .ops = scmi_ops, .name = sclk->info->name, + .parent_data = sclk->parent_data, }; sclk->hw.init = &init; @@ -213,11 +277,13 @@ static int scmi_clocks_probe(struct scmi_device *sdev) sclk->info = scmi_proto_clk_ops->info_get(ph, idx); if (!sclk->info) { dev_dbg(dev, "invalid clock info for idx %d\n", idx); + devm_kfree(dev, sclk); continue; } sclk->id = idx; sclk->ph = ph; + sclk->dev = dev; /* * Note that when transport is atomic but SCMI protocol did not @@ -230,9 +296,23 @@ static int scmi_clocks_probe(struct scmi_device *sdev) else scmi_ops = &scmi_clk_ops; + /* Initialize clock parent data. */ + if (sclk->info->num_parents > 0) { + sclk->parent_data = devm_kcalloc(dev, sclk->info->num_parents, + sizeof(*sclk->parent_data), GFP_KERNEL); + if (!sclk->parent_data) + return -ENOMEM; + + for (int i = 0; i < sclk->info->num_parents; i++) { + sclk->parent_data[i].index = sclk->info->parents[i]; + sclk->parent_data[i].hw = hws[sclk->info->parents[i]]; + } + } + err = scmi_clk_ops_init(dev, sclk, scmi_ops); if (err) { dev_err(dev, "failed to register clock %d\n", idx); + devm_kfree(dev, sclk->parent_data); devm_kfree(dev, sclk); hws[idx] = NULL; } else { diff --git a/drivers/clk/clk-si521xx.c b/drivers/clk/clk-si521xx.c index 4eaf1b53f06b..ef4ba467e747 100644 --- a/drivers/clk/clk-si521xx.c +++ b/drivers/clk/clk-si521xx.c @@ -96,7 +96,7 @@ static int si521xx_regmap_i2c_write(void *context, unsigned int reg, unsigned int val) { struct i2c_client *i2c = context; - const u8 data[3] = { reg, 1, val }; + const u8 data[2] = { reg, val }; const int count = ARRAY_SIZE(data); int ret; @@ -146,7 +146,7 @@ static int si521xx_regmap_i2c_read(void *context, unsigned int reg, static const struct regmap_config si521xx_regmap_config = { .reg_bits = 8, .val_bits = 8, - .cache_type = REGCACHE_NONE, + .cache_type = REGCACHE_FLAT, .max_register = SI521XX_REG_DA, .rd_table = &si521xx_readable_table, .wr_table = &si521xx_writeable_table, @@ -281,9 +281,10 @@ static int si521xx_probe(struct i2c_client *client) { const u16 chip_info = (u16)(uintptr_t)device_get_match_data(&client->dev); const struct clk_parent_data clk_parent_data = { .index = 0 }; - struct si521xx *si; + const u8 data[3] = { SI521XX_REG_BC, 1, 1 }; unsigned char name[6] = "DIFF0"; struct clk_init_data init = {}; + struct si521xx *si; int i, ret; if (!chip_info) @@ -308,7 +309,7 @@ static int si521xx_probe(struct i2c_client *client) "Failed to allocate register map\n"); /* Always read back 1 Byte via I2C */ - ret = regmap_write(si->regmap, SI521XX_REG_BC, 1); + ret = i2c_master_send(client, data, ARRAY_SIZE(data)); if (ret < 0) return ret; diff --git a/drivers/clk/clk-versaclock3.c b/drivers/clk/clk-versaclock3.c index 7ab2447bd203..3d7de355f8f6 100644 --- a/drivers/clk/clk-versaclock3.c +++ b/drivers/clk/clk-versaclock3.c @@ -118,21 +118,21 @@ enum vc3_div { VC3_DIV5, }; -enum vc3_clk_mux { - VC3_DIFF2_MUX, - VC3_DIFF1_MUX, - VC3_SE3_MUX, - VC3_SE2_MUX, - VC3_SE1_MUX, -}; - enum vc3_clk { - VC3_DIFF2, - VC3_DIFF1, - VC3_SE3, - VC3_SE2, - VC3_SE1, VC3_REF, + VC3_SE1, + VC3_SE2, + VC3_SE3, + VC3_DIFF1, + VC3_DIFF2, +}; + +enum vc3_clk_mux { + VC3_SE1_MUX = VC3_SE1 - 1, + VC3_SE2_MUX = VC3_SE2 - 1, + VC3_SE3_MUX = VC3_SE3 - 1, + VC3_DIFF1_MUX = VC3_DIFF1 - 1, + VC3_DIFF2_MUX = VC3_DIFF2 - 1, }; struct vc3_clk_data { @@ -401,11 +401,10 @@ static long vc3_pll_round_rate(struct clk_hw *hw, unsigned long rate, /* Determine best fractional part, which is 16 bit wide */ div_frc = rate % *parent_rate; div_frc *= BIT(16) - 1; - do_div(div_frc, *parent_rate); - vc3->div_frc = (u32)div_frc; + vc3->div_frc = min_t(u64, div64_ul(div_frc, *parent_rate), U16_MAX); rate = (*parent_rate * - (vc3->div_int * VC3_2_POW_16 + div_frc) / VC3_2_POW_16); + (vc3->div_int * VC3_2_POW_16 + vc3->div_frc) / VC3_2_POW_16); } else { rate = *parent_rate * vc3->div_int; } @@ -897,33 +896,33 @@ static struct vc3_hw_data clk_div[] = { }; static struct vc3_hw_data clk_mux[] = { - [VC3_DIFF2_MUX] = { + [VC3_SE1_MUX] = { .data = &(struct vc3_clk_data) { - .offs = VC3_DIFF2_CTRL_REG, - .bitmsk = VC3_DIFF2_CTRL_REG_DIFF2_CLK_SEL + .offs = VC3_SE1_DIV4_CTRL, + .bitmsk = VC3_SE1_DIV4_CTRL_SE1_CLK_SEL }, .hw.init = &(struct clk_init_data){ - .name = "diff2_mux", + .name = "se1_mux", .ops = &vc3_clk_mux_ops, .parent_hws = (const struct clk_hw *[]) { - &clk_div[VC3_DIV1].hw, - &clk_div[VC3_DIV3].hw + &clk_div[VC3_DIV5].hw, + &clk_div[VC3_DIV4].hw }, .num_parents = 2, .flags = CLK_SET_RATE_PARENT } }, - [VC3_DIFF1_MUX] = { + [VC3_SE2_MUX] = { .data = &(struct vc3_clk_data) { - .offs = VC3_DIFF1_CTRL_REG, - .bitmsk = VC3_DIFF1_CTRL_REG_DIFF1_CLK_SEL + .offs = VC3_SE2_CTRL_REG0, + .bitmsk = VC3_SE2_CTRL_REG0_SE2_CLK_SEL }, .hw.init = &(struct clk_init_data){ - .name = "diff1_mux", + .name = "se2_mux", .ops = &vc3_clk_mux_ops, .parent_hws = (const struct clk_hw *[]) { - &clk_div[VC3_DIV1].hw, - &clk_div[VC3_DIV3].hw + &clk_div[VC3_DIV5].hw, + &clk_div[VC3_DIV4].hw }, .num_parents = 2, .flags = CLK_SET_RATE_PARENT @@ -945,33 +944,33 @@ static struct vc3_hw_data clk_mux[] = { .flags = CLK_SET_RATE_PARENT } }, - [VC3_SE2_MUX] = { + [VC3_DIFF1_MUX] = { .data = &(struct vc3_clk_data) { - .offs = VC3_SE2_CTRL_REG0, - .bitmsk = VC3_SE2_CTRL_REG0_SE2_CLK_SEL + .offs = VC3_DIFF1_CTRL_REG, + .bitmsk = VC3_DIFF1_CTRL_REG_DIFF1_CLK_SEL }, .hw.init = &(struct clk_init_data){ - .name = "se2_mux", + .name = "diff1_mux", .ops = &vc3_clk_mux_ops, .parent_hws = (const struct clk_hw *[]) { - &clk_div[VC3_DIV5].hw, - &clk_div[VC3_DIV4].hw + &clk_div[VC3_DIV1].hw, + &clk_div[VC3_DIV3].hw }, .num_parents = 2, .flags = CLK_SET_RATE_PARENT } }, - [VC3_SE1_MUX] = { + [VC3_DIFF2_MUX] = { .data = &(struct vc3_clk_data) { - .offs = VC3_SE1_DIV4_CTRL, - .bitmsk = VC3_SE1_DIV4_CTRL_SE1_CLK_SEL + .offs = VC3_DIFF2_CTRL_REG, + .bitmsk = VC3_DIFF2_CTRL_REG_DIFF2_CLK_SEL }, .hw.init = &(struct clk_init_data){ - .name = "se1_mux", + .name = "diff2_mux", .ops = &vc3_clk_mux_ops, .parent_hws = (const struct clk_hw *[]) { - &clk_div[VC3_DIV5].hw, - &clk_div[VC3_DIV4].hw + &clk_div[VC3_DIV1].hw, + &clk_div[VC3_DIV3].hw }, .num_parents = 2, .flags = CLK_SET_RATE_PARENT @@ -1110,7 +1109,7 @@ static int vc3_probe(struct i2c_client *client) name, 0, CLK_SET_RATE_PARENT, 1, 1); else clk_out[i] = devm_clk_hw_register_fixed_factor_parent_hw(dev, - name, &clk_mux[i].hw, CLK_SET_RATE_PARENT, 1, 1); + name, &clk_mux[i - 1].hw, CLK_SET_RATE_PARENT, 1, 1); if (IS_ERR(clk_out[i])) return PTR_ERR(clk_out[i]); diff --git a/drivers/clk/sprd/ums512-clk.c b/drivers/clk/sprd/ums512-clk.c index 8f4441dd572b..9384ecc6c741 100644 --- a/drivers/clk/sprd/ums512-clk.c +++ b/drivers/clk/sprd/ums512-clk.c @@ -800,7 +800,7 @@ static SPRD_MUX_CLK_DATA(uart1_clk, "uart1-clk", uart_parents, 0x250, 0, 3, UMS512_MUX_FLAG); static const struct clk_parent_data thm_parents[] = { - { .fw_name = "ext-32m" }, + { .fw_name = "ext-32k" }, { .hw = &clk_250k.hw }, }; static SPRD_MUX_CLK_DATA(thm0_clk, "thm0-clk", thm_parents, diff --git a/drivers/clk/tegra/clk-bpmp.c b/drivers/clk/tegra/clk-bpmp.c index a9f3fb448de6..7bfba0afd778 100644 --- a/drivers/clk/tegra/clk-bpmp.c +++ b/drivers/clk/tegra/clk-bpmp.c @@ -159,7 +159,7 @@ static unsigned long tegra_bpmp_clk_recalc_rate(struct clk_hw *hw, err = tegra_bpmp_clk_transfer(clk->bpmp, &msg); if (err < 0) - return err; + return 0; return response.rate; } diff --git a/drivers/comedi/Kconfig b/drivers/comedi/Kconfig index 7a8d402f05be..9af280735cba 100644 --- a/drivers/comedi/Kconfig +++ b/drivers/comedi/Kconfig @@ -67,7 +67,6 @@ config COMEDI_TEST config COMEDI_PARPORT tristate "Parallel port support" - depends on HAS_IOPORT help Enable support for the standard parallel port. A cheap and easy way to get a few more digital I/O lines. Steal @@ -80,7 +79,6 @@ config COMEDI_PARPORT config COMEDI_SSV_DNP tristate "SSV Embedded Systems DIL/Net-PC support" depends on X86_32 || COMPILE_TEST - depends on HAS_IOPORT help Enable support for SSV Embedded Systems DIL/Net-PC @@ -91,7 +89,6 @@ endif # COMEDI_MISC_DRIVERS menuconfig COMEDI_ISA_DRIVERS bool "Comedi ISA and PC/104 drivers" - depends on ISA help Enable comedi ISA and PC/104 drivers to be built @@ -103,8 +100,7 @@ if COMEDI_ISA_DRIVERS config COMEDI_PCL711 tristate "Advantech PCL-711/711b and ADlink ACL-8112 ISA card support" - depends on HAS_IOPORT - depends on COMEDI_8254 + select COMEDI_8254 help Enable support for Advantech PCL-711 and 711b, ADlink ACL-8112 @@ -165,9 +161,8 @@ config COMEDI_PCL730 config COMEDI_PCL812 tristate "Advantech PCL-812/813 and ADlink ACL-8112/8113/8113/8216" - depends on HAS_IOPORT select COMEDI_ISADMA if ISA_DMA_API - depends on COMEDI_8254 + select COMEDI_8254 help Enable support for Advantech PCL-812/PG, PCL-813/B, ADLink ACL-8112DG/HG/PG, ACL-8113, ACL-8216, ICP DAS A-821PGH/PGL/PGL-NDA, @@ -178,9 +173,8 @@ config COMEDI_PCL812 config COMEDI_PCL816 tristate "Advantech PCL-814 and PCL-816 ISA card support" - depends on HAS_IOPORT select COMEDI_ISADMA if ISA_DMA_API - depends on COMEDI_8254 + select COMEDI_8254 help Enable support for Advantech PCL-814 and PCL-816 ISA cards @@ -189,9 +183,8 @@ config COMEDI_PCL816 config COMEDI_PCL818 tristate "Advantech PCL-718 and PCL-818 ISA card support" - depends on HAS_IOPORT select COMEDI_ISADMA if ISA_DMA_API - depends on COMEDI_8254 + select COMEDI_8254 help Enable support for Advantech PCL-818 ISA cards PCL-818L, PCL-818H, PCL-818HD, PCL-818HG, PCL-818 and PCL-718 @@ -210,7 +203,7 @@ config COMEDI_PCM3724 config COMEDI_AMPLC_DIO200_ISA tristate "Amplicon PC212E/PC214E/PC215E/PC218E/PC272E" - depends on COMEDI_AMPLC_DIO200 + select COMEDI_AMPLC_DIO200 help Enable support for Amplicon PC212E, PC214E, PC215E, PC218E and PC272E ISA DIO boards @@ -262,8 +255,7 @@ config COMEDI_DAC02 config COMEDI_DAS16M1 tristate "MeasurementComputing CIO-DAS16/M1DAS-16 ISA card support" - depends on HAS_IOPORT - depends on COMEDI_8254 + select COMEDI_8254 select COMEDI_8255 help Enable support for Measurement Computing CIO-DAS16/M1 ISA cards. @@ -273,7 +265,7 @@ config COMEDI_DAS16M1 config COMEDI_DAS08_ISA tristate "DAS-08 compatible ISA and PC/104 card support" - depends on COMEDI_DAS08 + select COMEDI_DAS08 help Enable support for Keithley Metrabyte/ComputerBoards DAS08 and compatible ISA and PC/104 cards: @@ -286,9 +278,8 @@ config COMEDI_DAS08_ISA config COMEDI_DAS16 tristate "DAS-16 compatible ISA and PC/104 card support" - depends on HAS_IOPORT select COMEDI_ISADMA if ISA_DMA_API - depends on COMEDI_8254 + select COMEDI_8254 select COMEDI_8255 help Enable support for Keithley Metrabyte/ComputerBoards DAS16 @@ -305,8 +296,7 @@ config COMEDI_DAS16 config COMEDI_DAS800 tristate "DAS800 and compatible ISA card support" - depends on HAS_IOPORT - depends on COMEDI_8254 + select COMEDI_8254 help Enable support for Keithley Metrabyte DAS800 and compatible ISA cards Keithley Metrabyte DAS-800, DAS-801, DAS-802 @@ -318,9 +308,8 @@ config COMEDI_DAS800 config COMEDI_DAS1800 tristate "DAS1800 and compatible ISA card support" - depends on HAS_IOPORT select COMEDI_ISADMA if ISA_DMA_API - depends on COMEDI_8254 + select COMEDI_8254 help Enable support for DAS1800 and compatible ISA cards Keithley Metrabyte DAS-1701ST, DAS-1701ST-DA, DAS-1701/AO, @@ -334,8 +323,7 @@ config COMEDI_DAS1800 config COMEDI_DAS6402 tristate "DAS6402 and compatible ISA card support" - depends on HAS_IOPORT - depends on COMEDI_8254 + select COMEDI_8254 help Enable support for DAS6402 and compatible ISA cards Computerboards, Keithley Metrabyte DAS6402 and compatibles @@ -414,8 +402,7 @@ config COMEDI_FL512 config COMEDI_AIO_AIO12_8 tristate "I/O Products PC/104 AIO12-8 Analog I/O Board support" - depends on HAS_IOPORT - depends on COMEDI_8254 + select COMEDI_8254 select COMEDI_8255 help Enable support for I/O Products PC/104 AIO12-8 Analog I/O Board @@ -469,9 +456,8 @@ config COMEDI_ADQ12B config COMEDI_NI_AT_A2150 tristate "NI AT-A2150 ISA card support" - depends on HAS_IOPORT select COMEDI_ISADMA if ISA_DMA_API - depends on COMEDI_8254 + select COMEDI_8254 help Enable support for National Instruments AT-A2150 cards @@ -480,8 +466,7 @@ config COMEDI_NI_AT_A2150 config COMEDI_NI_AT_AO tristate "NI AT-AO-6/10 EISA card support" - depends on HAS_IOPORT - depends on COMEDI_8254 + select COMEDI_8254 help Enable support for National Instruments AT-AO-6/10 cards @@ -512,7 +497,7 @@ config COMEDI_NI_ATMIO16D config COMEDI_NI_LABPC_ISA tristate "NI Lab-PC and compatibles ISA support" - depends on COMEDI_NI_LABPC + select COMEDI_NI_LABPC help Enable support for National Instruments Lab-PC and compatibles Lab-PC-1200, Lab-PC-1200AI, Lab-PC+. @@ -576,7 +561,7 @@ endif # COMEDI_ISA_DRIVERS menuconfig COMEDI_PCI_DRIVERS tristate "Comedi PCI drivers" - depends on PCI && HAS_IOPORT + depends on PCI help Enable support for comedi PCI drivers. @@ -725,8 +710,7 @@ config COMEDI_ADL_PCI8164 config COMEDI_ADL_PCI9111 tristate "ADLink PCI-9111HR support" - depends on HAS_IOPORT - depends on COMEDI_8254 + select COMEDI_8254 help Enable support for ADlink PCI9111 cards @@ -736,7 +720,7 @@ config COMEDI_ADL_PCI9111 config COMEDI_ADL_PCI9118 tristate "ADLink PCI-9118DG, PCI-9118HG, PCI-9118HR support" depends on HAS_DMA - depends on COMEDI_8254 + select COMEDI_8254 help Enable support for ADlink PCI-9118DG, PCI-9118HG, PCI-9118HR cards @@ -745,8 +729,7 @@ config COMEDI_ADL_PCI9118 config COMEDI_ADV_PCI1710 tristate "Advantech PCI-171x and PCI-1731 support" - depends on HAS_IOPORT - depends on COMEDI_8254 + select COMEDI_8254 help Enable support for Advantech PCI-1710, PCI-1710HG, PCI-1711, PCI-1713 and PCI-1731 @@ -790,8 +773,7 @@ config COMEDI_ADV_PCI1760 config COMEDI_ADV_PCI_DIO tristate "Advantech PCI DIO card support" - depends on HAS_IOPORT - depends on COMEDI_8254 + select COMEDI_8254 select COMEDI_8255 help Enable support for Advantech PCI DIO cards @@ -804,7 +786,7 @@ config COMEDI_ADV_PCI_DIO config COMEDI_AMPLC_DIO200_PCI tristate "Amplicon PCI215/PCI272/PCIe215/PCIe236/PCIe296 DIO support" - depends on COMEDI_AMPLC_DIO200 + select COMEDI_AMPLC_DIO200 help Enable support for Amplicon PCI215, PCI272, PCIe215, PCIe236 and PCIe296 DIO boards. @@ -832,8 +814,7 @@ config COMEDI_AMPLC_PC263_PCI config COMEDI_AMPLC_PCI224 tristate "Amplicon PCI224 and PCI234 support" - depends on HAS_IOPORT - depends on COMEDI_8254 + select COMEDI_8254 help Enable support for Amplicon PCI224 and PCI234 AO boards @@ -842,8 +823,7 @@ config COMEDI_AMPLC_PCI224 config COMEDI_AMPLC_PCI230 tristate "Amplicon PCI230 and PCI260 support" - depends on HAS_IOPORT - depends on COMEDI_8254 + select COMEDI_8254 select COMEDI_8255 help Enable support for Amplicon PCI230 and PCI260 Multifunction I/O @@ -862,7 +842,7 @@ config COMEDI_CONTEC_PCI_DIO config COMEDI_DAS08_PCI tristate "DAS-08 PCI support" - depends on COMEDI_DAS08 + select COMEDI_DAS08 help Enable support for PCI DAS-08 cards. @@ -949,8 +929,7 @@ config COMEDI_CB_PCIDAS64 config COMEDI_CB_PCIDAS tristate "MeasurementComputing PCI-DAS support" - depends on HAS_IOPORT - depends on COMEDI_8254 + select COMEDI_8254 select COMEDI_8255 help Enable support for ComputerBoards/MeasurementComputing PCI-DAS with @@ -974,8 +953,7 @@ config COMEDI_CB_PCIDDA config COMEDI_CB_PCIMDAS tristate "MeasurementComputing PCIM-DAS1602/16, PCIe-DAS1602/16 support" - depends on HAS_IOPORT - depends on COMEDI_8254 + select COMEDI_8254 select COMEDI_8255 help Enable support for ComputerBoards/MeasurementComputing PCI Migration @@ -995,8 +973,7 @@ config COMEDI_CB_PCIMDDA config COMEDI_ME4000 tristate "Meilhaus ME-4000 support" - depends on HAS_IOPORT - depends on COMEDI_8254 + select COMEDI_8254 help Enable support for Meilhaus PCI data acquisition cards ME-4650, ME-4670i, ME-4680, ME-4680i and ME-4680is @@ -1054,7 +1031,7 @@ config COMEDI_NI_670X config COMEDI_NI_LABPC_PCI tristate "NI Lab-PC PCI-1200 support" - depends on COMEDI_NI_LABPC + select COMEDI_NI_LABPC help Enable support for National Instruments Lab-PC PCI-1200. @@ -1076,7 +1053,6 @@ config COMEDI_NI_PCIDIO config COMEDI_NI_PCIMIO tristate "NI PCI-MIO-E series and M series support" depends on HAS_DMA - depends on HAS_IOPORT select COMEDI_NI_TIOCMD select COMEDI_8255 help @@ -1098,8 +1074,7 @@ config COMEDI_NI_PCIMIO config COMEDI_RTD520 tristate "Real Time Devices PCI4520/DM7520 support" - depends on HAS_IOPORT - depends on COMEDI_8254 + select COMEDI_8254 help Enable support for Real Time Devices PCI4520/DM7520 @@ -1139,8 +1114,7 @@ if COMEDI_PCMCIA_DRIVERS config COMEDI_CB_DAS16_CS tristate "CB DAS16 series PCMCIA support" - depends on HAS_IOPORT - depends on COMEDI_8254 + select COMEDI_8254 help Enable support for the ComputerBoards/MeasurementComputing PCMCIA cards DAS16/16, PCM-DAS16D/12 and PCM-DAS16s/16 @@ -1150,7 +1124,7 @@ config COMEDI_CB_DAS16_CS config COMEDI_DAS08_CS tristate "CB DAS08 PCMCIA support" - depends on COMEDI_DAS08 + select COMEDI_DAS08 help Enable support for the ComputerBoards/MeasurementComputing DAS-08 PCMCIA card @@ -1160,7 +1134,6 @@ config COMEDI_DAS08_CS config COMEDI_NI_DAQ_700_CS tristate "NI DAQCard-700 PCMCIA support" - depends on HAS_IOPORT help Enable support for the National Instruments PCMCIA DAQCard-700 DIO @@ -1169,7 +1142,6 @@ config COMEDI_NI_DAQ_700_CS config COMEDI_NI_DAQ_DIO24_CS tristate "NI DAQ-Card DIO-24 PCMCIA support" - depends on HAS_IOPORT select COMEDI_8255 help Enable support for the National Instruments PCMCIA DAQ-Card DIO-24 @@ -1179,7 +1151,7 @@ config COMEDI_NI_DAQ_DIO24_CS config COMEDI_NI_LABPC_CS tristate "NI DAQCard-1200 PCMCIA support" - depends on COMEDI_NI_LABPC + select COMEDI_NI_LABPC help Enable support for the National Instruments PCMCIA DAQCard-1200 @@ -1188,7 +1160,6 @@ config COMEDI_NI_LABPC_CS config COMEDI_NI_MIO_CS tristate "NI DAQCard E series PCMCIA support" - depends on HAS_IOPORT select COMEDI_NI_TIO select COMEDI_8255 help @@ -1201,7 +1172,6 @@ config COMEDI_NI_MIO_CS config COMEDI_QUATECH_DAQP_CS tristate "Quatech DAQP PCMCIA data capture card support" - depends on HAS_IOPORT help Enable support for the Quatech DAQP PCMCIA data capture cards DAQP-208 and DAQP-308 @@ -1278,14 +1248,12 @@ endif # COMEDI_USB_DRIVERS config COMEDI_8254 tristate - depends on HAS_IOPORT config COMEDI_8255 tristate config COMEDI_8255_SA tristate "Standalone 8255 support" - depends on HAS_IOPORT select COMEDI_8255 help Enable support for 8255 digital I/O as a standalone driver. @@ -1317,7 +1285,7 @@ config COMEDI_KCOMEDILIB called kcomedilib. config COMEDI_AMPLC_DIO200 - depends on COMEDI_8254 + select COMEDI_8254 tristate config COMEDI_AMPLC_PC236 @@ -1326,7 +1294,7 @@ config COMEDI_AMPLC_PC236 config COMEDI_DAS08 tristate - depends on COMEDI_8254 + select COMEDI_8254 select COMEDI_8255 config COMEDI_ISADMA @@ -1334,8 +1302,7 @@ config COMEDI_ISADMA config COMEDI_NI_LABPC tristate - depends on HAS_IOPORT - depends on COMEDI_8254 + select COMEDI_8254 select COMEDI_8255 config COMEDI_NI_LABPC_ISADMA diff --git a/drivers/cpufreq/scmi-cpufreq.c b/drivers/cpufreq/scmi-cpufreq.c index f34e6382a4c5..c8a7ccc42c16 100644 --- a/drivers/cpufreq/scmi-cpufreq.c +++ b/drivers/cpufreq/scmi-cpufreq.c @@ -70,16 +70,36 @@ static unsigned int scmi_cpufreq_fast_switch(struct cpufreq_policy *policy, return 0; } +static int scmi_cpu_domain_id(struct device *cpu_dev) +{ + struct device_node *np = cpu_dev->of_node; + struct of_phandle_args domain_id; + int index; + + if (of_parse_phandle_with_args(np, "clocks", "#clock-cells", 0, + &domain_id)) { + /* Find the corresponding index for power-domain "perf". */ + index = of_property_match_string(np, "power-domain-names", + "perf"); + if (index < 0) + return -EINVAL; + + if (of_parse_phandle_with_args(np, "power-domains", + "#power-domain-cells", index, + &domain_id)) + return -EINVAL; + } + + return domain_id.args[0]; +} + static int -scmi_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumask) +scmi_get_sharing_cpus(struct device *cpu_dev, int domain, + struct cpumask *cpumask) { - int cpu, domain, tdomain; + int cpu, tdomain; struct device *tcpu_dev; - domain = perf_ops->device_domain_id(cpu_dev); - if (domain < 0) - return domain; - for_each_possible_cpu(cpu) { if (cpu == cpu_dev->id) continue; @@ -88,7 +108,7 @@ scmi_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumask) if (!tcpu_dev) continue; - tdomain = perf_ops->device_domain_id(tcpu_dev); + tdomain = scmi_cpu_domain_id(tcpu_dev); if (tdomain == domain) cpumask_set_cpu(cpu, cpumask); } @@ -104,7 +124,7 @@ scmi_get_cpu_power(struct device *cpu_dev, unsigned long *power, unsigned long Hz; int ret, domain; - domain = perf_ops->device_domain_id(cpu_dev); + domain = scmi_cpu_domain_id(cpu_dev); if (domain < 0) return domain; @@ -126,7 +146,7 @@ scmi_get_cpu_power(struct device *cpu_dev, unsigned long *power, static int scmi_cpufreq_init(struct cpufreq_policy *policy) { - int ret, nr_opp; + int ret, nr_opp, domain; unsigned int latency; struct device *cpu_dev; struct scmi_data *priv; @@ -138,6 +158,10 @@ static int scmi_cpufreq_init(struct cpufreq_policy *policy) return -ENODEV; } + domain = scmi_cpu_domain_id(cpu_dev); + if (domain < 0) + return domain; + priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; @@ -148,7 +172,7 @@ static int scmi_cpufreq_init(struct cpufreq_policy *policy) } /* Obtain CPUs that share SCMI performance controls */ - ret = scmi_get_sharing_cpus(cpu_dev, policy->cpus); + ret = scmi_get_sharing_cpus(cpu_dev, domain, policy->cpus); if (ret) { dev_warn(cpu_dev, "failed to get sharing cpumask\n"); goto out_free_cpumask; @@ -176,7 +200,7 @@ static int scmi_cpufreq_init(struct cpufreq_policy *policy) */ nr_opp = dev_pm_opp_get_opp_count(cpu_dev); if (nr_opp <= 0) { - ret = perf_ops->device_opps_add(ph, cpu_dev); + ret = perf_ops->device_opps_add(ph, cpu_dev, domain); if (ret) { dev_warn(cpu_dev, "failed to add opps to the device\n"); goto out_free_cpumask; @@ -209,7 +233,7 @@ static int scmi_cpufreq_init(struct cpufreq_policy *policy) } priv->cpu_dev = cpu_dev; - priv->domain_id = perf_ops->device_domain_id(cpu_dev); + priv->domain_id = domain; policy->driver_data = priv; policy->freq_table = freq_table; @@ -217,14 +241,14 @@ static int scmi_cpufreq_init(struct cpufreq_policy *policy) /* SCMI allows DVFS request for any domain from any CPU */ policy->dvfs_possible_from_any_cpu = true; - latency = perf_ops->transition_latency_get(ph, cpu_dev); + latency = perf_ops->transition_latency_get(ph, domain); if (!latency) latency = CPUFREQ_ETERNAL; policy->cpuinfo.transition_latency = latency; policy->fast_switch_possible = - perf_ops->fast_switch_possible(ph, cpu_dev); + perf_ops->fast_switch_possible(ph, domain); return 0; diff --git a/drivers/cxl/acpi.c b/drivers/cxl/acpi.c index d1c559879dcc..40d055560e52 100644 --- a/drivers/cxl/acpi.c +++ b/drivers/cxl/acpi.c @@ -14,7 +14,7 @@ struct cxl_cxims_data { int nr_maps; - u64 xormaps[]; + u64 xormaps[] __counted_by(nr_maps); }; /* @@ -112,9 +112,9 @@ static int cxl_parse_cxims(union acpi_subtable_headers *header, void *arg, GFP_KERNEL); if (!cximsd) return -ENOMEM; + cximsd->nr_maps = nr_maps; memcpy(cximsd->xormaps, cxims->xormap_list, nr_maps * sizeof(*cximsd->xormaps)); - cximsd->nr_maps = nr_maps; cxlrd->platform_data = cximsd; return 0; diff --git a/drivers/cxl/core/mbox.c b/drivers/cxl/core/mbox.c index ca60bb8114f2..4df4f614f490 100644 --- a/drivers/cxl/core/mbox.c +++ b/drivers/cxl/core/mbox.c @@ -715,24 +715,25 @@ static void cxl_walk_cel(struct cxl_memdev_state *mds, size_t size, u8 *cel) for (i = 0; i < cel_entries; i++) { u16 opcode = le16_to_cpu(cel_entry[i].opcode); struct cxl_mem_command *cmd = cxl_mem_find_command(opcode); + int enabled = 0; - if (!cmd && (!cxl_is_poison_command(opcode) || - !cxl_is_security_command(opcode))) { - dev_dbg(dev, - "Opcode 0x%04x unsupported by driver\n", opcode); - continue; - } - - if (cmd) + if (cmd) { set_bit(cmd->info.id, mds->enabled_cmds); + enabled++; + } - if (cxl_is_poison_command(opcode)) + if (cxl_is_poison_command(opcode)) { cxl_set_poison_cmd_enabled(&mds->poison, opcode); + enabled++; + } - if (cxl_is_security_command(opcode)) + if (cxl_is_security_command(opcode)) { cxl_set_security_cmd_enabled(&mds->security, opcode); + enabled++; + } - dev_dbg(dev, "Opcode 0x%04x enabled\n", opcode); + dev_dbg(dev, "Opcode 0x%04x %s\n", opcode, + enabled ? "enabled" : "unsupported by driver"); } } diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c index 724be8448eb4..7ca01a834e18 100644 --- a/drivers/cxl/core/port.c +++ b/drivers/cxl/core/port.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only /* Copyright(c) 2020 Intel Corporation. All rights reserved. */ +#include <linux/platform_device.h> #include <linux/memregion.h> #include <linux/workqueue.h> #include <linux/debugfs.h> @@ -706,16 +707,20 @@ static int cxl_setup_comp_regs(struct device *dev, struct cxl_register_map *map, return cxl_setup_regs(map); } -static inline int cxl_port_setup_regs(struct cxl_port *port, - resource_size_t component_reg_phys) +static int cxl_port_setup_regs(struct cxl_port *port, + resource_size_t component_reg_phys) { + if (dev_is_platform(port->uport_dev)) + return 0; return cxl_setup_comp_regs(&port->dev, &port->comp_map, component_reg_phys); } -static inline int cxl_dport_setup_regs(struct cxl_dport *dport, - resource_size_t component_reg_phys) +static int cxl_dport_setup_regs(struct cxl_dport *dport, + resource_size_t component_reg_phys) { + if (dev_is_platform(dport->dport_dev)) + return 0; return cxl_setup_comp_regs(dport->dport_dev, &dport->comp_map, component_reg_phys); } diff --git a/drivers/cxl/core/region.c b/drivers/cxl/core/region.c index e115ba382e04..6d63b8798c29 100644 --- a/drivers/cxl/core/region.c +++ b/drivers/cxl/core/region.c @@ -717,13 +717,35 @@ static int match_free_decoder(struct device *dev, void *data) return 0; } +static int match_auto_decoder(struct device *dev, void *data) +{ + struct cxl_region_params *p = data; + struct cxl_decoder *cxld; + struct range *r; + + if (!is_switch_decoder(dev)) + return 0; + + cxld = to_cxl_decoder(dev); + r = &cxld->hpa_range; + + if (p->res && p->res->start == r->start && p->res->end == r->end) + return 1; + + return 0; +} + static struct cxl_decoder *cxl_region_find_decoder(struct cxl_port *port, struct cxl_region *cxlr) { struct device *dev; int id = 0; - dev = device_find_child(&port->dev, &id, match_free_decoder); + if (test_bit(CXL_REGION_F_AUTO, &cxlr->flags)) + dev = device_find_child(&port->dev, &cxlr->params, + match_auto_decoder); + else + dev = device_find_child(&port->dev, &id, match_free_decoder); if (!dev) return NULL; /* @@ -1154,16 +1176,15 @@ static int cxl_port_setup_targets(struct cxl_port *port, } /* - * If @parent_port is masking address bits, pick the next unused address - * bit to route @port's targets. + * Interleave granularity is a multiple of @parent_port granularity. + * Multiplier is the parent port interleave ways. */ - if (parent_iw > 1 && cxl_rr->nr_targets > 1) { - u32 address_bit = max(peig + peiw, eiw + peig); - - eig = address_bit - eiw + 1; - } else { - eiw = peiw; - eig = peig; + rc = granularity_to_eig(parent_ig * parent_iw, &eig); + if (rc) { + dev_dbg(&cxlr->dev, + "%s: invalid granularity calculation (%d * %d)\n", + dev_name(&parent_port->dev), parent_ig, parent_iw); + return rc; } rc = eig_to_granularity(eig, &ig); diff --git a/drivers/cxl/pci.c b/drivers/cxl/pci.c index 1cb1494c28fe..44a21ab7add5 100644 --- a/drivers/cxl/pci.c +++ b/drivers/cxl/pci.c @@ -529,7 +529,6 @@ static int cxl_pci_setup_regs(struct pci_dev *pdev, enum cxl_regloc_type type, static int cxl_pci_ras_unmask(struct pci_dev *pdev) { - struct pci_host_bridge *host_bridge = pci_find_host_bridge(pdev->bus); struct cxl_dev_state *cxlds = pci_get_drvdata(pdev); void __iomem *addr; u32 orig_val, val, mask; @@ -541,9 +540,9 @@ static int cxl_pci_ras_unmask(struct pci_dev *pdev) return 0; } - /* BIOS has CXL error control */ - if (!host_bridge->native_cxl_error) - return -ENXIO; + /* BIOS has PCIe AER error control */ + if (!pcie_aer_is_native(pdev)) + return 0; rc = pcie_capability_read_word(pdev, PCI_EXP_DEVCTL, &cap); if (rc) diff --git a/drivers/firewire/core-device.c b/drivers/firewire/core-device.c index a3104e35412c..aa597cda0d88 100644 --- a/drivers/firewire/core-device.c +++ b/drivers/firewire/core-device.c @@ -1211,7 +1211,7 @@ void fw_node_event(struct fw_card *card, struct fw_node *node, int event) * without actually having a link. */ create: - device = kzalloc(sizeof(*device), GFP_KERNEL); + device = kzalloc(sizeof(*device), GFP_ATOMIC); if (device == NULL) break; diff --git a/drivers/firewire/core-topology.c b/drivers/firewire/core-topology.c index 88466b663482..f40c81534381 100644 --- a/drivers/firewire/core-topology.c +++ b/drivers/firewire/core-topology.c @@ -101,7 +101,7 @@ static struct fw_node *fw_node_create(u32 sid, int port_count, int color) { struct fw_node *node; - node = kzalloc(struct_size(node, ports, port_count), GFP_KERNEL); + node = kzalloc(struct_size(node, ports, port_count), GFP_ATOMIC); if (node == NULL) return NULL; diff --git a/drivers/firewire/sbp2.c b/drivers/firewire/sbp2.c index 26db5b8dfc1e..749868b9e80d 100644 --- a/drivers/firewire/sbp2.c +++ b/drivers/firewire/sbp2.c @@ -81,7 +81,8 @@ MODULE_PARM_DESC(exclusive_login, "Exclusive login to sbp2 device " * * - power condition * Set the power condition field in the START STOP UNIT commands sent by - * sd_mod on suspend, resume, and shutdown (if manage_start_stop is on). + * sd_mod on suspend, resume, and shutdown (if manage_system_start_stop or + * manage_runtime_start_stop is on). * Some disks need this to spin down or to resume properly. * * - override internal blacklist @@ -1517,8 +1518,10 @@ static int sbp2_scsi_slave_configure(struct scsi_device *sdev) sdev->use_10_for_rw = 1; - if (sbp2_param_exclusive_login) - sdev->manage_start_stop = 1; + if (sbp2_param_exclusive_login) { + sdev->manage_system_start_stop = true; + sdev->manage_runtime_start_stop = true; + } if (sdev->type == TYPE_ROM) sdev->use_10_for_ms = 1; diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig index b59e3041fd62..8c608be30060 100644 --- a/drivers/firmware/Kconfig +++ b/drivers/firmware/Kconfig @@ -226,6 +226,39 @@ config QCOM_SCM_DOWNLOAD_MODE_DEFAULT Say Y here to enable "download mode" by default. +config QCOM_QSEECOM + bool "Qualcomm QSEECOM interface driver" + depends on QCOM_SCM=y + select AUXILIARY_BUS + help + Various Qualcomm SoCs have a Secure Execution Environment (SEE) running + in the Trust Zone. This module provides an interface to that via the + QSEECOM mechanism, using SCM calls. + + The QSEECOM interface allows, among other things, access to applications + running in the SEE. An example of such an application is 'uefisecapp', + which is required to access UEFI variables on certain systems. If + selected, the interface will also attempt to detect and register client + devices for supported applications. + + Select Y here to enable the QSEECOM interface driver. + +config QCOM_QSEECOM_UEFISECAPP + bool "Qualcomm SEE UEFI Secure App client driver" + depends on QCOM_QSEECOM + depends on EFI + help + Various Qualcomm SoCs do not allow direct access to EFI variables. + Instead, these need to be accessed via the UEFI Secure Application + (uefisecapp), residing in the Secure Execution Environment (SEE). + + This module provides a client driver for uefisecapp, installing efivar + operations to allow the kernel accessing EFI variables, and via that also + provide user-space with access to EFI variables via efivarfs. + + Select Y here to provide access to EFI variables on the aforementioned + platforms. + config SYSFB bool select BOOT_VESA_SUPPORT diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile index 28fcddcd688f..d41b094a5e58 100644 --- a/drivers/firmware/Makefile +++ b/drivers/firmware/Makefile @@ -20,6 +20,8 @@ obj-$(CONFIG_RASPBERRYPI_FIRMWARE) += raspberrypi.o obj-$(CONFIG_FW_CFG_SYSFS) += qemu_fw_cfg.o obj-$(CONFIG_QCOM_SCM) += qcom-scm.o qcom-scm-objs += qcom_scm.o qcom_scm-smc.o qcom_scm-legacy.o +obj-$(CONFIG_QCOM_QSEECOM) += qcom_qseecom.o +obj-$(CONFIG_QCOM_QSEECOM_UEFISECAPP) += qcom_qseecom_uefisecapp.o obj-$(CONFIG_SYSFB) += sysfb.o obj-$(CONFIG_SYSFB_SIMPLEFB) += sysfb_simplefb.o obj-$(CONFIG_TI_SCI_PROTOCOL) += ti_sci.o diff --git a/drivers/firmware/arm_ffa/bus.c b/drivers/firmware/arm_ffa/bus.c index 2b8bfcd010f5..1c7940ba5539 100644 --- a/drivers/firmware/arm_ffa/bus.c +++ b/drivers/firmware/arm_ffa/bus.c @@ -15,6 +15,8 @@ #include "common.h" +#define SCMI_UEVENT_MODALIAS_FMT "arm_ffa:%04x:%pUb" + static DEFINE_IDA(ffa_bus_id); static int ffa_device_match(struct device *dev, struct device_driver *drv) @@ -63,10 +65,20 @@ static int ffa_device_uevent(const struct device *dev, struct kobj_uevent_env *e { const struct ffa_device *ffa_dev = to_ffa_dev(dev); - return add_uevent_var(env, "MODALIAS=arm_ffa:%04x:%pUb", + return add_uevent_var(env, "MODALIAS=" SCMI_UEVENT_MODALIAS_FMT, ffa_dev->vm_id, &ffa_dev->uuid); } +static ssize_t modalias_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ffa_device *ffa_dev = to_ffa_dev(dev); + + return sysfs_emit(buf, SCMI_UEVENT_MODALIAS_FMT, ffa_dev->vm_id, + &ffa_dev->uuid); +} +static DEVICE_ATTR_RO(modalias); + static ssize_t partition_id_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -88,6 +100,7 @@ static DEVICE_ATTR_RO(uuid); static struct attribute *ffa_device_attributes_attrs[] = { &dev_attr_partition_id.attr, &dev_attr_uuid.attr, + &dev_attr_modalias.attr, NULL, }; ATTRIBUTE_GROUPS(ffa_device_attributes); @@ -193,6 +206,7 @@ struct ffa_device *ffa_device_register(const uuid_t *uuid, int vm_id, dev->release = ffa_release_device; dev_set_name(&ffa_dev->dev, "arm-ffa-%d", id); + ffa_dev->id = id; ffa_dev->vm_id = vm_id; ffa_dev->ops = ops; uuid_copy(&ffa_dev->uuid, uuid); diff --git a/drivers/firmware/arm_ffa/driver.c b/drivers/firmware/arm_ffa/driver.c index 2109cd178ff7..07b72c679247 100644 --- a/drivers/firmware/arm_ffa/driver.c +++ b/drivers/firmware/arm_ffa/driver.c @@ -22,20 +22,28 @@ #define DRIVER_NAME "ARM FF-A" #define pr_fmt(fmt) DRIVER_NAME ": " fmt +#include <linux/acpi.h> #include <linux/arm_ffa.h> #include <linux/bitfield.h> +#include <linux/cpuhotplug.h> #include <linux/device.h> +#include <linux/hashtable.h> +#include <linux/interrupt.h> #include <linux/io.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/mm.h> +#include <linux/mutex.h> +#include <linux/of_irq.h> #include <linux/scatterlist.h> #include <linux/slab.h> +#include <linux/smp.h> #include <linux/uuid.h> +#include <linux/xarray.h> #include "common.h" -#define FFA_DRIVER_VERSION FFA_VERSION_1_0 +#define FFA_DRIVER_VERSION FFA_VERSION_1_1 #define FFA_MIN_VERSION FFA_VERSION_1_0 #define SENDER_ID_MASK GENMASK(31, 16) @@ -51,6 +59,8 @@ */ #define RXTX_BUFFER_SIZE SZ_4K +#define FFA_MAX_NOTIFICATIONS 64 + static ffa_fn *invoke_ffa_fn; static const int ffa_linux_errmap[] = { @@ -64,6 +74,7 @@ static const int ffa_linux_errmap[] = { -EACCES, /* FFA_RET_DENIED */ -EAGAIN, /* FFA_RET_RETRY */ -ECANCELED, /* FFA_RET_ABORTED */ + -ENODATA, /* FFA_RET_NO_DATA */ }; static inline int ffa_to_linux_errno(int errno) @@ -75,6 +86,10 @@ static inline int ffa_to_linux_errno(int errno) return -EINVAL; } +struct ffa_pcpu_irq { + struct ffa_drv_info *info; +}; + struct ffa_drv_info { u32 version; u16 vm_id; @@ -83,6 +98,17 @@ struct ffa_drv_info { void *rx_buffer; void *tx_buffer; bool mem_ops_native; + bool bitmap_created; + unsigned int sched_recv_irq; + unsigned int cpuhp_state; + struct ffa_pcpu_irq __percpu *irq_pcpu; + struct workqueue_struct *notif_pcpu_wq; + struct work_struct notif_pcpu_work; + struct work_struct irq_work; + struct xarray partition_info; + unsigned int partition_count; + DECLARE_HASHTABLE(notifier_hash, ilog2(FFA_MAX_NOTIFICATIONS)); + struct mutex notify_lock; /* lock to protect notifier hashtable */ }; static struct ffa_drv_info *drv_info; @@ -397,45 +423,66 @@ static u32 ffa_get_num_pages_sg(struct scatterlist *sg) return num_pages; } +static u16 ffa_memory_attributes_get(u32 func_id) +{ + /* + * For the memory lend or donate operation, if the receiver is a PE or + * a proxy endpoint, the owner/sender must not specify the attributes + */ + if (func_id == FFA_FN_NATIVE(MEM_LEND) || + func_id == FFA_MEM_LEND) + return 0; + + return FFA_MEM_NORMAL | FFA_MEM_WRITE_BACK | FFA_MEM_INNER_SHAREABLE; +} + static int ffa_setup_and_transmit(u32 func_id, void *buffer, u32 max_fragsize, struct ffa_mem_ops_args *args) { int rc = 0; bool first = true; + u32 composite_offset; phys_addr_t addr = 0; + struct ffa_mem_region *mem_region = buffer; struct ffa_composite_mem_region *composite; struct ffa_mem_region_addr_range *constituents; struct ffa_mem_region_attributes *ep_mem_access; - struct ffa_mem_region *mem_region = buffer; u32 idx, frag_len, length, buf_sz = 0, num_entries = sg_nents(args->sg); mem_region->tag = args->tag; mem_region->flags = args->flags; mem_region->sender_id = drv_info->vm_id; - mem_region->attributes = FFA_MEM_NORMAL | FFA_MEM_WRITE_BACK | - FFA_MEM_INNER_SHAREABLE; - ep_mem_access = &mem_region->ep_mem_access[0]; + mem_region->attributes = ffa_memory_attributes_get(func_id); + ep_mem_access = buffer + + ffa_mem_desc_offset(buffer, 0, drv_info->version); + composite_offset = ffa_mem_desc_offset(buffer, args->nattrs, + drv_info->version); for (idx = 0; idx < args->nattrs; idx++, ep_mem_access++) { ep_mem_access->receiver = args->attrs[idx].receiver; ep_mem_access->attrs = args->attrs[idx].attrs; - ep_mem_access->composite_off = COMPOSITE_OFFSET(args->nattrs); + ep_mem_access->composite_off = composite_offset; ep_mem_access->flag = 0; ep_mem_access->reserved = 0; } mem_region->handle = 0; - mem_region->reserved_0 = 0; - mem_region->reserved_1 = 0; mem_region->ep_count = args->nattrs; + if (drv_info->version <= FFA_VERSION_1_0) { + mem_region->ep_mem_size = 0; + } else { + mem_region->ep_mem_size = sizeof(*ep_mem_access); + mem_region->ep_mem_offset = sizeof(*mem_region); + memset(mem_region->reserved, 0, 12); + } - composite = buffer + COMPOSITE_OFFSET(args->nattrs); + composite = buffer + composite_offset; composite->total_pg_cnt = ffa_get_num_pages_sg(args->sg); composite->addr_range_cnt = num_entries; composite->reserved = 0; - length = COMPOSITE_CONSTITUENTS_OFFSET(args->nattrs, num_entries); - frag_len = COMPOSITE_CONSTITUENTS_OFFSET(args->nattrs, 0); + length = composite_offset + CONSTITUENTS_OFFSET(num_entries); + frag_len = composite_offset + CONSTITUENTS_OFFSET(0); if (frag_len > max_fragsize) return -ENXIO; @@ -542,6 +589,236 @@ static int ffa_features(u32 func_feat_id, u32 input_props, return 0; } +static int ffa_notification_bitmap_create(void) +{ + ffa_value_t ret; + u16 vcpu_count = nr_cpu_ids; + + invoke_ffa_fn((ffa_value_t){ + .a0 = FFA_NOTIFICATION_BITMAP_CREATE, + .a1 = drv_info->vm_id, .a2 = vcpu_count, + }, &ret); + + if (ret.a0 == FFA_ERROR) + return ffa_to_linux_errno((int)ret.a2); + + return 0; +} + +static int ffa_notification_bitmap_destroy(void) +{ + ffa_value_t ret; + + invoke_ffa_fn((ffa_value_t){ + .a0 = FFA_NOTIFICATION_BITMAP_DESTROY, + .a1 = drv_info->vm_id, + }, &ret); + + if (ret.a0 == FFA_ERROR) + return ffa_to_linux_errno((int)ret.a2); + + return 0; +} + +#define NOTIFICATION_LOW_MASK GENMASK(31, 0) +#define NOTIFICATION_HIGH_MASK GENMASK(63, 32) +#define NOTIFICATION_BITMAP_HIGH(x) \ + ((u32)(FIELD_GET(NOTIFICATION_HIGH_MASK, (x)))) +#define NOTIFICATION_BITMAP_LOW(x) \ + ((u32)(FIELD_GET(NOTIFICATION_LOW_MASK, (x)))) +#define PACK_NOTIFICATION_BITMAP(low, high) \ + (FIELD_PREP(NOTIFICATION_LOW_MASK, (low)) | \ + FIELD_PREP(NOTIFICATION_HIGH_MASK, (high))) + +#define RECEIVER_VCPU_MASK GENMASK(31, 16) +#define PACK_NOTIFICATION_GET_RECEIVER_INFO(vcpu_r, r) \ + (FIELD_PREP(RECEIVER_VCPU_MASK, (vcpu_r)) | \ + FIELD_PREP(RECEIVER_ID_MASK, (r))) + +#define NOTIFICATION_INFO_GET_MORE_PEND_MASK BIT(0) +#define NOTIFICATION_INFO_GET_ID_COUNT GENMASK(11, 7) +#define ID_LIST_MASK_64 GENMASK(51, 12) +#define ID_LIST_MASK_32 GENMASK(31, 12) +#define MAX_IDS_64 20 +#define MAX_IDS_32 10 + +#define PER_VCPU_NOTIFICATION_FLAG BIT(0) +#define SECURE_PARTITION_BITMAP BIT(0) +#define NON_SECURE_VM_BITMAP BIT(1) +#define SPM_FRAMEWORK_BITMAP BIT(2) +#define NS_HYP_FRAMEWORK_BITMAP BIT(3) + +static int ffa_notification_bind_common(u16 dst_id, u64 bitmap, + u32 flags, bool is_bind) +{ + ffa_value_t ret; + u32 func, src_dst_ids = PACK_TARGET_INFO(dst_id, drv_info->vm_id); + + func = is_bind ? FFA_NOTIFICATION_BIND : FFA_NOTIFICATION_UNBIND; + + invoke_ffa_fn((ffa_value_t){ + .a0 = func, .a1 = src_dst_ids, .a2 = flags, + .a3 = NOTIFICATION_BITMAP_LOW(bitmap), + .a4 = NOTIFICATION_BITMAP_HIGH(bitmap), + }, &ret); + + if (ret.a0 == FFA_ERROR) + return ffa_to_linux_errno((int)ret.a2); + else if (ret.a0 != FFA_SUCCESS) + return -EINVAL; + + return 0; +} + +static +int ffa_notification_set(u16 src_id, u16 dst_id, u32 flags, u64 bitmap) +{ + ffa_value_t ret; + u32 src_dst_ids = PACK_TARGET_INFO(dst_id, src_id); + + invoke_ffa_fn((ffa_value_t) { + .a0 = FFA_NOTIFICATION_SET, .a1 = src_dst_ids, .a2 = flags, + .a3 = NOTIFICATION_BITMAP_LOW(bitmap), + .a4 = NOTIFICATION_BITMAP_HIGH(bitmap), + }, &ret); + + if (ret.a0 == FFA_ERROR) + return ffa_to_linux_errno((int)ret.a2); + else if (ret.a0 != FFA_SUCCESS) + return -EINVAL; + + return 0; +} + +struct ffa_notify_bitmaps { + u64 sp_map; + u64 vm_map; + u64 arch_map; +}; + +static int ffa_notification_get(u32 flags, struct ffa_notify_bitmaps *notify) +{ + ffa_value_t ret; + u16 src_id = drv_info->vm_id; + u16 cpu_id = smp_processor_id(); + u32 rec_vcpu_ids = PACK_NOTIFICATION_GET_RECEIVER_INFO(cpu_id, src_id); + + invoke_ffa_fn((ffa_value_t){ + .a0 = FFA_NOTIFICATION_GET, .a1 = rec_vcpu_ids, .a2 = flags, + }, &ret); + + if (ret.a0 == FFA_ERROR) + return ffa_to_linux_errno((int)ret.a2); + else if (ret.a0 != FFA_SUCCESS) + return -EINVAL; /* Something else went wrong. */ + + notify->sp_map = PACK_NOTIFICATION_BITMAP(ret.a2, ret.a3); + notify->vm_map = PACK_NOTIFICATION_BITMAP(ret.a4, ret.a5); + notify->arch_map = PACK_NOTIFICATION_BITMAP(ret.a6, ret.a7); + + return 0; +} + +struct ffa_dev_part_info { + ffa_sched_recv_cb callback; + void *cb_data; + rwlock_t rw_lock; +}; + +static void __do_sched_recv_cb(u16 part_id, u16 vcpu, bool is_per_vcpu) +{ + struct ffa_dev_part_info *partition; + ffa_sched_recv_cb callback; + void *cb_data; + + partition = xa_load(&drv_info->partition_info, part_id); + read_lock(&partition->rw_lock); + callback = partition->callback; + cb_data = partition->cb_data; + read_unlock(&partition->rw_lock); + + if (callback) + callback(vcpu, is_per_vcpu, cb_data); +} + +static void ffa_notification_info_get(void) +{ + int idx, list, max_ids, lists_cnt, ids_processed, ids_count[MAX_IDS_64]; + bool is_64b_resp; + ffa_value_t ret; + u64 id_list; + + do { + invoke_ffa_fn((ffa_value_t){ + .a0 = FFA_FN_NATIVE(NOTIFICATION_INFO_GET), + }, &ret); + + if (ret.a0 != FFA_FN_NATIVE(SUCCESS) && ret.a0 != FFA_SUCCESS) { + if (ret.a2 != FFA_RET_NO_DATA) + pr_err("Notification Info fetch failed: 0x%lx (0x%lx)", + ret.a0, ret.a2); + return; + } + + is_64b_resp = (ret.a0 == FFA_FN64_SUCCESS); + + ids_processed = 0; + lists_cnt = FIELD_GET(NOTIFICATION_INFO_GET_ID_COUNT, ret.a2); + if (is_64b_resp) { + max_ids = MAX_IDS_64; + id_list = FIELD_GET(ID_LIST_MASK_64, ret.a2); + } else { + max_ids = MAX_IDS_32; + id_list = FIELD_GET(ID_LIST_MASK_32, ret.a2); + } + + for (idx = 0; idx < lists_cnt; idx++, id_list >>= 2) + ids_count[idx] = (id_list & 0x3) + 1; + + /* Process IDs */ + for (list = 0; list < lists_cnt; list++) { + u16 vcpu_id, part_id, *packed_id_list = (u16 *)&ret.a3; + + if (ids_processed >= max_ids - 1) + break; + + part_id = packed_id_list[++ids_processed]; + + if (!ids_count[list]) { /* Global Notification */ + __do_sched_recv_cb(part_id, 0, false); + continue; + } + + /* Per vCPU Notification */ + for (idx = 0; idx < ids_count[list]; idx++) { + if (ids_processed >= max_ids - 1) + break; + + vcpu_id = packed_id_list[++ids_processed]; + + __do_sched_recv_cb(part_id, vcpu_id, true); + } + } + } while (ret.a2 & NOTIFICATION_INFO_GET_MORE_PEND_MASK); +} + +static int ffa_run(struct ffa_device *dev, u16 vcpu) +{ + ffa_value_t ret; + u32 target = dev->vm_id << 16 | vcpu; + + invoke_ffa_fn((ffa_value_t){ .a0 = FFA_RUN, .a1 = target, }, &ret); + + while (ret.a0 == FFA_INTERRUPT) + invoke_ffa_fn((ffa_value_t){ .a0 = FFA_RUN, .a1 = ret.a1, }, + &ret); + + if (ret.a0 == FFA_ERROR) + return ffa_to_linux_errno((int)ret.a2); + + return 0; +} + static void ffa_set_up_mem_ops_native_flag(void) { if (!ffa_features(FFA_FN_NATIVE(MEM_LEND), 0, NULL, NULL) || @@ -575,17 +852,9 @@ static int ffa_partition_info_get(const char *uuid_str, return 0; } -static void _ffa_mode_32bit_set(struct ffa_device *dev) -{ - dev->mode_32bit = true; -} - static void ffa_mode_32bit_set(struct ffa_device *dev) { - if (drv_info->version > FFA_VERSION_1_0) - return; - - _ffa_mode_32bit_set(dev); + dev->mode_32bit = true; } static int ffa_sync_send_receive(struct ffa_device *dev, @@ -618,6 +887,231 @@ static int ffa_memory_lend(struct ffa_mem_ops_args *args) return ffa_memory_ops(FFA_MEM_LEND, args); } +#define FFA_SECURE_PARTITION_ID_FLAG BIT(15) + +enum notify_type { + NON_SECURE_VM, + SECURE_PARTITION, + FRAMEWORK, +}; + +struct notifier_cb_info { + struct hlist_node hnode; + ffa_notifier_cb cb; + void *cb_data; + enum notify_type type; +}; + +static int ffa_sched_recv_cb_update(u16 part_id, ffa_sched_recv_cb callback, + void *cb_data, bool is_registration) +{ + struct ffa_dev_part_info *partition; + bool cb_valid; + + partition = xa_load(&drv_info->partition_info, part_id); + write_lock(&partition->rw_lock); + + cb_valid = !!partition->callback; + if (!(is_registration ^ cb_valid)) { + write_unlock(&partition->rw_lock); + return -EINVAL; + } + + partition->callback = callback; + partition->cb_data = cb_data; + + write_unlock(&partition->rw_lock); + return 0; +} + +static int ffa_sched_recv_cb_register(struct ffa_device *dev, + ffa_sched_recv_cb cb, void *cb_data) +{ + return ffa_sched_recv_cb_update(dev->vm_id, cb, cb_data, true); +} + +static int ffa_sched_recv_cb_unregister(struct ffa_device *dev) +{ + return ffa_sched_recv_cb_update(dev->vm_id, NULL, NULL, false); +} + +static int ffa_notification_bind(u16 dst_id, u64 bitmap, u32 flags) +{ + return ffa_notification_bind_common(dst_id, bitmap, flags, true); +} + +static int ffa_notification_unbind(u16 dst_id, u64 bitmap) +{ + return ffa_notification_bind_common(dst_id, bitmap, 0, false); +} + +/* Should be called while the notify_lock is taken */ +static struct notifier_cb_info * +notifier_hash_node_get(u16 notify_id, enum notify_type type) +{ + struct notifier_cb_info *node; + + hash_for_each_possible(drv_info->notifier_hash, node, hnode, notify_id) + if (type == node->type) + return node; + + return NULL; +} + +static int +update_notifier_cb(int notify_id, enum notify_type type, ffa_notifier_cb cb, + void *cb_data, bool is_registration) +{ + struct notifier_cb_info *cb_info = NULL; + bool cb_found; + + cb_info = notifier_hash_node_get(notify_id, type); + cb_found = !!cb_info; + + if (!(is_registration ^ cb_found)) + return -EINVAL; + + if (is_registration) { + cb_info = kzalloc(sizeof(*cb_info), GFP_KERNEL); + if (!cb_info) + return -ENOMEM; + + cb_info->type = type; + cb_info->cb = cb; + cb_info->cb_data = cb_data; + + hash_add(drv_info->notifier_hash, &cb_info->hnode, notify_id); + } else { + hash_del(&cb_info->hnode); + } + + return 0; +} + +static enum notify_type ffa_notify_type_get(u16 vm_id) +{ + if (vm_id & FFA_SECURE_PARTITION_ID_FLAG) + return SECURE_PARTITION; + else + return NON_SECURE_VM; +} + +static int ffa_notify_relinquish(struct ffa_device *dev, int notify_id) +{ + int rc; + enum notify_type type = ffa_notify_type_get(dev->vm_id); + + if (notify_id >= FFA_MAX_NOTIFICATIONS) + return -EINVAL; + + mutex_lock(&drv_info->notify_lock); + + rc = update_notifier_cb(notify_id, type, NULL, NULL, false); + if (rc) { + pr_err("Could not unregister notification callback\n"); + mutex_unlock(&drv_info->notify_lock); + return rc; + } + + rc = ffa_notification_unbind(dev->vm_id, BIT(notify_id)); + + mutex_unlock(&drv_info->notify_lock); + + return rc; +} + +static int ffa_notify_request(struct ffa_device *dev, bool is_per_vcpu, + ffa_notifier_cb cb, void *cb_data, int notify_id) +{ + int rc; + u32 flags = 0; + enum notify_type type = ffa_notify_type_get(dev->vm_id); + + if (notify_id >= FFA_MAX_NOTIFICATIONS) + return -EINVAL; + + mutex_lock(&drv_info->notify_lock); + + if (is_per_vcpu) + flags = PER_VCPU_NOTIFICATION_FLAG; + + rc = ffa_notification_bind(dev->vm_id, BIT(notify_id), flags); + if (rc) { + mutex_unlock(&drv_info->notify_lock); + return rc; + } + + rc = update_notifier_cb(notify_id, type, cb, cb_data, true); + if (rc) { + pr_err("Failed to register callback for %d - %d\n", + notify_id, rc); + ffa_notification_unbind(dev->vm_id, BIT(notify_id)); + } + mutex_unlock(&drv_info->notify_lock); + + return rc; +} + +static int ffa_notify_send(struct ffa_device *dev, int notify_id, + bool is_per_vcpu, u16 vcpu) +{ + u32 flags = 0; + + if (is_per_vcpu) + flags |= (PER_VCPU_NOTIFICATION_FLAG | vcpu << 16); + + return ffa_notification_set(dev->vm_id, drv_info->vm_id, flags, + BIT(notify_id)); +} + +static void handle_notif_callbacks(u64 bitmap, enum notify_type type) +{ + int notify_id; + struct notifier_cb_info *cb_info = NULL; + + for (notify_id = 0; notify_id <= FFA_MAX_NOTIFICATIONS && bitmap; + notify_id++, bitmap >>= 1) { + if (!(bitmap & 1)) + continue; + + mutex_lock(&drv_info->notify_lock); + cb_info = notifier_hash_node_get(notify_id, type); + mutex_unlock(&drv_info->notify_lock); + + if (cb_info && cb_info->cb) + cb_info->cb(notify_id, cb_info->cb_data); + } +} + +static void notif_pcpu_irq_work_fn(struct work_struct *work) +{ + int rc; + struct ffa_notify_bitmaps bitmaps; + + rc = ffa_notification_get(SECURE_PARTITION_BITMAP | + SPM_FRAMEWORK_BITMAP, &bitmaps); + if (rc) { + pr_err("Failed to retrieve notifications with %d!\n", rc); + return; + } + + handle_notif_callbacks(bitmaps.vm_map, NON_SECURE_VM); + handle_notif_callbacks(bitmaps.sp_map, SECURE_PARTITION); + handle_notif_callbacks(bitmaps.arch_map, FRAMEWORK); +} + +static void +ffa_self_notif_handle(u16 vcpu, bool is_per_vcpu, void *cb_data) +{ + struct ffa_drv_info *info = cb_data; + + if (!is_per_vcpu) + notif_pcpu_irq_work_fn(&info->notif_pcpu_work); + else + queue_work_on(vcpu, info->notif_pcpu_wq, + &info->notif_pcpu_work); +} + static const struct ffa_info_ops ffa_drv_info_ops = { .api_version_get = ffa_api_version_get, .partition_info_get = ffa_partition_info_get, @@ -634,10 +1128,24 @@ static const struct ffa_mem_ops ffa_drv_mem_ops = { .memory_lend = ffa_memory_lend, }; +static const struct ffa_cpu_ops ffa_drv_cpu_ops = { + .run = ffa_run, +}; + +static const struct ffa_notifier_ops ffa_drv_notifier_ops = { + .sched_recv_cb_register = ffa_sched_recv_cb_register, + .sched_recv_cb_unregister = ffa_sched_recv_cb_unregister, + .notify_request = ffa_notify_request, + .notify_relinquish = ffa_notify_relinquish, + .notify_send = ffa_notify_send, +}; + static const struct ffa_ops ffa_drv_ops = { .info_ops = &ffa_drv_info_ops, .msg_ops = &ffa_drv_msg_ops, .mem_ops = &ffa_drv_mem_ops, + .cpu_ops = &ffa_drv_cpu_ops, + .notifier_ops = &ffa_drv_notifier_ops, }; void ffa_device_match_uuid(struct ffa_device *ffa_dev, const uuid_t *uuid) @@ -668,6 +1176,7 @@ static void ffa_setup_partitions(void) int count, idx; uuid_t uuid; struct ffa_device *ffa_dev; + struct ffa_dev_part_info *info; struct ffa_partition_info *pbuf, *tpbuf; count = ffa_partition_probe(&uuid_null, &pbuf); @@ -676,6 +1185,7 @@ static void ffa_setup_partitions(void) return; } + xa_init(&drv_info->partition_info); for (idx = 0, tpbuf = pbuf; idx < count; idx++, tpbuf++) { import_uuid(&uuid, (u8 *)tpbuf->uuid); @@ -694,9 +1204,232 @@ static void ffa_setup_partitions(void) if (drv_info->version > FFA_VERSION_1_0 && !(tpbuf->properties & FFA_PARTITION_AARCH64_EXEC)) - _ffa_mode_32bit_set(ffa_dev); + ffa_mode_32bit_set(ffa_dev); + + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (!info) { + ffa_device_unregister(ffa_dev); + continue; + } + xa_store(&drv_info->partition_info, tpbuf->id, info, GFP_KERNEL); } + drv_info->partition_count = count; + kfree(pbuf); + + /* Allocate for the host */ + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (!info) + return; + xa_store(&drv_info->partition_info, drv_info->vm_id, info, GFP_KERNEL); + drv_info->partition_count++; +} + +static void ffa_partitions_cleanup(void) +{ + struct ffa_dev_part_info **info; + int idx, count = drv_info->partition_count; + + if (!count) + return; + + info = kcalloc(count, sizeof(**info), GFP_KERNEL); + if (!info) + return; + + xa_extract(&drv_info->partition_info, (void **)info, 0, VM_ID_MASK, + count, XA_PRESENT); + + for (idx = 0; idx < count; idx++) + kfree(info[idx]); + kfree(info); + + drv_info->partition_count = 0; + xa_destroy(&drv_info->partition_info); +} + +/* FFA FEATURE IDs */ +#define FFA_FEAT_NOTIFICATION_PENDING_INT (1) +#define FFA_FEAT_SCHEDULE_RECEIVER_INT (2) +#define FFA_FEAT_MANAGED_EXIT_INT (3) + +static irqreturn_t irq_handler(int irq, void *irq_data) +{ + struct ffa_pcpu_irq *pcpu = irq_data; + struct ffa_drv_info *info = pcpu->info; + + queue_work(info->notif_pcpu_wq, &info->irq_work); + + return IRQ_HANDLED; +} + +static void ffa_sched_recv_irq_work_fn(struct work_struct *work) +{ + ffa_notification_info_get(); +} + +static int ffa_sched_recv_irq_map(void) +{ + int ret, irq, sr_intid; + + /* The returned sr_intid is assumed to be SGI donated to NS world */ + ret = ffa_features(FFA_FEAT_SCHEDULE_RECEIVER_INT, 0, &sr_intid, NULL); + if (ret < 0) { + if (ret != -EOPNOTSUPP) + pr_err("Failed to retrieve scheduler Rx interrupt\n"); + return ret; + } + + if (acpi_disabled) { + struct of_phandle_args oirq = {}; + struct device_node *gic; + + /* Only GICv3 supported currently with the device tree */ + gic = of_find_compatible_node(NULL, NULL, "arm,gic-v3"); + if (!gic) + return -ENXIO; + + oirq.np = gic; + oirq.args_count = 1; + oirq.args[0] = sr_intid; + irq = irq_create_of_mapping(&oirq); + of_node_put(gic); +#ifdef CONFIG_ACPI + } else { + irq = acpi_register_gsi(NULL, sr_intid, ACPI_EDGE_SENSITIVE, + ACPI_ACTIVE_HIGH); +#endif + } + + if (irq <= 0) { + pr_err("Failed to create IRQ mapping!\n"); + return -ENODATA; + } + + return irq; +} + +static void ffa_sched_recv_irq_unmap(void) +{ + if (drv_info->sched_recv_irq) + irq_dispose_mapping(drv_info->sched_recv_irq); +} + +static int ffa_cpuhp_pcpu_irq_enable(unsigned int cpu) +{ + enable_percpu_irq(drv_info->sched_recv_irq, IRQ_TYPE_NONE); + return 0; +} + +static int ffa_cpuhp_pcpu_irq_disable(unsigned int cpu) +{ + disable_percpu_irq(drv_info->sched_recv_irq); + return 0; +} + +static void ffa_uninit_pcpu_irq(void) +{ + if (drv_info->cpuhp_state) + cpuhp_remove_state(drv_info->cpuhp_state); + + if (drv_info->notif_pcpu_wq) + destroy_workqueue(drv_info->notif_pcpu_wq); + + if (drv_info->sched_recv_irq) + free_percpu_irq(drv_info->sched_recv_irq, drv_info->irq_pcpu); + + if (drv_info->irq_pcpu) + free_percpu(drv_info->irq_pcpu); +} + +static int ffa_init_pcpu_irq(unsigned int irq) +{ + struct ffa_pcpu_irq __percpu *irq_pcpu; + int ret, cpu; + + irq_pcpu = alloc_percpu(struct ffa_pcpu_irq); + if (!irq_pcpu) + return -ENOMEM; + + for_each_present_cpu(cpu) + per_cpu_ptr(irq_pcpu, cpu)->info = drv_info; + + drv_info->irq_pcpu = irq_pcpu; + + ret = request_percpu_irq(irq, irq_handler, "ARM-FFA", irq_pcpu); + if (ret) { + pr_err("Error registering notification IRQ %d: %d\n", irq, ret); + return ret; + } + + INIT_WORK(&drv_info->irq_work, ffa_sched_recv_irq_work_fn); + INIT_WORK(&drv_info->notif_pcpu_work, notif_pcpu_irq_work_fn); + drv_info->notif_pcpu_wq = create_workqueue("ffa_pcpu_irq_notification"); + if (!drv_info->notif_pcpu_wq) + return -EINVAL; + + ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "ffa/pcpu-irq:starting", + ffa_cpuhp_pcpu_irq_enable, + ffa_cpuhp_pcpu_irq_disable); + + if (ret < 0) + return ret; + + drv_info->cpuhp_state = ret; + return 0; +} + +static void ffa_notifications_cleanup(void) +{ + ffa_uninit_pcpu_irq(); + ffa_sched_recv_irq_unmap(); + + if (drv_info->bitmap_created) { + ffa_notification_bitmap_destroy(); + drv_info->bitmap_created = false; + } +} + +static int ffa_notifications_setup(void) +{ + int ret, irq; + + ret = ffa_features(FFA_NOTIFICATION_BITMAP_CREATE, 0, NULL, NULL); + if (ret) { + pr_err("Notifications not supported, continuing with it ..\n"); + return 0; + } + + ret = ffa_notification_bitmap_create(); + if (ret) { + pr_err("notification_bitmap_create error %d\n", ret); + return ret; + } + drv_info->bitmap_created = true; + + irq = ffa_sched_recv_irq_map(); + if (irq <= 0) { + ret = irq; + goto cleanup; + } + + drv_info->sched_recv_irq = irq; + + ret = ffa_init_pcpu_irq(irq); + if (ret) + goto cleanup; + + hash_init(drv_info->notifier_hash); + mutex_init(&drv_info->notify_lock); + + /* Register internal scheduling callback */ + ret = ffa_sched_recv_cb_update(drv_info->vm_id, ffa_self_notif_handle, + drv_info, true); + if (!ret) + return ret; +cleanup: + ffa_notifications_cleanup(); + return ret; } static int __init ffa_init(void) @@ -754,7 +1487,13 @@ static int __init ffa_init(void) ffa_set_up_mem_ops_native_flag(); + ret = ffa_notifications_setup(); + if (ret) + goto partitions_cleanup; + return 0; +partitions_cleanup: + ffa_partitions_cleanup(); free_pages: if (drv_info->tx_buffer) free_pages_exact(drv_info->tx_buffer, RXTX_BUFFER_SIZE); @@ -769,9 +1508,12 @@ subsys_initcall(ffa_init); static void __exit ffa_exit(void) { + ffa_notifications_cleanup(); + ffa_partitions_cleanup(); ffa_rxtx_unmap(drv_info->vm_id); free_pages_exact(drv_info->tx_buffer, RXTX_BUFFER_SIZE); free_pages_exact(drv_info->rx_buffer, RXTX_BUFFER_SIZE); + xa_destroy(&drv_info->partition_info); kfree(drv_info); arm_ffa_bus_exit(); } diff --git a/drivers/firmware/arm_scmi/Kconfig b/drivers/firmware/arm_scmi/Kconfig index ea0f5083ac47..706d1264d038 100644 --- a/drivers/firmware/arm_scmi/Kconfig +++ b/drivers/firmware/arm_scmi/Kconfig @@ -181,6 +181,18 @@ config ARM_SCMI_POWER_DOMAIN will be called scmi_pm_domain. Note this may needed early in boot before rootfs may be available. +config ARM_SCMI_PERF_DOMAIN + tristate "SCMI performance domain driver" + depends on ARM_SCMI_PROTOCOL || (COMPILE_TEST && OF) + default y + select PM_GENERIC_DOMAINS if PM + help + This enables support for the SCMI performance domains which can be + enabled or disabled via the SCP firmware. + + This driver can also be built as a module. If so, the module will be + called scmi_perf_domain. + config ARM_SCMI_POWER_CONTROL tristate "SCMI system power control driver" depends on ARM_SCMI_PROTOCOL || (COMPILE_TEST && OF) diff --git a/drivers/firmware/arm_scmi/Makefile b/drivers/firmware/arm_scmi/Makefile index b31d78fa66cc..a7bc4796519c 100644 --- a/drivers/firmware/arm_scmi/Makefile +++ b/drivers/firmware/arm_scmi/Makefile @@ -16,7 +16,6 @@ scmi-module-objs := $(scmi-driver-y) $(scmi-protocols-y) $(scmi-transport-y) obj-$(CONFIG_ARM_SCMI_PROTOCOL) += scmi-core.o obj-$(CONFIG_ARM_SCMI_PROTOCOL) += scmi-module.o -obj-$(CONFIG_ARM_SCMI_POWER_DOMAIN) += scmi_pm_domain.o obj-$(CONFIG_ARM_SCMI_POWER_CONTROL) += scmi_power_control.o ifeq ($(CONFIG_THUMB2_KERNEL)$(CONFIG_CC_IS_CLANG),yy) diff --git a/drivers/firmware/arm_scmi/clock.c b/drivers/firmware/arm_scmi/clock.c index 96060bf90a24..42b81c181d68 100644 --- a/drivers/firmware/arm_scmi/clock.c +++ b/drivers/firmware/arm_scmi/clock.c @@ -21,6 +21,17 @@ enum scmi_clock_protocol_cmd { CLOCK_NAME_GET = 0x8, CLOCK_RATE_NOTIFY = 0x9, CLOCK_RATE_CHANGE_REQUESTED_NOTIFY = 0xA, + CLOCK_CONFIG_GET = 0xB, + CLOCK_POSSIBLE_PARENTS_GET = 0xC, + CLOCK_PARENT_SET = 0xD, + CLOCK_PARENT_GET = 0xE, +}; + +enum clk_state { + CLK_STATE_DISABLE, + CLK_STATE_ENABLE, + CLK_STATE_RESERVED, + CLK_STATE_UNCHANGED, }; struct scmi_msg_resp_clock_protocol_attributes { @@ -31,17 +42,57 @@ struct scmi_msg_resp_clock_protocol_attributes { struct scmi_msg_resp_clock_attributes { __le32 attributes; -#define CLOCK_ENABLE BIT(0) #define SUPPORTS_RATE_CHANGED_NOTIF(x) ((x) & BIT(31)) #define SUPPORTS_RATE_CHANGE_REQUESTED_NOTIF(x) ((x) & BIT(30)) #define SUPPORTS_EXTENDED_NAMES(x) ((x) & BIT(29)) +#define SUPPORTS_PARENT_CLOCK(x) ((x) & BIT(28)) u8 name[SCMI_SHORT_NAME_MAX_SIZE]; __le32 clock_enable_latency; }; -struct scmi_clock_set_config { +struct scmi_msg_clock_possible_parents { + __le32 id; + __le32 skip_parents; +}; + +struct scmi_msg_resp_clock_possible_parents { + __le32 num_parent_flags; +#define NUM_PARENTS_RETURNED(x) ((x) & 0xff) +#define NUM_PARENTS_REMAINING(x) ((x) >> 24) + __le32 possible_parents[]; +}; + +struct scmi_msg_clock_set_parent { + __le32 id; + __le32 parent_id; +}; + +struct scmi_msg_clock_config_set { + __le32 id; + __le32 attributes; +}; + +/* Valid only from SCMI clock v2.1 */ +struct scmi_msg_clock_config_set_v2 { __le32 id; __le32 attributes; +#define NULL_OEM_TYPE 0 +#define REGMASK_OEM_TYPE_SET GENMASK(23, 16) +#define REGMASK_CLK_STATE GENMASK(1, 0) + __le32 oem_config_val; +}; + +struct scmi_msg_clock_config_get { + __le32 id; + __le32 flags; +#define REGMASK_OEM_TYPE_GET GENMASK(7, 0) +}; + +struct scmi_msg_resp_clock_config_get { + __le32 attributes; + __le32 config; +#define IS_CLK_ENABLED(x) le32_get_bits((x), BIT(0)) + __le32 oem_config_val; }; struct scmi_msg_clock_describe_rates { @@ -100,6 +151,12 @@ struct clock_info { int max_async_req; atomic_t cur_async_req; struct scmi_clock_info *clk; + int (*clock_config_set)(const struct scmi_protocol_handle *ph, + u32 clk_id, enum clk_state state, + u8 oem_type, u32 oem_val, bool atomic); + int (*clock_config_get)(const struct scmi_protocol_handle *ph, + u32 clk_id, u8 oem_type, u32 *attributes, + bool *enabled, u32 *oem_val, bool atomic); }; static enum scmi_clock_protocol_cmd evt_2_cmd[] = { @@ -132,6 +189,98 @@ scmi_clock_protocol_attributes_get(const struct scmi_protocol_handle *ph, return ret; } +struct scmi_clk_ipriv { + struct device *dev; + u32 clk_id; + struct scmi_clock_info *clk; +}; + +static void iter_clk_possible_parents_prepare_message(void *message, unsigned int desc_index, + const void *priv) +{ + struct scmi_msg_clock_possible_parents *msg = message; + const struct scmi_clk_ipriv *p = priv; + + msg->id = cpu_to_le32(p->clk_id); + /* Set the number of OPPs to be skipped/already read */ + msg->skip_parents = cpu_to_le32(desc_index); +} + +static int iter_clk_possible_parents_update_state(struct scmi_iterator_state *st, + const void *response, void *priv) +{ + const struct scmi_msg_resp_clock_possible_parents *r = response; + struct scmi_clk_ipriv *p = priv; + struct device *dev = ((struct scmi_clk_ipriv *)p)->dev; + u32 flags; + + flags = le32_to_cpu(r->num_parent_flags); + st->num_returned = NUM_PARENTS_RETURNED(flags); + st->num_remaining = NUM_PARENTS_REMAINING(flags); + + /* + * num parents is not declared previously anywhere so we + * assume it's returned+remaining on first call. + */ + if (!st->max_resources) { + p->clk->num_parents = st->num_returned + st->num_remaining; + p->clk->parents = devm_kcalloc(dev, p->clk->num_parents, + sizeof(*p->clk->parents), + GFP_KERNEL); + if (!p->clk->parents) { + p->clk->num_parents = 0; + return -ENOMEM; + } + st->max_resources = st->num_returned + st->num_remaining; + } + + return 0; +} + +static int iter_clk_possible_parents_process_response(const struct scmi_protocol_handle *ph, + const void *response, + struct scmi_iterator_state *st, + void *priv) +{ + const struct scmi_msg_resp_clock_possible_parents *r = response; + struct scmi_clk_ipriv *p = priv; + + u32 *parent = &p->clk->parents[st->desc_index + st->loop_idx]; + + *parent = le32_to_cpu(r->possible_parents[st->loop_idx]); + + return 0; +} + +static int scmi_clock_possible_parents(const struct scmi_protocol_handle *ph, u32 clk_id, + struct scmi_clock_info *clk) +{ + struct scmi_iterator_ops ops = { + .prepare_message = iter_clk_possible_parents_prepare_message, + .update_state = iter_clk_possible_parents_update_state, + .process_response = iter_clk_possible_parents_process_response, + }; + + struct scmi_clk_ipriv ppriv = { + .clk_id = clk_id, + .clk = clk, + .dev = ph->dev, + }; + void *iter; + int ret; + + iter = ph->hops->iter_response_init(ph, &ops, 0, + CLOCK_POSSIBLE_PARENTS_GET, + sizeof(struct scmi_msg_clock_possible_parents), + &ppriv); + if (IS_ERR(iter)) + return PTR_ERR(iter); + + ret = ph->hops->iter_response_run(iter); + + return ret; +} + static int scmi_clock_attributes_get(const struct scmi_protocol_handle *ph, u32 clk_id, struct scmi_clock_info *clk, u32 version) @@ -176,6 +325,8 @@ static int scmi_clock_attributes_get(const struct scmi_protocol_handle *ph, clk->rate_changed_notifications = true; if (SUPPORTS_RATE_CHANGE_REQUESTED_NOTIF(attributes)) clk->rate_change_requested_notifications = true; + if (SUPPORTS_PARENT_CLOCK(attributes)) + scmi_clock_possible_parents(ph, clk_id, clk); } return ret; @@ -193,12 +344,6 @@ static int rate_cmp_func(const void *_r1, const void *_r2) return 1; } -struct scmi_clk_ipriv { - struct device *dev; - u32 clk_id; - struct scmi_clock_info *clk; -}; - static void iter_clk_describe_prepare_message(void *message, const unsigned int desc_index, const void *priv) @@ -395,11 +540,105 @@ static int scmi_clock_rate_set(const struct scmi_protocol_handle *ph, static int scmi_clock_config_set(const struct scmi_protocol_handle *ph, u32 clk_id, - u32 config, bool atomic) + enum clk_state state, u8 __unused0, u32 __unused1, + bool atomic) +{ + int ret; + struct scmi_xfer *t; + struct scmi_msg_clock_config_set *cfg; + + if (state >= CLK_STATE_RESERVED) + return -EINVAL; + + ret = ph->xops->xfer_get_init(ph, CLOCK_CONFIG_SET, + sizeof(*cfg), 0, &t); + if (ret) + return ret; + + t->hdr.poll_completion = atomic; + + cfg = t->tx.buf; + cfg->id = cpu_to_le32(clk_id); + cfg->attributes = cpu_to_le32(state); + + ret = ph->xops->do_xfer(ph, t); + + ph->xops->xfer_put(ph, t); + return ret; +} + +static int +scmi_clock_set_parent(const struct scmi_protocol_handle *ph, u32 clk_id, + u32 parent_id) +{ + int ret; + struct scmi_xfer *t; + struct scmi_msg_clock_set_parent *cfg; + struct clock_info *ci = ph->get_priv(ph); + struct scmi_clock_info *clk; + + if (clk_id >= ci->num_clocks) + return -EINVAL; + + clk = ci->clk + clk_id; + + if (parent_id >= clk->num_parents) + return -EINVAL; + + ret = ph->xops->xfer_get_init(ph, CLOCK_PARENT_SET, + sizeof(*cfg), 0, &t); + if (ret) + return ret; + + t->hdr.poll_completion = false; + + cfg = t->tx.buf; + cfg->id = cpu_to_le32(clk_id); + cfg->parent_id = cpu_to_le32(clk->parents[parent_id]); + + ret = ph->xops->do_xfer(ph, t); + + ph->xops->xfer_put(ph, t); + + return ret; +} + +static int +scmi_clock_get_parent(const struct scmi_protocol_handle *ph, u32 clk_id, + u32 *parent_id) { int ret; struct scmi_xfer *t; - struct scmi_clock_set_config *cfg; + + ret = ph->xops->xfer_get_init(ph, CLOCK_PARENT_GET, + sizeof(__le32), sizeof(u32), &t); + if (ret) + return ret; + + put_unaligned_le32(clk_id, t->tx.buf); + + ret = ph->xops->do_xfer(ph, t); + if (!ret) + *parent_id = get_unaligned_le32(t->rx.buf); + + ph->xops->xfer_put(ph, t); + return ret; +} + +/* For SCMI clock v2.1 and onwards */ +static int +scmi_clock_config_set_v2(const struct scmi_protocol_handle *ph, u32 clk_id, + enum clk_state state, u8 oem_type, u32 oem_val, + bool atomic) +{ + int ret; + u32 attrs; + struct scmi_xfer *t; + struct scmi_msg_clock_config_set_v2 *cfg; + + if (state == CLK_STATE_RESERVED || + (!oem_type && state == CLK_STATE_UNCHANGED)) + return -EINVAL; ret = ph->xops->xfer_get_init(ph, CLOCK_CONFIG_SET, sizeof(*cfg), 0, &t); @@ -408,9 +647,16 @@ scmi_clock_config_set(const struct scmi_protocol_handle *ph, u32 clk_id, t->hdr.poll_completion = atomic; + attrs = FIELD_PREP(REGMASK_OEM_TYPE_SET, oem_type) | + FIELD_PREP(REGMASK_CLK_STATE, state); + cfg = t->tx.buf; cfg->id = cpu_to_le32(clk_id); - cfg->attributes = cpu_to_le32(config); + cfg->attributes = cpu_to_le32(attrs); + /* Clear in any case */ + cfg->oem_config_val = cpu_to_le32(0); + if (oem_type) + cfg->oem_config_val = cpu_to_le32(oem_val); ret = ph->xops->do_xfer(ph, t); @@ -418,26 +664,124 @@ scmi_clock_config_set(const struct scmi_protocol_handle *ph, u32 clk_id, return ret; } -static int scmi_clock_enable(const struct scmi_protocol_handle *ph, u32 clk_id) +static int scmi_clock_enable(const struct scmi_protocol_handle *ph, u32 clk_id, + bool atomic) { - return scmi_clock_config_set(ph, clk_id, CLOCK_ENABLE, false); + struct clock_info *ci = ph->get_priv(ph); + + return ci->clock_config_set(ph, clk_id, CLK_STATE_ENABLE, + NULL_OEM_TYPE, 0, atomic); } -static int scmi_clock_disable(const struct scmi_protocol_handle *ph, u32 clk_id) +static int scmi_clock_disable(const struct scmi_protocol_handle *ph, u32 clk_id, + bool atomic) { - return scmi_clock_config_set(ph, clk_id, 0, false); + struct clock_info *ci = ph->get_priv(ph); + + return ci->clock_config_set(ph, clk_id, CLK_STATE_DISABLE, + NULL_OEM_TYPE, 0, atomic); } -static int scmi_clock_enable_atomic(const struct scmi_protocol_handle *ph, - u32 clk_id) +/* For SCMI clock v2.1 and onwards */ +static int +scmi_clock_config_get_v2(const struct scmi_protocol_handle *ph, u32 clk_id, + u8 oem_type, u32 *attributes, bool *enabled, + u32 *oem_val, bool atomic) { - return scmi_clock_config_set(ph, clk_id, CLOCK_ENABLE, true); + int ret; + u32 flags; + struct scmi_xfer *t; + struct scmi_msg_clock_config_get *cfg; + + ret = ph->xops->xfer_get_init(ph, CLOCK_CONFIG_GET, + sizeof(*cfg), 0, &t); + if (ret) + return ret; + + t->hdr.poll_completion = atomic; + + flags = FIELD_PREP(REGMASK_OEM_TYPE_GET, oem_type); + + cfg = t->tx.buf; + cfg->id = cpu_to_le32(clk_id); + cfg->flags = cpu_to_le32(flags); + + ret = ph->xops->do_xfer(ph, t); + if (!ret) { + struct scmi_msg_resp_clock_config_get *resp = t->rx.buf; + + if (attributes) + *attributes = le32_to_cpu(resp->attributes); + + if (enabled) + *enabled = IS_CLK_ENABLED(resp->config); + + if (oem_val && oem_type) + *oem_val = le32_to_cpu(resp->oem_config_val); + } + + ph->xops->xfer_put(ph, t); + + return ret; +} + +static int +scmi_clock_config_get(const struct scmi_protocol_handle *ph, u32 clk_id, + u8 oem_type, u32 *attributes, bool *enabled, + u32 *oem_val, bool atomic) +{ + int ret; + struct scmi_xfer *t; + struct scmi_msg_resp_clock_attributes *resp; + + if (!enabled) + return -EINVAL; + + ret = ph->xops->xfer_get_init(ph, CLOCK_ATTRIBUTES, + sizeof(clk_id), sizeof(*resp), &t); + if (ret) + return ret; + + t->hdr.poll_completion = atomic; + put_unaligned_le32(clk_id, t->tx.buf); + resp = t->rx.buf; + + ret = ph->xops->do_xfer(ph, t); + if (!ret) + *enabled = IS_CLK_ENABLED(resp->attributes); + + ph->xops->xfer_put(ph, t); + + return ret; } -static int scmi_clock_disable_atomic(const struct scmi_protocol_handle *ph, - u32 clk_id) +static int scmi_clock_state_get(const struct scmi_protocol_handle *ph, + u32 clk_id, bool *enabled, bool atomic) { - return scmi_clock_config_set(ph, clk_id, 0, true); + struct clock_info *ci = ph->get_priv(ph); + + return ci->clock_config_get(ph, clk_id, NULL_OEM_TYPE, NULL, + enabled, NULL, atomic); +} + +static int scmi_clock_config_oem_set(const struct scmi_protocol_handle *ph, + u32 clk_id, u8 oem_type, u32 oem_val, + bool atomic) +{ + struct clock_info *ci = ph->get_priv(ph); + + return ci->clock_config_set(ph, clk_id, CLK_STATE_UNCHANGED, + oem_type, oem_val, atomic); +} + +static int scmi_clock_config_oem_get(const struct scmi_protocol_handle *ph, + u32 clk_id, u8 oem_type, u32 *oem_val, + u32 *attributes, bool atomic) +{ + struct clock_info *ci = ph->get_priv(ph); + + return ci->clock_config_get(ph, clk_id, oem_type, attributes, + NULL, oem_val, atomic); } static int scmi_clock_count_get(const struct scmi_protocol_handle *ph) @@ -470,8 +814,11 @@ static const struct scmi_clk_proto_ops clk_proto_ops = { .rate_set = scmi_clock_rate_set, .enable = scmi_clock_enable, .disable = scmi_clock_disable, - .enable_atomic = scmi_clock_enable_atomic, - .disable_atomic = scmi_clock_disable_atomic, + .state_get = scmi_clock_state_get, + .config_oem_get = scmi_clock_config_oem_get, + .config_oem_set = scmi_clock_config_oem_set, + .parent_set = scmi_clock_set_parent, + .parent_get = scmi_clock_get_parent, }; static int scmi_clk_rate_notify(const struct scmi_protocol_handle *ph, @@ -604,6 +951,15 @@ static int scmi_clock_protocol_init(const struct scmi_protocol_handle *ph) scmi_clock_describe_rates_get(ph, clkid, clk); } + if (PROTOCOL_REV_MAJOR(version) >= 0x2 && + PROTOCOL_REV_MINOR(version) >= 0x1) { + cinfo->clock_config_set = scmi_clock_config_set_v2; + cinfo->clock_config_get = scmi_clock_config_get_v2; + } else { + cinfo->clock_config_set = scmi_clock_config_set; + cinfo->clock_config_get = scmi_clock_config_get; + } + cinfo->version = version; return ph->set_priv(ph, cinfo); } diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c index 87383c05424b..09371f40d61f 100644 --- a/drivers/firmware/arm_scmi/driver.c +++ b/drivers/firmware/arm_scmi/driver.c @@ -2915,6 +2915,7 @@ static const struct of_device_id scmi_of_match[] = { #ifdef CONFIG_ARM_SCMI_TRANSPORT_SMC { .compatible = "arm,scmi-smc", .data = &scmi_smc_desc}, { .compatible = "arm,scmi-smc-param", .data = &scmi_smc_desc}, + { .compatible = "qcom,scmi-smc", .data = &scmi_smc_desc}, #endif #ifdef CONFIG_ARM_SCMI_TRANSPORT_VIRTIO { .compatible = "arm,scmi-virtio", .data = &scmi_virtio_desc}, diff --git a/drivers/firmware/arm_scmi/perf.c b/drivers/firmware/arm_scmi/perf.c index c0cd556fbaae..c2435be0ae1b 100644 --- a/drivers/firmware/arm_scmi/perf.c +++ b/drivers/firmware/arm_scmi/perf.c @@ -145,7 +145,6 @@ struct scmi_msg_resp_perf_describe_levels_v4 { struct perf_dom_info { u32 id; bool set_limits; - bool set_perf; bool perf_limit_notify; bool perf_level_notify; bool perf_fastchannels; @@ -154,7 +153,7 @@ struct perf_dom_info { u32 sustained_freq_khz; u32 sustained_perf_level; u32 mult_factor; - char name[SCMI_MAX_STR_SIZE]; + struct scmi_perf_domain_info info; struct scmi_opp opp[MAX_OPPS]; struct scmi_fc_info *fc_info; struct xarray opps_by_idx; @@ -257,7 +256,7 @@ scmi_perf_domain_attributes_get(const struct scmi_protocol_handle *ph, flags = le32_to_cpu(attr->flags); dom_info->set_limits = SUPPORTS_SET_LIMITS(flags); - dom_info->set_perf = SUPPORTS_SET_PERF_LVL(flags); + dom_info->info.set_perf = SUPPORTS_SET_PERF_LVL(flags); dom_info->perf_limit_notify = SUPPORTS_PERF_LIMIT_NOTIFY(flags); dom_info->perf_level_notify = SUPPORTS_PERF_LEVEL_NOTIFY(flags); dom_info->perf_fastchannels = SUPPORTS_PERF_FASTCHANNELS(flags); @@ -276,7 +275,8 @@ scmi_perf_domain_attributes_get(const struct scmi_protocol_handle *ph, dom_info->mult_factor = (dom_info->sustained_freq_khz * 1000) / dom_info->sustained_perf_level; - strscpy(dom_info->name, attr->name, SCMI_SHORT_NAME_MAX_SIZE); + strscpy(dom_info->info.name, attr->name, + SCMI_SHORT_NAME_MAX_SIZE); } ph->xops->xfer_put(ph, t); @@ -288,7 +288,7 @@ scmi_perf_domain_attributes_get(const struct scmi_protocol_handle *ph, if (!ret && PROTOCOL_REV_MAJOR(version) >= 0x3 && SUPPORTS_EXTENDED_NAMES(flags)) ph->hops->extended_name_get(ph, PERF_DOMAIN_NAME_GET, - dom_info->id, dom_info->name, + dom_info->id, dom_info->info.name, SCMI_MAX_STR_SIZE); if (dom_info->level_indexing_mode) { @@ -423,6 +423,36 @@ scmi_perf_describe_levels_get(const struct scmi_protocol_handle *ph, return ret; } +static int scmi_perf_num_domains_get(const struct scmi_protocol_handle *ph) +{ + struct scmi_perf_info *pi = ph->get_priv(ph); + + return pi->num_domains; +} + +static inline struct perf_dom_info * +scmi_perf_domain_lookup(const struct scmi_protocol_handle *ph, u32 domain) +{ + struct scmi_perf_info *pi = ph->get_priv(ph); + + if (domain >= pi->num_domains) + return ERR_PTR(-EINVAL); + + return pi->dom_info + domain; +} + +static const struct scmi_perf_domain_info * +scmi_perf_info_get(const struct scmi_protocol_handle *ph, u32 domain) +{ + struct perf_dom_info *dom; + + dom = scmi_perf_domain_lookup(ph, domain); + if (IS_ERR(dom)) + return ERR_PTR(-EINVAL); + + return &dom->info; +} + static int scmi_perf_msg_limits_set(const struct scmi_protocol_handle *ph, u32 domain, u32 max_perf, u32 min_perf) { @@ -446,17 +476,6 @@ static int scmi_perf_msg_limits_set(const struct scmi_protocol_handle *ph, return ret; } -static inline struct perf_dom_info * -scmi_perf_domain_lookup(const struct scmi_protocol_handle *ph, u32 domain) -{ - struct scmi_perf_info *pi = ph->get_priv(ph); - - if (domain >= pi->num_domains) - return ERR_PTR(-EINVAL); - - return pi->dom_info + domain; -} - static int __scmi_perf_limits_set(const struct scmi_protocol_handle *ph, struct perf_dom_info *dom, u32 max_perf, u32 min_perf) @@ -763,71 +782,46 @@ static void scmi_perf_domain_init_fc(const struct scmi_protocol_handle *ph, *p_fc = fc; } -/* Device specific ops */ -static int scmi_dev_domain_id(struct device *dev) -{ - struct of_phandle_args clkspec; - - if (of_parse_phandle_with_args(dev->of_node, "clocks", "#clock-cells", - 0, &clkspec)) - return -EINVAL; - - return clkspec.args[0]; -} - static int scmi_dvfs_device_opps_add(const struct scmi_protocol_handle *ph, - struct device *dev) + struct device *dev, u32 domain) { - int idx, ret, domain; + int idx, ret; unsigned long freq; - struct scmi_opp *opp; + struct dev_pm_opp_data data = {}; struct perf_dom_info *dom; - domain = scmi_dev_domain_id(dev); - if (domain < 0) - return -EINVAL; - dom = scmi_perf_domain_lookup(ph, domain); if (IS_ERR(dom)) return PTR_ERR(dom); - for (opp = dom->opp, idx = 0; idx < dom->opp_count; idx++, opp++) { + for (idx = 0; idx < dom->opp_count; idx++) { if (!dom->level_indexing_mode) - freq = opp->perf * dom->mult_factor; + freq = dom->opp[idx].perf * dom->mult_factor; else - freq = opp->indicative_freq * 1000; + freq = dom->opp[idx].indicative_freq * 1000; - ret = dev_pm_opp_add(dev, freq, 0); + data.level = dom->opp[idx].perf; + data.freq = freq; + + ret = dev_pm_opp_add_dynamic(dev, &data); if (ret) { dev_warn(dev, "failed to add opp %luHz\n", freq); - - while (idx-- > 0) { - if (!dom->level_indexing_mode) - freq = (--opp)->perf * dom->mult_factor; - else - freq = (--opp)->indicative_freq * 1000; - dev_pm_opp_remove(dev, freq); - } + dev_pm_opp_remove_all_dynamic(dev); return ret; } dev_dbg(dev, "[%d][%s]:: Registered OPP[%d] %lu\n", - domain, dom->name, idx, freq); + domain, dom->info.name, idx, freq); } return 0; } static int scmi_dvfs_transition_latency_get(const struct scmi_protocol_handle *ph, - struct device *dev) + u32 domain) { - int domain; struct perf_dom_info *dom; - domain = scmi_dev_domain_id(dev); - if (domain < 0) - return -EINVAL; - dom = scmi_perf_domain_lookup(ph, domain); if (IS_ERR(dom)) return PTR_ERR(dom); @@ -923,15 +917,10 @@ static int scmi_dvfs_est_power_get(const struct scmi_protocol_handle *ph, } static bool scmi_fast_switch_possible(const struct scmi_protocol_handle *ph, - struct device *dev) + u32 domain) { - int domain; struct perf_dom_info *dom; - domain = scmi_dev_domain_id(dev); - if (domain < 0) - return false; - dom = scmi_perf_domain_lookup(ph, domain); if (IS_ERR(dom)) return false; @@ -948,11 +937,12 @@ scmi_power_scale_get(const struct scmi_protocol_handle *ph) } static const struct scmi_perf_proto_ops perf_proto_ops = { + .num_domains_get = scmi_perf_num_domains_get, + .info_get = scmi_perf_info_get, .limits_set = scmi_perf_limits_set, .limits_get = scmi_perf_limits_get, .level_set = scmi_perf_level_set, .level_get = scmi_perf_level_get, - .device_domain_id = scmi_dev_domain_id, .transition_latency_get = scmi_dvfs_transition_latency_get, .device_opps_add = scmi_dvfs_device_opps_add, .freq_set = scmi_dvfs_freq_set, @@ -1080,6 +1070,8 @@ static int scmi_perf_protocol_init(const struct scmi_protocol_handle *ph) if (!pinfo) return -ENOMEM; + pinfo->version = version; + ret = scmi_perf_attributes_get(ph, pinfo); if (ret) return ret; @@ -1104,8 +1096,6 @@ static int scmi_perf_protocol_init(const struct scmi_protocol_handle *ph) if (ret) return ret; - pinfo->version = version; - return ph->set_priv(ph, pinfo); } diff --git a/drivers/firmware/arm_scmi/powercap.c b/drivers/firmware/arm_scmi/powercap.c index 244929cb4f3e..cb5617443a14 100644 --- a/drivers/firmware/arm_scmi/powercap.c +++ b/drivers/firmware/arm_scmi/powercap.c @@ -360,8 +360,8 @@ static int scmi_powercap_xfer_cap_set(const struct scmi_protocol_handle *ph, msg = t->tx.buf; msg->domain = cpu_to_le32(pc->id); msg->flags = - cpu_to_le32(FIELD_PREP(CAP_SET_ASYNC, !!pc->async_powercap_cap_set) | - FIELD_PREP(CAP_SET_IGNORE_DRESP, !!ignore_dresp)); + cpu_to_le32(FIELD_PREP(CAP_SET_ASYNC, pc->async_powercap_cap_set) | + FIELD_PREP(CAP_SET_IGNORE_DRESP, ignore_dresp)); msg->value = cpu_to_le32(power_cap); if (!pc->async_powercap_cap_set || ignore_dresp) { diff --git a/drivers/firmware/arm_scmi/smc.c b/drivers/firmware/arm_scmi/smc.c index c193516a254d..7611e9665038 100644 --- a/drivers/firmware/arm_scmi/smc.c +++ b/drivers/firmware/arm_scmi/smc.c @@ -15,6 +15,7 @@ #include <linux/of.h> #include <linux/of_address.h> #include <linux/of_irq.h> +#include <linux/limits.h> #include <linux/processor.h> #include <linux/slab.h> @@ -50,6 +51,8 @@ * @func_id: smc/hvc call function id * @param_page: 4K page number of the shmem channel * @param_offset: Offset within the 4K page of the shmem channel + * @cap_id: smc/hvc doorbell's capability id to be used on Qualcomm virtual + * platforms */ struct scmi_smc { @@ -60,9 +63,10 @@ struct scmi_smc { struct mutex shmem_lock; #define INFLIGHT_NONE MSG_TOKEN_MAX atomic_t inflight; - u32 func_id; - u32 param_page; - u32 param_offset; + unsigned long func_id; + unsigned long param_page; + unsigned long param_offset; + unsigned long cap_id; }; static irqreturn_t smc_msg_done_isr(int irq, void *data) @@ -124,6 +128,7 @@ static int smc_chan_setup(struct scmi_chan_info *cinfo, struct device *dev, bool tx) { struct device *cdev = cinfo->dev; + unsigned long cap_id = ULONG_MAX; struct scmi_smc *scmi_info; resource_size_t size; struct resource res; @@ -162,6 +167,18 @@ static int smc_chan_setup(struct scmi_chan_info *cinfo, struct device *dev, if (ret < 0) return ret; + if (of_device_is_compatible(dev->of_node, "qcom,scmi-smc")) { + void __iomem *ptr = (void __iomem *)scmi_info->shmem + size - 8; + /* The capability-id is kept in last 8 bytes of shmem. + * +-------+ <-- 0 + * | shmem | + * +-------+ <-- size - 8 + * | capId | + * +-------+ <-- size + */ + memcpy_fromio(&cap_id, ptr, sizeof(cap_id)); + } + if (of_device_is_compatible(dev->of_node, "arm,scmi-smc-param")) { scmi_info->param_page = SHMEM_PAGE(res.start); scmi_info->param_offset = SHMEM_OFFSET(res.start); @@ -184,6 +201,7 @@ static int smc_chan_setup(struct scmi_chan_info *cinfo, struct device *dev, } scmi_info->func_id = func_id; + scmi_info->cap_id = cap_id; scmi_info->cinfo = cinfo; smc_channel_lock_init(scmi_info); cinfo->transport_info = scmi_info; @@ -211,8 +229,6 @@ static int smc_send_message(struct scmi_chan_info *cinfo, { struct scmi_smc *scmi_info = cinfo->transport_info; struct arm_smccc_res res; - unsigned long page = scmi_info->param_page; - unsigned long offset = scmi_info->param_offset; /* * Channel will be released only once response has been @@ -222,8 +238,13 @@ static int smc_send_message(struct scmi_chan_info *cinfo, shmem_tx_prepare(scmi_info->shmem, xfer, cinfo); - arm_smccc_1_1_invoke(scmi_info->func_id, page, offset, 0, 0, 0, 0, 0, - &res); + if (scmi_info->cap_id != ULONG_MAX) + arm_smccc_1_1_invoke(scmi_info->func_id, scmi_info->cap_id, 0, + 0, 0, 0, 0, 0, &res); + else + arm_smccc_1_1_invoke(scmi_info->func_id, scmi_info->param_page, + scmi_info->param_offset, 0, 0, 0, 0, 0, + &res); /* Only SMCCC_RET_NOT_SUPPORTED is valid error code */ if (res.a0) { diff --git a/drivers/firmware/arm_scpi.c b/drivers/firmware/arm_scpi.c index 435d0e2658a4..3f123f592cb4 100644 --- a/drivers/firmware/arm_scpi.c +++ b/drivers/firmware/arm_scpi.c @@ -26,9 +26,12 @@ #include <linux/list.h> #include <linux/mailbox_client.h> #include <linux/module.h> +#include <linux/of.h> #include <linux/of_address.h> #include <linux/of_platform.h> +#include <linux/platform_device.h> #include <linux/printk.h> +#include <linux/property.h> #include <linux/pm_opp.h> #include <linux/scpi_protocol.h> #include <linux/slab.h> @@ -894,11 +897,6 @@ static int scpi_alloc_xfer_list(struct device *dev, struct scpi_chan *ch) return 0; } -static const struct of_device_id legacy_scpi_of_match[] = { - {.compatible = "arm,scpi-pre-1.0"}, - {}, -}; - static const struct of_device_id shmem_of_match[] __maybe_unused = { { .compatible = "amlogic,meson-gxbb-scp-shmem", }, { .compatible = "amlogic,meson-axg-scp-shmem", }, @@ -919,8 +917,7 @@ static int scpi_probe(struct platform_device *pdev) if (!scpi_drvinfo) return -ENOMEM; - if (of_match_device(legacy_scpi_of_match, &pdev->dev)) - scpi_drvinfo->is_legacy = true; + scpi_drvinfo->is_legacy = !!device_get_match_data(dev); count = of_count_phandle_with_args(np, "mboxes", "#mbox-cells"); if (count < 0) { @@ -1038,7 +1035,7 @@ static int scpi_probe(struct platform_device *pdev) static const struct of_device_id scpi_of_match[] = { {.compatible = "arm,scpi"}, - {.compatible = "arm,scpi-pre-1.0"}, + {.compatible = "arm,scpi-pre-1.0", .data = (void *)1UL }, {}, }; diff --git a/drivers/firmware/cirrus/cs_dsp.c b/drivers/firmware/cirrus/cs_dsp.c index 49b70c70dc69..79d4254d1f9b 100644 --- a/drivers/firmware/cirrus/cs_dsp.c +++ b/drivers/firmware/cirrus/cs_dsp.c @@ -1863,15 +1863,15 @@ static int cs_dsp_adsp2_setup_algs(struct cs_dsp *dsp) return PTR_ERR(adsp2_alg); for (i = 0; i < n_algs; i++) { - cs_dsp_info(dsp, - "%d: ID %x v%d.%d.%d XM@%x YM@%x ZM@%x\n", - i, be32_to_cpu(adsp2_alg[i].alg.id), - (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff0000) >> 16, - (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff00) >> 8, - be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff, - be32_to_cpu(adsp2_alg[i].xm), - be32_to_cpu(adsp2_alg[i].ym), - be32_to_cpu(adsp2_alg[i].zm)); + cs_dsp_dbg(dsp, + "%d: ID %x v%d.%d.%d XM@%x YM@%x ZM@%x\n", + i, be32_to_cpu(adsp2_alg[i].alg.id), + (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff0000) >> 16, + (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff00) >> 8, + be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff, + be32_to_cpu(adsp2_alg[i].xm), + be32_to_cpu(adsp2_alg[i].ym), + be32_to_cpu(adsp2_alg[i].zm)); alg_region = cs_dsp_create_region(dsp, WMFW_ADSP2_XM, adsp2_alg[i].alg.id, @@ -1996,14 +1996,14 @@ static int cs_dsp_halo_setup_algs(struct cs_dsp *dsp) return PTR_ERR(halo_alg); for (i = 0; i < n_algs; i++) { - cs_dsp_info(dsp, - "%d: ID %x v%d.%d.%d XM@%x YM@%x\n", - i, be32_to_cpu(halo_alg[i].alg.id), - (be32_to_cpu(halo_alg[i].alg.ver) & 0xff0000) >> 16, - (be32_to_cpu(halo_alg[i].alg.ver) & 0xff00) >> 8, - be32_to_cpu(halo_alg[i].alg.ver) & 0xff, - be32_to_cpu(halo_alg[i].xm_base), - be32_to_cpu(halo_alg[i].ym_base)); + cs_dsp_dbg(dsp, + "%d: ID %x v%d.%d.%d XM@%x YM@%x\n", + i, be32_to_cpu(halo_alg[i].alg.id), + (be32_to_cpu(halo_alg[i].alg.ver) & 0xff0000) >> 16, + (be32_to_cpu(halo_alg[i].alg.ver) & 0xff00) >> 8, + be32_to_cpu(halo_alg[i].alg.ver) & 0xff, + be32_to_cpu(halo_alg[i].xm_base), + be32_to_cpu(halo_alg[i].ym_base)); ret = cs_dsp_halo_create_regions(dsp, halo_alg[i].alg.id, halo_alg[i].alg.ver, diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index 1599f1176842..ce20a60676f0 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c @@ -623,6 +623,34 @@ static __init int match_config_table(const efi_guid_t *guid, return 0; } +/** + * reserve_unaccepted - Map and reserve unaccepted configuration table + * @unaccepted: Pointer to unaccepted memory table + * + * memblock_add() makes sure that the table is mapped in direct mapping. During + * normal boot it happens automatically because the table is allocated from + * usable memory. But during crashkernel boot only memory specifically reserved + * for crash scenario is mapped. memblock_add() forces the table to be mapped + * in crashkernel case. + * + * Align the range to the nearest page borders. Ranges smaller than page size + * are not going to be mapped. + * + * memblock_reserve() makes sure that future allocations will not touch the + * table. + */ + +static __init void reserve_unaccepted(struct efi_unaccepted_memory *unaccepted) +{ + phys_addr_t start, size; + + start = PAGE_ALIGN_DOWN(efi.unaccepted); + size = PAGE_ALIGN(sizeof(*unaccepted) + unaccepted->size); + + memblock_add(start, size); + memblock_reserve(start, size); +} + int __init efi_config_parse_tables(const efi_config_table_t *config_tables, int count, const efi_config_table_type_t *arch_tables) @@ -751,11 +779,9 @@ int __init efi_config_parse_tables(const efi_config_table_t *config_tables, unaccepted = early_memremap(efi.unaccepted, sizeof(*unaccepted)); if (unaccepted) { - unsigned long size; if (unaccepted->version == 1) { - size = sizeof(*unaccepted) + unaccepted->size; - memblock_reserve(efi.unaccepted, size); + reserve_unaccepted(unaccepted); } else { efi.unaccepted = EFI_INVALID_TABLE_ADDR; } diff --git a/drivers/firmware/efi/libstub/unaccepted_memory.c b/drivers/firmware/efi/libstub/unaccepted_memory.c index ca61f4733ea5..9a655f30ba47 100644 --- a/drivers/firmware/efi/libstub/unaccepted_memory.c +++ b/drivers/firmware/efi/libstub/unaccepted_memory.c @@ -62,7 +62,7 @@ efi_status_t allocate_unaccepted_bitmap(__u32 nr_desc, bitmap_size = DIV_ROUND_UP(unaccepted_end - unaccepted_start, EFI_UNACCEPTED_UNIT_SIZE * BITS_PER_BYTE); - status = efi_bs_call(allocate_pool, EFI_LOADER_DATA, + status = efi_bs_call(allocate_pool, EFI_ACPI_RECLAIM_MEMORY, sizeof(*unaccepted_table) + bitmap_size, (void **)&unaccepted_table); if (status != EFI_SUCCESS) { diff --git a/drivers/firmware/imx/imx-dsp.c b/drivers/firmware/imx/imx-dsp.c index 3dba590a2a95..508eab346fc6 100644 --- a/drivers/firmware/imx/imx-dsp.c +++ b/drivers/firmware/imx/imx-dsp.c @@ -114,6 +114,7 @@ static int imx_dsp_setup_channels(struct imx_dsp_ipc *dsp_ipc) dsp_chan->idx = i % 2; dsp_chan->ch = mbox_request_channel_byname(cl, chan_name); if (IS_ERR(dsp_chan->ch)) { + kfree(dsp_chan->name); ret = PTR_ERR(dsp_chan->ch); if (ret != -EPROBE_DEFER) dev_err(dev, "Failed to request mbox chan %s ret %d\n", diff --git a/drivers/firmware/meson/meson_sm.c b/drivers/firmware/meson/meson_sm.c index 9a2656d73600..ed60f1103053 100644 --- a/drivers/firmware/meson/meson_sm.c +++ b/drivers/firmware/meson/meson_sm.c @@ -13,9 +13,10 @@ #include <linux/io.h> #include <linux/module.h> #include <linux/of.h> -#include <linux/of_device.h> +#include <linux/of_platform.h> #include <linux/platform_device.h> #include <linux/printk.h> +#include <linux/property.h> #include <linux/types.h> #include <linux/sizes.h> #include <linux/slab.h> @@ -67,7 +68,7 @@ static u32 meson_sm_get_cmd(const struct meson_sm_chip *chip, return cmd->smc_id; } -static u32 __meson_sm_call(u32 cmd, u32 arg0, u32 arg1, u32 arg2, +static s32 __meson_sm_call(u32 cmd, u32 arg0, u32 arg1, u32 arg2, u32 arg3, u32 arg4) { struct arm_smccc_res res; @@ -102,9 +103,10 @@ static void __iomem *meson_sm_map_shmem(u32 cmd_shmem, unsigned int size) * Return: 0 on success, a negative value on error */ int meson_sm_call(struct meson_sm_firmware *fw, unsigned int cmd_index, - u32 *ret, u32 arg0, u32 arg1, u32 arg2, u32 arg3, u32 arg4) + s32 *ret, u32 arg0, u32 arg1, u32 arg2, u32 arg3, u32 arg4) { - u32 cmd, lret; + u32 cmd; + s32 lret; if (!fw->chip) return -ENOENT; @@ -143,7 +145,7 @@ int meson_sm_call_read(struct meson_sm_firmware *fw, void *buffer, unsigned int bsize, unsigned int cmd_index, u32 arg0, u32 arg1, u32 arg2, u32 arg3, u32 arg4) { - u32 size; + s32 size; int ret; if (!fw->chip) @@ -158,11 +160,16 @@ int meson_sm_call_read(struct meson_sm_firmware *fw, void *buffer, if (meson_sm_call(fw, cmd_index, &size, arg0, arg1, arg2, arg3, arg4) < 0) return -EINVAL; - if (size > bsize) + if (size < 0 || size > bsize) return -EINVAL; ret = size; + /* In some cases (for example GET_CHIP_ID command), + * SMC doesn't return the number of bytes read, even + * though the bytes were actually read into sm_shmem_out. + * So this check is needed. + */ if (!size) size = bsize; @@ -192,7 +199,7 @@ int meson_sm_call_write(struct meson_sm_firmware *fw, void *buffer, unsigned int size, unsigned int cmd_index, u32 arg0, u32 arg1, u32 arg2, u32 arg3, u32 arg4) { - u32 written; + s32 written; if (!fw->chip) return -ENOENT; @@ -208,7 +215,7 @@ int meson_sm_call_write(struct meson_sm_firmware *fw, void *buffer, if (meson_sm_call(fw, cmd_index, &written, arg0, arg1, arg2, arg3, arg4) < 0) return -EINVAL; - if (!written) + if (written <= 0 || written > size) return -EINVAL; return written; @@ -291,7 +298,7 @@ static int __init meson_sm_probe(struct platform_device *pdev) if (!fw) return -ENOMEM; - chip = of_match_device(meson_sm_ids, dev)->data; + chip = device_get_match_data(dev); if (!chip) return -EINVAL; diff --git a/drivers/firmware/qcom_qseecom.c b/drivers/firmware/qcom_qseecom.c new file mode 100644 index 000000000000..731e6d5719f9 --- /dev/null +++ b/drivers/firmware/qcom_qseecom.c @@ -0,0 +1,120 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Driver for Qualcomm Secure Execution Environment (SEE) interface (QSEECOM). + * Responsible for setting up and managing QSEECOM client devices. + * + * Copyright (C) 2023 Maximilian Luz <luzmaximilian@gmail.com> + */ +#include <linux/auxiliary_bus.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/types.h> + +#include <linux/firmware/qcom/qcom_qseecom.h> +#include <linux/firmware/qcom/qcom_scm.h> + +struct qseecom_app_desc { + const char *app_name; + const char *dev_name; +}; + +static void qseecom_client_release(struct device *dev) +{ + struct qseecom_client *client; + + client = container_of(dev, struct qseecom_client, aux_dev.dev); + kfree(client); +} + +static void qseecom_client_remove(void *data) +{ + struct qseecom_client *client = data; + + auxiliary_device_delete(&client->aux_dev); + auxiliary_device_uninit(&client->aux_dev); +} + +static int qseecom_client_register(struct platform_device *qseecom_dev, + const struct qseecom_app_desc *desc) +{ + struct qseecom_client *client; + u32 app_id; + int ret; + + /* Try to find the app ID, skip device if not found */ + ret = qcom_scm_qseecom_app_get_id(desc->app_name, &app_id); + if (ret) + return ret == -ENOENT ? 0 : ret; + + dev_info(&qseecom_dev->dev, "setting up client for %s\n", desc->app_name); + + /* Allocate and set-up the client device */ + client = kzalloc(sizeof(*client), GFP_KERNEL); + if (!client) + return -ENOMEM; + + client->aux_dev.name = desc->dev_name; + client->aux_dev.dev.parent = &qseecom_dev->dev; + client->aux_dev.dev.release = qseecom_client_release; + client->app_id = app_id; + + ret = auxiliary_device_init(&client->aux_dev); + if (ret) { + kfree(client); + return ret; + } + + ret = auxiliary_device_add(&client->aux_dev); + if (ret) { + auxiliary_device_uninit(&client->aux_dev); + return ret; + } + + ret = devm_add_action_or_reset(&qseecom_dev->dev, qseecom_client_remove, client); + if (ret) + return ret; + + return 0; +} + +/* + * List of supported applications. One client device will be created per entry, + * assuming the app has already been loaded (usually by firmware bootloaders) + * and its ID can be queried successfully. + */ +static const struct qseecom_app_desc qcom_qseecom_apps[] = { + { "qcom.tz.uefisecapp", "uefisecapp" }, +}; + +static int qcom_qseecom_probe(struct platform_device *qseecom_dev) +{ + int ret; + int i; + + /* Set up client devices for each base application */ + for (i = 0; i < ARRAY_SIZE(qcom_qseecom_apps); i++) { + ret = qseecom_client_register(qseecom_dev, &qcom_qseecom_apps[i]); + if (ret) + return ret; + } + + return 0; +} + +static struct platform_driver qcom_qseecom_driver = { + .driver = { + .name = "qcom_qseecom", + }, + .probe = qcom_qseecom_probe, +}; + +static int __init qcom_qseecom_init(void) +{ + return platform_driver_register(&qcom_qseecom_driver); +} +subsys_initcall(qcom_qseecom_init); + +MODULE_AUTHOR("Maximilian Luz <luzmaximilian@gmail.com>"); +MODULE_DESCRIPTION("Driver for the Qualcomm SEE (QSEECOM) interface"); +MODULE_LICENSE("GPL"); diff --git a/drivers/firmware/qcom_qseecom_uefisecapp.c b/drivers/firmware/qcom_qseecom_uefisecapp.c new file mode 100644 index 000000000000..a33acdaf7b78 --- /dev/null +++ b/drivers/firmware/qcom_qseecom_uefisecapp.c @@ -0,0 +1,871 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Client driver for Qualcomm UEFI Secure Application (qcom.tz.uefisecapp). + * Provides access to UEFI variables on platforms where they are secured by the + * aforementioned Secure Execution Environment (SEE) application. + * + * Copyright (C) 2023 Maximilian Luz <luzmaximilian@gmail.com> + */ + +#include <linux/efi.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/types.h> +#include <linux/ucs2_string.h> + +#include <linux/firmware/qcom/qcom_qseecom.h> + +/* -- Qualcomm "uefisecapp" interface definitions. -------------------------- */ + +/* Maximum length of name string with null-terminator */ +#define QSEE_MAX_NAME_LEN 1024 + +#define QSEE_CMD_UEFI(x) (0x8000 | (x)) +#define QSEE_CMD_UEFI_GET_VARIABLE QSEE_CMD_UEFI(0) +#define QSEE_CMD_UEFI_SET_VARIABLE QSEE_CMD_UEFI(1) +#define QSEE_CMD_UEFI_GET_NEXT_VARIABLE QSEE_CMD_UEFI(2) +#define QSEE_CMD_UEFI_QUERY_VARIABLE_INFO QSEE_CMD_UEFI(3) + +/** + * struct qsee_req_uefi_get_variable - Request for GetVariable command. + * @command_id: The ID of the command. Must be %QSEE_CMD_UEFI_GET_VARIABLE. + * @length: Length of the request in bytes, including this struct and any + * parameters (name, GUID) stored after it as well as any padding + * thereof for alignment. + * @name_offset: Offset from the start of this struct to where the variable + * name is stored (as utf-16 string), in bytes. + * @name_size: Size of the name parameter in bytes, including null-terminator. + * @guid_offset: Offset from the start of this struct to where the GUID + * parameter is stored, in bytes. + * @guid_size: Size of the GUID parameter in bytes, i.e. sizeof(efi_guid_t). + * @data_size: Size of the output buffer, in bytes. + */ +struct qsee_req_uefi_get_variable { + u32 command_id; + u32 length; + u32 name_offset; + u32 name_size; + u32 guid_offset; + u32 guid_size; + u32 data_size; +} __packed; + +/** + * struct qsee_rsp_uefi_get_variable - Response for GetVariable command. + * @command_id: The ID of the command. Should be %QSEE_CMD_UEFI_GET_VARIABLE. + * @length: Length of the response in bytes, including this struct and the + * returned data. + * @status: Status of this command. + * @attributes: EFI variable attributes. + * @data_offset: Offset from the start of this struct to where the data is + * stored, in bytes. + * @data_size: Size of the returned data, in bytes. In case status indicates + * that the buffer is too small, this will be the size required + * to store the EFI variable data. + */ +struct qsee_rsp_uefi_get_variable { + u32 command_id; + u32 length; + u32 status; + u32 attributes; + u32 data_offset; + u32 data_size; +} __packed; + +/** + * struct qsee_req_uefi_set_variable - Request for the SetVariable command. + * @command_id: The ID of the command. Must be %QSEE_CMD_UEFI_SET_VARIABLE. + * @length: Length of the request in bytes, including this struct and any + * parameters (name, GUID, data) stored after it as well as any + * padding thereof required for alignment. + * @name_offset: Offset from the start of this struct to where the variable + * name is stored (as utf-16 string), in bytes. + * @name_size: Size of the name parameter in bytes, including null-terminator. + * @guid_offset: Offset from the start of this struct to where the GUID + * parameter is stored, in bytes. + * @guid_size: Size of the GUID parameter in bytes, i.e. sizeof(efi_guid_t). + * @attributes: The EFI variable attributes to set for this variable. + * @data_offset: Offset from the start of this struct to where the EFI variable + * data is stored, in bytes. + * @data_size: Size of EFI variable data, in bytes. + * + */ +struct qsee_req_uefi_set_variable { + u32 command_id; + u32 length; + u32 name_offset; + u32 name_size; + u32 guid_offset; + u32 guid_size; + u32 attributes; + u32 data_offset; + u32 data_size; +} __packed; + +/** + * struct qsee_rsp_uefi_set_variable - Response for the SetVariable command. + * @command_id: The ID of the command. Should be %QSEE_CMD_UEFI_SET_VARIABLE. + * @length: The length of this response, i.e. the size of this struct in + * bytes. + * @status: Status of this command. + * @_unknown1: Unknown response field. + * @_unknown2: Unknown response field. + */ +struct qsee_rsp_uefi_set_variable { + u32 command_id; + u32 length; + u32 status; + u32 _unknown1; + u32 _unknown2; +} __packed; + +/** + * struct qsee_req_uefi_get_next_variable - Request for the + * GetNextVariableName command. + * @command_id: The ID of the command. Must be + * %QSEE_CMD_UEFI_GET_NEXT_VARIABLE. + * @length: Length of the request in bytes, including this struct and any + * parameters (name, GUID) stored after it as well as any padding + * thereof for alignment. + * @guid_offset: Offset from the start of this struct to where the GUID + * parameter is stored, in bytes. + * @guid_size: Size of the GUID parameter in bytes, i.e. sizeof(efi_guid_t). + * @name_offset: Offset from the start of this struct to where the variable + * name is stored (as utf-16 string), in bytes. + * @name_size: Size of the name parameter in bytes, including null-terminator. + */ +struct qsee_req_uefi_get_next_variable { + u32 command_id; + u32 length; + u32 guid_offset; + u32 guid_size; + u32 name_offset; + u32 name_size; +} __packed; + +/** + * struct qsee_rsp_uefi_get_next_variable - Response for the + * GetNextVariableName command. + * @command_id: The ID of the command. Should be + * %QSEE_CMD_UEFI_GET_NEXT_VARIABLE. + * @length: Length of the response in bytes, including this struct and any + * parameters (name, GUID) stored after it as well as any padding + * thereof for alignment. + * @status: Status of this command. + * @guid_offset: Offset from the start of this struct to where the GUID + * parameter is stored, in bytes. + * @guid_size: Size of the GUID parameter in bytes, i.e. sizeof(efi_guid_t). + * @name_offset: Offset from the start of this struct to where the variable + * name is stored (as utf-16 string), in bytes. + * @name_size: Size of the name parameter in bytes, including null-terminator. + */ +struct qsee_rsp_uefi_get_next_variable { + u32 command_id; + u32 length; + u32 status; + u32 guid_offset; + u32 guid_size; + u32 name_offset; + u32 name_size; +} __packed; + +/** + * struct qsee_req_uefi_query_variable_info - Response for the + * GetNextVariableName command. + * @command_id: The ID of the command. Must be + * %QSEE_CMD_UEFI_QUERY_VARIABLE_INFO. + * @length: The length of this request, i.e. the size of this struct in + * bytes. + * @attributes: The storage attributes to query the info for. + */ +struct qsee_req_uefi_query_variable_info { + u32 command_id; + u32 length; + u32 attributes; +} __packed; + +/** + * struct qsee_rsp_uefi_query_variable_info - Response for the + * GetNextVariableName command. + * @command_id: The ID of the command. Must be + * %QSEE_CMD_UEFI_QUERY_VARIABLE_INFO. + * @length: The length of this response, i.e. the size of this + * struct in bytes. + * @status: Status of this command. + * @_pad: Padding. + * @storage_space: Full storage space size, in bytes. + * @remaining_space: Free storage space available, in bytes. + * @max_variable_size: Maximum variable data size, in bytes. + */ +struct qsee_rsp_uefi_query_variable_info { + u32 command_id; + u32 length; + u32 status; + u32 _pad; + u64 storage_space; + u64 remaining_space; + u64 max_variable_size; +} __packed; + +/* -- Alignment helpers ----------------------------------------------------- */ + +/* + * Helper macro to ensure proper alignment of types (fields and arrays) when + * stored in some (contiguous) buffer. + * + * Note: The driver from which this one has been reverse-engineered expects an + * alignment of 8 bytes (64 bits) for GUIDs. Our definition of efi_guid_t, + * however, has an alignment of 4 byte (32 bits). So far, this seems to work + * fine here. See also the comment on the typedef of efi_guid_t. + */ +#define qcuefi_buf_align_fields(fields...) \ + ({ \ + size_t __len = 0; \ + fields \ + __len; \ + }) + +#define __field_impl(size, align, offset) \ + ({ \ + size_t *__offset = (offset); \ + size_t __aligned; \ + \ + __aligned = ALIGN(__len, align); \ + __len = __aligned + (size); \ + \ + if (__offset) \ + *__offset = __aligned; \ + }); + +#define __array_offs(type, count, offset) \ + __field_impl(sizeof(type) * (count), __alignof__(type), offset) + +#define __array(type, count) __array_offs(type, count, NULL) +#define __field_offs(type, offset) __array_offs(type, 1, offset) +#define __field(type) __array_offs(type, 1, NULL) + +/* -- UEFI app interface. --------------------------------------------------- */ + +struct qcuefi_client { + struct qseecom_client *client; + struct efivars efivars; +}; + +static struct device *qcuefi_dev(struct qcuefi_client *qcuefi) +{ + return &qcuefi->client->aux_dev.dev; +} + +static efi_status_t qsee_uefi_status_to_efi(u32 status) +{ + u64 category = status & 0xf0000000; + u64 code = status & 0x0fffffff; + + return category << (BITS_PER_LONG - 32) | code; +} + +static efi_status_t qsee_uefi_get_variable(struct qcuefi_client *qcuefi, const efi_char16_t *name, + const efi_guid_t *guid, u32 *attributes, + unsigned long *data_size, void *data) +{ + struct qsee_req_uefi_get_variable *req_data; + struct qsee_rsp_uefi_get_variable *rsp_data; + unsigned long buffer_size = *data_size; + efi_status_t efi_status = EFI_SUCCESS; + unsigned long name_length; + size_t guid_offs; + size_t name_offs; + size_t req_size; + size_t rsp_size; + ssize_t status; + + if (!name || !guid) + return EFI_INVALID_PARAMETER; + + name_length = ucs2_strnlen(name, QSEE_MAX_NAME_LEN) + 1; + if (name_length > QSEE_MAX_NAME_LEN) + return EFI_INVALID_PARAMETER; + + if (buffer_size && !data) + return EFI_INVALID_PARAMETER; + + req_size = qcuefi_buf_align_fields( + __field(*req_data) + __array_offs(*name, name_length, &name_offs) + __field_offs(*guid, &guid_offs) + ); + + rsp_size = qcuefi_buf_align_fields( + __field(*rsp_data) + __array(u8, buffer_size) + ); + + req_data = kzalloc(req_size, GFP_KERNEL); + if (!req_data) { + efi_status = EFI_OUT_OF_RESOURCES; + goto out; + } + + rsp_data = kzalloc(rsp_size, GFP_KERNEL); + if (!rsp_data) { + efi_status = EFI_OUT_OF_RESOURCES; + goto out_free_req; + } + + req_data->command_id = QSEE_CMD_UEFI_GET_VARIABLE; + req_data->data_size = buffer_size; + req_data->name_offset = name_offs; + req_data->name_size = name_length * sizeof(*name); + req_data->guid_offset = guid_offs; + req_data->guid_size = sizeof(*guid); + req_data->length = req_size; + + status = ucs2_strscpy(((void *)req_data) + req_data->name_offset, name, name_length); + if (status < 0) + return EFI_INVALID_PARAMETER; + + memcpy(((void *)req_data) + req_data->guid_offset, guid, req_data->guid_size); + + status = qcom_qseecom_app_send(qcuefi->client, req_data, req_size, rsp_data, rsp_size); + if (status) { + efi_status = EFI_DEVICE_ERROR; + goto out_free; + } + + if (rsp_data->command_id != QSEE_CMD_UEFI_GET_VARIABLE) { + efi_status = EFI_DEVICE_ERROR; + goto out_free; + } + + if (rsp_data->length < sizeof(*rsp_data)) { + efi_status = EFI_DEVICE_ERROR; + goto out_free; + } + + if (rsp_data->status) { + dev_dbg(qcuefi_dev(qcuefi), "%s: uefisecapp error: 0x%x\n", + __func__, rsp_data->status); + efi_status = qsee_uefi_status_to_efi(rsp_data->status); + + /* Update size and attributes in case buffer is too small. */ + if (efi_status == EFI_BUFFER_TOO_SMALL) { + *data_size = rsp_data->data_size; + if (attributes) + *attributes = rsp_data->attributes; + } + + goto out_free; + } + + if (rsp_data->length > rsp_size) { + efi_status = EFI_DEVICE_ERROR; + goto out_free; + } + + if (rsp_data->data_offset + rsp_data->data_size > rsp_data->length) { + efi_status = EFI_DEVICE_ERROR; + goto out_free; + } + + /* + * Note: We need to set attributes and data size even if the buffer is + * too small and we won't copy any data. This is described in spec, so + * that callers can either allocate a buffer properly (with two calls + * to this function) or just read back attributes withouth having to + * deal with that. + * + * Specifically: + * - If we have a buffer size of zero and no buffer, just return the + * attributes, required size, and indicate success. + * - If the buffer size is nonzero but too small, indicate that as an + * error. + * - Otherwise, we are good to copy the data. + * + * Note that we have already ensured above that the buffer pointer is + * non-NULL if its size is nonzero. + */ + *data_size = rsp_data->data_size; + if (attributes) + *attributes = rsp_data->attributes; + + if (buffer_size == 0 && !data) { + efi_status = EFI_SUCCESS; + goto out_free; + } + + if (buffer_size < rsp_data->data_size) { + efi_status = EFI_BUFFER_TOO_SMALL; + goto out_free; + } + + memcpy(data, ((void *)rsp_data) + rsp_data->data_offset, rsp_data->data_size); + +out_free: + kfree(rsp_data); +out_free_req: + kfree(req_data); +out: + return efi_status; +} + +static efi_status_t qsee_uefi_set_variable(struct qcuefi_client *qcuefi, const efi_char16_t *name, + const efi_guid_t *guid, u32 attributes, + unsigned long data_size, const void *data) +{ + struct qsee_req_uefi_set_variable *req_data; + struct qsee_rsp_uefi_set_variable *rsp_data; + efi_status_t efi_status = EFI_SUCCESS; + unsigned long name_length; + size_t name_offs; + size_t guid_offs; + size_t data_offs; + size_t req_size; + ssize_t status; + + if (!name || !guid) + return EFI_INVALID_PARAMETER; + + name_length = ucs2_strnlen(name, QSEE_MAX_NAME_LEN) + 1; + if (name_length > QSEE_MAX_NAME_LEN) + return EFI_INVALID_PARAMETER; + + /* + * Make sure we have some data if data_size is nonzero. Note that using + * a size of zero is a valid use-case described in spec and deletes the + * variable. + */ + if (data_size && !data) + return EFI_INVALID_PARAMETER; + + req_size = qcuefi_buf_align_fields( + __field(*req_data) + __array_offs(*name, name_length, &name_offs) + __field_offs(*guid, &guid_offs) + __array_offs(u8, data_size, &data_offs) + ); + + req_data = kzalloc(req_size, GFP_KERNEL); + if (!req_data) { + efi_status = EFI_OUT_OF_RESOURCES; + goto out; + } + + rsp_data = kzalloc(sizeof(*rsp_data), GFP_KERNEL); + if (!rsp_data) { + efi_status = EFI_OUT_OF_RESOURCES; + goto out_free_req; + } + + req_data->command_id = QSEE_CMD_UEFI_SET_VARIABLE; + req_data->attributes = attributes; + req_data->name_offset = name_offs; + req_data->name_size = name_length * sizeof(*name); + req_data->guid_offset = guid_offs; + req_data->guid_size = sizeof(*guid); + req_data->data_offset = data_offs; + req_data->data_size = data_size; + req_data->length = req_size; + + status = ucs2_strscpy(((void *)req_data) + req_data->name_offset, name, name_length); + if (status < 0) + return EFI_INVALID_PARAMETER; + + memcpy(((void *)req_data) + req_data->guid_offset, guid, req_data->guid_size); + + if (data_size) + memcpy(((void *)req_data) + req_data->data_offset, data, req_data->data_size); + + status = qcom_qseecom_app_send(qcuefi->client, req_data, req_size, rsp_data, + sizeof(*rsp_data)); + if (status) { + efi_status = EFI_DEVICE_ERROR; + goto out_free; + } + + if (rsp_data->command_id != QSEE_CMD_UEFI_SET_VARIABLE) { + efi_status = EFI_DEVICE_ERROR; + goto out_free; + } + + if (rsp_data->length != sizeof(*rsp_data)) { + efi_status = EFI_DEVICE_ERROR; + goto out_free; + } + + if (rsp_data->status) { + dev_dbg(qcuefi_dev(qcuefi), "%s: uefisecapp error: 0x%x\n", + __func__, rsp_data->status); + efi_status = qsee_uefi_status_to_efi(rsp_data->status); + } + +out_free: + kfree(rsp_data); +out_free_req: + kfree(req_data); +out: + return efi_status; +} + +static efi_status_t qsee_uefi_get_next_variable(struct qcuefi_client *qcuefi, + unsigned long *name_size, efi_char16_t *name, + efi_guid_t *guid) +{ + struct qsee_req_uefi_get_next_variable *req_data; + struct qsee_rsp_uefi_get_next_variable *rsp_data; + efi_status_t efi_status = EFI_SUCCESS; + size_t guid_offs; + size_t name_offs; + size_t req_size; + size_t rsp_size; + ssize_t status; + + if (!name_size || !name || !guid) + return EFI_INVALID_PARAMETER; + + if (*name_size == 0) + return EFI_INVALID_PARAMETER; + + req_size = qcuefi_buf_align_fields( + __field(*req_data) + __field_offs(*guid, &guid_offs) + __array_offs(*name, *name_size / sizeof(*name), &name_offs) + ); + + rsp_size = qcuefi_buf_align_fields( + __field(*rsp_data) + __field(*guid) + __array(*name, *name_size / sizeof(*name)) + ); + + req_data = kzalloc(req_size, GFP_KERNEL); + if (!req_data) { + efi_status = EFI_OUT_OF_RESOURCES; + goto out; + } + + rsp_data = kzalloc(rsp_size, GFP_KERNEL); + if (!rsp_data) { + efi_status = EFI_OUT_OF_RESOURCES; + goto out_free_req; + } + + req_data->command_id = QSEE_CMD_UEFI_GET_NEXT_VARIABLE; + req_data->guid_offset = guid_offs; + req_data->guid_size = sizeof(*guid); + req_data->name_offset = name_offs; + req_data->name_size = *name_size; + req_data->length = req_size; + + memcpy(((void *)req_data) + req_data->guid_offset, guid, req_data->guid_size); + status = ucs2_strscpy(((void *)req_data) + req_data->name_offset, name, + *name_size / sizeof(*name)); + if (status < 0) + return EFI_INVALID_PARAMETER; + + status = qcom_qseecom_app_send(qcuefi->client, req_data, req_size, rsp_data, rsp_size); + if (status) { + efi_status = EFI_DEVICE_ERROR; + goto out_free; + } + + if (rsp_data->command_id != QSEE_CMD_UEFI_GET_NEXT_VARIABLE) { + efi_status = EFI_DEVICE_ERROR; + goto out_free; + } + + if (rsp_data->length < sizeof(*rsp_data)) { + efi_status = EFI_DEVICE_ERROR; + goto out_free; + } + + if (rsp_data->status) { + dev_dbg(qcuefi_dev(qcuefi), "%s: uefisecapp error: 0x%x\n", + __func__, rsp_data->status); + efi_status = qsee_uefi_status_to_efi(rsp_data->status); + + /* + * If the buffer to hold the name is too small, update the + * name_size with the required size, so that callers can + * reallocate it accordingly. + */ + if (efi_status == EFI_BUFFER_TOO_SMALL) + *name_size = rsp_data->name_size; + + goto out_free; + } + + if (rsp_data->length > rsp_size) { + efi_status = EFI_DEVICE_ERROR; + goto out_free; + } + + if (rsp_data->name_offset + rsp_data->name_size > rsp_data->length) { + efi_status = EFI_DEVICE_ERROR; + goto out_free; + } + + if (rsp_data->guid_offset + rsp_data->guid_size > rsp_data->length) { + efi_status = EFI_DEVICE_ERROR; + goto out_free; + } + + if (rsp_data->name_size > *name_size) { + *name_size = rsp_data->name_size; + efi_status = EFI_BUFFER_TOO_SMALL; + goto out_free; + } + + if (rsp_data->guid_size != sizeof(*guid)) { + efi_status = EFI_DEVICE_ERROR; + goto out_free; + } + + memcpy(guid, ((void *)rsp_data) + rsp_data->guid_offset, rsp_data->guid_size); + status = ucs2_strscpy(name, ((void *)rsp_data) + rsp_data->name_offset, + rsp_data->name_size / sizeof(*name)); + *name_size = rsp_data->name_size; + + if (status < 0) { + /* + * Return EFI_DEVICE_ERROR here because the buffer size should + * have already been validated above, causing this function to + * bail with EFI_BUFFER_TOO_SMALL. + */ + return EFI_DEVICE_ERROR; + } + +out_free: + kfree(rsp_data); +out_free_req: + kfree(req_data); +out: + return efi_status; +} + +static efi_status_t qsee_uefi_query_variable_info(struct qcuefi_client *qcuefi, u32 attr, + u64 *storage_space, u64 *remaining_space, + u64 *max_variable_size) +{ + struct qsee_req_uefi_query_variable_info *req_data; + struct qsee_rsp_uefi_query_variable_info *rsp_data; + efi_status_t efi_status = EFI_SUCCESS; + int status; + + req_data = kzalloc(sizeof(*req_data), GFP_KERNEL); + if (!req_data) { + efi_status = EFI_OUT_OF_RESOURCES; + goto out; + } + + rsp_data = kzalloc(sizeof(*rsp_data), GFP_KERNEL); + if (!rsp_data) { + efi_status = EFI_OUT_OF_RESOURCES; + goto out_free_req; + } + + req_data->command_id = QSEE_CMD_UEFI_QUERY_VARIABLE_INFO; + req_data->attributes = attr; + req_data->length = sizeof(*req_data); + + status = qcom_qseecom_app_send(qcuefi->client, req_data, sizeof(*req_data), rsp_data, + sizeof(*rsp_data)); + if (status) { + efi_status = EFI_DEVICE_ERROR; + goto out_free; + } + + if (rsp_data->command_id != QSEE_CMD_UEFI_QUERY_VARIABLE_INFO) { + efi_status = EFI_DEVICE_ERROR; + goto out_free; + } + + if (rsp_data->length != sizeof(*rsp_data)) { + efi_status = EFI_DEVICE_ERROR; + goto out_free; + } + + if (rsp_data->status) { + dev_dbg(qcuefi_dev(qcuefi), "%s: uefisecapp error: 0x%x\n", + __func__, rsp_data->status); + efi_status = qsee_uefi_status_to_efi(rsp_data->status); + goto out_free; + } + + if (storage_space) + *storage_space = rsp_data->storage_space; + + if (remaining_space) + *remaining_space = rsp_data->remaining_space; + + if (max_variable_size) + *max_variable_size = rsp_data->max_variable_size; + +out_free: + kfree(rsp_data); +out_free_req: + kfree(req_data); +out: + return efi_status; +} + +/* -- Global efivar interface. ---------------------------------------------- */ + +static struct qcuefi_client *__qcuefi; +static DEFINE_MUTEX(__qcuefi_lock); + +static int qcuefi_set_reference(struct qcuefi_client *qcuefi) +{ + mutex_lock(&__qcuefi_lock); + + if (qcuefi && __qcuefi) { + mutex_unlock(&__qcuefi_lock); + return -EEXIST; + } + + __qcuefi = qcuefi; + + mutex_unlock(&__qcuefi_lock); + return 0; +} + +static struct qcuefi_client *qcuefi_acquire(void) +{ + mutex_lock(&__qcuefi_lock); + return __qcuefi; +} + +static void qcuefi_release(void) +{ + mutex_unlock(&__qcuefi_lock); +} + +static efi_status_t qcuefi_get_variable(efi_char16_t *name, efi_guid_t *vendor, u32 *attr, + unsigned long *data_size, void *data) +{ + struct qcuefi_client *qcuefi; + efi_status_t status; + + qcuefi = qcuefi_acquire(); + if (!qcuefi) + return EFI_NOT_READY; + + status = qsee_uefi_get_variable(qcuefi, name, vendor, attr, data_size, data); + + qcuefi_release(); + return status; +} + +static efi_status_t qcuefi_set_variable(efi_char16_t *name, efi_guid_t *vendor, + u32 attr, unsigned long data_size, void *data) +{ + struct qcuefi_client *qcuefi; + efi_status_t status; + + qcuefi = qcuefi_acquire(); + if (!qcuefi) + return EFI_NOT_READY; + + status = qsee_uefi_set_variable(qcuefi, name, vendor, attr, data_size, data); + + qcuefi_release(); + return status; +} + +static efi_status_t qcuefi_get_next_variable(unsigned long *name_size, efi_char16_t *name, + efi_guid_t *vendor) +{ + struct qcuefi_client *qcuefi; + efi_status_t status; + + qcuefi = qcuefi_acquire(); + if (!qcuefi) + return EFI_NOT_READY; + + status = qsee_uefi_get_next_variable(qcuefi, name_size, name, vendor); + + qcuefi_release(); + return status; +} + +static efi_status_t qcuefi_query_variable_info(u32 attr, u64 *storage_space, u64 *remaining_space, + u64 *max_variable_size) +{ + struct qcuefi_client *qcuefi; + efi_status_t status; + + qcuefi = qcuefi_acquire(); + if (!qcuefi) + return EFI_NOT_READY; + + status = qsee_uefi_query_variable_info(qcuefi, attr, storage_space, remaining_space, + max_variable_size); + + qcuefi_release(); + return status; +} + +static const struct efivar_operations qcom_efivar_ops = { + .get_variable = qcuefi_get_variable, + .set_variable = qcuefi_set_variable, + .get_next_variable = qcuefi_get_next_variable, + .query_variable_info = qcuefi_query_variable_info, +}; + +/* -- Driver setup. --------------------------------------------------------- */ + +static int qcom_uefisecapp_probe(struct auxiliary_device *aux_dev, + const struct auxiliary_device_id *aux_dev_id) +{ + struct qcuefi_client *qcuefi; + int status; + + qcuefi = devm_kzalloc(&aux_dev->dev, sizeof(*qcuefi), GFP_KERNEL); + if (!qcuefi) + return -ENOMEM; + + qcuefi->client = container_of(aux_dev, struct qseecom_client, aux_dev); + + auxiliary_set_drvdata(aux_dev, qcuefi); + status = qcuefi_set_reference(qcuefi); + if (status) + return status; + + status = efivars_register(&qcuefi->efivars, &qcom_efivar_ops); + if (status) + qcuefi_set_reference(NULL); + + return status; +} + +static void qcom_uefisecapp_remove(struct auxiliary_device *aux_dev) +{ + struct qcuefi_client *qcuefi = auxiliary_get_drvdata(aux_dev); + + efivars_unregister(&qcuefi->efivars); + qcuefi_set_reference(NULL); +} + +static const struct auxiliary_device_id qcom_uefisecapp_id_table[] = { + { .name = "qcom_qseecom.uefisecapp" }, + {} +}; +MODULE_DEVICE_TABLE(auxiliary, qcom_uefisecapp_id_table); + +static struct auxiliary_driver qcom_uefisecapp_driver = { + .probe = qcom_uefisecapp_probe, + .remove = qcom_uefisecapp_remove, + .id_table = qcom_uefisecapp_id_table, + .driver = { + .name = "qcom_qseecom_uefisecapp", + .probe_type = PROBE_PREFER_ASYNCHRONOUS, + }, +}; +module_auxiliary_driver(qcom_uefisecapp_driver); + +MODULE_AUTHOR("Maximilian Luz <luzmaximilian@gmail.com>"); +MODULE_DESCRIPTION("Client driver for Qualcomm SEE UEFI Secure App"); +MODULE_LICENSE("GPL"); diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c index 06fe8aca870d..520de9b5633a 100644 --- a/drivers/firmware/qcom_scm.c +++ b/drivers/firmware/qcom_scm.c @@ -2,24 +2,25 @@ /* Copyright (c) 2010,2015,2019 The Linux Foundation. All rights reserved. * Copyright (C) 2015 Linaro Ltd. */ -#include <linux/platform_device.h> -#include <linux/init.h> -#include <linux/interrupt.h> + +#include <linux/arm-smccc.h> +#include <linux/clk.h> #include <linux/completion.h> #include <linux/cpumask.h> -#include <linux/export.h> #include <linux/dma-mapping.h> +#include <linux/export.h> +#include <linux/firmware/qcom/qcom_scm.h> +#include <linux/init.h> #include <linux/interconnect.h> +#include <linux/interrupt.h> #include <linux/module.h> -#include <linux/types.h> -#include <linux/firmware/qcom/qcom_scm.h> #include <linux/of.h> #include <linux/of_address.h> #include <linux/of_irq.h> #include <linux/of_platform.h> -#include <linux/clk.h> +#include <linux/platform_device.h> #include <linux/reset-controller.h> -#include <linux/arm-smccc.h> +#include <linux/types.h> #include "qcom_scm.h" @@ -55,6 +56,53 @@ struct qcom_scm_mem_map_info { __le64 mem_size; }; +/** + * struct qcom_scm_qseecom_resp - QSEECOM SCM call response. + * @result: Result or status of the SCM call. See &enum qcom_scm_qseecom_result. + * @resp_type: Type of the response. See &enum qcom_scm_qseecom_resp_type. + * @data: Response data. The type of this data is given in @resp_type. + */ +struct qcom_scm_qseecom_resp { + u64 result; + u64 resp_type; + u64 data; +}; + +enum qcom_scm_qseecom_result { + QSEECOM_RESULT_SUCCESS = 0, + QSEECOM_RESULT_INCOMPLETE = 1, + QSEECOM_RESULT_BLOCKED_ON_LISTENER = 2, + QSEECOM_RESULT_FAILURE = 0xFFFFFFFF, +}; + +enum qcom_scm_qseecom_resp_type { + QSEECOM_SCM_RES_APP_ID = 0xEE01, + QSEECOM_SCM_RES_QSEOS_LISTENER_ID = 0xEE02, +}; + +enum qcom_scm_qseecom_tz_owner { + QSEECOM_TZ_OWNER_SIP = 2, + QSEECOM_TZ_OWNER_TZ_APPS = 48, + QSEECOM_TZ_OWNER_QSEE_OS = 50 +}; + +enum qcom_scm_qseecom_tz_svc { + QSEECOM_TZ_SVC_APP_ID_PLACEHOLDER = 0, + QSEECOM_TZ_SVC_APP_MGR = 1, + QSEECOM_TZ_SVC_INFO = 6, +}; + +enum qcom_scm_qseecom_tz_cmd_app { + QSEECOM_TZ_CMD_APP_SEND = 1, + QSEECOM_TZ_CMD_APP_LOOKUP = 3, +}; + +enum qcom_scm_qseecom_tz_cmd_info { + QSEECOM_TZ_CMD_INFO_VERSION = 3, +}; + +#define QSEECOM_MAX_APP_NAME_SIZE 64 + /* Each bit configures cold/warm boot address for one of the 4 CPUs */ static const u8 qcom_scm_cpu_cold_bits[QCOM_SCM_BOOT_MAX_CPUS] = { 0, BIT(0), BIT(3), BIT(5) @@ -168,6 +216,12 @@ static enum qcom_scm_convention __get_convention(void) return qcom_scm_convention; /* + * Per the "SMC calling convention specification", the 64-bit calling + * convention can only be used when the client is 64-bit, otherwise + * system will encounter the undefined behaviour. + */ +#if IS_ENABLED(CONFIG_ARM64) + /* * Device isn't required as there is only one argument - no device * needed to dma_map_single to secure world */ @@ -187,6 +241,7 @@ static enum qcom_scm_convention __get_convention(void) forced = true; goto found; } +#endif probed_convention = SMC_CONVENTION_ARM_32; ret = __scm_smc_call(NULL, &desc, probed_convention, &res, true); @@ -403,6 +458,29 @@ int qcom_scm_set_remote_state(u32 state, u32 id) } EXPORT_SYMBOL_GPL(qcom_scm_set_remote_state); +static int qcom_scm_disable_sdi(void) +{ + int ret; + struct qcom_scm_desc desc = { + .svc = QCOM_SCM_SVC_BOOT, + .cmd = QCOM_SCM_BOOT_SDI_CONFIG, + .args[0] = 1, /* Disable watchdog debug */ + .args[1] = 0, /* Disable SDI */ + .arginfo = QCOM_SCM_ARGS(2), + .owner = ARM_SMCCC_OWNER_SIP, + }; + struct qcom_scm_res res; + + ret = qcom_scm_clk_enable(); + if (ret) + return ret; + ret = qcom_scm_call(__scm->dev, &desc, &res); + + qcom_scm_clk_disable(); + + return ret ? : res.result[0]; +} + static int __qcom_scm_set_dload_mode(struct device *dev, bool enable) { struct qcom_scm_desc desc = { @@ -1321,6 +1399,340 @@ static int qcom_scm_find_dload_address(struct device *dev, u64 *addr) return 0; } +#ifdef CONFIG_QCOM_QSEECOM + +/* Lock for QSEECOM SCM call executions */ +static DEFINE_MUTEX(qcom_scm_qseecom_call_lock); + +static int __qcom_scm_qseecom_call(const struct qcom_scm_desc *desc, + struct qcom_scm_qseecom_resp *res) +{ + struct qcom_scm_res scm_res = {}; + int status; + + /* + * QSEECOM SCM calls should not be executed concurrently. Therefore, we + * require the respective call lock to be held. + */ + lockdep_assert_held(&qcom_scm_qseecom_call_lock); + + status = qcom_scm_call(__scm->dev, desc, &scm_res); + + res->result = scm_res.result[0]; + res->resp_type = scm_res.result[1]; + res->data = scm_res.result[2]; + + if (status) + return status; + + return 0; +} + +/** + * qcom_scm_qseecom_call() - Perform a QSEECOM SCM call. + * @desc: SCM call descriptor. + * @res: SCM call response (output). + * + * Performs the QSEECOM SCM call described by @desc, returning the response in + * @rsp. + * + * Return: Zero on success, nonzero on failure. + */ +static int qcom_scm_qseecom_call(const struct qcom_scm_desc *desc, + struct qcom_scm_qseecom_resp *res) +{ + int status; + + /* + * Note: Multiple QSEECOM SCM calls should not be executed same time, + * so lock things here. This needs to be extended to callback/listener + * handling when support for that is implemented. + */ + + mutex_lock(&qcom_scm_qseecom_call_lock); + status = __qcom_scm_qseecom_call(desc, res); + mutex_unlock(&qcom_scm_qseecom_call_lock); + + dev_dbg(__scm->dev, "%s: owner=%x, svc=%x, cmd=%x, result=%lld, type=%llx, data=%llx\n", + __func__, desc->owner, desc->svc, desc->cmd, res->result, + res->resp_type, res->data); + + if (status) { + dev_err(__scm->dev, "qseecom: scm call failed with error %d\n", status); + return status; + } + + /* + * TODO: Handle incomplete and blocked calls: + * + * Incomplete and blocked calls are not supported yet. Some devices + * and/or commands require those, some don't. Let's warn about them + * prominently in case someone attempts to try these commands with a + * device/command combination that isn't supported yet. + */ + WARN_ON(res->result == QSEECOM_RESULT_INCOMPLETE); + WARN_ON(res->result == QSEECOM_RESULT_BLOCKED_ON_LISTENER); + + return 0; +} + +/** + * qcom_scm_qseecom_get_version() - Query the QSEECOM version. + * @version: Pointer where the QSEECOM version will be stored. + * + * Performs the QSEECOM SCM querying the QSEECOM version currently running in + * the TrustZone. + * + * Return: Zero on success, nonzero on failure. + */ +static int qcom_scm_qseecom_get_version(u32 *version) +{ + struct qcom_scm_desc desc = {}; + struct qcom_scm_qseecom_resp res = {}; + u32 feature = 10; + int ret; + + desc.owner = QSEECOM_TZ_OWNER_SIP; + desc.svc = QSEECOM_TZ_SVC_INFO; + desc.cmd = QSEECOM_TZ_CMD_INFO_VERSION; + desc.arginfo = QCOM_SCM_ARGS(1, QCOM_SCM_VAL); + desc.args[0] = feature; + + ret = qcom_scm_qseecom_call(&desc, &res); + if (ret) + return ret; + + *version = res.result; + return 0; +} + +/** + * qcom_scm_qseecom_app_get_id() - Query the app ID for a given QSEE app name. + * @app_name: The name of the app. + * @app_id: The returned app ID. + * + * Query and return the application ID of the SEE app identified by the given + * name. This returned ID is the unique identifier of the app required for + * subsequent communication. + * + * Return: Zero on success, nonzero on failure, -ENOENT if the app has not been + * loaded or could not be found. + */ +int qcom_scm_qseecom_app_get_id(const char *app_name, u32 *app_id) +{ + unsigned long name_buf_size = QSEECOM_MAX_APP_NAME_SIZE; + unsigned long app_name_len = strlen(app_name); + struct qcom_scm_desc desc = {}; + struct qcom_scm_qseecom_resp res = {}; + dma_addr_t name_buf_phys; + char *name_buf; + int status; + + if (app_name_len >= name_buf_size) + return -EINVAL; + + name_buf = kzalloc(name_buf_size, GFP_KERNEL); + if (!name_buf) + return -ENOMEM; + + memcpy(name_buf, app_name, app_name_len); + + name_buf_phys = dma_map_single(__scm->dev, name_buf, name_buf_size, DMA_TO_DEVICE); + status = dma_mapping_error(__scm->dev, name_buf_phys); + if (status) { + kfree(name_buf); + dev_err(__scm->dev, "qseecom: failed to map dma address\n"); + return status; + } + + desc.owner = QSEECOM_TZ_OWNER_QSEE_OS; + desc.svc = QSEECOM_TZ_SVC_APP_MGR; + desc.cmd = QSEECOM_TZ_CMD_APP_LOOKUP; + desc.arginfo = QCOM_SCM_ARGS(2, QCOM_SCM_RW, QCOM_SCM_VAL); + desc.args[0] = name_buf_phys; + desc.args[1] = app_name_len; + + status = qcom_scm_qseecom_call(&desc, &res); + dma_unmap_single(__scm->dev, name_buf_phys, name_buf_size, DMA_TO_DEVICE); + kfree(name_buf); + + if (status) + return status; + + if (res.result == QSEECOM_RESULT_FAILURE) + return -ENOENT; + + if (res.result != QSEECOM_RESULT_SUCCESS) + return -EINVAL; + + if (res.resp_type != QSEECOM_SCM_RES_APP_ID) + return -EINVAL; + + *app_id = res.data; + return 0; +} +EXPORT_SYMBOL_GPL(qcom_scm_qseecom_app_get_id); + +/** + * qcom_scm_qseecom_app_send() - Send to and receive data from a given QSEE app. + * @app_id: The ID of the target app. + * @req: Request buffer sent to the app (must be DMA-mappable). + * @req_size: Size of the request buffer. + * @rsp: Response buffer, written to by the app (must be DMA-mappable). + * @rsp_size: Size of the response buffer. + * + * Sends a request to the QSEE app associated with the given ID and read back + * its response. The caller must provide two DMA memory regions, one for the + * request and one for the response, and fill out the @req region with the + * respective (app-specific) request data. The QSEE app reads this and returns + * its response in the @rsp region. + * + * Return: Zero on success, nonzero on failure. + */ +int qcom_scm_qseecom_app_send(u32 app_id, void *req, size_t req_size, void *rsp, + size_t rsp_size) +{ + struct qcom_scm_qseecom_resp res = {}; + struct qcom_scm_desc desc = {}; + dma_addr_t req_phys; + dma_addr_t rsp_phys; + int status; + + /* Map request buffer */ + req_phys = dma_map_single(__scm->dev, req, req_size, DMA_TO_DEVICE); + status = dma_mapping_error(__scm->dev, req_phys); + if (status) { + dev_err(__scm->dev, "qseecom: failed to map request buffer\n"); + return status; + } + + /* Map response buffer */ + rsp_phys = dma_map_single(__scm->dev, rsp, rsp_size, DMA_FROM_DEVICE); + status = dma_mapping_error(__scm->dev, rsp_phys); + if (status) { + dma_unmap_single(__scm->dev, req_phys, req_size, DMA_TO_DEVICE); + dev_err(__scm->dev, "qseecom: failed to map response buffer\n"); + return status; + } + + /* Set up SCM call data */ + desc.owner = QSEECOM_TZ_OWNER_TZ_APPS; + desc.svc = QSEECOM_TZ_SVC_APP_ID_PLACEHOLDER; + desc.cmd = QSEECOM_TZ_CMD_APP_SEND; + desc.arginfo = QCOM_SCM_ARGS(5, QCOM_SCM_VAL, + QCOM_SCM_RW, QCOM_SCM_VAL, + QCOM_SCM_RW, QCOM_SCM_VAL); + desc.args[0] = app_id; + desc.args[1] = req_phys; + desc.args[2] = req_size; + desc.args[3] = rsp_phys; + desc.args[4] = rsp_size; + + /* Perform call */ + status = qcom_scm_qseecom_call(&desc, &res); + + /* Unmap buffers */ + dma_unmap_single(__scm->dev, rsp_phys, rsp_size, DMA_FROM_DEVICE); + dma_unmap_single(__scm->dev, req_phys, req_size, DMA_TO_DEVICE); + + if (status) + return status; + + if (res.result != QSEECOM_RESULT_SUCCESS) + return -EIO; + + return 0; +} +EXPORT_SYMBOL_GPL(qcom_scm_qseecom_app_send); + +/* + * We do not yet support re-entrant calls via the qseecom interface. To prevent + + any potential issues with this, only allow validated machines for now. + */ +static const struct of_device_id qcom_scm_qseecom_allowlist[] = { + { .compatible = "lenovo,thinkpad-x13s", }, + { } +}; + +static bool qcom_scm_qseecom_machine_is_allowed(void) +{ + struct device_node *np; + bool match; + + np = of_find_node_by_path("/"); + if (!np) + return false; + + match = of_match_node(qcom_scm_qseecom_allowlist, np); + of_node_put(np); + + return match; +} + +static void qcom_scm_qseecom_free(void *data) +{ + struct platform_device *qseecom_dev = data; + + platform_device_del(qseecom_dev); + platform_device_put(qseecom_dev); +} + +static int qcom_scm_qseecom_init(struct qcom_scm *scm) +{ + struct platform_device *qseecom_dev; + u32 version; + int ret; + + /* + * Note: We do two steps of validation here: First, we try to query the + * QSEECOM version as a check to see if the interface exists on this + * device. Second, we check against known good devices due to current + * driver limitations (see comment in qcom_scm_qseecom_allowlist). + * + * Note that we deliberately do the machine check after the version + * check so that we can log potentially supported devices. This should + * be safe as downstream sources indicate that the version query is + * neither blocking nor reentrant. + */ + ret = qcom_scm_qseecom_get_version(&version); + if (ret) + return 0; + + dev_info(scm->dev, "qseecom: found qseecom with version 0x%x\n", version); + + if (!qcom_scm_qseecom_machine_is_allowed()) { + dev_info(scm->dev, "qseecom: untested machine, skipping\n"); + return 0; + } + + /* + * Set up QSEECOM interface device. All application clients will be + * set up and managed by the corresponding driver for it. + */ + qseecom_dev = platform_device_alloc("qcom_qseecom", -1); + if (!qseecom_dev) + return -ENOMEM; + + qseecom_dev->dev.parent = scm->dev; + + ret = platform_device_add(qseecom_dev); + if (ret) { + platform_device_put(qseecom_dev); + return ret; + } + + return devm_add_action_or_reset(scm->dev, qcom_scm_qseecom_free, qseecom_dev); +} + +#else /* CONFIG_QCOM_QSEECOM */ + +static int qcom_scm_qseecom_init(struct qcom_scm *scm) +{ + return 0; +} + +#endif /* CONFIG_QCOM_QSEECOM */ + /** * qcom_scm_is_available() - Checks if SCM is available */ @@ -1468,6 +1880,26 @@ static int qcom_scm_probe(struct platform_device *pdev) if (download_mode) qcom_scm_set_download_mode(true); + + /* + * Disable SDI if indicated by DT that it is enabled by default. + */ + if (of_property_read_bool(pdev->dev.of_node, "qcom,sdi-enabled")) + qcom_scm_disable_sdi(); + + /* + * Initialize the QSEECOM interface. + * + * Note: QSEECOM is fairly self-contained and this only adds the + * interface device (the driver of which does most of the heavy + * lifting). So any errors returned here should be either -ENOMEM or + * -EINVAL (with the latter only in case there's a bug in our code). + * This means that there is no need to bring down the whole SCM driver. + * Just log the error instead and let SCM live. + */ + ret = qcom_scm_qseecom_init(scm); + WARN(ret < 0, "failed to initialize qseecom: %d\n", ret); + return 0; } diff --git a/drivers/firmware/qcom_scm.h b/drivers/firmware/qcom_scm.h index e6e512bd57d1..7b68fa820495 100644 --- a/drivers/firmware/qcom_scm.h +++ b/drivers/firmware/qcom_scm.h @@ -80,6 +80,7 @@ extern int scm_legacy_call(struct device *dev, const struct qcom_scm_desc *desc, #define QCOM_SCM_SVC_BOOT 0x01 #define QCOM_SCM_BOOT_SET_ADDR 0x01 #define QCOM_SCM_BOOT_TERMINATE_PC 0x02 +#define QCOM_SCM_BOOT_SDI_CONFIG 0x09 #define QCOM_SCM_BOOT_SET_DLOAD_MODE 0x10 #define QCOM_SCM_BOOT_SET_ADDR_MC 0x11 #define QCOM_SCM_BOOT_SET_REMOTE_STATE 0x0a diff --git a/drivers/firmware/tegra/bpmp.c b/drivers/firmware/tegra/bpmp.c index 51d062e0c3f1..c1590d3aa9cb 100644 --- a/drivers/firmware/tegra/bpmp.c +++ b/drivers/firmware/tegra/bpmp.c @@ -313,6 +313,8 @@ static ssize_t tegra_bpmp_channel_write(struct tegra_bpmp_channel *channel, return __tegra_bpmp_channel_write(channel, mrq, flags, data, size); } +static int __maybe_unused tegra_bpmp_resume(struct device *dev); + int tegra_bpmp_transfer_atomic(struct tegra_bpmp *bpmp, struct tegra_bpmp_message *msg) { @@ -325,6 +327,14 @@ int tegra_bpmp_transfer_atomic(struct tegra_bpmp *bpmp, if (!tegra_bpmp_message_valid(msg)) return -EINVAL; + if (bpmp->suspended) { + /* Reset BPMP IPC channels during resume based on flags passed */ + if (msg->flags & TEGRA_BPMP_MESSAGE_RESET) + tegra_bpmp_resume(bpmp->dev); + else + return -EAGAIN; + } + channel = bpmp->tx_channel; spin_lock(&bpmp->atomic_tx_lock); @@ -364,6 +374,14 @@ int tegra_bpmp_transfer(struct tegra_bpmp *bpmp, if (!tegra_bpmp_message_valid(msg)) return -EINVAL; + if (bpmp->suspended) { + /* Reset BPMP IPC channels during resume based on flags passed */ + if (msg->flags & TEGRA_BPMP_MESSAGE_RESET) + tegra_bpmp_resume(bpmp->dev); + else + return -EAGAIN; + } + channel = tegra_bpmp_write_threaded(bpmp, msg->mrq, msg->tx.data, msg->tx.size); if (IS_ERR(channel)) @@ -796,10 +814,21 @@ deinit: return err; } +static int __maybe_unused tegra_bpmp_suspend(struct device *dev) +{ + struct tegra_bpmp *bpmp = dev_get_drvdata(dev); + + bpmp->suspended = true; + + return 0; +} + static int __maybe_unused tegra_bpmp_resume(struct device *dev) { struct tegra_bpmp *bpmp = dev_get_drvdata(dev); + bpmp->suspended = false; + if (bpmp->soc->ops->resume) return bpmp->soc->ops->resume(bpmp); else @@ -807,6 +836,7 @@ static int __maybe_unused tegra_bpmp_resume(struct device *dev) } static const struct dev_pm_ops tegra_bpmp_pm_ops = { + .suspend_noirq = tegra_bpmp_suspend, .resume_noirq = tegra_bpmp_resume, }; diff --git a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c index 26a37f47f4ca..7041befc756a 100644 --- a/drivers/firmware/ti_sci.c +++ b/drivers/firmware/ti_sci.c @@ -16,7 +16,10 @@ #include <linux/kernel.h> #include <linux/mailbox_client.h> #include <linux/module.h> -#include <linux/of_device.h> +#include <linux/of.h> +#include <linux/of_platform.h> +#include <linux/platform_device.h> +#include <linux/property.h> #include <linux/semaphore.h> #include <linux/slab.h> #include <linux/soc/ti/ti-msgmgr.h> @@ -190,19 +193,6 @@ static int ti_sci_debugfs_create(struct platform_device *pdev, return 0; } -/** - * ti_sci_debugfs_destroy() - clean up log debug file - * @pdev: platform device pointer - * @info: Pointer to SCI entity information - */ -static void ti_sci_debugfs_destroy(struct platform_device *pdev, - struct ti_sci_info *info) -{ - if (IS_ERR(info->debug_region)) - return; - - debugfs_remove(info->d); -} #else /* CONFIG_DEBUG_FS */ static inline int ti_sci_debugfs_create(struct platform_device *dev, struct ti_sci_info *info) @@ -485,7 +475,7 @@ static int ti_sci_cmd_get_revision(struct ti_sci_info *info) ver->abi_major = rev_info->abi_major; ver->abi_minor = rev_info->abi_minor; ver->firmware_revision = rev_info->firmware_revision; - strncpy(ver->firmware_description, rev_info->firmware_description, + strscpy(ver->firmware_description, rev_info->firmware_description, sizeof(ver->firmware_description)); fail: @@ -2886,7 +2876,6 @@ static void ti_sci_setup_ops(struct ti_sci_info *info) const struct ti_sci_handle *ti_sci_get_handle(struct device *dev) { struct device_node *ti_sci_np; - struct list_head *p; struct ti_sci_handle *handle = NULL; struct ti_sci_info *info; @@ -2901,8 +2890,7 @@ const struct ti_sci_handle *ti_sci_get_handle(struct device *dev) } mutex_lock(&ti_sci_list_mutex); - list_for_each(p, &ti_sci_list) { - info = list_entry(p, struct ti_sci_info, node); + list_for_each_entry(info, &ti_sci_list, node) { if (ti_sci_np == info->dev->of_node) { handle = &info->handle; info->users++; @@ -3012,7 +3000,6 @@ const struct ti_sci_handle *ti_sci_get_by_phandle(struct device_node *np, struct ti_sci_handle *handle = NULL; struct device_node *ti_sci_np; struct ti_sci_info *info; - struct list_head *p; if (!np) { pr_err("I need a device pointer\n"); @@ -3024,8 +3011,7 @@ const struct ti_sci_handle *ti_sci_get_by_phandle(struct device_node *np, return ERR_PTR(-ENODEV); mutex_lock(&ti_sci_list_mutex); - list_for_each(p, &ti_sci_list) { - info = list_entry(p, struct ti_sci_info, node); + list_for_each_entry(info, &ti_sci_list, node) { if (ti_sci_np == info->dev->of_node) { handle = &info->handle; info->users++; @@ -3310,7 +3296,6 @@ MODULE_DEVICE_TABLE(of, ti_sci_of_match); static int ti_sci_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - const struct of_device_id *of_id; const struct ti_sci_desc *desc; struct ti_sci_xfer *xfer; struct ti_sci_info *info = NULL; @@ -3321,12 +3306,7 @@ static int ti_sci_probe(struct platform_device *pdev) int reboot = 0; u32 h_id; - of_id = of_match_device(ti_sci_of_match, dev); - if (!of_id) { - dev_err(dev, "OF data missing\n"); - return -EINVAL; - } - desc = of_id->data; + desc = device_get_match_data(dev); info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL); if (!info) @@ -3449,43 +3429,12 @@ out: return ret; } -static int ti_sci_remove(struct platform_device *pdev) -{ - struct ti_sci_info *info; - struct device *dev = &pdev->dev; - int ret = 0; - - of_platform_depopulate(dev); - - info = platform_get_drvdata(pdev); - - if (info->nb.notifier_call) - unregister_restart_handler(&info->nb); - - mutex_lock(&ti_sci_list_mutex); - if (info->users) - ret = -EBUSY; - else - list_del(&info->node); - mutex_unlock(&ti_sci_list_mutex); - - if (!ret) { - ti_sci_debugfs_destroy(pdev, info); - - /* Safe to free channels since no more users */ - mbox_free_channel(info->chan_tx); - mbox_free_channel(info->chan_rx); - } - - return ret; -} - static struct platform_driver ti_sci_driver = { .probe = ti_sci_probe, - .remove = ti_sci_remove, .driver = { .name = "ti-sci", .of_match_table = of_match_ptr(ti_sci_of_match), + .suppress_bind_attrs = true, }, }; module_platform_driver(ti_sci_driver); diff --git a/drivers/gpio/gpio-pmic-eic-sprd.c b/drivers/gpio/gpio-pmic-eic-sprd.c index 2b9b7be9b8fd..01c0fd0a9d8c 100644 --- a/drivers/gpio/gpio-pmic-eic-sprd.c +++ b/drivers/gpio/gpio-pmic-eic-sprd.c @@ -352,6 +352,7 @@ static int sprd_pmic_eic_probe(struct platform_device *pdev) pmic_eic->chip.set_config = sprd_pmic_eic_set_config; pmic_eic->chip.set = sprd_pmic_eic_set; pmic_eic->chip.get = sprd_pmic_eic_get; + pmic_eic->chip.can_sleep = true; irq = &pmic_eic->chip.irq; gpio_irq_chip_set_chip(irq, &pmic_eic_irq_chip); diff --git a/drivers/gpio/gpio-sim.c b/drivers/gpio/gpio-sim.c index 271db3639a78..44bf1709a648 100644 --- a/drivers/gpio/gpio-sim.c +++ b/drivers/gpio/gpio-sim.c @@ -19,6 +19,7 @@ #include <linux/irq.h> #include <linux/irq_sim.h> #include <linux/list.h> +#include <linux/minmax.h> #include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/mutex.h> @@ -685,52 +686,32 @@ gpio_sim_device_config_live_show(struct config_item *item, char *page) return sprintf(page, "%c\n", live ? '1' : '0'); } -static char **gpio_sim_make_line_names(struct gpio_sim_bank *bank, - unsigned int *line_names_size) +static unsigned int gpio_sim_get_line_names_size(struct gpio_sim_bank *bank) { - unsigned int max_offset = 0; - bool has_line_names = false; struct gpio_sim_line *line; - char **line_names; + unsigned int size = 0; list_for_each_entry(line, &bank->line_list, siblings) { - if (line->offset >= bank->num_lines) + if (!line->name || (line->offset >= bank->num_lines)) continue; - if (line->name) { - if (line->offset > max_offset) - max_offset = line->offset; - - /* - * max_offset can stay at 0 so it's not an indicator - * of whether line names were configured at all. - */ - has_line_names = true; - } + size = max(size, line->offset + 1); } - if (!has_line_names) - /* - * This is not an error - NULL means, there are no line - * names configured. - */ - return NULL; - - *line_names_size = max_offset + 1; + return size; +} - line_names = kcalloc(*line_names_size, sizeof(*line_names), GFP_KERNEL); - if (!line_names) - return ERR_PTR(-ENOMEM); +static void +gpio_sim_set_line_names(struct gpio_sim_bank *bank, char **line_names) +{ + struct gpio_sim_line *line; list_for_each_entry(line, &bank->line_list, siblings) { - if (line->offset >= bank->num_lines) + if (!line->name || (line->offset >= bank->num_lines)) continue; - if (line->name && (line->offset <= max_offset)) - line_names[line->offset] = line->name; + line_names[line->offset] = line->name; } - - return line_names; } static void gpio_sim_remove_hogs(struct gpio_sim_device *dev) @@ -834,7 +815,7 @@ gpio_sim_make_bank_swnode(struct gpio_sim_bank *bank, struct fwnode_handle *parent) { struct property_entry properties[GPIO_SIM_PROP_MAX]; - unsigned int prop_idx = 0, line_names_size = 0; + unsigned int prop_idx = 0, line_names_size; char **line_names __free(kfree) = NULL; memset(properties, 0, sizeof(properties)); @@ -845,14 +826,19 @@ gpio_sim_make_bank_swnode(struct gpio_sim_bank *bank, properties[prop_idx++] = PROPERTY_ENTRY_STRING("gpio-sim,label", bank->label); - line_names = gpio_sim_make_line_names(bank, &line_names_size); - if (IS_ERR(line_names)) - return ERR_CAST(line_names); + line_names_size = gpio_sim_get_line_names_size(bank); + if (line_names_size) { + line_names = kcalloc(line_names_size, sizeof(*line_names), + GFP_KERNEL); + if (!line_names) + return ERR_PTR(-ENOMEM); + + gpio_sim_set_line_names(bank, line_names); - if (line_names) properties[prop_idx++] = PROPERTY_ENTRY_STRING_ARRAY_LEN( "gpio-line-names", line_names, line_names_size); + } return fwnode_create_software_node(properties, parent); } diff --git a/drivers/gpio/gpio-tb10x.c b/drivers/gpio/gpio-tb10x.c index 78f8790168ae..f96d260a4a19 100644 --- a/drivers/gpio/gpio-tb10x.c +++ b/drivers/gpio/gpio-tb10x.c @@ -195,7 +195,7 @@ static int tb10x_gpio_probe(struct platform_device *pdev) handle_edge_irq, IRQ_NOREQUEST, IRQ_NOPROBE, IRQ_GC_INIT_MASK_CACHE); if (ret) - return ret; + goto err_remove_domain; gc = tb10x_gpio->domain->gc->gc[0]; gc->reg_base = tb10x_gpio->base; @@ -209,6 +209,10 @@ static int tb10x_gpio_probe(struct platform_device *pdev) } return 0; + +err_remove_domain: + irq_domain_remove(tb10x_gpio->domain); + return ret; } static int tb10x_gpio_remove(struct platform_device *pdev) diff --git a/drivers/gpio/gpio-timberdale.c b/drivers/gpio/gpio-timberdale.c index bbd9e9191199..fad979797486 100644 --- a/drivers/gpio/gpio-timberdale.c +++ b/drivers/gpio/gpio-timberdale.c @@ -43,9 +43,10 @@ static int timbgpio_update_bit(struct gpio_chip *gpio, unsigned index, unsigned offset, bool enabled) { struct timbgpio *tgpio = gpiochip_get_data(gpio); + unsigned long flags; u32 reg; - spin_lock(&tgpio->lock); + spin_lock_irqsave(&tgpio->lock, flags); reg = ioread32(tgpio->membase + offset); if (enabled) @@ -54,7 +55,7 @@ static int timbgpio_update_bit(struct gpio_chip *gpio, unsigned index, reg &= ~(1 << index); iowrite32(reg, tgpio->membase + offset); - spin_unlock(&tgpio->lock); + spin_unlock_irqrestore(&tgpio->lock, flags); return 0; } diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig index ab9ef1c20349..3caa020391c7 100644 --- a/drivers/gpu/drm/Kconfig +++ b/drivers/gpu/drm/Kconfig @@ -136,7 +136,7 @@ config DRM_FBDEV_EMULATION bool "Enable legacy fbdev support for your modesetting driver" depends on DRM select FRAMEBUFFER_CONSOLE_DETECT_PRIMARY if FRAMEBUFFER_CONSOLE - default y + default FB help Choose this option if you have a need for the legacy fbdev support. Note that this support also provides the linux console diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index dc2d53081e80..a79d53bdbe13 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -1293,7 +1293,6 @@ int amdgpu_device_gpu_recover(struct amdgpu_device *adev, void amdgpu_device_pci_config_reset(struct amdgpu_device *adev); int amdgpu_device_pci_reset(struct amdgpu_device *adev); bool amdgpu_device_need_post(struct amdgpu_device *adev); -bool amdgpu_sg_display_supported(struct amdgpu_device *adev); bool amdgpu_device_pcie_dynamic_switching_supported(void); bool amdgpu_device_should_use_aspm(struct amdgpu_device *adev); bool amdgpu_device_aspm_support_quirk(void); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c index cdf6087706aa..25d5fda5b243 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c @@ -478,7 +478,7 @@ void amdgpu_amdkfd_get_cu_info(struct amdgpu_device *adev, struct kfd_cu_info *c cu_info->cu_active_number = acu_info.number; cu_info->cu_ao_mask = acu_info.ao_cu_mask; memcpy(&cu_info->cu_bitmap[0], &acu_info.bitmap[0], - sizeof(acu_info.bitmap)); + sizeof(cu_info->cu_bitmap)); cu_info->num_shader_engines = adev->gfx.config.max_shader_engines; cu_info->num_shader_arrays_per_engine = adev->gfx.config.max_sh_per_se; cu_info->num_cu_per_sh = adev->gfx.config.max_cu_per_sh; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v10.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v10.c index f1f2c24de081..69810b3f1c63 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v10.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v10.c @@ -980,8 +980,7 @@ void kgd_gfx_v10_build_grace_period_packet_info(struct amdgpu_device *adev, uint32_t wait_times, uint32_t grace_period, uint32_t *reg_offset, - uint32_t *reg_data, - uint32_t inst) + uint32_t *reg_data) { *reg_data = wait_times; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v10.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v10.h index ecaead24e8c9..67bcaa3d4226 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v10.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v10.h @@ -55,5 +55,4 @@ void kgd_gfx_v10_build_grace_period_packet_info(struct amdgpu_device *adev, uint32_t wait_times, uint32_t grace_period, uint32_t *reg_offset, - uint32_t *reg_data, - uint32_t inst); + uint32_t *reg_data); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.c index fa5ee96f8845..3c45a188b701 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.c @@ -1103,8 +1103,7 @@ void kgd_gfx_v9_build_grace_period_packet_info(struct amdgpu_device *adev, uint32_t wait_times, uint32_t grace_period, uint32_t *reg_offset, - uint32_t *reg_data, - uint32_t inst) + uint32_t *reg_data) { *reg_data = wait_times; @@ -1120,8 +1119,7 @@ void kgd_gfx_v9_build_grace_period_packet_info(struct amdgpu_device *adev, SCH_WAVE, grace_period); - *reg_offset = SOC15_REG_OFFSET(GC, GET_INST(GC, inst), - mmCP_IQ_WAIT_TIME2); + *reg_offset = SOC15_REG_OFFSET(GC, 0, mmCP_IQ_WAIT_TIME2); } void kgd_gfx_v9_program_trap_handler_settings(struct amdgpu_device *adev, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.h index 936e501908ce..ce424615f59b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v9.h @@ -100,5 +100,4 @@ void kgd_gfx_v9_build_grace_period_packet_info(struct amdgpu_device *adev, uint32_t wait_times, uint32_t grace_period, uint32_t *reg_offset, - uint32_t *reg_data, - uint32_t inst); + uint32_t *reg_data); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c index 73ee14f7a9a4..dce9e7d5e4ec 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c @@ -1776,7 +1776,7 @@ static ssize_t amdgpu_atombios_get_vbios_version(struct device *dev, struct amdgpu_device *adev = drm_to_adev(ddev); struct atom_context *ctx = adev->mode_info.atom_context; - return sysfs_emit(buf, "%s\n", ctx->vbios_ver_str); + return sysfs_emit(buf, "%s\n", ctx->vbios_pn); } static DEVICE_ATTR(vbios_version, 0444, amdgpu_atombios_get_vbios_version, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 3f001a50b34a..30c4f5cca02c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -1245,32 +1245,6 @@ bool amdgpu_device_need_post(struct amdgpu_device *adev) } /* - * On APUs with >= 64GB white flickering has been observed w/ SG enabled. - * Disable S/G on such systems until we have a proper fix. - * https://gitlab.freedesktop.org/drm/amd/-/issues/2354 - * https://gitlab.freedesktop.org/drm/amd/-/issues/2735 - */ -bool amdgpu_sg_display_supported(struct amdgpu_device *adev) -{ - switch (amdgpu_sg_display) { - case -1: - break; - case 0: - return false; - case 1: - return true; - default: - return false; - } - if ((totalram_pages() << (PAGE_SHIFT - 10)) + - (adev->gmc.real_vram_size / 1024) >= 64000000) { - DRM_WARN("Disabling S/G due to >=64GB RAM\n"); - return false; - } - return true; -} - -/* * Intel hosts such as Raptor Lake and Sapphire Rapids don't support dynamic * speed switching. Until we have confirmation from Intel that a specific host * supports it, it's safer that we keep it disabled for all. diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h index 395c1768b9fc..0ca95c4d4bfb 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.h @@ -43,6 +43,7 @@ #define AMDGPU_GFX_LBPW_DISABLED_MODE 0x00000008L #define AMDGPU_MAX_GC_INSTANCES 8 +#define KGD_MAX_QUEUES 128 #define AMDGPU_MAX_GFX_QUEUES KGD_MAX_QUEUES #define AMDGPU_MAX_COMPUTE_QUEUES KGD_MAX_QUEUES @@ -257,7 +258,7 @@ struct amdgpu_cu_info { uint32_t number; uint32_t ao_cu_mask; uint32_t ao_cu_bitmap[4][4]; - uint32_t bitmap[4][4]; + uint32_t bitmap[AMDGPU_MAX_GC_INSTANCES][4][4]; }; struct amdgpu_gfx_ras { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c index 99f4df133ed3..d30dc0b718c7 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c @@ -839,7 +839,7 @@ int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) memcpy(&dev_info->cu_ao_bitmap[0], &adev->gfx.cu_info.ao_cu_bitmap[0], sizeof(adev->gfx.cu_info.ao_cu_bitmap)); memcpy(&dev_info->cu_bitmap[0], &adev->gfx.cu_info.bitmap[0], - sizeof(adev->gfx.cu_info.bitmap)); + sizeof(dev_info->cu_bitmap)); dev_info->vram_type = adev->gmc.vram_type; dev_info->vram_bit_width = adev->gmc.vram_width; dev_info->vce_harvest_config = adev->vce.harvest_config; @@ -940,12 +940,17 @@ int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) struct atom_context *atom_context; atom_context = adev->mode_info.atom_context; - memcpy(vbios_info.name, atom_context->name, sizeof(atom_context->name)); - memcpy(vbios_info.vbios_pn, atom_context->vbios_pn, sizeof(atom_context->vbios_pn)); - vbios_info.version = atom_context->version; - memcpy(vbios_info.vbios_ver_str, atom_context->vbios_ver_str, - sizeof(atom_context->vbios_ver_str)); - memcpy(vbios_info.date, atom_context->date, sizeof(atom_context->date)); + if (atom_context) { + memcpy(vbios_info.name, atom_context->name, + sizeof(atom_context->name)); + memcpy(vbios_info.vbios_pn, atom_context->vbios_pn, + sizeof(atom_context->vbios_pn)); + vbios_info.version = atom_context->version; + memcpy(vbios_info.vbios_ver_str, atom_context->vbios_ver_str, + sizeof(atom_context->vbios_ver_str)); + memcpy(vbios_info.date, atom_context->date, + sizeof(atom_context->date)); + } return copy_to_user(out, &vbios_info, min((size_t)size, sizeof(vbios_info))) ? -EFAULT : 0; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c index 3c4600e15b86..163445baa4fc 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c @@ -801,6 +801,7 @@ int amdgpu_ras_feature_enable(struct amdgpu_device *adev, enable ? "enable":"disable", get_ras_block_str(head), amdgpu_ras_is_poison_mode_supported(adev), ret); + kfree(info); return ret; } @@ -1052,7 +1053,8 @@ int amdgpu_ras_query_error_status(struct amdgpu_device *adev, info->ce_count = obj->err_data.ce_count; if (err_data.ce_count) { - if (adev->smuio.funcs && + if (!adev->aid_mask && + adev->smuio.funcs && adev->smuio.funcs->get_socket_id && adev->smuio.funcs->get_die_id) { dev_info(adev->dev, "socket: %d, die: %d " @@ -1072,7 +1074,8 @@ int amdgpu_ras_query_error_status(struct amdgpu_device *adev, } } if (err_data.ue_count) { - if (adev->smuio.funcs && + if (!adev->aid_mask && + adev->smuio.funcs && adev->smuio.funcs->get_socket_id && adev->smuio.funcs->get_die_id) { dev_info(adev->dev, "socket: %d, die: %d " diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sa.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_sa.c index c6b4337eb20c..10df731998b2 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sa.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sa.c @@ -81,7 +81,7 @@ int amdgpu_sa_bo_new(struct amdgpu_sa_manager *sa_manager, unsigned int size) { struct drm_suballoc *sa = drm_suballoc_new(&sa_manager->base, size, - GFP_KERNEL, true, 0); + GFP_KERNEL, false, 0); if (IS_ERR(sa)) { *sa_bo = NULL; diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c index 0aee9c8288a2..9032d7a24d7c 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v10_0.c @@ -9449,7 +9449,7 @@ static int gfx_v10_0_get_cu_info(struct amdgpu_device *adev, gfx_v10_0_set_user_wgp_inactive_bitmap_per_sh( adev, disable_masks[i * 2 + j]); bitmap = gfx_v10_0_get_cu_active_bitmap_per_sh(adev); - cu_info->bitmap[i][j] = bitmap; + cu_info->bitmap[0][i][j] = bitmap; for (k = 0; k < adev->gfx.config.max_cu_per_sh; k++) { if (bitmap & mask) { diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c index 5c3db694afa8..762d7a19f1be 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v11_0.c @@ -6368,7 +6368,7 @@ static int gfx_v11_0_get_cu_info(struct amdgpu_device *adev, * SE6: {SH0,SH1} --> {bitmap[2][2], bitmap[2][3]} * SE7: {SH0,SH1} --> {bitmap[3][2], bitmap[3][3]} */ - cu_info->bitmap[i % 4][j + (i / 4) * 2] = bitmap; + cu_info->bitmap[0][i % 4][j + (i / 4) * 2] = bitmap; for (k = 0; k < adev->gfx.config.max_cu_per_sh; k++) { if (bitmap & mask) diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c index da6caff78c22..34f9211b2679 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c @@ -3577,7 +3577,7 @@ static void gfx_v6_0_get_cu_info(struct amdgpu_device *adev) gfx_v6_0_set_user_cu_inactive_bitmap( adev, disable_masks[i * 2 + j]); bitmap = gfx_v6_0_get_cu_enabled(adev); - cu_info->bitmap[i][j] = bitmap; + cu_info->bitmap[0][i][j] = bitmap; for (k = 0; k < adev->gfx.config.max_cu_per_sh; k++) { if (bitmap & mask) { diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c index 90b034b173c1..c2faf6b4c2fc 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c @@ -5119,7 +5119,7 @@ static void gfx_v7_0_get_cu_info(struct amdgpu_device *adev) gfx_v7_0_set_user_cu_inactive_bitmap( adev, disable_masks[i * 2 + j]); bitmap = gfx_v7_0_get_cu_active_bitmap(adev); - cu_info->bitmap[i][j] = bitmap; + cu_info->bitmap[0][i][j] = bitmap; for (k = 0; k < adev->gfx.config.max_cu_per_sh; k++) { if (bitmap & mask) { diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c index 51c1745c8369..885ebd703260 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c @@ -7121,7 +7121,7 @@ static void gfx_v8_0_get_cu_info(struct amdgpu_device *adev) gfx_v8_0_set_user_cu_inactive_bitmap( adev, disable_masks[i * 2 + j]); bitmap = gfx_v8_0_get_cu_active_bitmap(adev); - cu_info->bitmap[i][j] = bitmap; + cu_info->bitmap[0][i][j] = bitmap; for (k = 0; k < adev->gfx.config.max_cu_per_sh; k ++) { if (bitmap & mask) { diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c index 458faf657042..fd61574a737c 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_0.c @@ -1499,7 +1499,7 @@ static void gfx_v9_0_init_always_on_cu_mask(struct amdgpu_device *adev) amdgpu_gfx_select_se_sh(adev, i, j, 0xffffffff, 0); for (k = 0; k < adev->gfx.config.max_cu_per_sh; k ++) { - if (cu_info->bitmap[i][j] & mask) { + if (cu_info->bitmap[0][i][j] & mask) { if (counter == pg_always_on_cu_num) WREG32_SOC15(GC, 0, mmRLC_PG_ALWAYS_ON_CU_MASK, cu_bitmap); if (counter < always_on_cu_num) @@ -7233,7 +7233,7 @@ static int gfx_v9_0_get_cu_info(struct amdgpu_device *adev, * SE6,SH0 --> bitmap[2][1] * SE7,SH0 --> bitmap[3][1] */ - cu_info->bitmap[i % 4][j + i / 4] = bitmap; + cu_info->bitmap[0][i % 4][j + i / 4] = bitmap; for (k = 0; k < adev->gfx.config.max_cu_per_sh; k ++) { if (bitmap & mask) { diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c b/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c index 0a26a00074a6..18ce5fe45f6f 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c @@ -4259,7 +4259,7 @@ static void gfx_v9_4_3_set_gds_init(struct amdgpu_device *adev) } static void gfx_v9_4_3_set_user_cu_inactive_bitmap(struct amdgpu_device *adev, - u32 bitmap) + u32 bitmap, int xcc_id) { u32 data; @@ -4269,15 +4269,15 @@ static void gfx_v9_4_3_set_user_cu_inactive_bitmap(struct amdgpu_device *adev, data = bitmap << GC_USER_SHADER_ARRAY_CONFIG__INACTIVE_CUS__SHIFT; data &= GC_USER_SHADER_ARRAY_CONFIG__INACTIVE_CUS_MASK; - WREG32_SOC15(GC, GET_INST(GC, 0), regGC_USER_SHADER_ARRAY_CONFIG, data); + WREG32_SOC15(GC, GET_INST(GC, xcc_id), regGC_USER_SHADER_ARRAY_CONFIG, data); } -static u32 gfx_v9_4_3_get_cu_active_bitmap(struct amdgpu_device *adev) +static u32 gfx_v9_4_3_get_cu_active_bitmap(struct amdgpu_device *adev, int xcc_id) { u32 data, mask; - data = RREG32_SOC15(GC, GET_INST(GC, 0), regCC_GC_SHADER_ARRAY_CONFIG); - data |= RREG32_SOC15(GC, GET_INST(GC, 0), regGC_USER_SHADER_ARRAY_CONFIG); + data = RREG32_SOC15(GC, GET_INST(GC, xcc_id), regCC_GC_SHADER_ARRAY_CONFIG); + data |= RREG32_SOC15(GC, GET_INST(GC, xcc_id), regGC_USER_SHADER_ARRAY_CONFIG); data &= CC_GC_SHADER_ARRAY_CONFIG__INACTIVE_CUS_MASK; data >>= CC_GC_SHADER_ARRAY_CONFIG__INACTIVE_CUS__SHIFT; @@ -4290,7 +4290,7 @@ static u32 gfx_v9_4_3_get_cu_active_bitmap(struct amdgpu_device *adev) static int gfx_v9_4_3_get_cu_info(struct amdgpu_device *adev, struct amdgpu_cu_info *cu_info) { - int i, j, k, counter, active_cu_number = 0; + int i, j, k, counter, xcc_id, active_cu_number = 0; u32 mask, bitmap, ao_bitmap, ao_cu_mask = 0; unsigned disable_masks[4 * 4]; @@ -4309,46 +4309,38 @@ static int gfx_v9_4_3_get_cu_info(struct amdgpu_device *adev, adev->gfx.config.max_sh_per_se); mutex_lock(&adev->grbm_idx_mutex); - for (i = 0; i < adev->gfx.config.max_shader_engines; i++) { - for (j = 0; j < adev->gfx.config.max_sh_per_se; j++) { - mask = 1; - ao_bitmap = 0; - counter = 0; - gfx_v9_4_3_xcc_select_se_sh(adev, i, j, 0xffffffff, 0); - gfx_v9_4_3_set_user_cu_inactive_bitmap( - adev, disable_masks[i * adev->gfx.config.max_sh_per_se + j]); - bitmap = gfx_v9_4_3_get_cu_active_bitmap(adev); - - /* - * The bitmap(and ao_cu_bitmap) in cu_info structure is - * 4x4 size array, and it's usually suitable for Vega - * ASICs which has 4*2 SE/SH layout. - * But for Arcturus, SE/SH layout is changed to 8*1. - * To mostly reduce the impact, we make it compatible - * with current bitmap array as below: - * SE4,SH0 --> bitmap[0][1] - * SE5,SH0 --> bitmap[1][1] - * SE6,SH0 --> bitmap[2][1] - * SE7,SH0 --> bitmap[3][1] - */ - cu_info->bitmap[i % 4][j + i / 4] = bitmap; - - for (k = 0; k < adev->gfx.config.max_cu_per_sh; k++) { - if (bitmap & mask) { - if (counter < adev->gfx.config.max_cu_per_sh) - ao_bitmap |= mask; - counter++; + for (xcc_id = 0; xcc_id < NUM_XCC(adev->gfx.xcc_mask); xcc_id++) { + for (i = 0; i < adev->gfx.config.max_shader_engines; i++) { + for (j = 0; j < adev->gfx.config.max_sh_per_se; j++) { + mask = 1; + ao_bitmap = 0; + counter = 0; + gfx_v9_4_3_xcc_select_se_sh(adev, i, j, 0xffffffff, xcc_id); + gfx_v9_4_3_set_user_cu_inactive_bitmap( + adev, + disable_masks[i * adev->gfx.config.max_sh_per_se + j], + xcc_id); + bitmap = gfx_v9_4_3_get_cu_active_bitmap(adev, xcc_id); + + cu_info->bitmap[xcc_id][i][j] = bitmap; + + for (k = 0; k < adev->gfx.config.max_cu_per_sh; k++) { + if (bitmap & mask) { + if (counter < adev->gfx.config.max_cu_per_sh) + ao_bitmap |= mask; + counter++; + } + mask <<= 1; } - mask <<= 1; + active_cu_number += counter; + if (i < 2 && j < 2) + ao_cu_mask |= (ao_bitmap << (i * 16 + j * 8)); + cu_info->ao_cu_bitmap[i][j] = ao_bitmap; } - active_cu_number += counter; - if (i < 2 && j < 2) - ao_cu_mask |= (ao_bitmap << (i * 16 + j * 8)); - cu_info->ao_cu_bitmap[i % 4][j + i / 4] = ao_bitmap; } + gfx_v9_4_3_xcc_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff, + xcc_id); } - gfx_v9_4_3_xcc_select_se_sh(adev, 0xffffffff, 0xffffffff, 0xffffffff, - 0); mutex_unlock(&adev->grbm_idx_mutex); cu_info->number = active_cu_number; diff --git a/drivers/gpu/drm/amd/amdgpu/nbio_v4_3.c b/drivers/gpu/drm/amd/amdgpu/nbio_v4_3.c index d5ed9e0e1a5f..e5b5b0f4940f 100644 --- a/drivers/gpu/drm/amd/amdgpu/nbio_v4_3.c +++ b/drivers/gpu/drm/amd/amdgpu/nbio_v4_3.c @@ -345,6 +345,9 @@ static void nbio_v4_3_init_registers(struct amdgpu_device *adev) data &= ~RCC_DEV0_EPF2_STRAP2__STRAP_NO_SOFT_RESET_DEV0_F2_MASK; WREG32_SOC15(NBIO, 0, regRCC_DEV0_EPF2_STRAP2, data); } + if (amdgpu_sriov_vf(adev)) + adev->rmmio_remap.reg_offset = SOC15_REG_OFFSET(NBIO, 0, + regBIF_BX_DEV0_EPF0_VF0_HDP_MEM_COHERENCY_FLUSH_CNTL) << 2; } static u32 nbio_v4_3_get_rom_offset(struct amdgpu_device *adev) diff --git a/drivers/gpu/drm/amd/amdgpu/soc21.c b/drivers/gpu/drm/amd/amdgpu/soc21.c index 40d23738ee4e..8b2ff2b281b0 100644 --- a/drivers/gpu/drm/amd/amdgpu/soc21.c +++ b/drivers/gpu/drm/amd/amdgpu/soc21.c @@ -766,7 +766,7 @@ static int soc21_common_hw_init(void *handle) * for the purpose of expose those registers * to process space */ - if (adev->nbio.funcs->remap_hdp_registers) + if (adev->nbio.funcs->remap_hdp_registers && !amdgpu_sriov_vf(adev)) adev->nbio.funcs->remap_hdp_registers(adev); /* enable the doorbell aperture */ adev->nbio.funcs->enable_doorbell_aperture(adev, true); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_crat.c b/drivers/gpu/drm/amd/amdkfd/kfd_crat.c index 86fb7ac7982a..f76b7aee5c0a 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_crat.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_crat.c @@ -2087,7 +2087,8 @@ static int kfd_create_vcrat_image_gpu(void *pcrat_image, amdgpu_amdkfd_get_cu_info(kdev->adev, &cu_info); cu->num_simd_per_cu = cu_info.simd_per_cu; - cu->num_simd_cores = cu_info.simd_per_cu * cu_info.cu_active_number; + cu->num_simd_cores = cu_info.simd_per_cu * + (cu_info.cu_active_number / kdev->kfd->num_nodes); cu->max_waves_simd = cu_info.max_waves_per_simd; cu->wave_front_size = cu_info.wave_front_size; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_crat.h b/drivers/gpu/drm/amd/amdkfd/kfd_crat.h index 387a8ef49385..74c2d7a0d628 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_crat.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_crat.h @@ -79,6 +79,10 @@ struct crat_header { #define CRAT_SUBTYPE_IOLINK_AFFINITY 5 #define CRAT_SUBTYPE_MAX 6 +/* + * Do not change the value of CRAT_SIBLINGMAP_SIZE from 32 + * as it breaks the ABI. + */ #define CRAT_SIBLINGMAP_SIZE 32 /* diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c index b166f30f083e..0d3d538b64eb 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c @@ -216,7 +216,7 @@ static int add_queue_mes(struct device_queue_manager *dqm, struct queue *q, if (q->wptr_bo) { wptr_addr_off = (uint64_t)q->properties.write_ptr & (PAGE_SIZE - 1); - queue_input.wptr_mc_addr = ((uint64_t)q->wptr_bo->tbo.resource->start << PAGE_SHIFT) + wptr_addr_off; + queue_input.wptr_mc_addr = amdgpu_bo_gpu_offset(q->wptr_bo) + wptr_addr_off; } queue_input.is_kfd_process = 1; @@ -1677,8 +1677,7 @@ static int start_cpsch(struct device_queue_manager *dqm) dqm->dev->kfd2kgd->build_grace_period_packet_info( dqm->dev->adev, dqm->wait_times, grace_period, ®_offset, - &dqm->wait_times, - ffs(dqm->dev->xcc_mask) - 1); + &dqm->wait_times); } dqm_unlock(dqm); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c b/drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c index c2e0b79dcc6d..7b38537c7c99 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c @@ -162,6 +162,7 @@ void __iomem *kfd_get_kernel_doorbell(struct kfd_dev *kfd, return NULL; *doorbell_off = amdgpu_doorbell_index_on_bar(kfd->adev, kfd->doorbells, inx); + inx *= 2; pr_debug("Get kernel queue doorbell\n" " doorbell offset == 0x%08X\n" @@ -176,6 +177,7 @@ void kfd_release_kernel_doorbell(struct kfd_dev *kfd, u32 __iomem *db_addr) unsigned int inx; inx = (unsigned int)(db_addr - kfd->doorbell_kernel_ptr); + inx /= 2; mutex_lock(&kfd->doorbell_mutex); __clear_bit(inx, kfd->doorbell_bitmap); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c index d01bb57733b3..447829c22295 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c @@ -97,18 +97,22 @@ void free_mqd_hiq_sdma(struct mqd_manager *mm, void *mqd, void mqd_symmetrically_map_cu_mask(struct mqd_manager *mm, const uint32_t *cu_mask, uint32_t cu_mask_count, - uint32_t *se_mask) + uint32_t *se_mask, uint32_t inst) { struct kfd_cu_info cu_info; uint32_t cu_per_sh[KFD_MAX_NUM_SE][KFD_MAX_NUM_SH_PER_SE] = {0}; bool wgp_mode_req = KFD_GC_VERSION(mm->dev) >= IP_VERSION(10, 0, 0); uint32_t en_mask = wgp_mode_req ? 0x3 : 0x1; - int i, se, sh, cu, cu_bitmap_sh_mul, inc = wgp_mode_req ? 2 : 1; + int i, se, sh, cu, cu_bitmap_sh_mul, cu_inc = wgp_mode_req ? 2 : 1; + uint32_t cu_active_per_node; + int inc = cu_inc * NUM_XCC(mm->dev->xcc_mask); + int xcc_inst = inst + ffs(mm->dev->xcc_mask) - 1; amdgpu_amdkfd_get_cu_info(mm->dev->adev, &cu_info); - if (cu_mask_count > cu_info.cu_active_number) - cu_mask_count = cu_info.cu_active_number; + cu_active_per_node = cu_info.cu_active_number / mm->dev->kfd->num_nodes; + if (cu_mask_count > cu_active_per_node) + cu_mask_count = cu_active_per_node; /* Exceeding these bounds corrupts the stack and indicates a coding error. * Returning with no CU's enabled will hang the queue, which should be @@ -141,7 +145,8 @@ void mqd_symmetrically_map_cu_mask(struct mqd_manager *mm, for (se = 0; se < cu_info.num_shader_engines; se++) for (sh = 0; sh < cu_info.num_shader_arrays_per_engine; sh++) cu_per_sh[se][sh] = hweight32( - cu_info.cu_bitmap[se % 4][sh + (se / 4) * cu_bitmap_sh_mul]); + cu_info.cu_bitmap[xcc_inst][se % 4][sh + (se / 4) * + cu_bitmap_sh_mul]); /* Symmetrically map cu_mask to all SEs & SHs: * se_mask programs up to 2 SH in the upper and lower 16 bits. @@ -164,20 +169,33 @@ void mqd_symmetrically_map_cu_mask(struct mqd_manager *mm, * cu_mask[0] bit8 -> se_mask[0] bit1 (SE0,SH0,CU1) * ... * + * For GFX 9.4.3, the following code only looks at a + * subset of the cu_mask corresponding to the inst parameter. + * If we have n XCCs under one GPU node + * cu_mask[0] bit0 -> XCC0 se_mask[0] bit0 (XCC0,SE0,SH0,CU0) + * cu_mask[0] bit1 -> XCC1 se_mask[0] bit0 (XCC1,SE0,SH0,CU0) + * .. + * cu_mask[0] bitn -> XCCn se_mask[0] bit0 (XCCn,SE0,SH0,CU0) + * cu_mask[0] bit n+1 -> XCC0 se_mask[1] bit0 (XCC0,SE1,SH0,CU0) + * + * For example, if there are 6 XCCs under 1 KFD node, this code + * running for each inst, will look at the bits as: + * inst, inst + 6, inst + 12... + * * First ensure all CUs are disabled, then enable user specified CUs. */ for (i = 0; i < cu_info.num_shader_engines; i++) se_mask[i] = 0; - i = 0; - for (cu = 0; cu < 16; cu += inc) { + i = inst; + for (cu = 0; cu < 16; cu += cu_inc) { for (sh = 0; sh < cu_info.num_shader_arrays_per_engine; sh++) { for (se = 0; se < cu_info.num_shader_engines; se++) { if (cu_per_sh[se][sh] > cu) { if (cu_mask[i / 32] & (en_mask << (i % 32))) se_mask[se] |= en_mask << (cu + sh * 16); i += inc; - if (i == cu_mask_count) + if (i >= cu_mask_count) return; } } diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.h b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.h index 23158db7da03..57bf5e513f4d 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.h @@ -138,7 +138,7 @@ void free_mqd_hiq_sdma(struct mqd_manager *mm, void *mqd, void mqd_symmetrically_map_cu_mask(struct mqd_manager *mm, const uint32_t *cu_mask, uint32_t cu_mask_count, - uint32_t *se_mask); + uint32_t *se_mask, uint32_t inst); int kfd_hiq_load_mqd_kiq(struct mqd_manager *mm, void *mqd, uint32_t pipe_id, uint32_t queue_id, diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c index ee1d32d957f2..1a4a69943c71 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c @@ -52,7 +52,7 @@ static void update_cu_mask(struct mqd_manager *mm, void *mqd, return; mqd_symmetrically_map_cu_mask(mm, - minfo->cu_mask.ptr, minfo->cu_mask.count, se_mask); + minfo->cu_mask.ptr, minfo->cu_mask.count, se_mask, 0); m = get_mqd(mqd); m->compute_static_thread_mgmt_se0 = se_mask[0]; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c index 83699392c808..8b7fed913526 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v10.c @@ -52,7 +52,7 @@ static void update_cu_mask(struct mqd_manager *mm, void *mqd, return; mqd_symmetrically_map_cu_mask(mm, - minfo->cu_mask.ptr, minfo->cu_mask.count, se_mask); + minfo->cu_mask.ptr, minfo->cu_mask.count, se_mask, 0); m = get_mqd(mqd); m->compute_static_thread_mgmt_se0 = se_mask[0]; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c index 0bbf0edbabd4..15277f1d5cf0 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v11.c @@ -71,7 +71,7 @@ static void update_cu_mask(struct mqd_manager *mm, void *mqd, } mqd_symmetrically_map_cu_mask(mm, - minfo->cu_mask.ptr, minfo->cu_mask.count, se_mask); + minfo->cu_mask.ptr, minfo->cu_mask.count, se_mask, 0); m->compute_static_thread_mgmt_se0 = se_mask[0]; m->compute_static_thread_mgmt_se1 = se_mask[1]; @@ -321,6 +321,43 @@ static int get_wave_state(struct mqd_manager *mm, void *mqd, return 0; } +static void checkpoint_mqd(struct mqd_manager *mm, void *mqd, void *mqd_dst, void *ctl_stack_dst) +{ + struct v11_compute_mqd *m; + + m = get_mqd(mqd); + + memcpy(mqd_dst, m, sizeof(struct v11_compute_mqd)); +} + +static void restore_mqd(struct mqd_manager *mm, void **mqd, + struct kfd_mem_obj *mqd_mem_obj, uint64_t *gart_addr, + struct queue_properties *qp, + const void *mqd_src, + const void *ctl_stack_src, const u32 ctl_stack_size) +{ + uint64_t addr; + struct v11_compute_mqd *m; + + m = (struct v11_compute_mqd *) mqd_mem_obj->cpu_ptr; + addr = mqd_mem_obj->gpu_addr; + + memcpy(m, mqd_src, sizeof(*m)); + + *mqd = m; + if (gart_addr) + *gart_addr = addr; + + m->cp_hqd_pq_doorbell_control = + qp->doorbell_off << + CP_HQD_PQ_DOORBELL_CONTROL__DOORBELL_OFFSET__SHIFT; + pr_debug("cp_hqd_pq_doorbell_control 0x%x\n", + m->cp_hqd_pq_doorbell_control); + + qp->is_active = 0; +} + + static void init_mqd_hiq(struct mqd_manager *mm, void **mqd, struct kfd_mem_obj *mqd_mem_obj, uint64_t *gart_addr, struct queue_properties *q) @@ -458,6 +495,8 @@ struct mqd_manager *mqd_manager_init_v11(enum KFD_MQD_TYPE type, mqd->mqd_size = sizeof(struct v11_compute_mqd); mqd->get_wave_state = get_wave_state; mqd->mqd_stride = kfd_mqd_stride; + mqd->checkpoint_mqd = checkpoint_mqd; + mqd->restore_mqd = restore_mqd; #if defined(CONFIG_DEBUG_FS) mqd->debugfs_show_mqd = debugfs_show_mqd; #endif @@ -502,6 +541,8 @@ struct mqd_manager *mqd_manager_init_v11(enum KFD_MQD_TYPE type, mqd->update_mqd = update_mqd_sdma; mqd->destroy_mqd = kfd_destroy_mqd_sdma; mqd->is_occupied = kfd_is_occupied_sdma; + mqd->checkpoint_mqd = checkpoint_mqd; + mqd->restore_mqd = restore_mqd; mqd->mqd_size = sizeof(struct v11_sdma_mqd); mqd->mqd_stride = kfd_mqd_stride; #if defined(CONFIG_DEBUG_FS) 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 e23d32f35607..42d881809dc7 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_v9.c @@ -60,7 +60,7 @@ static inline struct v9_sdma_mqd *get_sdma_mqd(void *mqd) } static void update_cu_mask(struct mqd_manager *mm, void *mqd, - struct mqd_update_info *minfo) + struct mqd_update_info *minfo, uint32_t inst) { struct v9_mqd *m; uint32_t se_mask[KFD_MAX_NUM_SE] = {0}; @@ -69,27 +69,36 @@ static void update_cu_mask(struct mqd_manager *mm, void *mqd, return; mqd_symmetrically_map_cu_mask(mm, - minfo->cu_mask.ptr, minfo->cu_mask.count, se_mask); + minfo->cu_mask.ptr, minfo->cu_mask.count, se_mask, inst); m = get_mqd(mqd); + m->compute_static_thread_mgmt_se0 = se_mask[0]; m->compute_static_thread_mgmt_se1 = se_mask[1]; m->compute_static_thread_mgmt_se2 = se_mask[2]; m->compute_static_thread_mgmt_se3 = se_mask[3]; - m->compute_static_thread_mgmt_se4 = se_mask[4]; - m->compute_static_thread_mgmt_se5 = se_mask[5]; - m->compute_static_thread_mgmt_se6 = se_mask[6]; - m->compute_static_thread_mgmt_se7 = se_mask[7]; - - pr_debug("update cu mask to %#x %#x %#x %#x %#x %#x %#x %#x\n", - m->compute_static_thread_mgmt_se0, - m->compute_static_thread_mgmt_se1, - m->compute_static_thread_mgmt_se2, - m->compute_static_thread_mgmt_se3, - m->compute_static_thread_mgmt_se4, - m->compute_static_thread_mgmt_se5, - m->compute_static_thread_mgmt_se6, - m->compute_static_thread_mgmt_se7); + if (KFD_GC_VERSION(mm->dev) != IP_VERSION(9, 4, 3)) { + m->compute_static_thread_mgmt_se4 = se_mask[4]; + m->compute_static_thread_mgmt_se5 = se_mask[5]; + m->compute_static_thread_mgmt_se6 = se_mask[6]; + m->compute_static_thread_mgmt_se7 = se_mask[7]; + + pr_debug("update cu mask to %#x %#x %#x %#x %#x %#x %#x %#x\n", + m->compute_static_thread_mgmt_se0, + m->compute_static_thread_mgmt_se1, + m->compute_static_thread_mgmt_se2, + m->compute_static_thread_mgmt_se3, + m->compute_static_thread_mgmt_se4, + m->compute_static_thread_mgmt_se5, + m->compute_static_thread_mgmt_se6, + m->compute_static_thread_mgmt_se7); + } else { + pr_debug("inst: %u, update cu mask to %#x %#x %#x %#x\n", + inst, m->compute_static_thread_mgmt_se0, + m->compute_static_thread_mgmt_se1, + m->compute_static_thread_mgmt_se2, + m->compute_static_thread_mgmt_se3); + } } static void set_priority(struct v9_mqd *m, struct queue_properties *q) @@ -290,7 +299,8 @@ static void update_mqd(struct mqd_manager *mm, void *mqd, if (mm->dev->kfd->cwsr_enabled && q->ctx_save_restore_area_address) m->cp_hqd_ctx_save_control = 0; - update_cu_mask(mm, mqd, minfo); + if (KFD_GC_VERSION(mm->dev) != IP_VERSION(9, 4, 3)) + update_cu_mask(mm, mqd, minfo, 0); set_priority(m, q); q->is_active = QUEUE_IS_ACTIVE(*q); @@ -676,6 +686,8 @@ static void update_mqd_v9_4_3(struct mqd_manager *mm, void *mqd, m = get_mqd(mqd + size * xcc); update_mqd(mm, m, q, minfo); + update_cu_mask(mm, mqd, minfo, xcc); + if (q->format == KFD_QUEUE_FORMAT_AQL) { switch (xcc) { case 0: diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c index 657c37822980..3e1a574d4ea6 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c @@ -55,7 +55,7 @@ static void update_cu_mask(struct mqd_manager *mm, void *mqd, return; mqd_symmetrically_map_cu_mask(mm, - minfo->cu_mask.ptr, minfo->cu_mask.count, se_mask); + minfo->cu_mask.ptr, minfo->cu_mask.count, se_mask, 0); m = get_mqd(mqd); m->compute_static_thread_mgmt_se0 = se_mask[0]; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_packet_manager_v9.c b/drivers/gpu/drm/amd/amdkfd/kfd_packet_manager_v9.c index 8ce6f5200905..1a03173e2313 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_packet_manager_v9.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_packet_manager_v9.c @@ -299,8 +299,7 @@ static int pm_set_grace_period_v9(struct packet_manager *pm, pm->dqm->wait_times, grace_period, ®_offset, - ®_data, - 0); + ®_data); if (grace_period == USE_DEFAULT_GRACE_PERIOD) reg_data = pm->dqm->wait_times; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h index 3d9ce44d88da..fa24e1852493 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h @@ -1466,8 +1466,7 @@ void kfd_flush_tlb(struct kfd_process_device *pdd, enum TLB_FLUSH_TYPE type); static inline bool kfd_flush_tlb_after_unmap(struct kfd_dev *dev) { - return KFD_GC_VERSION(dev) == IP_VERSION(9, 4, 3) || - KFD_GC_VERSION(dev) == IP_VERSION(9, 4, 2) || + return KFD_GC_VERSION(dev) > IP_VERSION(9, 4, 2) || (KFD_GC_VERSION(dev) == IP_VERSION(9, 4, 1) && dev->sdma_fw_version >= 18) || KFD_GC_VERSION(dev) == IP_VERSION(9, 4, 0); } diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c index ff98fded9534..c8c75ff7cea8 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c @@ -450,8 +450,7 @@ static ssize_t node_show(struct kobject *kobj, struct attribute *attr, sysfs_show_32bit_prop(buffer, offs, "cpu_cores_count", dev->node_props.cpu_cores_count); sysfs_show_32bit_prop(buffer, offs, "simd_count", - dev->gpu ? (dev->node_props.simd_count * - NUM_XCC(dev->gpu->xcc_mask)) : 0); + dev->gpu ? dev->node_props.simd_count : 0); sysfs_show_32bit_prop(buffer, offs, "mem_banks_count", dev->node_props.mem_banks_count); sysfs_show_32bit_prop(buffer, offs, "caches_count", @@ -1597,14 +1596,17 @@ static int fill_in_l1_pcache(struct kfd_cache_properties **props_ext, static int fill_in_l2_l3_pcache(struct kfd_cache_properties **props_ext, struct kfd_gpu_cache_info *pcache_info, struct kfd_cu_info *cu_info, - int cache_type, unsigned int cu_processor_id) + int cache_type, unsigned int cu_processor_id, + struct kfd_node *knode) { unsigned int cu_sibling_map_mask; int first_active_cu; - int i, j, k; + int i, j, k, xcc, start, end; struct kfd_cache_properties *pcache = NULL; - cu_sibling_map_mask = cu_info->cu_bitmap[0][0]; + start = ffs(knode->xcc_mask) - 1; + end = start + NUM_XCC(knode->xcc_mask); + cu_sibling_map_mask = cu_info->cu_bitmap[start][0][0]; cu_sibling_map_mask &= ((1 << pcache_info[cache_type].num_cu_shared) - 1); first_active_cu = ffs(cu_sibling_map_mask); @@ -1639,16 +1641,18 @@ static int fill_in_l2_l3_pcache(struct kfd_cache_properties **props_ext, cu_sibling_map_mask = cu_sibling_map_mask >> (first_active_cu - 1); k = 0; - for (i = 0; i < cu_info->num_shader_engines; i++) { - for (j = 0; j < cu_info->num_shader_arrays_per_engine; j++) { - pcache->sibling_map[k] = (uint8_t)(cu_sibling_map_mask & 0xFF); - pcache->sibling_map[k+1] = (uint8_t)((cu_sibling_map_mask >> 8) & 0xFF); - pcache->sibling_map[k+2] = (uint8_t)((cu_sibling_map_mask >> 16) & 0xFF); - pcache->sibling_map[k+3] = (uint8_t)((cu_sibling_map_mask >> 24) & 0xFF); - k += 4; - - cu_sibling_map_mask = cu_info->cu_bitmap[i % 4][j + i / 4]; - cu_sibling_map_mask &= ((1 << pcache_info[cache_type].num_cu_shared) - 1); + for (xcc = start; xcc < end; xcc++) { + for (i = 0; i < cu_info->num_shader_engines; i++) { + for (j = 0; j < cu_info->num_shader_arrays_per_engine; j++) { + pcache->sibling_map[k] = (uint8_t)(cu_sibling_map_mask & 0xFF); + pcache->sibling_map[k+1] = (uint8_t)((cu_sibling_map_mask >> 8) & 0xFF); + pcache->sibling_map[k+2] = (uint8_t)((cu_sibling_map_mask >> 16) & 0xFF); + pcache->sibling_map[k+3] = (uint8_t)((cu_sibling_map_mask >> 24) & 0xFF); + k += 4; + + cu_sibling_map_mask = cu_info->cu_bitmap[xcc][i % 4][j + i / 4]; + cu_sibling_map_mask &= ((1 << pcache_info[cache_type].num_cu_shared) - 1); + } } } pcache->sibling_map_size = k; @@ -1666,7 +1670,7 @@ static int fill_in_l2_l3_pcache(struct kfd_cache_properties **props_ext, static void kfd_fill_cache_non_crat_info(struct kfd_topology_device *dev, struct kfd_node *kdev) { struct kfd_gpu_cache_info *pcache_info = NULL; - int i, j, k; + int i, j, k, xcc, start, end; int ct = 0; unsigned int cu_processor_id; int ret; @@ -1700,37 +1704,42 @@ static void kfd_fill_cache_non_crat_info(struct kfd_topology_device *dev, struct * then it will consider only one CU from * the shared unit */ + start = ffs(kdev->xcc_mask) - 1; + end = start + NUM_XCC(kdev->xcc_mask); + for (ct = 0; ct < num_of_cache_types; ct++) { cu_processor_id = gpu_processor_id; if (pcache_info[ct].cache_level == 1) { - for (i = 0; i < pcu_info->num_shader_engines; i++) { - for (j = 0; j < pcu_info->num_shader_arrays_per_engine; j++) { - for (k = 0; k < pcu_info->num_cu_per_sh; k += pcache_info[ct].num_cu_shared) { + for (xcc = start; xcc < end; xcc++) { + for (i = 0; i < pcu_info->num_shader_engines; i++) { + for (j = 0; j < pcu_info->num_shader_arrays_per_engine; j++) { + for (k = 0; k < pcu_info->num_cu_per_sh; k += pcache_info[ct].num_cu_shared) { - ret = fill_in_l1_pcache(&props_ext, pcache_info, pcu_info, - pcu_info->cu_bitmap[i % 4][j + i / 4], ct, + ret = fill_in_l1_pcache(&props_ext, pcache_info, pcu_info, + pcu_info->cu_bitmap[xcc][i % 4][j + i / 4], ct, cu_processor_id, k); - if (ret < 0) - break; + if (ret < 0) + break; - if (!ret) { - num_of_entries++; - list_add_tail(&props_ext->list, &dev->cache_props); - } + if (!ret) { + num_of_entries++; + list_add_tail(&props_ext->list, &dev->cache_props); + } - /* Move to next CU block */ - num_cu_shared = ((k + pcache_info[ct].num_cu_shared) <= - pcu_info->num_cu_per_sh) ? - pcache_info[ct].num_cu_shared : - (pcu_info->num_cu_per_sh - k); - cu_processor_id += num_cu_shared; + /* Move to next CU block */ + num_cu_shared = ((k + pcache_info[ct].num_cu_shared) <= + pcu_info->num_cu_per_sh) ? + pcache_info[ct].num_cu_shared : + (pcu_info->num_cu_per_sh - k); + cu_processor_id += num_cu_shared; + } } } } } else { ret = fill_in_l2_l3_pcache(&props_ext, pcache_info, - pcu_info, ct, cu_processor_id); + pcu_info, ct, cu_processor_id, kdev); if (ret < 0) break; diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_topology.h b/drivers/gpu/drm/amd/amdkfd/kfd_topology.h index dea32a9e5506..27386ce9a021 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_topology.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_topology.h @@ -89,7 +89,7 @@ struct kfd_mem_properties { struct attribute attr; }; -#define CACHE_SIBLINGMAP_SIZE 64 +#define CACHE_SIBLINGMAP_SIZE 128 struct kfd_cache_properties { struct list_head list; 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 88ba8b66de1f..868946dd7ef1 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -1274,11 +1274,15 @@ static void mmhub_read_system_context(struct amdgpu_device *adev, struct dc_phy_ pt_base = amdgpu_gmc_pd_addr(adev->gart.bo); - page_table_start.high_part = (u32)(adev->gmc.gart_start >> 44) & 0xF; - page_table_start.low_part = (u32)(adev->gmc.gart_start >> 12); - page_table_end.high_part = (u32)(adev->gmc.gart_end >> 44) & 0xF; - page_table_end.low_part = (u32)(adev->gmc.gart_end >> 12); - page_table_base.high_part = upper_32_bits(pt_base) & 0xF; + page_table_start.high_part = upper_32_bits(adev->gmc.gart_start >> + AMDGPU_GPU_PAGE_SHIFT); + page_table_start.low_part = lower_32_bits(adev->gmc.gart_start >> + AMDGPU_GPU_PAGE_SHIFT); + page_table_end.high_part = upper_32_bits(adev->gmc.gart_end >> + AMDGPU_GPU_PAGE_SHIFT); + page_table_end.low_part = lower_32_bits(adev->gmc.gart_end >> + AMDGPU_GPU_PAGE_SHIFT); + page_table_base.high_part = upper_32_bits(pt_base); page_table_base.low_part = lower_32_bits(pt_base); pa_config->system_aperture.start_addr = (uint64_t)logical_addr_low << 18; @@ -1640,8 +1644,9 @@ static int amdgpu_dm_init(struct amdgpu_device *adev) } break; } - if (init_data.flags.gpu_vm_support) - init_data.flags.gpu_vm_support = amdgpu_sg_display_supported(adev); + if (init_data.flags.gpu_vm_support && + (amdgpu_sg_display == 0)) + init_data.flags.gpu_vm_support = false; if (init_data.flags.gpu_vm_support) adev->mode_info.gpu_vm_support = true; @@ -2335,14 +2340,62 @@ static int dm_late_init(void *handle) return detect_mst_link_for_all_connectors(adev_to_drm(adev)); } +static void resume_mst_branch_status(struct drm_dp_mst_topology_mgr *mgr) +{ + int ret; + u8 guid[16]; + u64 tmp64; + + mutex_lock(&mgr->lock); + if (!mgr->mst_primary) + goto out_fail; + + if (drm_dp_read_dpcd_caps(mgr->aux, mgr->dpcd) < 0) { + drm_dbg_kms(mgr->dev, "dpcd read failed - undocked during suspend?\n"); + goto out_fail; + } + + ret = drm_dp_dpcd_writeb(mgr->aux, DP_MSTM_CTRL, + DP_MST_EN | + DP_UP_REQ_EN | + DP_UPSTREAM_IS_SRC); + if (ret < 0) { + drm_dbg_kms(mgr->dev, "mst write failed - undocked during suspend?\n"); + goto out_fail; + } + + /* Some hubs forget their guids after they resume */ + ret = drm_dp_dpcd_read(mgr->aux, DP_GUID, guid, 16); + if (ret != 16) { + drm_dbg_kms(mgr->dev, "dpcd read failed - undocked during suspend?\n"); + goto out_fail; + } + + if (memchr_inv(guid, 0, 16) == NULL) { + tmp64 = get_jiffies_64(); + memcpy(&guid[0], &tmp64, sizeof(u64)); + memcpy(&guid[8], &tmp64, sizeof(u64)); + + ret = drm_dp_dpcd_write(mgr->aux, DP_GUID, guid, 16); + + if (ret != 16) { + drm_dbg_kms(mgr->dev, "check mstb guid failed - undocked during suspend?\n"); + goto out_fail; + } + } + + memcpy(mgr->mst_primary->guid, guid, 16); + +out_fail: + mutex_unlock(&mgr->lock); +} + static void s3_handle_mst(struct drm_device *dev, bool suspend) { struct amdgpu_dm_connector *aconnector; struct drm_connector *connector; struct drm_connector_list_iter iter; struct drm_dp_mst_topology_mgr *mgr; - int ret; - bool need_hotplug = false; drm_connector_list_iter_begin(dev, &iter); drm_for_each_connector_iter(connector, &iter) { @@ -2364,18 +2417,15 @@ static void s3_handle_mst(struct drm_device *dev, bool suspend) if (!dp_is_lttpr_present(aconnector->dc_link)) try_to_configure_aux_timeout(aconnector->dc_link->ddc, LINK_AUX_DEFAULT_TIMEOUT_PERIOD); - ret = drm_dp_mst_topology_mgr_resume(mgr, true); - if (ret < 0) { - dm_helpers_dp_mst_stop_top_mgr(aconnector->dc_link->ctx, - aconnector->dc_link); - need_hotplug = true; - } + /* TODO: move resume_mst_branch_status() into drm mst resume again + * once topology probing work is pulled out from mst resume into mst + * resume 2nd step. mst resume 2nd step should be called after old + * state getting restored (i.e. drm_atomic_helper_resume()). + */ + resume_mst_branch_status(mgr); } } drm_connector_list_iter_end(&iter); - - if (need_hotplug) - drm_kms_helper_hotplug_event(dev); } static int amdgpu_dm_smu_write_watermarks_table(struct amdgpu_device *adev) @@ -2769,7 +2819,8 @@ static int dm_resume(void *handle) struct dm_atomic_state *dm_state = to_dm_atomic_state(dm->atomic_obj.state); enum dc_connection_type new_connection_type = dc_connection_none; struct dc_state *dc_state; - int i, r, j; + int i, r, j, ret; + bool need_hotplug = false; if (amdgpu_in_reset(adev)) { dc_state = dm->cached_dc_state; @@ -2867,7 +2918,7 @@ static int dm_resume(void *handle) continue; /* - * this is the case when traversing through already created + * this is the case when traversing through already created end sink * MST connectors, should be skipped */ if (aconnector && aconnector->mst_root) @@ -2927,6 +2978,27 @@ static int dm_resume(void *handle) dm->cached_state = NULL; + /* Do mst topology probing after resuming cached state*/ + drm_connector_list_iter_begin(ddev, &iter); + drm_for_each_connector_iter(connector, &iter) { + aconnector = to_amdgpu_dm_connector(connector); + if (aconnector->dc_link->type != dc_connection_mst_branch || + aconnector->mst_root) + continue; + + ret = drm_dp_mst_topology_mgr_resume(&aconnector->mst_mgr, true); + + if (ret < 0) { + dm_helpers_dp_mst_stop_top_mgr(aconnector->dc_link->ctx, + aconnector->dc_link); + need_hotplug = true; + } + } + drm_connector_list_iter_end(&iter); + + if (need_hotplug) + drm_kms_helper_hotplug_event(ddev); + amdgpu_dm_irq_resume_late(adev); amdgpu_dm_smu_write_watermarks_table(adev); @@ -6026,8 +6098,6 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector, if (recalculate_timing) drm_mode_set_crtcinfo(&saved_mode, 0); - else if (!old_stream) - drm_mode_set_crtcinfo(&mode, 0); /* * If scaling is enabled and refresh rate didn't change @@ -6589,6 +6659,8 @@ enum drm_mode_status amdgpu_dm_connector_mode_valid(struct drm_connector *connec goto fail; } + drm_mode_set_crtcinfo(mode, 0); + stream = create_validate_stream_for_sink(aconnector, mode, to_dm_connector_state(connector->state), NULL); @@ -8073,7 +8145,8 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, bundle->surface_updates[planes_count].plane_info = &bundle->plane_infos[planes_count]; - if (acrtc_state->stream->link->psr_settings.psr_feature_enabled) { + if (acrtc_state->stream->link->psr_settings.psr_feature_enabled || + acrtc_state->stream->link->replay_settings.replay_feature_enabled) { fill_dc_dirty_rects(plane, old_plane_state, new_plane_state, new_crtc_state, &bundle->flip_addrs[planes_count], 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 a2d34be82613..9e4cc5eeda76 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h @@ -620,7 +620,7 @@ struct amdgpu_hdmi_vsdb_info { unsigned int max_refresh_rate_hz; /** - * @replay mode: Replay supported + * @replay_mode: Replay supported */ bool replay_mode; }; diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_enc_cfg.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_enc_cfg.c index 30c0644d4418..be5a6d008b29 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link_enc_cfg.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_enc_cfg.c @@ -169,11 +169,23 @@ static void add_link_enc_assignment( /* Return first available DIG link encoder. */ static enum engine_id find_first_avail_link_enc( const struct dc_context *ctx, - const struct dc_state *state) + const struct dc_state *state, + enum engine_id eng_id_requested) { enum engine_id eng_id = ENGINE_ID_UNKNOWN; int i; + if (eng_id_requested != ENGINE_ID_UNKNOWN) { + + for (i = 0; i < ctx->dc->res_pool->res_cap->num_dig_link_enc; i++) { + eng_id = state->res_ctx.link_enc_cfg_ctx.link_enc_avail[i]; + if (eng_id == eng_id_requested) + return eng_id; + } + } + + eng_id = ENGINE_ID_UNKNOWN; + for (i = 0; i < ctx->dc->res_pool->res_cap->num_dig_link_enc; i++) { eng_id = state->res_ctx.link_enc_cfg_ctx.link_enc_avail[i]; if (eng_id != ENGINE_ID_UNKNOWN) @@ -287,7 +299,7 @@ void link_enc_cfg_link_encs_assign( struct dc_stream_state *streams[], uint8_t stream_count) { - enum engine_id eng_id = ENGINE_ID_UNKNOWN; + enum engine_id eng_id = ENGINE_ID_UNKNOWN, eng_id_req = ENGINE_ID_UNKNOWN; int i; int j; @@ -377,8 +389,14 @@ void link_enc_cfg_link_encs_assign( * assigned to that endpoint. */ link_enc = get_link_enc_used_by_link(state, stream->link); - if (link_enc == NULL) - eng_id = find_first_avail_link_enc(stream->ctx, state); + if (link_enc == NULL) { + + if (stream->link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA && + stream->link->dpia_preferred_eng_id != ENGINE_ID_UNKNOWN) + eng_id_req = stream->link->dpia_preferred_eng_id; + + eng_id = find_first_avail_link_enc(stream->ctx, state, eng_id_req); + } else eng_id = link_enc->preferred_engine; @@ -402,7 +420,9 @@ void link_enc_cfg_link_encs_assign( DC_LOG_DEBUG("%s: CUR %s(%d) - enc_id(%d)\n", __func__, assignment.ep_id.ep_type == DISPLAY_ENDPOINT_PHY ? "PHY" : "DPIA", - assignment.ep_id.link_id.enum_id - 1, + assignment.ep_id.ep_type == DISPLAY_ENDPOINT_PHY ? + assignment.ep_id.link_id.enum_id : + assignment.ep_id.link_id.enum_id - 1, assignment.eng_id); } for (i = 0; i < MAX_PIPES; i++) { @@ -413,7 +433,9 @@ void link_enc_cfg_link_encs_assign( DC_LOG_DEBUG("%s: NEW %s(%d) - enc_id(%d)\n", __func__, assignment.ep_id.ep_type == DISPLAY_ENDPOINT_PHY ? "PHY" : "DPIA", - assignment.ep_id.link_id.enum_id - 1, + assignment.ep_id.ep_type == DISPLAY_ENDPOINT_PHY ? + assignment.ep_id.link_id.enum_id : + assignment.ep_id.link_id.enum_id - 1, assignment.eng_id); } @@ -478,7 +500,6 @@ struct dc_link *link_enc_cfg_get_link_using_link_enc( if (stream) link = stream->link; - // dm_output_to_console("%s: No link using DIG(%d).\n", __func__, eng_id); return link; } diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 0d0bef8eb331..31e3183497a7 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -1496,6 +1496,7 @@ struct dc_link { * object creation. */ enum engine_id eng_id; + enum engine_id dpia_preferred_eng_id; bool test_pattern_enabled; enum dp_test_pattern current_test_pattern; diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c index ad967b58d7be..2a6157555fd1 100644 --- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c +++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c @@ -964,7 +964,9 @@ void dce110_edp_backlight_control( return; } - if (link->panel_cntl) { + if (link->panel_cntl && !(link->dpcd_sink_ext_caps.bits.oled || + link->dpcd_sink_ext_caps.bits.hdr_aux_backlight_control == 1 || + link->dpcd_sink_ext_caps.bits.sdr_aux_backlight_control == 1)) { bool is_backlight_on = link->panel_cntl->funcs->is_panel_backlight_on(link->panel_cntl); if ((enable && is_backlight_on) || (!enable && !is_backlight_on)) { @@ -1176,12 +1178,15 @@ void dce110_disable_stream(struct pipe_ctx *pipe_ctx) dto_params.otg_inst = tg->inst; dto_params.timing = &pipe_ctx->stream->timing; dp_hpo_inst = pipe_ctx->stream_res.hpo_dp_stream_enc->inst; - dccg->funcs->set_dtbclk_dto(dccg, &dto_params); - dccg->funcs->disable_symclk32_se(dccg, dp_hpo_inst); - dccg->funcs->set_dpstreamclk(dccg, REFCLK, tg->inst, dp_hpo_inst); - } else if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST && dccg->funcs->disable_symclk_se) + if (dccg) { + dccg->funcs->set_dtbclk_dto(dccg, &dto_params); + dccg->funcs->disable_symclk32_se(dccg, dp_hpo_inst); + dccg->funcs->set_dpstreamclk(dccg, REFCLK, tg->inst, dp_hpo_inst); + } + } else if (dccg && dccg->funcs->disable_symclk_se) { dccg->funcs->disable_symclk_se(dccg, stream_enc->stream_enc_inst, link_enc->transmitter - TRANSMITTER_UNIPHY_A); + } if (dc->link_srv->dp_is_128b_132b_signal(pipe_ctx)) { /* TODO: This looks like a bug to me as we are disabling HPO IO when @@ -2656,11 +2661,11 @@ void dce110_prepare_bandwidth( struct clk_mgr *dccg = dc->clk_mgr; dce110_set_safe_displaymarks(&context->res_ctx, dc->res_pool); - - dccg->funcs->update_clocks( - dccg, - context, - false); + if (dccg) + dccg->funcs->update_clocks( + dccg, + context, + false); } void dce110_optimize_bandwidth( @@ -2671,10 +2676,11 @@ void dce110_optimize_bandwidth( dce110_set_displaymarks(dc, context); - dccg->funcs->update_clocks( - dccg, - context, - true); + if (dccg) + dccg->funcs->update_clocks( + dccg, + context, + true); } static void dce110_program_front_end_for_pipe( diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c index e72f15ac0048..aeadc587433f 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c @@ -2692,8 +2692,6 @@ void dcn20_enable_stream(struct pipe_ctx *pipe_ctx) struct dce_hwseq *hws = dc->hwseq; unsigned int k1_div = PIXEL_RATE_DIV_NA; unsigned int k2_div = PIXEL_RATE_DIV_NA; - struct link_encoder *link_enc = link_enc_cfg_get_link_enc(pipe_ctx->stream->link); - struct stream_encoder *stream_enc = pipe_ctx->stream_res.stream_enc; if (dc->link_srv->dp_is_128b_132b_signal(pipe_ctx)) { if (dc->hwseq->funcs.setup_hpo_hw_control) @@ -2713,10 +2711,8 @@ void dcn20_enable_stream(struct pipe_ctx *pipe_ctx) dto_params.timing = &pipe_ctx->stream->timing; dto_params.ref_dtbclk_khz = dc->clk_mgr->funcs->get_dtb_ref_clk_frequency(dc->clk_mgr); dccg->funcs->set_dtbclk_dto(dccg, &dto_params); - } else if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST && dccg->funcs->enable_symclk_se) - dccg->funcs->enable_symclk_se(dccg, - stream_enc->stream_enc_inst, link_enc->transmitter - TRANSMITTER_UNIPHY_A); - + } else { + } if (hws->funcs.calculate_dccg_k1_k2_values && dc->res_pool->dccg->funcs->set_pixel_rate_div) { hws->funcs.calculate_dccg_k1_k2_values(pipe_ctx, &k1_div, &k2_div); diff --git a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c index 1c1fb2fa0822..004beed9bd44 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn314/dcn314_resource.c @@ -1032,6 +1032,28 @@ static const struct dce_i2c_mask i2c_masks = { I2C_COMMON_MASK_SH_LIST_DCN30(_MASK) }; +/* ========================================================== */ + +/* + * DPIA index | Preferred Encoder | Host Router + * 0 | C | 0 + * 1 | First Available | 0 + * 2 | D | 1 + * 3 | First Available | 1 + */ +/* ========================================================== */ +static const enum engine_id dpia_to_preferred_enc_id_table[] = { + ENGINE_ID_DIGC, + ENGINE_ID_DIGC, + ENGINE_ID_DIGD, + ENGINE_ID_DIGD +}; + +static enum engine_id dcn314_get_preferred_eng_id_dpia(unsigned int dpia_index) +{ + return dpia_to_preferred_enc_id_table[dpia_index]; +} + static struct dce_i2c_hw *dcn31_i2c_hw_create( struct dc_context *ctx, uint32_t inst) @@ -1785,6 +1807,7 @@ static struct resource_funcs dcn314_res_pool_funcs = { .update_bw_bounding_box = dcn314_update_bw_bounding_box, .patch_unknown_plane_state = dcn20_patch_unknown_plane_state, .get_panel_config_defaults = dcn314_get_panel_config_defaults, + .get_preferred_eng_id_dpia = dcn314_get_preferred_eng_id_dpia, }; static struct clock_source *dcn30_clock_source_create( diff --git a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_mpc.c b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_mpc.c index 3082da04a63d..1d052f08aff5 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_mpc.c +++ b/drivers/gpu/drm/amd/display/dc/dcn32/dcn32_mpc.c @@ -75,7 +75,7 @@ void mpc32_power_on_blnd_lut( if (power_on) { REG_UPDATE(MPCC_MCM_MEM_PWR_CTRL[mpcc_id], MPCC_MCM_1DLUT_MEM_PWR_FORCE, 0); REG_WAIT(MPCC_MCM_MEM_PWR_CTRL[mpcc_id], MPCC_MCM_1DLUT_MEM_PWR_STATE, 0, 1, 5); - } else { + } else if (!mpc->ctx->dc->debug.disable_mem_low_power) { ASSERT(false); /* TODO: change to mpc * dpp_base->ctx->dc->optimized_required = true; diff --git a/drivers/gpu/drm/amd/display/dc/inc/core_types.h b/drivers/gpu/drm/amd/display/dc/inc/core_types.h index 027aec70c070..eaad1260bfd1 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/core_types.h +++ b/drivers/gpu/drm/amd/display/dc/inc/core_types.h @@ -65,6 +65,7 @@ struct resource_context; struct clk_bw_params; struct resource_funcs { + enum engine_id (*get_preferred_eng_id_dpia)(unsigned int dpia_index); void (*destroy)(struct resource_pool **pool); void (*link_init)(struct dc_link *link); struct panel_cntl*(*panel_cntl_create)( diff --git a/drivers/gpu/drm/amd/display/dc/link/link_factory.c b/drivers/gpu/drm/amd/display/dc/link/link_factory.c index 195ca9e52eda..0895742a3102 100644 --- a/drivers/gpu/drm/amd/display/dc/link/link_factory.c +++ b/drivers/gpu/drm/amd/display/dc/link/link_factory.c @@ -791,6 +791,10 @@ static bool construct_dpia(struct dc_link *link, /* Set dpia port index : 0 to number of dpia ports */ link->ddc_hw_inst = init_params->connector_index; + // Assign Dpia preferred eng_id + if (link->dc->res_pool->funcs->get_preferred_eng_id_dpia) + link->dpia_preferred_eng_id = link->dc->res_pool->funcs->get_preferred_eng_id_dpia(link->ddc_hw_inst); + /* TODO: Create link encoder */ link->psr_settings.psr_version = DC_PSR_VERSION_UNSUPPORTED; diff --git a/drivers/gpu/drm/amd/include/kgd_kfd_interface.h b/drivers/gpu/drm/amd/include/kgd_kfd_interface.h index 8433f99f6667..3b5a56585c4b 100644 --- a/drivers/gpu/drm/amd/include/kgd_kfd_interface.h +++ b/drivers/gpu/drm/amd/include/kgd_kfd_interface.h @@ -31,12 +31,12 @@ #include <linux/types.h> #include <linux/bitmap.h> #include <linux/dma-fence.h> +#include "amdgpu_irq.h" +#include "amdgpu_gfx.h" struct pci_dev; struct amdgpu_device; -#define KGD_MAX_QUEUES 128 - struct kfd_dev; struct kgd_mem; @@ -68,7 +68,7 @@ struct kfd_cu_info { uint32_t wave_front_size; uint32_t max_scratch_slots_per_cu; uint32_t lds_size; - uint32_t cu_bitmap[4][4]; + uint32_t cu_bitmap[AMDGPU_MAX_GC_INSTANCES][4][4]; }; /* For getting GPU local memory information from KGD */ @@ -326,8 +326,7 @@ struct kfd2kgd_calls { uint32_t wait_times, uint32_t grace_period, uint32_t *reg_offset, - uint32_t *reg_data, - uint32_t inst); + uint32_t *reg_data); void (*get_cu_occupancy)(struct amdgpu_device *adev, int pasid, int *wave_cnt, int *max_waves_per_cu, uint32_t inst); void (*program_trap_handler_settings)(struct amdgpu_device *adev, 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 199a673b8120..de80e191a92c 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 @@ -336,7 +336,7 @@ static int smu_v13_0_6_setup_driver_pptable(struct smu_context *smu) /* Store one-time values in driver PPTable */ if (!pptable->Init) { - while (retry--) { + while (--retry) { ret = smu_v13_0_6_get_metrics_table(smu, NULL, true); if (ret) return ret; diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c index bf8371dc2a61..c44d5bcf1284 100644 --- a/drivers/gpu/drm/drm_connector.c +++ b/drivers/gpu/drm/drm_connector.c @@ -2203,6 +2203,7 @@ static int drm_mode_create_colorspace_property(struct drm_connector *connector, /** * drm_mode_create_hdmi_colorspace_property - create hdmi colorspace property * @connector: connector to create the Colorspace property on. + * @supported_colorspaces: bitmap of supported color spaces * * Called by a driver the first time it's needed, must be attached to desired * HDMI connectors. @@ -2227,6 +2228,7 @@ EXPORT_SYMBOL(drm_mode_create_hdmi_colorspace_property); /** * drm_mode_create_dp_colorspace_property - create dp colorspace property * @connector: connector to create the Colorspace property on. + * @supported_colorspaces: bitmap of supported color spaces * * Called by a driver the first time it's needed, must be attached to desired * DP connectors. diff --git a/drivers/gpu/drm/drm_exec.c b/drivers/gpu/drm/drm_exec.c index ff69cf0fb42a..5d2809de4517 100644 --- a/drivers/gpu/drm/drm_exec.c +++ b/drivers/gpu/drm/drm_exec.c @@ -56,7 +56,7 @@ static void drm_exec_unlock_all(struct drm_exec *exec) struct drm_gem_object *obj; unsigned long index; - drm_exec_for_each_locked_object(exec, index, obj) { + drm_exec_for_each_locked_object_reverse(exec, index, obj) { dma_resv_unlock(obj->resv); drm_gem_object_put(obj); } diff --git a/drivers/gpu/drm/i915/display/intel_bios.c b/drivers/gpu/drm/i915/display/intel_bios.c index 858c959f7bab..f735b035436c 100644 --- a/drivers/gpu/drm/i915/display/intel_bios.c +++ b/drivers/gpu/drm/i915/display/intel_bios.c @@ -3540,6 +3540,27 @@ enum aux_ch intel_bios_dp_aux_ch(const struct intel_bios_encoder_data *devdata) return map_aux_ch(devdata->i915, devdata->child.aux_channel); } +bool intel_bios_dp_has_shared_aux_ch(const struct intel_bios_encoder_data *devdata) +{ + struct drm_i915_private *i915; + u8 aux_channel; + int count = 0; + + if (!devdata || !devdata->child.aux_channel) + return false; + + i915 = devdata->i915; + aux_channel = devdata->child.aux_channel; + + list_for_each_entry(devdata, &i915->display.vbt.display_devices, node) { + if (intel_bios_encoder_supports_dp(devdata) && + aux_channel == devdata->child.aux_channel) + count++; + } + + return count > 1; +} + int intel_bios_dp_boost_level(const struct intel_bios_encoder_data *devdata) { if (!devdata || devdata->i915->display.vbt.version < 196 || !devdata->child.iboost) diff --git a/drivers/gpu/drm/i915/display/intel_bios.h b/drivers/gpu/drm/i915/display/intel_bios.h index 9680e3e92bb5..49e24b7cf675 100644 --- a/drivers/gpu/drm/i915/display/intel_bios.h +++ b/drivers/gpu/drm/i915/display/intel_bios.h @@ -273,6 +273,7 @@ enum aux_ch intel_bios_dp_aux_ch(const struct intel_bios_encoder_data *devdata); int intel_bios_dp_boost_level(const struct intel_bios_encoder_data *devdata); int intel_bios_dp_max_lane_count(const struct intel_bios_encoder_data *devdata); int intel_bios_dp_max_link_rate(const struct intel_bios_encoder_data *devdata); +bool intel_bios_dp_has_shared_aux_ch(const struct intel_bios_encoder_data *devdata); int intel_bios_hdmi_boost_level(const struct intel_bios_encoder_data *devdata); int intel_bios_hdmi_ddc_pin(const struct intel_bios_encoder_data *devdata); int intel_bios_hdmi_level_shift(const struct intel_bios_encoder_data *devdata); diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 12bd2f322e62..e0e4cb529284 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -5512,8 +5512,13 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp, /* * VBT and straps are liars. Also check HPD as that seems * to be the most reliable piece of information available. + * + * ... expect on devices that forgot to hook HPD up for eDP + * (eg. Acer Chromebook C710), so we'll check it only if multiple + * ports are attempting to use the same AUX CH, according to VBT. */ - if (!intel_digital_port_connected(encoder)) { + if (intel_bios_dp_has_shared_aux_ch(encoder->devdata) && + !intel_digital_port_connected(encoder)) { /* * If this fails, presume the DPCD answer came * from some other port using the same AUX CH. diff --git a/drivers/gpu/drm/i915/gem/i915_gem_shmem.c b/drivers/gpu/drm/i915/gem/i915_gem_shmem.c index 8f1633c3fb93..73a4a4eb29e0 100644 --- a/drivers/gpu/drm/i915/gem/i915_gem_shmem.c +++ b/drivers/gpu/drm/i915/gem/i915_gem_shmem.c @@ -100,6 +100,7 @@ int shmem_sg_alloc_table(struct drm_i915_private *i915, struct sg_table *st, st->nents = 0; for (i = 0; i < page_count; i++) { struct folio *folio; + unsigned long nr_pages; const unsigned int shrink[] = { I915_SHRINK_BOUND | I915_SHRINK_UNBOUND, 0, @@ -150,6 +151,8 @@ int shmem_sg_alloc_table(struct drm_i915_private *i915, struct sg_table *st, } } while (1); + nr_pages = min_t(unsigned long, + folio_nr_pages(folio), page_count - i); if (!i || sg->length >= max_segment || folio_pfn(folio) != next_pfn) { @@ -157,13 +160,13 @@ int shmem_sg_alloc_table(struct drm_i915_private *i915, struct sg_table *st, sg = sg_next(sg); st->nents++; - sg_set_folio(sg, folio, folio_size(folio), 0); + sg_set_folio(sg, folio, nr_pages * PAGE_SIZE, 0); } else { /* XXX: could overflow? */ - sg->length += folio_size(folio); + sg->length += nr_pages * PAGE_SIZE; } - next_pfn = folio_pfn(folio) + folio_nr_pages(folio); - i += folio_nr_pages(folio) - 1; + next_pfn = folio_pfn(folio) + nr_pages; + i += nr_pages - 1; /* Check that the i965g/gm workaround works. */ GEM_BUG_ON(gfp & __GFP_DMA32 && next_pfn >= 0x00100000UL); diff --git a/drivers/gpu/drm/i915/gt/intel_engine_cs.c b/drivers/gpu/drm/i915/gt/intel_engine_cs.c index ee15486fed0d..e85d70a62123 100644 --- a/drivers/gpu/drm/i915/gt/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/gt/intel_engine_cs.c @@ -558,7 +558,6 @@ static int intel_engine_setup(struct intel_gt *gt, enum intel_engine_id id, DRIVER_CAPS(i915)->has_logical_contexts = true; ewma__engine_latency_init(&engine->latency); - seqcount_init(&engine->stats.execlists.lock); ATOMIC_INIT_NOTIFIER_HEAD(&engine->context_status_notifier); diff --git a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c index 8a641bcf777c..3292524469d5 100644 --- a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c +++ b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c @@ -3550,6 +3550,8 @@ int intel_execlists_submission_setup(struct intel_engine_cs *engine) logical_ring_default_vfuncs(engine); logical_ring_default_irqs(engine); + seqcount_init(&engine->stats.execlists.lock); + if (engine->flags & I915_ENGINE_HAS_RCS_REG_STATE) rcs_submission_override(engine); diff --git a/drivers/gpu/drm/i915/gt/intel_ggtt.c b/drivers/gpu/drm/i915/gt/intel_ggtt.c index dd0ed941441a..da21f2786b5d 100644 --- a/drivers/gpu/drm/i915/gt/intel_ggtt.c +++ b/drivers/gpu/drm/i915/gt/intel_ggtt.c @@ -511,20 +511,31 @@ void intel_ggtt_unbind_vma(struct i915_address_space *vm, vm->clear_range(vm, vma_res->start, vma_res->vma_size); } +/* + * Reserve the top of the GuC address space for firmware images. Addresses + * beyond GUC_GGTT_TOP in the GuC address space are inaccessible by GuC, + * which makes for a suitable range to hold GuC/HuC firmware images if the + * size of the GGTT is 4G. However, on a 32-bit platform the size of the GGTT + * is limited to 2G, which is less than GUC_GGTT_TOP, but we reserve a chunk + * of the same size anyway, which is far more than needed, to keep the logic + * in uc_fw_ggtt_offset() simple. + */ +#define GUC_TOP_RESERVE_SIZE (SZ_4G - GUC_GGTT_TOP) + static int ggtt_reserve_guc_top(struct i915_ggtt *ggtt) { - u64 size; + u64 offset; int ret; if (!intel_uc_uses_guc(&ggtt->vm.gt->uc)) return 0; - GEM_BUG_ON(ggtt->vm.total <= GUC_GGTT_TOP); - size = ggtt->vm.total - GUC_GGTT_TOP; + GEM_BUG_ON(ggtt->vm.total <= GUC_TOP_RESERVE_SIZE); + offset = ggtt->vm.total - GUC_TOP_RESERVE_SIZE; - ret = i915_gem_gtt_reserve(&ggtt->vm, NULL, &ggtt->uc_fw, size, - GUC_GGTT_TOP, I915_COLOR_UNEVICTABLE, - PIN_NOEVICT); + ret = i915_gem_gtt_reserve(&ggtt->vm, NULL, &ggtt->uc_fw, + GUC_TOP_RESERVE_SIZE, offset, + I915_COLOR_UNEVICTABLE, PIN_NOEVICT); if (ret) drm_dbg(&ggtt->vm.i915->drm, "Failed to reserve top of GGTT for GuC\n"); diff --git a/drivers/gpu/drm/i915/gt/intel_lrc.c b/drivers/gpu/drm/i915/gt/intel_lrc.c index 957d0aeb0c02..c378cc7c953c 100644 --- a/drivers/gpu/drm/i915/gt/intel_lrc.c +++ b/drivers/gpu/drm/i915/gt/intel_lrc.c @@ -1094,6 +1094,9 @@ __lrc_alloc_state(struct intel_context *ce, struct intel_engine_cs *engine) I915_BO_ALLOC_PM_VOLATILE); if (IS_ERR(obj)) { obj = i915_gem_object_create_shmem(engine->i915, context_size); + if (IS_ERR(obj)) + return ERR_CAST(obj); + /* * Wa_22016122933: For Media version 13.0, all Media GT shared * memory needs to be mapped as WC on CPU side and UC (PAT @@ -1102,8 +1105,6 @@ __lrc_alloc_state(struct intel_context *ce, struct intel_engine_cs *engine) if (intel_gt_needs_wa_22016122933(engine->gt)) i915_gem_object_set_cache_coherency(obj, I915_CACHE_NONE); } - if (IS_ERR(obj)) - return ERR_CAST(obj); vma = i915_vma_instance(obj, &engine->gt->ggtt->vm, NULL); if (IS_ERR(vma)) { diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c index b5b7f2fe8c78..dc7b40e06e38 100644 --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c @@ -1433,6 +1433,36 @@ static void guc_timestamp_ping(struct work_struct *wrk) int srcu, ret; /* + * Ideally the busyness worker should take a gt pm wakeref because the + * worker only needs to be active while gt is awake. However, the + * gt_park path cancels the worker synchronously and this complicates + * the flow if the worker is also running at the same time. The cancel + * waits for the worker and when the worker releases the wakeref, that + * would call gt_park and would lead to a deadlock. + * + * The resolution is to take the global pm wakeref if runtime pm is + * already active. If not, we don't need to update the busyness stats as + * the stats would already be updated when the gt was parked. + * + * Note: + * - We do not requeue the worker if we cannot take a reference to runtime + * pm since intel_guc_busyness_unpark would requeue the worker in the + * resume path. + * + * - If the gt was parked longer than time taken for GT timestamp to roll + * over, we ignore those rollovers since we don't care about tracking + * the exact GT time. We only care about roll overs when the gt is + * active and running workloads. + * + * - There is a window of time between gt_park and runtime suspend, + * where the worker may run. This is acceptable since the worker will + * not find any new data to update busyness. + */ + wakeref = intel_runtime_pm_get_if_active(>->i915->runtime_pm); + if (!wakeref) + return; + + /* * Synchronize with gt reset to make sure the worker does not * corrupt the engine/guc stats. NB: can't actually block waiting * for a reset to complete as the reset requires flushing out @@ -1440,10 +1470,9 @@ static void guc_timestamp_ping(struct work_struct *wrk) */ ret = intel_gt_reset_trylock(gt, &srcu); if (ret) - return; + goto err_trylock; - with_intel_runtime_pm(>->i915->runtime_pm, wakeref) - __update_guc_busyness_stats(guc); + __update_guc_busyness_stats(guc); /* adjust context stats for overflow */ xa_for_each(&guc->context_lookup, index, ce) @@ -1452,6 +1481,9 @@ static void guc_timestamp_ping(struct work_struct *wrk) intel_gt_reset_unlock(gt, srcu); guc_enable_busyness_worker(guc); + +err_trylock: + intel_runtime_pm_put(>->i915->runtime_pm, wakeref); } static int guc_action_enable_usage_stats(struct intel_guc *guc) diff --git a/drivers/gpu/drm/meson/meson_encoder_hdmi.c b/drivers/gpu/drm/meson/meson_encoder_hdmi.c index 9913971fa5d2..25ea76558690 100644 --- a/drivers/gpu/drm/meson/meson_encoder_hdmi.c +++ b/drivers/gpu/drm/meson/meson_encoder_hdmi.c @@ -334,6 +334,8 @@ static void meson_encoder_hdmi_hpd_notify(struct drm_bridge *bridge, return; cec_notifier_set_phys_addr_from_edid(encoder_hdmi->cec_notifier, edid); + + kfree(edid); } else cec_notifier_phys_addr_invalidate(encoder_hdmi->cec_notifier); } diff --git a/drivers/gpu/drm/nouveau/nouveau_drv.h b/drivers/gpu/drm/nouveau/nouveau_drv.h index 1fe17ff95f5e..e73a233c6572 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drv.h +++ b/drivers/gpu/drm/nouveau/nouveau_drv.h @@ -189,21 +189,12 @@ u_free(void *addr) static inline void * u_memcpya(uint64_t user, unsigned int nmemb, unsigned int size) { - void *mem; - void __user *userptr = (void __force __user *)(uintptr_t)user; + void __user *userptr = u64_to_user_ptr(user); + size_t bytes; - size *= nmemb; - - mem = kvmalloc(size, GFP_KERNEL); - if (!mem) - return ERR_PTR(-ENOMEM); - - if (copy_from_user(mem, userptr, size)) { - u_free(mem); - return ERR_PTR(-EFAULT); - } - - return mem; + if (unlikely(check_mul_overflow(nmemb, size, &bytes))) + return ERR_PTR(-EOVERFLOW); + return vmemdup_user(userptr, bytes); } #include <nvif/object.h> diff --git a/drivers/gpu/drm/nouveau/nouveau_exec.c b/drivers/gpu/drm/nouveau/nouveau_exec.c index 19024ce21fbb..5dda94e1318c 100644 --- a/drivers/gpu/drm/nouveau/nouveau_exec.c +++ b/drivers/gpu/drm/nouveau/nouveau_exec.c @@ -213,7 +213,7 @@ nouveau_exec_job_timeout(struct nouveau_job *job) nouveau_sched_entity_fini(job->entity); - return DRM_GPU_SCHED_STAT_ENODEV; + return DRM_GPU_SCHED_STAT_NOMINAL; } static struct nouveau_job_ops nouveau_exec_job_ops = { diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c index 61d9e70da9fd..ca762ea55413 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.c +++ b/drivers/gpu/drm/nouveau/nouveau_fence.c @@ -207,7 +207,7 @@ nouveau_fence_context_new(struct nouveau_channel *chan, struct nouveau_fence_cha int nouveau_fence_emit(struct nouveau_fence *fence) { - struct nouveau_channel *chan = fence->channel; + struct nouveau_channel *chan = unrcu_pointer(fence->channel); struct nouveau_fence_chan *fctx = chan->fence; struct nouveau_fence_priv *priv = (void*)chan->drm->fence; int ret; diff --git a/drivers/gpu/drm/nouveau/nouveau_sched.c b/drivers/gpu/drm/nouveau/nouveau_sched.c index 88217185e0f3..3b7ea5221226 100644 --- a/drivers/gpu/drm/nouveau/nouveau_sched.c +++ b/drivers/gpu/drm/nouveau/nouveau_sched.c @@ -375,14 +375,20 @@ nouveau_sched_run_job(struct drm_sched_job *sched_job) static enum drm_gpu_sched_stat nouveau_sched_timedout_job(struct drm_sched_job *sched_job) { + struct drm_gpu_scheduler *sched = sched_job->sched; struct nouveau_job *job = to_nouveau_job(sched_job); + enum drm_gpu_sched_stat stat = DRM_GPU_SCHED_STAT_NOMINAL; - NV_PRINTK(warn, job->cli, "Job timed out.\n"); + drm_sched_stop(sched, sched_job); if (job->ops->timeout) - return job->ops->timeout(job); + stat = job->ops->timeout(job); + else + NV_PRINTK(warn, job->cli, "Generic job timeout.\n"); + + drm_sched_start(sched, true); - return DRM_GPU_SCHED_STAT_ENODEV; + return stat; } static void diff --git a/drivers/gpu/drm/radeon/radeon_sa.c b/drivers/gpu/drm/radeon/radeon_sa.c index c87a57c9c592..22dd8b445685 100644 --- a/drivers/gpu/drm/radeon/radeon_sa.c +++ b/drivers/gpu/drm/radeon/radeon_sa.c @@ -123,7 +123,7 @@ int radeon_sa_bo_new(struct radeon_sa_manager *sa_manager, unsigned int size, unsigned int align) { struct drm_suballoc *sa = drm_suballoc_new(&sa_manager->base, size, - GFP_KERNEL, true, align); + GFP_KERNEL, false, align); if (IS_ERR(sa)) { *sa_bo = NULL; diff --git a/drivers/gpu/drm/tests/drm_mm_test.c b/drivers/gpu/drm/tests/drm_mm_test.c index 186b28dc7038..05d5e7af6d25 100644 --- a/drivers/gpu/drm/tests/drm_mm_test.c +++ b/drivers/gpu/drm/tests/drm_mm_test.c @@ -939,7 +939,7 @@ static void drm_test_mm_insert_range(struct kunit *test) KUNIT_ASSERT_FALSE(test, __drm_test_mm_insert_range(test, count, size, 0, max - 1)); KUNIT_ASSERT_FALSE(test, __drm_test_mm_insert_range(test, count, size, 0, max / 2)); KUNIT_ASSERT_FALSE(test, __drm_test_mm_insert_range(test, count, size, - max / 2, max / 2)); + max / 2, max)); KUNIT_ASSERT_FALSE(test, __drm_test_mm_insert_range(test, count, size, max / 4 + 1, 3 * max / 4 - 1)); diff --git a/drivers/gpu/drm/tiny/gm12u320.c b/drivers/gpu/drm/tiny/gm12u320.c index c5bb683e440c..0187539ff5ea 100644 --- a/drivers/gpu/drm/tiny/gm12u320.c +++ b/drivers/gpu/drm/tiny/gm12u320.c @@ -70,10 +70,10 @@ MODULE_PARM_DESC(eco_mode, "Turn on Eco mode (less bright, more silent)"); #define READ_STATUS_SIZE 13 #define MISC_VALUE_SIZE 4 -#define CMD_TIMEOUT msecs_to_jiffies(200) -#define DATA_TIMEOUT msecs_to_jiffies(1000) -#define IDLE_TIMEOUT msecs_to_jiffies(2000) -#define FIRST_FRAME_TIMEOUT msecs_to_jiffies(2000) +#define CMD_TIMEOUT 200 +#define DATA_TIMEOUT 1000 +#define IDLE_TIMEOUT 2000 +#define FIRST_FRAME_TIMEOUT 2000 #define MISC_REQ_GET_SET_ECO_A 0xff #define MISC_REQ_GET_SET_ECO_B 0x35 @@ -389,7 +389,7 @@ static void gm12u320_fb_update_work(struct work_struct *work) * switches back to showing its logo. */ queue_delayed_work(system_long_wq, &gm12u320->fb_update.work, - IDLE_TIMEOUT); + msecs_to_jiffies(IDLE_TIMEOUT)); return; err: diff --git a/drivers/gpu/drm/virtio/virtgpu_submit.c b/drivers/gpu/drm/virtio/virtgpu_submit.c index 3c00135ead45..5c514946bbad 100644 --- a/drivers/gpu/drm/virtio/virtgpu_submit.c +++ b/drivers/gpu/drm/virtio/virtgpu_submit.c @@ -361,7 +361,6 @@ static void virtio_gpu_complete_submit(struct virtio_gpu_submit *submit) submit->buf = NULL; submit->buflist = NULL; submit->sync_file = NULL; - submit->out_fence = NULL; submit->out_fence_fd = -1; } diff --git a/drivers/gpu/drm/vkms/vkms_composer.c b/drivers/gpu/drm/vkms/vkms_composer.c index d5d4f642d367..3c99fb8b54e2 100644 --- a/drivers/gpu/drm/vkms/vkms_composer.c +++ b/drivers/gpu/drm/vkms/vkms_composer.c @@ -408,15 +408,10 @@ void vkms_set_composer(struct vkms_output *out, bool enabled) if (enabled) drm_crtc_vblank_get(&out->crtc); - mutex_lock(&out->enabled_lock); + spin_lock_irq(&out->lock); old_enabled = out->composer_enabled; out->composer_enabled = enabled; - - /* the composition wasn't enabled, so unlock the lock to make sure the lock - * will be balanced even if we have a failed commit - */ - if (!out->composer_enabled) - mutex_unlock(&out->enabled_lock); + spin_unlock_irq(&out->lock); if (old_enabled) drm_crtc_vblank_put(&out->crtc); diff --git a/drivers/gpu/drm/vkms/vkms_crtc.c b/drivers/gpu/drm/vkms/vkms_crtc.c index 3c5ebf106b66..61e500b8c9da 100644 --- a/drivers/gpu/drm/vkms/vkms_crtc.c +++ b/drivers/gpu/drm/vkms/vkms_crtc.c @@ -16,7 +16,7 @@ static enum hrtimer_restart vkms_vblank_simulate(struct hrtimer *timer) struct drm_crtc *crtc = &output->crtc; struct vkms_crtc_state *state; u64 ret_overrun; - bool ret, fence_cookie, composer_enabled; + bool ret, fence_cookie; fence_cookie = dma_fence_begin_signalling(); @@ -25,15 +25,15 @@ static enum hrtimer_restart vkms_vblank_simulate(struct hrtimer *timer) if (ret_overrun != 1) pr_warn("%s: vblank timer overrun\n", __func__); + spin_lock(&output->lock); ret = drm_crtc_handle_vblank(crtc); if (!ret) DRM_ERROR("vkms failure on handling vblank"); state = output->composer_state; - composer_enabled = output->composer_enabled; - mutex_unlock(&output->enabled_lock); + spin_unlock(&output->lock); - if (state && composer_enabled) { + if (state && output->composer_enabled) { u64 frame = drm_crtc_accurate_vblank_count(crtc); /* update frame_start only if a queued vkms_composer_worker() @@ -295,7 +295,6 @@ int vkms_crtc_init(struct drm_device *dev, struct drm_crtc *crtc, spin_lock_init(&vkms_out->lock); spin_lock_init(&vkms_out->composer_lock); - mutex_init(&vkms_out->enabled_lock); vkms_out->composer_workq = alloc_ordered_workqueue("vkms_composer", 0); if (!vkms_out->composer_workq) diff --git a/drivers/gpu/drm/vkms/vkms_drv.h b/drivers/gpu/drm/vkms/vkms_drv.h index c7ae6c2ba1df..8f5710debb1e 100644 --- a/drivers/gpu/drm/vkms/vkms_drv.h +++ b/drivers/gpu/drm/vkms/vkms_drv.h @@ -108,10 +108,8 @@ struct vkms_output { struct workqueue_struct *composer_workq; /* protects concurrent access to composer */ spinlock_t lock; - /* guarantees that if the composer is enabled, a job will be queued */ - struct mutex enabled_lock; - /* protected by @enabled_lock */ + /* protected by @lock */ bool composer_enabled; struct vkms_crtc_state *composer_state; diff --git a/drivers/hwmon/nct6775-core.c b/drivers/hwmon/nct6775-core.c index 02a71244fc3b..b5b81bd83bb1 100644 --- a/drivers/hwmon/nct6775-core.c +++ b/drivers/hwmon/nct6775-core.c @@ -1910,6 +1910,10 @@ static umode_t nct6775_in_is_visible(struct kobject *kobj, struct device *dev = kobj_to_dev(kobj); struct nct6775_data *data = dev_get_drvdata(dev); int in = index / 5; /* voltage index */ + int nr = index % 5; /* attribute index */ + + if (nr == 1 && data->ALARM_BITS[in] == -1) + return 0; if (!(data->have_in & BIT(in))) return 0; diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig index c6d1a345ea6d..9388823bb0bb 100644 --- a/drivers/i2c/Kconfig +++ b/drivers/i2c/Kconfig @@ -72,7 +72,7 @@ config I2C_MUX source "drivers/i2c/muxes/Kconfig" config I2C_ATR - tristate "I2C Address Translator (ATR) support" + tristate "I2C Address Translator (ATR) support" if COMPILE_TEST help Enable support for I2C Address Translator (ATR) chips. diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 169607e80331..6644eebedaf3 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -1384,10 +1384,10 @@ config I2C_ICY config I2C_MLXCPLD tristate "Mellanox I2C driver" - depends on X86_64 || ARM64 || COMPILE_TEST + depends on X86_64 || (ARM64 && ACPI) || COMPILE_TEST help This exposes the Mellanox platform I2C busses to the linux I2C layer - for X86 based systems. + for X86 and ARM64/ACPI based systems. Controller is implemented as CPLD logic. This driver can also be built as a module. If so, the module will be diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c index 2e5acfeb76c8..5a416b39b818 100644 --- a/drivers/i2c/busses/i2c-aspeed.c +++ b/drivers/i2c/busses/i2c-aspeed.c @@ -698,13 +698,16 @@ static int aspeed_i2c_master_xfer(struct i2c_adapter *adap, if (time_left == 0) { /* - * If timed out and bus is still busy in a multi master - * environment, attempt recovery at here. + * In a multi-master setup, if a timeout occurs, attempt + * recovery. But if the bus is idle, we still need to reset the + * i2c controller to clear the remaining interrupts. */ if (bus->multi_master && (readl(bus->base + ASPEED_I2C_CMD_REG) & ASPEED_I2CD_BUS_BUSY_STS)) aspeed_i2c_recover_bus(bus); + else + aspeed_i2c_reset(bus); /* * If timed out and the state is still pending, drop the pending diff --git a/drivers/i2c/busses/i2c-cadence.c b/drivers/i2c/busses/i2c-cadence.c index 9849f4502570..de3f58b60dce 100644 --- a/drivers/i2c/busses/i2c-cadence.c +++ b/drivers/i2c/busses/i2c-cadence.c @@ -182,6 +182,7 @@ enum cdns_i2c_slave_state { * @reset: Reset control for the device * @quirks: flag for broken hold bit usage in r1p10 * @ctrl_reg: Cached value of the control register. + * @rinfo: I2C GPIO recovery information * @ctrl_reg_diva_divb: value of fields DIV_A and DIV_B from CR register * @slave: Registered slave instance. * @dev_mode: I2C operating role(master/slave). diff --git a/drivers/i2c/busses/i2c-designware-common.c b/drivers/i2c/busses/i2c-designware-common.c index cdd8c67d9129..affcfb243f0f 100644 --- a/drivers/i2c/busses/i2c-designware-common.c +++ b/drivers/i2c/busses/i2c-designware-common.c @@ -441,8 +441,25 @@ err_release_lock: void __i2c_dw_disable(struct dw_i2c_dev *dev) { + unsigned int raw_intr_stats; + unsigned int enable; int timeout = 100; + bool abort_needed; unsigned int status; + int ret; + + regmap_read(dev->map, DW_IC_RAW_INTR_STAT, &raw_intr_stats); + regmap_read(dev->map, DW_IC_ENABLE, &enable); + + abort_needed = raw_intr_stats & DW_IC_INTR_MST_ON_HOLD; + if (abort_needed) { + regmap_write(dev->map, DW_IC_ENABLE, enable | DW_IC_ENABLE_ABORT); + ret = regmap_read_poll_timeout(dev->map, DW_IC_ENABLE, enable, + !(enable & DW_IC_ENABLE_ABORT), 10, + 100); + if (ret) + dev_err(dev->dev, "timeout while trying to abort current transfer\n"); + } do { __i2c_dw_disable_nowait(dev); diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h index cf4f684f5356..a7f6f3eafad7 100644 --- a/drivers/i2c/busses/i2c-designware-core.h +++ b/drivers/i2c/busses/i2c-designware-core.h @@ -98,6 +98,7 @@ #define DW_IC_INTR_START_DET BIT(10) #define DW_IC_INTR_GEN_CALL BIT(11) #define DW_IC_INTR_RESTART_DET BIT(12) +#define DW_IC_INTR_MST_ON_HOLD BIT(13) #define DW_IC_INTR_DEFAULT_MASK (DW_IC_INTR_RX_FULL | \ DW_IC_INTR_TX_ABRT | \ @@ -108,6 +109,8 @@ DW_IC_INTR_RX_UNDER | \ DW_IC_INTR_RD_REQ) +#define DW_IC_ENABLE_ABORT BIT(1) + #define DW_IC_STATUS_ACTIVITY BIT(0) #define DW_IC_STATUS_TFE BIT(2) #define DW_IC_STATUS_RFNE BIT(3) diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 73ae06432133..1d855258a45d 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -1754,6 +1754,7 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id) "SMBus I801 adapter at %04lx", priv->smba); err = i2c_add_adapter(&priv->adapter); if (err) { + platform_device_unregister(priv->tco_pdev); i801_acpi_remove(priv); return err; } diff --git a/drivers/i2c/busses/i2c-npcm7xx.c b/drivers/i2c/busses/i2c-npcm7xx.c index 495a8b5f6a2b..ae4bae63ad4f 100644 --- a/drivers/i2c/busses/i2c-npcm7xx.c +++ b/drivers/i2c/busses/i2c-npcm7xx.c @@ -694,6 +694,7 @@ static void npcm_i2c_callback(struct npcm_i2c *bus, { struct i2c_msg *msgs; int msgs_num; + bool do_complete = false; msgs = bus->msgs; msgs_num = bus->msgs_num; @@ -722,23 +723,17 @@ static void npcm_i2c_callback(struct npcm_i2c *bus, msgs[1].flags & I2C_M_RD) msgs[1].len = info; } - if (completion_done(&bus->cmd_complete) == false) - complete(&bus->cmd_complete); - break; - + do_complete = true; + break; case I2C_NACK_IND: /* MASTER transmit got a NACK before tx all bytes */ bus->cmd_err = -ENXIO; - if (bus->master_or_slave == I2C_MASTER) - complete(&bus->cmd_complete); - + do_complete = true; break; case I2C_BUS_ERR_IND: /* Bus error */ bus->cmd_err = -EAGAIN; - if (bus->master_or_slave == I2C_MASTER) - complete(&bus->cmd_complete); - + do_complete = true; break; case I2C_WAKE_UP_IND: /* I2C wake up */ @@ -752,6 +747,8 @@ static void npcm_i2c_callback(struct npcm_i2c *bus, if (bus->slave) bus->master_or_slave = I2C_SLAVE; #endif + if (do_complete) + complete(&bus->cmd_complete); } static u8 npcm_i2c_fifo_usage(struct npcm_i2c *bus) diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c index b3bb97762c85..71391b590ada 100644 --- a/drivers/i2c/busses/i2c-xiic.c +++ b/drivers/i2c/busses/i2c-xiic.c @@ -710,7 +710,7 @@ static irqreturn_t xiic_process(int irq, void *dev_id) * reset the IP instead of just flush fifos */ ret = xiic_reinit(i2c); - if (!ret) + if (ret < 0) dev_dbg(i2c->adap.dev.parent, "reinit failed\n"); if (i2c->rx_msg) { diff --git a/drivers/i2c/i2c-mux.c b/drivers/i2c/i2c-mux.c index 313904be5f3b..57ff09f18c37 100644 --- a/drivers/i2c/i2c-mux.c +++ b/drivers/i2c/i2c-mux.c @@ -341,7 +341,7 @@ int i2c_mux_add_adapter(struct i2c_mux_core *muxc, priv->adap.lock_ops = &i2c_parent_lock_ops; /* Sanity check on class */ - if (i2c_mux_parent_classes(parent) & class) + if (i2c_mux_parent_classes(parent) & class & ~I2C_CLASS_DEPRECATED) dev_err(&parent->dev, "Segment %d behind mux can't share classes with ancestors\n", chan_id); diff --git a/drivers/i2c/muxes/i2c-demux-pinctrl.c b/drivers/i2c/muxes/i2c-demux-pinctrl.c index a3a122fae71e..22f2280eab7f 100644 --- a/drivers/i2c/muxes/i2c-demux-pinctrl.c +++ b/drivers/i2c/muxes/i2c-demux-pinctrl.c @@ -243,6 +243,10 @@ static int i2c_demux_pinctrl_probe(struct platform_device *pdev) props[i].name = devm_kstrdup(&pdev->dev, "status", GFP_KERNEL); props[i].value = devm_kstrdup(&pdev->dev, "ok", GFP_KERNEL); + if (!props[i].name || !props[i].value) { + err = -ENOMEM; + goto err_rollback; + } props[i].length = 3; of_changeset_init(&priv->chan[i].chgset); diff --git a/drivers/i2c/muxes/i2c-mux-gpio.c b/drivers/i2c/muxes/i2c-mux-gpio.c index 5d5cbe0130cd..5ca03bd34c8d 100644 --- a/drivers/i2c/muxes/i2c-mux-gpio.c +++ b/drivers/i2c/muxes/i2c-mux-gpio.c @@ -105,8 +105,10 @@ static int i2c_mux_gpio_probe_fw(struct gpiomux *mux, } else if (is_acpi_node(child)) { rc = acpi_get_local_address(ACPI_HANDLE_FWNODE(child), values + i); - if (rc) + if (rc) { + fwnode_handle_put(child); return dev_err_probe(dev, rc, "Cannot get address\n"); + } } i++; diff --git a/drivers/irqchip/irq-xtensa-mx.c b/drivers/irqchip/irq-xtensa-mx.c index 8c581c985aa7..7f314e58f3ce 100644 --- a/drivers/irqchip/irq-xtensa-mx.c +++ b/drivers/irqchip/irq-xtensa-mx.c @@ -12,6 +12,7 @@ #include <linux/irqdomain.h> #include <linux/irq.h> #include <linux/irqchip.h> +#include <linux/irqchip/xtensa-mx.h> #include <linux/of.h> #include <asm/mxregs.h> diff --git a/drivers/md/dm-core.h b/drivers/md/dm-core.h index 0d93661f88d3..095b9b49aa82 100644 --- a/drivers/md/dm-core.h +++ b/drivers/md/dm-core.h @@ -214,6 +214,7 @@ struct dm_table { /* a list of devices used by this table */ struct list_head devices; + struct rw_semaphore devices_lock; /* events get handed up using this callback */ void (*event_fn)(void *data); diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c index f5ed729a8e0c..21ebb6c39394 100644 --- a/drivers/md/dm-ioctl.c +++ b/drivers/md/dm-ioctl.c @@ -1630,6 +1630,8 @@ static void retrieve_deps(struct dm_table *table, struct dm_dev_internal *dd; struct dm_target_deps *deps; + down_read(&table->devices_lock); + deps = get_result_buffer(param, param_size, &len); /* @@ -1644,7 +1646,7 @@ static void retrieve_deps(struct dm_table *table, needed = struct_size(deps, dev, count); if (len < needed) { param->flags |= DM_BUFFER_FULL_FLAG; - return; + goto out; } /* @@ -1656,6 +1658,9 @@ static void retrieve_deps(struct dm_table *table, deps->dev[count++] = huge_encode_dev(dd->dm_dev->bdev->bd_dev); param->data_size = param->data_start + needed; + +out: + up_read(&table->devices_lock); } static int table_deps(struct file *filp, struct dm_ioctl *param, size_t param_size) diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index 7d208b2b1a19..37b48f63ae6a 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c @@ -135,6 +135,7 @@ int dm_table_create(struct dm_table **result, blk_mode_t mode, return -ENOMEM; INIT_LIST_HEAD(&t->devices); + init_rwsem(&t->devices_lock); if (!num_targets) num_targets = KEYS_PER_NODE; @@ -359,16 +360,20 @@ int __ref dm_get_device(struct dm_target *ti, const char *path, blk_mode_t mode, if (dev == disk_devt(t->md->disk)) return -EINVAL; + down_write(&t->devices_lock); + dd = find_device(&t->devices, dev); if (!dd) { dd = kmalloc(sizeof(*dd), GFP_KERNEL); - if (!dd) - return -ENOMEM; + if (!dd) { + r = -ENOMEM; + goto unlock_ret_r; + } r = dm_get_table_device(t->md, dev, mode, &dd->dm_dev); if (r) { kfree(dd); - return r; + goto unlock_ret_r; } refcount_set(&dd->count, 1); @@ -378,12 +383,17 @@ int __ref dm_get_device(struct dm_target *ti, const char *path, blk_mode_t mode, } else if (dd->dm_dev->mode != (mode | dd->dm_dev->mode)) { r = upgrade_mode(dd, mode, t->md); if (r) - return r; + goto unlock_ret_r; } refcount_inc(&dd->count); out: + up_write(&t->devices_lock); *result = dd->dm_dev; return 0; + +unlock_ret_r: + up_write(&t->devices_lock); + return r; } EXPORT_SYMBOL(dm_get_device); @@ -419,9 +429,12 @@ static int dm_set_device_limits(struct dm_target *ti, struct dm_dev *dev, void dm_put_device(struct dm_target *ti, struct dm_dev *d) { int found = 0; - struct list_head *devices = &ti->table->devices; + struct dm_table *t = ti->table; + struct list_head *devices = &t->devices; struct dm_dev_internal *dd; + down_write(&t->devices_lock); + list_for_each_entry(dd, devices, list) { if (dd->dm_dev == d) { found = 1; @@ -430,14 +443,17 @@ void dm_put_device(struct dm_target *ti, struct dm_dev *d) } if (!found) { DMERR("%s: device %s not in table devices list", - dm_device_name(ti->table->md), d->name); - return; + dm_device_name(t->md), d->name); + goto unlock_ret; } if (refcount_dec_and_test(&dd->count)) { - dm_put_table_device(ti->table->md, d); + dm_put_table_device(t->md, d); list_del(&dd->list); kfree(dd); } + +unlock_ret: + up_write(&t->devices_lock); } EXPORT_SYMBOL(dm_put_device); diff --git a/drivers/md/dm.c b/drivers/md/dm.c index f0f118ab20fa..64a1f306c96c 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -715,24 +715,6 @@ static void dm_put_live_table_fast(struct mapped_device *md) __releases(RCU) rcu_read_unlock(); } -static inline struct dm_table *dm_get_live_table_bio(struct mapped_device *md, - int *srcu_idx, blk_opf_t bio_opf) -{ - if (bio_opf & REQ_NOWAIT) - return dm_get_live_table_fast(md); - else - return dm_get_live_table(md, srcu_idx); -} - -static inline void dm_put_live_table_bio(struct mapped_device *md, int srcu_idx, - blk_opf_t bio_opf) -{ - if (bio_opf & REQ_NOWAIT) - dm_put_live_table_fast(md); - else - dm_put_live_table(md, srcu_idx); -} - static char *_dm_claim_ptr = "I belong to device-mapper"; /* @@ -1833,9 +1815,8 @@ static void dm_submit_bio(struct bio *bio) struct mapped_device *md = bio->bi_bdev->bd_disk->private_data; int srcu_idx; struct dm_table *map; - blk_opf_t bio_opf = bio->bi_opf; - map = dm_get_live_table_bio(md, &srcu_idx, bio_opf); + map = dm_get_live_table(md, &srcu_idx); /* If suspended, or map not yet available, queue this IO for later */ if (unlikely(test_bit(DMF_BLOCK_IO_FOR_SUSPEND, &md->flags)) || @@ -1851,7 +1832,7 @@ static void dm_submit_bio(struct bio *bio) dm_split_and_process_bio(md, map, bio); out: - dm_put_live_table_bio(md, srcu_idx, bio_opf); + dm_put_live_table(md, srcu_idx); } static bool dm_poll_dm_io(struct dm_io *io, struct io_comp_batch *iob, diff --git a/drivers/md/md.c b/drivers/md/md.c index 0fe7ab6e8ab9..a104a025084d 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -798,14 +798,14 @@ void mddev_unlock(struct mddev *mddev) } else mutex_unlock(&mddev->reconfig_mutex); + md_wakeup_thread(mddev->thread); + wake_up(&mddev->sb_wait); + list_for_each_entry_safe(rdev, tmp, &delete, same_set) { list_del_init(&rdev->same_set); kobject_del(&rdev->kobj); export_rdev(rdev, mddev); } - - md_wakeup_thread(mddev->thread); - wake_up(&mddev->sb_wait); } EXPORT_SYMBOL_GPL(mddev_unlock); @@ -2452,7 +2452,8 @@ static void export_rdev(struct md_rdev *rdev, struct mddev *mddev) if (test_bit(AutoDetected, &rdev->flags)) md_autodetect_dev(rdev->bdev->bd_dev); #endif - blkdev_put(rdev->bdev, mddev->external ? &claim_rdev : rdev); + blkdev_put(rdev->bdev, + test_bit(Holder, &rdev->flags) ? rdev : &claim_rdev); rdev->bdev = NULL; kobject_put(&rdev->kobj); } @@ -3632,6 +3633,7 @@ EXPORT_SYMBOL_GPL(md_rdev_init); static struct md_rdev *md_import_device(dev_t newdev, int super_format, int super_minor) { struct md_rdev *rdev; + struct md_rdev *holder; sector_t size; int err; @@ -3646,8 +3648,15 @@ static struct md_rdev *md_import_device(dev_t newdev, int super_format, int supe if (err) goto out_clear_rdev; + if (super_format == -2) { + holder = &claim_rdev; + } else { + holder = rdev; + set_bit(Holder, &rdev->flags); + } + rdev->bdev = blkdev_get_by_dev(newdev, BLK_OPEN_READ | BLK_OPEN_WRITE, - super_format == -2 ? &claim_rdev : rdev, NULL); + holder, NULL); if (IS_ERR(rdev->bdev)) { pr_warn("md: could not open device unknown-block(%u,%u).\n", MAJOR(newdev), MINOR(newdev)); @@ -3684,7 +3693,7 @@ static struct md_rdev *md_import_device(dev_t newdev, int super_format, int supe return rdev; out_blkdev_put: - blkdev_put(rdev->bdev, super_format == -2 ? &claim_rdev : rdev); + blkdev_put(rdev->bdev, holder); out_clear_rdev: md_rdev_clear(rdev); out_free_rdev: @@ -8256,7 +8265,7 @@ static void *md_seq_next(struct seq_file *seq, void *v, loff_t *pos) spin_unlock(&all_mddevs_lock); if (to_put) - mddev_put(mddev); + mddev_put(to_put); return next_mddev; } diff --git a/drivers/md/md.h b/drivers/md/md.h index 9bcb77bca963..7c9c13abd7ca 100644 --- a/drivers/md/md.h +++ b/drivers/md/md.h @@ -211,6 +211,9 @@ enum flag_bits { * check if there is collision between raid1 * serial bios. */ + Holder, /* rdev is used as holder while opening + * underlying disk exclusively. + */ }; static inline int is_badblock(struct md_rdev *rdev, sector_t s, int sectors, diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 4b30a1742162..2aabac773fe7 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -1837,12 +1837,11 @@ static int raid1_remove_disk(struct mddev *mddev, struct md_rdev *rdev) struct r1conf *conf = mddev->private; int err = 0; int number = rdev->raid_disk; + struct raid1_info *p = conf->mirrors + number; if (unlikely(number >= conf->raid_disks)) goto abort; - struct raid1_info *p = conf->mirrors + number; - if (rdev != p->rdev) p = conf->mirrors + conf->raid_disks + number; diff --git a/drivers/media/common/videobuf2/frame_vector.c b/drivers/media/common/videobuf2/frame_vector.c index 0f430ddc1f67..fd87747be9b1 100644 --- a/drivers/media/common/videobuf2/frame_vector.c +++ b/drivers/media/common/videobuf2/frame_vector.c @@ -31,6 +31,10 @@ * different type underlying the specified range of virtual addresses. * When the function isn't able to map a single page, it returns error. * + * Note that get_vaddr_frames() cannot follow VM_IO mappings. It used + * to be able to do that, but that could (racily) return non-refcounted + * pfns. + * * This function takes care of grabbing mmap_lock as necessary. */ int get_vaddr_frames(unsigned long start, unsigned int nr_frames, bool write, @@ -59,8 +63,6 @@ int get_vaddr_frames(unsigned long start, unsigned int nr_frames, bool write, if (likely(ret > 0)) return ret; - /* This used to (racily) return non-refcounted pfns. Let people know */ - WARN_ONCE(1, "get_vaddr_frames() cannot follow VM_IO mapping"); vec->nr_frames = 0; return ret ? ret : -EFAULT; } diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c index a1136fdfbed2..ec53abe2e84e 100644 --- a/drivers/media/i2c/imx219.c +++ b/drivers/media/i2c/imx219.c @@ -691,12 +691,12 @@ static int imx219_init_cfg(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *format; struct v4l2_rect *crop; - /* Initialize try_fmt */ + /* Initialize the format. */ format = v4l2_subdev_get_pad_format(sd, state, 0); imx219_update_pad_format(imx219, &supported_modes[0], format, MEDIA_BUS_FMT_SRGGB10_1X10); - /* Initialize crop rectangle. */ + /* Initialize the crop rectangle. */ crop = v4l2_subdev_get_pad_crop(sd, state, 0); crop->top = IMX219_PIXEL_ARRAY_TOP; crop->left = IMX219_PIXEL_ARRAY_LEFT; @@ -750,6 +750,7 @@ static int imx219_set_pad_format(struct v4l2_subdev *sd, const struct imx219_mode *mode; int exposure_max, exposure_def, hblank; struct v4l2_mbus_framefmt *format; + struct v4l2_rect *crop; mode = v4l2_find_nearest_size(supported_modes, ARRAY_SIZE(supported_modes), @@ -757,10 +758,12 @@ static int imx219_set_pad_format(struct v4l2_subdev *sd, fmt->format.width, fmt->format.height); imx219_update_pad_format(imx219, mode, &fmt->format, fmt->format.code); + format = v4l2_subdev_get_pad_format(sd, sd_state, 0); + crop = v4l2_subdev_get_pad_crop(sd, sd_state, 0); - if (imx219->mode == mode && format->code == fmt->format.code) - return 0; + *format = fmt->format; + *crop = mode->crop; if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { imx219->mode = mode; @@ -788,8 +791,6 @@ static int imx219_set_pad_format(struct v4l2_subdev *sd, hblank); } - *format = fmt->format; - return 0; } diff --git a/drivers/media/i2c/max9286.c b/drivers/media/i2c/max9286.c index 20e7c7cf5eeb..be84ff1e2b17 100644 --- a/drivers/media/i2c/max9286.c +++ b/drivers/media/i2c/max9286.c @@ -1110,7 +1110,6 @@ err_async: static void max9286_v4l2_unregister(struct max9286_priv *priv) { - fwnode_handle_put(priv->sd.fwnode); v4l2_ctrl_handler_free(&priv->ctrls); v4l2_async_unregister_subdev(&priv->sd); max9286_v4l2_notifier_unregister(priv); diff --git a/drivers/media/i2c/rdacm21.c b/drivers/media/i2c/rdacm21.c index a36a709243fd..3e22df36354f 100644 --- a/drivers/media/i2c/rdacm21.c +++ b/drivers/media/i2c/rdacm21.c @@ -608,7 +608,6 @@ static void rdacm21_remove(struct i2c_client *client) v4l2_async_unregister_subdev(&dev->sd); v4l2_ctrl_handler_free(&dev->ctrls); i2c_unregister_device(dev->isp); - fwnode_handle_put(dev->sd.fwnode); } static const struct of_device_id rdacm21_of_ids[] = { diff --git a/drivers/media/pci/bt8xx/bttv-risc.c b/drivers/media/pci/bt8xx/bttv-risc.c index 436baf6c8b08..241a696e374a 100644 --- a/drivers/media/pci/bt8xx/bttv-risc.c +++ b/drivers/media/pci/bt8xx/bttv-risc.c @@ -68,9 +68,7 @@ bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc, sg = sglist; for (line = 0; line < store_lines; line++) { if ((line >= (store_lines - VCR_HACK_LINES)) && - (btv->opt_vcr_hack || - (V4L2_FIELD_HAS_BOTH(btv->field) || - btv->field == V4L2_FIELD_ALTERNATE))) + btv->opt_vcr_hack) continue; while (offset && offset >= sg_dma_len(sg)) { offset -= sg_dma_len(sg); diff --git a/drivers/media/pci/intel/ivsc/Kconfig b/drivers/media/pci/intel/ivsc/Kconfig index 1ef1c4e3750d..212753450576 100644 --- a/drivers/media/pci/intel/ivsc/Kconfig +++ b/drivers/media/pci/intel/ivsc/Kconfig @@ -3,7 +3,10 @@ config INTEL_VSC tristate "Intel Visual Sensing Controller" - depends on INTEL_MEI && ACPI + depends on INTEL_MEI && ACPI && VIDEO_DEV + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API + select V4L2_ASYNC help This adds support for Intel Visual Sensing Controller (IVSC). diff --git a/drivers/media/platform/marvell/Kconfig b/drivers/media/platform/marvell/Kconfig index ec1a16734a28..d6499ffe30e8 100644 --- a/drivers/media/platform/marvell/Kconfig +++ b/drivers/media/platform/marvell/Kconfig @@ -7,7 +7,7 @@ config VIDEO_CAFE_CCIC depends on V4L_PLATFORM_DRIVERS depends on PCI && I2C && VIDEO_DEV depends on COMMON_CLK - select VIDEO_OV7670 + select VIDEO_OV7670 if MEDIA_SUBDRV_AUTOSELECT && VIDEO_CAMERA_SENSOR select VIDEOBUF2_VMALLOC select VIDEOBUF2_DMA_CONTIG select VIDEOBUF2_DMA_SG @@ -22,7 +22,7 @@ config VIDEO_MMP_CAMERA depends on I2C && VIDEO_DEV depends on ARCH_MMP || COMPILE_TEST depends on COMMON_CLK - select VIDEO_OV7670 + select VIDEO_OV7670 if MEDIA_SUBDRV_AUTOSELECT && VIDEO_CAMERA_SENSOR select I2C_GPIO select VIDEOBUF2_VMALLOC select VIDEOBUF2_DMA_CONTIG diff --git a/drivers/media/platform/nxp/imx-mipi-csis.c b/drivers/media/platform/nxp/imx-mipi-csis.c index 16f19a640130..5f93712bf485 100644 --- a/drivers/media/platform/nxp/imx-mipi-csis.c +++ b/drivers/media/platform/nxp/imx-mipi-csis.c @@ -1490,7 +1490,6 @@ err_cleanup: v4l2_async_unregister_subdev(&csis->sd); err_disable_clock: mipi_csis_clk_disable(csis); - fwnode_handle_put(csis->sd.fwnode); return ret; } @@ -1510,7 +1509,6 @@ static void mipi_csis_remove(struct platform_device *pdev) mipi_csis_clk_disable(csis); v4l2_subdev_cleanup(&csis->sd); media_entity_cleanup(&csis->sd.entity); - fwnode_handle_put(csis->sd.fwnode); pm_runtime_set_suspended(&pdev->dev); } diff --git a/drivers/media/platform/via/Kconfig b/drivers/media/platform/via/Kconfig index 8926eb0803b2..6e603c038248 100644 --- a/drivers/media/platform/via/Kconfig +++ b/drivers/media/platform/via/Kconfig @@ -7,7 +7,7 @@ config VIDEO_VIA_CAMERA depends on V4L_PLATFORM_DRIVERS depends on FB_VIA && VIDEO_DEV select VIDEOBUF2_DMA_SG - select VIDEO_OV7670 + select VIDEO_OV7670 if VIDEO_CAMERA_SENSOR help Driver support for the integrated camera controller in VIA Chrome9 chipsets. Currently only tested on OLPC xo-1.5 systems diff --git a/drivers/media/usb/em28xx/Kconfig b/drivers/media/usb/em28xx/Kconfig index b3c472b8c5a9..cb61fd6cc6c6 100644 --- a/drivers/media/usb/em28xx/Kconfig +++ b/drivers/media/usb/em28xx/Kconfig @@ -12,8 +12,8 @@ config VIDEO_EM28XX_V4L2 select VIDEO_SAA711X if MEDIA_SUBDRV_AUTOSELECT select VIDEO_TVP5150 if MEDIA_SUBDRV_AUTOSELECT select VIDEO_MSP3400 if MEDIA_SUBDRV_AUTOSELECT - select VIDEO_MT9V011 if MEDIA_SUBDRV_AUTOSELECT && MEDIA_CAMERA_SUPPORT - select VIDEO_OV2640 if MEDIA_SUBDRV_AUTOSELECT && MEDIA_CAMERA_SUPPORT + select VIDEO_MT9V011 if MEDIA_SUBDRV_AUTOSELECT && VIDEO_CAMERA_SENSOR + select VIDEO_OV2640 if MEDIA_SUBDRV_AUTOSELECT && VIDEO_CAMERA_SENSOR help This is a video4linux driver for Empia 28xx based TV cards. diff --git a/drivers/media/usb/go7007/Kconfig b/drivers/media/usb/go7007/Kconfig index 4ff79940ad8d..b2a15d9fb1f3 100644 --- a/drivers/media/usb/go7007/Kconfig +++ b/drivers/media/usb/go7007/Kconfig @@ -12,8 +12,8 @@ config VIDEO_GO7007 select VIDEO_TW2804 if MEDIA_SUBDRV_AUTOSELECT select VIDEO_TW9903 if MEDIA_SUBDRV_AUTOSELECT select VIDEO_TW9906 if MEDIA_SUBDRV_AUTOSELECT - select VIDEO_OV7640 if MEDIA_SUBDRV_AUTOSELECT && MEDIA_CAMERA_SUPPORT select VIDEO_UDA1342 if MEDIA_SUBDRV_AUTOSELECT + select VIDEO_OV7640 if MEDIA_SUBDRV_AUTOSELECT && VIDEO_CAMERA_SENSOR help This is a video4linux driver for the WIS GO7007 MPEG encoder chip. diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c index 5e9d3da862dd..e59a463c2761 100644 --- a/drivers/media/usb/uvc/uvc_ctrl.c +++ b/drivers/media/usb/uvc/uvc_ctrl.c @@ -1402,6 +1402,9 @@ int uvc_query_v4l2_menu(struct uvc_video_chain *chain, query_menu->id = id; query_menu->index = index; + if (index >= BITS_PER_TYPE(mapping->menu_mask)) + return -EINVAL; + ret = mutex_lock_interruptible(&chain->ctrl_mutex); if (ret < 0) return -ERESTARTSYS; diff --git a/drivers/memory/atmel-ebi.c b/drivers/memory/atmel-ebi.c index 635966d705cb..e8bb5f37f5cb 100644 --- a/drivers/memory/atmel-ebi.c +++ b/drivers/memory/atmel-ebi.c @@ -12,7 +12,10 @@ #include <linux/mfd/syscon/atmel-matrix.h> #include <linux/mfd/syscon/atmel-smc.h> #include <linux/init.h> -#include <linux/of_device.h> +#include <linux/of.h> +#include <linux/of_platform.h> +#include <linux/platform_device.h> +#include <linux/property.h> #include <linux/regmap.h> #include <soc/at91/atmel-sfr.h> @@ -30,7 +33,7 @@ struct atmel_ebi_dev { struct atmel_ebi *ebi; u32 mode; int numcs; - struct atmel_ebi_dev_config configs[]; + struct atmel_ebi_dev_config configs[] __counted_by(numcs); }; struct atmel_ebi_caps { @@ -515,16 +518,11 @@ static int atmel_ebi_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct device_node *child, *np = dev->of_node, *smc_np; - const struct of_device_id *match; struct atmel_ebi *ebi; int ret, reg_cells; struct clk *clk; u32 val; - match = of_match_device(atmel_ebi_id_table, dev); - if (!match || !match->data) - return -EINVAL; - ebi = devm_kzalloc(dev, sizeof(*ebi), GFP_KERNEL); if (!ebi) return -ENOMEM; @@ -532,7 +530,9 @@ static int atmel_ebi_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ebi); INIT_LIST_HEAD(&ebi->devs); - ebi->caps = match->data; + ebi->caps = device_get_match_data(dev); + if (!ebi->caps) + return -EINVAL; ebi->dev = dev; clk = devm_clk_get(dev, NULL); diff --git a/drivers/memory/brcmstb_memc.c b/drivers/memory/brcmstb_memc.c index 233a53f5bce1..a6ea51996522 100644 --- a/drivers/memory/brcmstb_memc.c +++ b/drivers/memory/brcmstb_memc.c @@ -8,8 +8,9 @@ #include <linux/io.h> #include <linux/kernel.h> #include <linux/module.h> -#include <linux/of_device.h> +#include <linux/of.h> #include <linux/platform_device.h> +#include <linux/property.h> #define REG_MEMC_CNTRLR_CONFIG 0x00 #define CNTRLR_CONFIG_LPDDR4_SHIFT 5 @@ -121,12 +122,9 @@ static struct attribute_group dev_attr_group = { .attrs = dev_attrs, }; -static const struct of_device_id brcmstb_memc_of_match[]; - static int brcmstb_memc_probe(struct platform_device *pdev) { const struct brcmstb_memc_data *memc_data; - const struct of_device_id *of_id; struct device *dev = &pdev->dev; struct brcmstb_memc *memc; int ret; @@ -137,8 +135,7 @@ static int brcmstb_memc_probe(struct platform_device *pdev) dev_set_drvdata(dev, memc); - of_id = of_match_device(brcmstb_memc_of_match, dev); - memc_data = of_id->data; + memc_data = device_get_match_data(dev); memc->srpd_offset = memc_data->srpd_offset; memc->ddr_ctrl = devm_platform_ioremap_resource(pdev, 0); diff --git a/drivers/memory/fsl-corenet-cf.c b/drivers/memory/fsl-corenet-cf.c index 7fc9f57ae278..8096c4f33303 100644 --- a/drivers/memory/fsl-corenet-cf.c +++ b/drivers/memory/fsl-corenet-cf.c @@ -10,10 +10,8 @@ #include <linux/irq.h> #include <linux/module.h> #include <linux/of.h> -#include <linux/of_address.h> -#include <linux/of_device.h> -#include <linux/of_irq.h> #include <linux/platform_device.h> +#include <linux/property.h> enum ccf_version { CCF1, @@ -172,14 +170,9 @@ out: static int ccf_probe(struct platform_device *pdev) { struct ccf_private *ccf; - const struct of_device_id *match; u32 errinten; int ret, irq; - match = of_match_device(ccf_matches, &pdev->dev); - if (WARN_ON(!match)) - return -ENODEV; - ccf = devm_kzalloc(&pdev->dev, sizeof(*ccf), GFP_KERNEL); if (!ccf) return -ENOMEM; @@ -189,7 +182,7 @@ static int ccf_probe(struct platform_device *pdev) return PTR_ERR(ccf->regs); ccf->dev = &pdev->dev; - ccf->info = match->data; + ccf->info = device_get_match_data(&pdev->dev); ccf->err_regs = ccf->regs + ccf->info->err_reg_offs; if (ccf->info->has_brr) { diff --git a/drivers/memory/tegra/tegra234.c b/drivers/memory/tegra/tegra234.c index 9e5b5dbd9c8d..abff87f917cb 100644 --- a/drivers/memory/tegra/tegra234.c +++ b/drivers/memory/tegra/tegra234.c @@ -450,6 +450,18 @@ static const struct tegra_mc_client tegra234_mc_clients[] = { }, }, }, { + .id = TEGRA234_MEMORY_CLIENT_VIW, + .name = "viw", + .bpmp_id = TEGRA_ICC_BPMP_VI, + .type = TEGRA_ICC_ISO_VI, + .sid = TEGRA234_SID_ISO_VI, + .regs = { + .sid = { + .override = 0x390, + .security = 0x394, + }, + }, + }, { .id = TEGRA234_MEMORY_CLIENT_NVDECSRD, .name = "nvdecsrd", .bpmp_id = TEGRA_ICC_BPMP_NVDEC, @@ -622,6 +634,30 @@ static const struct tegra_mc_client tegra234_mc_clients[] = { }, }, }, { + .id = TEGRA234_MEMORY_CLIENT_VIFALR, + .name = "vifalr", + .bpmp_id = TEGRA_ICC_BPMP_VIFAL, + .type = TEGRA_ICC_ISO_VIFAL, + .sid = TEGRA234_SID_ISO_VIFALC, + .regs = { + .sid = { + .override = 0x5e0, + .security = 0x5e4, + }, + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_VIFALW, + .name = "vifalw", + .bpmp_id = TEGRA_ICC_BPMP_VIFAL, + .type = TEGRA_ICC_ISO_VIFAL, + .sid = TEGRA234_SID_ISO_VIFALC, + .regs = { + .sid = { + .override = 0x5e8, + .security = 0x5ec, + }, + }, + }, { .id = TEGRA234_MEMORY_CLIENT_DLA0RDA, .name = "dla0rda", .sid = TEGRA234_SID_NVDLA0, @@ -702,6 +738,30 @@ static const struct tegra_mc_client tegra234_mc_clients[] = { }, }, }, { + .id = TEGRA234_MEMORY_CLIENT_RCER, + .name = "rcer", + .bpmp_id = TEGRA_ICC_BPMP_RCE, + .type = TEGRA_ICC_NISO, + .sid = TEGRA234_SID_RCE, + .regs = { + .sid = { + .override = 0x690, + .security = 0x694, + }, + }, + }, { + .id = TEGRA234_MEMORY_CLIENT_RCEW, + .name = "rcew", + .bpmp_id = TEGRA_ICC_BPMP_RCE, + .type = TEGRA_ICC_NISO, + .sid = TEGRA234_SID_RCE, + .regs = { + .sid = { + .override = 0x698, + .security = 0x69c, + }, + }, + }, { .id = TEGRA234_MEMORY_CLIENT_PCIE0R, .name = "pcie0r", .bpmp_id = TEGRA_ICC_BPMP_PCIE_0, @@ -986,6 +1046,10 @@ static int tegra234_mc_icc_set(struct icc_node *src, struct icc_node *dst) msg.rx.data = &bwmgr_resp; msg.rx.size = sizeof(bwmgr_resp); + if (pclient->bpmp_id >= TEGRA_ICC_BPMP_CPU_CLUSTER0 && + pclient->bpmp_id <= TEGRA_ICC_BPMP_CPU_CLUSTER2) + msg.flags = TEGRA_BPMP_MESSAGE_RESET; + ret = tegra_bpmp_transfer(mc->bpmp, &msg); if (ret < 0) { dev_err(mc->dev, "BPMP transfer failed: %d\n", ret); diff --git a/drivers/mfd/cs42l43.c b/drivers/mfd/cs42l43.c index 37b23e9bae82..7b6d07cbe6fc 100644 --- a/drivers/mfd/cs42l43.c +++ b/drivers/mfd/cs42l43.c @@ -1178,8 +1178,8 @@ err: } EXPORT_NS_GPL_DEV_PM_OPS(cs42l43_pm_ops, MFD_CS42L43) = { - SET_SYSTEM_SLEEP_PM_OPS(cs42l43_suspend, cs42l43_resume) - SET_RUNTIME_PM_OPS(cs42l43_runtime_suspend, cs42l43_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(cs42l43_suspend, cs42l43_resume) + RUNTIME_PM_OPS(cs42l43_runtime_suspend, cs42l43_runtime_resume, NULL) }; MODULE_DESCRIPTION("CS42L43 Core Driver"); diff --git a/drivers/misc/cardreader/rts5227.c b/drivers/misc/cardreader/rts5227.c index 3dae5e3a1697..cd512284bfb3 100644 --- a/drivers/misc/cardreader/rts5227.c +++ b/drivers/misc/cardreader/rts5227.c @@ -83,63 +83,20 @@ static void rts5227_fetch_vendor_settings(struct rtsx_pcr *pcr) static void rts5227_init_from_cfg(struct rtsx_pcr *pcr) { - struct pci_dev *pdev = pcr->pci; - int l1ss; - u32 lval; struct rtsx_cr_option *option = &pcr->option; - l1ss = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_L1SS); - if (!l1ss) - return; - - pci_read_config_dword(pdev, l1ss + PCI_L1SS_CTL1, &lval); - if (CHK_PCI_PID(pcr, 0x522A)) { - if (0 == (lval & 0x0F)) - rtsx_pci_enable_oobs_polling(pcr); - else + if (rtsx_check_dev_flag(pcr, ASPM_L1_1_EN | ASPM_L1_2_EN + | PM_L1_1_EN | PM_L1_2_EN)) rtsx_pci_disable_oobs_polling(pcr); + else + rtsx_pci_enable_oobs_polling(pcr); } - if (lval & PCI_L1SS_CTL1_ASPM_L1_1) - rtsx_set_dev_flag(pcr, ASPM_L1_1_EN); - else - rtsx_clear_dev_flag(pcr, ASPM_L1_1_EN); - - if (lval & PCI_L1SS_CTL1_ASPM_L1_2) - rtsx_set_dev_flag(pcr, ASPM_L1_2_EN); - else - rtsx_clear_dev_flag(pcr, ASPM_L1_2_EN); - - if (lval & PCI_L1SS_CTL1_PCIPM_L1_1) - rtsx_set_dev_flag(pcr, PM_L1_1_EN); - else - rtsx_clear_dev_flag(pcr, PM_L1_1_EN); - - if (lval & PCI_L1SS_CTL1_PCIPM_L1_2) - rtsx_set_dev_flag(pcr, PM_L1_2_EN); - else - rtsx_clear_dev_flag(pcr, PM_L1_2_EN); - if (option->ltr_en) { - u16 val; - - pcie_capability_read_word(pcr->pci, PCI_EXP_DEVCTL2, &val); - if (val & PCI_EXP_DEVCTL2_LTR_EN) { - option->ltr_enabled = true; - option->ltr_active = true; + if (option->ltr_enabled) rtsx_set_ltr_latency(pcr, option->ltr_active_latency); - } else { - option->ltr_enabled = false; - } } - - if (rtsx_check_dev_flag(pcr, ASPM_L1_1_EN | ASPM_L1_2_EN - | PM_L1_1_EN | PM_L1_2_EN)) - option->force_clkreq_0 = false; - else - option->force_clkreq_0 = true; - } static int rts5227_extra_init_hw(struct rtsx_pcr *pcr) @@ -195,7 +152,7 @@ static int rts5227_extra_init_hw(struct rtsx_pcr *pcr) } } - if (option->force_clkreq_0 && pcr->aspm_mode == ASPM_MODE_CFG) + if (option->force_clkreq_0) rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, PETXCFG, FORCE_CLKREQ_DELINK_MASK, FORCE_CLKREQ_LOW); else diff --git a/drivers/misc/cardreader/rts5228.c b/drivers/misc/cardreader/rts5228.c index f4ab09439da7..0c7f10bcf6f1 100644 --- a/drivers/misc/cardreader/rts5228.c +++ b/drivers/misc/cardreader/rts5228.c @@ -386,59 +386,25 @@ static void rts5228_process_ocp(struct rtsx_pcr *pcr) static void rts5228_init_from_cfg(struct rtsx_pcr *pcr) { - struct pci_dev *pdev = pcr->pci; - int l1ss; - u32 lval; struct rtsx_cr_option *option = &pcr->option; - l1ss = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_L1SS); - if (!l1ss) - return; - - pci_read_config_dword(pdev, l1ss + PCI_L1SS_CTL1, &lval); - - if (0 == (lval & 0x0F)) - rtsx_pci_enable_oobs_polling(pcr); - else + if (rtsx_check_dev_flag(pcr, ASPM_L1_1_EN | ASPM_L1_2_EN + | PM_L1_1_EN | PM_L1_2_EN)) rtsx_pci_disable_oobs_polling(pcr); - - if (lval & PCI_L1SS_CTL1_ASPM_L1_1) - rtsx_set_dev_flag(pcr, ASPM_L1_1_EN); - else - rtsx_clear_dev_flag(pcr, ASPM_L1_1_EN); - - if (lval & PCI_L1SS_CTL1_ASPM_L1_2) - rtsx_set_dev_flag(pcr, ASPM_L1_2_EN); - else - rtsx_clear_dev_flag(pcr, ASPM_L1_2_EN); - - if (lval & PCI_L1SS_CTL1_PCIPM_L1_1) - rtsx_set_dev_flag(pcr, PM_L1_1_EN); else - rtsx_clear_dev_flag(pcr, PM_L1_1_EN); - - if (lval & PCI_L1SS_CTL1_PCIPM_L1_2) - rtsx_set_dev_flag(pcr, PM_L1_2_EN); - else - rtsx_clear_dev_flag(pcr, PM_L1_2_EN); + rtsx_pci_enable_oobs_polling(pcr); rtsx_pci_write_register(pcr, ASPM_FORCE_CTL, 0xFF, 0); - if (option->ltr_en) { - u16 val; - pcie_capability_read_word(pcr->pci, PCI_EXP_DEVCTL2, &val); - if (val & PCI_EXP_DEVCTL2_LTR_EN) { - option->ltr_enabled = true; - option->ltr_active = true; + if (option->ltr_en) { + if (option->ltr_enabled) rtsx_set_ltr_latency(pcr, option->ltr_active_latency); - } else { - option->ltr_enabled = false; - } } } static int rts5228_extra_init_hw(struct rtsx_pcr *pcr) { + struct rtsx_cr_option *option = &pcr->option; rtsx_pci_write_register(pcr, RTS5228_AUTOLOAD_CFG1, CD_RESUME_EN_MASK, CD_RESUME_EN_MASK); @@ -469,6 +435,17 @@ static int rts5228_extra_init_hw(struct rtsx_pcr *pcr) else rtsx_pci_write_register(pcr, PETXCFG, 0x30, 0x00); + /* + * If u_force_clkreq_0 is enabled, CLKREQ# PIN will be forced + * to drive low, and we forcibly request clock. + */ + if (option->force_clkreq_0) + rtsx_pci_write_register(pcr, PETXCFG, + FORCE_CLKREQ_DELINK_MASK, FORCE_CLKREQ_LOW); + else + rtsx_pci_write_register(pcr, PETXCFG, + FORCE_CLKREQ_DELINK_MASK, FORCE_CLKREQ_HIGH); + rtsx_pci_write_register(pcr, PWD_SUSPEND_EN, 0xFF, 0xFB); if (pcr->rtd3_en) { diff --git a/drivers/misc/cardreader/rts5249.c b/drivers/misc/cardreader/rts5249.c index 47ab72a43256..6c81040e18be 100644 --- a/drivers/misc/cardreader/rts5249.c +++ b/drivers/misc/cardreader/rts5249.c @@ -86,64 +86,22 @@ static void rtsx_base_fetch_vendor_settings(struct rtsx_pcr *pcr) static void rts5249_init_from_cfg(struct rtsx_pcr *pcr) { - struct pci_dev *pdev = pcr->pci; - int l1ss; struct rtsx_cr_option *option = &(pcr->option); - u32 lval; - - l1ss = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_L1SS); - if (!l1ss) - return; - - pci_read_config_dword(pdev, l1ss + PCI_L1SS_CTL1, &lval); if (CHK_PCI_PID(pcr, PID_524A) || CHK_PCI_PID(pcr, PID_525A)) { - if (0 == (lval & 0x0F)) - rtsx_pci_enable_oobs_polling(pcr); - else + if (rtsx_check_dev_flag(pcr, ASPM_L1_1_EN | ASPM_L1_2_EN + | PM_L1_1_EN | PM_L1_2_EN)) rtsx_pci_disable_oobs_polling(pcr); + else + rtsx_pci_enable_oobs_polling(pcr); } - - if (lval & PCI_L1SS_CTL1_ASPM_L1_1) - rtsx_set_dev_flag(pcr, ASPM_L1_1_EN); - - if (lval & PCI_L1SS_CTL1_ASPM_L1_2) - rtsx_set_dev_flag(pcr, ASPM_L1_2_EN); - - if (lval & PCI_L1SS_CTL1_PCIPM_L1_1) - rtsx_set_dev_flag(pcr, PM_L1_1_EN); - - if (lval & PCI_L1SS_CTL1_PCIPM_L1_2) - rtsx_set_dev_flag(pcr, PM_L1_2_EN); - if (option->ltr_en) { - u16 val; - - pcie_capability_read_word(pdev, PCI_EXP_DEVCTL2, &val); - if (val & PCI_EXP_DEVCTL2_LTR_EN) { - option->ltr_enabled = true; - option->ltr_active = true; + if (option->ltr_enabled) rtsx_set_ltr_latency(pcr, option->ltr_active_latency); - } else { - option->ltr_enabled = false; - } } } -static int rts5249_init_from_hw(struct rtsx_pcr *pcr) -{ - struct rtsx_cr_option *option = &(pcr->option); - - if (rtsx_check_dev_flag(pcr, ASPM_L1_1_EN | ASPM_L1_2_EN - | PM_L1_1_EN | PM_L1_2_EN)) - option->force_clkreq_0 = false; - else - option->force_clkreq_0 = true; - - return 0; -} - static void rts52xa_force_power_down(struct rtsx_pcr *pcr, u8 pm_state, bool runtime) { /* Set relink_time to 0 */ @@ -276,7 +234,6 @@ static int rts5249_extra_init_hw(struct rtsx_pcr *pcr) struct rtsx_cr_option *option = &(pcr->option); rts5249_init_from_cfg(pcr); - rts5249_init_from_hw(pcr); rtsx_pci_init_cmd(pcr); @@ -327,11 +284,12 @@ static int rts5249_extra_init_hw(struct rtsx_pcr *pcr) } } + /* * If u_force_clkreq_0 is enabled, CLKREQ# PIN will be forced * to drive low, and we forcibly request clock. */ - if (option->force_clkreq_0 && pcr->aspm_mode == ASPM_MODE_CFG) + if (option->force_clkreq_0) rtsx_pci_write_register(pcr, PETXCFG, FORCE_CLKREQ_DELINK_MASK, FORCE_CLKREQ_LOW); else diff --git a/drivers/misc/cardreader/rts5260.c b/drivers/misc/cardreader/rts5260.c index 79b18f6f73a8..d2d3a6ccb8f7 100644 --- a/drivers/misc/cardreader/rts5260.c +++ b/drivers/misc/cardreader/rts5260.c @@ -480,47 +480,19 @@ static void rts5260_pwr_saving_setting(struct rtsx_pcr *pcr) static void rts5260_init_from_cfg(struct rtsx_pcr *pcr) { - struct pci_dev *pdev = pcr->pci; - int l1ss; struct rtsx_cr_option *option = &pcr->option; - u32 lval; - - l1ss = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_L1SS); - if (!l1ss) - return; - - pci_read_config_dword(pdev, l1ss + PCI_L1SS_CTL1, &lval); - - if (lval & PCI_L1SS_CTL1_ASPM_L1_1) - rtsx_set_dev_flag(pcr, ASPM_L1_1_EN); - - if (lval & PCI_L1SS_CTL1_ASPM_L1_2) - rtsx_set_dev_flag(pcr, ASPM_L1_2_EN); - - if (lval & PCI_L1SS_CTL1_PCIPM_L1_1) - rtsx_set_dev_flag(pcr, PM_L1_1_EN); - - if (lval & PCI_L1SS_CTL1_PCIPM_L1_2) - rtsx_set_dev_flag(pcr, PM_L1_2_EN); rts5260_pwr_saving_setting(pcr); if (option->ltr_en) { - u16 val; - - pcie_capability_read_word(pdev, PCI_EXP_DEVCTL2, &val); - if (val & PCI_EXP_DEVCTL2_LTR_EN) { - option->ltr_enabled = true; - option->ltr_active = true; + if (option->ltr_enabled) rtsx_set_ltr_latency(pcr, option->ltr_active_latency); - } else { - option->ltr_enabled = false; - } } } static int rts5260_extra_init_hw(struct rtsx_pcr *pcr) { + struct rtsx_cr_option *option = &pcr->option; /* Set mcu_cnt to 7 to ensure data can be sampled properly */ rtsx_pci_write_register(pcr, 0xFC03, 0x7F, 0x07); @@ -539,6 +511,17 @@ static int rts5260_extra_init_hw(struct rtsx_pcr *pcr) rts5260_init_hw(pcr); + /* + * If u_force_clkreq_0 is enabled, CLKREQ# PIN will be forced + * to drive low, and we forcibly request clock. + */ + if (option->force_clkreq_0) + rtsx_pci_write_register(pcr, PETXCFG, + FORCE_CLKREQ_DELINK_MASK, FORCE_CLKREQ_LOW); + else + rtsx_pci_write_register(pcr, PETXCFG, + FORCE_CLKREQ_DELINK_MASK, FORCE_CLKREQ_HIGH); + rtsx_pci_write_register(pcr, pcr->reg_pm_ctrl3, 0x10, 0x00); return 0; diff --git a/drivers/misc/cardreader/rts5261.c b/drivers/misc/cardreader/rts5261.c index 94af6bf8a25a..67252512a132 100644 --- a/drivers/misc/cardreader/rts5261.c +++ b/drivers/misc/cardreader/rts5261.c @@ -454,54 +454,17 @@ static void rts5261_init_from_hw(struct rtsx_pcr *pcr) static void rts5261_init_from_cfg(struct rtsx_pcr *pcr) { - struct pci_dev *pdev = pcr->pci; - int l1ss; - u32 lval; struct rtsx_cr_option *option = &pcr->option; - l1ss = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_L1SS); - if (!l1ss) - return; - - pci_read_config_dword(pdev, l1ss + PCI_L1SS_CTL1, &lval); - - if (lval & PCI_L1SS_CTL1_ASPM_L1_1) - rtsx_set_dev_flag(pcr, ASPM_L1_1_EN); - else - rtsx_clear_dev_flag(pcr, ASPM_L1_1_EN); - - if (lval & PCI_L1SS_CTL1_ASPM_L1_2) - rtsx_set_dev_flag(pcr, ASPM_L1_2_EN); - else - rtsx_clear_dev_flag(pcr, ASPM_L1_2_EN); - - if (lval & PCI_L1SS_CTL1_PCIPM_L1_1) - rtsx_set_dev_flag(pcr, PM_L1_1_EN); - else - rtsx_clear_dev_flag(pcr, PM_L1_1_EN); - - if (lval & PCI_L1SS_CTL1_PCIPM_L1_2) - rtsx_set_dev_flag(pcr, PM_L1_2_EN); - else - rtsx_clear_dev_flag(pcr, PM_L1_2_EN); - - rtsx_pci_write_register(pcr, ASPM_FORCE_CTL, 0xFF, 0); if (option->ltr_en) { - u16 val; - - pcie_capability_read_word(pdev, PCI_EXP_DEVCTL2, &val); - if (val & PCI_EXP_DEVCTL2_LTR_EN) { - option->ltr_enabled = true; - option->ltr_active = true; + if (option->ltr_enabled) rtsx_set_ltr_latency(pcr, option->ltr_active_latency); - } else { - option->ltr_enabled = false; - } } } static int rts5261_extra_init_hw(struct rtsx_pcr *pcr) { + struct rtsx_cr_option *option = &pcr->option; u32 val; rtsx_pci_write_register(pcr, RTS5261_AUTOLOAD_CFG1, @@ -547,6 +510,17 @@ static int rts5261_extra_init_hw(struct rtsx_pcr *pcr) else rtsx_pci_write_register(pcr, PETXCFG, 0x30, 0x00); + /* + * If u_force_clkreq_0 is enabled, CLKREQ# PIN will be forced + * to drive low, and we forcibly request clock. + */ + if (option->force_clkreq_0) + rtsx_pci_write_register(pcr, PETXCFG, + FORCE_CLKREQ_DELINK_MASK, FORCE_CLKREQ_LOW); + else + rtsx_pci_write_register(pcr, PETXCFG, + FORCE_CLKREQ_DELINK_MASK, FORCE_CLKREQ_HIGH); + rtsx_pci_write_register(pcr, PWD_SUSPEND_EN, 0xFF, 0xFB); if (pcr->rtd3_en) { diff --git a/drivers/misc/cardreader/rtsx_pcr.c b/drivers/misc/cardreader/rtsx_pcr.c index a3f4b52bb159..a30751ad3733 100644 --- a/drivers/misc/cardreader/rtsx_pcr.c +++ b/drivers/misc/cardreader/rtsx_pcr.c @@ -1326,11 +1326,8 @@ static int rtsx_pci_init_hw(struct rtsx_pcr *pcr) return err; } - if (pcr->aspm_mode == ASPM_MODE_REG) { + if (pcr->aspm_mode == ASPM_MODE_REG) rtsx_pci_write_register(pcr, ASPM_FORCE_CTL, 0x30, 0x30); - rtsx_pci_write_register(pcr, PETXCFG, - FORCE_CLKREQ_DELINK_MASK, FORCE_CLKREQ_HIGH); - } /* No CD interrupt if probing driver with card inserted. * So we need to initialize pcr->card_exist here. @@ -1345,7 +1342,9 @@ static int rtsx_pci_init_hw(struct rtsx_pcr *pcr) static int rtsx_pci_init_chip(struct rtsx_pcr *pcr) { - int err; + struct rtsx_cr_option *option = &(pcr->option); + int err, l1ss; + u32 lval; u16 cfg_val; u8 val; @@ -1430,6 +1429,48 @@ static int rtsx_pci_init_chip(struct rtsx_pcr *pcr) pcr->aspm_enabled = true; } + l1ss = pci_find_ext_capability(pcr->pci, PCI_EXT_CAP_ID_L1SS); + if (l1ss) { + pci_read_config_dword(pcr->pci, l1ss + PCI_L1SS_CTL1, &lval); + + if (lval & PCI_L1SS_CTL1_ASPM_L1_1) + rtsx_set_dev_flag(pcr, ASPM_L1_1_EN); + else + rtsx_clear_dev_flag(pcr, ASPM_L1_1_EN); + + if (lval & PCI_L1SS_CTL1_ASPM_L1_2) + rtsx_set_dev_flag(pcr, ASPM_L1_2_EN); + else + rtsx_clear_dev_flag(pcr, ASPM_L1_2_EN); + + if (lval & PCI_L1SS_CTL1_PCIPM_L1_1) + rtsx_set_dev_flag(pcr, PM_L1_1_EN); + else + rtsx_clear_dev_flag(pcr, PM_L1_1_EN); + + if (lval & PCI_L1SS_CTL1_PCIPM_L1_2) + rtsx_set_dev_flag(pcr, PM_L1_2_EN); + else + rtsx_clear_dev_flag(pcr, PM_L1_2_EN); + + pcie_capability_read_word(pcr->pci, PCI_EXP_DEVCTL2, &cfg_val); + if (cfg_val & PCI_EXP_DEVCTL2_LTR_EN) { + option->ltr_enabled = true; + option->ltr_active = true; + } else { + option->ltr_enabled = false; + } + + if (rtsx_check_dev_flag(pcr, ASPM_L1_1_EN | ASPM_L1_2_EN + | PM_L1_1_EN | PM_L1_2_EN)) + option->force_clkreq_0 = false; + else + option->force_clkreq_0 = true; + } else { + option->ltr_enabled = false; + option->force_clkreq_0 = true; + } + if (pcr->ops->fetch_vendor_settings) pcr->ops->fetch_vendor_settings(pcr); diff --git a/drivers/net/dsa/sja1105/sja1105.h b/drivers/net/dsa/sja1105/sja1105.h index 0617d5ccd3ff..8c66d3bf61f0 100644 --- a/drivers/net/dsa/sja1105/sja1105.h +++ b/drivers/net/dsa/sja1105/sja1105.h @@ -266,6 +266,8 @@ struct sja1105_private { * the switch doesn't confuse them with one another. */ struct mutex mgmt_lock; + /* Serializes accesses to the FDB */ + struct mutex fdb_lock; /* PTP two-step TX timestamp ID, and its serialization lock */ spinlock_t ts_id_lock; u8 ts_id; diff --git a/drivers/net/dsa/sja1105/sja1105_dynamic_config.c b/drivers/net/dsa/sja1105/sja1105_dynamic_config.c index 7729d3f8b7f5..984c0e604e8d 100644 --- a/drivers/net/dsa/sja1105/sja1105_dynamic_config.c +++ b/drivers/net/dsa/sja1105/sja1105_dynamic_config.c @@ -1175,18 +1175,15 @@ const struct sja1105_dynamic_table_ops sja1110_dyn_ops[BLK_IDX_MAX_DYN] = { static int sja1105_dynamic_config_poll_valid(struct sja1105_private *priv, - struct sja1105_dyn_cmd *cmd, - const struct sja1105_dynamic_table_ops *ops) + const struct sja1105_dynamic_table_ops *ops, + void *entry, bool check_valident, + bool check_errors) { u8 packed_buf[SJA1105_MAX_DYN_CMD_SIZE] = {}; + struct sja1105_dyn_cmd cmd = {}; int rc; - /* We don't _need_ to read the full entry, just the command area which - * is a fixed SJA1105_SIZE_DYN_CMD. But our cmd_packing() API expects a - * buffer that contains the full entry too. Additionally, our API - * doesn't really know how many bytes into the buffer does the command - * area really begin. So just read back the whole entry. - */ + /* Read back the whole entry + command structure. */ rc = sja1105_xfer_buf(priv, SPI_READ, ops->addr, packed_buf, ops->packed_size); if (rc) @@ -1195,11 +1192,25 @@ sja1105_dynamic_config_poll_valid(struct sja1105_private *priv, /* Unpack the command structure, and return it to the caller in case it * needs to perform further checks on it (VALIDENT). */ - memset(cmd, 0, sizeof(*cmd)); - ops->cmd_packing(packed_buf, cmd, UNPACK); + ops->cmd_packing(packed_buf, &cmd, UNPACK); /* Hardware hasn't cleared VALID => still working on it */ - return cmd->valid ? -EAGAIN : 0; + if (cmd.valid) + return -EAGAIN; + + if (check_valident && !cmd.valident && !(ops->access & OP_VALID_ANYWAY)) + return -ENOENT; + + if (check_errors && cmd.errors) + return -EINVAL; + + /* Don't dereference possibly NULL pointer - maybe caller + * only wanted to see whether the entry existed or not. + */ + if (entry) + ops->entry_packing(packed_buf, entry, UNPACK); + + return 0; } /* Poll the dynamic config entry's control area until the hardware has @@ -1208,16 +1219,19 @@ sja1105_dynamic_config_poll_valid(struct sja1105_private *priv, */ static int sja1105_dynamic_config_wait_complete(struct sja1105_private *priv, - struct sja1105_dyn_cmd *cmd, - const struct sja1105_dynamic_table_ops *ops) + const struct sja1105_dynamic_table_ops *ops, + void *entry, bool check_valident, + bool check_errors) { - int rc; - - return read_poll_timeout(sja1105_dynamic_config_poll_valid, - rc, rc != -EAGAIN, - SJA1105_DYNAMIC_CONFIG_SLEEP_US, - SJA1105_DYNAMIC_CONFIG_TIMEOUT_US, - false, priv, cmd, ops); + int err, rc; + + err = read_poll_timeout(sja1105_dynamic_config_poll_valid, + rc, rc != -EAGAIN, + SJA1105_DYNAMIC_CONFIG_SLEEP_US, + SJA1105_DYNAMIC_CONFIG_TIMEOUT_US, + false, priv, ops, entry, check_valident, + check_errors); + return err < 0 ? err : rc; } /* Provides read access to the settings through the dynamic interface @@ -1286,25 +1300,14 @@ int sja1105_dynamic_config_read(struct sja1105_private *priv, mutex_lock(&priv->dynamic_config_lock); rc = sja1105_xfer_buf(priv, SPI_WRITE, ops->addr, packed_buf, ops->packed_size); - if (rc < 0) { - mutex_unlock(&priv->dynamic_config_lock); - return rc; - } - - rc = sja1105_dynamic_config_wait_complete(priv, &cmd, ops); - mutex_unlock(&priv->dynamic_config_lock); if (rc < 0) - return rc; + goto out; - if (!cmd.valident && !(ops->access & OP_VALID_ANYWAY)) - return -ENOENT; + rc = sja1105_dynamic_config_wait_complete(priv, ops, entry, true, false); +out: + mutex_unlock(&priv->dynamic_config_lock); - /* Don't dereference possibly NULL pointer - maybe caller - * only wanted to see whether the entry existed or not. - */ - if (entry) - ops->entry_packing(packed_buf, entry, UNPACK); - return 0; + return rc; } int sja1105_dynamic_config_write(struct sja1105_private *priv, @@ -1356,22 +1359,14 @@ int sja1105_dynamic_config_write(struct sja1105_private *priv, mutex_lock(&priv->dynamic_config_lock); rc = sja1105_xfer_buf(priv, SPI_WRITE, ops->addr, packed_buf, ops->packed_size); - if (rc < 0) { - mutex_unlock(&priv->dynamic_config_lock); - return rc; - } - - rc = sja1105_dynamic_config_wait_complete(priv, &cmd, ops); - mutex_unlock(&priv->dynamic_config_lock); if (rc < 0) - return rc; + goto out; - cmd = (struct sja1105_dyn_cmd) {0}; - ops->cmd_packing(packed_buf, &cmd, UNPACK); - if (cmd.errors) - return -EINVAL; + rc = sja1105_dynamic_config_wait_complete(priv, ops, NULL, false, true); +out: + mutex_unlock(&priv->dynamic_config_lock); - return 0; + return rc; } static u8 sja1105_crc8_add(u8 crc, u8 byte, u8 poly) diff --git a/drivers/net/dsa/sja1105/sja1105_main.c b/drivers/net/dsa/sja1105/sja1105_main.c index a23d980d28f5..1a367e64bc3b 100644 --- a/drivers/net/dsa/sja1105/sja1105_main.c +++ b/drivers/net/dsa/sja1105/sja1105_main.c @@ -1798,6 +1798,7 @@ static int sja1105_fdb_add(struct dsa_switch *ds, int port, struct dsa_db db) { struct sja1105_private *priv = ds->priv; + int rc; if (!vid) { switch (db.type) { @@ -1812,12 +1813,16 @@ static int sja1105_fdb_add(struct dsa_switch *ds, int port, } } - return priv->info->fdb_add_cmd(ds, port, addr, vid); + mutex_lock(&priv->fdb_lock); + rc = priv->info->fdb_add_cmd(ds, port, addr, vid); + mutex_unlock(&priv->fdb_lock); + + return rc; } -static int sja1105_fdb_del(struct dsa_switch *ds, int port, - const unsigned char *addr, u16 vid, - struct dsa_db db) +static int __sja1105_fdb_del(struct dsa_switch *ds, int port, + const unsigned char *addr, u16 vid, + struct dsa_db db) { struct sja1105_private *priv = ds->priv; @@ -1837,6 +1842,20 @@ static int sja1105_fdb_del(struct dsa_switch *ds, int port, return priv->info->fdb_del_cmd(ds, port, addr, vid); } +static int sja1105_fdb_del(struct dsa_switch *ds, int port, + const unsigned char *addr, u16 vid, + struct dsa_db db) +{ + struct sja1105_private *priv = ds->priv; + int rc; + + mutex_lock(&priv->fdb_lock); + rc = __sja1105_fdb_del(ds, port, addr, vid, db); + mutex_unlock(&priv->fdb_lock); + + return rc; +} + static int sja1105_fdb_dump(struct dsa_switch *ds, int port, dsa_fdb_dump_cb_t *cb, void *data) { @@ -1868,13 +1887,14 @@ static int sja1105_fdb_dump(struct dsa_switch *ds, int port, if (!(l2_lookup.destports & BIT(port))) continue; - /* We need to hide the FDB entry for unknown multicast */ - if (l2_lookup.macaddr == SJA1105_UNKNOWN_MULTICAST && - l2_lookup.mask_macaddr == SJA1105_UNKNOWN_MULTICAST) - continue; - u64_to_ether_addr(l2_lookup.macaddr, macaddr); + /* Hardware FDB is shared for fdb and mdb, "bridge fdb show" + * only wants to see unicast + */ + if (is_multicast_ether_addr(macaddr)) + continue; + /* We need to hide the dsa_8021q VLANs from the user. */ if (vid_is_dsa_8021q(l2_lookup.vlanid)) l2_lookup.vlanid = 0; @@ -1898,6 +1918,8 @@ static void sja1105_fast_age(struct dsa_switch *ds, int port) }; int i; + mutex_lock(&priv->fdb_lock); + for (i = 0; i < SJA1105_MAX_L2_LOOKUP_COUNT; i++) { struct sja1105_l2_lookup_entry l2_lookup = {0}; u8 macaddr[ETH_ALEN]; @@ -1911,7 +1933,7 @@ static void sja1105_fast_age(struct dsa_switch *ds, int port) if (rc) { dev_err(ds->dev, "Failed to read FDB: %pe\n", ERR_PTR(rc)); - return; + break; } if (!(l2_lookup.destports & BIT(port))) @@ -1923,14 +1945,16 @@ static void sja1105_fast_age(struct dsa_switch *ds, int port) u64_to_ether_addr(l2_lookup.macaddr, macaddr); - rc = sja1105_fdb_del(ds, port, macaddr, l2_lookup.vlanid, db); + rc = __sja1105_fdb_del(ds, port, macaddr, l2_lookup.vlanid, db); if (rc) { dev_err(ds->dev, "Failed to delete FDB entry %pM vid %lld: %pe\n", macaddr, l2_lookup.vlanid, ERR_PTR(rc)); - return; + break; } } + + mutex_unlock(&priv->fdb_lock); } static int sja1105_mdb_add(struct dsa_switch *ds, int port, @@ -2273,6 +2297,7 @@ int sja1105_static_config_reload(struct sja1105_private *priv, int rc, i; s64 now; + mutex_lock(&priv->fdb_lock); mutex_lock(&priv->mgmt_lock); mac = priv->static_config.tables[BLK_IDX_MAC_CONFIG].entries; @@ -2385,6 +2410,7 @@ int sja1105_static_config_reload(struct sja1105_private *priv, goto out; out: mutex_unlock(&priv->mgmt_lock); + mutex_unlock(&priv->fdb_lock); return rc; } @@ -2954,7 +2980,9 @@ static int sja1105_port_mcast_flood(struct sja1105_private *priv, int to, { struct sja1105_l2_lookup_entry *l2_lookup; struct sja1105_table *table; - int match; + int match, rc; + + mutex_lock(&priv->fdb_lock); table = &priv->static_config.tables[BLK_IDX_L2_LOOKUP]; l2_lookup = table->entries; @@ -2967,7 +2995,8 @@ static int sja1105_port_mcast_flood(struct sja1105_private *priv, int to, if (match == table->entry_count) { NL_SET_ERR_MSG_MOD(extack, "Could not find FDB entry for unknown multicast"); - return -ENOSPC; + rc = -ENOSPC; + goto out; } if (flags.val & BR_MCAST_FLOOD) @@ -2975,10 +3004,13 @@ static int sja1105_port_mcast_flood(struct sja1105_private *priv, int to, else l2_lookup[match].destports &= ~BIT(to); - return sja1105_dynamic_config_write(priv, BLK_IDX_L2_LOOKUP, - l2_lookup[match].index, - &l2_lookup[match], - true); + rc = sja1105_dynamic_config_write(priv, BLK_IDX_L2_LOOKUP, + l2_lookup[match].index, + &l2_lookup[match], true); +out: + mutex_unlock(&priv->fdb_lock); + + return rc; } static int sja1105_port_pre_bridge_flags(struct dsa_switch *ds, int port, @@ -3348,6 +3380,7 @@ static int sja1105_probe(struct spi_device *spi) mutex_init(&priv->ptp_data.lock); mutex_init(&priv->dynamic_config_lock); mutex_init(&priv->mgmt_lock); + mutex_init(&priv->fdb_lock); spin_lock_init(&priv->ts_id_lock); rc = sja1105_parse_dt(priv); diff --git a/drivers/net/ethernet/adi/adin1110.c b/drivers/net/ethernet/adi/adin1110.c index 1c009b485188..ca66b747b7c5 100644 --- a/drivers/net/ethernet/adi/adin1110.c +++ b/drivers/net/ethernet/adi/adin1110.c @@ -1385,7 +1385,7 @@ static int adin1110_fdb_add(struct adin1110_port_priv *port_priv, return -ENOMEM; other_port = priv->ports[!port_priv->nr]; - port_rules = adin1110_port_rules(port_priv, false, true); + port_rules = adin1110_port_rules(other_port, false, true); eth_broadcast_addr(mask); return adin1110_write_mac_address(other_port, mac_nr, (u8 *)fdb->addr, diff --git a/drivers/net/ethernet/amazon/ena/ena_netdev.c b/drivers/net/ethernet/amazon/ena/ena_netdev.c index ad32ca81f7ef..f955bde10cf9 100644 --- a/drivers/net/ethernet/amazon/ena/ena_netdev.c +++ b/drivers/net/ethernet/amazon/ena/ena_netdev.c @@ -1833,6 +1833,9 @@ static int ena_clean_rx_irq(struct ena_ring *rx_ring, struct napi_struct *napi, return work_done; error: + if (xdp_flags & ENA_XDP_REDIRECT) + xdp_do_flush(); + adapter = netdev_priv(rx_ring->netdev); if (rc == -ENOSPC) { diff --git a/drivers/net/ethernet/broadcom/asp2/bcmasp.c b/drivers/net/ethernet/broadcom/asp2/bcmasp.c index d63d321f3e7b..41a6098eb0c2 100644 --- a/drivers/net/ethernet/broadcom/asp2/bcmasp.c +++ b/drivers/net/ethernet/broadcom/asp2/bcmasp.c @@ -528,13 +528,16 @@ void bcmasp_netfilt_suspend(struct bcmasp_intf *intf) ASP_RX_FILTER_BLK_CTRL); } -void bcmasp_netfilt_get_all_active(struct bcmasp_intf *intf, u32 *rule_locs, - u32 *rule_cnt) +int bcmasp_netfilt_get_all_active(struct bcmasp_intf *intf, u32 *rule_locs, + u32 *rule_cnt) { struct bcmasp_priv *priv = intf->parent; int j = 0, i; for (i = 0; i < NUM_NET_FILTERS; i++) { + if (j == *rule_cnt) + return -EMSGSIZE; + if (!priv->net_filters[i].claimed || priv->net_filters[i].port != intf->port) continue; @@ -548,6 +551,8 @@ void bcmasp_netfilt_get_all_active(struct bcmasp_intf *intf, u32 *rule_locs, } *rule_cnt = j; + + return 0; } int bcmasp_netfilt_get_active(struct bcmasp_intf *intf) @@ -1300,6 +1305,7 @@ static int bcmasp_probe(struct platform_device *pdev) if (!intf) { dev_err(dev, "Cannot create eth interface %d\n", i); bcmasp_remove_intfs(priv); + of_node_put(intf_node); goto of_put_exit; } list_add_tail(&intf->list, &priv->intfs); diff --git a/drivers/net/ethernet/broadcom/asp2/bcmasp.h b/drivers/net/ethernet/broadcom/asp2/bcmasp.h index 5b512f7f5e94..ec90add6b03e 100644 --- a/drivers/net/ethernet/broadcom/asp2/bcmasp.h +++ b/drivers/net/ethernet/broadcom/asp2/bcmasp.h @@ -577,8 +577,8 @@ void bcmasp_netfilt_release(struct bcmasp_intf *intf, int bcmasp_netfilt_get_active(struct bcmasp_intf *intf); -void bcmasp_netfilt_get_all_active(struct bcmasp_intf *intf, u32 *rule_locs, - u32 *rule_cnt); +int bcmasp_netfilt_get_all_active(struct bcmasp_intf *intf, u32 *rule_locs, + u32 *rule_cnt); void bcmasp_netfilt_suspend(struct bcmasp_intf *intf); diff --git a/drivers/net/ethernet/broadcom/asp2/bcmasp_ethtool.c b/drivers/net/ethernet/broadcom/asp2/bcmasp_ethtool.c index c4f1604d5ab3..ce6a3d56fb23 100644 --- a/drivers/net/ethernet/broadcom/asp2/bcmasp_ethtool.c +++ b/drivers/net/ethernet/broadcom/asp2/bcmasp_ethtool.c @@ -335,7 +335,7 @@ static int bcmasp_get_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd, err = bcmasp_flow_get(intf, cmd); break; case ETHTOOL_GRXCLSRLALL: - bcmasp_netfilt_get_all_active(intf, rule_locs, &cmd->rule_cnt); + err = bcmasp_netfilt_get_all_active(intf, rule_locs, &cmd->rule_cnt); cmd->data = NUM_NET_FILTERS; break; default: diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 5cc0dbe12132..7551aa8068f8 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -2614,6 +2614,7 @@ static int bnxt_poll_nitroa0(struct napi_struct *napi, int budget) struct rx_cmp_ext *rxcmp1; u32 cp_cons, tmp_raw_cons; u32 raw_cons = cpr->cp_raw_cons; + bool flush_xdp = false; u32 rx_pkts = 0; u8 event = 0; @@ -2648,6 +2649,8 @@ static int bnxt_poll_nitroa0(struct napi_struct *napi, int budget) rx_pkts++; else if (rc == -EBUSY) /* partial completion */ break; + if (event & BNXT_REDIRECT_EVENT) + flush_xdp = true; } else if (unlikely(TX_CMP_TYPE(txcmp) == CMPL_BASE_TYPE_HWRM_DONE)) { bnxt_hwrm_handler(bp, txcmp); @@ -2667,6 +2670,8 @@ static int bnxt_poll_nitroa0(struct napi_struct *napi, int budget) if (event & BNXT_AGG_EVENT) bnxt_db_write(bp, &rxr->rx_agg_db, rxr->rx_agg_prod); + if (flush_xdp) + xdp_do_flush(); if (!bnxt_has_work(bp, cpr) && rx_pkts < budget) { napi_complete_done(napi, rx_pkts); diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c index 31f664ee4d77..b940dcd3ace6 100644 --- a/drivers/net/ethernet/cadence/macb_main.c +++ b/drivers/net/ethernet/cadence/macb_main.c @@ -756,8 +756,6 @@ static void macb_mac_link_up(struct phylink_config *config, if (rx_pause) ctrl |= MACB_BIT(PAE); - macb_set_tx_clk(bp, speed); - /* Initialize rings & buffers as clearing MACB_BIT(TE) in link down * cleared the pipeline and control registers. */ @@ -777,6 +775,9 @@ static void macb_mac_link_up(struct phylink_config *config, spin_unlock_irqrestore(&bp->lock, flags); + if (!(bp->caps & MACB_CAPS_MACB_IS_EMAC)) + macb_set_tx_clk(bp, speed); + /* Enable Rx and Tx; Enable PTP unicast */ ctrl = macb_readl(bp, NCR); if (gem_has_ptp(bp)) diff --git a/drivers/net/ethernet/engleder/tsnep_ethtool.c b/drivers/net/ethernet/engleder/tsnep_ethtool.c index 716815dad7d2..65ec1abc9442 100644 --- a/drivers/net/ethernet/engleder/tsnep_ethtool.c +++ b/drivers/net/ethernet/engleder/tsnep_ethtool.c @@ -300,10 +300,8 @@ static void tsnep_ethtool_get_channels(struct net_device *netdev, { struct tsnep_adapter *adapter = netdev_priv(netdev); - ch->max_rx = adapter->num_rx_queues; - ch->max_tx = adapter->num_tx_queues; - ch->rx_count = adapter->num_rx_queues; - ch->tx_count = adapter->num_tx_queues; + ch->max_combined = adapter->num_queues; + ch->combined_count = adapter->num_queues; } static int tsnep_ethtool_get_ts_info(struct net_device *netdev, diff --git a/drivers/net/ethernet/engleder/tsnep_main.c b/drivers/net/ethernet/engleder/tsnep_main.c index f61bd89734c5..8b992dc9bb52 100644 --- a/drivers/net/ethernet/engleder/tsnep_main.c +++ b/drivers/net/ethernet/engleder/tsnep_main.c @@ -87,8 +87,11 @@ static irqreturn_t tsnep_irq(int irq, void *arg) /* handle TX/RX queue 0 interrupt */ if ((active & adapter->queue[0].irq_mask) != 0) { - tsnep_disable_irq(adapter, adapter->queue[0].irq_mask); - napi_schedule(&adapter->queue[0].napi); + if (napi_schedule_prep(&adapter->queue[0].napi)) { + tsnep_disable_irq(adapter, adapter->queue[0].irq_mask); + /* schedule after masking to avoid races */ + __napi_schedule(&adapter->queue[0].napi); + } } return IRQ_HANDLED; @@ -99,8 +102,11 @@ static irqreturn_t tsnep_irq_txrx(int irq, void *arg) struct tsnep_queue *queue = arg; /* handle TX/RX queue interrupt */ - tsnep_disable_irq(queue->adapter, queue->irq_mask); - napi_schedule(&queue->napi); + if (napi_schedule_prep(&queue->napi)) { + tsnep_disable_irq(queue->adapter, queue->irq_mask); + /* schedule after masking to avoid races */ + __napi_schedule(&queue->napi); + } return IRQ_HANDLED; } @@ -1728,6 +1734,10 @@ static int tsnep_poll(struct napi_struct *napi, int budget) if (queue->tx) complete = tsnep_tx_poll(queue->tx, budget); + /* handle case where we are called by netpoll with a budget of 0 */ + if (unlikely(budget <= 0)) + return budget; + if (queue->rx) { done = queue->rx->xsk_pool ? tsnep_rx_poll_zc(queue->rx, napi, budget) : diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c index b4895c7b3efd..cf50368441b7 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_enet.c @@ -3353,6 +3353,15 @@ static void hns3_set_default_feature(struct net_device *netdev) NETIF_F_HW_TC); netdev->hw_enc_features |= netdev->vlan_features | NETIF_F_TSO_MANGLEID; + + /* The device_version V3 hardware can't offload the checksum for IP in + * GRE packets, but can do it for NvGRE. So default to disable the + * checksum and GSO offload for GRE. + */ + if (ae_dev->dev_version > HNAE3_DEVICE_VERSION_V2) { + netdev->features &= ~NETIF_F_GSO_GRE; + netdev->features &= ~NETIF_F_GSO_GRE_CSUM; + } } static int hns3_alloc_buffer(struct hns3_enet_ring *ring, diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index 8ca368424436..c42574e29747 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -3564,9 +3564,14 @@ static u32 hclge_check_event_cause(struct hclge_dev *hdev, u32 *clearval) static void hclge_clear_event_cause(struct hclge_dev *hdev, u32 event_type, u32 regclr) { +#define HCLGE_IMP_RESET_DELAY 5 + switch (event_type) { case HCLGE_VECTOR0_EVENT_PTP: case HCLGE_VECTOR0_EVENT_RST: + if (regclr == BIT(HCLGE_VECTOR0_IMPRESET_INT_B)) + mdelay(HCLGE_IMP_RESET_DELAY); + hclge_write_dev(&hdev->hw, HCLGE_MISC_RESET_STS_REG, regclr); break; case HCLGE_VECTOR0_EVENT_MBX: @@ -7348,6 +7353,12 @@ static int hclge_del_cls_flower(struct hnae3_handle *handle, ret = hclge_fd_tcam_config(hdev, HCLGE_FD_STAGE_1, true, rule->location, NULL, false); if (ret) { + /* if tcam config fail, set rule state to TO_DEL, + * so the rule will be deleted when periodic + * task being scheduled. + */ + hclge_update_fd_list(hdev, HCLGE_FD_TO_DEL, rule->location, NULL); + set_bit(HCLGE_STATE_FD_TBL_CHANGED, &hdev->state); spin_unlock_bh(&hdev->fd_rule_lock); return ret; } @@ -8824,7 +8835,7 @@ static void hclge_update_overflow_flags(struct hclge_vport *vport, if (mac_type == HCLGE_MAC_ADDR_UC) { if (is_all_added) vport->overflow_promisc_flags &= ~HNAE3_OVERFLOW_UPE; - else + else if (hclge_is_umv_space_full(vport, true)) vport->overflow_promisc_flags |= HNAE3_OVERFLOW_UPE; } else { if (is_all_added) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c index 7a2f9233d695..a4d68fb216fb 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c @@ -1855,7 +1855,8 @@ static void hclgevf_periodic_service_task(struct hclgevf_dev *hdev) unsigned long delta = round_jiffies_relative(HZ); struct hnae3_handle *handle = &hdev->nic; - if (test_bit(HCLGEVF_STATE_RST_FAIL, &hdev->state)) + if (test_bit(HCLGEVF_STATE_RST_FAIL, &hdev->state) || + test_bit(HCLGE_COMM_STATE_CMD_DISABLE, &hdev->hw.hw.comm_state)) return; if (time_is_after_jiffies(hdev->last_serv_processed + HZ)) { diff --git a/drivers/net/ethernet/huawei/hinic/hinic_port.c b/drivers/net/ethernet/huawei/hinic/hinic_port.c index 9406237c461e..f81a43d2cdfc 100644 --- a/drivers/net/ethernet/huawei/hinic/hinic_port.c +++ b/drivers/net/ethernet/huawei/hinic/hinic_port.c @@ -456,9 +456,6 @@ int hinic_set_vlan_fliter(struct hinic_dev *nic_dev, u32 en) u16 out_size = sizeof(vlan_filter); int err; - if (!hwdev) - return -EINVAL; - vlan_filter.func_idx = HINIC_HWIF_FUNC_IDX(hwif); vlan_filter.enable = en; diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c index 8ea1a238dcef..d3d6415553ed 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c @@ -4475,9 +4475,7 @@ int i40e_ndo_set_vf_port_vlan(struct net_device *netdev, int vf_id, goto error_pvid; i40e_vlan_stripping_enable(vsi); - i40e_vc_reset_vf(vf, true); - /* During reset the VF got a new VSI, so refresh a pointer. */ - vsi = pf->vsi[vf->lan_vsi_idx]; + /* Locked once because multiple functions below iterate list */ spin_lock_bh(&vsi->mac_filter_hash_lock); @@ -4563,6 +4561,10 @@ int i40e_ndo_set_vf_port_vlan(struct net_device *netdev, int vf_id, */ vf->port_vlan_id = le16_to_cpu(vsi->info.pvid); + i40e_vc_reset_vf(vf, true); + /* During reset the VF got a new VSI, so refresh a pointer. */ + vsi = pf->vsi[vf->lan_vsi_idx]; + ret = i40e_config_vf_promiscuous_mode(vf, vsi->id, allmulti, alluni); if (ret) { dev_err(&pf->pdev->dev, "Unable to config vf promiscuous mode\n"); diff --git a/drivers/net/ethernet/intel/iavf/iavf.h b/drivers/net/ethernet/intel/iavf/iavf.h index 85fba85fbb23..e110ba346185 100644 --- a/drivers/net/ethernet/intel/iavf/iavf.h +++ b/drivers/net/ethernet/intel/iavf/iavf.h @@ -521,7 +521,7 @@ void iavf_down(struct iavf_adapter *adapter); int iavf_process_config(struct iavf_adapter *adapter); int iavf_parse_vf_resource_msg(struct iavf_adapter *adapter); void iavf_schedule_reset(struct iavf_adapter *adapter, u64 flags); -void iavf_schedule_request_stats(struct iavf_adapter *adapter); +void iavf_schedule_aq_request(struct iavf_adapter *adapter, u64 flags); void iavf_schedule_finish_config(struct iavf_adapter *adapter); void iavf_reset(struct iavf_adapter *adapter); void iavf_set_ethtool_ops(struct net_device *netdev); diff --git a/drivers/net/ethernet/intel/iavf/iavf_ethtool.c b/drivers/net/ethernet/intel/iavf/iavf_ethtool.c index a34303ad057d..90397293525f 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_ethtool.c +++ b/drivers/net/ethernet/intel/iavf/iavf_ethtool.c @@ -362,7 +362,7 @@ static void iavf_get_ethtool_stats(struct net_device *netdev, unsigned int i; /* Explicitly request stats refresh */ - iavf_schedule_request_stats(adapter); + iavf_schedule_aq_request(adapter, IAVF_FLAG_AQ_REQUEST_STATS); iavf_add_ethtool_stats(&data, adapter, iavf_gstrings_stats); diff --git a/drivers/net/ethernet/intel/iavf/iavf_main.c b/drivers/net/ethernet/intel/iavf/iavf_main.c index 7b300c86ceda..6a2e6d64bc3a 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_main.c +++ b/drivers/net/ethernet/intel/iavf/iavf_main.c @@ -314,15 +314,13 @@ void iavf_schedule_reset(struct iavf_adapter *adapter, u64 flags) } /** - * iavf_schedule_request_stats - Set the flags and schedule statistics request + * iavf_schedule_aq_request - Set the flags and schedule aq request * @adapter: board private structure - * - * Sets IAVF_FLAG_AQ_REQUEST_STATS flag so iavf_watchdog_task() will explicitly - * request and refresh ethtool stats + * @flags: requested aq flags **/ -void iavf_schedule_request_stats(struct iavf_adapter *adapter) +void iavf_schedule_aq_request(struct iavf_adapter *adapter, u64 flags) { - adapter->aq_required |= IAVF_FLAG_AQ_REQUEST_STATS; + adapter->aq_required |= flags; mod_delayed_work(adapter->wq, &adapter->watchdog_task, 0); } @@ -823,7 +821,7 @@ iavf_vlan_filter *iavf_add_vlan(struct iavf_adapter *adapter, list_add_tail(&f->list, &adapter->vlan_filter_list); f->state = IAVF_VLAN_ADD; adapter->num_vlan_filters++; - adapter->aq_required |= IAVF_FLAG_AQ_ADD_VLAN_FILTER; + iavf_schedule_aq_request(adapter, IAVF_FLAG_AQ_ADD_VLAN_FILTER); } clearout: @@ -845,7 +843,7 @@ static void iavf_del_vlan(struct iavf_adapter *adapter, struct iavf_vlan vlan) f = iavf_find_vlan(adapter, vlan); if (f) { f->state = IAVF_VLAN_REMOVE; - adapter->aq_required |= IAVF_FLAG_AQ_DEL_VLAN_FILTER; + iavf_schedule_aq_request(adapter, IAVF_FLAG_AQ_DEL_VLAN_FILTER); } spin_unlock_bh(&adapter->mac_vlan_list_lock); @@ -1421,7 +1419,8 @@ void iavf_down(struct iavf_adapter *adapter) iavf_clear_fdir_filters(adapter); iavf_clear_adv_rss_conf(adapter); - if (!(adapter->flags & IAVF_FLAG_PF_COMMS_FAILED)) { + if (!(adapter->flags & IAVF_FLAG_PF_COMMS_FAILED) && + !(test_bit(__IAVF_IN_REMOVE_TASK, &adapter->crit_section))) { /* cancel any current operation */ adapter->current_op = VIRTCHNL_OP_UNKNOWN; /* Schedule operations to close down the HW. Don't wait diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index 13ba9c74bd84..76b34cee1da3 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -3827,8 +3827,11 @@ static int igb_enable_sriov(struct pci_dev *pdev, int num_vfs, bool reinit) } /* only call pci_enable_sriov() if no VFs are allocated already */ - if (!old_vfs) + if (!old_vfs) { err = pci_enable_sriov(pdev, adapter->vfs_allocated_count); + if (err) + goto err_out; + } goto out; diff --git a/drivers/net/ethernet/intel/igc/igc_ethtool.c b/drivers/net/ethernet/intel/igc/igc_ethtool.c index 93bce729be76..7ab6dd58e400 100644 --- a/drivers/net/ethernet/intel/igc/igc_ethtool.c +++ b/drivers/net/ethernet/intel/igc/igc_ethtool.c @@ -868,6 +868,18 @@ static void igc_ethtool_get_stats(struct net_device *netdev, spin_unlock(&adapter->stats64_lock); } +static int igc_ethtool_get_previous_rx_coalesce(struct igc_adapter *adapter) +{ + return (adapter->rx_itr_setting <= 3) ? + adapter->rx_itr_setting : adapter->rx_itr_setting >> 2; +} + +static int igc_ethtool_get_previous_tx_coalesce(struct igc_adapter *adapter) +{ + return (adapter->tx_itr_setting <= 3) ? + adapter->tx_itr_setting : adapter->tx_itr_setting >> 2; +} + static int igc_ethtool_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *ec, struct kernel_ethtool_coalesce *kernel_coal, @@ -875,17 +887,8 @@ static int igc_ethtool_get_coalesce(struct net_device *netdev, { struct igc_adapter *adapter = netdev_priv(netdev); - if (adapter->rx_itr_setting <= 3) - ec->rx_coalesce_usecs = adapter->rx_itr_setting; - else - ec->rx_coalesce_usecs = adapter->rx_itr_setting >> 2; - - if (!(adapter->flags & IGC_FLAG_QUEUE_PAIRS)) { - if (adapter->tx_itr_setting <= 3) - ec->tx_coalesce_usecs = adapter->tx_itr_setting; - else - ec->tx_coalesce_usecs = adapter->tx_itr_setting >> 2; - } + ec->rx_coalesce_usecs = igc_ethtool_get_previous_rx_coalesce(adapter); + ec->tx_coalesce_usecs = igc_ethtool_get_previous_tx_coalesce(adapter); return 0; } @@ -910,8 +913,12 @@ static int igc_ethtool_set_coalesce(struct net_device *netdev, ec->tx_coalesce_usecs == 2) return -EINVAL; - if ((adapter->flags & IGC_FLAG_QUEUE_PAIRS) && ec->tx_coalesce_usecs) + if ((adapter->flags & IGC_FLAG_QUEUE_PAIRS) && + ec->tx_coalesce_usecs != igc_ethtool_get_previous_tx_coalesce(adapter)) { + NL_SET_ERR_MSG_MOD(extack, + "Queue Pair mode enabled, both Rx and Tx coalescing controlled by rx-usecs"); return -EINVAL; + } /* If ITR is disabled, disable DMAC */ if (ec->rx_coalesce_usecs == 0) { diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c index 293b45717683..98de34d0ce07 100644 --- a/drivers/net/ethernet/intel/igc/igc_main.c +++ b/drivers/net/ethernet/intel/igc/igc_main.c @@ -6491,7 +6491,7 @@ static int igc_xdp_xmit(struct net_device *dev, int num_frames, struct igc_ring *ring; int i, drops; - if (unlikely(test_bit(__IGC_DOWN, &adapter->state))) + if (unlikely(!netif_carrier_ok(dev))) return -ENETDOWN; if (unlikely(flags & ~XDP_XMIT_FLAGS_MASK)) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c index 0310af851086..9339edbd9082 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c @@ -979,6 +979,7 @@ static int ixgbe_ptp_set_timestamp_mode(struct ixgbe_adapter *adapter, u32 tsync_tx_ctl = IXGBE_TSYNCTXCTL_ENABLED; u32 tsync_rx_ctl = IXGBE_TSYNCRXCTL_ENABLED; u32 tsync_rx_mtrl = PTP_EV_PORT << 16; + u32 aflags = adapter->flags; bool is_l2 = false; u32 regval; @@ -996,20 +997,20 @@ static int ixgbe_ptp_set_timestamp_mode(struct ixgbe_adapter *adapter, case HWTSTAMP_FILTER_NONE: tsync_rx_ctl = 0; tsync_rx_mtrl = 0; - adapter->flags &= ~(IXGBE_FLAG_RX_HWTSTAMP_ENABLED | - IXGBE_FLAG_RX_HWTSTAMP_IN_REGISTER); + aflags &= ~(IXGBE_FLAG_RX_HWTSTAMP_ENABLED | + IXGBE_FLAG_RX_HWTSTAMP_IN_REGISTER); break; case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: tsync_rx_ctl |= IXGBE_TSYNCRXCTL_TYPE_L4_V1; tsync_rx_mtrl |= IXGBE_RXMTRL_V1_SYNC_MSG; - adapter->flags |= (IXGBE_FLAG_RX_HWTSTAMP_ENABLED | - IXGBE_FLAG_RX_HWTSTAMP_IN_REGISTER); + aflags |= (IXGBE_FLAG_RX_HWTSTAMP_ENABLED | + IXGBE_FLAG_RX_HWTSTAMP_IN_REGISTER); break; case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: tsync_rx_ctl |= IXGBE_TSYNCRXCTL_TYPE_L4_V1; tsync_rx_mtrl |= IXGBE_RXMTRL_V1_DELAY_REQ_MSG; - adapter->flags |= (IXGBE_FLAG_RX_HWTSTAMP_ENABLED | - IXGBE_FLAG_RX_HWTSTAMP_IN_REGISTER); + aflags |= (IXGBE_FLAG_RX_HWTSTAMP_ENABLED | + IXGBE_FLAG_RX_HWTSTAMP_IN_REGISTER); break; case HWTSTAMP_FILTER_PTP_V2_EVENT: case HWTSTAMP_FILTER_PTP_V2_L2_EVENT: @@ -1023,8 +1024,8 @@ static int ixgbe_ptp_set_timestamp_mode(struct ixgbe_adapter *adapter, tsync_rx_ctl |= IXGBE_TSYNCRXCTL_TYPE_EVENT_V2; is_l2 = true; config->rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT; - adapter->flags |= (IXGBE_FLAG_RX_HWTSTAMP_ENABLED | - IXGBE_FLAG_RX_HWTSTAMP_IN_REGISTER); + aflags |= (IXGBE_FLAG_RX_HWTSTAMP_ENABLED | + IXGBE_FLAG_RX_HWTSTAMP_IN_REGISTER); break; case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: case HWTSTAMP_FILTER_NTP_ALL: @@ -1035,7 +1036,7 @@ static int ixgbe_ptp_set_timestamp_mode(struct ixgbe_adapter *adapter, if (hw->mac.type >= ixgbe_mac_X550) { tsync_rx_ctl |= IXGBE_TSYNCRXCTL_TYPE_ALL; config->rx_filter = HWTSTAMP_FILTER_ALL; - adapter->flags |= IXGBE_FLAG_RX_HWTSTAMP_ENABLED; + aflags |= IXGBE_FLAG_RX_HWTSTAMP_ENABLED; break; } fallthrough; @@ -1046,8 +1047,6 @@ static int ixgbe_ptp_set_timestamp_mode(struct ixgbe_adapter *adapter, * Delay_Req messages and hardware does not support * timestamping all packets => return error */ - adapter->flags &= ~(IXGBE_FLAG_RX_HWTSTAMP_ENABLED | - IXGBE_FLAG_RX_HWTSTAMP_IN_REGISTER); config->rx_filter = HWTSTAMP_FILTER_NONE; return -ERANGE; } @@ -1079,8 +1078,8 @@ static int ixgbe_ptp_set_timestamp_mode(struct ixgbe_adapter *adapter, IXGBE_TSYNCRXCTL_TYPE_ALL | IXGBE_TSYNCRXCTL_TSIP_UT_EN; config->rx_filter = HWTSTAMP_FILTER_ALL; - adapter->flags |= IXGBE_FLAG_RX_HWTSTAMP_ENABLED; - adapter->flags &= ~IXGBE_FLAG_RX_HWTSTAMP_IN_REGISTER; + aflags |= IXGBE_FLAG_RX_HWTSTAMP_ENABLED; + aflags &= ~IXGBE_FLAG_RX_HWTSTAMP_IN_REGISTER; is_l2 = true; break; default: @@ -1113,6 +1112,9 @@ static int ixgbe_ptp_set_timestamp_mode(struct ixgbe_adapter *adapter, IXGBE_WRITE_FLUSH(hw); + /* configure adapter flags only when HW is actually configured */ + adapter->flags = aflags; + /* clear TX/RX time stamp registers, just to be sure */ ixgbe_ptp_clear_tx_timestamp(adapter); IXGBE_READ_REG(hw, IXGBE_RXSTMPH); diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c index eb74ccddb440..21c3f9b015c8 100644 --- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c +++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c @@ -5586,6 +5586,11 @@ static int mvpp2_ethtool_get_rxnfc(struct net_device *dev, break; case ETHTOOL_GRXCLSRLALL: for (i = 0; i < MVPP2_N_RFS_ENTRIES_PER_FLOW; i++) { + if (loc == info->rule_cnt) { + ret = -EMSGSIZE; + break; + } + if (port->rfs_rules[i]) rules[loc++] = i; } diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_main.c b/drivers/net/ethernet/marvell/octeon_ep/octep_main.c index 4424de2ffd70..dbc518ff8276 100644 --- a/drivers/net/ethernet/marvell/octeon_ep/octep_main.c +++ b/drivers/net/ethernet/marvell/octeon_ep/octep_main.c @@ -734,13 +734,13 @@ static netdev_tx_t octep_start_xmit(struct sk_buff *skb, dma_map_sg_err: if (si > 0) { dma_unmap_single(iq->dev, sglist[0].dma_ptr[0], - sglist[0].len[0], DMA_TO_DEVICE); - sglist[0].len[0] = 0; + sglist[0].len[3], DMA_TO_DEVICE); + sglist[0].len[3] = 0; } while (si > 1) { dma_unmap_page(iq->dev, sglist[si >> 2].dma_ptr[si & 3], - sglist[si >> 2].len[si & 3], DMA_TO_DEVICE); - sglist[si >> 2].len[si & 3] = 0; + sglist[si >> 2].len[3 - (si & 3)], DMA_TO_DEVICE); + sglist[si >> 2].len[3 - (si & 3)] = 0; si--; } tx_buffer->gather = 0; diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_tx.c b/drivers/net/ethernet/marvell/octeon_ep/octep_tx.c index 5a520d37bea0..d0adb82d65c3 100644 --- a/drivers/net/ethernet/marvell/octeon_ep/octep_tx.c +++ b/drivers/net/ethernet/marvell/octeon_ep/octep_tx.c @@ -69,12 +69,12 @@ int octep_iq_process_completions(struct octep_iq *iq, u16 budget) compl_sg++; dma_unmap_single(iq->dev, tx_buffer->sglist[0].dma_ptr[0], - tx_buffer->sglist[0].len[0], DMA_TO_DEVICE); + tx_buffer->sglist[0].len[3], DMA_TO_DEVICE); i = 1; /* entry 0 is main skb, unmapped above */ while (frags--) { dma_unmap_page(iq->dev, tx_buffer->sglist[i >> 2].dma_ptr[i & 3], - tx_buffer->sglist[i >> 2].len[i & 3], DMA_TO_DEVICE); + tx_buffer->sglist[i >> 2].len[3 - (i & 3)], DMA_TO_DEVICE); i++; } @@ -131,13 +131,13 @@ static void octep_iq_free_pending(struct octep_iq *iq) dma_unmap_single(iq->dev, tx_buffer->sglist[0].dma_ptr[0], - tx_buffer->sglist[0].len[0], + tx_buffer->sglist[0].len[3], DMA_TO_DEVICE); i = 1; /* entry 0 is main skb, unmapped above */ while (frags--) { dma_unmap_page(iq->dev, tx_buffer->sglist[i >> 2].dma_ptr[i & 3], - tx_buffer->sglist[i >> 2].len[i & 3], DMA_TO_DEVICE); + tx_buffer->sglist[i >> 2].len[3 - (i & 3)], DMA_TO_DEVICE); i++; } diff --git a/drivers/net/ethernet/marvell/octeon_ep/octep_tx.h b/drivers/net/ethernet/marvell/octeon_ep/octep_tx.h index 2ef57980eb47..21e75ff9f5e7 100644 --- a/drivers/net/ethernet/marvell/octeon_ep/octep_tx.h +++ b/drivers/net/ethernet/marvell/octeon_ep/octep_tx.h @@ -17,7 +17,21 @@ #define TX_BUFTYPE_NET_SG 2 #define NUM_TX_BUFTYPES 3 -/* Hardware format for Scatter/Gather list */ +/* Hardware format for Scatter/Gather list + * + * 63 48|47 32|31 16|15 0 + * ----------------------------------------- + * | Len 0 | Len 1 | Len 2 | Len 3 | + * ----------------------------------------- + * | Ptr 0 | + * ----------------------------------------- + * | Ptr 1 | + * ----------------------------------------- + * | Ptr 2 | + * ----------------------------------------- + * | Ptr 3 | + * ----------------------------------------- + */ struct octep_tx_sglist_desc { u16 len[4]; dma_addr_t dma_ptr[4]; diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/cn10k.c b/drivers/net/ethernet/marvell/octeontx2/nic/cn10k.c index 826f691de259..a4a258da8dd5 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/cn10k.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/cn10k.c @@ -107,12 +107,13 @@ int cn10k_sq_aq_init(void *dev, u16 qidx, u16 sqb_aura) } #define NPA_MAX_BURST 16 -void cn10k_refill_pool_ptrs(void *dev, struct otx2_cq_queue *cq) +int cn10k_refill_pool_ptrs(void *dev, struct otx2_cq_queue *cq) { struct otx2_nic *pfvf = dev; + int cnt = cq->pool_ptrs; u64 ptrs[NPA_MAX_BURST]; - int num_ptrs = 1; dma_addr_t bufptr; + int num_ptrs = 1; /* Refill pool with new buffers */ while (cq->pool_ptrs) { @@ -131,6 +132,7 @@ void cn10k_refill_pool_ptrs(void *dev, struct otx2_cq_queue *cq) num_ptrs = 1; } } + return cnt - cq->pool_ptrs; } void cn10k_sqe_flush(void *dev, struct otx2_snd_queue *sq, int size, int qidx) diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/cn10k.h b/drivers/net/ethernet/marvell/octeontx2/nic/cn10k.h index 8ae96815865e..c1861f7de254 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/cn10k.h +++ b/drivers/net/ethernet/marvell/octeontx2/nic/cn10k.h @@ -24,7 +24,7 @@ static inline int mtu_to_dwrr_weight(struct otx2_nic *pfvf, int mtu) return weight; } -void cn10k_refill_pool_ptrs(void *dev, struct otx2_cq_queue *cq); +int cn10k_refill_pool_ptrs(void *dev, struct otx2_cq_queue *cq); void cn10k_sqe_flush(void *dev, struct otx2_snd_queue *sq, int size, int qidx); int cn10k_sq_aq_init(void *dev, u16 qidx, u16 sqb_aura); int cn10k_lmtst_init(struct otx2_nic *pfvf); diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c index 8511906cb4e2..997fedac3a98 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.c @@ -574,20 +574,8 @@ int otx2_alloc_rbuf(struct otx2_nic *pfvf, struct otx2_pool *pool, int otx2_alloc_buffer(struct otx2_nic *pfvf, struct otx2_cq_queue *cq, dma_addr_t *dma) { - if (unlikely(__otx2_alloc_rbuf(pfvf, cq->rbpool, dma))) { - struct refill_work *work; - struct delayed_work *dwork; - - work = &pfvf->refill_wrk[cq->cq_idx]; - dwork = &work->pool_refill_work; - /* Schedule a task if no other task is running */ - if (!cq->refill_task_sched) { - cq->refill_task_sched = true; - schedule_delayed_work(dwork, - msecs_to_jiffies(100)); - } + if (unlikely(__otx2_alloc_rbuf(pfvf, cq->rbpool, dma))) return -ENOMEM; - } return 0; } @@ -1082,39 +1070,20 @@ static int otx2_cq_init(struct otx2_nic *pfvf, u16 qidx) static void otx2_pool_refill_task(struct work_struct *work) { struct otx2_cq_queue *cq; - struct otx2_pool *rbpool; struct refill_work *wrk; - int qidx, free_ptrs = 0; struct otx2_nic *pfvf; - dma_addr_t bufptr; + int qidx; wrk = container_of(work, struct refill_work, pool_refill_work.work); pfvf = wrk->pf; qidx = wrk - pfvf->refill_wrk; cq = &pfvf->qset.cq[qidx]; - rbpool = cq->rbpool; - free_ptrs = cq->pool_ptrs; - while (cq->pool_ptrs) { - if (otx2_alloc_rbuf(pfvf, rbpool, &bufptr)) { - /* Schedule a WQ if we fails to free atleast half of the - * pointers else enable napi for this RQ. - */ - if (!((free_ptrs - cq->pool_ptrs) > free_ptrs / 2)) { - struct delayed_work *dwork; - - dwork = &wrk->pool_refill_work; - schedule_delayed_work(dwork, - msecs_to_jiffies(100)); - } else { - cq->refill_task_sched = false; - } - return; - } - pfvf->hw_ops->aura_freeptr(pfvf, qidx, bufptr + OTX2_HEAD_ROOM); - cq->pool_ptrs--; - } cq->refill_task_sched = false; + + local_bh_disable(); + napi_schedule(wrk->napi); + local_bh_enable(); } int otx2_config_nix_queues(struct otx2_nic *pfvf) diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h index 4c6032ee7800..c04a8ee53a82 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_common.h @@ -302,6 +302,7 @@ struct flr_work { struct refill_work { struct delayed_work pool_refill_work; struct otx2_nic *pf; + struct napi_struct *napi; }; /* PTPv2 originTimestamp structure */ @@ -370,7 +371,7 @@ struct dev_hw_ops { int (*sq_aq_init)(void *dev, u16 qidx, u16 sqb_aura); void (*sqe_flush)(void *dev, struct otx2_snd_queue *sq, int size, int qidx); - void (*refill_pool_ptrs)(void *dev, struct otx2_cq_queue *cq); + int (*refill_pool_ptrs)(void *dev, struct otx2_cq_queue *cq); void (*aura_freeptr)(void *dev, int aura, u64 buf); }; diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c index 70b9065f7d10..6daf4d58c25d 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c @@ -1943,6 +1943,10 @@ int otx2_stop(struct net_device *netdev) netif_tx_disable(netdev); + for (wrk = 0; wrk < pf->qset.cq_cnt; wrk++) + cancel_delayed_work_sync(&pf->refill_wrk[wrk].pool_refill_work); + devm_kfree(pf->dev, pf->refill_wrk); + otx2_free_hw_resources(pf); otx2_free_cints(pf, pf->hw.cint_cnt); otx2_disable_napi(pf); @@ -1950,9 +1954,6 @@ int otx2_stop(struct net_device *netdev) for (qidx = 0; qidx < netdev->num_tx_queues; qidx++) netdev_tx_reset_queue(netdev_get_tx_queue(netdev, qidx)); - for (wrk = 0; wrk < pf->qset.cq_cnt; wrk++) - cancel_delayed_work_sync(&pf->refill_wrk[wrk].pool_refill_work); - devm_kfree(pf->dev, pf->refill_wrk); kfree(qset->sq); kfree(qset->cq); diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.c b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.c index e369baf11530..53b2a4ef5298 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.c +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.c @@ -29,7 +29,8 @@ static bool otx2_xdp_rcv_pkt_handler(struct otx2_nic *pfvf, struct bpf_prog *prog, struct nix_cqe_rx_s *cqe, - struct otx2_cq_queue *cq); + struct otx2_cq_queue *cq, + bool *need_xdp_flush); static int otx2_nix_cq_op_status(struct otx2_nic *pfvf, struct otx2_cq_queue *cq) @@ -337,7 +338,7 @@ static bool otx2_check_rcv_errors(struct otx2_nic *pfvf, static void otx2_rcv_pkt_handler(struct otx2_nic *pfvf, struct napi_struct *napi, struct otx2_cq_queue *cq, - struct nix_cqe_rx_s *cqe) + struct nix_cqe_rx_s *cqe, bool *need_xdp_flush) { struct nix_rx_parse_s *parse = &cqe->parse; struct nix_rx_sg_s *sg = &cqe->sg; @@ -353,7 +354,7 @@ static void otx2_rcv_pkt_handler(struct otx2_nic *pfvf, } if (pfvf->xdp_prog) - if (otx2_xdp_rcv_pkt_handler(pfvf, pfvf->xdp_prog, cqe, cq)) + if (otx2_xdp_rcv_pkt_handler(pfvf, pfvf->xdp_prog, cqe, cq, need_xdp_flush)) return; skb = napi_get_frags(napi); @@ -388,6 +389,7 @@ static int otx2_rx_napi_handler(struct otx2_nic *pfvf, struct napi_struct *napi, struct otx2_cq_queue *cq, int budget) { + bool need_xdp_flush = false; struct nix_cqe_rx_s *cqe; int processed_cqe = 0; @@ -409,13 +411,15 @@ process_cqe: cq->cq_head++; cq->cq_head &= (cq->cqe_cnt - 1); - otx2_rcv_pkt_handler(pfvf, napi, cq, cqe); + otx2_rcv_pkt_handler(pfvf, napi, cq, cqe, &need_xdp_flush); cqe->hdr.cqe_type = NIX_XQE_TYPE_INVALID; cqe->sg.seg_addr = 0x00; processed_cqe++; cq->pend_cqe--; } + if (need_xdp_flush) + xdp_do_flush(); /* Free CQEs to HW */ otx2_write64(pfvf, NIX_LF_CQ_OP_DOOR, @@ -424,9 +428,10 @@ process_cqe: return processed_cqe; } -void otx2_refill_pool_ptrs(void *dev, struct otx2_cq_queue *cq) +int otx2_refill_pool_ptrs(void *dev, struct otx2_cq_queue *cq) { struct otx2_nic *pfvf = dev; + int cnt = cq->pool_ptrs; dma_addr_t bufptr; while (cq->pool_ptrs) { @@ -435,6 +440,8 @@ void otx2_refill_pool_ptrs(void *dev, struct otx2_cq_queue *cq) otx2_aura_freeptr(pfvf, cq->cq_idx, bufptr + OTX2_HEAD_ROOM); cq->pool_ptrs--; } + + return cnt - cq->pool_ptrs; } static int otx2_tx_napi_handler(struct otx2_nic *pfvf, @@ -521,6 +528,7 @@ int otx2_napi_handler(struct napi_struct *napi, int budget) struct otx2_cq_queue *cq; struct otx2_qset *qset; struct otx2_nic *pfvf; + int filled_cnt = -1; cq_poll = container_of(napi, struct otx2_cq_poll, napi); pfvf = (struct otx2_nic *)cq_poll->dev; @@ -541,7 +549,7 @@ int otx2_napi_handler(struct napi_struct *napi, int budget) } if (rx_cq && rx_cq->pool_ptrs) - pfvf->hw_ops->refill_pool_ptrs(pfvf, rx_cq); + filled_cnt = pfvf->hw_ops->refill_pool_ptrs(pfvf, rx_cq); /* Clear the IRQ */ otx2_write64(pfvf, NIX_LF_CINTX_INT(cq_poll->cint_idx), BIT_ULL(0)); @@ -561,9 +569,25 @@ int otx2_napi_handler(struct napi_struct *napi, int budget) otx2_config_irq_coalescing(pfvf, i); } - /* Re-enable interrupts */ - otx2_write64(pfvf, NIX_LF_CINTX_ENA_W1S(cq_poll->cint_idx), - BIT_ULL(0)); + if (unlikely(!filled_cnt)) { + struct refill_work *work; + struct delayed_work *dwork; + + work = &pfvf->refill_wrk[cq->cq_idx]; + dwork = &work->pool_refill_work; + /* Schedule a task if no other task is running */ + if (!cq->refill_task_sched) { + work->napi = napi; + cq->refill_task_sched = true; + schedule_delayed_work(dwork, + msecs_to_jiffies(100)); + } + } else { + /* Re-enable interrupts */ + otx2_write64(pfvf, + NIX_LF_CINTX_ENA_W1S(cq_poll->cint_idx), + BIT_ULL(0)); + } } return workdone; } @@ -1334,7 +1358,8 @@ bool otx2_xdp_sq_append_pkt(struct otx2_nic *pfvf, u64 iova, int len, u16 qidx) static bool otx2_xdp_rcv_pkt_handler(struct otx2_nic *pfvf, struct bpf_prog *prog, struct nix_cqe_rx_s *cqe, - struct otx2_cq_queue *cq) + struct otx2_cq_queue *cq, + bool *need_xdp_flush) { unsigned char *hard_start, *data; int qidx = cq->cq_idx; @@ -1371,8 +1396,10 @@ static bool otx2_xdp_rcv_pkt_handler(struct otx2_nic *pfvf, otx2_dma_unmap_page(pfvf, iova, pfvf->rbsize, DMA_FROM_DEVICE); - if (!err) + if (!err) { + *need_xdp_flush = true; return true; + } put_page(page); break; default: diff --git a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.h b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.h index 9e3bfbe5c480..a82ffca8ce1b 100644 --- a/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.h +++ b/drivers/net/ethernet/marvell/octeontx2/nic/otx2_txrx.h @@ -170,6 +170,6 @@ void cn10k_sqe_flush(void *dev, struct otx2_snd_queue *sq, int size, int qidx); void otx2_sqe_flush(void *dev, struct otx2_snd_queue *sq, int size, int qidx); -void otx2_refill_pool_ptrs(void *dev, struct otx2_cq_queue *cq); -void cn10k_refill_pool_ptrs(void *dev, struct otx2_cq_queue *cq); +int otx2_refill_pool_ptrs(void *dev, struct otx2_cq_queue *cq); +int cn10k_refill_pool_ptrs(void *dev, struct otx2_cq_queue *cq); #endif /* OTX2_TXRX_H */ diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c index 6ad42e3b488f..3cffd1bd3067 100644 --- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c +++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c @@ -2005,11 +2005,11 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget, u8 *data, *new_data; struct mtk_rx_dma_v2 *rxd, trxd; int done = 0, bytes = 0; + dma_addr_t dma_addr = DMA_MAPPING_ERROR; while (done < budget) { unsigned int pktlen, *rxdcsum; struct net_device *netdev; - dma_addr_t dma_addr; u32 hash, reason; int mac = 0; @@ -2186,7 +2186,8 @@ release_desc: else rxd->rxd2 = RX_DMA_PREP_PLEN0(ring->buf_size); - if (MTK_HAS_CAPS(eth->soc->caps, MTK_36BIT_DMA)) + if (MTK_HAS_CAPS(eth->soc->caps, MTK_36BIT_DMA) && + likely(dma_addr != DMA_MAPPING_ERROR)) rxd->rxd2 |= RX_DMA_PREP_ADDR64(dma_addr); ring->calc_idx = idx; @@ -2994,6 +2995,9 @@ static int mtk_hwlro_get_fdir_all(struct net_device *dev, int i; for (i = 0; i < MTK_MAX_LRO_IP_CNT; i++) { + if (cnt == cmd->rule_cnt) + return -EMSGSIZE; + if (mac->hwlro_ip[i]) { rule_locs[cnt] = i; cnt++; diff --git a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c index a70a5417c173..a4efbeb16208 100644 --- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c +++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c @@ -214,9 +214,11 @@ mtk_flow_set_output_device(struct mtk_eth *eth, struct mtk_foe_entry *foe, dsa_port = mtk_flow_get_dsa_port(&dev); if (dev == eth->netdev[0]) - pse_port = 1; + pse_port = PSE_GDM1_PORT; else if (dev == eth->netdev[1]) - pse_port = 2; + pse_port = PSE_GDM2_PORT; + else if (dev == eth->netdev[2]) + pse_port = PSE_GDM3_PORT; else return -EOPNOTSUPP; diff --git a/drivers/net/ethernet/microchip/vcap/vcap_api.c b/drivers/net/ethernet/microchip/vcap/vcap_api.c index 300fe1a93dce..ef980e4e5bc2 100644 --- a/drivers/net/ethernet/microchip/vcap/vcap_api.c +++ b/drivers/net/ethernet/microchip/vcap/vcap_api.c @@ -1021,18 +1021,32 @@ static struct vcap_rule_internal *vcap_dup_rule(struct vcap_rule_internal *ri, list_for_each_entry(ckf, &ri->data.keyfields, ctrl.list) { newckf = kmemdup(ckf, sizeof(*newckf), GFP_KERNEL); if (!newckf) - return ERR_PTR(-ENOMEM); + goto err; list_add_tail(&newckf->ctrl.list, &duprule->data.keyfields); } list_for_each_entry(caf, &ri->data.actionfields, ctrl.list) { newcaf = kmemdup(caf, sizeof(*newcaf), GFP_KERNEL); if (!newcaf) - return ERR_PTR(-ENOMEM); + goto err; list_add_tail(&newcaf->ctrl.list, &duprule->data.actionfields); } return duprule; + +err: + list_for_each_entry_safe(ckf, newckf, &duprule->data.keyfields, ctrl.list) { + list_del(&ckf->ctrl.list); + kfree(ckf); + } + + list_for_each_entry_safe(caf, newcaf, &duprule->data.actionfields, ctrl.list) { + list_del(&caf->ctrl.list); + kfree(caf); + } + + kfree(duprule); + return ERR_PTR(-ENOMEM); } static void vcap_apply_width(u8 *dst, int width, int bytes) diff --git a/drivers/net/ethernet/microchip/vcap/vcap_api_kunit.c b/drivers/net/ethernet/microchip/vcap/vcap_api_kunit.c index c07f25e791c7..fe4e166de8a0 100644 --- a/drivers/net/ethernet/microchip/vcap/vcap_api_kunit.c +++ b/drivers/net/ethernet/microchip/vcap/vcap_api_kunit.c @@ -243,10 +243,9 @@ static void vcap_test_api_init(struct vcap_admin *admin) } /* Helper function to create a rule of a specific size */ -static struct vcap_rule * -test_vcap_xn_rule_creator(struct kunit *test, int cid, enum vcap_user user, - u16 priority, - int id, int size, int expected_addr) +static void test_vcap_xn_rule_creator(struct kunit *test, int cid, + enum vcap_user user, u16 priority, + int id, int size, int expected_addr) { struct vcap_rule *rule; struct vcap_rule_internal *ri; @@ -311,7 +310,7 @@ test_vcap_xn_rule_creator(struct kunit *test, int cid, enum vcap_user user, ret = vcap_add_rule(rule); KUNIT_EXPECT_EQ(test, 0, ret); KUNIT_EXPECT_EQ(test, expected_addr, ri->addr); - return rule; + vcap_free_rule(rule); } /* Prepare testing rule deletion */ @@ -995,6 +994,16 @@ static void vcap_api_encode_rule_actionset_test(struct kunit *test) KUNIT_EXPECT_EQ(test, (u32)0x00000000, actwords[11]); } +static void vcap_free_ckf(struct vcap_rule *rule) +{ + struct vcap_client_keyfield *ckf, *next_ckf; + + list_for_each_entry_safe(ckf, next_ckf, &rule->keyfields, ctrl.list) { + list_del(&ckf->ctrl.list); + kfree(ckf); + } +} + static void vcap_api_rule_add_keyvalue_test(struct kunit *test) { struct vcap_admin admin = { @@ -1027,6 +1036,7 @@ static void vcap_api_rule_add_keyvalue_test(struct kunit *test) KUNIT_EXPECT_EQ(test, VCAP_FIELD_BIT, kf->ctrl.type); KUNIT_EXPECT_EQ(test, 0x0, kf->data.u1.value); KUNIT_EXPECT_EQ(test, 0x1, kf->data.u1.mask); + vcap_free_ckf(rule); INIT_LIST_HEAD(&rule->keyfields); ret = vcap_rule_add_key_bit(rule, VCAP_KF_LOOKUP_FIRST_IS, VCAP_BIT_1); @@ -1039,6 +1049,7 @@ static void vcap_api_rule_add_keyvalue_test(struct kunit *test) KUNIT_EXPECT_EQ(test, VCAP_FIELD_BIT, kf->ctrl.type); KUNIT_EXPECT_EQ(test, 0x1, kf->data.u1.value); KUNIT_EXPECT_EQ(test, 0x1, kf->data.u1.mask); + vcap_free_ckf(rule); INIT_LIST_HEAD(&rule->keyfields); ret = vcap_rule_add_key_bit(rule, VCAP_KF_LOOKUP_FIRST_IS, @@ -1052,6 +1063,7 @@ static void vcap_api_rule_add_keyvalue_test(struct kunit *test) KUNIT_EXPECT_EQ(test, VCAP_FIELD_BIT, kf->ctrl.type); KUNIT_EXPECT_EQ(test, 0x0, kf->data.u1.value); KUNIT_EXPECT_EQ(test, 0x0, kf->data.u1.mask); + vcap_free_ckf(rule); INIT_LIST_HEAD(&rule->keyfields); ret = vcap_rule_add_key_u32(rule, VCAP_KF_TYPE, 0x98765432, 0xff00ffab); @@ -1064,6 +1076,7 @@ static void vcap_api_rule_add_keyvalue_test(struct kunit *test) KUNIT_EXPECT_EQ(test, VCAP_FIELD_U32, kf->ctrl.type); KUNIT_EXPECT_EQ(test, 0x98765432, kf->data.u32.value); KUNIT_EXPECT_EQ(test, 0xff00ffab, kf->data.u32.mask); + vcap_free_ckf(rule); INIT_LIST_HEAD(&rule->keyfields); ret = vcap_rule_add_key_u128(rule, VCAP_KF_L3_IP6_SIP, &dip); @@ -1078,6 +1091,18 @@ static void vcap_api_rule_add_keyvalue_test(struct kunit *test) KUNIT_EXPECT_EQ(test, dip.value[idx], kf->data.u128.value[idx]); for (idx = 0; idx < ARRAY_SIZE(dip.mask); ++idx) KUNIT_EXPECT_EQ(test, dip.mask[idx], kf->data.u128.mask[idx]); + vcap_free_ckf(rule); +} + +static void vcap_free_caf(struct vcap_rule *rule) +{ + struct vcap_client_actionfield *caf, *next_caf; + + list_for_each_entry_safe(caf, next_caf, + &rule->actionfields, ctrl.list) { + list_del(&caf->ctrl.list); + kfree(caf); + } } static void vcap_api_rule_add_actionvalue_test(struct kunit *test) @@ -1105,6 +1130,7 @@ static void vcap_api_rule_add_actionvalue_test(struct kunit *test) KUNIT_EXPECT_EQ(test, VCAP_AF_POLICE_ENA, af->ctrl.action); KUNIT_EXPECT_EQ(test, VCAP_FIELD_BIT, af->ctrl.type); KUNIT_EXPECT_EQ(test, 0x0, af->data.u1.value); + vcap_free_caf(rule); INIT_LIST_HEAD(&rule->actionfields); ret = vcap_rule_add_action_bit(rule, VCAP_AF_POLICE_ENA, VCAP_BIT_1); @@ -1116,6 +1142,7 @@ static void vcap_api_rule_add_actionvalue_test(struct kunit *test) KUNIT_EXPECT_EQ(test, VCAP_AF_POLICE_ENA, af->ctrl.action); KUNIT_EXPECT_EQ(test, VCAP_FIELD_BIT, af->ctrl.type); KUNIT_EXPECT_EQ(test, 0x1, af->data.u1.value); + vcap_free_caf(rule); INIT_LIST_HEAD(&rule->actionfields); ret = vcap_rule_add_action_bit(rule, VCAP_AF_POLICE_ENA, VCAP_BIT_ANY); @@ -1127,6 +1154,7 @@ static void vcap_api_rule_add_actionvalue_test(struct kunit *test) KUNIT_EXPECT_EQ(test, VCAP_AF_POLICE_ENA, af->ctrl.action); KUNIT_EXPECT_EQ(test, VCAP_FIELD_BIT, af->ctrl.type); KUNIT_EXPECT_EQ(test, 0x0, af->data.u1.value); + vcap_free_caf(rule); INIT_LIST_HEAD(&rule->actionfields); ret = vcap_rule_add_action_u32(rule, VCAP_AF_TYPE, 0x98765432); @@ -1138,6 +1166,7 @@ static void vcap_api_rule_add_actionvalue_test(struct kunit *test) KUNIT_EXPECT_EQ(test, VCAP_AF_TYPE, af->ctrl.action); KUNIT_EXPECT_EQ(test, VCAP_FIELD_U32, af->ctrl.type); KUNIT_EXPECT_EQ(test, 0x98765432, af->data.u32.value); + vcap_free_caf(rule); INIT_LIST_HEAD(&rule->actionfields); ret = vcap_rule_add_action_u32(rule, VCAP_AF_MASK_MODE, 0xaabbccdd); @@ -1149,6 +1178,7 @@ static void vcap_api_rule_add_actionvalue_test(struct kunit *test) KUNIT_EXPECT_EQ(test, VCAP_AF_MASK_MODE, af->ctrl.action); KUNIT_EXPECT_EQ(test, VCAP_FIELD_U32, af->ctrl.type); KUNIT_EXPECT_EQ(test, 0xaabbccdd, af->data.u32.value); + vcap_free_caf(rule); } static void vcap_api_rule_find_keyset_basic_test(struct kunit *test) @@ -1408,6 +1438,10 @@ static void vcap_api_encode_rule_test(struct kunit *test) ret = list_empty(&is2_admin.rules); KUNIT_EXPECT_EQ(test, false, ret); KUNIT_EXPECT_EQ(test, 0, ret); + + vcap_enable_lookups(&test_vctrl, &test_netdev, 0, 0, + rule->cookie, false); + vcap_free_rule(rule); /* Check that the rule has been freed: tricky to access since this @@ -1418,6 +1452,8 @@ static void vcap_api_encode_rule_test(struct kunit *test) KUNIT_EXPECT_EQ(test, true, ret); ret = list_empty(&rule->actionfields); KUNIT_EXPECT_EQ(test, true, ret); + + vcap_del_rule(&test_vctrl, &test_netdev, id); } static void vcap_api_set_rule_counter_test(struct kunit *test) @@ -1561,6 +1597,11 @@ static void vcap_api_rule_insert_in_order_test(struct kunit *test) test_vcap_xn_rule_creator(test, 10000, VCAP_USER_QOS, 20, 400, 6, 774); test_vcap_xn_rule_creator(test, 10000, VCAP_USER_QOS, 30, 300, 3, 771); test_vcap_xn_rule_creator(test, 10000, VCAP_USER_QOS, 40, 200, 2, 768); + + vcap_del_rule(&test_vctrl, &test_netdev, 200); + vcap_del_rule(&test_vctrl, &test_netdev, 300); + vcap_del_rule(&test_vctrl, &test_netdev, 400); + vcap_del_rule(&test_vctrl, &test_netdev, 500); } static void vcap_api_rule_insert_reverse_order_test(struct kunit *test) @@ -1619,6 +1660,11 @@ static void vcap_api_rule_insert_reverse_order_test(struct kunit *test) ++idx; } KUNIT_EXPECT_EQ(test, 768, admin.last_used_addr); + + vcap_del_rule(&test_vctrl, &test_netdev, 500); + vcap_del_rule(&test_vctrl, &test_netdev, 400); + vcap_del_rule(&test_vctrl, &test_netdev, 300); + vcap_del_rule(&test_vctrl, &test_netdev, 200); } static void vcap_api_rule_remove_at_end_test(struct kunit *test) @@ -1819,6 +1865,9 @@ static void vcap_api_rule_remove_in_front_test(struct kunit *test) KUNIT_EXPECT_EQ(test, 786, test_init_start); KUNIT_EXPECT_EQ(test, 8, test_init_count); KUNIT_EXPECT_EQ(test, 794, admin.last_used_addr); + + vcap_del_rule(&test_vctrl, &test_netdev, 200); + vcap_del_rule(&test_vctrl, &test_netdev, 300); } static struct kunit_case vcap_api_rule_remove_test_cases[] = { diff --git a/drivers/net/ethernet/pensando/ionic/ionic_dev.h b/drivers/net/ethernet/pensando/ionic/ionic_dev.h index 6aac98bcb9f4..aae4131f146a 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_dev.h +++ b/drivers/net/ethernet/pensando/ionic/ionic_dev.h @@ -187,6 +187,7 @@ typedef void (*ionic_desc_cb)(struct ionic_queue *q, struct ionic_desc_info *desc_info, struct ionic_cq_info *cq_info, void *cb_arg); +#define IONIC_MAX_BUF_LEN ((u16)-1) #define IONIC_PAGE_SIZE PAGE_SIZE #define IONIC_PAGE_SPLIT_SZ (PAGE_SIZE / 2) #define IONIC_PAGE_GFP_MASK (GFP_ATOMIC | __GFP_NOWARN |\ diff --git a/drivers/net/ethernet/pensando/ionic/ionic_txrx.c b/drivers/net/ethernet/pensando/ionic/ionic_txrx.c index 26798fc635db..44466e8c5d77 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_txrx.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_txrx.c @@ -207,7 +207,8 @@ static struct sk_buff *ionic_rx_frags(struct ionic_queue *q, return NULL; } - frag_len = min_t(u16, len, IONIC_PAGE_SIZE - buf_info->page_offset); + frag_len = min_t(u16, len, min_t(u32, IONIC_MAX_BUF_LEN, + IONIC_PAGE_SIZE - buf_info->page_offset)); len -= frag_len; dma_sync_single_for_cpu(dev, @@ -452,7 +453,8 @@ void ionic_rx_fill(struct ionic_queue *q) /* fill main descriptor - buf[0] */ desc->addr = cpu_to_le64(buf_info->dma_addr + buf_info->page_offset); - frag_len = min_t(u16, len, IONIC_PAGE_SIZE - buf_info->page_offset); + frag_len = min_t(u16, len, min_t(u32, IONIC_MAX_BUF_LEN, + IONIC_PAGE_SIZE - buf_info->page_offset)); desc->len = cpu_to_le16(frag_len); remain_len -= frag_len; buf_info++; @@ -471,7 +473,9 @@ void ionic_rx_fill(struct ionic_queue *q) } sg_elem->addr = cpu_to_le64(buf_info->dma_addr + buf_info->page_offset); - frag_len = min_t(u16, remain_len, IONIC_PAGE_SIZE - buf_info->page_offset); + frag_len = min_t(u16, remain_len, min_t(u32, IONIC_MAX_BUF_LEN, + IONIC_PAGE_SIZE - + buf_info->page_offset)); sg_elem->len = cpu_to_le16(frag_len); remain_len -= frag_len; buf_info++; diff --git a/drivers/net/ethernet/renesas/rswitch.c b/drivers/net/ethernet/renesas/rswitch.c index 6083b1c8e4fb..ea9186178091 100644 --- a/drivers/net/ethernet/renesas/rswitch.c +++ b/drivers/net/ethernet/renesas/rswitch.c @@ -799,6 +799,7 @@ static int rswitch_poll(struct napi_struct *napi, int budget) struct net_device *ndev = napi->dev; struct rswitch_private *priv; struct rswitch_device *rdev; + unsigned long flags; int quota = budget; rdev = netdev_priv(ndev); @@ -816,10 +817,12 @@ retry: netif_wake_subqueue(ndev, 0); - napi_complete(napi); - - rswitch_enadis_data_irq(priv, rdev->tx_queue->index, true); - rswitch_enadis_data_irq(priv, rdev->rx_queue->index, true); + if (napi_complete_done(napi, budget - quota)) { + spin_lock_irqsave(&priv->lock, flags); + rswitch_enadis_data_irq(priv, rdev->tx_queue->index, true); + rswitch_enadis_data_irq(priv, rdev->rx_queue->index, true); + spin_unlock_irqrestore(&priv->lock, flags); + } out: return budget - quota; @@ -835,8 +838,10 @@ static void rswitch_queue_interrupt(struct net_device *ndev) struct rswitch_device *rdev = netdev_priv(ndev); if (napi_schedule_prep(&rdev->napi)) { + spin_lock(&rdev->priv->lock); rswitch_enadis_data_irq(rdev->priv, rdev->tx_queue->index, false); rswitch_enadis_data_irq(rdev->priv, rdev->rx_queue->index, false); + spin_unlock(&rdev->priv->lock); __napi_schedule(&rdev->napi); } } @@ -1440,14 +1445,17 @@ static void rswitch_ether_port_deinit_all(struct rswitch_private *priv) static int rswitch_open(struct net_device *ndev) { struct rswitch_device *rdev = netdev_priv(ndev); + unsigned long flags; phy_start(ndev->phydev); napi_enable(&rdev->napi); netif_start_queue(ndev); + spin_lock_irqsave(&rdev->priv->lock, flags); rswitch_enadis_data_irq(rdev->priv, rdev->tx_queue->index, true); rswitch_enadis_data_irq(rdev->priv, rdev->rx_queue->index, true); + spin_unlock_irqrestore(&rdev->priv->lock, flags); if (bitmap_empty(rdev->priv->opened_ports, RSWITCH_NUM_PORTS)) iowrite32(GWCA_TS_IRQ_BIT, rdev->priv->addr + GWTSDIE); @@ -1461,6 +1469,7 @@ static int rswitch_stop(struct net_device *ndev) { struct rswitch_device *rdev = netdev_priv(ndev); struct rswitch_gwca_ts_info *ts_info, *ts_info2; + unsigned long flags; netif_tx_stop_all_queues(ndev); bitmap_clear(rdev->priv->opened_ports, rdev->port, 1); @@ -1476,8 +1485,10 @@ static int rswitch_stop(struct net_device *ndev) kfree(ts_info); } + spin_lock_irqsave(&rdev->priv->lock, flags); rswitch_enadis_data_irq(rdev->priv, rdev->tx_queue->index, false); rswitch_enadis_data_irq(rdev->priv, rdev->rx_queue->index, false); + spin_unlock_irqrestore(&rdev->priv->lock, flags); phy_stop(ndev->phydev); napi_disable(&rdev->napi); @@ -1887,6 +1898,7 @@ static int renesas_eth_sw_probe(struct platform_device *pdev) priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; + spin_lock_init(&priv->lock); attr = soc_device_match(rswitch_soc_no_speed_change); if (attr) diff --git a/drivers/net/ethernet/renesas/rswitch.h b/drivers/net/ethernet/renesas/rswitch.h index 54f397effbc6..f0c16a37ea55 100644 --- a/drivers/net/ethernet/renesas/rswitch.h +++ b/drivers/net/ethernet/renesas/rswitch.h @@ -1011,6 +1011,8 @@ struct rswitch_private { struct rswitch_etha etha[RSWITCH_NUM_PORTS]; struct rswitch_mfwd mfwd; + spinlock_t lock; /* lock interrupt registers' control */ + bool etha_no_runtime_change; bool gwca_halt; }; diff --git a/drivers/net/ethernet/sfc/tc.c b/drivers/net/ethernet/sfc/tc.c index 047322b04d4f..834f000ba1c4 100644 --- a/drivers/net/ethernet/sfc/tc.c +++ b/drivers/net/ethernet/sfc/tc.c @@ -136,6 +136,8 @@ static struct efx_tc_mac_pedit_action *efx_tc_flower_get_mac(struct efx_nic *efx if (old) { /* don't need our new entry */ kfree(ped); + if (IS_ERR(old)) /* oh dear, it's actually an error */ + return ERR_CAST(old); if (!refcount_inc_not_zero(&old->ref)) return ERR_PTR(-EAGAIN); /* existing entry found, ref taken */ @@ -602,6 +604,8 @@ static int efx_tc_flower_record_encap_match(struct efx_nic *efx, kfree(encap); if (pseudo) /* don't need our new pseudo either */ efx_tc_flower_release_encap_match(efx, pseudo); + if (IS_ERR(old)) /* oh dear, it's actually an error */ + return PTR_ERR(old); /* check old and new em_types are compatible */ switch (old->type) { case EFX_TC_EM_DIRECT: @@ -700,6 +704,8 @@ static struct efx_tc_recirc_id *efx_tc_get_recirc_id(struct efx_nic *efx, if (old) { /* don't need our new entry */ kfree(rid); + if (IS_ERR(old)) /* oh dear, it's actually an error */ + return ERR_CAST(old); if (!refcount_inc_not_zero(&old->ref)) return ERR_PTR(-EAGAIN); /* existing entry found */ @@ -1482,7 +1488,10 @@ static int efx_tc_flower_replace_foreign(struct efx_nic *efx, old = rhashtable_lookup_get_insert_fast(&efx->tc->match_action_ht, &rule->linkage, efx_tc_match_action_ht_params); - if (old) { + if (IS_ERR(old)) { + rc = PTR_ERR(old); + goto release; + } else if (old) { netif_dbg(efx, drv, efx->net_dev, "Ignoring already-offloaded rule (cookie %lx)\n", tc->cookie); @@ -1697,7 +1706,10 @@ static int efx_tc_flower_replace_lhs(struct efx_nic *efx, old = rhashtable_lookup_get_insert_fast(&efx->tc->lhs_rule_ht, &rule->linkage, efx_tc_lhs_rule_ht_params); - if (old) { + if (IS_ERR(old)) { + rc = PTR_ERR(old); + goto release; + } else if (old) { netif_dbg(efx, drv, efx->net_dev, "Already offloaded rule (cookie %lx)\n", tc->cookie); rc = -EEXIST; @@ -1858,7 +1870,10 @@ static int efx_tc_flower_replace(struct efx_nic *efx, old = rhashtable_lookup_get_insert_fast(&efx->tc->match_action_ht, &rule->linkage, efx_tc_match_action_ht_params); - if (old) { + if (IS_ERR(old)) { + rc = PTR_ERR(old); + goto release; + } else if (old) { netif_dbg(efx, drv, efx->net_dev, "Already offloaded rule (cookie %lx)\n", tc->cookie); NL_SET_ERR_MSG_MOD(extack, "Rule already offloaded"); diff --git a/drivers/net/ethernet/sfc/tc_conntrack.c b/drivers/net/ethernet/sfc/tc_conntrack.c index 8e06bfbcbea1..44bb57670340 100644 --- a/drivers/net/ethernet/sfc/tc_conntrack.c +++ b/drivers/net/ethernet/sfc/tc_conntrack.c @@ -298,7 +298,10 @@ static int efx_tc_ct_replace(struct efx_tc_ct_zone *ct_zone, old = rhashtable_lookup_get_insert_fast(&efx->tc->ct_ht, &conn->linkage, efx_tc_ct_ht_params); - if (old) { + if (IS_ERR(old)) { + rc = PTR_ERR(old); + goto release; + } else if (old) { netif_dbg(efx, drv, efx->net_dev, "Already offloaded conntrack (cookie %lx)\n", tc->cookie); rc = -EEXIST; @@ -482,6 +485,8 @@ struct efx_tc_ct_zone *efx_tc_ct_register_zone(struct efx_nic *efx, u16 zone, if (old) { /* don't need our new entry */ kfree(ct_zone); + if (IS_ERR(old)) /* oh dear, it's actually an error */ + return ERR_CAST(old); if (!refcount_inc_not_zero(&old->ref)) return ERR_PTR(-EAGAIN); /* existing entry found */ diff --git a/drivers/net/ethernet/sfc/tc_counters.c b/drivers/net/ethernet/sfc/tc_counters.c index 0fafb47ea082..c44088424323 100644 --- a/drivers/net/ethernet/sfc/tc_counters.c +++ b/drivers/net/ethernet/sfc/tc_counters.c @@ -236,6 +236,8 @@ struct efx_tc_counter_index *efx_tc_flower_get_counter_index( if (old) { /* don't need our new entry */ kfree(ctr); + if (IS_ERR(old)) /* oh dear, it's actually an error */ + return ERR_CAST(old); if (!refcount_inc_not_zero(&old->ref)) return ERR_PTR(-EAGAIN); /* existing entry found */ diff --git a/drivers/net/ethernet/sfc/tc_encap_actions.c b/drivers/net/ethernet/sfc/tc_encap_actions.c index 7e8bcdb222ad..87443f9dfd22 100644 --- a/drivers/net/ethernet/sfc/tc_encap_actions.c +++ b/drivers/net/ethernet/sfc/tc_encap_actions.c @@ -132,6 +132,8 @@ static int efx_bind_neigh(struct efx_nic *efx, /* don't need our new entry */ put_net_track(neigh->net, &neigh->ns_tracker); kfree(neigh); + if (IS_ERR(old)) /* oh dear, it's actually an error */ + return PTR_ERR(old); if (!refcount_inc_not_zero(&old->ref)) return -EAGAIN; /* existing entry found, ref taken */ @@ -640,6 +642,8 @@ struct efx_tc_encap_action *efx_tc_flower_create_encap_md( if (old) { /* don't need our new entry */ kfree(encap); + if (IS_ERR(old)) /* oh dear, it's actually an error */ + return ERR_CAST(old); if (!refcount_inc_not_zero(&old->ref)) return ERR_PTR(-EAGAIN); /* existing entry found, ref taken */ diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h index 403cb397d4d3..1e996c29043d 100644 --- a/drivers/net/ethernet/stmicro/stmmac/common.h +++ b/drivers/net/ethernet/stmicro/stmmac/common.h @@ -70,7 +70,7 @@ struct stmmac_txq_stats { u64 tx_tso_frames; u64 tx_tso_nfrags; struct u64_stats_sync syncp; -}; +} ____cacheline_aligned_in_smp; struct stmmac_rxq_stats { u64 rx_bytes; @@ -79,7 +79,7 @@ struct stmmac_rxq_stats { u64 rx_normal_irq_n; u64 napi_poll; struct u64_stats_sync syncp; -}; +} ____cacheline_aligned_in_smp; /* Extra statistic and debug information exposed by ethtool */ struct stmmac_extra_stats { @@ -202,6 +202,9 @@ struct stmmac_extra_stats { unsigned long mtl_est_hlbf; unsigned long mtl_est_btre; unsigned long mtl_est_btrlm; + /* per queue statistics */ + struct stmmac_txq_stats txq_stats[MTL_MAX_TX_QUEUES]; + struct stmmac_rxq_stats rxq_stats[MTL_MAX_RX_QUEUES]; unsigned long rx_dropped; unsigned long rx_errors; unsigned long tx_dropped; diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c index 01e77368eef1..465ff1fd4785 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sun8i.c @@ -441,8 +441,8 @@ static int sun8i_dwmac_dma_interrupt(struct stmmac_priv *priv, struct stmmac_extra_stats *x, u32 chan, u32 dir) { - struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[chan]; - struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[chan]; + struct stmmac_rxq_stats *rxq_stats = &priv->xstats.rxq_stats[chan]; + struct stmmac_txq_stats *txq_stats = &priv->xstats.txq_stats[chan]; int ret = 0; u32 v; @@ -455,9 +455,9 @@ static int sun8i_dwmac_dma_interrupt(struct stmmac_priv *priv, if (v & EMAC_TX_INT) { ret |= handle_tx; - u64_stats_update_begin(&tx_q->txq_stats.syncp); - tx_q->txq_stats.tx_normal_irq_n++; - u64_stats_update_end(&tx_q->txq_stats.syncp); + u64_stats_update_begin(&txq_stats->syncp); + txq_stats->tx_normal_irq_n++; + u64_stats_update_end(&txq_stats->syncp); } if (v & EMAC_TX_DMA_STOP_INT) @@ -479,9 +479,9 @@ static int sun8i_dwmac_dma_interrupt(struct stmmac_priv *priv, if (v & EMAC_RX_INT) { ret |= handle_rx; - u64_stats_update_begin(&rx_q->rxq_stats.syncp); - rx_q->rxq_stats.rx_normal_irq_n++; - u64_stats_update_end(&rx_q->rxq_stats.syncp); + u64_stats_update_begin(&rxq_stats->syncp); + rxq_stats->rx_normal_irq_n++; + u64_stats_update_end(&rxq_stats->syncp); } if (v & EMAC_RX_BUF_UA_INT) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c index 980e5f8a37ec..9470d3fd2ded 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_lib.c @@ -171,8 +171,8 @@ int dwmac4_dma_interrupt(struct stmmac_priv *priv, void __iomem *ioaddr, const struct dwmac4_addrs *dwmac4_addrs = priv->plat->dwmac4_addrs; u32 intr_status = readl(ioaddr + DMA_CHAN_STATUS(dwmac4_addrs, chan)); u32 intr_en = readl(ioaddr + DMA_CHAN_INTR_ENA(dwmac4_addrs, chan)); - struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[chan]; - struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[chan]; + struct stmmac_rxq_stats *rxq_stats = &priv->xstats.rxq_stats[chan]; + struct stmmac_txq_stats *txq_stats = &priv->xstats.txq_stats[chan]; int ret = 0; if (dir == DMA_DIR_RX) @@ -201,15 +201,15 @@ int dwmac4_dma_interrupt(struct stmmac_priv *priv, void __iomem *ioaddr, } /* TX/RX NORMAL interrupts */ if (likely(intr_status & DMA_CHAN_STATUS_RI)) { - u64_stats_update_begin(&rx_q->rxq_stats.syncp); - rx_q->rxq_stats.rx_normal_irq_n++; - u64_stats_update_end(&rx_q->rxq_stats.syncp); + u64_stats_update_begin(&rxq_stats->syncp); + rxq_stats->rx_normal_irq_n++; + u64_stats_update_end(&rxq_stats->syncp); ret |= handle_rx; } if (likely(intr_status & DMA_CHAN_STATUS_TI)) { - u64_stats_update_begin(&tx_q->txq_stats.syncp); - tx_q->txq_stats.tx_normal_irq_n++; - u64_stats_update_end(&tx_q->txq_stats.syncp); + u64_stats_update_begin(&txq_stats->syncp); + txq_stats->tx_normal_irq_n++; + u64_stats_update_end(&txq_stats->syncp); ret |= handle_tx; } diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c b/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c index aaa09b16b016..7907d62d3437 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac_lib.c @@ -162,8 +162,8 @@ static void show_rx_process_state(unsigned int status) int dwmac_dma_interrupt(struct stmmac_priv *priv, void __iomem *ioaddr, struct stmmac_extra_stats *x, u32 chan, u32 dir) { - struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[chan]; - struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[chan]; + struct stmmac_rxq_stats *rxq_stats = &priv->xstats.rxq_stats[chan]; + struct stmmac_txq_stats *txq_stats = &priv->xstats.txq_stats[chan]; int ret = 0; /* read the status register (CSR5) */ u32 intr_status = readl(ioaddr + DMA_STATUS); @@ -215,16 +215,16 @@ int dwmac_dma_interrupt(struct stmmac_priv *priv, void __iomem *ioaddr, u32 value = readl(ioaddr + DMA_INTR_ENA); /* to schedule NAPI on real RIE event. */ if (likely(value & DMA_INTR_ENA_RIE)) { - u64_stats_update_begin(&rx_q->rxq_stats.syncp); - rx_q->rxq_stats.rx_normal_irq_n++; - u64_stats_update_end(&rx_q->rxq_stats.syncp); + u64_stats_update_begin(&rxq_stats->syncp); + rxq_stats->rx_normal_irq_n++; + u64_stats_update_end(&rxq_stats->syncp); ret |= handle_rx; } } if (likely(intr_status & DMA_STATUS_TI)) { - u64_stats_update_begin(&tx_q->txq_stats.syncp); - tx_q->txq_stats.tx_normal_irq_n++; - u64_stats_update_end(&tx_q->txq_stats.syncp); + u64_stats_update_begin(&txq_stats->syncp); + txq_stats->tx_normal_irq_n++; + u64_stats_update_end(&txq_stats->syncp); ret |= handle_tx; } if (unlikely(intr_status & DMA_STATUS_ERI)) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c index fa69d64a8694..3cde695fec91 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_dma.c @@ -337,8 +337,8 @@ static int dwxgmac2_dma_interrupt(struct stmmac_priv *priv, struct stmmac_extra_stats *x, u32 chan, u32 dir) { - struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[chan]; - struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[chan]; + struct stmmac_rxq_stats *rxq_stats = &priv->xstats.rxq_stats[chan]; + struct stmmac_txq_stats *txq_stats = &priv->xstats.txq_stats[chan]; u32 intr_status = readl(ioaddr + XGMAC_DMA_CH_STATUS(chan)); u32 intr_en = readl(ioaddr + XGMAC_DMA_CH_INT_EN(chan)); int ret = 0; @@ -367,15 +367,15 @@ static int dwxgmac2_dma_interrupt(struct stmmac_priv *priv, /* TX/RX NORMAL interrupts */ if (likely(intr_status & XGMAC_NIS)) { if (likely(intr_status & XGMAC_RI)) { - u64_stats_update_begin(&rx_q->rxq_stats.syncp); - rx_q->rxq_stats.rx_normal_irq_n++; - u64_stats_update_end(&rx_q->rxq_stats.syncp); + u64_stats_update_begin(&rxq_stats->syncp); + rxq_stats->rx_normal_irq_n++; + u64_stats_update_end(&rxq_stats->syncp); ret |= handle_rx; } if (likely(intr_status & (XGMAC_TI | XGMAC_TBU))) { - u64_stats_update_begin(&tx_q->txq_stats.syncp); - tx_q->txq_stats.tx_normal_irq_n++; - u64_stats_update_end(&tx_q->txq_stats.syncp); + u64_stats_update_begin(&txq_stats->syncp); + txq_stats->tx_normal_irq_n++; + u64_stats_update_end(&txq_stats->syncp); ret |= handle_tx; } } diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h index 3401e888a9f6..cd7a9768de5f 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h @@ -78,7 +78,6 @@ struct stmmac_tx_queue { dma_addr_t dma_tx_phy; dma_addr_t tx_tail_addr; u32 mss; - struct stmmac_txq_stats txq_stats; }; struct stmmac_rx_buffer { @@ -123,7 +122,6 @@ struct stmmac_rx_queue { unsigned int len; unsigned int error; } state; - struct stmmac_rxq_stats rxq_stats; }; struct stmmac_channel { diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c index b7ac7abecdd3..6aa5c0556d22 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c @@ -548,14 +548,14 @@ static void stmmac_get_per_qstats(struct stmmac_priv *priv, u64 *data) pos = data; for (q = 0; q < tx_cnt; q++) { - struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[q]; + struct stmmac_txq_stats *txq_stats = &priv->xstats.txq_stats[q]; struct stmmac_txq_stats snapshot; data = pos; do { - start = u64_stats_fetch_begin(&tx_q->txq_stats.syncp); - snapshot = tx_q->txq_stats; - } while (u64_stats_fetch_retry(&tx_q->txq_stats.syncp, start)); + start = u64_stats_fetch_begin(&txq_stats->syncp); + snapshot = *txq_stats; + } while (u64_stats_fetch_retry(&txq_stats->syncp, start)); p = (char *)&snapshot + offsetof(struct stmmac_txq_stats, tx_pkt_n); for (stat = 0; stat < STMMAC_TXQ_STATS; stat++) { @@ -566,14 +566,14 @@ static void stmmac_get_per_qstats(struct stmmac_priv *priv, u64 *data) pos = data; for (q = 0; q < rx_cnt; q++) { - struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[q]; + struct stmmac_rxq_stats *rxq_stats = &priv->xstats.rxq_stats[q]; struct stmmac_rxq_stats snapshot; data = pos; do { - start = u64_stats_fetch_begin(&rx_q->rxq_stats.syncp); - snapshot = rx_q->rxq_stats; - } while (u64_stats_fetch_retry(&rx_q->rxq_stats.syncp, start)); + start = u64_stats_fetch_begin(&rxq_stats->syncp); + snapshot = *rxq_stats; + } while (u64_stats_fetch_retry(&rxq_stats->syncp, start)); p = (char *)&snapshot + offsetof(struct stmmac_rxq_stats, rx_pkt_n); for (stat = 0; stat < STMMAC_RXQ_STATS; stat++) { @@ -637,14 +637,14 @@ static void stmmac_get_ethtool_stats(struct net_device *dev, pos = j; for (i = 0; i < rx_queues_count; i++) { - struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[i]; + struct stmmac_rxq_stats *rxq_stats = &priv->xstats.rxq_stats[i]; struct stmmac_rxq_stats snapshot; j = pos; do { - start = u64_stats_fetch_begin(&rx_q->rxq_stats.syncp); - snapshot = rx_q->rxq_stats; - } while (u64_stats_fetch_retry(&rx_q->rxq_stats.syncp, start)); + start = u64_stats_fetch_begin(&rxq_stats->syncp); + snapshot = *rxq_stats; + } while (u64_stats_fetch_retry(&rxq_stats->syncp, start)); data[j++] += snapshot.rx_pkt_n; data[j++] += snapshot.rx_normal_irq_n; @@ -654,14 +654,14 @@ static void stmmac_get_ethtool_stats(struct net_device *dev, pos = j; for (i = 0; i < tx_queues_count; i++) { - struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[i]; + struct stmmac_txq_stats *txq_stats = &priv->xstats.txq_stats[i]; struct stmmac_txq_stats snapshot; j = pos; do { - start = u64_stats_fetch_begin(&tx_q->txq_stats.syncp); - snapshot = tx_q->txq_stats; - } while (u64_stats_fetch_retry(&tx_q->txq_stats.syncp, start)); + start = u64_stats_fetch_begin(&txq_stats->syncp); + snapshot = *txq_stats; + } while (u64_stats_fetch_retry(&txq_stats->syncp, start)); data[j++] += snapshot.tx_pkt_n; data[j++] += snapshot.tx_normal_irq_n; diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 9a3182b9e767..83c567a89a46 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -2426,6 +2426,7 @@ static bool stmmac_xdp_xmit_zc(struct stmmac_priv *priv, u32 queue, u32 budget) { struct netdev_queue *nq = netdev_get_tx_queue(priv->dev, queue); struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[queue]; + struct stmmac_txq_stats *txq_stats = &priv->xstats.txq_stats[queue]; struct xsk_buff_pool *pool = tx_q->xsk_pool; unsigned int entry = tx_q->cur_tx; struct dma_desc *tx_desc = NULL; @@ -2505,9 +2506,9 @@ static bool stmmac_xdp_xmit_zc(struct stmmac_priv *priv, u32 queue, u32 budget) tx_q->cur_tx = STMMAC_GET_ENTRY(tx_q->cur_tx, priv->dma_conf.dma_tx_size); entry = tx_q->cur_tx; } - flags = u64_stats_update_begin_irqsave(&tx_q->txq_stats.syncp); - tx_q->txq_stats.tx_set_ic_bit += tx_set_ic_bit; - u64_stats_update_end_irqrestore(&tx_q->txq_stats.syncp, flags); + flags = u64_stats_update_begin_irqsave(&txq_stats->syncp); + txq_stats->tx_set_ic_bit += tx_set_ic_bit; + u64_stats_update_end_irqrestore(&txq_stats->syncp, flags); if (tx_desc) { stmmac_flush_tx_descriptors(priv, queue); @@ -2547,6 +2548,7 @@ static void stmmac_bump_dma_threshold(struct stmmac_priv *priv, u32 chan) static int stmmac_tx_clean(struct stmmac_priv *priv, int budget, u32 queue) { struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[queue]; + struct stmmac_txq_stats *txq_stats = &priv->xstats.txq_stats[queue]; unsigned int bytes_compl = 0, pkts_compl = 0; unsigned int entry, xmits = 0, count = 0; u32 tx_packets = 0, tx_errors = 0; @@ -2704,15 +2706,13 @@ static int stmmac_tx_clean(struct stmmac_priv *priv, int budget, u32 queue) /* We still have pending packets, let's call for a new scheduling */ if (tx_q->dirty_tx != tx_q->cur_tx) - hrtimer_start(&tx_q->txtimer, - STMMAC_COAL_TIMER(priv->tx_coal_timer[queue]), - HRTIMER_MODE_REL); + stmmac_tx_timer_arm(priv, queue); - flags = u64_stats_update_begin_irqsave(&tx_q->txq_stats.syncp); - tx_q->txq_stats.tx_packets += tx_packets; - tx_q->txq_stats.tx_pkt_n += tx_packets; - tx_q->txq_stats.tx_clean++; - u64_stats_update_end_irqrestore(&tx_q->txq_stats.syncp, flags); + flags = u64_stats_update_begin_irqsave(&txq_stats->syncp); + txq_stats->tx_packets += tx_packets; + txq_stats->tx_pkt_n += tx_packets; + txq_stats->tx_clean++; + u64_stats_update_end_irqrestore(&txq_stats->syncp, flags); priv->xstats.tx_errors += tx_errors; @@ -2995,9 +2995,13 @@ static int stmmac_init_dma_engine(struct stmmac_priv *priv) static void stmmac_tx_timer_arm(struct stmmac_priv *priv, u32 queue) { struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[queue]; + u32 tx_coal_timer = priv->tx_coal_timer[queue]; + + if (!tx_coal_timer) + return; hrtimer_start(&tx_q->txtimer, - STMMAC_COAL_TIMER(priv->tx_coal_timer[queue]), + STMMAC_COAL_TIMER(tx_coal_timer), HRTIMER_MODE_REL); } @@ -4112,6 +4116,7 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev) int nfrags = skb_shinfo(skb)->nr_frags; u32 queue = skb_get_queue_mapping(skb); unsigned int first_entry, tx_packets; + struct stmmac_txq_stats *txq_stats; int tmp_pay_len = 0, first_tx; struct stmmac_tx_queue *tx_q; bool has_vlan, set_ic; @@ -4122,6 +4127,7 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev) int i; tx_q = &priv->dma_conf.tx_queue[queue]; + txq_stats = &priv->xstats.txq_stats[queue]; first_tx = tx_q->cur_tx; /* Compute header lengths */ @@ -4280,13 +4286,13 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev) netif_tx_stop_queue(netdev_get_tx_queue(priv->dev, queue)); } - flags = u64_stats_update_begin_irqsave(&tx_q->txq_stats.syncp); - tx_q->txq_stats.tx_bytes += skb->len; - tx_q->txq_stats.tx_tso_frames++; - tx_q->txq_stats.tx_tso_nfrags += nfrags; + flags = u64_stats_update_begin_irqsave(&txq_stats->syncp); + txq_stats->tx_bytes += skb->len; + txq_stats->tx_tso_frames++; + txq_stats->tx_tso_nfrags += nfrags; if (set_ic) - tx_q->txq_stats.tx_set_ic_bit++; - u64_stats_update_end_irqrestore(&tx_q->txq_stats.syncp, flags); + txq_stats->tx_set_ic_bit++; + u64_stats_update_end_irqrestore(&txq_stats->syncp, flags); if (priv->sarc_type) stmmac_set_desc_sarc(priv, first, priv->sarc_type); @@ -4357,6 +4363,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) u32 queue = skb_get_queue_mapping(skb); int nfrags = skb_shinfo(skb)->nr_frags; int gso = skb_shinfo(skb)->gso_type; + struct stmmac_txq_stats *txq_stats; struct dma_edesc *tbs_desc = NULL; struct dma_desc *desc, *first; struct stmmac_tx_queue *tx_q; @@ -4366,6 +4373,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) dma_addr_t des; tx_q = &priv->dma_conf.tx_queue[queue]; + txq_stats = &priv->xstats.txq_stats[queue]; first_tx = tx_q->cur_tx; if (priv->tx_path_in_lpi_mode && priv->eee_sw_timer_en) @@ -4517,11 +4525,11 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) netif_tx_stop_queue(netdev_get_tx_queue(priv->dev, queue)); } - flags = u64_stats_update_begin_irqsave(&tx_q->txq_stats.syncp); - tx_q->txq_stats.tx_bytes += skb->len; + flags = u64_stats_update_begin_irqsave(&txq_stats->syncp); + txq_stats->tx_bytes += skb->len; if (set_ic) - tx_q->txq_stats.tx_set_ic_bit++; - u64_stats_update_end_irqrestore(&tx_q->txq_stats.syncp, flags); + txq_stats->tx_set_ic_bit++; + u64_stats_update_end_irqrestore(&txq_stats->syncp, flags); if (priv->sarc_type) stmmac_set_desc_sarc(priv, first, priv->sarc_type); @@ -4728,6 +4736,7 @@ static unsigned int stmmac_rx_buf2_len(struct stmmac_priv *priv, static int stmmac_xdp_xmit_xdpf(struct stmmac_priv *priv, int queue, struct xdp_frame *xdpf, bool dma_map) { + struct stmmac_txq_stats *txq_stats = &priv->xstats.txq_stats[queue]; struct stmmac_tx_queue *tx_q = &priv->dma_conf.tx_queue[queue]; unsigned int entry = tx_q->cur_tx; struct dma_desc *tx_desc; @@ -4787,9 +4796,9 @@ static int stmmac_xdp_xmit_xdpf(struct stmmac_priv *priv, int queue, unsigned long flags; tx_q->tx_count_frames = 0; stmmac_set_tx_ic(priv, tx_desc); - flags = u64_stats_update_begin_irqsave(&tx_q->txq_stats.syncp); - tx_q->txq_stats.tx_set_ic_bit++; - u64_stats_update_end_irqrestore(&tx_q->txq_stats.syncp, flags); + flags = u64_stats_update_begin_irqsave(&txq_stats->syncp); + txq_stats->tx_set_ic_bit++; + u64_stats_update_end_irqrestore(&txq_stats->syncp, flags); } stmmac_enable_dma_transmission(priv, priv->ioaddr); @@ -4934,7 +4943,7 @@ static void stmmac_dispatch_skb_zc(struct stmmac_priv *priv, u32 queue, struct dma_desc *p, struct dma_desc *np, struct xdp_buff *xdp) { - struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[queue]; + struct stmmac_rxq_stats *rxq_stats = &priv->xstats.rxq_stats[queue]; struct stmmac_channel *ch = &priv->channel[queue]; unsigned int len = xdp->data_end - xdp->data; enum pkt_hash_types hash_type; @@ -4964,10 +4973,10 @@ static void stmmac_dispatch_skb_zc(struct stmmac_priv *priv, u32 queue, skb_record_rx_queue(skb, queue); napi_gro_receive(&ch->rxtx_napi, skb); - flags = u64_stats_update_begin_irqsave(&rx_q->rxq_stats.syncp); - rx_q->rxq_stats.rx_pkt_n++; - rx_q->rxq_stats.rx_bytes += len; - u64_stats_update_end_irqrestore(&rx_q->rxq_stats.syncp, flags); + flags = u64_stats_update_begin_irqsave(&rxq_stats->syncp); + rxq_stats->rx_pkt_n++; + rxq_stats->rx_bytes += len; + u64_stats_update_end_irqrestore(&rxq_stats->syncp, flags); } static bool stmmac_rx_refill_zc(struct stmmac_priv *priv, u32 queue, u32 budget) @@ -5040,6 +5049,7 @@ static struct stmmac_xdp_buff *xsk_buff_to_stmmac_ctx(struct xdp_buff *xdp) static int stmmac_rx_zc(struct stmmac_priv *priv, int limit, u32 queue) { + struct stmmac_rxq_stats *rxq_stats = &priv->xstats.rxq_stats[queue]; struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[queue]; unsigned int count = 0, error = 0, len = 0; int dirty = stmmac_rx_dirty(priv, queue); @@ -5203,9 +5213,9 @@ read_again: stmmac_finalize_xdp_rx(priv, xdp_status); - flags = u64_stats_update_begin_irqsave(&rx_q->rxq_stats.syncp); - rx_q->rxq_stats.rx_pkt_n += count; - u64_stats_update_end_irqrestore(&rx_q->rxq_stats.syncp, flags); + flags = u64_stats_update_begin_irqsave(&rxq_stats->syncp); + rxq_stats->rx_pkt_n += count; + u64_stats_update_end_irqrestore(&rxq_stats->syncp, flags); priv->xstats.rx_dropped += rx_dropped; priv->xstats.rx_errors += rx_errors; @@ -5233,6 +5243,7 @@ read_again: static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue) { u32 rx_errors = 0, rx_dropped = 0, rx_bytes = 0, rx_packets = 0; + struct stmmac_rxq_stats *rxq_stats = &priv->xstats.rxq_stats[queue]; struct stmmac_rx_queue *rx_q = &priv->dma_conf.rx_queue[queue]; struct stmmac_channel *ch = &priv->channel[queue]; unsigned int count = 0, error = 0, len = 0; @@ -5494,11 +5505,11 @@ drain_data: stmmac_rx_refill(priv, queue); - flags = u64_stats_update_begin_irqsave(&rx_q->rxq_stats.syncp); - rx_q->rxq_stats.rx_packets += rx_packets; - rx_q->rxq_stats.rx_bytes += rx_bytes; - rx_q->rxq_stats.rx_pkt_n += count; - u64_stats_update_end_irqrestore(&rx_q->rxq_stats.syncp, flags); + flags = u64_stats_update_begin_irqsave(&rxq_stats->syncp); + rxq_stats->rx_packets += rx_packets; + rxq_stats->rx_bytes += rx_bytes; + rxq_stats->rx_pkt_n += count; + u64_stats_update_end_irqrestore(&rxq_stats->syncp, flags); priv->xstats.rx_dropped += rx_dropped; priv->xstats.rx_errors += rx_errors; @@ -5511,15 +5522,15 @@ static int stmmac_napi_poll_rx(struct napi_struct *napi, int budget) struct stmmac_channel *ch = container_of(napi, struct stmmac_channel, rx_napi); struct stmmac_priv *priv = ch->priv_data; - struct stmmac_rx_queue *rx_q; + struct stmmac_rxq_stats *rxq_stats; u32 chan = ch->index; unsigned long flags; int work_done; - rx_q = &priv->dma_conf.rx_queue[chan]; - flags = u64_stats_update_begin_irqsave(&rx_q->rxq_stats.syncp); - rx_q->rxq_stats.napi_poll++; - u64_stats_update_end_irqrestore(&rx_q->rxq_stats.syncp, flags); + rxq_stats = &priv->xstats.rxq_stats[chan]; + flags = u64_stats_update_begin_irqsave(&rxq_stats->syncp); + rxq_stats->napi_poll++; + u64_stats_update_end_irqrestore(&rxq_stats->syncp, flags); work_done = stmmac_rx(priv, budget, chan); if (work_done < budget && napi_complete_done(napi, work_done)) { @@ -5538,15 +5549,15 @@ static int stmmac_napi_poll_tx(struct napi_struct *napi, int budget) struct stmmac_channel *ch = container_of(napi, struct stmmac_channel, tx_napi); struct stmmac_priv *priv = ch->priv_data; - struct stmmac_tx_queue *tx_q; + struct stmmac_txq_stats *txq_stats; u32 chan = ch->index; unsigned long flags; int work_done; - tx_q = &priv->dma_conf.tx_queue[chan]; - flags = u64_stats_update_begin_irqsave(&tx_q->txq_stats.syncp); - tx_q->txq_stats.napi_poll++; - u64_stats_update_end_irqrestore(&tx_q->txq_stats.syncp, flags); + txq_stats = &priv->xstats.txq_stats[chan]; + flags = u64_stats_update_begin_irqsave(&txq_stats->syncp); + txq_stats->napi_poll++; + u64_stats_update_end_irqrestore(&txq_stats->syncp, flags); work_done = stmmac_tx_clean(priv, budget, chan); work_done = min(work_done, budget); @@ -5568,20 +5579,20 @@ static int stmmac_napi_poll_rxtx(struct napi_struct *napi, int budget) container_of(napi, struct stmmac_channel, rxtx_napi); struct stmmac_priv *priv = ch->priv_data; int rx_done, tx_done, rxtx_done; - struct stmmac_rx_queue *rx_q; - struct stmmac_tx_queue *tx_q; + struct stmmac_rxq_stats *rxq_stats; + struct stmmac_txq_stats *txq_stats; u32 chan = ch->index; unsigned long flags; - rx_q = &priv->dma_conf.rx_queue[chan]; - flags = u64_stats_update_begin_irqsave(&rx_q->rxq_stats.syncp); - rx_q->rxq_stats.napi_poll++; - u64_stats_update_end_irqrestore(&rx_q->rxq_stats.syncp, flags); + rxq_stats = &priv->xstats.rxq_stats[chan]; + flags = u64_stats_update_begin_irqsave(&rxq_stats->syncp); + rxq_stats->napi_poll++; + u64_stats_update_end_irqrestore(&rxq_stats->syncp, flags); - tx_q = &priv->dma_conf.tx_queue[chan]; - flags = u64_stats_update_begin_irqsave(&tx_q->txq_stats.syncp); - tx_q->txq_stats.napi_poll++; - u64_stats_update_end_irqrestore(&tx_q->txq_stats.syncp, flags); + txq_stats = &priv->xstats.txq_stats[chan]; + flags = u64_stats_update_begin_irqsave(&txq_stats->syncp); + txq_stats->napi_poll++; + u64_stats_update_end_irqrestore(&txq_stats->syncp, flags); tx_done = stmmac_tx_clean(priv, budget, chan); tx_done = min(tx_done, budget); @@ -6924,7 +6935,7 @@ static void stmmac_get_stats64(struct net_device *dev, struct rtnl_link_stats64 int q; for (q = 0; q < tx_cnt; q++) { - struct stmmac_txq_stats *txq_stats = &priv->dma_conf.tx_queue[q].txq_stats; + struct stmmac_txq_stats *txq_stats = &priv->xstats.txq_stats[q]; u64 tx_packets; u64 tx_bytes; @@ -6939,7 +6950,7 @@ static void stmmac_get_stats64(struct net_device *dev, struct rtnl_link_stats64 } for (q = 0; q < rx_cnt; q++) { - struct stmmac_rxq_stats *rxq_stats = &priv->dma_conf.rx_queue[q].rxq_stats; + struct stmmac_rxq_stats *rxq_stats = &priv->xstats.rxq_stats[q]; u64 rx_packets; u64 rx_bytes; @@ -7340,9 +7351,9 @@ int stmmac_dvr_probe(struct device *device, priv->dev = ndev; for (i = 0; i < MTL_MAX_RX_QUEUES; i++) - u64_stats_init(&priv->dma_conf.rx_queue[i].rxq_stats.syncp); + u64_stats_init(&priv->xstats.rxq_stats[i].syncp); for (i = 0; i < MTL_MAX_TX_QUEUES; i++) - u64_stats_init(&priv->dma_conf.tx_queue[i].txq_stats.syncp); + u64_stats_init(&priv->xstats.txq_stats[i].syncp); stmmac_set_ethtool_ops(ndev); priv->pause = pause; diff --git a/drivers/net/ethernet/ti/Kconfig b/drivers/net/ethernet/ti/Kconfig index 88b5b1b47779..0a3346650e03 100644 --- a/drivers/net/ethernet/ti/Kconfig +++ b/drivers/net/ethernet/ti/Kconfig @@ -199,6 +199,7 @@ config TI_ICSSG_PRUETH config TI_ICSS_IEP tristate "TI PRU ICSS IEP driver" + depends on PTP_1588_CLOCK_OPTIONAL depends on TI_PRUSS default TI_PRUSS help diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c index e8b94580194e..508d9a392ab1 100644 --- a/drivers/net/team/team.c +++ b/drivers/net/team/team.c @@ -2115,7 +2115,12 @@ static const struct ethtool_ops team_ethtool_ops = { static void team_setup_by_port(struct net_device *dev, struct net_device *port_dev) { - dev->header_ops = port_dev->header_ops; + struct team *team = netdev_priv(dev); + + if (port_dev->type == ARPHRD_ETHER) + dev->header_ops = team->header_ops_cache; + else + dev->header_ops = port_dev->header_ops; dev->type = port_dev->type; dev->hard_header_len = port_dev->hard_header_len; dev->needed_headroom = port_dev->needed_headroom; @@ -2162,8 +2167,11 @@ static int team_dev_type_check_change(struct net_device *dev, static void team_setup(struct net_device *dev) { + struct team *team = netdev_priv(dev); + ether_setup(dev); dev->max_mtu = ETH_MAX_MTU; + team->header_ops_cache = dev->header_ops; dev->netdev_ops = &team_netdev_ops; dev->ethtool_ops = &team_ethtool_ops; diff --git a/drivers/net/thunderbolt/main.c b/drivers/net/thunderbolt/main.c index 0c1e8970ee58..0a53ec293d04 100644 --- a/drivers/net/thunderbolt/main.c +++ b/drivers/net/thunderbolt/main.c @@ -1049,12 +1049,11 @@ static bool tbnet_xmit_csum_and_map(struct tbnet *net, struct sk_buff *skb, *tucso = ~csum_tcpudp_magic(ip_hdr(skb)->saddr, ip_hdr(skb)->daddr, 0, ip_hdr(skb)->protocol, 0); - } else if (skb_is_gso_v6(skb)) { + } else if (skb_is_gso(skb) && skb_is_gso_v6(skb)) { tucso = dest + ((void *)&(tcp_hdr(skb)->check) - data); *tucso = ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr, 0, IPPROTO_TCP, 0); - return false; } else if (protocol == htons(ETH_P_IPV6)) { tucso = dest + skb_checksum_start_offset(skb) + skb->csum_offset; *tucso = ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr, diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 332c853ca99b..0c13d9950cd8 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -2636,6 +2636,9 @@ static int r8152_poll(struct napi_struct *napi, int budget) struct r8152 *tp = container_of(napi, struct r8152, napi); int work_done; + if (!budget) + return 0; + work_done = rx_bottom(tp, budget); if (work_done < budget) { diff --git a/drivers/net/veth.c b/drivers/net/veth.c index 9c6f4f83f22b..0deefd1573cf 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -1446,6 +1446,8 @@ static int veth_open(struct net_device *dev) netif_carrier_on(peer); } + veth_set_xdp_features(dev); + return 0; } diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c index e463f59e95c2..5b5597073b00 100644 --- a/drivers/net/vxlan/vxlan_core.c +++ b/drivers/net/vxlan/vxlan_core.c @@ -4331,6 +4331,10 @@ static size_t vxlan_get_size(const struct net_device *dev) nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_REMCSUM_TX */ nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_REMCSUM_RX */ nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_LOCALBYPASS */ + nla_total_size(0) + /* IFLA_VXLAN_GBP */ + nla_total_size(0) + /* IFLA_VXLAN_GPE */ + nla_total_size(0) + /* IFLA_VXLAN_REMCSUM_NOPARTIAL */ + nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_VNIFILTER */ 0; } diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index f3a01b79148c..21783aa2ee8e 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -2245,25 +2245,8 @@ int nvme_enable_ctrl(struct nvme_ctrl *ctrl) else ctrl->ctrl_config = NVME_CC_CSS_NVM; - if (ctrl->cap & NVME_CAP_CRMS_CRWMS) { - u32 crto; - - ret = ctrl->ops->reg_read32(ctrl, NVME_REG_CRTO, &crto); - if (ret) { - dev_err(ctrl->device, "Reading CRTO failed (%d)\n", - ret); - return ret; - } - - if (ctrl->cap & NVME_CAP_CRMS_CRIMS) { - ctrl->ctrl_config |= NVME_CC_CRIME; - timeout = NVME_CRTO_CRIMT(crto); - } else { - timeout = NVME_CRTO_CRWMT(crto); - } - } else { - timeout = NVME_CAP_TIMEOUT(ctrl->cap); - } + if (ctrl->cap & NVME_CAP_CRMS_CRWMS && ctrl->cap & NVME_CAP_CRMS_CRIMS) + ctrl->ctrl_config |= NVME_CC_CRIME; ctrl->ctrl_config |= (NVME_CTRL_PAGE_SHIFT - 12) << NVME_CC_MPS_SHIFT; ctrl->ctrl_config |= NVME_CC_AMS_RR | NVME_CC_SHN_NONE; @@ -2277,6 +2260,39 @@ int nvme_enable_ctrl(struct nvme_ctrl *ctrl) if (ret) return ret; + /* CAP value may change after initial CC write */ + ret = ctrl->ops->reg_read64(ctrl, NVME_REG_CAP, &ctrl->cap); + if (ret) + return ret; + + timeout = NVME_CAP_TIMEOUT(ctrl->cap); + if (ctrl->cap & NVME_CAP_CRMS_CRWMS) { + u32 crto, ready_timeout; + + ret = ctrl->ops->reg_read32(ctrl, NVME_REG_CRTO, &crto); + if (ret) { + dev_err(ctrl->device, "Reading CRTO failed (%d)\n", + ret); + return ret; + } + + /* + * CRTO should always be greater or equal to CAP.TO, but some + * devices are known to get this wrong. Use the larger of the + * two values. + */ + if (ctrl->ctrl_config & NVME_CC_CRIME) + ready_timeout = NVME_CRTO_CRIMT(crto); + else + ready_timeout = NVME_CRTO_CRWMT(crto); + + if (ready_timeout < timeout) + dev_warn_once(ctrl->device, "bad crto:%x cap:%llx\n", + crto, ctrl->cap); + else + timeout = ready_timeout; + } + ctrl->ctrl_config |= NVME_CC_ENABLE; ret = ctrl->ops->reg_write32(ctrl, NVME_REG_CC, ctrl->ctrl_config); if (ret) diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c index 1cd2bf82319a..a15b37750d6e 100644 --- a/drivers/nvme/host/fc.c +++ b/drivers/nvme/host/fc.c @@ -1924,7 +1924,7 @@ char *nvme_fc_io_getuuid(struct nvmefc_fcp_req *req) struct nvme_fc_fcp_op *op = fcp_req_to_fcp_op(req); struct request *rq = op->rq; - if (!IS_ENABLED(CONFIG_BLK_CGROUP_FC_APPID) || !rq->bio) + if (!IS_ENABLED(CONFIG_BLK_CGROUP_FC_APPID) || !rq || !rq->bio) return NULL; return blkcg_get_fc_appid(rq->bio); } diff --git a/drivers/nvme/host/hwmon.c b/drivers/nvme/host/hwmon.c index 316f3e4ca7cc..8df73a0b3980 100644 --- a/drivers/nvme/host/hwmon.c +++ b/drivers/nvme/host/hwmon.c @@ -187,7 +187,7 @@ static umode_t nvme_hwmon_is_visible(const void *_data, return 0; } -static const struct hwmon_channel_info *nvme_hwmon_info[] = { +static const struct hwmon_channel_info *const nvme_hwmon_info[] = { HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ), HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MIN | diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index 2f57da12d983..347cb5daebc3 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -2916,9 +2916,6 @@ static struct nvme_dev *nvme_pci_alloc_dev(struct pci_dev *pdev, struct nvme_dev *dev; int ret = -ENOMEM; - if (node == NUMA_NO_NODE) - set_dev_node(&pdev->dev, first_memory_node); - dev = kzalloc_node(sizeof(*dev), GFP_KERNEL, node); if (!dev) return ERR_PTR(-ENOMEM); diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c index 868aa4de2e4c..cd92d7ddf5ed 100644 --- a/drivers/nvme/target/tcp.c +++ b/drivers/nvme/target/tcp.c @@ -348,7 +348,7 @@ static void nvmet_tcp_build_pdu_iovec(struct nvmet_tcp_cmd *cmd) while (length) { u32 iov_len = min_t(u32, length, sg->length - sg_offset); - bvec_set_page(iov, sg_page(sg), sg->length, + bvec_set_page(iov, sg_page(sg), iov_len, sg->offset + sg_offset); length -= iov_len; diff --git a/drivers/opp/core.c b/drivers/opp/core.c index 919cc53bc02e..8978e94c9ca1 100644 --- a/drivers/opp/core.c +++ b/drivers/opp/core.c @@ -1030,7 +1030,7 @@ static int _set_performance_state(struct device *dev, struct device *pd_dev, if (!pd_dev) return 0; - ret = dev_pm_genpd_set_performance_state(pd_dev, pstate); + ret = dev_pm_domain_set_performance_state(pd_dev, pstate); if (ret) { dev_err(dev, "Failed to set performance state of %s: %d (%d)\n", dev_name(pd_dev), pstate, ret); @@ -1107,6 +1107,28 @@ void _update_set_required_opps(struct opp_table *opp_table) opp_table->set_required_opps = _opp_set_required_opps_generic; } +static int _set_opp_level(struct device *dev, struct opp_table *opp_table, + struct dev_pm_opp *opp) +{ + unsigned int level = 0; + int ret = 0; + + if (opp) { + if (!opp->level) + return 0; + + level = opp->level; + } + + /* Request a new performance state through the device's PM domain. */ + ret = dev_pm_domain_set_performance_state(dev, level); + if (ret) + dev_err(dev, "Failed to set performance state %u (%d)\n", level, + ret); + + return ret; +} + static void _find_current_opp(struct device *dev, struct opp_table *opp_table) { struct dev_pm_opp *opp = ERR_PTR(-ENODEV); @@ -1154,8 +1176,13 @@ static int _disable_opp_table(struct device *dev, struct opp_table *opp_table) if (opp_table->regulators) regulator_disable(opp_table->regulators[0]); + ret = _set_opp_level(dev, opp_table, NULL); + if (ret) + goto out; + ret = _set_required_opps(dev, opp_table, NULL, false); +out: opp_table->enabled = false; return ret; } @@ -1198,6 +1225,10 @@ static int _set_opp(struct device *dev, struct opp_table *opp_table, return ret; } + ret = _set_opp_level(dev, opp_table, opp); + if (ret) + return ret; + ret = _set_opp_bw(opp_table, opp, dev); if (ret) { dev_err(dev, "Failed to set bw: %d\n", ret); @@ -1241,6 +1272,10 @@ static int _set_opp(struct device *dev, struct opp_table *opp_table, return ret; } + ret = _set_opp_level(dev, opp_table, opp); + if (ret) + return ret; + ret = _set_required_opps(dev, opp_table, opp, false); if (ret) { dev_err(dev, "Failed to set required opps: %d\n", ret); @@ -2002,8 +2037,7 @@ int _opp_add(struct device *dev, struct dev_pm_opp *new_opp, * _opp_add_v1() - Allocate a OPP based on v1 bindings. * @opp_table: OPP table * @dev: device for which we do this operation - * @freq: Frequency in Hz for this OPP - * @u_volt: Voltage in uVolts for this OPP + * @data: The OPP data for the OPP to add * @dynamic: Dynamically added OPPs. * * This function adds an opp definition to the opp table and returns status. @@ -2021,10 +2055,10 @@ int _opp_add(struct device *dev, struct dev_pm_opp *new_opp, * -ENOMEM Memory allocation failure */ int _opp_add_v1(struct opp_table *opp_table, struct device *dev, - unsigned long freq, long u_volt, bool dynamic) + struct dev_pm_opp_data *data, bool dynamic) { struct dev_pm_opp *new_opp; - unsigned long tol; + unsigned long tol, u_volt = data->u_volt; int ret; if (!assert_single_clk(opp_table)) @@ -2035,7 +2069,8 @@ int _opp_add_v1(struct opp_table *opp_table, struct device *dev, return -ENOMEM; /* populate the opp table */ - new_opp->rates[0] = freq; + new_opp->rates[0] = data->freq; + new_opp->level = data->level; tol = u_volt * opp_table->voltage_tolerance_v1 / 100; new_opp->supplies[0].u_volt = u_volt; new_opp->supplies[0].u_volt_min = u_volt - tol; @@ -2825,10 +2860,9 @@ unlock: } /** - * dev_pm_opp_add() - Add an OPP table from a table definitions - * @dev: device for which we do this operation - * @freq: Frequency in Hz for this OPP - * @u_volt: Voltage in uVolts for this OPP + * dev_pm_opp_add_dynamic() - Add an OPP table from a table definitions + * @dev: The device for which we do this operation + * @data: The OPP data for the OPP to add * * This function adds an opp definition to the opp table and returns status. * The opp is made available by default and it can be controlled using @@ -2841,7 +2875,7 @@ unlock: * Duplicate OPPs (both freq and volt are same) and !opp->available * -ENOMEM Memory allocation failure */ -int dev_pm_opp_add(struct device *dev, unsigned long freq, unsigned long u_volt) +int dev_pm_opp_add_dynamic(struct device *dev, struct dev_pm_opp_data *data) { struct opp_table *opp_table; int ret; @@ -2853,13 +2887,13 @@ int dev_pm_opp_add(struct device *dev, unsigned long freq, unsigned long u_volt) /* Fix regulator count for dynamic OPPs */ opp_table->regulator_count = 1; - ret = _opp_add_v1(opp_table, dev, freq, u_volt, true); + ret = _opp_add_v1(opp_table, dev, data, true); if (ret) dev_pm_opp_put_opp_table(opp_table); return ret; } -EXPORT_SYMBOL_GPL(dev_pm_opp_add); +EXPORT_SYMBOL_GPL(dev_pm_opp_add_dynamic); /** * _opp_set_availability() - helper to set the availability of an opp diff --git a/drivers/opp/of.c b/drivers/opp/of.c index ada4963c7cfa..ade6d42cae46 100644 --- a/drivers/opp/of.c +++ b/drivers/opp/of.c @@ -1077,13 +1077,15 @@ static int _of_add_opp_table_v1(struct device *dev, struct opp_table *opp_table) val = prop->value; while (nr) { - unsigned long freq = be32_to_cpup(val++) * 1000; - unsigned long volt = be32_to_cpup(val++); + struct dev_pm_opp_data data = { + .freq = be32_to_cpup(val++) * 1000, + .u_volt = be32_to_cpup(val++), + }; - ret = _opp_add_v1(opp_table, dev, freq, volt, false); + ret = _opp_add_v1(opp_table, dev, &data, false); if (ret) { dev_err(dev, "%s: Failed to add OPP %ld (%d)\n", - __func__, freq, ret); + __func__, data.freq, ret); goto remove_static_opp; } nr -= 2; diff --git a/drivers/opp/opp.h b/drivers/opp/opp.h index 8a5ea38f3a3d..fefdf9845692 100644 --- a/drivers/opp/opp.h +++ b/drivers/opp/opp.h @@ -251,7 +251,7 @@ struct dev_pm_opp *_opp_allocate(struct opp_table *opp_table); void _opp_free(struct dev_pm_opp *opp); int _opp_compare_key(struct opp_table *opp_table, struct dev_pm_opp *opp1, struct dev_pm_opp *opp2); int _opp_add(struct device *dev, struct dev_pm_opp *new_opp, struct opp_table *opp_table); -int _opp_add_v1(struct opp_table *opp_table, struct device *dev, unsigned long freq, long u_volt, bool dynamic); +int _opp_add_v1(struct opp_table *opp_table, struct device *dev, struct dev_pm_opp_data *data, bool dynamic); void _dev_pm_opp_cpumask_remove_table(const struct cpumask *cpumask, int last_cpu); struct opp_table *_add_opp_table_indexed(struct device *dev, int index, bool getclk); void _put_opp_list_kref(struct opp_table *opp_table); diff --git a/drivers/parisc/ccio-dma.c b/drivers/parisc/ccio-dma.c index 509a4072d50a..9ce0d20a6c58 100644 --- a/drivers/parisc/ccio-dma.c +++ b/drivers/parisc/ccio-dma.c @@ -214,7 +214,7 @@ struct ioa_registers { struct ioc { struct ioa_registers __iomem *ioc_regs; /* I/O MMU base address */ u8 *res_map; /* resource map, bit == pdir entry */ - u64 *pdir_base; /* physical base address */ + __le64 *pdir_base; /* physical base address */ u32 pdir_size; /* bytes, function of IOV Space size */ u32 res_hint; /* next available IOVP - circular search */ @@ -339,7 +339,7 @@ ccio_alloc_range(struct ioc *ioc, struct device *dev, size_t size) BUG_ON(pages_needed == 0); BUG_ON((pages_needed * IOVP_SIZE) > DMA_CHUNK_SIZE); - DBG_RES("%s() size: %d pages_needed %d\n", + DBG_RES("%s() size: %zu pages_needed %d\n", __func__, size, pages_needed); /* @@ -427,7 +427,7 @@ ccio_free_range(struct ioc *ioc, dma_addr_t iova, unsigned long pages_mapped) BUG_ON((pages_mapped * IOVP_SIZE) > DMA_CHUNK_SIZE); BUG_ON(pages_mapped > BITS_PER_LONG); - DBG_RES("%s(): res_idx: %d pages_mapped %d\n", + DBG_RES("%s(): res_idx: %d pages_mapped %lu\n", __func__, res_idx, pages_mapped); #ifdef CCIO_COLLECT_STATS @@ -543,7 +543,7 @@ static u32 hint_lookup[] = { * index are bits 12:19 of the value returned by LCI. */ static void -ccio_io_pdir_entry(u64 *pdir_ptr, space_t sid, unsigned long vba, +ccio_io_pdir_entry(__le64 *pdir_ptr, space_t sid, unsigned long vba, unsigned long hints) { register unsigned long pa; @@ -719,7 +719,7 @@ ccio_map_single(struct device *dev, void *addr, size_t size, unsigned long flags; dma_addr_t iovp; dma_addr_t offset; - u64 *pdir_start; + __le64 *pdir_start; unsigned long hint = hint_lookup[(int)direction]; BUG_ON(!dev); @@ -746,8 +746,8 @@ ccio_map_single(struct device *dev, void *addr, size_t size, pdir_start = &(ioc->pdir_base[idx]); - DBG_RUN("%s() 0x%p -> 0x%lx size: %0x%x\n", - __func__, addr, (long)iovp | offset, size); + DBG_RUN("%s() %px -> %#lx size: %zu\n", + __func__, addr, (long)(iovp | offset), size); /* If not cacheline aligned, force SAFE_DMA on the whole mess */ if((size % L1_CACHE_BYTES) || ((unsigned long)addr % L1_CACHE_BYTES)) @@ -805,7 +805,7 @@ ccio_unmap_page(struct device *dev, dma_addr_t iova, size_t size, return; } - DBG_RUN("%s() iovp 0x%lx/%x\n", + DBG_RUN("%s() iovp %#lx/%zx\n", __func__, (long)iova, size); iova ^= offset; /* clear offset bits */ @@ -1283,7 +1283,7 @@ ccio_ioc_init(struct ioc *ioc) iova_space_size>>20, iov_order + PAGE_SHIFT); - ioc->pdir_base = (u64 *)__get_free_pages(GFP_KERNEL, + ioc->pdir_base = (__le64 *)__get_free_pages(GFP_KERNEL, get_order(ioc->pdir_size)); if(NULL == ioc->pdir_base) { panic("%s() could not allocate I/O Page Table\n", __func__); diff --git a/drivers/parisc/iommu-helpers.h b/drivers/parisc/iommu-helpers.h index 0905be256de0..c43f1a212a5c 100644 --- a/drivers/parisc/iommu-helpers.h +++ b/drivers/parisc/iommu-helpers.h @@ -14,13 +14,13 @@ static inline unsigned int iommu_fill_pdir(struct ioc *ioc, struct scatterlist *startsg, int nents, unsigned long hint, - void (*iommu_io_pdir_entry)(u64 *, space_t, unsigned long, + void (*iommu_io_pdir_entry)(__le64 *, space_t, unsigned long, unsigned long)) { struct scatterlist *dma_sg = startsg; /* pointer to current DMA */ unsigned int n_mappings = 0; unsigned long dma_offset = 0, dma_len = 0; - u64 *pdirp = NULL; + __le64 *pdirp = NULL; /* Horrible hack. For efficiency's sake, dma_sg starts one * entry below the true start (it is immediately incremented @@ -31,8 +31,8 @@ iommu_fill_pdir(struct ioc *ioc, struct scatterlist *startsg, int nents, unsigned long vaddr; long size; - DBG_RUN_SG(" %d : %08lx/%05x %p/%05x\n", nents, - (unsigned long)sg_dma_address(startsg), cnt, + DBG_RUN_SG(" %d : %08lx %p/%05x\n", nents, + (unsigned long)sg_dma_address(startsg), sg_virt(startsg), startsg->length ); diff --git a/drivers/parisc/iosapic.c b/drivers/parisc/iosapic.c index a7df764f1a72..a4011461189b 100644 --- a/drivers/parisc/iosapic.c +++ b/drivers/parisc/iosapic.c @@ -202,9 +202,9 @@ static inline void iosapic_write(void __iomem *iosapic, unsigned int reg, u32 va static DEFINE_SPINLOCK(iosapic_lock); -static inline void iosapic_eoi(void __iomem *addr, unsigned int data) +static inline void iosapic_eoi(__le32 __iomem *addr, __le32 data) { - __raw_writel(data, addr); + __raw_writel((__force u32)data, addr); } /* diff --git a/drivers/parisc/iosapic_private.h b/drivers/parisc/iosapic_private.h index 73ecc657ad95..bd8ff40162b4 100644 --- a/drivers/parisc/iosapic_private.h +++ b/drivers/parisc/iosapic_private.h @@ -118,8 +118,8 @@ struct iosapic_irt { struct vector_info { struct iosapic_info *iosapic; /* I/O SAPIC this vector is on */ struct irt_entry *irte; /* IRT entry */ - u32 __iomem *eoi_addr; /* precalculate EOI reg address */ - u32 eoi_data; /* IA64: ? PA: swapped txn_data */ + __le32 __iomem *eoi_addr; /* precalculate EOI reg address */ + __le32 eoi_data; /* IA64: ? PA: swapped txn_data */ int txn_irq; /* virtual IRQ number for processor */ ulong txn_addr; /* IA64: id_eid PA: partial HPA */ u32 txn_data; /* CPU interrupt bit */ diff --git a/drivers/parisc/sba_iommu.c b/drivers/parisc/sba_iommu.c index f6b510675318..05e7103d1d40 100644 --- a/drivers/parisc/sba_iommu.c +++ b/drivers/parisc/sba_iommu.c @@ -46,8 +46,6 @@ #include <linux/module.h> #include <asm/ropes.h> -#include <asm/mckinley.h> /* for proc_mckinley_root */ -#include <asm/runway.h> /* for proc_runway_root */ #include <asm/page.h> /* for PAGE0 */ #include <asm/pdc.h> /* for PDC_MODEL_* */ #include <asm/pdcpat.h> /* for is_pdc_pat() */ @@ -122,7 +120,7 @@ MODULE_PARM_DESC(sba_reserve_agpgart, "Reserve half of IO pdir as AGPGART"); #endif static struct proc_dir_entry *proc_runway_root __ro_after_init; -struct proc_dir_entry *proc_mckinley_root __ro_after_init; +static struct proc_dir_entry *proc_mckinley_root __ro_after_init; /************************************ ** SBA register read and write support @@ -204,7 +202,7 @@ static void sba_dump_pdir_entry(struct ioc *ioc, char *msg, uint pide) { /* start printing from lowest pde in rval */ - u64 *ptr = &(ioc->pdir_base[pide & (~0U * BITS_PER_LONG)]); + __le64 *ptr = &(ioc->pdir_base[pide & (~0U * BITS_PER_LONG)]); unsigned long *rptr = (unsigned long *) &(ioc->res_map[(pide >>3) & ~(sizeof(unsigned long) - 1)]); uint rcnt; @@ -571,7 +569,7 @@ typedef unsigned long space_t; */ static void -sba_io_pdir_entry(u64 *pdir_ptr, space_t sid, unsigned long vba, +sba_io_pdir_entry(__le64 *pdir_ptr, space_t sid, unsigned long vba, unsigned long hint) { u64 pa; /* physical address */ @@ -615,7 +613,7 @@ static void sba_mark_invalid(struct ioc *ioc, dma_addr_t iova, size_t byte_cnt) { u32 iovp = (u32) SBA_IOVP(ioc,iova); - u64 *pdir_ptr = &ioc->pdir_base[PDIR_INDEX(iovp)]; + __le64 *pdir_ptr = &ioc->pdir_base[PDIR_INDEX(iovp)]; #ifdef ASSERT_PDIR_SANITY /* Assert first pdir entry is set. @@ -716,7 +714,7 @@ sba_map_single(struct device *dev, void *addr, size_t size, unsigned long flags; dma_addr_t iovp; dma_addr_t offset; - u64 *pdir_start; + __le64 *pdir_start; int pide; ioc = GET_IOC(dev); @@ -1434,7 +1432,7 @@ sba_ioc_init(struct parisc_device *sba, struct ioc *ioc, int ioc_num) ioc->pdir_size = pdir_size = (iova_space_size/IOVP_SIZE) * sizeof(u64); - DBG_INIT("%s() hpa 0x%lx mem %ldMB IOV %dMB (%d bits)\n", + DBG_INIT("%s() hpa %px mem %ldMB IOV %dMB (%d bits)\n", __func__, ioc->ioc_hpa, (unsigned long) totalram_pages() >> (20 - PAGE_SHIFT), @@ -1471,7 +1469,7 @@ sba_ioc_init(struct parisc_device *sba, struct ioc *ioc, int ioc_num) ioc->iovp_mask = ~(iova_space_mask + PAGE_SIZE - 1); #endif - DBG_INIT("%s() IOV base 0x%lx mask 0x%0lx\n", + DBG_INIT("%s() IOV base %#lx mask %#0lx\n", __func__, ioc->ibase, ioc->imask); /* @@ -1583,7 +1581,7 @@ printk("sba_hw_init(): mem_boot 0x%x 0x%x 0x%x 0x%x\n", PAGE0->mem_boot.hpa, if (!IS_PLUTO(sba_dev->dev)) { ioc_ctl = READ_REG(sba_dev->sba_hpa+IOC_CTRL); - DBG_INIT("%s() hpa 0x%lx ioc_ctl 0x%Lx ->", + DBG_INIT("%s() hpa %px ioc_ctl 0x%Lx ->", __func__, sba_dev->sba_hpa, ioc_ctl); ioc_ctl &= ~(IOC_CTRL_RM | IOC_CTRL_NC | IOC_CTRL_CE); ioc_ctl |= IOC_CTRL_DD | IOC_CTRL_D4 | IOC_CTRL_TC; @@ -1668,14 +1666,14 @@ printk("sba_hw_init(): mem_boot 0x%x 0x%x 0x%x 0x%x\n", PAGE0->mem_boot.hpa, /* flush out the last writes */ READ_REG(sba_dev->ioc[i].ioc_hpa + ROPE7_CTL); - DBG_INIT(" ioc[%d] ROPE_CFG 0x%Lx ROPE_DBG 0x%Lx\n", + DBG_INIT(" ioc[%d] ROPE_CFG %#lx ROPE_DBG %lx\n", i, - READ_REG(sba_dev->ioc[i].ioc_hpa + 0x40), - READ_REG(sba_dev->ioc[i].ioc_hpa + 0x50) + (unsigned long) READ_REG(sba_dev->ioc[i].ioc_hpa + 0x40), + (unsigned long) READ_REG(sba_dev->ioc[i].ioc_hpa + 0x50) ); - DBG_INIT(" STATUS_CONTROL 0x%Lx FLUSH_CTRL 0x%Lx\n", - READ_REG(sba_dev->ioc[i].ioc_hpa + 0x108), - READ_REG(sba_dev->ioc[i].ioc_hpa + 0x400) + DBG_INIT(" STATUS_CONTROL %#lx FLUSH_CTRL %#lx\n", + (unsigned long) READ_REG(sba_dev->ioc[i].ioc_hpa + 0x108), + (unsigned long) READ_REG(sba_dev->ioc[i].ioc_hpa + 0x400) ); if (IS_PLUTO(sba_dev->dev)) { @@ -1739,7 +1737,7 @@ sba_common_init(struct sba_device *sba_dev) #ifdef ASSERT_PDIR_SANITY /* Mark first bit busy - ie no IOVA 0 */ sba_dev->ioc[i].res_map[0] = 0x80; - sba_dev->ioc[i].pdir_base[0] = 0xeeffc0addbba0080ULL; + sba_dev->ioc[i].pdir_base[0] = (__force __le64) 0xeeffc0addbba0080ULL; #endif /* Third (and last) part of PIRANHA BUG */ @@ -1899,9 +1897,7 @@ static int __init sba_driver_callback(struct parisc_device *dev) int i; char *version; void __iomem *sba_addr = ioremap(dev->hpa.start, SBA_FUNC_SIZE); -#ifdef CONFIG_PROC_FS - struct proc_dir_entry *root; -#endif + struct proc_dir_entry *root __maybe_unused; sba_dump_ranges(sba_addr); @@ -1967,7 +1963,6 @@ static int __init sba_driver_callback(struct parisc_device *dev) hppa_dma_ops = &sba_ops; -#ifdef CONFIG_PROC_FS switch (dev->id.hversion) { case PLUTO_MCKINLEY_PORT: if (!proc_mckinley_root) @@ -1985,7 +1980,6 @@ static int __init sba_driver_callback(struct parisc_device *dev) proc_create_single("sba_iommu", 0, root, sba_proc_info); proc_create_single("sba_iommu-bitmap", 0, root, sba_proc_bitmap_info); -#endif return 0; } diff --git a/drivers/pci/pcie/aer.c b/drivers/pci/pcie/aer.c index e85ff946e8c8..9c8fd69ae5ad 100644 --- a/drivers/pci/pcie/aer.c +++ b/drivers/pci/pcie/aer.c @@ -229,6 +229,7 @@ int pcie_aer_is_native(struct pci_dev *dev) return pcie_ports_native || host->native_aer; } +EXPORT_SYMBOL_NS_GPL(pcie_aer_is_native, CXL); static int pci_enable_pcie_error_reporting(struct pci_dev *dev) { diff --git a/drivers/pci/pcie/portdrv.h b/drivers/pci/pcie/portdrv.h index 58a2b1a1cae4..1f3803bde7ee 100644 --- a/drivers/pci/pcie/portdrv.h +++ b/drivers/pci/pcie/portdrv.h @@ -29,10 +29,8 @@ extern bool pcie_ports_dpc_native; #ifdef CONFIG_PCIEAER int pcie_aer_init(void); -int pcie_aer_is_native(struct pci_dev *dev); #else static inline int pcie_aer_init(void) { return 0; } -static inline int pcie_aer_is_native(struct pci_dev *dev) { return 0; } #endif #ifdef CONFIG_HOTPLUG_PCI_PCIE diff --git a/drivers/platform/mellanox/Kconfig b/drivers/platform/mellanox/Kconfig index 382793e73a60..f7dfa0e785fd 100644 --- a/drivers/platform/mellanox/Kconfig +++ b/drivers/platform/mellanox/Kconfig @@ -60,6 +60,7 @@ config MLXBF_BOOTCTL tristate "Mellanox BlueField Firmware Boot Control driver" depends on ARM64 depends on ACPI + depends on NET help The Mellanox BlueField firmware implements functionality to request swapping the primary and alternate eMMC boot partition, @@ -80,8 +81,8 @@ config MLXBF_PMC config NVSW_SN2201 tristate "Nvidia SN2201 platform driver support" - depends on HWMON - depends on I2C + depends on HWMON && I2C + depends on ACPI || COMPILE_TEST select REGMAP_I2C help This driver provides support for the Nvidia SN2201 platform. diff --git a/drivers/platform/mellanox/mlxbf-pmc.c b/drivers/platform/mellanox/mlxbf-pmc.c index be967d797c28..2d4bbe99959e 100644 --- a/drivers/platform/mellanox/mlxbf-pmc.c +++ b/drivers/platform/mellanox/mlxbf-pmc.c @@ -191,6 +191,7 @@ static const struct mlxbf_pmc_events mlxbf_pmc_smgen_events[] = { }; static const struct mlxbf_pmc_events mlxbf_pmc_trio_events_1[] = { + { 0x0, "DISABLE" }, { 0xa0, "TPIO_DATA_BEAT" }, { 0xa1, "TDMA_DATA_BEAT" }, { 0xa2, "MAP_DATA_BEAT" }, @@ -214,6 +215,7 @@ static const struct mlxbf_pmc_events mlxbf_pmc_trio_events_1[] = { }; static const struct mlxbf_pmc_events mlxbf_pmc_trio_events_2[] = { + { 0x0, "DISABLE" }, { 0xa0, "TPIO_DATA_BEAT" }, { 0xa1, "TDMA_DATA_BEAT" }, { 0xa2, "MAP_DATA_BEAT" }, @@ -246,6 +248,7 @@ static const struct mlxbf_pmc_events mlxbf_pmc_trio_events_2[] = { }; static const struct mlxbf_pmc_events mlxbf_pmc_ecc_events[] = { + { 0x0, "DISABLE" }, { 0x100, "ECC_SINGLE_ERROR_CNT" }, { 0x104, "ECC_DOUBLE_ERROR_CNT" }, { 0x114, "SERR_INJ" }, @@ -258,6 +261,7 @@ static const struct mlxbf_pmc_events mlxbf_pmc_ecc_events[] = { }; static const struct mlxbf_pmc_events mlxbf_pmc_mss_events[] = { + { 0x0, "DISABLE" }, { 0xc0, "RXREQ_MSS" }, { 0xc1, "RXDAT_MSS" }, { 0xc2, "TXRSP_MSS" }, @@ -265,6 +269,7 @@ static const struct mlxbf_pmc_events mlxbf_pmc_mss_events[] = { }; static const struct mlxbf_pmc_events mlxbf_pmc_hnf_events[] = { + { 0x0, "DISABLE" }, { 0x45, "HNF_REQUESTS" }, { 0x46, "HNF_REJECTS" }, { 0x47, "ALL_BUSY" }, @@ -323,6 +328,7 @@ static const struct mlxbf_pmc_events mlxbf_pmc_hnf_events[] = { }; static const struct mlxbf_pmc_events mlxbf_pmc_hnfnet_events[] = { + { 0x0, "DISABLE" }, { 0x12, "CDN_REQ" }, { 0x13, "DDN_REQ" }, { 0x14, "NDN_REQ" }, @@ -892,7 +898,7 @@ static int mlxbf_pmc_read_event(int blk_num, uint32_t cnt_num, bool is_l3, uint64_t *result) { uint32_t perfcfg_offset, perfval_offset; - uint64_t perfmon_cfg, perfevt, perfctl; + uint64_t perfmon_cfg, perfevt; if (cnt_num >= pmc->block[blk_num].counters) return -EINVAL; @@ -906,25 +912,6 @@ static int mlxbf_pmc_read_event(int blk_num, uint32_t cnt_num, bool is_l3, /* Set counter in "read" mode */ perfmon_cfg = FIELD_PREP(MLXBF_PMC_PERFMON_CONFIG_ADDR, - MLXBF_PMC_PERFCTL); - perfmon_cfg |= FIELD_PREP(MLXBF_PMC_PERFMON_CONFIG_STROBE, 1); - perfmon_cfg |= FIELD_PREP(MLXBF_PMC_PERFMON_CONFIG_WR_R_B, 0); - - if (mlxbf_pmc_write(pmc->block[blk_num].mmio_base + perfcfg_offset, - MLXBF_PMC_WRITE_REG_64, perfmon_cfg)) - return -EFAULT; - - /* Check if the counter is enabled */ - - if (mlxbf_pmc_read(pmc->block[blk_num].mmio_base + perfval_offset, - MLXBF_PMC_READ_REG_64, &perfctl)) - return -EFAULT; - - if (!FIELD_GET(MLXBF_PMC_PERFCTL_EN0, perfctl)) - return -EINVAL; - - /* Set counter in "read" mode */ - perfmon_cfg = FIELD_PREP(MLXBF_PMC_PERFMON_CONFIG_ADDR, MLXBF_PMC_PERFEVT); perfmon_cfg |= FIELD_PREP(MLXBF_PMC_PERFMON_CONFIG_STROBE, 1); perfmon_cfg |= FIELD_PREP(MLXBF_PMC_PERFMON_CONFIG_WR_R_B, 0); @@ -1008,7 +995,7 @@ static ssize_t mlxbf_pmc_counter_show(struct device *dev, } else return -EINVAL; - return sprintf(buf, "0x%llx\n", value); + return sysfs_emit(buf, "0x%llx\n", value); } /* Store function for "counter" sysfs files */ @@ -1078,13 +1065,13 @@ static ssize_t mlxbf_pmc_event_show(struct device *dev, err = mlxbf_pmc_read_event(blk_num, cnt_num, is_l3, &evt_num); if (err) - return sprintf(buf, "No event being monitored\n"); + return sysfs_emit(buf, "No event being monitored\n"); evt_name = mlxbf_pmc_get_event_name(pmc->block_name[blk_num], evt_num); if (!evt_name) return -EINVAL; - return sprintf(buf, "0x%llx: %s\n", evt_num, evt_name); + return sysfs_emit(buf, "0x%llx: %s\n", evt_num, evt_name); } /* Store function for "event" sysfs files */ @@ -1139,9 +1126,9 @@ static ssize_t mlxbf_pmc_event_list_show(struct device *dev, return -EINVAL; for (i = 0, buf[0] = '\0'; i < size; ++i) { - len += sprintf(e_info, "0x%x: %s\n", events[i].evt_num, - events[i].evt_name); - if (len > PAGE_SIZE) + len += snprintf(e_info, sizeof(e_info), "0x%x: %s\n", + events[i].evt_num, events[i].evt_name); + if (len >= PAGE_SIZE) break; strcat(buf, e_info); ret = len; @@ -1168,7 +1155,7 @@ static ssize_t mlxbf_pmc_enable_show(struct device *dev, value = FIELD_GET(MLXBF_PMC_L3C_PERF_CNT_CFG_EN, perfcnt_cfg); - return sprintf(buf, "%d\n", value); + return sysfs_emit(buf, "%d\n", value); } /* Store function for "enable" sysfs files - only for l3cache */ diff --git a/drivers/platform/mellanox/mlxbf-tmfifo.c b/drivers/platform/mellanox/mlxbf-tmfifo.c index b600b77d91ef..f3696a54a2bd 100644 --- a/drivers/platform/mellanox/mlxbf-tmfifo.c +++ b/drivers/platform/mellanox/mlxbf-tmfifo.c @@ -59,6 +59,7 @@ struct mlxbf_tmfifo; * @vq: pointer to the virtio virtqueue * @desc: current descriptor of the pending packet * @desc_head: head descriptor of the pending packet + * @drop_desc: dummy desc for packet dropping * @cur_len: processed length of the current descriptor * @rem_len: remaining length of the pending packet * @pkt_len: total length of the pending packet @@ -75,6 +76,7 @@ struct mlxbf_tmfifo_vring { struct virtqueue *vq; struct vring_desc *desc; struct vring_desc *desc_head; + struct vring_desc drop_desc; int cur_len; int rem_len; u32 pkt_len; @@ -86,6 +88,14 @@ struct mlxbf_tmfifo_vring { struct mlxbf_tmfifo *fifo; }; +/* Check whether vring is in drop mode. */ +#define IS_VRING_DROP(_r) ({ \ + typeof(_r) (r) = (_r); \ + (r->desc_head == &r->drop_desc ? true : false); }) + +/* A stub length to drop maximum length packet. */ +#define VRING_DROP_DESC_MAX_LEN GENMASK(15, 0) + /* Interrupt types. */ enum { MLXBF_TM_RX_LWM_IRQ, @@ -214,7 +224,7 @@ static u8 mlxbf_tmfifo_net_default_mac[ETH_ALEN] = { static efi_char16_t mlxbf_tmfifo_efi_name[] = L"RshimMacAddr"; /* Maximum L2 header length. */ -#define MLXBF_TMFIFO_NET_L2_OVERHEAD 36 +#define MLXBF_TMFIFO_NET_L2_OVERHEAD (ETH_HLEN + VLAN_HLEN) /* Supported virtio-net features. */ #define MLXBF_TMFIFO_NET_FEATURES \ @@ -262,6 +272,7 @@ static int mlxbf_tmfifo_alloc_vrings(struct mlxbf_tmfifo *fifo, vring->align = SMP_CACHE_BYTES; vring->index = i; vring->vdev_id = tm_vdev->vdev.id.device; + vring->drop_desc.len = VRING_DROP_DESC_MAX_LEN; dev = &tm_vdev->vdev.dev; size = vring_size(vring->num, vring->align); @@ -367,7 +378,7 @@ static u32 mlxbf_tmfifo_get_pkt_len(struct mlxbf_tmfifo_vring *vring, return len; } -static void mlxbf_tmfifo_release_pending_pkt(struct mlxbf_tmfifo_vring *vring) +static void mlxbf_tmfifo_release_pkt(struct mlxbf_tmfifo_vring *vring) { struct vring_desc *desc_head; u32 len = 0; @@ -596,19 +607,25 @@ static void mlxbf_tmfifo_rxtx_word(struct mlxbf_tmfifo_vring *vring, if (vring->cur_len + sizeof(u64) <= len) { /* The whole word. */ - if (is_rx) - memcpy(addr + vring->cur_len, &data, sizeof(u64)); - else - memcpy(&data, addr + vring->cur_len, sizeof(u64)); + if (!IS_VRING_DROP(vring)) { + if (is_rx) + memcpy(addr + vring->cur_len, &data, + sizeof(u64)); + else + memcpy(&data, addr + vring->cur_len, + sizeof(u64)); + } vring->cur_len += sizeof(u64); } else { /* Leftover bytes. */ - if (is_rx) - memcpy(addr + vring->cur_len, &data, - len - vring->cur_len); - else - memcpy(&data, addr + vring->cur_len, - len - vring->cur_len); + if (!IS_VRING_DROP(vring)) { + if (is_rx) + memcpy(addr + vring->cur_len, &data, + len - vring->cur_len); + else + memcpy(&data, addr + vring->cur_len, + len - vring->cur_len); + } vring->cur_len = len; } @@ -625,13 +642,14 @@ static void mlxbf_tmfifo_rxtx_word(struct mlxbf_tmfifo_vring *vring, * flag is set. */ static void mlxbf_tmfifo_rxtx_header(struct mlxbf_tmfifo_vring *vring, - struct vring_desc *desc, + struct vring_desc **desc, bool is_rx, bool *vring_change) { struct mlxbf_tmfifo *fifo = vring->fifo; struct virtio_net_config *config; struct mlxbf_tmfifo_msg_hdr hdr; int vdev_id, hdr_len; + bool drop_rx = false; /* Read/Write packet header. */ if (is_rx) { @@ -651,8 +669,8 @@ static void mlxbf_tmfifo_rxtx_header(struct mlxbf_tmfifo_vring *vring, if (ntohs(hdr.len) > __virtio16_to_cpu(virtio_legacy_is_little_endian(), config->mtu) + - MLXBF_TMFIFO_NET_L2_OVERHEAD) - return; + MLXBF_TMFIFO_NET_L2_OVERHEAD) + drop_rx = true; } else { vdev_id = VIRTIO_ID_CONSOLE; hdr_len = 0; @@ -667,16 +685,25 @@ static void mlxbf_tmfifo_rxtx_header(struct mlxbf_tmfifo_vring *vring, if (!tm_dev2) return; - vring->desc = desc; + vring->desc = *desc; vring = &tm_dev2->vrings[MLXBF_TMFIFO_VRING_RX]; *vring_change = true; } + + if (drop_rx && !IS_VRING_DROP(vring)) { + if (vring->desc_head) + mlxbf_tmfifo_release_pkt(vring); + *desc = &vring->drop_desc; + vring->desc_head = *desc; + vring->desc = *desc; + } + vring->pkt_len = ntohs(hdr.len) + hdr_len; } else { /* Network virtio has an extra header. */ hdr_len = (vring->vdev_id == VIRTIO_ID_NET) ? sizeof(struct virtio_net_hdr) : 0; - vring->pkt_len = mlxbf_tmfifo_get_pkt_len(vring, desc); + vring->pkt_len = mlxbf_tmfifo_get_pkt_len(vring, *desc); hdr.type = (vring->vdev_id == VIRTIO_ID_NET) ? VIRTIO_ID_NET : VIRTIO_ID_CONSOLE; hdr.len = htons(vring->pkt_len - hdr_len); @@ -709,15 +736,23 @@ static bool mlxbf_tmfifo_rxtx_one_desc(struct mlxbf_tmfifo_vring *vring, /* Get the descriptor of the next packet. */ if (!vring->desc) { desc = mlxbf_tmfifo_get_next_pkt(vring, is_rx); - if (!desc) - return false; + if (!desc) { + /* Drop next Rx packet to avoid stuck. */ + if (is_rx) { + desc = &vring->drop_desc; + vring->desc_head = desc; + vring->desc = desc; + } else { + return false; + } + } } else { desc = vring->desc; } /* Beginning of a packet. Start to Rx/Tx packet header. */ if (vring->pkt_len == 0) { - mlxbf_tmfifo_rxtx_header(vring, desc, is_rx, &vring_change); + mlxbf_tmfifo_rxtx_header(vring, &desc, is_rx, &vring_change); (*avail)--; /* Return if new packet is for another ring. */ @@ -743,17 +778,24 @@ static bool mlxbf_tmfifo_rxtx_one_desc(struct mlxbf_tmfifo_vring *vring, vring->rem_len -= len; /* Get the next desc on the chain. */ - if (vring->rem_len > 0 && + if (!IS_VRING_DROP(vring) && vring->rem_len > 0 && (virtio16_to_cpu(vdev, desc->flags) & VRING_DESC_F_NEXT)) { idx = virtio16_to_cpu(vdev, desc->next); desc = &vr->desc[idx]; goto mlxbf_tmfifo_desc_done; } - /* Done and release the pending packet. */ - mlxbf_tmfifo_release_pending_pkt(vring); + /* Done and release the packet. */ desc = NULL; fifo->vring[is_rx] = NULL; + if (!IS_VRING_DROP(vring)) { + mlxbf_tmfifo_release_pkt(vring); + } else { + vring->pkt_len = 0; + vring->desc_head = NULL; + vring->desc = NULL; + return false; + } /* * Make sure the load/store are in order before @@ -933,7 +975,7 @@ static void mlxbf_tmfifo_virtio_del_vqs(struct virtio_device *vdev) /* Release the pending packet. */ if (vring->desc) - mlxbf_tmfifo_release_pending_pkt(vring); + mlxbf_tmfifo_release_pkt(vring); vq = vring->vq; if (vq) { vring->vq = NULL; diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c index fdf7da06af30..d85d895fee89 100644 --- a/drivers/platform/x86/asus-nb-wmi.c +++ b/drivers/platform/x86/asus-nb-wmi.c @@ -480,6 +480,15 @@ static const struct dmi_system_id asus_quirks[] = { }, { .callback = dmi_matched, + .ident = "ASUS ROG FLOW X16", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "GV601V"), + }, + .driver_data = &quirk_asus_tablet_mode, + }, + { + .callback = dmi_matched, .ident = "ASUS VivoBook E410MA", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), diff --git a/drivers/platform/x86/intel_scu_ipc.c b/drivers/platform/x86/intel_scu_ipc.c index 6851d10d6582..a68df4133403 100644 --- a/drivers/platform/x86/intel_scu_ipc.c +++ b/drivers/platform/x86/intel_scu_ipc.c @@ -19,6 +19,7 @@ #include <linux/init.h> #include <linux/interrupt.h> #include <linux/io.h> +#include <linux/iopoll.h> #include <linux/module.h> #include <linux/slab.h> @@ -231,19 +232,15 @@ static inline u32 ipc_data_readl(struct intel_scu_ipc_dev *scu, u32 offset) /* Wait till scu status is busy */ static inline int busy_loop(struct intel_scu_ipc_dev *scu) { - unsigned long end = jiffies + IPC_TIMEOUT; - - do { - u32 status; - - status = ipc_read_status(scu); - if (!(status & IPC_STATUS_BUSY)) - return (status & IPC_STATUS_ERR) ? -EIO : 0; + u8 status; + int err; - usleep_range(50, 100); - } while (time_before(jiffies, end)); + err = readx_poll_timeout(ipc_read_status, scu, status, !(status & IPC_STATUS_BUSY), + 100, jiffies_to_usecs(IPC_TIMEOUT)); + if (err) + return err; - return -ETIMEDOUT; + return (status & IPC_STATUS_ERR) ? -EIO : 0; } /* Wait till ipc ioc interrupt is received or timeout in 10 HZ */ @@ -251,10 +248,12 @@ static inline int ipc_wait_for_interrupt(struct intel_scu_ipc_dev *scu) { int status; - if (!wait_for_completion_timeout(&scu->cmd_complete, IPC_TIMEOUT)) - return -ETIMEDOUT; + wait_for_completion_timeout(&scu->cmd_complete, IPC_TIMEOUT); status = ipc_read_status(scu); + if (status & IPC_STATUS_BUSY) + return -ETIMEDOUT; + if (status & IPC_STATUS_ERR) return -EIO; @@ -266,6 +265,24 @@ static int intel_scu_ipc_check_status(struct intel_scu_ipc_dev *scu) return scu->irq > 0 ? ipc_wait_for_interrupt(scu) : busy_loop(scu); } +static struct intel_scu_ipc_dev *intel_scu_ipc_get(struct intel_scu_ipc_dev *scu) +{ + u8 status; + + if (!scu) + scu = ipcdev; + if (!scu) + return ERR_PTR(-ENODEV); + + status = ipc_read_status(scu); + if (status & IPC_STATUS_BUSY) { + dev_dbg(&scu->dev, "device is busy\n"); + return ERR_PTR(-EBUSY); + } + + return scu; +} + /* Read/Write power control(PMIC in Langwell, MSIC in PenWell) registers */ static int pwr_reg_rdwr(struct intel_scu_ipc_dev *scu, u16 *addr, u8 *data, u32 count, u32 op, u32 id) @@ -279,11 +296,10 @@ static int pwr_reg_rdwr(struct intel_scu_ipc_dev *scu, u16 *addr, u8 *data, memset(cbuf, 0, sizeof(cbuf)); mutex_lock(&ipclock); - if (!scu) - scu = ipcdev; - if (!scu) { + scu = intel_scu_ipc_get(scu); + if (IS_ERR(scu)) { mutex_unlock(&ipclock); - return -ENODEV; + return PTR_ERR(scu); } for (nc = 0; nc < count; nc++, offset += 2) { @@ -438,13 +454,12 @@ int intel_scu_ipc_dev_simple_command(struct intel_scu_ipc_dev *scu, int cmd, int err; mutex_lock(&ipclock); - if (!scu) - scu = ipcdev; - if (!scu) { + scu = intel_scu_ipc_get(scu); + if (IS_ERR(scu)) { mutex_unlock(&ipclock); - return -ENODEV; + return PTR_ERR(scu); } - scu = ipcdev; + cmdval = sub << 12 | cmd; ipc_command(scu, cmdval); err = intel_scu_ipc_check_status(scu); @@ -484,11 +499,10 @@ int intel_scu_ipc_dev_command_with_size(struct intel_scu_ipc_dev *scu, int cmd, return -EINVAL; mutex_lock(&ipclock); - if (!scu) - scu = ipcdev; - if (!scu) { + scu = intel_scu_ipc_get(scu); + if (IS_ERR(scu)) { mutex_unlock(&ipclock); - return -ENODEV; + return PTR_ERR(scu); } memcpy(inbuf, in, inlen); diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index d70c89d32534..41584427dc32 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -4116,9 +4116,11 @@ static void hotkey_resume(void) { tpacpi_disable_brightness_delay(); + mutex_lock(&hotkey_mutex); if (hotkey_status_set(true) < 0 || hotkey_mask_set(hotkey_acpi_mask) < 0) pr_err("error while attempting to reset the event firmware interface\n"); + mutex_unlock(&hotkey_mutex); tpacpi_send_radiosw_update(); tpacpi_input_send_tabletsw(); diff --git a/drivers/genpd/Makefile b/drivers/pmdomain/Makefile index 666753676e5c..f0326b27b30b 100644 --- a/drivers/genpd/Makefile +++ b/drivers/pmdomain/Makefile @@ -2,6 +2,7 @@ obj-y += actions/ obj-y += amlogic/ obj-y += apple/ +obj-y += arm/ obj-y += bcm/ obj-y += imx/ obj-y += mediatek/ diff --git a/drivers/genpd/actions/Makefile b/drivers/pmdomain/actions/Makefile index 7e8aa473d12d..7e8aa473d12d 100644 --- a/drivers/genpd/actions/Makefile +++ b/drivers/pmdomain/actions/Makefile diff --git a/drivers/genpd/actions/owl-sps-helper.c b/drivers/pmdomain/actions/owl-sps-helper.c index e3f36603dd53..e3f36603dd53 100644 --- a/drivers/genpd/actions/owl-sps-helper.c +++ b/drivers/pmdomain/actions/owl-sps-helper.c diff --git a/drivers/genpd/actions/owl-sps.c b/drivers/pmdomain/actions/owl-sps.c index 73a9e0bb7e8e..73a9e0bb7e8e 100644 --- a/drivers/genpd/actions/owl-sps.c +++ b/drivers/pmdomain/actions/owl-sps.c diff --git a/drivers/genpd/amlogic/Makefile b/drivers/pmdomain/amlogic/Makefile index 3d58abd574f9..3d58abd574f9 100644 --- a/drivers/genpd/amlogic/Makefile +++ b/drivers/pmdomain/amlogic/Makefile diff --git a/drivers/genpd/amlogic/meson-ee-pwrc.c b/drivers/pmdomain/amlogic/meson-ee-pwrc.c index cfb796d40d9d..cfb796d40d9d 100644 --- a/drivers/genpd/amlogic/meson-ee-pwrc.c +++ b/drivers/pmdomain/amlogic/meson-ee-pwrc.c diff --git a/drivers/genpd/amlogic/meson-gx-pwrc-vpu.c b/drivers/pmdomain/amlogic/meson-gx-pwrc-vpu.c index 33df520eab95..33df520eab95 100644 --- a/drivers/genpd/amlogic/meson-gx-pwrc-vpu.c +++ b/drivers/pmdomain/amlogic/meson-gx-pwrc-vpu.c diff --git a/drivers/genpd/amlogic/meson-secure-pwrc.c b/drivers/pmdomain/amlogic/meson-secure-pwrc.c index 89c881c56cd7..89c881c56cd7 100644 --- a/drivers/genpd/amlogic/meson-secure-pwrc.c +++ b/drivers/pmdomain/amlogic/meson-secure-pwrc.c diff --git a/drivers/genpd/apple/Makefile b/drivers/pmdomain/apple/Makefile index 53665af630be..53665af630be 100644 --- a/drivers/genpd/apple/Makefile +++ b/drivers/pmdomain/apple/Makefile diff --git a/drivers/genpd/apple/pmgr-pwrstate.c b/drivers/pmdomain/apple/pmgr-pwrstate.c index d62a776c89a1..d62a776c89a1 100644 --- a/drivers/genpd/apple/pmgr-pwrstate.c +++ b/drivers/pmdomain/apple/pmgr-pwrstate.c diff --git a/drivers/pmdomain/arm/Makefile b/drivers/pmdomain/arm/Makefile new file mode 100644 index 000000000000..cfcb1f6cdd90 --- /dev/null +++ b/drivers/pmdomain/arm/Makefile @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only + +obj-$(CONFIG_ARM_SCMI_PERF_DOMAIN) += scmi_perf_domain.o +obj-$(CONFIG_ARM_SCMI_POWER_DOMAIN) += scmi_pm_domain.o diff --git a/drivers/pmdomain/arm/scmi_perf_domain.c b/drivers/pmdomain/arm/scmi_perf_domain.c new file mode 100644 index 000000000000..bc3f78abb6da --- /dev/null +++ b/drivers/pmdomain/arm/scmi_perf_domain.c @@ -0,0 +1,184 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * SCMI performance domain support. + * + * Copyright (C) 2023 Linaro Ltd. + */ + +#include <linux/err.h> +#include <linux/device.h> +#include <linux/module.h> +#include <linux/pm_domain.h> +#include <linux/pm_opp.h> +#include <linux/scmi_protocol.h> +#include <linux/slab.h> + +struct scmi_perf_domain { + struct generic_pm_domain genpd; + const struct scmi_perf_proto_ops *perf_ops; + const struct scmi_protocol_handle *ph; + const struct scmi_perf_domain_info *info; + u32 domain_id; +}; + +#define to_scmi_pd(pd) container_of(pd, struct scmi_perf_domain, genpd) + +static int +scmi_pd_set_perf_state(struct generic_pm_domain *genpd, unsigned int state) +{ + struct scmi_perf_domain *pd = to_scmi_pd(genpd); + int ret; + + if (!pd->info->set_perf) + return 0; + + if (!state) + return -EINVAL; + + ret = pd->perf_ops->level_set(pd->ph, pd->domain_id, state, true); + if (ret) + dev_warn(&genpd->dev, "Failed with %d when trying to set %d perf level", + ret, state); + + return ret; +} + +static int +scmi_pd_attach_dev(struct generic_pm_domain *genpd, struct device *dev) +{ + struct scmi_perf_domain *pd = to_scmi_pd(genpd); + int ret; + + /* + * Allow the device to be attached, but don't add the OPP table unless + * the performance level can be changed. + */ + if (!pd->info->set_perf) + return 0; + + ret = pd->perf_ops->device_opps_add(pd->ph, dev, pd->domain_id); + if (ret) + dev_warn(dev, "failed to add OPPs for the device\n"); + + return ret; +} + +static void +scmi_pd_detach_dev(struct generic_pm_domain *genpd, struct device *dev) +{ + struct scmi_perf_domain *pd = to_scmi_pd(genpd); + + if (!pd->info->set_perf) + return; + + dev_pm_opp_remove_all_dynamic(dev); +} + +static int scmi_perf_domain_probe(struct scmi_device *sdev) +{ + struct device *dev = &sdev->dev; + const struct scmi_handle *handle = sdev->handle; + const struct scmi_perf_proto_ops *perf_ops; + struct scmi_protocol_handle *ph; + struct scmi_perf_domain *scmi_pd; + struct genpd_onecell_data *scmi_pd_data; + struct generic_pm_domain **domains; + int num_domains, i, ret = 0; + + if (!handle) + return -ENODEV; + + /* The OF node must specify us as a power-domain provider. */ + if (!of_find_property(dev->of_node, "#power-domain-cells", NULL)) + return 0; + + perf_ops = handle->devm_protocol_get(sdev, SCMI_PROTOCOL_PERF, &ph); + if (IS_ERR(perf_ops)) + return PTR_ERR(perf_ops); + + num_domains = perf_ops->num_domains_get(ph); + if (num_domains < 0) { + dev_warn(dev, "Failed with %d when getting num perf domains\n", + num_domains); + return num_domains; + } else if (!num_domains) { + return 0; + } + + scmi_pd = devm_kcalloc(dev, num_domains, sizeof(*scmi_pd), GFP_KERNEL); + if (!scmi_pd) + return -ENOMEM; + + scmi_pd_data = devm_kzalloc(dev, sizeof(*scmi_pd_data), GFP_KERNEL); + if (!scmi_pd_data) + return -ENOMEM; + + domains = devm_kcalloc(dev, num_domains, sizeof(*domains), GFP_KERNEL); + if (!domains) + return -ENOMEM; + + for (i = 0; i < num_domains; i++, scmi_pd++) { + scmi_pd->info = perf_ops->info_get(ph, i); + + scmi_pd->domain_id = i; + scmi_pd->perf_ops = perf_ops; + scmi_pd->ph = ph; + scmi_pd->genpd.name = scmi_pd->info->name; + scmi_pd->genpd.flags = GENPD_FLAG_ALWAYS_ON | + GENPD_FLAG_OPP_TABLE_FW; + scmi_pd->genpd.set_performance_state = scmi_pd_set_perf_state; + scmi_pd->genpd.attach_dev = scmi_pd_attach_dev; + scmi_pd->genpd.detach_dev = scmi_pd_detach_dev; + + ret = pm_genpd_init(&scmi_pd->genpd, NULL, false); + if (ret) + goto err; + + domains[i] = &scmi_pd->genpd; + } + + scmi_pd_data->domains = domains; + scmi_pd_data->num_domains = num_domains; + + ret = of_genpd_add_provider_onecell(dev->of_node, scmi_pd_data); + if (ret) + goto err; + + dev_set_drvdata(dev, scmi_pd_data); + dev_info(dev, "Initialized %d performance domains", num_domains); + return 0; +err: + for (i--; i >= 0; i--) + pm_genpd_remove(domains[i]); + return ret; +} + +static void scmi_perf_domain_remove(struct scmi_device *sdev) +{ + struct device *dev = &sdev->dev; + struct genpd_onecell_data *scmi_pd_data = dev_get_drvdata(dev); + int i; + + of_genpd_del_provider(dev->of_node); + + for (i = 0; i < scmi_pd_data->num_domains; i++) + pm_genpd_remove(scmi_pd_data->domains[i]); +} + +static const struct scmi_device_id scmi_id_table[] = { + { SCMI_PROTOCOL_PERF, "perf" }, + { }, +}; +MODULE_DEVICE_TABLE(scmi, scmi_id_table); + +static struct scmi_driver scmi_perf_domain_driver = { + .name = "scmi-perf-domain", + .probe = scmi_perf_domain_probe, + .remove = scmi_perf_domain_remove, + .id_table = scmi_id_table, +}; +module_scmi_driver(scmi_perf_domain_driver); + +MODULE_AUTHOR("Ulf Hansson <ulf.hansson@linaro.org>"); +MODULE_DESCRIPTION("ARM SCMI perf domain driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/firmware/arm_scmi/scmi_pm_domain.c b/drivers/pmdomain/arm/scmi_pm_domain.c index 0e05a79de82d..0e05a79de82d 100644 --- a/drivers/firmware/arm_scmi/scmi_pm_domain.c +++ b/drivers/pmdomain/arm/scmi_pm_domain.c diff --git a/drivers/genpd/bcm/Makefile b/drivers/pmdomain/bcm/Makefile index 6bfbe4e4db13..6bfbe4e4db13 100644 --- a/drivers/genpd/bcm/Makefile +++ b/drivers/pmdomain/bcm/Makefile diff --git a/drivers/genpd/bcm/bcm-pmb.c b/drivers/pmdomain/bcm/bcm-pmb.c index a72ba26ecf9d..a72ba26ecf9d 100644 --- a/drivers/genpd/bcm/bcm-pmb.c +++ b/drivers/pmdomain/bcm/bcm-pmb.c diff --git a/drivers/genpd/bcm/bcm2835-power.c b/drivers/pmdomain/bcm/bcm2835-power.c index 1a179d4e011c..1a179d4e011c 100644 --- a/drivers/genpd/bcm/bcm2835-power.c +++ b/drivers/pmdomain/bcm/bcm2835-power.c diff --git a/drivers/genpd/bcm/bcm63xx-power.c b/drivers/pmdomain/bcm/bcm63xx-power.c index 98b0c2430dbc..98b0c2430dbc 100644 --- a/drivers/genpd/bcm/bcm63xx-power.c +++ b/drivers/pmdomain/bcm/bcm63xx-power.c diff --git a/drivers/genpd/bcm/raspberrypi-power.c b/drivers/pmdomain/bcm/raspberrypi-power.c index 06196ebfe03b..06196ebfe03b 100644 --- a/drivers/genpd/bcm/raspberrypi-power.c +++ b/drivers/pmdomain/bcm/raspberrypi-power.c diff --git a/drivers/genpd/imx/Makefile b/drivers/pmdomain/imx/Makefile index 52d2629014a7..52d2629014a7 100644 --- a/drivers/genpd/imx/Makefile +++ b/drivers/pmdomain/imx/Makefile diff --git a/drivers/genpd/imx/gpc.c b/drivers/pmdomain/imx/gpc.c index 90a8b2c0676f..90a8b2c0676f 100644 --- a/drivers/genpd/imx/gpc.c +++ b/drivers/pmdomain/imx/gpc.c diff --git a/drivers/genpd/imx/gpcv2.c b/drivers/pmdomain/imx/gpcv2.c index fbd3d92f8cd8..fbd3d92f8cd8 100644 --- a/drivers/genpd/imx/gpcv2.c +++ b/drivers/pmdomain/imx/gpcv2.c diff --git a/drivers/genpd/imx/imx8m-blk-ctrl.c b/drivers/pmdomain/imx/imx8m-blk-ctrl.c index cc5ef6e2f0a8..cc5ef6e2f0a8 100644 --- a/drivers/genpd/imx/imx8m-blk-ctrl.c +++ b/drivers/pmdomain/imx/imx8m-blk-ctrl.c diff --git a/drivers/genpd/imx/imx8mp-blk-ctrl.c b/drivers/pmdomain/imx/imx8mp-blk-ctrl.c index c6ac32c1a8c1..c6ac32c1a8c1 100644 --- a/drivers/genpd/imx/imx8mp-blk-ctrl.c +++ b/drivers/pmdomain/imx/imx8mp-blk-ctrl.c diff --git a/drivers/genpd/imx/imx93-blk-ctrl.c b/drivers/pmdomain/imx/imx93-blk-ctrl.c index 40bd90f8b977..40bd90f8b977 100644 --- a/drivers/genpd/imx/imx93-blk-ctrl.c +++ b/drivers/pmdomain/imx/imx93-blk-ctrl.c diff --git a/drivers/genpd/imx/imx93-pd.c b/drivers/pmdomain/imx/imx93-pd.c index b9e60d136875..b9e60d136875 100644 --- a/drivers/genpd/imx/imx93-pd.c +++ b/drivers/pmdomain/imx/imx93-pd.c diff --git a/drivers/genpd/imx/scu-pd.c b/drivers/pmdomain/imx/scu-pd.c index 2f693b67ddb4..2f693b67ddb4 100644 --- a/drivers/genpd/imx/scu-pd.c +++ b/drivers/pmdomain/imx/scu-pd.c diff --git a/drivers/genpd/mediatek/Makefile b/drivers/pmdomain/mediatek/Makefile index 8cde09e654b3..8cde09e654b3 100644 --- a/drivers/genpd/mediatek/Makefile +++ b/drivers/pmdomain/mediatek/Makefile diff --git a/drivers/genpd/mediatek/mt6795-pm-domains.h b/drivers/pmdomain/mediatek/mt6795-pm-domains.h index ef07c9dfdd9b..ef07c9dfdd9b 100644 --- a/drivers/genpd/mediatek/mt6795-pm-domains.h +++ b/drivers/pmdomain/mediatek/mt6795-pm-domains.h diff --git a/drivers/genpd/mediatek/mt8167-pm-domains.h b/drivers/pmdomain/mediatek/mt8167-pm-domains.h index 4d6c32759606..4d6c32759606 100644 --- a/drivers/genpd/mediatek/mt8167-pm-domains.h +++ b/drivers/pmdomain/mediatek/mt8167-pm-domains.h diff --git a/drivers/genpd/mediatek/mt8173-pm-domains.h b/drivers/pmdomain/mediatek/mt8173-pm-domains.h index 1a5dc63b7357..1a5dc63b7357 100644 --- a/drivers/genpd/mediatek/mt8173-pm-domains.h +++ b/drivers/pmdomain/mediatek/mt8173-pm-domains.h diff --git a/drivers/genpd/mediatek/mt8183-pm-domains.h b/drivers/pmdomain/mediatek/mt8183-pm-domains.h index 99de67fe5de8..99de67fe5de8 100644 --- a/drivers/genpd/mediatek/mt8183-pm-domains.h +++ b/drivers/pmdomain/mediatek/mt8183-pm-domains.h diff --git a/drivers/genpd/mediatek/mt8186-pm-domains.h b/drivers/pmdomain/mediatek/mt8186-pm-domains.h index fce86f79c505..fce86f79c505 100644 --- a/drivers/genpd/mediatek/mt8186-pm-domains.h +++ b/drivers/pmdomain/mediatek/mt8186-pm-domains.h diff --git a/drivers/genpd/mediatek/mt8188-pm-domains.h b/drivers/pmdomain/mediatek/mt8188-pm-domains.h index 0692cb444ed0..0692cb444ed0 100644 --- a/drivers/genpd/mediatek/mt8188-pm-domains.h +++ b/drivers/pmdomain/mediatek/mt8188-pm-domains.h diff --git a/drivers/genpd/mediatek/mt8192-pm-domains.h b/drivers/pmdomain/mediatek/mt8192-pm-domains.h index b97b2051920f..b97b2051920f 100644 --- a/drivers/genpd/mediatek/mt8192-pm-domains.h +++ b/drivers/pmdomain/mediatek/mt8192-pm-domains.h diff --git a/drivers/genpd/mediatek/mt8195-pm-domains.h b/drivers/pmdomain/mediatek/mt8195-pm-domains.h index d7387ea1b9c9..d7387ea1b9c9 100644 --- a/drivers/genpd/mediatek/mt8195-pm-domains.h +++ b/drivers/pmdomain/mediatek/mt8195-pm-domains.h diff --git a/drivers/genpd/mediatek/mtk-pm-domains.c b/drivers/pmdomain/mediatek/mtk-pm-domains.c index ee962804b830..ee962804b830 100644 --- a/drivers/genpd/mediatek/mtk-pm-domains.c +++ b/drivers/pmdomain/mediatek/mtk-pm-domains.c diff --git a/drivers/genpd/mediatek/mtk-pm-domains.h b/drivers/pmdomain/mediatek/mtk-pm-domains.h index 5ec53ee073c4..5ec53ee073c4 100644 --- a/drivers/genpd/mediatek/mtk-pm-domains.h +++ b/drivers/pmdomain/mediatek/mtk-pm-domains.h diff --git a/drivers/genpd/mediatek/mtk-scpsys.c b/drivers/pmdomain/mediatek/mtk-scpsys.c index b374d01fdac7..b374d01fdac7 100644 --- a/drivers/genpd/mediatek/mtk-scpsys.c +++ b/drivers/pmdomain/mediatek/mtk-scpsys.c diff --git a/drivers/genpd/qcom/Makefile b/drivers/pmdomain/qcom/Makefile index 403dfc5af095..403dfc5af095 100644 --- a/drivers/genpd/qcom/Makefile +++ b/drivers/pmdomain/qcom/Makefile diff --git a/drivers/genpd/qcom/cpr.c b/drivers/pmdomain/qcom/cpr.c index 94a3f0977212..94a3f0977212 100644 --- a/drivers/genpd/qcom/cpr.c +++ b/drivers/pmdomain/qcom/cpr.c diff --git a/drivers/genpd/qcom/rpmhpd.c b/drivers/pmdomain/qcom/rpmhpd.c index a87e336d5e33..a87e336d5e33 100644 --- a/drivers/genpd/qcom/rpmhpd.c +++ b/drivers/pmdomain/qcom/rpmhpd.c diff --git a/drivers/genpd/qcom/rpmpd.c b/drivers/pmdomain/qcom/rpmpd.c index 3135dd1dafe0..3135dd1dafe0 100644 --- a/drivers/genpd/qcom/rpmpd.c +++ b/drivers/pmdomain/qcom/rpmpd.c diff --git a/drivers/genpd/renesas/Makefile b/drivers/pmdomain/renesas/Makefile index e306e396fc8c..e306e396fc8c 100644 --- a/drivers/genpd/renesas/Makefile +++ b/drivers/pmdomain/renesas/Makefile diff --git a/drivers/genpd/renesas/r8a7742-sysc.c b/drivers/pmdomain/renesas/r8a7742-sysc.c index 219a675f83f4..219a675f83f4 100644 --- a/drivers/genpd/renesas/r8a7742-sysc.c +++ b/drivers/pmdomain/renesas/r8a7742-sysc.c diff --git a/drivers/genpd/renesas/r8a7743-sysc.c b/drivers/pmdomain/renesas/r8a7743-sysc.c index 4e2c0ab951b3..4e2c0ab951b3 100644 --- a/drivers/genpd/renesas/r8a7743-sysc.c +++ b/drivers/pmdomain/renesas/r8a7743-sysc.c diff --git a/drivers/genpd/renesas/r8a7745-sysc.c b/drivers/pmdomain/renesas/r8a7745-sysc.c index 865821a2f0c6..865821a2f0c6 100644 --- a/drivers/genpd/renesas/r8a7745-sysc.c +++ b/drivers/pmdomain/renesas/r8a7745-sysc.c diff --git a/drivers/genpd/renesas/r8a77470-sysc.c b/drivers/pmdomain/renesas/r8a77470-sysc.c index 1eeb8018df50..1eeb8018df50 100644 --- a/drivers/genpd/renesas/r8a77470-sysc.c +++ b/drivers/pmdomain/renesas/r8a77470-sysc.c diff --git a/drivers/genpd/renesas/r8a774a1-sysc.c b/drivers/pmdomain/renesas/r8a774a1-sysc.c index 38ac2c689ff0..38ac2c689ff0 100644 --- a/drivers/genpd/renesas/r8a774a1-sysc.c +++ b/drivers/pmdomain/renesas/r8a774a1-sysc.c diff --git a/drivers/genpd/renesas/r8a774b1-sysc.c b/drivers/pmdomain/renesas/r8a774b1-sysc.c index 5f97ff26f3f8..5f97ff26f3f8 100644 --- a/drivers/genpd/renesas/r8a774b1-sysc.c +++ b/drivers/pmdomain/renesas/r8a774b1-sysc.c diff --git a/drivers/genpd/renesas/r8a774c0-sysc.c b/drivers/pmdomain/renesas/r8a774c0-sysc.c index c1c216f7d073..c1c216f7d073 100644 --- a/drivers/genpd/renesas/r8a774c0-sysc.c +++ b/drivers/pmdomain/renesas/r8a774c0-sysc.c diff --git a/drivers/genpd/renesas/r8a774e1-sysc.c b/drivers/pmdomain/renesas/r8a774e1-sysc.c index 18449f746455..18449f746455 100644 --- a/drivers/genpd/renesas/r8a774e1-sysc.c +++ b/drivers/pmdomain/renesas/r8a774e1-sysc.c diff --git a/drivers/genpd/renesas/r8a7779-sysc.c b/drivers/pmdomain/renesas/r8a7779-sysc.c index e24a7151d55f..e24a7151d55f 100644 --- a/drivers/genpd/renesas/r8a7779-sysc.c +++ b/drivers/pmdomain/renesas/r8a7779-sysc.c diff --git a/drivers/genpd/renesas/r8a7790-sysc.c b/drivers/pmdomain/renesas/r8a7790-sysc.c index b9afe7f6245b..b9afe7f6245b 100644 --- a/drivers/genpd/renesas/r8a7790-sysc.c +++ b/drivers/pmdomain/renesas/r8a7790-sysc.c diff --git a/drivers/genpd/renesas/r8a7791-sysc.c b/drivers/pmdomain/renesas/r8a7791-sysc.c index f00fa24522a3..f00fa24522a3 100644 --- a/drivers/genpd/renesas/r8a7791-sysc.c +++ b/drivers/pmdomain/renesas/r8a7791-sysc.c diff --git a/drivers/genpd/renesas/r8a7792-sysc.c b/drivers/pmdomain/renesas/r8a7792-sysc.c index 60aae242c43f..60aae242c43f 100644 --- a/drivers/genpd/renesas/r8a7792-sysc.c +++ b/drivers/pmdomain/renesas/r8a7792-sysc.c diff --git a/drivers/genpd/renesas/r8a7794-sysc.c b/drivers/pmdomain/renesas/r8a7794-sysc.c index 72ef4e85458f..72ef4e85458f 100644 --- a/drivers/genpd/renesas/r8a7794-sysc.c +++ b/drivers/pmdomain/renesas/r8a7794-sysc.c diff --git a/drivers/genpd/renesas/r8a7795-sysc.c b/drivers/pmdomain/renesas/r8a7795-sysc.c index cbe1ff0fc583..cbe1ff0fc583 100644 --- a/drivers/genpd/renesas/r8a7795-sysc.c +++ b/drivers/pmdomain/renesas/r8a7795-sysc.c diff --git a/drivers/genpd/renesas/r8a7796-sysc.c b/drivers/pmdomain/renesas/r8a7796-sysc.c index 471bd5b3b6ad..471bd5b3b6ad 100644 --- a/drivers/genpd/renesas/r8a7796-sysc.c +++ b/drivers/pmdomain/renesas/r8a7796-sysc.c diff --git a/drivers/genpd/renesas/r8a77965-sysc.c b/drivers/pmdomain/renesas/r8a77965-sysc.c index ff0b0d116992..ff0b0d116992 100644 --- a/drivers/genpd/renesas/r8a77965-sysc.c +++ b/drivers/pmdomain/renesas/r8a77965-sysc.c diff --git a/drivers/genpd/renesas/r8a77970-sysc.c b/drivers/pmdomain/renesas/r8a77970-sysc.c index 706258250600..706258250600 100644 --- a/drivers/genpd/renesas/r8a77970-sysc.c +++ b/drivers/pmdomain/renesas/r8a77970-sysc.c diff --git a/drivers/genpd/renesas/r8a77980-sysc.c b/drivers/pmdomain/renesas/r8a77980-sysc.c index 39ca84a67daa..39ca84a67daa 100644 --- a/drivers/genpd/renesas/r8a77980-sysc.c +++ b/drivers/pmdomain/renesas/r8a77980-sysc.c diff --git a/drivers/genpd/renesas/r8a77990-sysc.c b/drivers/pmdomain/renesas/r8a77990-sysc.c index 9f92737dc352..9f92737dc352 100644 --- a/drivers/genpd/renesas/r8a77990-sysc.c +++ b/drivers/pmdomain/renesas/r8a77990-sysc.c diff --git a/drivers/genpd/renesas/r8a77995-sysc.c b/drivers/pmdomain/renesas/r8a77995-sysc.c index efcc67e3d76d..efcc67e3d76d 100644 --- a/drivers/genpd/renesas/r8a77995-sysc.c +++ b/drivers/pmdomain/renesas/r8a77995-sysc.c diff --git a/drivers/genpd/renesas/r8a779a0-sysc.c b/drivers/pmdomain/renesas/r8a779a0-sysc.c index 04f1bc322ae7..04f1bc322ae7 100644 --- a/drivers/genpd/renesas/r8a779a0-sysc.c +++ b/drivers/pmdomain/renesas/r8a779a0-sysc.c diff --git a/drivers/genpd/renesas/r8a779f0-sysc.c b/drivers/pmdomain/renesas/r8a779f0-sysc.c index 5602aa6bd7ed..5602aa6bd7ed 100644 --- a/drivers/genpd/renesas/r8a779f0-sysc.c +++ b/drivers/pmdomain/renesas/r8a779f0-sysc.c diff --git a/drivers/genpd/renesas/r8a779g0-sysc.c b/drivers/pmdomain/renesas/r8a779g0-sysc.c index b932eba1b804..b932eba1b804 100644 --- a/drivers/genpd/renesas/r8a779g0-sysc.c +++ b/drivers/pmdomain/renesas/r8a779g0-sysc.c diff --git a/drivers/genpd/renesas/rcar-gen4-sysc.c b/drivers/pmdomain/renesas/rcar-gen4-sysc.c index 9e5e6e077abc..9e5e6e077abc 100644 --- a/drivers/genpd/renesas/rcar-gen4-sysc.c +++ b/drivers/pmdomain/renesas/rcar-gen4-sysc.c diff --git a/drivers/genpd/renesas/rcar-gen4-sysc.h b/drivers/pmdomain/renesas/rcar-gen4-sysc.h index 388cfa8f8f9f..388cfa8f8f9f 100644 --- a/drivers/genpd/renesas/rcar-gen4-sysc.h +++ b/drivers/pmdomain/renesas/rcar-gen4-sysc.h diff --git a/drivers/genpd/renesas/rcar-sysc.c b/drivers/pmdomain/renesas/rcar-sysc.c index eed47696e825..eed47696e825 100644 --- a/drivers/genpd/renesas/rcar-sysc.c +++ b/drivers/pmdomain/renesas/rcar-sysc.c diff --git a/drivers/genpd/renesas/rcar-sysc.h b/drivers/pmdomain/renesas/rcar-sysc.h index 266c599a0a9b..266c599a0a9b 100644 --- a/drivers/genpd/renesas/rcar-sysc.h +++ b/drivers/pmdomain/renesas/rcar-sysc.h diff --git a/drivers/genpd/renesas/rmobile-sysc.c b/drivers/pmdomain/renesas/rmobile-sysc.c index 912daadaa10d..912daadaa10d 100644 --- a/drivers/genpd/renesas/rmobile-sysc.c +++ b/drivers/pmdomain/renesas/rmobile-sysc.c diff --git a/drivers/genpd/rockchip/Makefile b/drivers/pmdomain/rockchip/Makefile index 8fb9d88a3492..8fb9d88a3492 100644 --- a/drivers/genpd/rockchip/Makefile +++ b/drivers/pmdomain/rockchip/Makefile diff --git a/drivers/genpd/rockchip/pm-domains.c b/drivers/pmdomain/rockchip/pm-domains.c index d5d3ecb38283..d5d3ecb38283 100644 --- a/drivers/genpd/rockchip/pm-domains.c +++ b/drivers/pmdomain/rockchip/pm-domains.c diff --git a/drivers/genpd/samsung/Makefile b/drivers/pmdomain/samsung/Makefile index 397aa5908c1d..397aa5908c1d 100644 --- a/drivers/genpd/samsung/Makefile +++ b/drivers/pmdomain/samsung/Makefile diff --git a/drivers/genpd/samsung/exynos-pm-domains.c b/drivers/pmdomain/samsung/exynos-pm-domains.c index 9b502e8751d1..9b502e8751d1 100644 --- a/drivers/genpd/samsung/exynos-pm-domains.c +++ b/drivers/pmdomain/samsung/exynos-pm-domains.c diff --git a/drivers/genpd/st/Makefile b/drivers/pmdomain/st/Makefile index 8fa5f9855460..8fa5f9855460 100644 --- a/drivers/genpd/st/Makefile +++ b/drivers/pmdomain/st/Makefile diff --git a/drivers/genpd/st/ste-ux500-pm-domain.c b/drivers/pmdomain/st/ste-ux500-pm-domain.c index 3d4f111ed156..3d4f111ed156 100644 --- a/drivers/genpd/st/ste-ux500-pm-domain.c +++ b/drivers/pmdomain/st/ste-ux500-pm-domain.c diff --git a/drivers/genpd/starfive/Makefile b/drivers/pmdomain/starfive/Makefile index 975bba2a29a9..975bba2a29a9 100644 --- a/drivers/genpd/starfive/Makefile +++ b/drivers/pmdomain/starfive/Makefile diff --git a/drivers/genpd/starfive/jh71xx-pmu.c b/drivers/pmdomain/starfive/jh71xx-pmu.c index 7d5f50d71c0d..7d5f50d71c0d 100644 --- a/drivers/genpd/starfive/jh71xx-pmu.c +++ b/drivers/pmdomain/starfive/jh71xx-pmu.c diff --git a/drivers/genpd/sunxi/Makefile b/drivers/pmdomain/sunxi/Makefile index ec1d7a2fb21d..ec1d7a2fb21d 100644 --- a/drivers/genpd/sunxi/Makefile +++ b/drivers/pmdomain/sunxi/Makefile diff --git a/drivers/genpd/sunxi/sun20i-ppu.c b/drivers/pmdomain/sunxi/sun20i-ppu.c index 8700f9dd5f75..8700f9dd5f75 100644 --- a/drivers/genpd/sunxi/sun20i-ppu.c +++ b/drivers/pmdomain/sunxi/sun20i-ppu.c diff --git a/drivers/genpd/tegra/Makefile b/drivers/pmdomain/tegra/Makefile index ec8acfd2c77c..ec8acfd2c77c 100644 --- a/drivers/genpd/tegra/Makefile +++ b/drivers/pmdomain/tegra/Makefile diff --git a/drivers/genpd/tegra/powergate-bpmp.c b/drivers/pmdomain/tegra/powergate-bpmp.c index 179ed895c279..179ed895c279 100644 --- a/drivers/genpd/tegra/powergate-bpmp.c +++ b/drivers/pmdomain/tegra/powergate-bpmp.c diff --git a/drivers/genpd/ti/Makefile b/drivers/pmdomain/ti/Makefile index 69580afbb436..69580afbb436 100644 --- a/drivers/genpd/ti/Makefile +++ b/drivers/pmdomain/ti/Makefile diff --git a/drivers/genpd/ti/omap_prm.c b/drivers/pmdomain/ti/omap_prm.c index c2feae3a634c..c2feae3a634c 100644 --- a/drivers/genpd/ti/omap_prm.c +++ b/drivers/pmdomain/ti/omap_prm.c diff --git a/drivers/genpd/ti/ti_sci_pm_domains.c b/drivers/pmdomain/ti/ti_sci_pm_domains.c index 34645104fe45..34645104fe45 100644 --- a/drivers/genpd/ti/ti_sci_pm_domains.c +++ b/drivers/pmdomain/ti/ti_sci_pm_domains.c diff --git a/drivers/genpd/xilinx/Makefile b/drivers/pmdomain/xilinx/Makefile index a706ab699cfa..a706ab699cfa 100644 --- a/drivers/genpd/xilinx/Makefile +++ b/drivers/pmdomain/xilinx/Makefile diff --git a/drivers/genpd/xilinx/zynqmp-pm-domains.c b/drivers/pmdomain/xilinx/zynqmp-pm-domains.c index 69d03ad4cf1e..69d03ad4cf1e 100644 --- a/drivers/genpd/xilinx/zynqmp-pm-domains.c +++ b/drivers/pmdomain/xilinx/zynqmp-pm-domains.c diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig index 59e1ebb7842e..411e00b255d6 100644 --- a/drivers/power/reset/Kconfig +++ b/drivers/power/reset/Kconfig @@ -300,7 +300,7 @@ config NVMEM_REBOOT_MODE config POWER_MLXBF tristate "Mellanox BlueField power handling driver" - depends on (GPIO_MLXBF2 && ACPI) + depends on (GPIO_MLXBF2 || GPIO_MLXBF3) && ACPI help This driver supports reset or low power mode handling for Mellanox BlueField. diff --git a/drivers/power/reset/pwr-mlxbf.c b/drivers/power/reset/pwr-mlxbf.c index 12dedf841a44..de35d24bb7ef 100644 --- a/drivers/power/reset/pwr-mlxbf.c +++ b/drivers/power/reset/pwr-mlxbf.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0-only or BSD-3-Clause +// SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause /* * Copyright (c) 2022 NVIDIA CORPORATION & AFFILIATES. diff --git a/drivers/power/reset/vexpress-poweroff.c b/drivers/power/reset/vexpress-poweroff.c index 447ffdacddf9..17064d7b19f6 100644 --- a/drivers/power/reset/vexpress-poweroff.c +++ b/drivers/power/reset/vexpress-poweroff.c @@ -121,7 +121,7 @@ static int vexpress_reset_probe(struct platform_device *pdev) return PTR_ERR(regmap); dev_set_drvdata(&pdev->dev, regmap); - switch ((enum vexpress_reset_func)match->data) { + switch ((uintptr_t)match->data) { case FUNC_SHUTDOWN: vexpress_power_off_device = &pdev->dev; pm_power_off = vexpress_power_off; diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig index 663a1c423806..a61bb1283e19 100644 --- a/drivers/power/supply/Kconfig +++ b/drivers/power/supply/Kconfig @@ -769,6 +769,7 @@ config BATTERY_RT5033 config CHARGER_RT5033 tristate "RT5033 battery charger support" depends on MFD_RT5033 + depends on EXTCON || !EXTCON help This adds support for battery charger in Richtek RT5033 PMIC. The device supports pre-charge mode, fast charge mode and diff --git a/drivers/power/supply/ab8500_btemp.c b/drivers/power/supply/ab8500_btemp.c index 6f83e99d2eb7..ce36d6ca3422 100644 --- a/drivers/power/supply/ab8500_btemp.c +++ b/drivers/power/supply/ab8500_btemp.c @@ -115,7 +115,6 @@ struct ab8500_btemp { static enum power_supply_property ab8500_btemp_props[] = { POWER_SUPPLY_PROP_PRESENT, POWER_SUPPLY_PROP_ONLINE, - POWER_SUPPLY_PROP_TECHNOLOGY, POWER_SUPPLY_PROP_TEMP, }; @@ -532,12 +531,6 @@ static int ab8500_btemp_get_property(struct power_supply *psy, else val->intval = 1; break; - case POWER_SUPPLY_PROP_TECHNOLOGY: - if (di->bm->bi) - val->intval = di->bm->bi->technology; - else - val->intval = POWER_SUPPLY_TECHNOLOGY_UNKNOWN; - break; case POWER_SUPPLY_PROP_TEMP: val->intval = ab8500_btemp_get_temp(di); break; @@ -662,7 +655,7 @@ static char *supply_interface[] = { static const struct power_supply_desc ab8500_btemp_desc = { .name = "ab8500_btemp", - .type = POWER_SUPPLY_TYPE_BATTERY, + .type = POWER_SUPPLY_TYPE_UNKNOWN, .properties = ab8500_btemp_props, .num_properties = ARRAY_SIZE(ab8500_btemp_props), .get_property = ab8500_btemp_get_property, diff --git a/drivers/power/supply/ab8500_chargalg.c b/drivers/power/supply/ab8500_chargalg.c index ea4ad61d4c7e..2205ea0834a6 100644 --- a/drivers/power/supply/ab8500_chargalg.c +++ b/drivers/power/supply/ab8500_chargalg.c @@ -1720,7 +1720,7 @@ static char *supply_interface[] = { static const struct power_supply_desc ab8500_chargalg_desc = { .name = "ab8500_chargalg", - .type = POWER_SUPPLY_TYPE_BATTERY, + .type = POWER_SUPPLY_TYPE_UNKNOWN, .properties = ab8500_chargalg_props, .num_properties = ARRAY_SIZE(ab8500_chargalg_props), .get_property = ab8500_chargalg_get_property, diff --git a/drivers/power/supply/mt6370-charger.c b/drivers/power/supply/mt6370-charger.c index f27dae5043f5..a9641bd3d8cf 100644 --- a/drivers/power/supply/mt6370-charger.c +++ b/drivers/power/supply/mt6370-charger.c @@ -324,7 +324,7 @@ static int mt6370_chg_toggle_cfo(struct mt6370_priv *priv) if (fl_strobe) { dev_err(priv->dev, "Flash led is still in strobe mode\n"); - return ret; + return -EINVAL; } /* cfo off */ diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c index 06e5b6b0e255..d483a81560ab 100644 --- a/drivers/power/supply/power_supply_sysfs.c +++ b/drivers/power/supply/power_supply_sysfs.c @@ -482,6 +482,13 @@ int power_supply_uevent(const struct device *dev, struct kobj_uevent_env *env) if (ret) return ret; + /* + * Kernel generates KOBJ_REMOVE uevent in device removal path, after + * resources have been freed. Exit early to avoid use-after-free. + */ + if (psy->removing) + return 0; + prop_buf = (char *)get_zeroed_page(GFP_KERNEL); if (!prop_buf) return -ENOMEM; diff --git a/drivers/power/supply/rk817_charger.c b/drivers/power/supply/rk817_charger.c index 8328bcea1a29..f64daf5a41d9 100644 --- a/drivers/power/supply/rk817_charger.c +++ b/drivers/power/supply/rk817_charger.c @@ -1045,6 +1045,13 @@ static void rk817_charging_monitor(struct work_struct *work) queue_delayed_work(system_wq, &charger->work, msecs_to_jiffies(8000)); } +static void rk817_cleanup_node(void *data) +{ + struct device_node *node = data; + + of_node_put(node); +} + static int rk817_charger_probe(struct platform_device *pdev) { struct rk808 *rk808 = dev_get_drvdata(pdev->dev.parent); @@ -1061,11 +1068,13 @@ static int rk817_charger_probe(struct platform_device *pdev) if (!node) return -ENODEV; + ret = devm_add_action_or_reset(&pdev->dev, rk817_cleanup_node, node); + if (ret) + return ret; + charger = devm_kzalloc(&pdev->dev, sizeof(*charger), GFP_KERNEL); - if (!charger) { - of_node_put(node); + if (!charger) return -ENOMEM; - } charger->rk808 = rk808; @@ -1211,3 +1220,4 @@ MODULE_DESCRIPTION("Battery power supply driver for RK817 PMIC"); MODULE_AUTHOR("Maya Matuszczyk <maccraft123mc@gmail.com>"); MODULE_AUTHOR("Chris Morgan <macromorgan@hotmail.com>"); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:rk817-charger"); diff --git a/drivers/power/supply/rt9467-charger.c b/drivers/power/supply/rt9467-charger.c index 683adb18253d..fdfdc83ab045 100644 --- a/drivers/power/supply/rt9467-charger.c +++ b/drivers/power/supply/rt9467-charger.c @@ -598,8 +598,8 @@ static int rt9467_run_aicl(struct rt9467_chg_data *data) reinit_completion(&data->aicl_done); ret = wait_for_completion_timeout(&data->aicl_done, msecs_to_jiffies(3500)); - if (ret) - return ret; + if (ret == 0) + return -ETIMEDOUT; ret = rt9467_get_value_from_ranges(data, F_IAICR, RT9467_RANGE_IAICR, &aicr_get); if (ret) { diff --git a/drivers/power/supply/ucs1002_power.c b/drivers/power/supply/ucs1002_power.c index 954feba6600b..7970843a4f48 100644 --- a/drivers/power/supply/ucs1002_power.c +++ b/drivers/power/supply/ucs1002_power.c @@ -384,7 +384,8 @@ static int ucs1002_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_USB_TYPE: return ucs1002_get_usb_type(info, val); case POWER_SUPPLY_PROP_HEALTH: - return val->intval = info->health; + val->intval = info->health; + return 0; case POWER_SUPPLY_PROP_PRESENT: val->intval = info->present; return 0; diff --git a/drivers/regulator/helpers.c b/drivers/regulator/helpers.c index 5ad5f3b3a6b5..d49268336553 100644 --- a/drivers/regulator/helpers.c +++ b/drivers/regulator/helpers.c @@ -197,7 +197,7 @@ int regulator_set_voltage_sel_pickable_regmap(struct regulator_dev *rdev, sel += rdev->desc->linear_ranges[i].min_sel; range = rdev->desc->linear_range_selectors_bitfield[i]; - range <<= ffs(rdev->desc->vsel_mask) - 1; + range <<= ffs(rdev->desc->vsel_range_mask) - 1; if (rdev->desc->vsel_reg == rdev->desc->vsel_range_reg) { ret = regmap_update_bits(rdev->regmap, diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 9ab8555180a3..8e14cea15f98 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -724,6 +724,10 @@ iscsi_sw_tcp_conn_bind(struct iscsi_cls_session *cls_session, return -EEXIST; } + err = -EINVAL; + if (!sk_is_tcp(sock->sk)) + goto free_socket; + err = iscsi_conn_bind(cls_session, cls_conn, is_leading); if (err) goto free_socket; diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c index 7f9b221e7c34..ea9b42225e62 100644 --- a/drivers/scsi/lpfc/lpfc_debugfs.c +++ b/drivers/scsi/lpfc/lpfc_debugfs.c @@ -6073,7 +6073,7 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport) phba->hba_debugfs_root, phba, &lpfc_debugfs_op_multixripools); - if (!phba->debug_multixri_pools) { + if (IS_ERR(phba->debug_multixri_pools)) { lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, "0527 Cannot create debugfs multixripools\n"); goto debug_failed; @@ -6085,7 +6085,7 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport) debugfs_create_file(name, S_IFREG | 0644, phba->hba_debugfs_root, phba, &lpfc_cgn_buffer_op); - if (!phba->debug_cgn_buffer) { + if (IS_ERR(phba->debug_cgn_buffer)) { lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, "6527 Cannot create debugfs " "cgn_buffer\n"); @@ -6098,7 +6098,7 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport) debugfs_create_file(name, S_IFREG | 0644, phba->hba_debugfs_root, phba, &lpfc_rx_monitor_op); - if (!phba->debug_rx_monitor) { + if (IS_ERR(phba->debug_rx_monitor)) { lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, "6528 Cannot create debugfs " "rx_monitor\n"); @@ -6111,7 +6111,7 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport) debugfs_create_file(name, 0644, phba->hba_debugfs_root, phba, &lpfc_debugfs_ras_log); - if (!phba->debug_ras_log) { + if (IS_ERR(phba->debug_ras_log)) { lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, "6148 Cannot create debugfs" " ras_log\n"); @@ -6132,7 +6132,7 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport) debugfs_create_file(name, S_IFREG | 0644, phba->hba_debugfs_root, phba, &lpfc_debugfs_op_lockstat); - if (!phba->debug_lockstat) { + if (IS_ERR(phba->debug_lockstat)) { lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, "4610 Can't create debugfs lockstat\n"); goto debug_failed; @@ -6358,7 +6358,7 @@ nvmeio_off: debugfs_create_file(name, 0644, vport->vport_debugfs_root, vport, &lpfc_debugfs_op_scsistat); - if (!vport->debug_scsistat) { + if (IS_ERR(vport->debug_scsistat)) { lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, "4611 Cannot create debugfs scsistat\n"); goto debug_failed; @@ -6369,7 +6369,7 @@ nvmeio_off: debugfs_create_file(name, 0644, vport->vport_debugfs_root, vport, &lpfc_debugfs_op_ioktime); - if (!vport->debug_ioktime) { + if (IS_ERR(vport->debug_ioktime)) { lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, "0815 Cannot create debugfs ioktime\n"); goto debug_failed; diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 51afb60859eb..5154eeaee0ec 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -199,11 +199,12 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport) /* Only 1 thread can drop the initial node reference. If * another thread has set NLP_DROPPED, this thread is done. */ - if (!(ndlp->nlp_flag & NLP_DROPPED)) { + if (!(ndlp->fc4_xpt_flags & NVME_XPT_REGD) && + !(ndlp->nlp_flag & NLP_DROPPED)) { ndlp->nlp_flag |= NLP_DROPPED; spin_unlock_irqrestore(&ndlp->lock, iflags); lpfc_nlp_put(ndlp); - spin_lock_irqsave(&ndlp->lock, iflags); + return; } spin_unlock_irqrestore(&ndlp->lock, iflags); diff --git a/drivers/scsi/lpfc/lpfc_nvme.c b/drivers/scsi/lpfc/lpfc_nvme.c index 39acbcb7ec66..96e11a26c297 100644 --- a/drivers/scsi/lpfc/lpfc_nvme.c +++ b/drivers/scsi/lpfc/lpfc_nvme.c @@ -228,8 +228,7 @@ lpfc_nvme_remoteport_delete(struct nvme_fc_remote_port *remoteport) spin_unlock_irq(&ndlp->lock); /* On a devloss timeout event, one more put is executed provided the - * NVME and SCSI rport unregister requests are complete. If the vport - * is unloading, this extra put is executed by lpfc_drop_node. + * NVME and SCSI rport unregister requests are complete. */ if (!(ndlp->fc4_xpt_flags & fc4_xpt_flags)) lpfc_disc_state_machine(vport, ndlp, NULL, NLP_EVT_DEVICE_RM); @@ -2567,11 +2566,7 @@ lpfc_nvme_rescan_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) * nvme_transport perspective. Loss of an rport just means IO cannot * be sent and recovery is completely up to the initator. * For now, the driver just unbinds the DID and port_role so that - * no further IO can be issued. Changes are planned for later. - * - * Notes - the ndlp reference count is not decremented here since - * since there is no nvme_transport api for devloss. Node ref count - * is only adjusted in driver unload. + * no further IO can be issued. */ void lpfc_nvme_unregister_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) @@ -2646,6 +2641,21 @@ lpfc_nvme_unregister_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) "6167 NVME unregister failed %d " "port_state x%x\n", ret, remoteport->port_state); + + if (vport->load_flag & FC_UNLOADING) { + /* Only 1 thread can drop the initial node + * reference. Check if another thread has set + * NLP_DROPPED. + */ + spin_lock_irq(&ndlp->lock); + if (!(ndlp->nlp_flag & NLP_DROPPED)) { + ndlp->nlp_flag |= NLP_DROPPED; + spin_unlock_irq(&ndlp->lock); + lpfc_nlp_put(ndlp); + return; + } + spin_unlock_irq(&ndlp->lock); + } } } return; diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index 3554f6b07727..94abba57582d 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h @@ -2332,7 +2332,7 @@ struct megasas_instance { u32 support_morethan256jbod; /* FW support for more than 256 PD/JBOD */ bool use_seqnum_jbod_fp; /* Added for PD sequence */ bool smp_affinity_enable; - spinlock_t crashdump_lock; + struct mutex crashdump_lock; struct megasas_register_set __iomem *reg_set; u32 __iomem *reply_post_host_index_addr[MR_MAX_MSIX_REG_ARRAY]; diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index b9d46dcb5210..e1aa667dae66 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -3271,14 +3271,13 @@ fw_crash_buffer_store(struct device *cdev, struct megasas_instance *instance = (struct megasas_instance *) shost->hostdata; int val = 0; - unsigned long flags; if (kstrtoint(buf, 0, &val) != 0) return -EINVAL; - spin_lock_irqsave(&instance->crashdump_lock, flags); + mutex_lock(&instance->crashdump_lock); instance->fw_crash_buffer_offset = val; - spin_unlock_irqrestore(&instance->crashdump_lock, flags); + mutex_unlock(&instance->crashdump_lock); return strlen(buf); } @@ -3293,24 +3292,23 @@ fw_crash_buffer_show(struct device *cdev, unsigned long dmachunk = CRASH_DMA_BUF_SIZE; unsigned long chunk_left_bytes; unsigned long src_addr; - unsigned long flags; u32 buff_offset; - spin_lock_irqsave(&instance->crashdump_lock, flags); + mutex_lock(&instance->crashdump_lock); buff_offset = instance->fw_crash_buffer_offset; if (!instance->crash_dump_buf || !((instance->fw_crash_state == AVAILABLE) || (instance->fw_crash_state == COPYING))) { dev_err(&instance->pdev->dev, "Firmware crash dump is not available\n"); - spin_unlock_irqrestore(&instance->crashdump_lock, flags); + mutex_unlock(&instance->crashdump_lock); return -EINVAL; } if (buff_offset > (instance->fw_crash_buffer_size * dmachunk)) { dev_err(&instance->pdev->dev, "Firmware crash dump offset is out of range\n"); - spin_unlock_irqrestore(&instance->crashdump_lock, flags); + mutex_unlock(&instance->crashdump_lock); return 0; } @@ -3322,7 +3320,7 @@ fw_crash_buffer_show(struct device *cdev, src_addr = (unsigned long)instance->crash_buf[buff_offset / dmachunk] + (buff_offset % dmachunk); memcpy(buf, (void *)src_addr, size); - spin_unlock_irqrestore(&instance->crashdump_lock, flags); + mutex_unlock(&instance->crashdump_lock); return size; } @@ -3347,7 +3345,6 @@ fw_crash_state_store(struct device *cdev, struct megasas_instance *instance = (struct megasas_instance *) shost->hostdata; int val = 0; - unsigned long flags; if (kstrtoint(buf, 0, &val) != 0) return -EINVAL; @@ -3361,9 +3358,9 @@ fw_crash_state_store(struct device *cdev, instance->fw_crash_state = val; if ((val == COPIED) || (val == COPY_ERROR)) { - spin_lock_irqsave(&instance->crashdump_lock, flags); + mutex_lock(&instance->crashdump_lock); megasas_free_host_crash_buffer(instance); - spin_unlock_irqrestore(&instance->crashdump_lock, flags); + mutex_unlock(&instance->crashdump_lock); if (val == COPY_ERROR) dev_info(&instance->pdev->dev, "application failed to " "copy Firmware crash dump\n"); @@ -7422,7 +7419,7 @@ static inline void megasas_init_ctrl_params(struct megasas_instance *instance) init_waitqueue_head(&instance->int_cmd_wait_q); init_waitqueue_head(&instance->abort_cmd_wait_q); - spin_lock_init(&instance->crashdump_lock); + mutex_init(&instance->crashdump_lock); spin_lock_init(&instance->mfi_pool_lock); spin_lock_init(&instance->hba_lock); spin_lock_init(&instance->stream_lock); diff --git a/drivers/scsi/pm8001/pm8001_hwi.c b/drivers/scsi/pm8001/pm8001_hwi.c index 33053db5a713..90069c7b1642 100644 --- a/drivers/scsi/pm8001/pm8001_hwi.c +++ b/drivers/scsi/pm8001/pm8001_hwi.c @@ -4180,7 +4180,7 @@ pm8001_chip_phy_start_req(struct pm8001_hba_info *pm8001_ha, u8 phy_id) payload.sas_identify.dev_type = SAS_END_DEVICE; payload.sas_identify.initiator_bits = SAS_PROTOCOL_ALL; memcpy(payload.sas_identify.sas_addr, - pm8001_ha->sas_addr, SAS_ADDR_SIZE); + &pm8001_ha->phy[phy_id].dev_sas_addr, SAS_ADDR_SIZE); payload.sas_identify.phy_id = phy_id; return pm8001_mpi_build_cmd(pm8001_ha, 0, opcode, &payload, diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c index 5e5ce1e74c3b..443a3176c6c0 100644 --- a/drivers/scsi/pm8001/pm8001_init.c +++ b/drivers/scsi/pm8001/pm8001_init.c @@ -273,7 +273,6 @@ static irqreturn_t pm8001_interrupt_handler_intx(int irq, void *dev_id) return ret; } -static u32 pm8001_setup_irq(struct pm8001_hba_info *pm8001_ha); static u32 pm8001_request_irq(struct pm8001_hba_info *pm8001_ha); /** @@ -294,13 +293,6 @@ static int pm8001_alloc(struct pm8001_hba_info *pm8001_ha, pm8001_dbg(pm8001_ha, INIT, "pm8001_alloc: PHY:%x\n", pm8001_ha->chip->n_phy); - /* Setup Interrupt */ - rc = pm8001_setup_irq(pm8001_ha); - if (rc) { - pm8001_dbg(pm8001_ha, FAIL, - "pm8001_setup_irq failed [ret: %d]\n", rc); - goto err_out; - } /* Request Interrupt */ rc = pm8001_request_irq(pm8001_ha); if (rc) @@ -1031,47 +1023,38 @@ static u32 pm8001_request_msix(struct pm8001_hba_info *pm8001_ha) } #endif -static u32 pm8001_setup_irq(struct pm8001_hba_info *pm8001_ha) -{ - struct pci_dev *pdev; - - pdev = pm8001_ha->pdev; - -#ifdef PM8001_USE_MSIX - if (pci_find_capability(pdev, PCI_CAP_ID_MSIX)) - return pm8001_setup_msix(pm8001_ha); - pm8001_dbg(pm8001_ha, INIT, "MSIX not supported!!!\n"); -#endif - return 0; -} - /** * pm8001_request_irq - register interrupt * @pm8001_ha: our ha struct. */ static u32 pm8001_request_irq(struct pm8001_hba_info *pm8001_ha) { - struct pci_dev *pdev; + struct pci_dev *pdev = pm8001_ha->pdev; +#ifdef PM8001_USE_MSIX int rc; - pdev = pm8001_ha->pdev; + if (pci_find_capability(pdev, PCI_CAP_ID_MSIX)) { + rc = pm8001_setup_msix(pm8001_ha); + if (rc) { + pm8001_dbg(pm8001_ha, FAIL, + "pm8001_setup_irq failed [ret: %d]\n", rc); + return rc; + } -#ifdef PM8001_USE_MSIX - if (pdev->msix_cap && pci_msi_enabled()) - return pm8001_request_msix(pm8001_ha); - else { - pm8001_dbg(pm8001_ha, INIT, "MSIX not supported!!!\n"); - goto intx; + if (pdev->msix_cap && pci_msi_enabled()) + return pm8001_request_msix(pm8001_ha); } + + pm8001_dbg(pm8001_ha, INIT, "MSIX not supported!!!\n"); #endif -intx: /* initialize the INT-X interrupt */ pm8001_ha->irq_vector[0].irq_id = 0; pm8001_ha->irq_vector[0].drv_inst = pm8001_ha; - rc = request_irq(pdev->irq, pm8001_interrupt_handler_intx, IRQF_SHARED, - pm8001_ha->name, SHOST_TO_SAS_HA(pm8001_ha->shost)); - return rc; + + return request_irq(pdev->irq, pm8001_interrupt_handler_intx, + IRQF_SHARED, pm8001_ha->name, + SHOST_TO_SAS_HA(pm8001_ha->shost)); } /** diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c index f6857632dc7c..3afd9443c425 100644 --- a/drivers/scsi/pm8001/pm80xx_hwi.c +++ b/drivers/scsi/pm8001/pm80xx_hwi.c @@ -3671,10 +3671,12 @@ static int mpi_set_controller_config_resp(struct pm8001_hba_info *pm8001_ha, (struct set_ctrl_cfg_resp *)(piomb + 4); u32 status = le32_to_cpu(pPayload->status); u32 err_qlfr_pgcd = le32_to_cpu(pPayload->err_qlfr_pgcd); + u32 tag = le32_to_cpu(pPayload->tag); pm8001_dbg(pm8001_ha, MSG, "SET CONTROLLER RESP: status 0x%x qlfr_pgcd 0x%x\n", status, err_qlfr_pgcd); + pm8001_tag_free(pm8001_ha, tag); return 0; } @@ -4671,7 +4673,7 @@ pm80xx_chip_phy_start_req(struct pm8001_hba_info *pm8001_ha, u8 phy_id) payload.sas_identify.dev_type = SAS_END_DEVICE; payload.sas_identify.initiator_bits = SAS_PROTOCOL_ALL; memcpy(payload.sas_identify.sas_addr, - &pm8001_ha->sas_addr, SAS_ADDR_SIZE); + &pm8001_ha->phy[phy_id].dev_sas_addr, SAS_ADDR_SIZE); payload.sas_identify.phy_id = phy_id; return pm8001_mpi_build_cmd(pm8001_ha, 0, opcode, &payload, diff --git a/drivers/scsi/ppa.c b/drivers/scsi/ppa.c index 19f0b93fa3d8..d592ee9170c1 100644 --- a/drivers/scsi/ppa.c +++ b/drivers/scsi/ppa.c @@ -307,9 +307,9 @@ static int ppa_out(ppa_struct *dev, char *buffer, int len) case PPA_EPP_8: epp_reset(ppb); w_ctr(ppb, 0x4); - if (dev->mode == PPA_EPP_32 && !(((long) buffer | len) & 0x01)) + if (dev->mode == PPA_EPP_32 && !(((long) buffer | len) & 0x03)) outsl(ppb + 4, buffer, len >> 2); - else if (dev->mode == PPA_EPP_16 && !(((long) buffer | len) & 0x03)) + else if (dev->mode == PPA_EPP_16 && !(((long) buffer | len) & 0x01)) outsw(ppb + 4, buffer, len >> 1); else outsb(ppb + 4, buffer, len); diff --git a/drivers/scsi/qedf/qedf_io.c b/drivers/scsi/qedf/qedf_io.c index 4750ec5789a8..10fe3383855c 100644 --- a/drivers/scsi/qedf/qedf_io.c +++ b/drivers/scsi/qedf/qedf_io.c @@ -1904,6 +1904,7 @@ int qedf_initiate_abts(struct qedf_ioreq *io_req, bool return_scsi_cmd_on_abts) goto drop_rdata_kref; } + spin_lock_irqsave(&fcport->rport_lock, flags); if (!test_bit(QEDF_CMD_OUTSTANDING, &io_req->flags) || test_bit(QEDF_CMD_IN_CLEANUP, &io_req->flags) || test_bit(QEDF_CMD_IN_ABORT, &io_req->flags)) { @@ -1911,17 +1912,20 @@ int qedf_initiate_abts(struct qedf_ioreq *io_req, bool return_scsi_cmd_on_abts) "io_req xid=0x%x sc_cmd=%p already in cleanup or abort processing or already completed.\n", io_req->xid, io_req->sc_cmd); rc = 1; + spin_unlock_irqrestore(&fcport->rport_lock, flags); goto drop_rdata_kref; } + /* Set the command type to abort */ + io_req->cmd_type = QEDF_ABTS; + spin_unlock_irqrestore(&fcport->rport_lock, flags); + kref_get(&io_req->refcount); xid = io_req->xid; qedf->control_requests++; qedf->packet_aborts++; - /* Set the command type to abort */ - io_req->cmd_type = QEDF_ABTS; io_req->return_scsi_cmd_on_abts = return_scsi_cmd_on_abts; set_bit(QEDF_CMD_IN_ABORT, &io_req->flags); @@ -2210,7 +2214,9 @@ process_els: refcount, fcport, fcport->rdata->ids.port_id); /* Cleanup cmds re-use the same TID as the original I/O */ + spin_lock_irqsave(&fcport->rport_lock, flags); io_req->cmd_type = QEDF_CLEANUP; + spin_unlock_irqrestore(&fcport->rport_lock, flags); io_req->return_scsi_cmd_on_abts = return_scsi_cmd_on_abts; init_completion(&io_req->cleanup_done); diff --git a/drivers/scsi/qedf/qedf_main.c b/drivers/scsi/qedf/qedf_main.c index 7825765c936c..91f3f1d7098e 100644 --- a/drivers/scsi/qedf/qedf_main.c +++ b/drivers/scsi/qedf/qedf_main.c @@ -2805,6 +2805,8 @@ void qedf_process_cqe(struct qedf_ctx *qedf, struct fcoe_cqe *cqe) struct qedf_ioreq *io_req; struct qedf_rport *fcport; u32 comp_type; + u8 io_comp_type; + unsigned long flags; comp_type = (cqe->cqe_data >> FCOE_CQE_CQE_TYPE_SHIFT) & FCOE_CQE_CQE_TYPE_MASK; @@ -2838,11 +2840,14 @@ void qedf_process_cqe(struct qedf_ctx *qedf, struct fcoe_cqe *cqe) return; } + spin_lock_irqsave(&fcport->rport_lock, flags); + io_comp_type = io_req->cmd_type; + spin_unlock_irqrestore(&fcport->rport_lock, flags); switch (comp_type) { case FCOE_GOOD_COMPLETION_CQE_TYPE: atomic_inc(&fcport->free_sqes); - switch (io_req->cmd_type) { + switch (io_comp_type) { case QEDF_SCSI_CMD: qedf_scsi_completion(qedf, cqe, io_req); break; diff --git a/drivers/scsi/qla2xxx/qla_dfs.c b/drivers/scsi/qla2xxx/qla_dfs.c index f060e593685d..a7a364760b80 100644 --- a/drivers/scsi/qla2xxx/qla_dfs.c +++ b/drivers/scsi/qla2xxx/qla_dfs.c @@ -116,7 +116,7 @@ qla2x00_dfs_create_rport(scsi_qla_host_t *vha, struct fc_port *fp) sprintf(wwn, "pn-%016llx", wwn_to_u64(fp->port_name)); fp->dfs_rport_dir = debugfs_create_dir(wwn, vha->dfs_rport_root); - if (!fp->dfs_rport_dir) + if (IS_ERR(fp->dfs_rport_dir)) return; if (NVME_TARGET(vha->hw, fp)) debugfs_create_file("dev_loss_tmo", 0600, fp->dfs_rport_dir, @@ -708,14 +708,14 @@ create_nodes: if (IS_QLA27XX(ha) || IS_QLA83XX(ha) || IS_QLA28XX(ha)) { ha->tgt.dfs_naqp = debugfs_create_file("naqp", 0400, ha->dfs_dir, vha, &dfs_naqp_ops); - if (!ha->tgt.dfs_naqp) { + if (IS_ERR(ha->tgt.dfs_naqp)) { ql_log(ql_log_warn, vha, 0xd011, "Unable to create debugFS naqp node.\n"); goto out; } } vha->dfs_rport_root = debugfs_create_dir("rports", ha->dfs_dir); - if (!vha->dfs_rport_root) { + if (IS_ERR(vha->dfs_rport_root)) { ql_log(ql_log_warn, vha, 0xd012, "Unable to create debugFS rports node.\n"); goto out; diff --git a/drivers/scsi/qla2xxx/qla_inline.h b/drivers/scsi/qla2xxx/qla_inline.h index 0556969f6dc1..a4a56ab0ba74 100644 --- a/drivers/scsi/qla2xxx/qla_inline.h +++ b/drivers/scsi/qla2xxx/qla_inline.h @@ -577,7 +577,7 @@ fcport_is_bigger(fc_port_t *fcport) static inline struct qla_qpair * qla_mapq_nvme_select_qpair(struct qla_hw_data *ha, struct qla_qpair *qpair) { - int cpuid = smp_processor_id(); + int cpuid = raw_smp_processor_id(); if (qpair->cpuid != cpuid && ha->qp_cpu_map[cpuid]) { diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index e98788191897..d48007e18288 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -3965,7 +3965,7 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha, if (!ha->flags.fw_started) return; - if (rsp->qpair->cpuid != smp_processor_id() || !rsp->qpair->rcv_intr) { + if (rsp->qpair->cpuid != raw_smp_processor_id() || !rsp->qpair->rcv_intr) { rsp->qpair->rcv_intr = 1; if (!rsp->qpair->cpu_mapped) @@ -4468,7 +4468,7 @@ qla2xxx_msix_rsp_q(int irq, void *dev_id) } ha = qpair->hw; - queue_work_on(smp_processor_id(), ha->wq, &qpair->q_work); + queue_work(ha->wq, &qpair->q_work); return IRQ_HANDLED; } @@ -4494,7 +4494,7 @@ qla2xxx_msix_rsp_q_hs(int irq, void *dev_id) wrt_reg_dword(®->hccr, HCCRX_CLR_RISC_INT); spin_unlock_irqrestore(&ha->hardware_lock, flags); - queue_work_on(smp_processor_id(), ha->wq, &qpair->q_work); + queue_work(ha->wq, &qpair->q_work); return IRQ_HANDLED; } diff --git a/drivers/scsi/qla2xxx/qla_nvme.c b/drivers/scsi/qla2xxx/qla_nvme.c index db753d712991..a8ddf356e662 100644 --- a/drivers/scsi/qla2xxx/qla_nvme.c +++ b/drivers/scsi/qla2xxx/qla_nvme.c @@ -399,14 +399,14 @@ static int qla_nvme_xmt_ls_rsp(struct nvme_fc_local_port *lport, nvme->u.nvme.dl = 0; nvme->u.nvme.timeout_sec = 0; nvme->u.nvme.cmd_dma = fd_resp->rspdma; - nvme->u.nvme.cmd_len = fd_resp->rsplen; + nvme->u.nvme.cmd_len = cpu_to_le32(fd_resp->rsplen); nvme->u.nvme.rsp_len = 0; nvme->u.nvme.rsp_dma = 0; nvme->u.nvme.exchange_address = uctx->exchange_address; nvme->u.nvme.nport_handle = uctx->nport_handle; nvme->u.nvme.ox_id = uctx->ox_id; dma_sync_single_for_device(&ha->pdev->dev, nvme->u.nvme.cmd_dma, - le32_to_cpu(fd_resp->rsplen), DMA_TO_DEVICE); + fd_resp->rsplen, DMA_TO_DEVICE); ql_dbg(ql_dbg_unsol, vha, 0x2122, "Unsol lsreq portid=%06x %8phC exchange_address 0x%x ox_id 0x%x hdl 0x%x\n", @@ -504,13 +504,13 @@ static int qla_nvme_ls_req(struct nvme_fc_local_port *lport, nvme->u.nvme.desc = fd; nvme->u.nvme.dir = 0; nvme->u.nvme.dl = 0; - nvme->u.nvme.cmd_len = fd->rqstlen; - nvme->u.nvme.rsp_len = fd->rsplen; + nvme->u.nvme.cmd_len = cpu_to_le32(fd->rqstlen); + nvme->u.nvme.rsp_len = cpu_to_le32(fd->rsplen); nvme->u.nvme.rsp_dma = fd->rspdma; nvme->u.nvme.timeout_sec = fd->timeout; nvme->u.nvme.cmd_dma = fd->rqstdma; dma_sync_single_for_device(&ha->pdev->dev, nvme->u.nvme.cmd_dma, - le32_to_cpu(fd->rqstlen), DMA_TO_DEVICE); + fd->rqstlen, DMA_TO_DEVICE); rval = qla2x00_start_sp(sp); if (rval != QLA_SUCCESS) { diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c index 2b815a9928ea..2ef2dbac0db2 100644 --- a/drivers/scsi/qla2xxx/qla_target.c +++ b/drivers/scsi/qla2xxx/qla_target.c @@ -4425,8 +4425,7 @@ static int qlt_handle_cmd_for_atio(struct scsi_qla_host *vha, queue_work_on(cmd->se_cmd.cpuid, qla_tgt_wq, &cmd->work); } else if (ha->msix_count) { if (cmd->atio.u.isp24.fcp_cmnd.rddata) - queue_work_on(smp_processor_id(), qla_tgt_wq, - &cmd->work); + queue_work(qla_tgt_wq, &cmd->work); else queue_work_on(cmd->se_cmd.cpuid, qla_tgt_wq, &cmd->work); diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c index 3b5ba4b47b3b..68a0e6a2fb6e 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c @@ -310,7 +310,7 @@ static void tcm_qla2xxx_free_cmd(struct qla_tgt_cmd *cmd) cmd->trc_flags |= TRC_CMD_DONE; INIT_WORK(&cmd->work, tcm_qla2xxx_complete_free); - queue_work_on(smp_processor_id(), tcm_qla2xxx_free_wq, &cmd->work); + queue_work(tcm_qla2xxx_free_wq, &cmd->work); } /* @@ -547,7 +547,7 @@ static void tcm_qla2xxx_handle_data(struct qla_tgt_cmd *cmd) cmd->trc_flags |= TRC_DATA_IN; cmd->cmd_in_wq = 1; INIT_WORK(&cmd->work, tcm_qla2xxx_handle_data_work); - queue_work_on(smp_processor_id(), tcm_qla2xxx_free_wq, &cmd->work); + queue_work(tcm_qla2xxx_free_wq, &cmd->work); } static int tcm_qla2xxx_chk_dif_tags(uint32_t tag) diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index d0911bc28663..89367c4bf0ef 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -613,6 +613,17 @@ void scsi_cdl_check(struct scsi_device *sdev) bool cdl_supported; unsigned char *buf; + /* + * Support for CDL was defined in SPC-5. Ignore devices reporting an + * lower SPC version. This also avoids problems with old drives choking + * on MAINTENANCE_IN / MI_REPORT_SUPPORTED_OPERATION_CODES with a + * service action specified, as done in scsi_cdl_check_cmd(). + */ + if (sdev->scsi_level < SCSI_SPC_5) { + sdev->cdl_supported = 0; + return; + } + buf = kmalloc(SCSI_CDL_CHECK_BUF_LEN, GFP_KERNEL); if (!buf) { sdev->cdl_supported = 0; diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 52014b2d39e1..902655d75947 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -822,7 +822,7 @@ static int scsi_probe_lun(struct scsi_device *sdev, unsigned char *inq_result, * device is attached at LUN 0 (SCSI_SCAN_TARGET_PRESENT) so * non-zero LUNs can be scanned. */ - sdev->scsi_level = inq_result[2] & 0x07; + sdev->scsi_level = inq_result[2] & 0x0f; if (sdev->scsi_level >= 2 || (sdev->scsi_level == 1 && (inq_result[3] & 0x0f) == 1)) sdev->scsi_level++; @@ -1619,12 +1619,24 @@ int scsi_add_device(struct Scsi_Host *host, uint channel, } EXPORT_SYMBOL(scsi_add_device); -void scsi_rescan_device(struct scsi_device *sdev) +int scsi_rescan_device(struct scsi_device *sdev) { struct device *dev = &sdev->sdev_gendev; + int ret = 0; device_lock(dev); + /* + * Bail out if the device is not running. Otherwise, the rescan may + * block waiting for commands to be executed, with us holding the + * device lock. This can result in a potential deadlock in the power + * management core code when system resume is on-going. + */ + if (sdev->sdev_state != SDEV_RUNNING) { + ret = -EWOULDBLOCK; + goto unlock; + } + scsi_attach_vpd(sdev); scsi_cdl_check(sdev); @@ -1638,7 +1650,11 @@ void scsi_rescan_device(struct scsi_device *sdev) drv->rescan(dev); module_put(dev->driver->owner); } + +unlock: device_unlock(dev); + + return ret; } EXPORT_SYMBOL(scsi_rescan_device); diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index c92a317ba547..83b6a3f3863b 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -201,18 +201,32 @@ cache_type_store(struct device *dev, struct device_attribute *attr, } static ssize_t -manage_start_stop_show(struct device *dev, struct device_attribute *attr, - char *buf) +manage_start_stop_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct scsi_disk *sdkp = to_scsi_disk(dev); struct scsi_device *sdp = sdkp->device; - return sprintf(buf, "%u\n", sdp->manage_start_stop); + return sysfs_emit(buf, "%u\n", + sdp->manage_system_start_stop && + sdp->manage_runtime_start_stop); } +static DEVICE_ATTR_RO(manage_start_stop); static ssize_t -manage_start_stop_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +manage_system_start_stop_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct scsi_disk *sdkp = to_scsi_disk(dev); + struct scsi_device *sdp = sdkp->device; + + return sysfs_emit(buf, "%u\n", sdp->manage_system_start_stop); +} + +static ssize_t +manage_system_start_stop_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { struct scsi_disk *sdkp = to_scsi_disk(dev); struct scsi_device *sdp = sdkp->device; @@ -224,11 +238,42 @@ manage_start_stop_store(struct device *dev, struct device_attribute *attr, if (kstrtobool(buf, &v)) return -EINVAL; - sdp->manage_start_stop = v; + sdp->manage_system_start_stop = v; return count; } -static DEVICE_ATTR_RW(manage_start_stop); +static DEVICE_ATTR_RW(manage_system_start_stop); + +static ssize_t +manage_runtime_start_stop_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct scsi_disk *sdkp = to_scsi_disk(dev); + struct scsi_device *sdp = sdkp->device; + + return sysfs_emit(buf, "%u\n", sdp->manage_runtime_start_stop); +} + +static ssize_t +manage_runtime_start_stop_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct scsi_disk *sdkp = to_scsi_disk(dev); + struct scsi_device *sdp = sdkp->device; + bool v; + + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + + if (kstrtobool(buf, &v)) + return -EINVAL; + + sdp->manage_runtime_start_stop = v; + + return count; +} +static DEVICE_ATTR_RW(manage_runtime_start_stop); static ssize_t allow_restart_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -560,6 +605,8 @@ static struct attribute *sd_disk_attrs[] = { &dev_attr_FUA.attr, &dev_attr_allow_restart.attr, &dev_attr_manage_start_stop.attr, + &dev_attr_manage_system_start_stop.attr, + &dev_attr_manage_runtime_start_stop.attr, &dev_attr_protection_type.attr, &dev_attr_protection_mode.attr, &dev_attr_app_tag_own.attr, @@ -3694,7 +3741,8 @@ static int sd_remove(struct device *dev) device_del(&sdkp->disk_dev); del_gendisk(sdkp->disk); - sd_shutdown(dev); + if (!sdkp->suspended) + sd_shutdown(dev); put_disk(sdkp->disk); return 0; @@ -3771,13 +3819,20 @@ static void sd_shutdown(struct device *dev) sd_sync_cache(sdkp, NULL); } - if (system_state != SYSTEM_RESTART && sdkp->device->manage_start_stop) { + if (system_state != SYSTEM_RESTART && + sdkp->device->manage_system_start_stop) { sd_printk(KERN_NOTICE, sdkp, "Stopping disk\n"); sd_start_stop_device(sdkp, 0); } } -static int sd_suspend_common(struct device *dev, bool ignore_stop_errors) +static inline bool sd_do_start_stop(struct scsi_device *sdev, bool runtime) +{ + return (sdev->manage_system_start_stop && !runtime) || + (sdev->manage_runtime_start_stop && runtime); +} + +static int sd_suspend_common(struct device *dev, bool runtime) { struct scsi_disk *sdkp = dev_get_drvdata(dev); struct scsi_sense_hdr sshdr; @@ -3809,15 +3864,18 @@ static int sd_suspend_common(struct device *dev, bool ignore_stop_errors) } } - if (sdkp->device->manage_start_stop) { + if (sd_do_start_stop(sdkp->device, runtime)) { if (!sdkp->device->silence_suspend) sd_printk(KERN_NOTICE, sdkp, "Stopping disk\n"); /* an error is not worth aborting a system sleep */ ret = sd_start_stop_device(sdkp, 0); - if (ignore_stop_errors) + if (!runtime) ret = 0; } + if (!ret) + sdkp->suspended = true; + return ret; } @@ -3826,15 +3884,15 @@ static int sd_suspend_system(struct device *dev) if (pm_runtime_suspended(dev)) return 0; - return sd_suspend_common(dev, true); + return sd_suspend_common(dev, false); } static int sd_suspend_runtime(struct device *dev) { - return sd_suspend_common(dev, false); + return sd_suspend_common(dev, true); } -static int sd_resume(struct device *dev) +static int sd_resume(struct device *dev, bool runtime) { struct scsi_disk *sdkp = dev_get_drvdata(dev); int ret = 0; @@ -3842,16 +3900,21 @@ static int sd_resume(struct device *dev) if (!sdkp) /* E.g.: runtime resume at the start of sd_probe() */ return 0; - if (!sdkp->device->manage_start_stop) + if (!sd_do_start_stop(sdkp->device, runtime)) { + sdkp->suspended = false; return 0; + } if (!sdkp->device->no_start_on_resume) { sd_printk(KERN_NOTICE, sdkp, "Starting disk\n"); ret = sd_start_stop_device(sdkp, 1); } - if (!ret) + if (!ret) { opal_unlock_from_suspend(sdkp->opal_dev); + sdkp->suspended = false; + } + return ret; } @@ -3860,7 +3923,7 @@ static int sd_resume_system(struct device *dev) if (pm_runtime_suspended(dev)) return 0; - return sd_resume(dev); + return sd_resume(dev, false); } static int sd_resume_runtime(struct device *dev) @@ -3887,7 +3950,7 @@ static int sd_resume_runtime(struct device *dev) "Failed to clear sense data\n"); } - return sd_resume(dev); + return sd_resume(dev, true); } static const struct dev_pm_ops sd_pm_ops = { diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h index 5eea762f84d1..409dda5350d1 100644 --- a/drivers/scsi/sd.h +++ b/drivers/scsi/sd.h @@ -131,6 +131,7 @@ struct scsi_disk { u8 provisioning_mode; u8 zeroing_mode; u8 nr_actuators; /* Number of actuators */ + bool suspended; /* Disk is suspended (stopped) */ unsigned ATO : 1; /* state of disk ATO bit */ unsigned cache_override : 1; /* temp override of WCE,RCD */ unsigned WCE : 1; /* state of disk WCE bit */ diff --git a/drivers/soc/aspeed/aspeed-lpc-ctrl.c b/drivers/soc/aspeed/aspeed-lpc-ctrl.c index 258894ed234b..e87038009d1b 100644 --- a/drivers/soc/aspeed/aspeed-lpc-ctrl.c +++ b/drivers/soc/aspeed/aspeed-lpc-ctrl.c @@ -332,14 +332,12 @@ err: return rc; } -static int aspeed_lpc_ctrl_remove(struct platform_device *pdev) +static void aspeed_lpc_ctrl_remove(struct platform_device *pdev) { struct aspeed_lpc_ctrl *lpc_ctrl = dev_get_drvdata(&pdev->dev); misc_deregister(&lpc_ctrl->miscdev); clk_disable_unprepare(lpc_ctrl->clk); - - return 0; } static const struct of_device_id aspeed_lpc_ctrl_match[] = { @@ -355,7 +353,7 @@ static struct platform_driver aspeed_lpc_ctrl_driver = { .of_match_table = aspeed_lpc_ctrl_match, }, .probe = aspeed_lpc_ctrl_probe, - .remove = aspeed_lpc_ctrl_remove, + .remove_new = aspeed_lpc_ctrl_remove, }; module_platform_driver(aspeed_lpc_ctrl_driver); diff --git a/drivers/soc/aspeed/aspeed-lpc-snoop.c b/drivers/soc/aspeed/aspeed-lpc-snoop.c index 773dbcbc03a6..888b5840c015 100644 --- a/drivers/soc/aspeed/aspeed-lpc-snoop.c +++ b/drivers/soc/aspeed/aspeed-lpc-snoop.c @@ -331,7 +331,7 @@ err: return rc; } -static int aspeed_lpc_snoop_remove(struct platform_device *pdev) +static void aspeed_lpc_snoop_remove(struct platform_device *pdev) { struct aspeed_lpc_snoop *lpc_snoop = dev_get_drvdata(&pdev->dev); @@ -340,8 +340,6 @@ static int aspeed_lpc_snoop_remove(struct platform_device *pdev) aspeed_lpc_disable_snoop(lpc_snoop, 1); clk_disable_unprepare(lpc_snoop->clk); - - return 0; } static const struct aspeed_lpc_snoop_model_data ast2400_model_data = { @@ -368,7 +366,7 @@ static struct platform_driver aspeed_lpc_snoop_driver = { .of_match_table = aspeed_lpc_snoop_match, }, .probe = aspeed_lpc_snoop_probe, - .remove = aspeed_lpc_snoop_remove, + .remove_new = aspeed_lpc_snoop_remove, }; module_platform_driver(aspeed_lpc_snoop_driver); diff --git a/drivers/soc/aspeed/aspeed-p2a-ctrl.c b/drivers/soc/aspeed/aspeed-p2a-ctrl.c index 548f44da28a9..8610ddacc7bc 100644 --- a/drivers/soc/aspeed/aspeed-p2a-ctrl.c +++ b/drivers/soc/aspeed/aspeed-p2a-ctrl.c @@ -383,13 +383,11 @@ static int aspeed_p2a_ctrl_probe(struct platform_device *pdev) return rc; } -static int aspeed_p2a_ctrl_remove(struct platform_device *pdev) +static void aspeed_p2a_ctrl_remove(struct platform_device *pdev) { struct aspeed_p2a_ctrl *p2a_ctrl = dev_get_drvdata(&pdev->dev); misc_deregister(&p2a_ctrl->miscdev); - - return 0; } #define SCU2C_DRAM BIT(25) @@ -433,7 +431,7 @@ static struct platform_driver aspeed_p2a_ctrl_driver = { .of_match_table = aspeed_p2a_ctrl_match, }, .probe = aspeed_p2a_ctrl_probe, - .remove = aspeed_p2a_ctrl_remove, + .remove_new = aspeed_p2a_ctrl_remove, }; module_platform_driver(aspeed_p2a_ctrl_driver); diff --git a/drivers/soc/aspeed/aspeed-uart-routing.c b/drivers/soc/aspeed/aspeed-uart-routing.c index 3a4c1f28cb34..a2195f062e01 100644 --- a/drivers/soc/aspeed/aspeed-uart-routing.c +++ b/drivers/soc/aspeed/aspeed-uart-routing.c @@ -565,14 +565,12 @@ static int aspeed_uart_routing_probe(struct platform_device *pdev) return 0; } -static int aspeed_uart_routing_remove(struct platform_device *pdev) +static void aspeed_uart_routing_remove(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct aspeed_uart_routing *uart_routing = platform_get_drvdata(pdev); sysfs_remove_group(&dev->kobj, uart_routing->attr_grp); - - return 0; } static const struct of_device_id aspeed_uart_routing_table[] = { @@ -591,7 +589,7 @@ static struct platform_driver aspeed_uart_routing_driver = { .of_match_table = aspeed_uart_routing_table, }, .probe = aspeed_uart_routing_probe, - .remove = aspeed_uart_routing_remove, + .remove_new = aspeed_uart_routing_remove, }; module_platform_driver(aspeed_uart_routing_driver); diff --git a/drivers/soc/dove/pmu.c b/drivers/soc/dove/pmu.c index ffc5311c0ed8..6202dbcd20a8 100644 --- a/drivers/soc/dove/pmu.c +++ b/drivers/soc/dove/pmu.c @@ -410,13 +410,16 @@ int __init dove_init_pmu(void) struct pmu_domain *domain; domain = kzalloc(sizeof(*domain), GFP_KERNEL); - if (!domain) + if (!domain) { + of_node_put(np); break; + } domain->pmu = pmu; domain->base.name = kasprintf(GFP_KERNEL, "%pOFn", np); if (!domain->base.name) { kfree(domain); + of_node_put(np); break; } diff --git a/drivers/soc/fsl/dpaa2-console.c b/drivers/soc/fsl/dpaa2-console.c index 1dca693b6b38..6dbc77db7718 100644 --- a/drivers/soc/fsl/dpaa2-console.c +++ b/drivers/soc/fsl/dpaa2-console.c @@ -300,12 +300,10 @@ err_register_mc: return error; } -static int dpaa2_console_remove(struct platform_device *pdev) +static void dpaa2_console_remove(struct platform_device *pdev) { misc_deregister(&dpaa2_mc_console_dev); misc_deregister(&dpaa2_aiop_console_dev); - - return 0; } static const struct of_device_id dpaa2_console_match_table[] = { @@ -322,7 +320,7 @@ static struct platform_driver dpaa2_console_driver = { .of_match_table = dpaa2_console_match_table, }, .probe = dpaa2_console_probe, - .remove = dpaa2_console_remove, + .remove_new = dpaa2_console_remove, }; module_platform_driver(dpaa2_console_driver); diff --git a/drivers/soc/fsl/qe/qmc.c b/drivers/soc/fsl/qe/qmc.c index b3c292c9a14e..92ec76c03965 100644 --- a/drivers/soc/fsl/qe/qmc.c +++ b/drivers/soc/fsl/qe/qmc.c @@ -1415,7 +1415,7 @@ err_tsa_serial_disconnect: return ret; } -static int qmc_remove(struct platform_device *pdev) +static void qmc_remove(struct platform_device *pdev) { struct qmc *qmc = platform_get_drvdata(pdev); @@ -1427,8 +1427,6 @@ static int qmc_remove(struct platform_device *pdev) /* Disconnect the serial from TSA */ tsa_serial_disconnect(qmc->tsa_serial); - - return 0; } static const struct of_device_id qmc_id_table[] = { @@ -1443,7 +1441,7 @@ static struct platform_driver qmc_driver = { .of_match_table = of_match_ptr(qmc_id_table), }, .probe = qmc_probe, - .remove = qmc_remove, + .remove_new = qmc_remove, }; module_platform_driver(qmc_driver); diff --git a/drivers/soc/fsl/qe/tsa.c b/drivers/soc/fsl/qe/tsa.c index 3646153117b3..3f9981335590 100644 --- a/drivers/soc/fsl/qe/tsa.c +++ b/drivers/soc/fsl/qe/tsa.c @@ -706,7 +706,7 @@ static int tsa_probe(struct platform_device *pdev) return 0; } -static int tsa_remove(struct platform_device *pdev) +static void tsa_remove(struct platform_device *pdev) { struct tsa *tsa = platform_get_drvdata(pdev); int i; @@ -729,7 +729,6 @@ static int tsa_remove(struct platform_device *pdev) clk_put(tsa->tdm[i].l1rclk_clk); } } - return 0; } static const struct of_device_id tsa_id_table[] = { @@ -744,7 +743,7 @@ static struct platform_driver tsa_driver = { .of_match_table = of_match_ptr(tsa_id_table), }, .probe = tsa_probe, - .remove = tsa_remove, + .remove_new = tsa_remove, }; module_platform_driver(tsa_driver); diff --git a/drivers/soc/fujitsu/a64fx-diag.c b/drivers/soc/fujitsu/a64fx-diag.c index 524fbfeb94e3..330901893577 100644 --- a/drivers/soc/fujitsu/a64fx-diag.c +++ b/drivers/soc/fujitsu/a64fx-diag.c @@ -116,7 +116,7 @@ static int a64fx_diag_probe(struct platform_device *pdev) return 0; } -static int a64fx_diag_remove(struct platform_device *pdev) +static void a64fx_diag_remove(struct platform_device *pdev) { struct a64fx_diag_priv *priv = platform_get_drvdata(pdev); @@ -127,8 +127,6 @@ static int a64fx_diag_remove(struct platform_device *pdev) free_nmi(priv->irq, NULL); else free_irq(priv->irq, NULL); - - return 0; } static const struct acpi_device_id a64fx_diag_acpi_match[] = { @@ -144,7 +142,7 @@ static struct platform_driver a64fx_diag_driver = { .acpi_match_table = ACPI_PTR(a64fx_diag_acpi_match), }, .probe = a64fx_diag_probe, - .remove = a64fx_diag_remove, + .remove_new = a64fx_diag_remove, }; module_platform_driver(a64fx_diag_driver); diff --git a/drivers/soc/hisilicon/kunpeng_hccs.c b/drivers/soc/hisilicon/kunpeng_hccs.c index f3810d9d1caa..01aec0df98ec 100644 --- a/drivers/soc/hisilicon/kunpeng_hccs.c +++ b/drivers/soc/hisilicon/kunpeng_hccs.c @@ -1244,14 +1244,12 @@ unregister_pcc_chan: return rc; } -static int hccs_remove(struct platform_device *pdev) +static void hccs_remove(struct platform_device *pdev) { struct hccs_dev *hdev = platform_get_drvdata(pdev); hccs_remove_topo_dirs(hdev); hccs_unregister_pcc_channel(hdev); - - return 0; } static const struct acpi_device_id hccs_acpi_match[] = { @@ -1262,7 +1260,7 @@ MODULE_DEVICE_TABLE(acpi, hccs_acpi_match); static struct platform_driver hccs_driver = { .probe = hccs_probe, - .remove = hccs_remove, + .remove_new = hccs_remove, .driver = { .name = "kunpeng_hccs", .acpi_match_table = hccs_acpi_match, diff --git a/drivers/soc/imx/soc-imx8m.c b/drivers/soc/imx/soc-imx8m.c index 1dcd243df567..ec87d9d878f3 100644 --- a/drivers/soc/imx/soc-imx8m.c +++ b/drivers/soc/imx/soc-imx8m.c @@ -100,6 +100,7 @@ static void __init imx8mm_soc_uid(void) { void __iomem *ocotp_base; struct device_node *np; + struct clk *clk; u32 offset = of_machine_is_compatible("fsl,imx8mp") ? IMX8MP_OCOTP_UID_OFFSET : 0; @@ -109,11 +110,20 @@ static void __init imx8mm_soc_uid(void) ocotp_base = of_iomap(np, 0); WARN_ON(!ocotp_base); + clk = of_clk_get_by_name(np, NULL); + if (IS_ERR(clk)) { + WARN_ON(IS_ERR(clk)); + return; + } + + clk_prepare_enable(clk); soc_uid = readl_relaxed(ocotp_base + OCOTP_UID_HIGH + offset); soc_uid <<= 32; soc_uid |= readl_relaxed(ocotp_base + OCOTP_UID_LOW + offset); + clk_disable_unprepare(clk); + clk_put(clk); iounmap(ocotp_base); of_node_put(np); } diff --git a/drivers/soc/ixp4xx/ixp4xx-npe.c b/drivers/soc/ixp4xx/ixp4xx-npe.c index 5be9988f30ce..35825ee95dff 100644 --- a/drivers/soc/ixp4xx/ixp4xx-npe.c +++ b/drivers/soc/ixp4xx/ixp4xx-npe.c @@ -736,7 +736,7 @@ static int ixp4xx_npe_probe(struct platform_device *pdev) return 0; } -static int ixp4xx_npe_remove(struct platform_device *pdev) +static void ixp4xx_npe_remove(struct platform_device *pdev) { int i; @@ -744,8 +744,6 @@ static int ixp4xx_npe_remove(struct platform_device *pdev) if (npe_tab[i].regs) { npe_reset(&npe_tab[i]); } - - return 0; } static const struct of_device_id ixp4xx_npe_of_match[] = { @@ -761,7 +759,7 @@ static struct platform_driver ixp4xx_npe_driver = { .of_match_table = ixp4xx_npe_of_match, }, .probe = ixp4xx_npe_probe, - .remove = ixp4xx_npe_remove, + .remove_new = ixp4xx_npe_remove, }; module_platform_driver(ixp4xx_npe_driver); diff --git a/drivers/soc/ixp4xx/ixp4xx-qmgr.c b/drivers/soc/ixp4xx/ixp4xx-qmgr.c index 291086bb9313..244ad8d7e80b 100644 --- a/drivers/soc/ixp4xx/ixp4xx-qmgr.c +++ b/drivers/soc/ixp4xx/ixp4xx-qmgr.c @@ -442,11 +442,10 @@ static int ixp4xx_qmgr_probe(struct platform_device *pdev) return 0; } -static int ixp4xx_qmgr_remove(struct platform_device *pdev) +static void ixp4xx_qmgr_remove(struct platform_device *pdev) { synchronize_irq(qmgr_irq_1); synchronize_irq(qmgr_irq_2); - return 0; } static const struct of_device_id ixp4xx_qmgr_of_match[] = { @@ -462,7 +461,7 @@ static struct platform_driver ixp4xx_qmgr_driver = { .of_match_table = ixp4xx_qmgr_of_match, }, .probe = ixp4xx_qmgr_probe, - .remove = ixp4xx_qmgr_remove, + .remove_new = ixp4xx_qmgr_remove, }; module_platform_driver(ixp4xx_qmgr_driver); diff --git a/drivers/soc/litex/litex_soc_ctrl.c b/drivers/soc/litex/litex_soc_ctrl.c index f75790091d38..10813299aa10 100644 --- a/drivers/soc/litex/litex_soc_ctrl.c +++ b/drivers/soc/litex/litex_soc_ctrl.c @@ -120,12 +120,11 @@ static int litex_soc_ctrl_probe(struct platform_device *pdev) return 0; } -static int litex_soc_ctrl_remove(struct platform_device *pdev) +static void litex_soc_ctrl_remove(struct platform_device *pdev) { struct litex_soc_ctrl_device *soc_ctrl_dev = platform_get_drvdata(pdev); unregister_restart_handler(&soc_ctrl_dev->reset_nb); - return 0; } static struct platform_driver litex_soc_ctrl_driver = { @@ -134,7 +133,7 @@ static struct platform_driver litex_soc_ctrl_driver = { .of_match_table = of_match_ptr(litex_soc_ctrl_of_match) }, .probe = litex_soc_ctrl_probe, - .remove = litex_soc_ctrl_remove, + .remove_new = litex_soc_ctrl_remove, }; module_platform_driver(litex_soc_ctrl_driver); diff --git a/drivers/soc/loongson/Kconfig b/drivers/soc/loongson/Kconfig index 314e13bb3e01..368344943a93 100644 --- a/drivers/soc/loongson/Kconfig +++ b/drivers/soc/loongson/Kconfig @@ -20,6 +20,7 @@ config LOONGSON2_GUTS config LOONGSON2_PM bool "Loongson-2 SoC Power Management Controller Driver" depends on LOONGARCH && OF + depends on INPUT=y help The Loongson-2's power management controller was ACPI, supports ACPI S2Idle (Suspend To Idle), ACPI S3 (Suspend To RAM), ACPI S4 (Suspend To diff --git a/drivers/soc/loongson/loongson2_guts.c b/drivers/soc/loongson/loongson2_guts.c index bace4bc8e03b..ef352a0f5022 100644 --- a/drivers/soc/loongson/loongson2_guts.c +++ b/drivers/soc/loongson/loongson2_guts.c @@ -70,7 +70,7 @@ static const struct loongson2_soc_die_attr *loongson2_soc_die_match( if (matches->svr == (svr & matches->mask)) return matches; matches++; - }; + } return NULL; } @@ -94,7 +94,6 @@ static int loongson2_guts_probe(struct platform_device *pdev) { struct device_node *root, *np = pdev->dev.of_node; struct device *dev = &pdev->dev; - struct resource *res; const struct loongson2_soc_die_attr *soc_die; const char *machine; u32 svr; @@ -106,8 +105,7 @@ static int loongson2_guts_probe(struct platform_device *pdev) guts->little_endian = of_property_read_bool(np, "little-endian"); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - guts->regs = ioremap(res->start, res->end - res->start + 1); + guts->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(guts->regs)) return PTR_ERR(guts->regs); @@ -150,11 +148,9 @@ static int loongson2_guts_probe(struct platform_device *pdev) return 0; } -static int loongson2_guts_remove(struct platform_device *dev) +static void loongson2_guts_remove(struct platform_device *dev) { soc_device_unregister(soc_dev); - - return 0; } /* @@ -173,7 +169,7 @@ static struct platform_driver loongson2_guts_driver = { .of_match_table = loongson2_guts_of_match, }, .probe = loongson2_guts_probe, - .remove = loongson2_guts_remove, + .remove_new = loongson2_guts_remove, }; static int __init loongson2_guts_init(void) diff --git a/drivers/soc/loongson/loongson2_pm.c b/drivers/soc/loongson/loongson2_pm.c index 796add6e8b63..b8e5e1e3528a 100644 --- a/drivers/soc/loongson/loongson2_pm.c +++ b/drivers/soc/loongson/loongson2_pm.c @@ -11,6 +11,7 @@ #include <linux/input.h> #include <linux/suspend.h> #include <linux/interrupt.h> +#include <linux/of_platform.h> #include <linux/pm_wakeirq.h> #include <linux/platform_device.h> #include <asm/bootinfo.h> @@ -192,12 +193,16 @@ static int loongson2_pm_probe(struct platform_device *pdev) if (loongson_sysconf.suspend_addr) suspend_set_ops(&loongson2_suspend_ops); + /* Populate children */ + retval = devm_of_platform_populate(dev); + if (retval) + dev_err(dev, "Error populating children, reboot and poweroff might not work properly\n"); + return 0; } static const struct of_device_id loongson2_pm_match[] = { { .compatible = "loongson,ls2k0500-pmc", }, - { .compatible = "loongson,ls2k1000-pmc", }, {}, }; diff --git a/drivers/soc/mediatek/mtk-devapc.c b/drivers/soc/mediatek/mtk-devapc.c index b28feb967540..56cc345552a4 100644 --- a/drivers/soc/mediatek/mtk-devapc.c +++ b/drivers/soc/mediatek/mtk-devapc.c @@ -292,18 +292,16 @@ static int mtk_devapc_probe(struct platform_device *pdev) return 0; } -static int mtk_devapc_remove(struct platform_device *pdev) +static void mtk_devapc_remove(struct platform_device *pdev) { struct mtk_devapc_context *ctx = platform_get_drvdata(pdev); stop_devapc(ctx); - - return 0; } static struct platform_driver mtk_devapc_driver = { .probe = mtk_devapc_probe, - .remove = mtk_devapc_remove, + .remove_new = mtk_devapc_remove, .driver = { .name = "mtk-devapc", .of_match_table = mtk_devapc_dt_match, diff --git a/drivers/soc/mediatek/mtk-mmsys.c b/drivers/soc/mediatek/mtk-mmsys.c index ffb75711a1da..88209102ff3b 100644 --- a/drivers/soc/mediatek/mtk-mmsys.c +++ b/drivers/soc/mediatek/mtk-mmsys.c @@ -410,14 +410,12 @@ out_probe_done: return 0; } -static int mtk_mmsys_remove(struct platform_device *pdev) +static void mtk_mmsys_remove(struct platform_device *pdev) { struct mtk_mmsys *mmsys = platform_get_drvdata(pdev); platform_device_unregister(mmsys->drm_pdev); platform_device_unregister(mmsys->clks_pdev); - - return 0; } static const struct of_device_id of_match_mtk_mmsys[] = { @@ -449,7 +447,7 @@ static struct platform_driver mtk_mmsys_drv = { .of_match_table = of_match_mtk_mmsys, }, .probe = mtk_mmsys_probe, - .remove = mtk_mmsys_remove, + .remove_new = mtk_mmsys_remove, }; module_platform_driver(mtk_mmsys_drv); diff --git a/drivers/soc/mediatek/mtk-svs.c b/drivers/soc/mediatek/mtk-svs.c index 3a2f97cd5272..f31e3bedff50 100644 --- a/drivers/soc/mediatek/mtk-svs.c +++ b/drivers/soc/mediatek/mtk-svs.c @@ -407,6 +407,7 @@ struct svs_platform_data { * @dcbdet: svs efuse data * @dcmdet: svs efuse data * @turn_pt: 2-line turn point tells which opp_volt calculated by high/low bank + * @vbin_turn_pt: voltage bin turn point helps know which svsb_volt should be overridden * @type: bank type to represent it is 2-line (high/low) bank or 1-line bank * * Svs bank will generate suitalbe voltages by below general math equation @@ -469,6 +470,7 @@ struct svs_bank { u32 dcbdet; u32 dcmdet; u32 turn_pt; + u32 vbin_turn_pt; u32 type; }; @@ -751,11 +753,12 @@ static int svs_status_debug_show(struct seq_file *m, void *v) ret = thermal_zone_get_temp(svsb->tzd, &tzone_temp); if (ret) - seq_printf(m, "%s: temperature ignore, turn_pt = %u\n", - svsb->name, svsb->turn_pt); + seq_printf(m, "%s: temperature ignore, vbin_turn_pt = %u, turn_pt = %u\n", + svsb->name, svsb->vbin_turn_pt, svsb->turn_pt); else - seq_printf(m, "%s: temperature = %d, turn_pt = %u\n", - svsb->name, tzone_temp, svsb->turn_pt); + seq_printf(m, "%s: temperature = %d, vbin_turn_pt = %u, turn_pt = %u\n", + svsb->name, tzone_temp, svsb->vbin_turn_pt, + svsb->turn_pt); for (i = 0; i < svsb->opp_count; i++) { opp = dev_pm_opp_find_freq_exact(svsb->opp_dev, @@ -952,6 +955,29 @@ static void svs_get_bank_volts_v3(struct svs_platform *svsp) for (i = opp_start; i < opp_stop; i++) if (svsb->volt_flags & SVSB_REMOVE_DVTFIXED_VOLT) svsb->volt[i] -= svsb->dvt_fixed; + + /* For voltage bin support */ + if (svsb->opp_dfreq[0] > svsb->freq_base) { + svsb->volt[0] = svs_opp_volt_to_bank_volt(svsb->opp_dvolt[0], + svsb->volt_step, + svsb->volt_base); + + /* Find voltage bin turn point */ + for (i = 0; i < svsb->opp_count; i++) { + if (svsb->opp_dfreq[i] <= svsb->freq_base) { + svsb->vbin_turn_pt = i; + break; + } + } + + /* Override svs bank voltages */ + for (i = 1; i < svsb->vbin_turn_pt; i++) + svsb->volt[i] = interpolate(svsb->freq_pct[0], + svsb->freq_pct[svsb->vbin_turn_pt], + svsb->volt[0], + svsb->volt[svsb->vbin_turn_pt], + svsb->freq_pct[i]); + } } static void svs_set_bank_freq_pct_v3(struct svs_platform *svsp) @@ -1069,6 +1095,29 @@ static void svs_get_bank_volts_v2(struct svs_platform *svsp) for (i = 0; i < svsb->opp_count; i++) svsb->volt[i] += svsb->volt_od; + + /* For voltage bin support */ + if (svsb->opp_dfreq[0] > svsb->freq_base) { + svsb->volt[0] = svs_opp_volt_to_bank_volt(svsb->opp_dvolt[0], + svsb->volt_step, + svsb->volt_base); + + /* Find voltage bin turn point */ + for (i = 0; i < svsb->opp_count; i++) { + if (svsb->opp_dfreq[i] <= svsb->freq_base) { + svsb->vbin_turn_pt = i; + break; + } + } + + /* Override svs bank voltages */ + for (i = 1; i < svsb->vbin_turn_pt; i++) + svsb->volt[i] = interpolate(svsb->freq_pct[0], + svsb->freq_pct[svsb->vbin_turn_pt], + svsb->volt[0], + svsb->volt[svsb->vbin_turn_pt], + svsb->freq_pct[i]); + } } static void svs_set_bank_freq_pct_v2(struct svs_platform *svsp) @@ -1808,6 +1857,66 @@ static bool svs_mt8192_efuse_parsing(struct svs_platform *svsp) return true; } +static bool svs_mt8188_efuse_parsing(struct svs_platform *svsp) +{ + struct svs_bank *svsb; + u32 idx, i, golden_temp; + int ret; + + for (i = 0; i < svsp->efuse_max; i++) + if (svsp->efuse[i]) + dev_info(svsp->dev, "M_HW_RES%d: 0x%08x\n", + i, svsp->efuse[i]); + + if (!svsp->efuse[5]) { + dev_notice(svsp->dev, "svs_efuse[5] = 0x0?\n"); + return false; + } + + /* Svs efuse parsing */ + for (idx = 0; idx < svsp->bank_max; idx++) { + svsb = &svsp->banks[idx]; + + if (svsb->type == SVSB_LOW) { + svsb->mtdes = svsp->efuse[5] & GENMASK(7, 0); + svsb->bdes = (svsp->efuse[5] >> 16) & GENMASK(7, 0); + svsb->mdes = (svsp->efuse[5] >> 24) & GENMASK(7, 0); + svsb->dcbdet = (svsp->efuse[15] >> 16) & GENMASK(7, 0); + svsb->dcmdet = (svsp->efuse[15] >> 24) & GENMASK(7, 0); + } else if (svsb->type == SVSB_HIGH) { + svsb->mtdes = svsp->efuse[4] & GENMASK(7, 0); + svsb->bdes = (svsp->efuse[4] >> 16) & GENMASK(7, 0); + svsb->mdes = (svsp->efuse[4] >> 24) & GENMASK(7, 0); + svsb->dcbdet = svsp->efuse[14] & GENMASK(7, 0); + svsb->dcmdet = (svsp->efuse[14] >> 8) & GENMASK(7, 0); + } + + svsb->vmax += svsb->dvt_fixed; + } + + ret = svs_get_efuse_data(svsp, "t-calibration-data", + &svsp->tefuse, &svsp->tefuse_max); + if (ret) + return false; + + for (i = 0; i < svsp->tefuse_max; i++) + if (svsp->tefuse[i] != 0) + break; + + if (i == svsp->tefuse_max) + golden_temp = 50; /* All thermal efuse data are 0 */ + else + golden_temp = (svsp->tefuse[0] >> 24) & GENMASK(7, 0); + + for (idx = 0; idx < svsp->bank_max; idx++) { + svsb = &svsp->banks[idx]; + svsb->mts = 500; + svsb->bts = (((500 * golden_temp + 250460) / 1000) - 25) * 4; + } + + return true; +} + static bool svs_mt8183_efuse_parsing(struct svs_platform *svsp) { struct svs_bank *svsb; @@ -2173,6 +2282,61 @@ static struct svs_bank svs_mt8192_banks[] = { }, }; +static struct svs_bank svs_mt8188_banks[] = { + { + .sw_id = SVSB_GPU, + .type = SVSB_LOW, + .set_freq_pct = svs_set_bank_freq_pct_v3, + .get_volts = svs_get_bank_volts_v3, + .volt_flags = SVSB_REMOVE_DVTFIXED_VOLT, + .mode_support = SVSB_MODE_INIT02, + .opp_count = MAX_OPP_ENTRIES, + .freq_base = 640000000, + .turn_freq_base = 640000000, + .volt_step = 6250, + .volt_base = 400000, + .vmax = 0x38, + .vmin = 0x1c, + .age_config = 0x555555, + .dc_config = 0x555555, + .dvt_fixed = 0x1, + .vco = 0x10, + .chk_shift = 0x87, + .core_sel = 0x0fff0000, + .int_st = BIT(0), + .ctl0 = 0x00100003, + }, + { + .sw_id = SVSB_GPU, + .type = SVSB_HIGH, + .set_freq_pct = svs_set_bank_freq_pct_v3, + .get_volts = svs_get_bank_volts_v3, + .tzone_name = "gpu1", + .volt_flags = SVSB_REMOVE_DVTFIXED_VOLT | + SVSB_MON_VOLT_IGNORE, + .mode_support = SVSB_MODE_INIT02 | SVSB_MODE_MON, + .opp_count = MAX_OPP_ENTRIES, + .freq_base = 880000000, + .turn_freq_base = 640000000, + .volt_step = 6250, + .volt_base = 400000, + .vmax = 0x38, + .vmin = 0x1c, + .age_config = 0x555555, + .dc_config = 0x555555, + .dvt_fixed = 0x4, + .vco = 0x10, + .chk_shift = 0x87, + .core_sel = 0x0fff0001, + .int_st = BIT(1), + .ctl0 = 0x00100003, + .tzone_htemp = 85000, + .tzone_htemp_voffset = 0, + .tzone_ltemp = 25000, + .tzone_ltemp_voffset = 7, + }, +}; + static struct svs_bank svs_mt8183_banks[] = { { .sw_id = SVSB_CPU_LITTLE, @@ -2286,6 +2450,15 @@ static const struct svs_platform_data svs_mt8192_platform_data = { .bank_max = ARRAY_SIZE(svs_mt8192_banks), }; +static const struct svs_platform_data svs_mt8188_platform_data = { + .name = "mt8188-svs", + .banks = svs_mt8188_banks, + .efuse_parsing = svs_mt8188_efuse_parsing, + .probe = svs_mt8192_platform_probe, + .regs = svs_regs_v2, + .bank_max = ARRAY_SIZE(svs_mt8188_banks), +}; + static const struct svs_platform_data svs_mt8183_platform_data = { .name = "mt8183-svs", .banks = svs_mt8183_banks, @@ -2300,6 +2473,9 @@ static const struct of_device_id svs_of_match[] = { .compatible = "mediatek,mt8192-svs", .data = &svs_mt8192_platform_data, }, { + .compatible = "mediatek,mt8188-svs", + .data = &svs_mt8188_platform_data, + }, { .compatible = "mediatek,mt8183-svs", .data = &svs_mt8183_platform_data, }, { diff --git a/drivers/soc/microchip/mpfs-sys-controller.c b/drivers/soc/microchip/mpfs-sys-controller.c index fbcd5fd24d7c..0935e9e94172 100644 --- a/drivers/soc/microchip/mpfs-sys-controller.c +++ b/drivers/soc/microchip/mpfs-sys-controller.c @@ -149,13 +149,11 @@ static int mpfs_sys_controller_probe(struct platform_device *pdev) return 0; } -static int mpfs_sys_controller_remove(struct platform_device *pdev) +static void mpfs_sys_controller_remove(struct platform_device *pdev) { struct mpfs_sys_controller *sys_controller = platform_get_drvdata(pdev); mpfs_sys_controller_put(sys_controller); - - return 0; } static const struct of_device_id mpfs_sys_controller_of_match[] = { @@ -207,7 +205,7 @@ static struct platform_driver mpfs_sys_controller_driver = { .of_match_table = mpfs_sys_controller_of_match, }, .probe = mpfs_sys_controller_probe, - .remove = mpfs_sys_controller_remove, + .remove_new = mpfs_sys_controller_remove, }; module_platform_driver(mpfs_sys_controller_driver); diff --git a/drivers/soc/pxa/ssp.c b/drivers/soc/pxa/ssp.c index bd029e838241..a1e8a07f7275 100644 --- a/drivers/soc/pxa/ssp.c +++ b/drivers/soc/pxa/ssp.c @@ -176,15 +176,13 @@ static int pxa_ssp_probe(struct platform_device *pdev) return 0; } -static int pxa_ssp_remove(struct platform_device *pdev) +static void pxa_ssp_remove(struct platform_device *pdev) { struct ssp_device *ssp = platform_get_drvdata(pdev); mutex_lock(&ssp_lock); list_del(&ssp->node); mutex_unlock(&ssp_lock); - - return 0; } static const struct platform_device_id ssp_id_table[] = { @@ -199,7 +197,7 @@ static const struct platform_device_id ssp_id_table[] = { static struct platform_driver pxa_ssp_driver = { .probe = pxa_ssp_probe, - .remove = pxa_ssp_remove, + .remove_new = pxa_ssp_remove, .driver = { .name = "pxa2xx-ssp", .of_match_table = of_match_ptr(pxa_ssp_of_ids), diff --git a/drivers/soc/qcom/cmd-db.c b/drivers/soc/qcom/cmd-db.c index 34c40368d5b5..a5fd68411bed 100644 --- a/drivers/soc/qcom/cmd-db.c +++ b/drivers/soc/qcom/cmd-db.c @@ -133,7 +133,7 @@ int cmd_db_ready(void) return 0; } -EXPORT_SYMBOL(cmd_db_ready); +EXPORT_SYMBOL_GPL(cmd_db_ready); static int cmd_db_get_header(const char *id, const struct entry_header **eh, const struct rsc_hdr **rh) @@ -193,7 +193,7 @@ u32 cmd_db_read_addr(const char *id) return ret < 0 ? 0 : le32_to_cpu(ent->addr); } -EXPORT_SYMBOL(cmd_db_read_addr); +EXPORT_SYMBOL_GPL(cmd_db_read_addr); /** * cmd_db_read_aux_data() - Query command db for aux data. @@ -218,7 +218,7 @@ const void *cmd_db_read_aux_data(const char *id, size_t *len) return rsc_offset(rsc_hdr, ent); } -EXPORT_SYMBOL(cmd_db_read_aux_data); +EXPORT_SYMBOL_GPL(cmd_db_read_aux_data); /** * cmd_db_read_slave_id - Get the slave ID for a given resource address @@ -240,7 +240,7 @@ enum cmd_db_hw_type cmd_db_read_slave_id(const char *id) addr = le32_to_cpu(ent->addr); return (addr >> SLAVE_ID_SHIFT) & SLAVE_ID_MASK; } -EXPORT_SYMBOL(cmd_db_read_slave_id); +EXPORT_SYMBOL_GPL(cmd_db_read_slave_id); #ifdef CONFIG_DEBUG_FS static int cmd_db_debugfs_dump(struct seq_file *seq, void *p) diff --git a/drivers/soc/qcom/icc-bwmon.c b/drivers/soc/qcom/icc-bwmon.c index adf2d523f103..656706259353 100644 --- a/drivers/soc/qcom/icc-bwmon.c +++ b/drivers/soc/qcom/icc-bwmon.c @@ -793,13 +793,11 @@ static int bwmon_probe(struct platform_device *pdev) return 0; } -static int bwmon_remove(struct platform_device *pdev) +static void bwmon_remove(struct platform_device *pdev) { struct icc_bwmon *bwmon = platform_get_drvdata(pdev); bwmon_disable(bwmon); - - return 0; } static const struct icc_bwmon_data msm8998_bwmon_data = { @@ -862,7 +860,7 @@ MODULE_DEVICE_TABLE(of, bwmon_of_match); static struct platform_driver bwmon_driver = { .probe = bwmon_probe, - .remove = bwmon_remove, + .remove_new = bwmon_remove, .driver = { .name = "qcom-bwmon", .of_match_table = bwmon_of_match, diff --git a/drivers/soc/qcom/kryo-l2-accessors.c b/drivers/soc/qcom/kryo-l2-accessors.c index 7886af4fd726..50cd710c5e82 100644 --- a/drivers/soc/qcom/kryo-l2-accessors.c +++ b/drivers/soc/qcom/kryo-l2-accessors.c @@ -32,7 +32,7 @@ void kryo_l2_set_indirect_reg(u64 reg, u64 val) isb(); raw_spin_unlock_irqrestore(&l2_access_lock, flags); } -EXPORT_SYMBOL(kryo_l2_set_indirect_reg); +EXPORT_SYMBOL_GPL(kryo_l2_set_indirect_reg); /** * kryo_l2_get_indirect_reg() - read an L2 register value @@ -54,4 +54,4 @@ u64 kryo_l2_get_indirect_reg(u64 reg) return val; } -EXPORT_SYMBOL(kryo_l2_get_indirect_reg); +EXPORT_SYMBOL_GPL(kryo_l2_get_indirect_reg); diff --git a/drivers/soc/qcom/llcc-qcom.c b/drivers/soc/qcom/llcc-qcom.c index e32a4161a8d0..674abd0d6700 100644 --- a/drivers/soc/qcom/llcc-qcom.c +++ b/drivers/soc/qcom/llcc-qcom.c @@ -12,6 +12,7 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/mutex.h> +#include <linux/nvmem-consumer.h> #include <linux/of.h> #include <linux/regmap.h> #include <linux/sizes.h> @@ -126,6 +127,11 @@ struct qcom_llcc_config { bool no_edac; }; +struct qcom_sct_config { + const struct qcom_llcc_config *llcc_config; + int num_config; +}; + enum llcc_reg_offset { LLCC_COMMON_HW_INFO, LLCC_COMMON_STATUS0, @@ -185,7 +191,7 @@ static const struct llcc_slice_config sc8280xp_data[] = { { LLCC_MMUHWT, 13, 1024, 1, 1, 0xfff, 0x0, 0, 0, 0, 0, 1, 0 }, { LLCC_DISP, 16, 6144, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0 }, { LLCC_AUDHW, 22, 2048, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0 }, - { LLCC_DRE, 26, 1024, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0 }, + { LLCC_ECC, 26, 1024, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0 }, { LLCC_CVP, 28, 512, 3, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0 }, { LLCC_APTCM, 30, 1024, 3, 1, 0x0, 0x1, 1, 0, 0, 1, 0, 0 }, { LLCC_WRCACHE, 31, 1024, 1, 1, 0xfff, 0x0, 0, 0, 0, 0, 1, 0 }, @@ -356,6 +362,36 @@ static const struct llcc_slice_config sm8550_data[] = { {LLCC_VIDVSP, 28, 256, 4, 1, 0xFFFFFF, 0x0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, }; +static const struct llcc_slice_config qdu1000_data_2ch[] = { + { LLCC_MDMHPGRW, 7, 512, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0, 0 }, + { LLCC_MODHW, 9, 256, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0, 0 }, + { LLCC_MDMPNG, 21, 256, 0, 1, 0x3, 0x0, 0, 0, 0, 1, 0, 0, 0 }, + { LLCC_ECC, 26, 512, 3, 1, 0xffc, 0x0, 0, 0, 0, 0, 1, 0, 0 }, + { LLCC_MODPE, 29, 256, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0, 0 }, + { LLCC_APTCM, 30, 256, 3, 1, 0x0, 0xc, 1, 0, 0, 1, 0, 0, 0 }, + { LLCC_WRCACHE, 31, 128, 1, 1, 0x3, 0x0, 0, 0, 0, 0, 1, 0, 0 }, +}; + +static const struct llcc_slice_config qdu1000_data_4ch[] = { + { LLCC_MDMHPGRW, 7, 1024, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0, 0 }, + { LLCC_MODHW, 9, 512, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0, 0 }, + { LLCC_MDMPNG, 21, 512, 0, 1, 0x3, 0x0, 0, 0, 0, 1, 0, 0, 0 }, + { LLCC_ECC, 26, 1024, 3, 1, 0xffc, 0x0, 0, 0, 0, 0, 1, 0, 0 }, + { LLCC_MODPE, 29, 512, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0, 0 }, + { LLCC_APTCM, 30, 512, 3, 1, 0x0, 0xc, 1, 0, 0, 1, 0, 0, 0 }, + { LLCC_WRCACHE, 31, 256, 1, 1, 0x3, 0x0, 0, 0, 0, 0, 1, 0, 0 }, +}; + +static const struct llcc_slice_config qdu1000_data_8ch[] = { + { LLCC_MDMHPGRW, 7, 2048, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0, 0 }, + { LLCC_MODHW, 9, 1024, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0, 0 }, + { LLCC_MDMPNG, 21, 1024, 0, 1, 0x3, 0x0, 0, 0, 0, 1, 0, 0, 0 }, + { LLCC_ECC, 26, 2048, 3, 1, 0xffc, 0x0, 0, 0, 0, 0, 1, 0, 0 }, + { LLCC_MODPE, 29, 1024, 1, 1, 0xfff, 0x0, 0, 0, 0, 1, 0, 0, 0 }, + { LLCC_APTCM, 30, 1024, 3, 1, 0x0, 0xc, 1, 0, 0, 1, 0, 0, 0 }, + { LLCC_WRCACHE, 31, 512, 1, 1, 0x3, 0x0, 0, 0, 0, 0, 1, 0, 0 }, +}; + static const struct llcc_edac_reg_offset llcc_v1_edac_reg_offset = { .trp_ecc_error_status0 = 0x20344, .trp_ecc_error_status1 = 0x20348, @@ -422,101 +458,221 @@ static const u32 llcc_v2_1_reg_offset[] = { [LLCC_COMMON_STATUS0] = 0x0003400c, }; -static const struct qcom_llcc_config sc7180_cfg = { - .sct_data = sc7180_data, - .size = ARRAY_SIZE(sc7180_data), - .need_llcc_cfg = true, - .reg_offset = llcc_v1_reg_offset, - .edac_reg_offset = &llcc_v1_edac_reg_offset, +static const struct qcom_llcc_config qdu1000_cfg[] = { + { + .sct_data = qdu1000_data_8ch, + .size = ARRAY_SIZE(qdu1000_data_8ch), + .need_llcc_cfg = true, + .reg_offset = llcc_v2_1_reg_offset, + .edac_reg_offset = &llcc_v2_1_edac_reg_offset, + }, + { + .sct_data = qdu1000_data_4ch, + .size = ARRAY_SIZE(qdu1000_data_4ch), + .need_llcc_cfg = true, + .reg_offset = llcc_v2_1_reg_offset, + .edac_reg_offset = &llcc_v2_1_edac_reg_offset, + }, + { + .sct_data = qdu1000_data_4ch, + .size = ARRAY_SIZE(qdu1000_data_4ch), + .need_llcc_cfg = true, + .reg_offset = llcc_v2_1_reg_offset, + .edac_reg_offset = &llcc_v2_1_edac_reg_offset, + }, + { + .sct_data = qdu1000_data_2ch, + .size = ARRAY_SIZE(qdu1000_data_2ch), + .need_llcc_cfg = true, + .reg_offset = llcc_v2_1_reg_offset, + .edac_reg_offset = &llcc_v2_1_edac_reg_offset, + }, +}; + +static const struct qcom_llcc_config sc7180_cfg[] = { + { + .sct_data = sc7180_data, + .size = ARRAY_SIZE(sc7180_data), + .need_llcc_cfg = true, + .reg_offset = llcc_v1_reg_offset, + .edac_reg_offset = &llcc_v1_edac_reg_offset, + }, +}; + +static const struct qcom_llcc_config sc7280_cfg[] = { + { + .sct_data = sc7280_data, + .size = ARRAY_SIZE(sc7280_data), + .need_llcc_cfg = true, + .reg_offset = llcc_v1_reg_offset, + .edac_reg_offset = &llcc_v1_edac_reg_offset, + }, +}; + +static const struct qcom_llcc_config sc8180x_cfg[] = { + { + .sct_data = sc8180x_data, + .size = ARRAY_SIZE(sc8180x_data), + .need_llcc_cfg = true, + .reg_offset = llcc_v1_reg_offset, + .edac_reg_offset = &llcc_v1_edac_reg_offset, + }, +}; + +static const struct qcom_llcc_config sc8280xp_cfg[] = { + { + .sct_data = sc8280xp_data, + .size = ARRAY_SIZE(sc8280xp_data), + .need_llcc_cfg = true, + .reg_offset = llcc_v1_reg_offset, + .edac_reg_offset = &llcc_v1_edac_reg_offset, + }, +}; + +static const struct qcom_llcc_config sdm845_cfg[] = { + { + .sct_data = sdm845_data, + .size = ARRAY_SIZE(sdm845_data), + .need_llcc_cfg = false, + .reg_offset = llcc_v1_reg_offset, + .edac_reg_offset = &llcc_v1_edac_reg_offset, + .no_edac = true, + }, +}; + +static const struct qcom_llcc_config sm6350_cfg[] = { + { + .sct_data = sm6350_data, + .size = ARRAY_SIZE(sm6350_data), + .need_llcc_cfg = true, + .reg_offset = llcc_v1_reg_offset, + .edac_reg_offset = &llcc_v1_edac_reg_offset, + }, +}; + +static const struct qcom_llcc_config sm7150_cfg[] = { + { + .sct_data = sm7150_data, + .size = ARRAY_SIZE(sm7150_data), + .need_llcc_cfg = true, + .reg_offset = llcc_v1_reg_offset, + .edac_reg_offset = &llcc_v1_edac_reg_offset, + }, +}; + +static const struct qcom_llcc_config sm8150_cfg[] = { + { + .sct_data = sm8150_data, + .size = ARRAY_SIZE(sm8150_data), + .need_llcc_cfg = true, + .reg_offset = llcc_v1_reg_offset, + .edac_reg_offset = &llcc_v1_edac_reg_offset, + }, +}; + +static const struct qcom_llcc_config sm8250_cfg[] = { + { + .sct_data = sm8250_data, + .size = ARRAY_SIZE(sm8250_data), + .need_llcc_cfg = true, + .reg_offset = llcc_v1_reg_offset, + .edac_reg_offset = &llcc_v1_edac_reg_offset, + }, +}; + +static const struct qcom_llcc_config sm8350_cfg[] = { + { + .sct_data = sm8350_data, + .size = ARRAY_SIZE(sm8350_data), + .need_llcc_cfg = true, + .reg_offset = llcc_v1_reg_offset, + .edac_reg_offset = &llcc_v1_edac_reg_offset, + }, +}; + +static const struct qcom_llcc_config sm8450_cfg[] = { + { + .sct_data = sm8450_data, + .size = ARRAY_SIZE(sm8450_data), + .need_llcc_cfg = true, + .reg_offset = llcc_v2_1_reg_offset, + .edac_reg_offset = &llcc_v2_1_edac_reg_offset, + }, +}; + +static const struct qcom_llcc_config sm8550_cfg[] = { + { + .sct_data = sm8550_data, + .size = ARRAY_SIZE(sm8550_data), + .need_llcc_cfg = true, + .reg_offset = llcc_v2_1_reg_offset, + .edac_reg_offset = &llcc_v2_1_edac_reg_offset, + }, +}; + +static const struct qcom_sct_config qdu1000_cfgs = { + .llcc_config = qdu1000_cfg, + .num_config = ARRAY_SIZE(qdu1000_cfg), +}; + +static const struct qcom_sct_config sc7180_cfgs = { + .llcc_config = sc7180_cfg, + .num_config = ARRAY_SIZE(sc7180_cfg), }; -static const struct qcom_llcc_config sc7280_cfg = { - .sct_data = sc7280_data, - .size = ARRAY_SIZE(sc7280_data), - .need_llcc_cfg = true, - .reg_offset = llcc_v1_reg_offset, - .edac_reg_offset = &llcc_v1_edac_reg_offset, +static const struct qcom_sct_config sc7280_cfgs = { + .llcc_config = sc7280_cfg, + .num_config = ARRAY_SIZE(sc7280_cfg), }; -static const struct qcom_llcc_config sc8180x_cfg = { - .sct_data = sc8180x_data, - .size = ARRAY_SIZE(sc8180x_data), - .need_llcc_cfg = true, - .reg_offset = llcc_v1_reg_offset, - .edac_reg_offset = &llcc_v1_edac_reg_offset, +static const struct qcom_sct_config sc8180x_cfgs = { + .llcc_config = sc8180x_cfg, + .num_config = ARRAY_SIZE(sc8180x_cfg), }; -static const struct qcom_llcc_config sc8280xp_cfg = { - .sct_data = sc8280xp_data, - .size = ARRAY_SIZE(sc8280xp_data), - .need_llcc_cfg = true, - .reg_offset = llcc_v1_reg_offset, - .edac_reg_offset = &llcc_v1_edac_reg_offset, +static const struct qcom_sct_config sc8280xp_cfgs = { + .llcc_config = sc8280xp_cfg, + .num_config = ARRAY_SIZE(sc8280xp_cfg), }; -static const struct qcom_llcc_config sdm845_cfg = { - .sct_data = sdm845_data, - .size = ARRAY_SIZE(sdm845_data), - .need_llcc_cfg = false, - .reg_offset = llcc_v1_reg_offset, - .edac_reg_offset = &llcc_v1_edac_reg_offset, - .no_edac = true, +static const struct qcom_sct_config sdm845_cfgs = { + .llcc_config = sdm845_cfg, + .num_config = ARRAY_SIZE(sdm845_cfg), }; -static const struct qcom_llcc_config sm6350_cfg = { - .sct_data = sm6350_data, - .size = ARRAY_SIZE(sm6350_data), - .need_llcc_cfg = true, - .reg_offset = llcc_v1_reg_offset, - .edac_reg_offset = &llcc_v1_edac_reg_offset, +static const struct qcom_sct_config sm6350_cfgs = { + .llcc_config = sm6350_cfg, + .num_config = ARRAY_SIZE(sm6350_cfg), }; -static const struct qcom_llcc_config sm7150_cfg = { - .sct_data = sm7150_data, - .size = ARRAY_SIZE(sm7150_data), - .need_llcc_cfg = true, - .reg_offset = llcc_v1_reg_offset, - .edac_reg_offset = &llcc_v1_edac_reg_offset, +static const struct qcom_sct_config sm7150_cfgs = { + .llcc_config = sm7150_cfg, + .num_config = ARRAY_SIZE(sm7150_cfg), }; -static const struct qcom_llcc_config sm8150_cfg = { - .sct_data = sm8150_data, - .size = ARRAY_SIZE(sm8150_data), - .need_llcc_cfg = true, - .reg_offset = llcc_v1_reg_offset, - .edac_reg_offset = &llcc_v1_edac_reg_offset, +static const struct qcom_sct_config sm8150_cfgs = { + .llcc_config = sm8150_cfg, + .num_config = ARRAY_SIZE(sm8150_cfg), }; -static const struct qcom_llcc_config sm8250_cfg = { - .sct_data = sm8250_data, - .size = ARRAY_SIZE(sm8250_data), - .need_llcc_cfg = true, - .reg_offset = llcc_v1_reg_offset, - .edac_reg_offset = &llcc_v1_edac_reg_offset, +static const struct qcom_sct_config sm8250_cfgs = { + .llcc_config = sm8250_cfg, + .num_config = ARRAY_SIZE(sm8250_cfg), }; -static const struct qcom_llcc_config sm8350_cfg = { - .sct_data = sm8350_data, - .size = ARRAY_SIZE(sm8350_data), - .need_llcc_cfg = true, - .reg_offset = llcc_v1_reg_offset, - .edac_reg_offset = &llcc_v1_edac_reg_offset, +static const struct qcom_sct_config sm8350_cfgs = { + .llcc_config = sm8350_cfg, + .num_config = ARRAY_SIZE(sm8350_cfg), }; -static const struct qcom_llcc_config sm8450_cfg = { - .sct_data = sm8450_data, - .size = ARRAY_SIZE(sm8450_data), - .need_llcc_cfg = true, - .reg_offset = llcc_v2_1_reg_offset, - .edac_reg_offset = &llcc_v2_1_edac_reg_offset, +static const struct qcom_sct_config sm8450_cfgs = { + .llcc_config = sm8450_cfg, + .num_config = ARRAY_SIZE(sm8450_cfg), }; -static const struct qcom_llcc_config sm8550_cfg = { - .sct_data = sm8550_data, - .size = ARRAY_SIZE(sm8550_data), - .need_llcc_cfg = true, - .reg_offset = llcc_v2_1_reg_offset, - .edac_reg_offset = &llcc_v2_1_edac_reg_offset, +static const struct qcom_sct_config sm8550_cfgs = { + .llcc_config = sm8550_cfg, + .num_config = ARRAY_SIZE(sm8550_cfg), }; static struct llcc_drv_data *drv_data = (void *) -EPROBE_DEFER; @@ -906,11 +1062,28 @@ static int qcom_llcc_cfg_program(struct platform_device *pdev, return ret; } -static int qcom_llcc_remove(struct platform_device *pdev) +static int qcom_llcc_get_cfg_index(struct platform_device *pdev, u8 *cfg_index, int num_config) +{ + int ret; + + ret = nvmem_cell_read_u8(&pdev->dev, "multi-chan-ddr", cfg_index); + if (ret == -ENOENT || ret == -EOPNOTSUPP) { + if (num_config > 1) + return -EINVAL; + *cfg_index = 0; + return 0; + } + + if (!ret && *cfg_index >= num_config) + ret = -EINVAL; + + return ret; +} + +static void qcom_llcc_remove(struct platform_device *pdev) { /* Set the global pointer to a error code to avoid referencing it */ drv_data = ERR_PTR(-ENODEV); - return 0; } static struct regmap *qcom_llcc_init_mmio(struct platform_device *pdev, u8 index, @@ -938,12 +1111,17 @@ static int qcom_llcc_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; int ret, i; struct platform_device *llcc_edac; + const struct qcom_sct_config *cfgs; const struct qcom_llcc_config *cfg; const struct llcc_slice_config *llcc_cfg; u32 sz; + u8 cfg_index; u32 version; struct regmap *regmap; + if (!IS_ERR(drv_data)) + return -EBUSY; + drv_data = devm_kzalloc(dev, sizeof(*drv_data), GFP_KERNEL); if (!drv_data) { ret = -ENOMEM; @@ -957,7 +1135,15 @@ static int qcom_llcc_probe(struct platform_device *pdev) goto err; } - cfg = of_device_get_match_data(&pdev->dev); + cfgs = of_device_get_match_data(&pdev->dev); + if (!cfgs) { + ret = -EINVAL; + goto err; + } + ret = qcom_llcc_get_cfg_index(pdev, &cfg_index, cfgs->num_config); + if (ret) + goto err; + cfg = &cfgs->llcc_config[cfg_index]; ret = regmap_read(regmap, cfg->reg_offset[LLCC_COMMON_STATUS0], &num_banks); if (ret) @@ -1050,18 +1236,19 @@ err: } static const struct of_device_id qcom_llcc_of_match[] = { - { .compatible = "qcom,sc7180-llcc", .data = &sc7180_cfg }, - { .compatible = "qcom,sc7280-llcc", .data = &sc7280_cfg }, - { .compatible = "qcom,sc8180x-llcc", .data = &sc8180x_cfg }, - { .compatible = "qcom,sc8280xp-llcc", .data = &sc8280xp_cfg }, - { .compatible = "qcom,sdm845-llcc", .data = &sdm845_cfg }, - { .compatible = "qcom,sm6350-llcc", .data = &sm6350_cfg }, - { .compatible = "qcom,sm7150-llcc", .data = &sm7150_cfg }, - { .compatible = "qcom,sm8150-llcc", .data = &sm8150_cfg }, - { .compatible = "qcom,sm8250-llcc", .data = &sm8250_cfg }, - { .compatible = "qcom,sm8350-llcc", .data = &sm8350_cfg }, - { .compatible = "qcom,sm8450-llcc", .data = &sm8450_cfg }, - { .compatible = "qcom,sm8550-llcc", .data = &sm8550_cfg }, + { .compatible = "qcom,qdu1000-llcc", .data = &qdu1000_cfgs}, + { .compatible = "qcom,sc7180-llcc", .data = &sc7180_cfgs }, + { .compatible = "qcom,sc7280-llcc", .data = &sc7280_cfgs }, + { .compatible = "qcom,sc8180x-llcc", .data = &sc8180x_cfgs }, + { .compatible = "qcom,sc8280xp-llcc", .data = &sc8280xp_cfgs }, + { .compatible = "qcom,sdm845-llcc", .data = &sdm845_cfgs }, + { .compatible = "qcom,sm6350-llcc", .data = &sm6350_cfgs }, + { .compatible = "qcom,sm7150-llcc", .data = &sm7150_cfgs }, + { .compatible = "qcom,sm8150-llcc", .data = &sm8150_cfgs }, + { .compatible = "qcom,sm8250-llcc", .data = &sm8250_cfgs }, + { .compatible = "qcom,sm8350-llcc", .data = &sm8350_cfgs }, + { .compatible = "qcom,sm8450-llcc", .data = &sm8450_cfgs }, + { .compatible = "qcom,sm8550-llcc", .data = &sm8550_cfgs }, { } }; MODULE_DEVICE_TABLE(of, qcom_llcc_of_match); @@ -1072,7 +1259,7 @@ static struct platform_driver qcom_llcc_driver = { .of_match_table = qcom_llcc_of_match, }, .probe = qcom_llcc_probe, - .remove = qcom_llcc_remove, + .remove_new = qcom_llcc_remove, }; module_platform_driver(qcom_llcc_driver); diff --git a/drivers/soc/qcom/ocmem.c b/drivers/soc/qcom/ocmem.c index 20f5461d46b9..e8841d247953 100644 --- a/drivers/soc/qcom/ocmem.c +++ b/drivers/soc/qcom/ocmem.c @@ -211,7 +211,7 @@ struct ocmem *of_get_ocmem(struct device *dev) } return ocmem; } -EXPORT_SYMBOL(of_get_ocmem); +EXPORT_SYMBOL_GPL(of_get_ocmem); struct ocmem_buf *ocmem_allocate(struct ocmem *ocmem, enum ocmem_client client, unsigned long size) @@ -267,7 +267,7 @@ err_unlock: return ERR_PTR(ret); } -EXPORT_SYMBOL(ocmem_allocate); +EXPORT_SYMBOL_GPL(ocmem_allocate); void ocmem_free(struct ocmem *ocmem, enum ocmem_client client, struct ocmem_buf *buf) @@ -294,7 +294,7 @@ void ocmem_free(struct ocmem *ocmem, enum ocmem_client client, clear_bit_unlock(BIT(client), &ocmem->active_allocations); } -EXPORT_SYMBOL(ocmem_free); +EXPORT_SYMBOL_GPL(ocmem_free); static int ocmem_dev_probe(struct platform_device *pdev) { @@ -416,14 +416,12 @@ err_clk_disable: return ret; } -static int ocmem_dev_remove(struct platform_device *pdev) +static void ocmem_dev_remove(struct platform_device *pdev) { struct ocmem *ocmem = platform_get_drvdata(pdev); clk_disable_unprepare(ocmem->core_clk); clk_disable_unprepare(ocmem->iface_clk); - - return 0; } static const struct ocmem_config ocmem_8226_config = { @@ -446,7 +444,7 @@ MODULE_DEVICE_TABLE(of, ocmem_of_match); static struct platform_driver ocmem_driver = { .probe = ocmem_dev_probe, - .remove = ocmem_dev_remove, + .remove_new = ocmem_dev_remove, .driver = { .name = "ocmem", .of_match_table = ocmem_of_match, diff --git a/drivers/soc/qcom/pdr_interface.c b/drivers/soc/qcom/pdr_interface.c index 0034af927b48..a1b6a4081dea 100644 --- a/drivers/soc/qcom/pdr_interface.c +++ b/drivers/soc/qcom/pdr_interface.c @@ -554,7 +554,7 @@ err: kfree(pds); return ERR_PTR(ret); } -EXPORT_SYMBOL(pdr_add_lookup); +EXPORT_SYMBOL_GPL(pdr_add_lookup); /** * pdr_restart_pd() - restart PD @@ -634,7 +634,7 @@ int pdr_restart_pd(struct pdr_handle *pdr, struct pdr_service *pds) return 0; } -EXPORT_SYMBOL(pdr_restart_pd); +EXPORT_SYMBOL_GPL(pdr_restart_pd); /** * pdr_handle_alloc() - initialize the PDR client handle @@ -715,7 +715,7 @@ free_pdr_handle: return ERR_PTR(ret); } -EXPORT_SYMBOL(pdr_handle_alloc); +EXPORT_SYMBOL_GPL(pdr_handle_alloc); /** * pdr_handle_release() - release the PDR client handle @@ -749,7 +749,7 @@ void pdr_handle_release(struct pdr_handle *pdr) kfree(pdr); } -EXPORT_SYMBOL(pdr_handle_release); +EXPORT_SYMBOL_GPL(pdr_handle_release); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("Qualcomm Protection Domain Restart helpers"); diff --git a/drivers/soc/qcom/pmic_glink.c b/drivers/soc/qcom/pmic_glink.c index 61c89ddfc75b..914057331afd 100644 --- a/drivers/soc/qcom/pmic_glink.c +++ b/drivers/soc/qcom/pmic_glink.c @@ -318,7 +318,7 @@ out_release_ucsi_aux: return ret; } -static int pmic_glink_remove(struct platform_device *pdev) +static void pmic_glink_remove(struct platform_device *pdev) { struct pmic_glink *pg = dev_get_drvdata(&pdev->dev); @@ -334,8 +334,6 @@ static int pmic_glink_remove(struct platform_device *pdev) mutex_lock(&__pmic_glink_lock); __pmic_glink = NULL; mutex_unlock(&__pmic_glink_lock); - - return 0; } static const unsigned long pmic_glink_sm8450_client_mask = BIT(PMIC_GLINK_CLIENT_BATT) | @@ -352,7 +350,7 @@ MODULE_DEVICE_TABLE(of, pmic_glink_of_match); static struct platform_driver pmic_glink_driver = { .probe = pmic_glink_probe, - .remove = pmic_glink_remove, + .remove_new = pmic_glink_remove, .driver = { .name = "qcom_pmic_glink", .of_match_table = pmic_glink_of_match, diff --git a/drivers/soc/qcom/pmic_glink_altmode.c b/drivers/soc/qcom/pmic_glink_altmode.c index d05e0d6edf49..9569d999391d 100644 --- a/drivers/soc/qcom/pmic_glink_altmode.c +++ b/drivers/soc/qcom/pmic_glink_altmode.c @@ -444,6 +444,7 @@ static int pmic_glink_altmode_probe(struct auxiliary_device *adev, ret = fwnode_property_read_u32(fwnode, "reg", &port); if (ret < 0) { dev_err(dev, "missing reg property of %pOFn\n", fwnode); + fwnode_handle_put(fwnode); return ret; } @@ -454,6 +455,7 @@ static int pmic_glink_altmode_probe(struct auxiliary_device *adev, if (altmode->ports[port].altmode) { dev_err(dev, "multiple connector definition for port %u\n", port); + fwnode_handle_put(fwnode); return -EINVAL; } @@ -468,45 +470,59 @@ static int pmic_glink_altmode_probe(struct auxiliary_device *adev, alt_port->bridge.type = DRM_MODE_CONNECTOR_USB; ret = devm_drm_bridge_add(dev, &alt_port->bridge); - if (ret) + if (ret) { + fwnode_handle_put(fwnode); return ret; + } alt_port->dp_alt.svid = USB_TYPEC_DP_SID; alt_port->dp_alt.mode = USB_TYPEC_DP_MODE; alt_port->dp_alt.active = 1; alt_port->typec_mux = fwnode_typec_mux_get(fwnode); - if (IS_ERR(alt_port->typec_mux)) + if (IS_ERR(alt_port->typec_mux)) { + fwnode_handle_put(fwnode); return dev_err_probe(dev, PTR_ERR(alt_port->typec_mux), "failed to acquire mode-switch for port: %d\n", port); + } ret = devm_add_action_or_reset(dev, pmic_glink_altmode_put_mux, alt_port->typec_mux); - if (ret) + if (ret) { + fwnode_handle_put(fwnode); return ret; + } alt_port->typec_retimer = fwnode_typec_retimer_get(fwnode); - if (IS_ERR(alt_port->typec_retimer)) + if (IS_ERR(alt_port->typec_retimer)) { + fwnode_handle_put(fwnode); return dev_err_probe(dev, PTR_ERR(alt_port->typec_retimer), "failed to acquire retimer-switch for port: %d\n", port); + } ret = devm_add_action_or_reset(dev, pmic_glink_altmode_put_retimer, alt_port->typec_retimer); - if (ret) + if (ret) { + fwnode_handle_put(fwnode); return ret; + } alt_port->typec_switch = fwnode_typec_switch_get(fwnode); - if (IS_ERR(alt_port->typec_switch)) + if (IS_ERR(alt_port->typec_switch)) { + fwnode_handle_put(fwnode); return dev_err_probe(dev, PTR_ERR(alt_port->typec_switch), "failed to acquire orientation-switch for port: %d\n", port); + } ret = devm_add_action_or_reset(dev, pmic_glink_altmode_put_switch, alt_port->typec_switch); - if (ret) + if (ret) { + fwnode_handle_put(fwnode); return ret; + } } altmode->client = devm_pmic_glink_register_client(dev, diff --git a/drivers/soc/qcom/qcom-geni-se.c b/drivers/soc/qcom/qcom-geni-se.c index ba788762835f..bdcf44b85b2f 100644 --- a/drivers/soc/qcom/qcom-geni-se.c +++ b/drivers/soc/qcom/qcom-geni-se.c @@ -199,7 +199,7 @@ u32 geni_se_get_qup_hw_version(struct geni_se *se) return readl_relaxed(wrapper->base + QUP_HW_VER_REG); } -EXPORT_SYMBOL(geni_se_get_qup_hw_version); +EXPORT_SYMBOL_GPL(geni_se_get_qup_hw_version); static void geni_se_io_set_mode(void __iomem *base) { @@ -272,7 +272,7 @@ void geni_se_init(struct geni_se *se, u32 rx_wm, u32 rx_rfr) val |= S_COMMON_GENI_S_IRQ_EN; writel_relaxed(val, se->base + SE_GENI_S_IRQ_EN); } -EXPORT_SYMBOL(geni_se_init); +EXPORT_SYMBOL_GPL(geni_se_init); static void geni_se_select_fifo_mode(struct geni_se *se) { @@ -364,7 +364,7 @@ void geni_se_select_mode(struct geni_se *se, enum geni_se_xfer_mode mode) break; } } -EXPORT_SYMBOL(geni_se_select_mode); +EXPORT_SYMBOL_GPL(geni_se_select_mode); /** * DOC: Overview @@ -481,7 +481,7 @@ void geni_se_config_packing(struct geni_se *se, int bpw, int pack_words, if (pack_words || bpw == 32) writel_relaxed(bpw / 16, se->base + SE_GENI_BYTE_GRAN); } -EXPORT_SYMBOL(geni_se_config_packing); +EXPORT_SYMBOL_GPL(geni_se_config_packing); static void geni_se_clks_off(struct geni_se *se) { @@ -512,7 +512,7 @@ int geni_se_resources_off(struct geni_se *se) geni_se_clks_off(se); return 0; } -EXPORT_SYMBOL(geni_se_resources_off); +EXPORT_SYMBOL_GPL(geni_se_resources_off); static int geni_se_clks_on(struct geni_se *se) { @@ -553,7 +553,7 @@ int geni_se_resources_on(struct geni_se *se) return ret; } -EXPORT_SYMBOL(geni_se_resources_on); +EXPORT_SYMBOL_GPL(geni_se_resources_on); /** * geni_se_clk_tbl_get() - Get the clock table to program DFS @@ -594,7 +594,7 @@ int geni_se_clk_tbl_get(struct geni_se *se, unsigned long **tbl) *tbl = se->clk_perf_tbl; return se->num_clk_levels; } -EXPORT_SYMBOL(geni_se_clk_tbl_get); +EXPORT_SYMBOL_GPL(geni_se_clk_tbl_get); /** * geni_se_clk_freq_match() - Get the matching or closest SE clock frequency @@ -656,7 +656,7 @@ int geni_se_clk_freq_match(struct geni_se *se, unsigned long req_freq, return 0; } -EXPORT_SYMBOL(geni_se_clk_freq_match); +EXPORT_SYMBOL_GPL(geni_se_clk_freq_match); #define GENI_SE_DMA_DONE_EN BIT(0) #define GENI_SE_DMA_EOT_EN BIT(1) @@ -684,7 +684,7 @@ void geni_se_tx_init_dma(struct geni_se *se, dma_addr_t iova, size_t len) writel_relaxed(GENI_SE_DMA_EOT_BUF, se->base + SE_DMA_TX_ATTR); writel(len, se->base + SE_DMA_TX_LEN); } -EXPORT_SYMBOL(geni_se_tx_init_dma); +EXPORT_SYMBOL_GPL(geni_se_tx_init_dma); /** * geni_se_tx_dma_prep() - Prepare the serial engine for TX DMA transfer @@ -712,7 +712,7 @@ int geni_se_tx_dma_prep(struct geni_se *se, void *buf, size_t len, geni_se_tx_init_dma(se, *iova, len); return 0; } -EXPORT_SYMBOL(geni_se_tx_dma_prep); +EXPORT_SYMBOL_GPL(geni_se_tx_dma_prep); /** * geni_se_rx_init_dma() - Initiate RX DMA transfer on the serial engine @@ -736,7 +736,7 @@ void geni_se_rx_init_dma(struct geni_se *se, dma_addr_t iova, size_t len) writel_relaxed(0, se->base + SE_DMA_RX_ATTR); writel(len, se->base + SE_DMA_RX_LEN); } -EXPORT_SYMBOL(geni_se_rx_init_dma); +EXPORT_SYMBOL_GPL(geni_se_rx_init_dma); /** * geni_se_rx_dma_prep() - Prepare the serial engine for RX DMA transfer @@ -764,7 +764,7 @@ int geni_se_rx_dma_prep(struct geni_se *se, void *buf, size_t len, geni_se_rx_init_dma(se, *iova, len); return 0; } -EXPORT_SYMBOL(geni_se_rx_dma_prep); +EXPORT_SYMBOL_GPL(geni_se_rx_dma_prep); /** * geni_se_tx_dma_unprep() - Unprepare the serial engine after TX DMA transfer @@ -781,7 +781,7 @@ void geni_se_tx_dma_unprep(struct geni_se *se, dma_addr_t iova, size_t len) if (!dma_mapping_error(wrapper->dev, iova)) dma_unmap_single(wrapper->dev, iova, len, DMA_TO_DEVICE); } -EXPORT_SYMBOL(geni_se_tx_dma_unprep); +EXPORT_SYMBOL_GPL(geni_se_tx_dma_unprep); /** * geni_se_rx_dma_unprep() - Unprepare the serial engine after RX DMA transfer @@ -798,7 +798,7 @@ void geni_se_rx_dma_unprep(struct geni_se *se, dma_addr_t iova, size_t len) if (!dma_mapping_error(wrapper->dev, iova)) dma_unmap_single(wrapper->dev, iova, len, DMA_FROM_DEVICE); } -EXPORT_SYMBOL(geni_se_rx_dma_unprep); +EXPORT_SYMBOL_GPL(geni_se_rx_dma_unprep); int geni_icc_get(struct geni_se *se, const char *icc_ddr) { @@ -827,7 +827,7 @@ err: return err; } -EXPORT_SYMBOL(geni_icc_get); +EXPORT_SYMBOL_GPL(geni_icc_get); int geni_icc_set_bw(struct geni_se *se) { @@ -845,7 +845,7 @@ int geni_icc_set_bw(struct geni_se *se) return 0; } -EXPORT_SYMBOL(geni_icc_set_bw); +EXPORT_SYMBOL_GPL(geni_icc_set_bw); void geni_icc_set_tag(struct geni_se *se, u32 tag) { @@ -854,7 +854,7 @@ void geni_icc_set_tag(struct geni_se *se, u32 tag) for (i = 0; i < ARRAY_SIZE(se->icc_paths); i++) icc_set_tag(se->icc_paths[i].path, tag); } -EXPORT_SYMBOL(geni_icc_set_tag); +EXPORT_SYMBOL_GPL(geni_icc_set_tag); /* To do: Replace this by icc_bulk_enable once it's implemented in ICC core */ int geni_icc_enable(struct geni_se *se) @@ -872,7 +872,7 @@ int geni_icc_enable(struct geni_se *se) return 0; } -EXPORT_SYMBOL(geni_icc_enable); +EXPORT_SYMBOL_GPL(geni_icc_enable); int geni_icc_disable(struct geni_se *se) { @@ -889,7 +889,7 @@ int geni_icc_disable(struct geni_se *se) return 0; } -EXPORT_SYMBOL(geni_icc_disable); +EXPORT_SYMBOL_GPL(geni_icc_disable); static int geni_se_probe(struct platform_device *pdev) { diff --git a/drivers/soc/qcom/qcom_aoss.c b/drivers/soc/qcom/qcom_aoss.c index 77f0cf126629..aff0cfb71482 100644 --- a/drivers/soc/qcom/qcom_aoss.c +++ b/drivers/soc/qcom/qcom_aoss.c @@ -260,7 +260,7 @@ int qmp_send(struct qmp *qmp, const char *fmt, ...) return ret; } -EXPORT_SYMBOL(qmp_send); +EXPORT_SYMBOL_GPL(qmp_send); static int qmp_qdss_clk_prepare(struct clk_hw *hw) { @@ -458,7 +458,7 @@ struct qmp *qmp_get(struct device *dev) } return qmp; } -EXPORT_SYMBOL(qmp_get); +EXPORT_SYMBOL_GPL(qmp_get); /** * qmp_put() - release a qmp handle @@ -473,7 +473,7 @@ void qmp_put(struct qmp *qmp) if (!IS_ERR_OR_NULL(qmp)) put_device(qmp->dev); } -EXPORT_SYMBOL(qmp_put); +EXPORT_SYMBOL_GPL(qmp_put); static int qmp_probe(struct platform_device *pdev) { @@ -533,7 +533,7 @@ err_free_mbox: return ret; } -static int qmp_remove(struct platform_device *pdev) +static void qmp_remove(struct platform_device *pdev) { struct qmp *qmp = platform_get_drvdata(pdev); @@ -542,8 +542,6 @@ static int qmp_remove(struct platform_device *pdev) qmp_close(qmp); mbox_free_channel(qmp->mbox_chan); - - return 0; } static const struct of_device_id qmp_dt_match[] = { @@ -565,7 +563,7 @@ static struct platform_driver qmp_driver = { .suppress_bind_attrs = true, }, .probe = qmp_probe, - .remove = qmp_remove, + .remove_new = qmp_remove, }; module_platform_driver(qmp_driver); diff --git a/drivers/soc/qcom/qcom_gsbi.c b/drivers/soc/qcom/qcom_gsbi.c index df7907a83aa8..f04b9a324ea9 100644 --- a/drivers/soc/qcom/qcom_gsbi.c +++ b/drivers/soc/qcom/qcom_gsbi.c @@ -212,13 +212,11 @@ static int gsbi_probe(struct platform_device *pdev) return of_platform_populate(node, NULL, NULL, &pdev->dev); } -static int gsbi_remove(struct platform_device *pdev) +static void gsbi_remove(struct platform_device *pdev) { struct gsbi_info *gsbi = platform_get_drvdata(pdev); clk_disable_unprepare(gsbi->hclk); - - return 0; } static const struct of_device_id gsbi_dt_match[] = { @@ -234,7 +232,7 @@ static struct platform_driver gsbi_driver = { .of_match_table = gsbi_dt_match, }, .probe = gsbi_probe, - .remove = gsbi_remove, + .remove_new = gsbi_remove, }; module_platform_driver(gsbi_driver); diff --git a/drivers/soc/qcom/qcom_stats.c b/drivers/soc/qcom/qcom_stats.c index c207bb96c523..0216fc24f2ca 100644 --- a/drivers/soc/qcom/qcom_stats.c +++ b/drivers/soc/qcom/qcom_stats.c @@ -216,13 +216,11 @@ static int qcom_stats_probe(struct platform_device *pdev) return 0; } -static int qcom_stats_remove(struct platform_device *pdev) +static void qcom_stats_remove(struct platform_device *pdev) { struct dentry *root = platform_get_drvdata(pdev); debugfs_remove_recursive(root); - - return 0; } static const struct stats_config rpm_data = { @@ -272,7 +270,7 @@ MODULE_DEVICE_TABLE(of, qcom_stats_table); static struct platform_driver qcom_stats = { .probe = qcom_stats_probe, - .remove = qcom_stats_remove, + .remove_new = qcom_stats_remove, .driver = { .name = "qcom_stats", .of_match_table = qcom_stats_table, diff --git a/drivers/soc/qcom/qmi_encdec.c b/drivers/soc/qcom/qmi_encdec.c index 5c7161b18b72..bb09eff85cff 100644 --- a/drivers/soc/qcom/qmi_encdec.c +++ b/drivers/soc/qcom/qmi_encdec.c @@ -754,7 +754,7 @@ void *qmi_encode_message(int type, unsigned int msg_id, size_t *len, return msg; } -EXPORT_SYMBOL(qmi_encode_message); +EXPORT_SYMBOL_GPL(qmi_encode_message); /** * qmi_decode_message() - Decode QMI encoded message to C structure @@ -778,7 +778,7 @@ int qmi_decode_message(const void *buf, size_t len, return qmi_decode(ei, c_struct, buf + sizeof(struct qmi_header), len - sizeof(struct qmi_header), 1); } -EXPORT_SYMBOL(qmi_decode_message); +EXPORT_SYMBOL_GPL(qmi_decode_message); /* Common header in all QMI responses */ const struct qmi_elem_info qmi_response_type_v01_ei[] = { @@ -810,7 +810,7 @@ const struct qmi_elem_info qmi_response_type_v01_ei[] = { .ei_array = NULL, }, }; -EXPORT_SYMBOL(qmi_response_type_v01_ei); +EXPORT_SYMBOL_GPL(qmi_response_type_v01_ei); MODULE_DESCRIPTION("QMI encoder/decoder helper"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/soc/qcom/qmi_interface.c b/drivers/soc/qcom/qmi_interface.c index 78d7361fdcf2..bb98b06e87f8 100644 --- a/drivers/soc/qcom/qmi_interface.c +++ b/drivers/soc/qcom/qmi_interface.c @@ -223,7 +223,7 @@ int qmi_add_lookup(struct qmi_handle *qmi, unsigned int service, return 0; } -EXPORT_SYMBOL(qmi_add_lookup); +EXPORT_SYMBOL_GPL(qmi_add_lookup); static void qmi_send_new_server(struct qmi_handle *qmi, struct qmi_service *svc) { @@ -287,7 +287,7 @@ int qmi_add_server(struct qmi_handle *qmi, unsigned int service, return 0; } -EXPORT_SYMBOL(qmi_add_server); +EXPORT_SYMBOL_GPL(qmi_add_server); /** * qmi_txn_init() - allocate transaction id within the given QMI handle @@ -328,7 +328,7 @@ int qmi_txn_init(struct qmi_handle *qmi, struct qmi_txn *txn, return ret; } -EXPORT_SYMBOL(qmi_txn_init); +EXPORT_SYMBOL_GPL(qmi_txn_init); /** * qmi_txn_wait() - wait for a response on a transaction @@ -359,7 +359,7 @@ int qmi_txn_wait(struct qmi_txn *txn, unsigned long timeout) else return txn->result; } -EXPORT_SYMBOL(qmi_txn_wait); +EXPORT_SYMBOL_GPL(qmi_txn_wait); /** * qmi_txn_cancel() - cancel an ongoing transaction @@ -375,7 +375,7 @@ void qmi_txn_cancel(struct qmi_txn *txn) mutex_unlock(&txn->lock); mutex_unlock(&qmi->txn_lock); } -EXPORT_SYMBOL(qmi_txn_cancel); +EXPORT_SYMBOL_GPL(qmi_txn_cancel); /** * qmi_invoke_handler() - find and invoke a handler for a message @@ -676,7 +676,7 @@ err_free_recv_buf: return ret; } -EXPORT_SYMBOL(qmi_handle_init); +EXPORT_SYMBOL_GPL(qmi_handle_init); /** * qmi_handle_release() - release the QMI client handle @@ -717,7 +717,7 @@ void qmi_handle_release(struct qmi_handle *qmi) kfree(svc); } } -EXPORT_SYMBOL(qmi_handle_release); +EXPORT_SYMBOL_GPL(qmi_handle_release); /** * qmi_send_message() - send a QMI message @@ -796,7 +796,7 @@ ssize_t qmi_send_request(struct qmi_handle *qmi, struct sockaddr_qrtr *sq, return qmi_send_message(qmi, sq, txn, QMI_REQUEST, msg_id, len, ei, c_struct); } -EXPORT_SYMBOL(qmi_send_request); +EXPORT_SYMBOL_GPL(qmi_send_request); /** * qmi_send_response() - send a response QMI message @@ -817,7 +817,7 @@ ssize_t qmi_send_response(struct qmi_handle *qmi, struct sockaddr_qrtr *sq, return qmi_send_message(qmi, sq, txn, QMI_RESPONSE, msg_id, len, ei, c_struct); } -EXPORT_SYMBOL(qmi_send_response); +EXPORT_SYMBOL_GPL(qmi_send_response); /** * qmi_send_indication() - send an indication QMI message @@ -851,4 +851,4 @@ ssize_t qmi_send_indication(struct qmi_handle *qmi, struct sockaddr_qrtr *sq, return rval; } -EXPORT_SYMBOL(qmi_send_indication); +EXPORT_SYMBOL_GPL(qmi_send_indication); diff --git a/drivers/soc/qcom/rmtfs_mem.c b/drivers/soc/qcom/rmtfs_mem.c index f83811f51175..df850d073102 100644 --- a/drivers/soc/qcom/rmtfs_mem.c +++ b/drivers/soc/qcom/rmtfs_mem.c @@ -200,6 +200,15 @@ static int qcom_rmtfs_mem_probe(struct platform_device *pdev) rmtfs_mem->client_id = client_id; rmtfs_mem->size = rmem->size; + /* + * If requested, discard the first and last 4k block in order to ensure + * that the rmtfs region isn't adjacent to other protected regions. + */ + if (of_property_read_bool(node, "qcom,use-guard-pages")) { + rmtfs_mem->addr += SZ_4K; + rmtfs_mem->size -= 2 * SZ_4K; + } + device_initialize(&rmtfs_mem->dev); rmtfs_mem->dev.parent = &pdev->dev; rmtfs_mem->dev.groups = qcom_rmtfs_mem_groups; @@ -281,7 +290,7 @@ put_device: return ret; } -static int qcom_rmtfs_mem_remove(struct platform_device *pdev) +static void qcom_rmtfs_mem_remove(struct platform_device *pdev) { struct qcom_rmtfs_mem *rmtfs_mem = dev_get_drvdata(&pdev->dev); struct qcom_scm_vmperm perm; @@ -296,8 +305,6 @@ static int qcom_rmtfs_mem_remove(struct platform_device *pdev) cdev_device_del(&rmtfs_mem->cdev, &rmtfs_mem->dev); put_device(&rmtfs_mem->dev); - - return 0; } static const struct of_device_id qcom_rmtfs_mem_of_match[] = { @@ -308,7 +315,7 @@ MODULE_DEVICE_TABLE(of, qcom_rmtfs_mem_of_match); static struct platform_driver qcom_rmtfs_mem_driver = { .probe = qcom_rmtfs_mem_probe, - .remove = qcom_rmtfs_mem_remove, + .remove_new = qcom_rmtfs_mem_remove, .driver = { .name = "qcom_rmtfs_mem", .of_match_table = qcom_rmtfs_mem_of_match, diff --git a/drivers/soc/qcom/rpmh.c b/drivers/soc/qcom/rpmh.c index 08e09642d7f5..9f26d7f9b9dc 100644 --- a/drivers/soc/qcom/rpmh.c +++ b/drivers/soc/qcom/rpmh.c @@ -239,7 +239,7 @@ int rpmh_write_async(const struct device *dev, enum rpmh_state state, return __rpmh_write(dev, state, rpm_msg); } -EXPORT_SYMBOL(rpmh_write_async); +EXPORT_SYMBOL_GPL(rpmh_write_async); /** * rpmh_write: Write a set of RPMH commands and block until response @@ -270,7 +270,7 @@ int rpmh_write(const struct device *dev, enum rpmh_state state, WARN_ON(!ret); return (ret > 0) ? 0 : -ETIMEDOUT; } -EXPORT_SYMBOL(rpmh_write); +EXPORT_SYMBOL_GPL(rpmh_write); static void cache_batch(struct rpmh_ctrlr *ctrlr, struct batch_cache_req *req) { @@ -395,7 +395,7 @@ exit: return ret; } -EXPORT_SYMBOL(rpmh_write_batch); +EXPORT_SYMBOL_GPL(rpmh_write_batch); static int is_req_valid(struct cache_req *req) { @@ -500,4 +500,4 @@ void rpmh_invalidate(const struct device *dev) ctrlr->dirty = true; spin_unlock_irqrestore(&ctrlr->cache_lock, flags); } -EXPORT_SYMBOL(rpmh_invalidate); +EXPORT_SYMBOL_GPL(rpmh_invalidate); diff --git a/drivers/soc/qcom/smd-rpm.c b/drivers/soc/qcom/smd-rpm.c index f9fd6177118c..b7056aed4c7d 100644 --- a/drivers/soc/qcom/smd-rpm.c +++ b/drivers/soc/qcom/smd-rpm.c @@ -142,7 +142,7 @@ out: mutex_unlock(&rpm->lock); return ret; } -EXPORT_SYMBOL(qcom_rpm_smd_write); +EXPORT_SYMBOL_GPL(qcom_rpm_smd_write); static int qcom_smd_rpm_callback(struct rpmsg_device *rpdev, void *data, diff --git a/drivers/soc/qcom/smem.c b/drivers/soc/qcom/smem.c index d4a89d2bb43b..690afc9a12f4 100644 --- a/drivers/soc/qcom/smem.c +++ b/drivers/soc/qcom/smem.c @@ -285,7 +285,7 @@ struct qcom_smem { struct smem_partition partitions[SMEM_HOST_COUNT]; unsigned num_regions; - struct smem_region regions[]; + struct smem_region regions[] __counted_by(num_regions); }; static void * @@ -368,7 +368,7 @@ bool qcom_smem_is_available(void) { return !!__smem; } -EXPORT_SYMBOL(qcom_smem_is_available); +EXPORT_SYMBOL_GPL(qcom_smem_is_available); static int qcom_smem_alloc_private(struct qcom_smem *smem, struct smem_partition *part, @@ -1187,14 +1187,12 @@ static int qcom_smem_probe(struct platform_device *pdev) return 0; } -static int qcom_smem_remove(struct platform_device *pdev) +static void qcom_smem_remove(struct platform_device *pdev) { platform_device_unregister(__smem->socinfo); hwspin_lock_free(__smem->hwlock); __smem = NULL; - - return 0; } static const struct of_device_id qcom_smem_of_match[] = { @@ -1205,7 +1203,7 @@ MODULE_DEVICE_TABLE(of, qcom_smem_of_match); static struct platform_driver qcom_smem_driver = { .probe = qcom_smem_probe, - .remove = qcom_smem_remove, + .remove_new = qcom_smem_remove, .driver = { .name = "qcom-smem", .of_match_table = qcom_smem_of_match, diff --git a/drivers/soc/qcom/smp2p.c b/drivers/soc/qcom/smp2p.c index e9c8030d50ee..914b2246148f 100644 --- a/drivers/soc/qcom/smp2p.c +++ b/drivers/soc/qcom/smp2p.c @@ -660,7 +660,7 @@ report_read_failure: return -EINVAL; } -static int qcom_smp2p_remove(struct platform_device *pdev) +static void qcom_smp2p_remove(struct platform_device *pdev) { struct qcom_smp2p *smp2p = platform_get_drvdata(pdev); struct smp2p_entry *entry; @@ -676,8 +676,6 @@ static int qcom_smp2p_remove(struct platform_device *pdev) mbox_free_channel(smp2p->mbox_chan); smp2p->out->valid_entries = 0; - - return 0; } static const struct of_device_id qcom_smp2p_of_match[] = { @@ -688,7 +686,7 @@ MODULE_DEVICE_TABLE(of, qcom_smp2p_of_match); static struct platform_driver qcom_smp2p_driver = { .probe = qcom_smp2p_probe, - .remove = qcom_smp2p_remove, + .remove_new = qcom_smp2p_remove, .driver = { .name = "qcom_smp2p", .of_match_table = qcom_smp2p_of_match, diff --git a/drivers/soc/qcom/smsm.c b/drivers/soc/qcom/smsm.c index c58cfff64856..e7c7e9a640a6 100644 --- a/drivers/soc/qcom/smsm.c +++ b/drivers/soc/qcom/smsm.c @@ -613,7 +613,7 @@ out_put: return ret; } -static int qcom_smsm_remove(struct platform_device *pdev) +static void qcom_smsm_remove(struct platform_device *pdev) { struct qcom_smsm *smsm = platform_get_drvdata(pdev); unsigned id; @@ -623,8 +623,6 @@ static int qcom_smsm_remove(struct platform_device *pdev) irq_domain_remove(smsm->entries[id].domain); qcom_smem_state_unregister(smsm->state); - - return 0; } static const struct of_device_id qcom_smsm_of_match[] = { @@ -635,7 +633,7 @@ MODULE_DEVICE_TABLE(of, qcom_smsm_of_match); static struct platform_driver qcom_smsm_driver = { .probe = qcom_smsm_probe, - .remove = qcom_smsm_remove, + .remove_new = qcom_smsm_remove, .driver = { .name = "qcom-smsm", .of_match_table = qcom_smsm_of_match, diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c index 497cfb720fcb..51e05bec5bfc 100644 --- a/drivers/soc/qcom/socinfo.c +++ b/drivers/soc/qcom/socinfo.c @@ -117,6 +117,12 @@ static const char *const pmic_models[] = { [55] = "PM2250", [58] = "PM8450", [65] = "PM8010", + [69] = "PM8550VS", + [70] = "PM8550VE", + [71] = "PM8550B", + [72] = "PMR735D", + [73] = "PM8550", + [74] = "PMK8550", }; struct socinfo_params { @@ -349,6 +355,7 @@ static const struct soc_id soc_id[] = { { qcom_board_id(SDA439) }, { qcom_board_id(SDA429) }, { qcom_board_id(SM7150) }, + { qcom_board_id(SM7150P) }, { qcom_board_id(IPQ8070) }, { qcom_board_id(IPQ8071) }, { qcom_board_id(QM215) }, @@ -359,6 +366,9 @@ static const struct soc_id soc_id[] = { { qcom_board_id(SM6125) }, { qcom_board_id(IPQ8070A) }, { qcom_board_id(IPQ8071A) }, + { qcom_board_id(IPQ8172) }, + { qcom_board_id(IPQ8173) }, + { qcom_board_id(IPQ8174) }, { qcom_board_id(IPQ6018) }, { qcom_board_id(IPQ6028) }, { qcom_board_id(SDM429W) }, @@ -389,6 +399,7 @@ static const struct soc_id soc_id[] = { { qcom_board_id_named(SM8450_3, "SM8450") }, { qcom_board_id(SC7280) }, { qcom_board_id(SC7180P) }, + { qcom_board_id(QCM6490) }, { qcom_board_id(IPQ5000) }, { qcom_board_id(IPQ0509) }, { qcom_board_id(IPQ0518) }, @@ -776,20 +787,18 @@ static int qcom_socinfo_probe(struct platform_device *pdev) return 0; } -static int qcom_socinfo_remove(struct platform_device *pdev) +static void qcom_socinfo_remove(struct platform_device *pdev) { struct qcom_socinfo *qs = platform_get_drvdata(pdev); soc_device_unregister(qs->soc_dev); socinfo_debugfs_exit(qs); - - return 0; } static struct platform_driver qcom_socinfo_driver = { .probe = qcom_socinfo_probe, - .remove = qcom_socinfo_remove, + .remove_new = qcom_socinfo_remove, .driver = { .name = "qcom-socinfo", }, diff --git a/drivers/soc/qcom/wcnss_ctrl.c b/drivers/soc/qcom/wcnss_ctrl.c index ad9942412c58..148bcbac332d 100644 --- a/drivers/soc/qcom/wcnss_ctrl.c +++ b/drivers/soc/qcom/wcnss_ctrl.c @@ -287,7 +287,7 @@ struct rpmsg_endpoint *qcom_wcnss_open_channel(void *wcnss, const char *name, rp return rpmsg_create_ept(_wcnss->channel->rpdev, cb, priv, chinfo); } -EXPORT_SYMBOL(qcom_wcnss_open_channel); +EXPORT_SYMBOL_GPL(qcom_wcnss_open_channel); static void wcnss_async_probe(struct work_struct *work) { @@ -355,7 +355,6 @@ static struct rpmsg_driver wcnss_ctrl_driver = { .callback = wcnss_ctrl_smd_callback, .drv = { .name = "qcom_wcnss_ctrl", - .owner = THIS_MODULE, .of_match_table = wcnss_ctrl_of_match, }, }; diff --git a/drivers/soc/renesas/Kconfig b/drivers/soc/renesas/Kconfig index 5a75ab64d1ed..309039710614 100644 --- a/drivers/soc/renesas/Kconfig +++ b/drivers/soc/renesas/Kconfig @@ -319,6 +319,12 @@ config ARCH_R9A07G054 help This enables support for the Renesas RZ/V2L SoC variants. +config ARCH_R9A08G045 + bool "ARM64 Platform support for RZ/G3S" + select ARCH_RZG2L + help + This enables support for the Renesas RZ/G3S SoC variants. + config ARCH_R9A09G011 bool "ARM64 Platform support for RZ/V2M" select PM @@ -338,7 +344,6 @@ config ARCH_R9A07G043 select DMA_GLOBAL_POOL select ERRATA_ANDES if RISCV_SBI select ERRATA_ANDES_CMO if ERRATA_ANDES - help This enables support for the Renesas RZ/Five SoC. diff --git a/drivers/soc/renesas/renesas-soc.c b/drivers/soc/renesas/renesas-soc.c index 42af7c09f743..c732d4a5b26a 100644 --- a/drivers/soc/renesas/renesas-soc.c +++ b/drivers/soc/renesas/renesas-soc.c @@ -12,7 +12,6 @@ #include <linux/string.h> #include <linux/sys_soc.h> - struct renesas_family { const char name[16]; u32 reg; /* CCCR or PRR, if not in DT */ @@ -72,6 +71,10 @@ static const struct renesas_family fam_rzg2ul __initconst __maybe_unused = { .name = "RZ/G2UL", }; +static const struct renesas_family fam_rzg3s __initconst __maybe_unused = { + .name = "RZ/G3S", +}; + static const struct renesas_family fam_rzv2l __initconst __maybe_unused = { .name = "RZ/V2L", }; @@ -85,7 +88,6 @@ static const struct renesas_family fam_shmobile __initconst __maybe_unused = { .reg = 0xe600101c, /* CCCR (Common Chip Code Register) */ }; - struct renesas_soc { const struct renesas_family *family; u32 id; @@ -170,6 +172,11 @@ static const struct renesas_soc soc_rz_g2ul __initconst __maybe_unused = { .id = 0x8450447, }; +static const struct renesas_soc soc_rz_g3s __initconst __maybe_unused = { + .family = &fam_rzg3s, + .id = 0x85e0447, +}; + static const struct renesas_soc soc_rz_v2l __initconst __maybe_unused = { .family = &fam_rzv2l, .id = 0x8447447, @@ -386,6 +393,9 @@ static const struct of_device_id renesas_socs[] __initconst __maybe_unused = { #ifdef CONFIG_ARCH_R9A07G054 { .compatible = "renesas,r9a07g054", .data = &soc_rz_v2l }, #endif +#ifdef CONFIG_ARCH_R9A08G045 + { .compatible = "renesas,r9a08g045", .data = &soc_rz_g3s }, +#endif #ifdef CONFIG_ARCH_R9A09G011 { .compatible = "renesas,r9a09g011", .data = &soc_rz_v2m }, #endif @@ -429,6 +439,7 @@ static const struct of_device_id renesas_ids[] __initconst = { { .compatible = "renesas,r9a07g043-sysc", .data = &id_rzg2l }, { .compatible = "renesas,r9a07g044-sysc", .data = &id_rzg2l }, { .compatible = "renesas,r9a07g054-sysc", .data = &id_rzg2l }, + { .compatible = "renesas,r9a08g045-sysc", .data = &id_rzg2l }, { .compatible = "renesas,r9a09g011-sys", .data = &id_rzv2m }, { .compatible = "renesas,prr", .data = &id_prr }, { /* sentinel */ } diff --git a/drivers/soc/rockchip/io-domain.c b/drivers/soc/rockchip/io-domain.c index 6619256c2d11..18f809c160a7 100644 --- a/drivers/soc/rockchip/io-domain.c +++ b/drivers/soc/rockchip/io-domain.c @@ -687,7 +687,7 @@ unreg_notify: return ret; } -static int rockchip_iodomain_remove(struct platform_device *pdev) +static void rockchip_iodomain_remove(struct platform_device *pdev) { struct rockchip_iodomain *iod = platform_get_drvdata(pdev); int i; @@ -699,13 +699,11 @@ static int rockchip_iodomain_remove(struct platform_device *pdev) regulator_unregister_notifier(io_supply->reg, &io_supply->nb); } - - return 0; } static struct platform_driver rockchip_iodomain_driver = { .probe = rockchip_iodomain_probe, - .remove = rockchip_iodomain_remove, + .remove_new = rockchip_iodomain_remove, .driver = { .name = "rockchip-iodomain", .of_match_table = rockchip_iodomain_match, diff --git a/drivers/soc/samsung/exynos-chipid.c b/drivers/soc/samsung/exynos-chipid.c index 7ba45c4aff97..3fd0f2b84dd3 100644 --- a/drivers/soc/samsung/exynos-chipid.c +++ b/drivers/soc/samsung/exynos-chipid.c @@ -158,13 +158,11 @@ err: return ret; } -static int exynos_chipid_remove(struct platform_device *pdev) +static void exynos_chipid_remove(struct platform_device *pdev) { struct soc_device *soc_dev = platform_get_drvdata(pdev); soc_device_unregister(soc_dev); - - return 0; } static const struct exynos_chipid_variant exynos4210_chipid_drv_data = { @@ -197,7 +195,7 @@ static struct platform_driver exynos_chipid_driver = { .of_match_table = exynos_chipid_of_device_ids, }, .probe = exynos_chipid_probe, - .remove = exynos_chipid_remove, + .remove_new = exynos_chipid_remove, }; module_platform_driver(exynos_chipid_driver); diff --git a/drivers/soc/sifive/Kconfig b/drivers/soc/sifive/Kconfig index e86870be34c9..139884addc41 100644 --- a/drivers/soc/sifive/Kconfig +++ b/drivers/soc/sifive/Kconfig @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 -if SOC_SIFIVE || SOC_STARFIVE +if ARCH_SIFIVE || ARCH_STARFIVE config SIFIVE_CCACHE bool "Sifive Composable Cache controller" diff --git a/drivers/soc/tegra/cbb/tegra194-cbb.c b/drivers/soc/tegra/cbb/tegra194-cbb.c index cf6886f362d3..9cbc562ae7d3 100644 --- a/drivers/soc/tegra/cbb/tegra194-cbb.c +++ b/drivers/soc/tegra/cbb/tegra194-cbb.c @@ -2293,7 +2293,7 @@ static int tegra194_cbb_probe(struct platform_device *pdev) return tegra_cbb_register(&cbb->base); } -static int tegra194_cbb_remove(struct platform_device *pdev) +static void tegra194_cbb_remove(struct platform_device *pdev) { struct tegra194_cbb *cbb = platform_get_drvdata(pdev); struct tegra_cbb *noc, *tmp; @@ -2311,8 +2311,6 @@ static int tegra194_cbb_remove(struct platform_device *pdev) } spin_unlock_irqrestore(&cbb_lock, flags); - - return 0; } static int __maybe_unused tegra194_cbb_resume_noirq(struct device *dev) @@ -2332,7 +2330,7 @@ static const struct dev_pm_ops tegra194_cbb_pm = { static struct platform_driver tegra194_cbb_driver = { .probe = tegra194_cbb_probe, - .remove = tegra194_cbb_remove, + .remove_new = tegra194_cbb_remove, .driver = { .name = "tegra194-cbb", .of_match_table = of_match_ptr(tegra194_cbb_match), diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index 162f52456f65..f432aa022ace 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -1393,13 +1393,6 @@ tegra_pmc_core_pd_set_performance_state(struct generic_pm_domain *genpd, return 0; } -static unsigned int -tegra_pmc_core_pd_opp_to_performance_state(struct generic_pm_domain *genpd, - struct dev_pm_opp *opp) -{ - return dev_pm_opp_get_level(opp); -} - static int tegra_pmc_core_pd_add(struct tegra_pmc *pmc, struct device_node *np) { struct generic_pm_domain *genpd; @@ -1412,7 +1405,6 @@ static int tegra_pmc_core_pd_add(struct tegra_pmc *pmc, struct device_node *np) genpd->name = "core"; genpd->set_performance_state = tegra_pmc_core_pd_set_performance_state; - genpd->opp_to_performance_state = tegra_pmc_core_pd_opp_to_performance_state; err = devm_pm_opp_set_regulators(pmc->dev, rname); if (err) diff --git a/drivers/soc/ti/k3-ringacc.c b/drivers/soc/ti/k3-ringacc.c index 148f54d9691d..fd4251d75935 100644 --- a/drivers/soc/ti/k3-ringacc.c +++ b/drivers/soc/ti/k3-ringacc.c @@ -1551,19 +1551,18 @@ static int k3_ringacc_probe(struct platform_device *pdev) return 0; } -static int k3_ringacc_remove(struct platform_device *pdev) +static void k3_ringacc_remove(struct platform_device *pdev) { struct k3_ringacc *ringacc = dev_get_drvdata(&pdev->dev); mutex_lock(&k3_ringacc_list_lock); list_del(&ringacc->list); mutex_unlock(&k3_ringacc_list_lock); - return 0; } static struct platform_driver k3_ringacc_driver = { .probe = k3_ringacc_probe, - .remove = k3_ringacc_remove, + .remove_new = k3_ringacc_remove, .driver = { .name = "k3-ringacc", .of_match_table = k3_ringacc_of_match, diff --git a/drivers/soc/ti/k3-socinfo.c b/drivers/soc/ti/k3-socinfo.c index 6ea9b8c7d335..7fc3548e084c 100644 --- a/drivers/soc/ti/k3-socinfo.c +++ b/drivers/soc/ti/k3-socinfo.c @@ -20,7 +20,7 @@ * 31-28 VARIANT Device variant * 27-12 PARTNO Part number * 11-1 MFG Indicates TI as manufacturer (0x17) - * 1 Always 1 + * 0 Always 1 */ #define CTRLMMR_WKUP_JTAGID_VARIANT_SHIFT (28) #define CTRLMMR_WKUP_JTAGID_VARIANT_MASK GENMASK(31, 28) @@ -60,7 +60,7 @@ k3_chipinfo_partno_to_names(unsigned int partno, return 0; } - return -EINVAL; + return -ENODEV; } static int k3_chipinfo_probe(struct platform_device *pdev) @@ -111,8 +111,7 @@ static int k3_chipinfo_probe(struct platform_device *pdev) ret = k3_chipinfo_partno_to_names(partno_id, soc_dev_attr); if (ret) { - dev_err(dev, "Unknown SoC JTAGID[0x%08X]\n", jtag_id); - ret = -ENODEV; + dev_err(dev, "Unknown SoC JTAGID[0x%08X]: %d\n", jtag_id, ret); goto err_free_rev; } diff --git a/drivers/soc/ti/knav_dma.c b/drivers/soc/ti/knav_dma.c index 0fbc37cd5123..6023006685fc 100644 --- a/drivers/soc/ti/knav_dma.c +++ b/drivers/soc/ti/knav_dma.c @@ -773,7 +773,7 @@ err_pm_disable: return ret; } -static int knav_dma_remove(struct platform_device *pdev) +static void knav_dma_remove(struct platform_device *pdev) { struct knav_dma_device *dma; @@ -784,8 +784,6 @@ static int knav_dma_remove(struct platform_device *pdev) pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); - - return 0; } static struct of_device_id of_match[] = { @@ -797,7 +795,7 @@ MODULE_DEVICE_TABLE(of, of_match); static struct platform_driver knav_dma_driver = { .probe = knav_dma_probe, - .remove = knav_dma_remove, + .remove_new = knav_dma_remove, .driver = { .name = "keystone-navigator-dma", .of_match_table = of_match, diff --git a/drivers/soc/ti/knav_qmss_queue.c b/drivers/soc/ti/knav_qmss_queue.c index 0f252c2549ba..06fb5505c22c 100644 --- a/drivers/soc/ti/knav_qmss_queue.c +++ b/drivers/soc/ti/knav_qmss_queue.c @@ -14,10 +14,12 @@ #include <linux/interrupt.h> #include <linux/io.h> #include <linux/module.h> +#include <linux/of.h> #include <linux/of_address.h> -#include <linux/of_device.h> #include <linux/of_irq.h> +#include <linux/platform_device.h> #include <linux/pm_runtime.h> +#include <linux/property.h> #include <linux/slab.h> #include <linux/soc/ti/knav_qmss.h> @@ -1754,7 +1756,6 @@ static int knav_queue_probe(struct platform_device *pdev) { struct device_node *node = pdev->dev.of_node; struct device_node *qmgrs, *queue_pools, *regions, *pdsps; - const struct of_device_id *match; struct device *dev = &pdev->dev; u32 temp[2]; int ret; @@ -1770,8 +1771,7 @@ static int knav_queue_probe(struct platform_device *pdev) return -ENOMEM; } - match = of_match_device(of_match_ptr(keystone_qmss_of_match), dev); - if (match && match->data) + if (device_get_match_data(dev)) kdev->version = QMSS_66AK2G; platform_set_drvdata(pdev, kdev); @@ -1884,17 +1884,16 @@ err: return ret; } -static int knav_queue_remove(struct platform_device *pdev) +static void knav_queue_remove(struct platform_device *pdev) { /* TODO: Free resources */ pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); - return 0; } static struct platform_driver keystone_qmss_driver = { .probe = knav_queue_probe, - .remove = knav_queue_remove, + .remove_new = knav_queue_remove, .driver = { .name = "keystone-navigator-qmss", .of_match_table = keystone_qmss_of_match, diff --git a/drivers/soc/ti/pm33xx.c b/drivers/soc/ti/pm33xx.c index f04c21157904..8e983c3c4e03 100644 --- a/drivers/soc/ti/pm33xx.c +++ b/drivers/soc/ti/pm33xx.c @@ -583,7 +583,7 @@ err_wkup_m3_ipc_put: return ret; } -static int am33xx_pm_remove(struct platform_device *pdev) +static void am33xx_pm_remove(struct platform_device *pdev) { pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); @@ -594,7 +594,6 @@ static int am33xx_pm_remove(struct platform_device *pdev) am33xx_pm_free_sram(); iounmap(rtc_base_virt); clk_put(rtc_fck); - return 0; } static struct platform_driver am33xx_pm_driver = { @@ -602,7 +601,7 @@ static struct platform_driver am33xx_pm_driver = { .name = "pm33xx", }, .probe = am33xx_pm_probe, - .remove = am33xx_pm_remove, + .remove_new = am33xx_pm_remove, }; module_platform_driver(am33xx_pm_driver); diff --git a/drivers/soc/ti/pruss.c b/drivers/soc/ti/pruss.c index f49f8492dde5..24a42e0b645c 100644 --- a/drivers/soc/ti/pruss.c +++ b/drivers/soc/ti/pruss.c @@ -565,7 +565,7 @@ rpm_disable: return ret; } -static int pruss_remove(struct platform_device *pdev) +static void pruss_remove(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -573,8 +573,6 @@ static int pruss_remove(struct platform_device *pdev) pm_runtime_put_sync(dev); pm_runtime_disable(dev); - - return 0; } /* instance-specific driver private data */ @@ -610,7 +608,7 @@ static struct platform_driver pruss_driver = { .of_match_table = pruss_of_match, }, .probe = pruss_probe, - .remove = pruss_remove, + .remove_new = pruss_remove, }; module_platform_driver(pruss_driver); diff --git a/drivers/soc/ti/smartreflex.c b/drivers/soc/ti/smartreflex.c index 62b2f1464e46..d6219060b616 100644 --- a/drivers/soc/ti/smartreflex.c +++ b/drivers/soc/ti/smartreflex.c @@ -933,7 +933,7 @@ err_list_del: return ret; } -static int omap_sr_remove(struct platform_device *pdev) +static void omap_sr_remove(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct omap_sr *sr_info = platform_get_drvdata(pdev); @@ -945,7 +945,6 @@ static int omap_sr_remove(struct platform_device *pdev) pm_runtime_disable(dev); clk_unprepare(sr_info->fck); list_del(&sr_info->node); - return 0; } static void omap_sr_shutdown(struct platform_device *pdev) @@ -970,7 +969,7 @@ MODULE_DEVICE_TABLE(of, omap_sr_match); static struct platform_driver smartreflex_driver = { .probe = omap_sr_probe, - .remove = omap_sr_remove, + .remove_new = omap_sr_remove, .shutdown = omap_sr_shutdown, .driver = { .name = DRIVER_NAME, diff --git a/drivers/soc/ti/wkup_m3_ipc.c b/drivers/soc/ti/wkup_m3_ipc.c index 3aff106fc11a..6a1c6b34c414 100644 --- a/drivers/soc/ti/wkup_m3_ipc.c +++ b/drivers/soc/ti/wkup_m3_ipc.c @@ -713,7 +713,7 @@ err_free_mbox: return ret; } -static int wkup_m3_ipc_remove(struct platform_device *pdev) +static void wkup_m3_ipc_remove(struct platform_device *pdev) { wkup_m3_ipc_dbg_destroy(m3_ipc_state); @@ -723,8 +723,6 @@ static int wkup_m3_ipc_remove(struct platform_device *pdev) rproc_put(m3_ipc_state->rproc); m3_ipc_state = NULL; - - return 0; } static int __maybe_unused wkup_m3_ipc_suspend(struct device *dev) @@ -760,7 +758,7 @@ MODULE_DEVICE_TABLE(of, wkup_m3_ipc_of_match); static struct platform_driver wkup_m3_ipc_driver = { .probe = wkup_m3_ipc_probe, - .remove = wkup_m3_ipc_remove, + .remove_new = wkup_m3_ipc_remove, .driver = { .name = "wkup_m3_ipc", .of_match_table = wkup_m3_ipc_of_match, diff --git a/drivers/spi/spi-cs42l43.c b/drivers/spi/spi-cs42l43.c index 453a9b37ce78..d239fc5a49cc 100644 --- a/drivers/spi/spi-cs42l43.c +++ b/drivers/spi/spi-cs42l43.c @@ -256,7 +256,6 @@ static int cs42l43_spi_probe(struct platform_device *pdev) ret = devm_spi_register_controller(priv->dev, priv->ctlr); if (ret) { - pm_runtime_disable(priv->dev); dev_err(priv->dev, "Failed to register SPI controller: %d\n", ret); } diff --git a/drivers/spi/spi-gxp.c b/drivers/spi/spi-gxp.c index fd2fac236bbd..3aff5a166c94 100644 --- a/drivers/spi/spi-gxp.c +++ b/drivers/spi/spi-gxp.c @@ -194,7 +194,7 @@ static ssize_t gxp_spi_write(struct gxp_spi_chip *chip, const struct spi_mem_op return ret; } - return write_len; + return 0; } static int do_gxp_exec_mem_op(struct spi_mem *mem, const struct spi_mem_op *op) diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c index a8a74c7cb79f..498e35c8db2c 100644 --- a/drivers/spi/spi-imx.c +++ b/drivers/spi/spi-imx.c @@ -662,7 +662,7 @@ static int mx51_ecspi_prepare_transfer(struct spi_imx_data *spi_imx, if (spi_imx->count >= 512) ctrl |= 0xFFF << MX51_ECSPI_CTRL_BL_OFFSET; else - ctrl |= (spi_imx->count*8 - 1) + ctrl |= (spi_imx->count * spi_imx->bits_per_word - 1) << MX51_ECSPI_CTRL_BL_OFFSET; } diff --git a/drivers/spi/spi-intel-pci.c b/drivers/spi/spi-intel-pci.c index a7381e774b95..57d767a68e7b 100644 --- a/drivers/spi/spi-intel-pci.c +++ b/drivers/spi/spi-intel-pci.c @@ -72,6 +72,7 @@ static const struct pci_device_id intel_spi_pci_ids[] = { { PCI_VDEVICE(INTEL, 0x4da4), (unsigned long)&bxt_info }, { PCI_VDEVICE(INTEL, 0x51a4), (unsigned long)&cnl_info }, { PCI_VDEVICE(INTEL, 0x54a4), (unsigned long)&cnl_info }, + { PCI_VDEVICE(INTEL, 0x5794), (unsigned long)&cnl_info }, { PCI_VDEVICE(INTEL, 0x7a24), (unsigned long)&cnl_info }, { PCI_VDEVICE(INTEL, 0x7aa4), (unsigned long)&cnl_info }, { PCI_VDEVICE(INTEL, 0x7e23), (unsigned long)&cnl_info }, diff --git a/drivers/spi/spi-nxp-fspi.c b/drivers/spi/spi-nxp-fspi.c index 45a4acc95661..c964f41dcc42 100644 --- a/drivers/spi/spi-nxp-fspi.c +++ b/drivers/spi/spi-nxp-fspi.c @@ -1084,6 +1084,13 @@ static int nxp_fspi_default_setup(struct nxp_fspi *f) fspi_writel(f, FSPI_AHBCR_PREF_EN | FSPI_AHBCR_RDADDROPT, base + FSPI_AHBCR); + /* Reset the FLSHxCR1 registers. */ + reg = FSPI_FLSHXCR1_TCSH(0x3) | FSPI_FLSHXCR1_TCSS(0x3); + fspi_writel(f, reg, base + FSPI_FLSHA1CR1); + fspi_writel(f, reg, base + FSPI_FLSHA2CR1); + fspi_writel(f, reg, base + FSPI_FLSHB1CR1); + fspi_writel(f, reg, base + FSPI_FLSHB2CR1); + /* AHB Read - Set lut sequence ID for all CS. */ fspi_writel(f, SEQID_LUT, base + FSPI_FLSHA1CR2); fspi_writel(f, SEQID_LUT, base + FSPI_FLSHA2CR2); diff --git a/drivers/spi/spi-stm32.c b/drivers/spi/spi-stm32.c index b6d66caba4c0..ef665f470c5b 100644 --- a/drivers/spi/spi-stm32.c +++ b/drivers/spi/spi-stm32.c @@ -277,6 +277,7 @@ struct stm32_spi_cfg { * @fifo_size: size of the embedded fifo in bytes * @cur_midi: master inter-data idleness in ns * @cur_speed: speed configured in Hz + * @cur_half_period: time of a half bit in us * @cur_bpw: number of bits in a single SPI data frame * @cur_fthlv: fifo threshold level (data frames in a single data packet) * @cur_comm: SPI communication mode @@ -304,6 +305,7 @@ struct stm32_spi { unsigned int cur_midi; unsigned int cur_speed; + unsigned int cur_half_period; unsigned int cur_bpw; unsigned int cur_fthlv; unsigned int cur_comm; @@ -468,6 +470,8 @@ static int stm32_spi_prepare_mbr(struct stm32_spi *spi, u32 speed_hz, spi->cur_speed = spi->clk_rate / (1 << mbrdiv); + spi->cur_half_period = DIV_ROUND_CLOSEST(USEC_PER_SEC, 2 * spi->cur_speed); + return mbrdiv - 1; } @@ -709,6 +713,10 @@ static void stm32h7_spi_disable(struct stm32_spi *spi) return; } + /* Add a delay to make sure that transmission is ended. */ + if (spi->cur_half_period) + udelay(spi->cur_half_period); + if (spi->cur_usedma && spi->dma_tx) dmaengine_terminate_async(spi->dma_tx); if (spi->cur_usedma && spi->dma_rx) diff --git a/drivers/spi/spi-zynqmp-gqspi.c b/drivers/spi/spi-zynqmp-gqspi.c index 94d9a33d9af5..9a46b2478f4e 100644 --- a/drivers/spi/spi-zynqmp-gqspi.c +++ b/drivers/spi/spi-zynqmp-gqspi.c @@ -1340,9 +1340,9 @@ static int zynqmp_qspi_probe(struct platform_device *pdev) return 0; clk_dis_all: - pm_runtime_put_sync(&pdev->dev); - pm_runtime_set_suspended(&pdev->dev); pm_runtime_disable(&pdev->dev); + pm_runtime_put_noidle(&pdev->dev); + pm_runtime_set_suspended(&pdev->dev); clk_disable_unprepare(xqspi->refclk); clk_dis_pclk: clk_disable_unprepare(xqspi->pclk); @@ -1366,11 +1366,15 @@ static void zynqmp_qspi_remove(struct platform_device *pdev) { struct zynqmp_qspi *xqspi = platform_get_drvdata(pdev); + pm_runtime_get_sync(&pdev->dev); + zynqmp_gqspi_write(xqspi, GQSPI_EN_OFST, 0x0); + + pm_runtime_disable(&pdev->dev); + pm_runtime_put_noidle(&pdev->dev); + pm_runtime_set_suspended(&pdev->dev); clk_disable_unprepare(xqspi->refclk); clk_disable_unprepare(xqspi->pclk); - pm_runtime_set_suspended(&pdev->dev); - pm_runtime_disable(&pdev->dev); } MODULE_DEVICE_TABLE(of, zynqmp_qspi_of_match); diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index 936e5ff1b209..d5860c1c1f46 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -1392,16 +1392,16 @@ static ssize_t target_wwn_vendor_id_store(struct config_item *item, /* +2 to allow for a trailing (stripped) '\n' and null-terminator */ unsigned char buf[INQUIRY_VENDOR_LEN + 2]; char *stripped = NULL; - size_t len; + ssize_t len; ssize_t ret; - len = strlcpy(buf, page, sizeof(buf)); - if (len < sizeof(buf)) { + len = strscpy(buf, page, sizeof(buf)); + if (len > 0) { /* Strip any newline added from userspace. */ stripped = strstrip(buf); len = strlen(stripped); } - if (len > INQUIRY_VENDOR_LEN) { + if (len < 0 || len > INQUIRY_VENDOR_LEN) { pr_err("Emulated T10 Vendor Identification exceeds" " INQUIRY_VENDOR_LEN: " __stringify(INQUIRY_VENDOR_LEN) "\n"); @@ -1448,16 +1448,16 @@ static ssize_t target_wwn_product_id_store(struct config_item *item, /* +2 to allow for a trailing (stripped) '\n' and null-terminator */ unsigned char buf[INQUIRY_MODEL_LEN + 2]; char *stripped = NULL; - size_t len; + ssize_t len; ssize_t ret; - len = strlcpy(buf, page, sizeof(buf)); - if (len < sizeof(buf)) { + len = strscpy(buf, page, sizeof(buf)); + if (len > 0) { /* Strip any newline added from userspace. */ stripped = strstrip(buf); len = strlen(stripped); } - if (len > INQUIRY_MODEL_LEN) { + if (len < 0 || len > INQUIRY_MODEL_LEN) { pr_err("Emulated T10 Vendor exceeds INQUIRY_MODEL_LEN: " __stringify(INQUIRY_MODEL_LEN) "\n"); @@ -1504,16 +1504,16 @@ static ssize_t target_wwn_revision_store(struct config_item *item, /* +2 to allow for a trailing (stripped) '\n' and null-terminator */ unsigned char buf[INQUIRY_REVISION_LEN + 2]; char *stripped = NULL; - size_t len; + ssize_t len; ssize_t ret; - len = strlcpy(buf, page, sizeof(buf)); - if (len < sizeof(buf)) { + len = strscpy(buf, page, sizeof(buf)); + if (len > 0) { /* Strip any newline added from userspace. */ stripped = strstrip(buf); len = strlen(stripped); } - if (len > INQUIRY_REVISION_LEN) { + if (len < 0 || len > INQUIRY_REVISION_LEN) { pr_err("Emulated T10 Revision exceeds INQUIRY_REVISION_LEN: " __stringify(INQUIRY_REVISION_LEN) "\n"); diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 687adc9e086c..0686882bcbda 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -264,6 +264,7 @@ void target_free_cmd_counter(struct target_cmd_counter *cmd_cnt) percpu_ref_put(&cmd_cnt->refcnt); percpu_ref_exit(&cmd_cnt->refcnt); + kfree(cmd_cnt); } EXPORT_SYMBOL_GPL(target_free_cmd_counter); diff --git a/drivers/tee/optee/optee_private.h b/drivers/tee/optee/optee_private.h index 72685ee0d53f..6bb5cae09688 100644 --- a/drivers/tee/optee/optee_private.h +++ b/drivers/tee/optee/optee_private.h @@ -238,8 +238,6 @@ int optee_notif_send(struct optee *optee, u_int key); u32 optee_supp_thrd_req(struct tee_context *ctx, u32 func, size_t num_params, struct tee_param *param); -int optee_supp_read(struct tee_context *ctx, void __user *buf, size_t len); -int optee_supp_write(struct tee_context *ctx, void __user *buf, size_t len); void optee_supp_init(struct optee_supp *supp); void optee_supp_uninit(struct optee_supp *supp); void optee_supp_release(struct optee_supp *supp); diff --git a/drivers/tee/tee_private.h b/drivers/tee/tee_private.h index 409cadcc1cff..754e11dcb240 100644 --- a/drivers/tee/tee_private.h +++ b/drivers/tee/tee_private.h @@ -47,8 +47,6 @@ struct tee_device { struct tee_shm_pool *pool; }; -int tee_shm_init(void); - int tee_shm_get_fd(struct tee_shm *shm); bool tee_device_get(struct tee_device *teedev); diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c index 8717a3343512..58533ea75cd9 100644 --- a/drivers/thermal/thermal_core.c +++ b/drivers/thermal/thermal_core.c @@ -348,12 +348,14 @@ static void handle_thermal_trip(struct thermal_zone_device *tz, int trip_id) struct thermal_trip trip; /* Ignore disabled trip points */ - if (test_bit(trip_id, &tz->trips_disabled) || - trip.temperature == THERMAL_TEMP_INVALID) + if (test_bit(trip_id, &tz->trips_disabled)) return; __thermal_zone_get_trip(tz, trip_id, &trip); + if (trip.temperature == THERMAL_TEMP_INVALID) + return; + if (tz->last_temperature != THERMAL_TEMP_INVALID) { if (tz->last_temperature < trip.temperature && tz->temperature >= trip.temperature) diff --git a/drivers/thermal/thermal_of.c b/drivers/thermal/thermal_of.c index 4ca905723429..1e0655b63259 100644 --- a/drivers/thermal/thermal_of.c +++ b/drivers/thermal/thermal_of.c @@ -37,8 +37,10 @@ static int of_find_trip_id(struct device_node *np, struct device_node *trip) */ for_each_child_of_node(trips, t) { - if (t == trip) + if (t == trip) { + of_node_put(t); goto out; + } i++; } @@ -401,8 +403,10 @@ static int thermal_of_for_each_cooling_maps(struct thermal_zone_device *tz, for_each_child_of_node(cm_np, child) { ret = thermal_of_for_each_cooling_device(tz_np, child, tz, cdev, action); - if (ret) + if (ret) { + of_node_put(child); break; + } } of_node_put(cm_np); diff --git a/drivers/thermal/thermal_sysfs.c b/drivers/thermal/thermal_sysfs.c index 6c20c9f90a05..4e6a97db894e 100644 --- a/drivers/thermal/thermal_sysfs.c +++ b/drivers/thermal/thermal_sysfs.c @@ -185,9 +185,6 @@ trip_point_hyst_store(struct device *dev, struct device_attribute *attr, if (sscanf(attr->attr.name, "trip_point_%d_hyst", &trip_id) != 1) return -EINVAL; - if (kstrtoint(buf, 10, &trip.hysteresis)) - return -EINVAL; - mutex_lock(&tz->lock); if (!device_is_registered(dev)) { @@ -198,7 +195,11 @@ trip_point_hyst_store(struct device *dev, struct device_attribute *attr, ret = __thermal_zone_get_trip(tz, trip_id, &trip); if (ret) goto unlock; - + + ret = kstrtoint(buf, 10, &trip.hysteresis); + if (ret) + goto unlock; + ret = thermal_zone_set_trip(tz, trip_id, &trip); unlock: mutex_unlock(&tz->lock); diff --git a/drivers/thermal/ti-soc-thermal/ti-thermal-common.c b/drivers/thermal/ti-soc-thermal/ti-thermal-common.c index 6ba2613627e1..0cf0826b805a 100644 --- a/drivers/thermal/ti-soc-thermal/ti-thermal-common.c +++ b/drivers/thermal/ti-soc-thermal/ti-thermal-common.c @@ -110,7 +110,8 @@ static inline int __ti_thermal_get_temp(struct thermal_zone_device *tz, int *tem } static int __ti_thermal_get_trend(struct thermal_zone_device *tz, - struct thermal_trip *trip, enum thermal_trend *trend) + const struct thermal_trip *trip, + enum thermal_trend *trend) { struct ti_thermal_data *data = thermal_zone_device_priv(tz); struct ti_bandgap *bgp; diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index b3550ff9c494..1f3aba607cd5 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -3097,10 +3097,8 @@ static void gsm_cleanup_mux(struct gsm_mux *gsm, bool disc) gsm->has_devices = false; } for (i = NUM_DLCI - 1; i >= 0; i--) - if (gsm->dlci[i]) { + if (gsm->dlci[i]) gsm_dlci_release(gsm->dlci[i]); - gsm->dlci[i] = NULL; - } mutex_unlock(&gsm->mutex); /* Now wipe the queues */ tty_ldisc_flush(gsm->tty); diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index fb891b67968f..141627370aab 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -1936,7 +1936,10 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir) skip_rx = true; if (status & (UART_LSR_DR | UART_LSR_BI) && !skip_rx) { - if (irqd_is_wakeup_set(irq_get_irq_data(port->irq))) + struct irq_data *d; + + d = irq_get_irq_data(port->irq); + if (d && irqd_is_wakeup_set(d)) pm_wakeup_event(tport->tty->dev, 0); if (!up->dma || handle_rx_dma(up, iir)) status = serial8250_rx_chars(up, status); diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 93417518c04d..c2df07545f96 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -22,6 +22,7 @@ #include <linux/module.h> #include <linux/regulator/consumer.h> #include <linux/sched/clock.h> +#include <linux/iopoll.h> #include <scsi/scsi_cmnd.h> #include <scsi/scsi_dbg.h> #include <scsi/scsi_driver.h> @@ -2299,7 +2300,11 @@ static inline int ufshcd_hba_capabilities(struct ufs_hba *hba) */ static inline bool ufshcd_ready_for_uic_cmd(struct ufs_hba *hba) { - return ufshcd_readl(hba, REG_CONTROLLER_STATUS) & UIC_COMMAND_READY; + u32 val; + int ret = read_poll_timeout(ufshcd_readl, val, val & UIC_COMMAND_READY, + 500, UIC_CMD_TIMEOUT * 1000, false, hba, + REG_CONTROLLER_STATUS); + return ret == 0 ? true : false; } /** @@ -2392,7 +2397,6 @@ __ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd, bool completion) { lockdep_assert_held(&hba->uic_cmd_mutex); - lockdep_assert_held(hba->host->host_lock); if (!ufshcd_ready_for_uic_cmd(hba)) { dev_err(hba->dev, @@ -2419,7 +2423,6 @@ __ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd, int ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd) { int ret; - unsigned long flags; if (hba->quirks & UFSHCD_QUIRK_BROKEN_UIC_CMD) return 0; @@ -2428,9 +2431,7 @@ int ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd) mutex_lock(&hba->uic_cmd_mutex); ufshcd_add_delay_before_dme_cmd(hba); - spin_lock_irqsave(hba->host->host_lock, flags); ret = __ufshcd_send_uic_cmd(hba, uic_cmd, true); - spin_unlock_irqrestore(hba->host->host_lock, flags); if (!ret) ret = ufshcd_wait_for_uic_cmd(hba, uic_cmd); @@ -4133,8 +4134,8 @@ static int ufshcd_uic_pwr_ctrl(struct ufs_hba *hba, struct uic_command *cmd) wmb(); reenable_intr = true; } - ret = __ufshcd_send_uic_cmd(hba, cmd, false); spin_unlock_irqrestore(hba->host->host_lock, flags); + ret = __ufshcd_send_uic_cmd(hba, cmd, false); if (ret) { dev_err(hba->dev, "pwr ctrl cmd 0x%x with mode 0x%x uic error %d\n", diff --git a/drivers/usb/typec/ucsi/debugfs.c b/drivers/usb/typec/ucsi/debugfs.c index 0c7bf88d4a7f..f67733cecfdf 100644 --- a/drivers/usb/typec/ucsi/debugfs.c +++ b/drivers/usb/typec/ucsi/debugfs.c @@ -84,6 +84,9 @@ void ucsi_debugfs_register(struct ucsi *ucsi) void ucsi_debugfs_unregister(struct ucsi *ucsi) { + if (IS_ERR_OR_NULL(ucsi) || !ucsi->debugfs) + return; + debugfs_remove_recursive(ucsi->debugfs->dentry); kfree(ucsi->debugfs); } diff --git a/drivers/vfio/mdev/mdev_sysfs.c b/drivers/vfio/mdev/mdev_sysfs.c index e4490639d383..9d2738e10c0b 100644 --- a/drivers/vfio/mdev/mdev_sysfs.c +++ b/drivers/vfio/mdev/mdev_sysfs.c @@ -233,7 +233,8 @@ int parent_create_sysfs_files(struct mdev_parent *parent) out_err: while (--i >= 0) mdev_type_remove(parent->types[i]); - return 0; + kset_unregister(parent->mdev_types_kset); + return ret; } static ssize_t remove_store(struct device *dev, struct device_attribute *attr, diff --git a/drivers/vfio/pci/pds/Kconfig b/drivers/vfio/pci/pds/Kconfig index 407b3fd32733..6eceef7b028a 100644 --- a/drivers/vfio/pci/pds/Kconfig +++ b/drivers/vfio/pci/pds/Kconfig @@ -3,7 +3,7 @@ config PDS_VFIO_PCI tristate "VFIO support for PDS PCI devices" - depends on PDS_CORE + depends on PDS_CORE && PCI_IOV select VFIO_PCI_CORE help This provides generic PCI support for PDS devices using the VFIO diff --git a/drivers/vfio/pci/pds/vfio_dev.c b/drivers/vfio/pci/pds/vfio_dev.c index b46174f5eb09..649b18ee394b 100644 --- a/drivers/vfio/pci/pds/vfio_dev.c +++ b/drivers/vfio/pci/pds/vfio_dev.c @@ -162,7 +162,7 @@ static int pds_vfio_init_device(struct vfio_device *vdev) pci_id = PCI_DEVID(pdev->bus->number, pdev->devfn); dev_dbg(&pdev->dev, "%s: PF %#04x VF %#04x vf_id %d domain %d pds_vfio %p\n", - __func__, pci_dev_id(pdev->physfn), pci_id, vf_id, + __func__, pci_dev_id(pci_physfn(pdev)), pci_id, vf_id, pci_domain_nr(pdev->bus), pds_vfio); return 0; diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig index 1b5a319971ed..30577b1d3de5 100644 --- a/drivers/video/console/Kconfig +++ b/drivers/video/console/Kconfig @@ -73,6 +73,7 @@ config DUMMY_CONSOLE_ROWS config FRAMEBUFFER_CONSOLE bool "Framebuffer Console support" depends on FB_CORE && !UML + default DRM_FBDEV_EMULATION select VT_HW_CONSOLE_BINDING select CRC32 select FONT_SUPPORT diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig index eac0ba39581e..c29754b65c0e 100644 --- a/drivers/video/fbdev/Kconfig +++ b/drivers/video/fbdev/Kconfig @@ -1762,7 +1762,7 @@ config FB_COBALT config FB_SH7760 bool "SH7760/SH7763/SH7720/SH7721 LCDC support" - depends on FB && (CPU_SUBTYPE_SH7760 || CPU_SUBTYPE_SH7763 \ + depends on FB=y && (CPU_SUBTYPE_SH7760 || CPU_SUBTYPE_SH7763 \ || CPU_SUBTYPE_SH7720 || CPU_SUBTYPE_SH7721) select FB_IOMEM_HELPERS help diff --git a/drivers/video/fbdev/core/Kconfig b/drivers/video/fbdev/core/Kconfig index baf7e852c75b..5ac1b0637531 100644 --- a/drivers/video/fbdev/core/Kconfig +++ b/drivers/video/fbdev/core/Kconfig @@ -28,7 +28,7 @@ config FIRMWARE_EDID config FB_DEVICE bool "Provide legacy /dev/fb* device" depends on FB_CORE - default y + default FB help Say Y here if you want the legacy /dev/fb* device file and interfaces within sysfs anc procfs. It is only required if you diff --git a/drivers/w1/masters/ds2482.c b/drivers/w1/masters/ds2482.c index c1de8a92e144..b2d76c1784bd 100644 --- a/drivers/w1/masters/ds2482.c +++ b/drivers/w1/masters/ds2482.c @@ -551,7 +551,7 @@ static struct i2c_driver ds2482_driver = { .driver = { .name = "ds2482", }, - .probe_new = ds2482_probe, + .probe = ds2482_probe, .remove = ds2482_remove, .id_table = ds2482_id, }; diff --git a/drivers/xen/events/events_base.c b/drivers/xen/events/events_base.c index 3bdd5b59661d..0bb86e6c4d0a 100644 --- a/drivers/xen/events/events_base.c +++ b/drivers/xen/events/events_base.c @@ -1704,7 +1704,7 @@ void handle_irq_for_port(evtchn_port_t port, struct evtchn_loop_ctrl *ctrl) generic_handle_irq(irq); } -static int __xen_evtchn_do_upcall(void) +int xen_evtchn_do_upcall(void) { struct vcpu_info *vcpu_info = __this_cpu_read(xen_vcpu); int ret = vcpu_info->evtchn_upcall_pending ? IRQ_HANDLED : IRQ_NONE; @@ -1735,24 +1735,7 @@ static int __xen_evtchn_do_upcall(void) return ret; } - -void xen_evtchn_do_upcall(struct pt_regs *regs) -{ - struct pt_regs *old_regs = set_irq_regs(regs); - - irq_enter(); - - __xen_evtchn_do_upcall(); - - irq_exit(); - set_irq_regs(old_regs); -} - -int xen_hvm_evtchn_do_upcall(void) -{ - return __xen_evtchn_do_upcall(); -} -EXPORT_SYMBOL_GPL(xen_hvm_evtchn_do_upcall); +EXPORT_SYMBOL_GPL(xen_evtchn_do_upcall); /* Rebind a new event channel to an existing irq. */ void rebind_evtchn_irq(evtchn_port_t evtchn, int irq) diff --git a/drivers/xen/platform-pci.c b/drivers/xen/platform-pci.c index fcc819131572..544d3f9010b9 100644 --- a/drivers/xen/platform-pci.c +++ b/drivers/xen/platform-pci.c @@ -64,7 +64,7 @@ static uint64_t get_callback_via(struct pci_dev *pdev) static irqreturn_t do_hvm_evtchn_intr(int irq, void *dev_id) { - return xen_hvm_evtchn_do_upcall(); + return xen_evtchn_do_upcall(); } static int xen_allocate_irq(struct pci_dev *pdev) |