diff options
Diffstat (limited to 'drivers')
292 files changed, 5663 insertions, 3404 deletions
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 4a46344bf0e3..dd1eea90f67f 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -3,6 +3,9 @@ # ACPI Configuration # +config ARCH_SUPPORTS_ACPI + bool + menuconfig ACPI bool "ACPI (Advanced Configuration and Power Interface) Support" depends on ARCH_SUPPORTS_ACPI @@ -40,9 +43,6 @@ menuconfig ACPI <http://www.acpi.info> <http://www.uefi.org/acpi/specs> -config ARCH_SUPPORTS_ACPI - bool - if ACPI config ACPI_LEGACY_TABLES_LOOKUP diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index b933061b6b60..8c0a54d50d0e 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -205,6 +205,7 @@ phys_cpuid_t acpi_get_phys_id(acpi_handle handle, int type, u32 acpi_id) return phys_id; } +EXPORT_SYMBOL_GPL(acpi_get_phys_id); int acpi_map_cpuid(phys_cpuid_t phys_id, u32 acpi_id) { diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index b2b9eba1d214..021ce46e2e57 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -610,7 +610,7 @@ static int marvell_enable = 1; module_param(marvell_enable, int, 0644); MODULE_PARM_DESC(marvell_enable, "Marvell SATA via AHCI (1 = enabled)"); -static int mobile_lpm_policy = CONFIG_SATA_MOBILE_LPM_POLICY; +static int mobile_lpm_policy = -1; module_param(mobile_lpm_policy, int, 0644); MODULE_PARM_DESC(mobile_lpm_policy, "Default LPM policy for mobile chipsets"); @@ -1604,6 +1604,37 @@ static int ahci_init_msi(struct pci_dev *pdev, unsigned int n_ports, return pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSIX); } +static void ahci_update_initial_lpm_policy(struct ata_port *ap, + struct ahci_host_priv *hpriv) +{ + int policy = CONFIG_SATA_MOBILE_LPM_POLICY; + + + /* Ignore processing for non mobile platforms */ + if (!(hpriv->flags & AHCI_HFLAG_IS_MOBILE)) + return; + + /* user modified policy via module param */ + if (mobile_lpm_policy != -1) { + policy = mobile_lpm_policy; + goto update_policy; + } + +#ifdef CONFIG_ACPI + if (policy > ATA_LPM_MED_POWER && + (acpi_gbl_FADT.flags & ACPI_FADT_LOW_POWER_S0)) { + if (hpriv->cap & HOST_CAP_PART) + policy = ATA_LPM_MIN_POWER_WITH_PARTIAL; + else if (hpriv->cap & HOST_CAP_SSC) + policy = ATA_LPM_MIN_POWER; + } +#endif + +update_policy: + if (policy >= ATA_LPM_UNKNOWN && policy <= ATA_LPM_MIN_POWER) + ap->target_lpm_policy = policy; +} + static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { unsigned int board_id = ent->driver_data; @@ -1807,10 +1838,7 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (ap->flags & ATA_FLAG_EM) ap->em_message_type = hpriv->em_msg_type; - if ((hpriv->flags & AHCI_HFLAG_IS_MOBILE) && - mobile_lpm_policy >= ATA_LPM_UNKNOWN && - mobile_lpm_policy <= ATA_LPM_MIN_POWER) - ap->target_lpm_policy = mobile_lpm_policy; + ahci_update_initial_lpm_policy(ap, hpriv); /* disabled/not-implemented port */ if (!(hpriv->port_map & (1 << i))) diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h index 1609ebab4e23..6a1515f0da40 100644 --- a/drivers/ata/ahci.h +++ b/drivers/ata/ahci.h @@ -350,6 +350,7 @@ struct ahci_host_priv { u32 em_msg_type; /* EM message type */ bool got_runtime_pm; /* Did we do pm_runtime_get? */ struct clk *clks[AHCI_MAX_CLKS]; /* Optional */ + struct reset_control *rsts; /* Optional */ struct regulator **target_pwrs; /* Optional */ /* * If platform uses PHYs. There is a 1:1 relation between the port number and diff --git a/drivers/ata/ahci_brcm.c b/drivers/ata/ahci_brcm.c index ea430819c80b..f3d557777d82 100644 --- a/drivers/ata/ahci_brcm.c +++ b/drivers/ata/ahci_brcm.c @@ -425,7 +425,7 @@ static int brcm_ahci_probe(struct platform_device *pdev) brcm_sata_phys_enable(priv); - hpriv = ahci_platform_get_resources(pdev); + hpriv = ahci_platform_get_resources(pdev, 0); if (IS_ERR(hpriv)) return PTR_ERR(hpriv); hpriv->plat_data = priv; diff --git a/drivers/ata/ahci_ceva.c b/drivers/ata/ahci_ceva.c index 5ecc9d46cb54..dc78c98cb9f1 100644 --- a/drivers/ata/ahci_ceva.c +++ b/drivers/ata/ahci_ceva.c @@ -213,7 +213,7 @@ static int ceva_ahci_probe(struct platform_device *pdev) cevapriv->ahci_pdev = pdev; - hpriv = ahci_platform_get_resources(pdev); + hpriv = ahci_platform_get_resources(pdev, 0); if (IS_ERR(hpriv)) return PTR_ERR(hpriv); diff --git a/drivers/ata/ahci_da850.c b/drivers/ata/ahci_da850.c index 9b34dff64536..ebaa657f28c4 100644 --- a/drivers/ata/ahci_da850.c +++ b/drivers/ata/ahci_da850.c @@ -171,7 +171,7 @@ static int ahci_da850_probe(struct platform_device *pdev) u32 mpy; int rc; - hpriv = ahci_platform_get_resources(pdev); + hpriv = ahci_platform_get_resources(pdev, 0); if (IS_ERR(hpriv)) return PTR_ERR(hpriv); diff --git a/drivers/ata/ahci_dm816.c b/drivers/ata/ahci_dm816.c index fbd827c3a75c..89509c3efb01 100644 --- a/drivers/ata/ahci_dm816.c +++ b/drivers/ata/ahci_dm816.c @@ -148,7 +148,7 @@ static int ahci_dm816_probe(struct platform_device *pdev) struct ahci_host_priv *hpriv; int rc; - hpriv = ahci_platform_get_resources(pdev); + hpriv = ahci_platform_get_resources(pdev, 0); if (IS_ERR(hpriv)) return PTR_ERR(hpriv); diff --git a/drivers/ata/ahci_imx.c b/drivers/ata/ahci_imx.c index 6822e2f33f7e..b00799d208f5 100644 --- a/drivers/ata/ahci_imx.c +++ b/drivers/ata/ahci_imx.c @@ -1127,7 +1127,7 @@ static int imx_ahci_probe(struct platform_device *pdev) return ret; } - hpriv = ahci_platform_get_resources(pdev); + hpriv = ahci_platform_get_resources(pdev, 0); if (IS_ERR(hpriv)) return PTR_ERR(hpriv); diff --git a/drivers/ata/ahci_mtk.c b/drivers/ata/ahci_mtk.c index 0ae6971c2a4c..8bc1a26ffc31 100644 --- a/drivers/ata/ahci_mtk.c +++ b/drivers/ata/ahci_mtk.c @@ -142,7 +142,7 @@ static int mtk_ahci_probe(struct platform_device *pdev) if (!plat) return -ENOMEM; - hpriv = ahci_platform_get_resources(pdev); + hpriv = ahci_platform_get_resources(pdev, 0); if (IS_ERR(hpriv)) return PTR_ERR(hpriv); diff --git a/drivers/ata/ahci_mvebu.c b/drivers/ata/ahci_mvebu.c index 72d90b4c3aae..f9cb51be38eb 100644 --- a/drivers/ata/ahci_mvebu.c +++ b/drivers/ata/ahci_mvebu.c @@ -158,7 +158,7 @@ static int ahci_mvebu_probe(struct platform_device *pdev) const struct mbus_dram_target_info *dram; int rc; - hpriv = ahci_platform_get_resources(pdev); + hpriv = ahci_platform_get_resources(pdev, 0); if (IS_ERR(hpriv)) return PTR_ERR(hpriv); diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c index 99f9a895a459..46f0bd75eff7 100644 --- a/drivers/ata/ahci_platform.c +++ b/drivers/ata/ahci_platform.c @@ -43,7 +43,8 @@ static int ahci_probe(struct platform_device *pdev) struct ahci_host_priv *hpriv; int rc; - hpriv = ahci_platform_get_resources(pdev); + hpriv = ahci_platform_get_resources(pdev, + AHCI_PLATFORM_GET_RESETS); if (IS_ERR(hpriv)) return PTR_ERR(hpriv); @@ -75,7 +76,6 @@ static const struct of_device_id ahci_of_match[] = { { .compatible = "generic-ahci", }, /* Keep the following compatibles for device tree compatibility */ { .compatible = "snps,spear-ahci", }, - { .compatible = "snps,exynos5440-ahci", }, { .compatible = "ibm,476gtr-ahci", }, { .compatible = "snps,dwc-ahci", }, { .compatible = "hisilicon,hisi-ahci", }, diff --git a/drivers/ata/ahci_qoriq.c b/drivers/ata/ahci_qoriq.c index cfdef4d44ae9..ce59253ec158 100644 --- a/drivers/ata/ahci_qoriq.c +++ b/drivers/ata/ahci_qoriq.c @@ -250,7 +250,7 @@ static int ahci_qoriq_probe(struct platform_device *pdev) struct resource *res; int rc; - hpriv = ahci_platform_get_resources(pdev); + hpriv = ahci_platform_get_resources(pdev, 0); if (IS_ERR(hpriv)) return PTR_ERR(hpriv); diff --git a/drivers/ata/ahci_seattle.c b/drivers/ata/ahci_seattle.c index 1d31c0c0fc20..e57b6f92c288 100644 --- a/drivers/ata/ahci_seattle.c +++ b/drivers/ata/ahci_seattle.c @@ -164,7 +164,7 @@ static int ahci_seattle_probe(struct platform_device *pdev) int rc; struct ahci_host_priv *hpriv; - hpriv = ahci_platform_get_resources(pdev); + hpriv = ahci_platform_get_resources(pdev, 0); if (IS_ERR(hpriv)) return PTR_ERR(hpriv); diff --git a/drivers/ata/ahci_st.c b/drivers/ata/ahci_st.c index bc345f249555..21c5c44832ef 100644 --- a/drivers/ata/ahci_st.c +++ b/drivers/ata/ahci_st.c @@ -156,7 +156,7 @@ static int st_ahci_probe(struct platform_device *pdev) if (!drv_data) return -ENOMEM; - hpriv = ahci_platform_get_resources(pdev); + hpriv = ahci_platform_get_resources(pdev, 0); if (IS_ERR(hpriv)) return PTR_ERR(hpriv); hpriv->plat_data = drv_data; diff --git a/drivers/ata/ahci_sunxi.c b/drivers/ata/ahci_sunxi.c index b26437430163..631610b72aa5 100644 --- a/drivers/ata/ahci_sunxi.c +++ b/drivers/ata/ahci_sunxi.c @@ -181,7 +181,7 @@ static int ahci_sunxi_probe(struct platform_device *pdev) struct ahci_host_priv *hpriv; int rc; - hpriv = ahci_platform_get_resources(pdev); + hpriv = ahci_platform_get_resources(pdev, 0); if (IS_ERR(hpriv)) return PTR_ERR(hpriv); diff --git a/drivers/ata/ahci_tegra.c b/drivers/ata/ahci_tegra.c index 64d848409fe2..004f2608818e 100644 --- a/drivers/ata/ahci_tegra.c +++ b/drivers/ata/ahci_tegra.c @@ -494,7 +494,7 @@ static int tegra_ahci_probe(struct platform_device *pdev) int ret; unsigned int i; - hpriv = ahci_platform_get_resources(pdev); + hpriv = ahci_platform_get_resources(pdev, 0); if (IS_ERR(hpriv)) return PTR_ERR(hpriv); diff --git a/drivers/ata/ahci_xgene.c b/drivers/ata/ahci_xgene.c index ad58da7c9aff..7e157e1bf65e 100644 --- a/drivers/ata/ahci_xgene.c +++ b/drivers/ata/ahci_xgene.c @@ -759,7 +759,7 @@ static int xgene_ahci_probe(struct platform_device *pdev) &xgene_ahci_v2_port_info }; int rc; - hpriv = ahci_platform_get_resources(pdev); + hpriv = ahci_platform_get_resources(pdev, 0); if (IS_ERR(hpriv)) return PTR_ERR(hpriv); diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index 09620c2ffa0f..b5f57c69c487 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -801,6 +801,8 @@ static int ahci_set_lpm(struct ata_link *link, enum ata_lpm_policy policy, cmd |= PORT_CMD_ALPE; if (policy == ATA_LPM_MIN_POWER) cmd |= PORT_CMD_ASP; + else if (policy == ATA_LPM_MIN_POWER_WITH_PARTIAL) + cmd &= ~PORT_CMD_ASP; /* write out new cmd value */ writel(cmd, port_mmio + PORT_CMD); @@ -811,7 +813,8 @@ static int ahci_set_lpm(struct ata_link *link, enum ata_lpm_policy policy, if ((hpriv->cap2 & HOST_CAP2_SDS) && (hpriv->cap2 & HOST_CAP2_SADM) && (link->device->flags & ATA_DFLAG_DEVSLP)) { - if (policy == ATA_LPM_MIN_POWER) + if (policy == ATA_LPM_MIN_POWER || + policy == ATA_LPM_MIN_POWER_WITH_PARTIAL) ahci_set_aggressive_devslp(ap, true); else ahci_set_aggressive_devslp(ap, false); @@ -2107,7 +2110,7 @@ static void ahci_set_aggressive_devslp(struct ata_port *ap, bool sleep) struct ahci_host_priv *hpriv = ap->host->private_data; void __iomem *port_mmio = ahci_port_base(ap); struct ata_device *dev = ap->link.device; - u32 devslp, dm, dito, mdat, deto; + u32 devslp, dm, dito, mdat, deto, dito_conf; int rc; unsigned int err_mask; @@ -2131,8 +2134,15 @@ static void ahci_set_aggressive_devslp(struct ata_port *ap, bool sleep) return; } - /* device sleep was already enabled */ - if (devslp & PORT_DEVSLP_ADSE) + dm = (devslp & PORT_DEVSLP_DM_MASK) >> PORT_DEVSLP_DM_OFFSET; + dito = devslp_idle_timeout / (dm + 1); + if (dito > 0x3ff) + dito = 0x3ff; + + dito_conf = (devslp >> PORT_DEVSLP_DITO_OFFSET) & 0x3FF; + + /* device sleep was already enabled and same dito */ + if ((devslp & PORT_DEVSLP_ADSE) && (dito_conf == dito)) return; /* set DITO, MDAT, DETO and enable DevSlp, need to stop engine first */ @@ -2140,11 +2150,6 @@ static void ahci_set_aggressive_devslp(struct ata_port *ap, bool sleep) if (rc) return; - dm = (devslp & PORT_DEVSLP_DM_MASK) >> PORT_DEVSLP_DM_OFFSET; - dito = devslp_idle_timeout / (dm + 1); - if (dito > 0x3ff) - dito = 0x3ff; - /* Use the nominal value 10 ms if the read MDAT is zero, * the nominal value of DETO is 20 ms. */ @@ -2162,6 +2167,8 @@ static void ahci_set_aggressive_devslp(struct ata_port *ap, bool sleep) deto = 20; } + /* Make dito, mdat, deto bits to 0s */ + devslp &= ~GENMASK_ULL(24, 2); devslp |= ((dito << PORT_DEVSLP_DITO_OFFSET) | (mdat << PORT_DEVSLP_MDAT_OFFSET) | (deto << PORT_DEVSLP_DETO_OFFSET) | @@ -2439,6 +2446,8 @@ static void ahci_port_stop(struct ata_port *ap) * re-enabling INTx. */ writel(1 << ap->port_no, host_mmio + HOST_IRQ_STAT); + + ahci_rpm_put_port(ap); } void ahci_print_info(struct ata_host *host, const char *scc_s) diff --git a/drivers/ata/libahci_platform.c b/drivers/ata/libahci_platform.c index 30cc8f1a31e1..c92c10d55374 100644 --- a/drivers/ata/libahci_platform.c +++ b/drivers/ata/libahci_platform.c @@ -25,6 +25,7 @@ #include <linux/phy/phy.h> #include <linux/pm_runtime.h> #include <linux/of_platform.h> +#include <linux/reset.h> #include "ahci.h" static void ahci_host_stop(struct ata_host *host); @@ -195,7 +196,8 @@ EXPORT_SYMBOL_GPL(ahci_platform_disable_regulators); * following order: * 1) Regulator * 2) Clocks (through ahci_platform_enable_clks) - * 3) Phys + * 3) Resets + * 4) Phys * * If resource enabling fails at any point the previous enabled resources * are disabled in reverse order. @@ -215,12 +217,19 @@ int ahci_platform_enable_resources(struct ahci_host_priv *hpriv) if (rc) goto disable_regulator; - rc = ahci_platform_enable_phys(hpriv); + rc = reset_control_deassert(hpriv->rsts); if (rc) goto disable_clks; + rc = ahci_platform_enable_phys(hpriv); + if (rc) + goto disable_resets; + return 0; +disable_resets: + reset_control_assert(hpriv->rsts); + disable_clks: ahci_platform_disable_clks(hpriv); @@ -238,13 +247,16 @@ EXPORT_SYMBOL_GPL(ahci_platform_enable_resources); * This function disables all ahci_platform managed resources in the * following order: * 1) Phys - * 2) Clocks (through ahci_platform_disable_clks) - * 3) Regulator + * 2) Resets + * 3) Clocks (through ahci_platform_disable_clks) + * 4) Regulator */ void ahci_platform_disable_resources(struct ahci_host_priv *hpriv) { ahci_platform_disable_phys(hpriv); + reset_control_assert(hpriv->rsts); + ahci_platform_disable_clks(hpriv); ahci_platform_disable_regulators(hpriv); @@ -332,6 +344,7 @@ static int ahci_platform_get_regulator(struct ahci_host_priv *hpriv, u32 port, /** * ahci_platform_get_resources - Get platform resources * @pdev: platform device to get resources for + * @flags: bitmap representing the resource to get * * This function allocates an ahci_host_priv struct, and gets the following * resources, storing a reference to them inside the returned struct: @@ -340,18 +353,20 @@ static int ahci_platform_get_regulator(struct ahci_host_priv *hpriv, u32 port, * 2) regulator for controlling the targets power (optional) * 3) 0 - AHCI_MAX_CLKS clocks, as specified in the devs devicetree node, * or for non devicetree enabled platforms a single clock - * 4) phys (optional) + * 4) resets, if flags has AHCI_PLATFORM_GET_RESETS (optional) + * 5) phys (optional) * * RETURNS: * The allocated ahci_host_priv on success, otherwise an ERR_PTR value */ -struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev) +struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev, + unsigned int flags) { struct device *dev = &pdev->dev; struct ahci_host_priv *hpriv; struct clk *clk; struct device_node *child; - int i, sz, enabled_ports = 0, rc = -ENOMEM, child_nodes; + int i, enabled_ports = 0, rc = -ENOMEM, child_nodes; u32 mask_port_map = 0; if (!devres_open_group(dev, NULL, GFP_KERNEL)) @@ -393,6 +408,14 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev) hpriv->clks[i] = clk; } + if (flags & AHCI_PLATFORM_GET_RESETS) { + hpriv->rsts = devm_reset_control_array_get_optional_shared(dev); + if (IS_ERR(hpriv->rsts)) { + rc = PTR_ERR(hpriv->rsts); + goto err_out; + } + } + hpriv->nports = child_nodes = of_get_child_count(dev->of_node); /* @@ -403,14 +426,16 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev) if (!child_nodes) hpriv->nports = 1; - sz = hpriv->nports * sizeof(*hpriv->phys); - hpriv->phys = devm_kzalloc(dev, sz, GFP_KERNEL); + hpriv->phys = devm_kcalloc(dev, hpriv->nports, sizeof(*hpriv->phys), GFP_KERNEL); if (!hpriv->phys) { rc = -ENOMEM; goto err_out; } - sz = hpriv->nports * sizeof(*hpriv->target_pwrs); - hpriv->target_pwrs = kzalloc(sz, GFP_KERNEL); + /* + * We cannot use devm_ here, since ahci_platform_put_resources() uses + * target_pwrs after devm_ have freed memory + */ + hpriv->target_pwrs = kcalloc(hpriv->nports, sizeof(*hpriv->target_pwrs), GFP_KERNEL); if (!hpriv->target_pwrs) { rc = -ENOMEM; goto err_out; @@ -605,7 +630,7 @@ static void ahci_host_stop(struct ata_host *host) /** * ahci_platform_shutdown - Disable interrupts and stop DMA for host ports - * @dev: platform device pointer for the host + * @pdev: platform device pointer for the host * * This function is called during system shutdown and performs the minimal * deconfiguration required to ensure that an ahci_platform host cannot diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index 984b37647b2f..172e32840256 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -3970,6 +3970,7 @@ int sata_link_scr_lpm(struct ata_link *link, enum ata_lpm_policy policy, scontrol |= (0x6 << 8); break; 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 */ @@ -5066,7 +5067,7 @@ static int ata_sg_setup(struct ata_queued_cmd *qc) if (n_elem < 1) return -1; - DPRINTK("%d sg elements mapped\n", n_elem); + VPRINTK("%d sg elements mapped\n", n_elem); qc->orig_n_elem = qc->n_elem; qc->n_elem = n_elem; qc->flags |= ATA_QCFLAG_DMAMAP; diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 8e270962b2f3..1984fc78c750 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -110,6 +110,7 @@ static const char *ata_lpm_policy_names[] = { [ATA_LPM_MAX_POWER] = "max_performance", [ATA_LPM_MED_POWER] = "medium_power", [ATA_LPM_MED_POWER_WITH_DIPM] = "med_power_with_dipm", + [ATA_LPM_MIN_POWER_WITH_PARTIAL] = "min_power_with_partial", [ATA_LPM_MIN_POWER] = "min_power", }; @@ -4288,10 +4289,10 @@ static inline ata_xlat_func_t ata_get_xlat_func(struct ata_device *dev, u8 cmd) static inline void ata_scsi_dump_cdb(struct ata_port *ap, struct scsi_cmnd *cmd) { -#ifdef ATA_DEBUG +#ifdef ATA_VERBOSE_DEBUG struct scsi_device *scsidev = cmd->device; - DPRINTK("CDB (%u:%d,%d,%lld) %9ph\n", + VPRINTK("CDB (%u:%d,%d,%lld) %9ph\n", ap->print_id, scsidev->channel, scsidev->id, scsidev->lun, cmd->cmnd); diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index cc2f2e35f4c2..c5ea0fc635e5 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -658,36 +658,6 @@ unsigned int ata_sff_data_xfer32(struct ata_queued_cmd *qc, unsigned char *buf, EXPORT_SYMBOL_GPL(ata_sff_data_xfer32); /** - * ata_sff_data_xfer_noirq - Transfer data by PIO - * @qc: queued command - * @buf: data buffer - * @buflen: buffer length - * @rw: read/write - * - * Transfer data from/to the device data register by PIO. Do the - * transfer with interrupts disabled. - * - * LOCKING: - * Inherited from caller. - * - * RETURNS: - * Bytes consumed. - */ -unsigned int ata_sff_data_xfer_noirq(struct ata_queued_cmd *qc, unsigned char *buf, - unsigned int buflen, int rw) -{ - unsigned long flags; - unsigned int consumed; - - local_irq_save(flags); - consumed = ata_sff_data_xfer32(qc, buf, buflen, rw); - local_irq_restore(flags); - - return consumed; -} -EXPORT_SYMBOL_GPL(ata_sff_data_xfer_noirq); - -/** * ata_pio_sector - Transfer a sector of data. * @qc: Command on going * diff --git a/drivers/ata/pata_cmd640.c b/drivers/ata/pata_cmd640.c index c47caa807fa9..e3532eda7b05 100644 --- a/drivers/ata/pata_cmd640.c +++ b/drivers/ata/pata_cmd640.c @@ -178,7 +178,7 @@ static struct scsi_host_template cmd640_sht = { static struct ata_port_operations cmd640_port_ops = { .inherits = &ata_sff_port_ops, /* In theory xfer_noirq is not needed once we kill the prefetcher */ - .sff_data_xfer = ata_sff_data_xfer_noirq, + .sff_data_xfer = ata_sff_data_xfer32, .sff_irq_check = cmd640_sff_irq_check, .qc_issue = cmd640_qc_issue, .cable_detect = ata_cable_40wire, diff --git a/drivers/ata/pata_icside.c b/drivers/ata/pata_icside.c index 188f2f2eb21f..c272f2cbb47c 100644 --- a/drivers/ata/pata_icside.c +++ b/drivers/ata/pata_icside.c @@ -324,7 +324,7 @@ static struct ata_port_operations pata_icside_port_ops = { .inherits = &ata_bmdma_port_ops, /* no need to build any PRD tables for DMA */ .qc_prep = ata_noop_qc_prep, - .sff_data_xfer = ata_sff_data_xfer_noirq, + .sff_data_xfer = ata_sff_data_xfer32, .bmdma_setup = pata_icside_bmdma_setup, .bmdma_start = pata_icside_bmdma_start, .bmdma_stop = pata_icside_bmdma_stop, diff --git a/drivers/ata/pata_imx.c b/drivers/ata/pata_imx.c index 6f0534047c6d..2e538726802b 100644 --- a/drivers/ata/pata_imx.c +++ b/drivers/ata/pata_imx.c @@ -103,7 +103,7 @@ static struct scsi_host_template pata_imx_sht = { static struct ata_port_operations pata_imx_port_ops = { .inherits = &ata_sff_port_ops, - .sff_data_xfer = ata_sff_data_xfer_noirq, + .sff_data_xfer = ata_sff_data_xfer32, .cable_detect = ata_cable_unknown, .set_piomode = pata_imx_set_piomode, }; diff --git a/drivers/ata/pata_legacy.c b/drivers/ata/pata_legacy.c index 53828b6c3044..8ea4b8431fc8 100644 --- a/drivers/ata/pata_legacy.c +++ b/drivers/ata/pata_legacy.c @@ -246,12 +246,12 @@ static const struct ata_port_operations legacy_base_port_ops = { static struct ata_port_operations simple_port_ops = { .inherits = &legacy_base_port_ops, - .sff_data_xfer = ata_sff_data_xfer_noirq, + .sff_data_xfer = ata_sff_data_xfer32, }; static struct ata_port_operations legacy_port_ops = { .inherits = &legacy_base_port_ops, - .sff_data_xfer = ata_sff_data_xfer_noirq, + .sff_data_xfer = ata_sff_data_xfer32, .set_mode = legacy_set_mode, }; @@ -341,7 +341,7 @@ static unsigned int pdc_data_xfer_vlb(struct ata_queued_cmd *qc, } local_irq_restore(flags); } else - buflen = ata_sff_data_xfer_noirq(qc, buf, buflen, rw); + buflen = ata_sff_data_xfer32(qc, buf, buflen, rw); return buflen; } diff --git a/drivers/ata/pata_palmld.c b/drivers/ata/pata_palmld.c index 8c0d7d736b7a..d071ab6864a8 100644 --- a/drivers/ata/pata_palmld.c +++ b/drivers/ata/pata_palmld.c @@ -44,7 +44,7 @@ static struct scsi_host_template palmld_sht = { static struct ata_port_operations palmld_port_ops = { .inherits = &ata_sff_port_ops, - .sff_data_xfer = ata_sff_data_xfer_noirq, + .sff_data_xfer = ata_sff_data_xfer32, .cable_detect = ata_cable_40wire, }; diff --git a/drivers/ata/pata_pcmcia.c b/drivers/ata/pata_pcmcia.c index a541eacc5e95..9b0e6c72e3f9 100644 --- a/drivers/ata/pata_pcmcia.c +++ b/drivers/ata/pata_pcmcia.c @@ -151,7 +151,7 @@ static struct scsi_host_template pcmcia_sht = { static struct ata_port_operations pcmcia_port_ops = { .inherits = &ata_sff_port_ops, - .sff_data_xfer = ata_sff_data_xfer_noirq, + .sff_data_xfer = ata_sff_data_xfer32, .cable_detect = ata_cable_40wire, .set_mode = pcmcia_set_mode, }; diff --git a/drivers/ata/pata_platform.c b/drivers/ata/pata_platform.c index c503ded87bb8..d6f8f5406442 100644 --- a/drivers/ata/pata_platform.c +++ b/drivers/ata/pata_platform.c @@ -49,7 +49,7 @@ static struct scsi_host_template pata_platform_sht = { static struct ata_port_operations pata_platform_port_ops = { .inherits = &ata_sff_port_ops, - .sff_data_xfer = ata_sff_data_xfer_noirq, + .sff_data_xfer = ata_sff_data_xfer32, .cable_detect = ata_cable_unknown, .set_mode = pata_platform_set_mode, }; diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c index 1ca6bcab369f..fd19f1ce83aa 100644 --- a/drivers/ata/pata_via.c +++ b/drivers/ata/pata_via.c @@ -471,7 +471,7 @@ static struct ata_port_operations via_port_ops = { static struct ata_port_operations via_port_ops_noirq = { .inherits = &via_port_ops, - .sff_data_xfer = ata_sff_data_xfer_noirq, + .sff_data_xfer = ata_sff_data_xfer32, }; /** diff --git a/drivers/ata/sata_rcar.c b/drivers/ata/sata_rcar.c index 6456e07db72a..10ecb232245d 100644 --- a/drivers/ata/sata_rcar.c +++ b/drivers/ata/sata_rcar.c @@ -17,7 +17,7 @@ #include <linux/libata.h> #include <linux/of_device.h> #include <linux/platform_device.h> -#include <linux/clk.h> +#include <linux/pm_runtime.h> #include <linux/err.h> #define DRV_NAME "sata_rcar" @@ -109,6 +109,8 @@ #define SATAINTMASK_ERRMSK BIT(2) #define SATAINTMASK_ERRCRTMSK BIT(1) #define SATAINTMASK_ATAMSK BIT(0) +#define SATAINTMASK_ALL_GEN1 0x7ff +#define SATAINTMASK_ALL_GEN2 0xfff #define SATA_RCAR_INT_MASK (SATAINTMASK_SERRMSK | \ SATAINTMASK_ATAMSK) @@ -152,7 +154,7 @@ enum sata_rcar_type { struct sata_rcar_priv { void __iomem *base; - struct clk *clk; + u32 sataint_mask; enum sata_rcar_type type; }; @@ -226,7 +228,7 @@ static void sata_rcar_freeze(struct ata_port *ap) struct sata_rcar_priv *priv = ap->host->private_data; /* mask */ - iowrite32(0x7ff, priv->base + SATAINTMASK_REG); + iowrite32(priv->sataint_mask, priv->base + SATAINTMASK_REG); ata_sff_freeze(ap); } @@ -242,7 +244,7 @@ static void sata_rcar_thaw(struct ata_port *ap) ata_sff_thaw(ap); /* unmask */ - iowrite32(0x7ff & ~SATA_RCAR_INT_MASK, base + SATAINTMASK_REG); + iowrite32(priv->sataint_mask & ~SATA_RCAR_INT_MASK, base + SATAINTMASK_REG); } static void sata_rcar_ioread16_rep(void __iomem *reg, void *buffer, int count) @@ -736,7 +738,7 @@ static irqreturn_t sata_rcar_interrupt(int irq, void *dev_instance) if (!sataintstat) goto done; /* ack */ - iowrite32(~sataintstat & 0x7ff, base + SATAINTSTAT_REG); + iowrite32(~sataintstat & priv->sataint_mask, base + SATAINTSTAT_REG); ap = host->ports[0]; @@ -809,7 +811,7 @@ static void sata_rcar_init_module(struct sata_rcar_priv *priv) /* ack and mask */ iowrite32(0, base + SATAINTSTAT_REG); - iowrite32(0x7ff, base + SATAINTMASK_REG); + iowrite32(priv->sataint_mask, base + SATAINTMASK_REG); /* enable interrupts */ iowrite32(ATAPI_INT_ENABLE_SATAINT, base + ATAPI_INT_ENABLE_REG); @@ -819,16 +821,20 @@ static void sata_rcar_init_controller(struct ata_host *host) { struct sata_rcar_priv *priv = host->private_data; + priv->sataint_mask = SATAINTMASK_ALL_GEN2; + /* reset and setup phy */ switch (priv->type) { case RCAR_GEN1_SATA: + priv->sataint_mask = SATAINTMASK_ALL_GEN1; sata_rcar_gen1_phy_init(priv); break; case RCAR_GEN2_SATA: - case RCAR_GEN3_SATA: case RCAR_R8A7790_ES1_SATA: sata_rcar_gen2_phy_init(priv); break; + case RCAR_GEN3_SATA: + break; default: dev_warn(host->dev, "SATA phy is not initialized\n"); break; @@ -881,6 +887,7 @@ MODULE_DEVICE_TABLE(of, sata_rcar_match); static int sata_rcar_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; struct ata_host *host; struct sata_rcar_priv *priv; struct resource *mem; @@ -891,36 +898,31 @@ static int sata_rcar_probe(struct platform_device *pdev) if (irq <= 0) return -EINVAL; - priv = devm_kzalloc(&pdev->dev, sizeof(struct sata_rcar_priv), - GFP_KERNEL); + priv = devm_kzalloc(dev, sizeof(struct sata_rcar_priv), GFP_KERNEL); if (!priv) return -ENOMEM; - priv->type = (enum sata_rcar_type)of_device_get_match_data(&pdev->dev); - priv->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(priv->clk)) { - dev_err(&pdev->dev, "failed to get access to sata clock\n"); - return PTR_ERR(priv->clk); - } + priv->type = (enum sata_rcar_type)of_device_get_match_data(dev); - ret = clk_prepare_enable(priv->clk); - if (ret) - return ret; + pm_runtime_enable(dev); + ret = pm_runtime_get_sync(dev); + if (ret < 0) + goto err_pm_disable; - host = ata_host_alloc(&pdev->dev, 1); + host = ata_host_alloc(dev, 1); if (!host) { - dev_err(&pdev->dev, "ata_host_alloc failed\n"); + dev_err(dev, "ata_host_alloc failed\n"); ret = -ENOMEM; - goto cleanup; + goto err_pm_put; } host->private_data = priv; mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - priv->base = devm_ioremap_resource(&pdev->dev, mem); + priv->base = devm_ioremap_resource(dev, mem); if (IS_ERR(priv->base)) { ret = PTR_ERR(priv->base); - goto cleanup; + goto err_pm_put; } /* setup port */ @@ -934,9 +936,10 @@ static int sata_rcar_probe(struct platform_device *pdev) if (!ret) return 0; -cleanup: - clk_disable_unprepare(priv->clk); - +err_pm_put: + pm_runtime_put(dev); +err_pm_disable: + pm_runtime_disable(dev); return ret; } @@ -952,9 +955,10 @@ static int sata_rcar_remove(struct platform_device *pdev) iowrite32(0, base + ATAPI_INT_ENABLE_REG); /* ack and mask */ iowrite32(0, base + SATAINTSTAT_REG); - iowrite32(0x7ff, base + SATAINTMASK_REG); + iowrite32(priv->sataint_mask, base + SATAINTMASK_REG); - clk_disable_unprepare(priv->clk); + pm_runtime_put(&pdev->dev); + pm_runtime_disable(&pdev->dev); return 0; } @@ -972,9 +976,9 @@ static int sata_rcar_suspend(struct device *dev) /* disable interrupts */ iowrite32(0, base + ATAPI_INT_ENABLE_REG); /* mask */ - iowrite32(0x7ff, base + SATAINTMASK_REG); + iowrite32(priv->sataint_mask, base + SATAINTMASK_REG); - clk_disable_unprepare(priv->clk); + pm_runtime_put(dev); } return ret; @@ -987,17 +991,16 @@ static int sata_rcar_resume(struct device *dev) void __iomem *base = priv->base; int ret; - ret = clk_prepare_enable(priv->clk); - if (ret) + ret = pm_runtime_get_sync(dev); + if (ret < 0) return ret; if (priv->type == RCAR_GEN3_SATA) { - sata_rcar_gen2_phy_init(priv); sata_rcar_init_module(priv); } else { /* ack and mask */ iowrite32(0, base + SATAINTSTAT_REG); - iowrite32(0x7ff, base + SATAINTMASK_REG); + iowrite32(priv->sataint_mask, base + SATAINTMASK_REG); /* enable interrupts */ iowrite32(ATAPI_INT_ENABLE_SATAINT, @@ -1012,11 +1015,10 @@ static int sata_rcar_resume(struct device *dev) static int sata_rcar_restore(struct device *dev) { struct ata_host *host = dev_get_drvdata(dev); - struct sata_rcar_priv *priv = host->private_data; int ret; - ret = clk_prepare_enable(priv->clk); - if (ret) + ret = pm_runtime_get_sync(dev); + if (ret < 0) return ret; sata_rcar_setup_port(host); diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig index d1c0b60e9326..1851112ccc29 100644 --- a/drivers/bus/Kconfig +++ b/drivers/bus/Kconfig @@ -103,6 +103,16 @@ config SIMPLE_PM_BUS Controller (BSC, sometimes called "LBSC within Bus Bridge", or "External Bus Interface") as found on several Renesas ARM SoCs. +config SUN50I_DE2_BUS + bool "Allwinner A64 DE2 Bus Driver" + default ARM64 + depends on ARCH_SUNXI + select SUNXI_SRAM + help + Say y here to enable support for Allwinner A64 DE2 bus driver. It's + mostly transparent, but a SRAM region needs to be claimed in the SRAM + controller to make the all blocks in the DE2 part accessible. + config SUNXI_RSB tristate "Allwinner sunXi Reduced Serial Bus Driver" default MACH_SUN8I || MACH_SUN9I || ARM64 diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile index b8f036cca7ff..ca300b1914ce 100644 --- a/drivers/bus/Makefile +++ b/drivers/bus/Makefile @@ -21,6 +21,7 @@ obj-$(CONFIG_OMAP_INTERCONNECT) += omap_l3_smx.o omap_l3_noc.o obj-$(CONFIG_OMAP_OCP2SCP) += omap-ocp2scp.o obj-$(CONFIG_QCOM_EBI2) += qcom-ebi2.o +obj-$(CONFIG_SUN50I_DE2_BUS) += sun50i-de2.o obj-$(CONFIG_SUNXI_RSB) += sunxi-rsb.o obj-$(CONFIG_SIMPLE_PM_BUS) += simple-pm-bus.o obj-$(CONFIG_TEGRA_ACONNECT) += tegra-aconnect.o diff --git a/drivers/bus/sun50i-de2.c b/drivers/bus/sun50i-de2.c new file mode 100644 index 000000000000..672518741f86 --- /dev/null +++ b/drivers/bus/sun50i-de2.c @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Allwinner A64 Display Engine 2.0 Bus Driver + * + * Copyright (C) 2018 Icenowy Zheng <icenowy@aosc.io> + */ + +#include <linux/of_platform.h> +#include <linux/platform_device.h> +#include <linux/soc/sunxi/sunxi_sram.h> + +static int sun50i_de2_bus_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + int ret; + + ret = sunxi_sram_claim(&pdev->dev); + if (ret) { + dev_err(&pdev->dev, "Error couldn't map SRAM to device\n"); + return ret; + } + + of_platform_populate(np, NULL, NULL, &pdev->dev); + + return 0; +} + +static int sun50i_de2_bus_remove(struct platform_device *pdev) +{ + sunxi_sram_release(&pdev->dev); + return 0; +} + +static const struct of_device_id sun50i_de2_bus_of_match[] = { + { .compatible = "allwinner,sun50i-a64-de2", }, + { /* sentinel */ } +}; + +static struct platform_driver sun50i_de2_bus_driver = { + .probe = sun50i_de2_bus_probe, + .remove = sun50i_de2_bus_remove, + .driver = { + .name = "sun50i-de2-bus", + .of_match_table = sun50i_de2_bus_of_match, + }, +}; + +builtin_platform_driver(sun50i_de2_bus_driver); diff --git a/drivers/bus/ti-sysc.c b/drivers/bus/ti-sysc.c index 80d60f43db56..c9bac9dc4637 100644 --- a/drivers/bus/ti-sysc.c +++ b/drivers/bus/ti-sysc.c @@ -23,11 +23,14 @@ #include <linux/of_address.h> #include <linux/of_platform.h> #include <linux/slab.h> +#include <linux/iopoll.h> #include <linux/platform_data/ti-sysc.h> #include <dt-bindings/bus/ti-sysc.h> +#define MAX_MODULE_SOFTRESET_WAIT 10000 + static const char * const reg_names[] = { "rev", "sysc", "syss", }; enum sysc_clocks { @@ -88,6 +91,11 @@ struct sysc { struct delayed_work idle_work; }; +void sysc_write(struct sysc *ddata, int offset, u32 value) +{ + writel_relaxed(value, ddata->module_va + offset); +} + static u32 sysc_read(struct sysc *ddata, int offset) { if (ddata->cfg.quirks & SYSC_QUIRK_16BIT) { @@ -943,6 +951,36 @@ static void sysc_init_revision_quirks(struct sysc *ddata) } } +static int sysc_reset(struct sysc *ddata) +{ + int offset = ddata->offsets[SYSC_SYSCONFIG]; + int val; + + if (ddata->legacy_mode || offset < 0 || + ddata->cfg.quirks & SYSC_QUIRK_NO_RESET_ON_INIT) + return 0; + + /* + * Currently only support reset status in sysstatus. + * Warn and return error in all other cases + */ + if (!ddata->cfg.syss_mask) { + dev_err(ddata->dev, "No ti,syss-mask. Reset failed\n"); + return -EINVAL; + } + + val = sysc_read(ddata, offset); + val |= (0x1 << ddata->cap->regbits->srst_shift); + sysc_write(ddata, offset, val); + + /* Poll on reset status */ + offset = ddata->offsets[SYSC_SYSSTATUS]; + + return readl_poll_timeout(ddata->module_va + offset, val, + (val & ddata->cfg.syss_mask) == 0x0, + 100, MAX_MODULE_SOFTRESET_WAIT); +} + /* At this point the module is configured enough to read the revision */ static int sysc_init_module(struct sysc *ddata) { @@ -960,6 +998,14 @@ static int sysc_init_module(struct sysc *ddata) return 0; } + error = sysc_reset(ddata); + if (error) { + dev_err(ddata->dev, "Reset failed with %d\n", error); + pm_runtime_put_sync(ddata->dev); + + return error; + } + ddata->revision = sysc_read_revision(ddata); pm_runtime_put_sync(ddata->dev); @@ -1552,6 +1598,23 @@ static const struct sysc_capabilities sysc_omap4_usb_host_fs = { .regbits = &sysc_regbits_omap4_usb_host_fs, }; +static const struct sysc_regbits sysc_regbits_dra7_mcan = { + .dmadisable_shift = -ENODEV, + .midle_shift = -ENODEV, + .sidle_shift = -ENODEV, + .clkact_shift = -ENODEV, + .enwkup_shift = 4, + .srst_shift = 0, + .emufree_shift = -ENODEV, + .autoidle_shift = -ENODEV, +}; + +static const struct sysc_capabilities sysc_dra7_mcan = { + .type = TI_SYSC_DRA7_MCAN, + .sysc_mask = SYSC_DRA7_MCAN_ENAWAKEUP | SYSC_OMAP4_SOFTRESET, + .regbits = &sysc_regbits_dra7_mcan, +}; + static int sysc_init_pdata(struct sysc *ddata) { struct ti_sysc_platform_data *pdata = dev_get_platdata(ddata->dev); @@ -1743,6 +1806,7 @@ static const struct of_device_id sysc_match[] = { { .compatible = "ti,sysc-mcasp", .data = &sysc_omap4_mcasp, }, { .compatible = "ti,sysc-usb-host-fs", .data = &sysc_omap4_usb_host_fs, }, + { .compatible = "ti,sysc-dra7-mcan", .data = &sysc_dra7_mcan, }, { }, }; MODULE_DEVICE_TABLE(of, sysc_match); diff --git a/drivers/clk/davinci/psc-da830.c b/drivers/clk/davinci/psc-da830.c index 081b039fcb02..6481337382a6 100644 --- a/drivers/clk/davinci/psc-da830.c +++ b/drivers/clk/davinci/psc-da830.c @@ -14,6 +14,7 @@ #include "psc.h" +LPSC_CLKDEV1(aemif_clkdev, NULL, "ti-aemif"); LPSC_CLKDEV1(spi0_clkdev, NULL, "spi_davinci.0"); LPSC_CLKDEV1(mmcsd_clkdev, NULL, "da830-mmc.0"); LPSC_CLKDEV1(uart0_clkdev, NULL, "serial8250.0"); @@ -22,7 +23,7 @@ static const struct davinci_lpsc_clk_info da830_psc0_info[] = { LPSC(0, 0, tpcc, pll0_sysclk2, NULL, LPSC_ALWAYS_ENABLED), LPSC(1, 0, tptc0, pll0_sysclk2, NULL, LPSC_ALWAYS_ENABLED), LPSC(2, 0, tptc1, pll0_sysclk2, NULL, LPSC_ALWAYS_ENABLED), - LPSC(3, 0, aemif, pll0_sysclk3, NULL, LPSC_ALWAYS_ENABLED), + LPSC(3, 0, aemif, pll0_sysclk3, aemif_clkdev, LPSC_ALWAYS_ENABLED), LPSC(4, 0, spi0, pll0_sysclk2, spi0_clkdev, 0), LPSC(5, 0, mmcsd, pll0_sysclk2, mmcsd_clkdev, 0), LPSC(6, 0, aintc, pll0_sysclk4, NULL, LPSC_ALWAYS_ENABLED), diff --git a/drivers/clk/davinci/psc-da850.c b/drivers/clk/davinci/psc-da850.c index d196dcbed560..5a18bca464cd 100644 --- a/drivers/clk/davinci/psc-da850.c +++ b/drivers/clk/davinci/psc-da850.c @@ -16,8 +16,7 @@ #include "psc.h" -LPSC_CLKDEV2(emifa_clkdev, NULL, "ti-aemif", - "aemif", "davinci_nand.0"); +LPSC_CLKDEV1(emifa_clkdev, NULL, "ti-aemif"); LPSC_CLKDEV1(spi0_clkdev, NULL, "spi_davinci.0"); LPSC_CLKDEV1(mmcsd0_clkdev, NULL, "da830-mmc.0"); LPSC_CLKDEV1(uart0_clkdev, NULL, "serial8250.0"); diff --git a/drivers/clk/davinci/psc-dm365.c b/drivers/clk/davinci/psc-dm365.c index 8c73086cc676..c75424f4ea3b 100644 --- a/drivers/clk/davinci/psc-dm365.c +++ b/drivers/clk/davinci/psc-dm365.c @@ -21,7 +21,8 @@ LPSC_CLKDEV1(mmcsd1_clkdev, NULL, "da830-mmc.1"); LPSC_CLKDEV1(asp0_clkdev, NULL, "davinci-mcbsp"); LPSC_CLKDEV1(usb_clkdev, "usb", NULL); LPSC_CLKDEV1(spi2_clkdev, NULL, "spi_davinci.2"); -LPSC_CLKDEV1(aemif_clkdev, "aemif", NULL); +LPSC_CLKDEV2(aemif_clkdev, "aemif", NULL, + NULL, "ti-aemif"); LPSC_CLKDEV1(mmcsd0_clkdev, NULL, "da830-mmc.0"); LPSC_CLKDEV1(i2c_clkdev, NULL, "i2c_davinci.1"); LPSC_CLKDEV1(uart0_clkdev, NULL, "serial8250.0"); diff --git a/drivers/clk/davinci/psc-dm644x.c b/drivers/clk/davinci/psc-dm644x.c index fc0230e3a3d6..0cea6e0bd5f0 100644 --- a/drivers/clk/davinci/psc-dm644x.c +++ b/drivers/clk/davinci/psc-dm644x.c @@ -21,7 +21,8 @@ LPSC_CLKDEV2(emac_clkdev, NULL, "davinci_emac.1", "fck", "davinci_mdio.0"); LPSC_CLKDEV1(usb_clkdev, "usb", NULL); LPSC_CLKDEV1(ide_clkdev, NULL, "palm_bk3710"); -LPSC_CLKDEV1(aemif_clkdev, "aemif", NULL); +LPSC_CLKDEV2(aemif_clkdev, "aemif", NULL, + NULL, "ti-aemif"); LPSC_CLKDEV1(mmcsd_clkdev, NULL, "dm6441-mmc.0"); LPSC_CLKDEV1(asp0_clkdev, NULL, "davinci-mcbsp"); LPSC_CLKDEV1(i2c_clkdev, NULL, "i2c_davinci.1"); diff --git a/drivers/clk/davinci/psc-dm646x.c b/drivers/clk/davinci/psc-dm646x.c index c3f82ed70a80..20012dc7471a 100644 --- a/drivers/clk/davinci/psc-dm646x.c +++ b/drivers/clk/davinci/psc-dm646x.c @@ -18,7 +18,8 @@ LPSC_CLKDEV1(ide_clkdev, NULL, "palm_bk3710"); LPSC_CLKDEV2(emac_clkdev, NULL, "davinci_emac.1", "fck", "davinci_mdio.0"); -LPSC_CLKDEV1(aemif_clkdev, "aemif", NULL); +LPSC_CLKDEV2(aemif_clkdev, "aemif", NULL, + NULL, "ti-aemif"); LPSC_CLKDEV1(mcasp0_clkdev, NULL, "davinci-mcasp.0"); LPSC_CLKDEV1(mcasp1_clkdev, NULL, "davinci-mcasp.1"); LPSC_CLKDEV1(uart0_clkdev, NULL, "serial8250.0"); diff --git a/drivers/clk/samsung/Makefile b/drivers/clk/samsung/Makefile index 513826393158..1a4e6b787978 100644 --- a/drivers/clk/samsung/Makefile +++ b/drivers/clk/samsung/Makefile @@ -14,7 +14,6 @@ obj-$(CONFIG_SOC_EXYNOS5410) += clk-exynos5410.o obj-$(CONFIG_SOC_EXYNOS5420) += clk-exynos5420.o obj-$(CONFIG_SOC_EXYNOS5420) += clk-exynos5-subcmu.o obj-$(CONFIG_EXYNOS_ARM64_COMMON_CLK) += clk-exynos5433.o -obj-$(CONFIG_SOC_EXYNOS5440) += clk-exynos5440.o obj-$(CONFIG_EXYNOS_AUDSS_CLK_CON) += clk-exynos-audss.o obj-$(CONFIG_ARCH_EXYNOS) += clk-exynos-clkout.o obj-$(CONFIG_EXYNOS_ARM64_COMMON_CLK) += clk-exynos7.o diff --git a/drivers/clk/samsung/clk-exynos5440.c b/drivers/clk/samsung/clk-exynos5440.c deleted file mode 100644 index b08bd54c5e76..000000000000 --- a/drivers/clk/samsung/clk-exynos5440.c +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Copyright (c) 2013 Samsung Electronics Co., Ltd. - * Author: Thomas Abraham <thomas.ab@samsung.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Common Clock Framework support for Exynos5440 SoC. -*/ - -#include <dt-bindings/clock/exynos5440.h> -#include <linux/clk-provider.h> -#include <linux/of.h> -#include <linux/of_address.h> -#include <linux/notifier.h> -#include <linux/reboot.h> - -#include "clk.h" -#include "clk-pll.h" - -#define CLKEN_OV_VAL 0xf8 -#define CPU_CLK_STATUS 0xfc -#define MISC_DOUT1 0x558 - -static void __iomem *reg_base; - -/* parent clock name list */ -PNAME(mout_armclk_p) = { "cplla", "cpllb" }; -PNAME(mout_spi_p) = { "div125", "div200" }; - -/* fixed rate clocks generated outside the soc */ -static struct samsung_fixed_rate_clock exynos5440_fixed_rate_ext_clks[] __initdata = { - FRATE(0, "xtal", NULL, 0, 0), -}; - -/* fixed rate clocks */ -static const struct samsung_fixed_rate_clock exynos5440_fixed_rate_clks[] __initconst = { - FRATE(0, "ppll", NULL, 0, 1000000000), - FRATE(0, "usb_phy0", NULL, 0, 60000000), - FRATE(0, "usb_phy1", NULL, 0, 60000000), - FRATE(0, "usb_ohci12", NULL, 0, 12000000), - FRATE(0, "usb_ohci48", NULL, 0, 48000000), -}; - -/* fixed factor clocks */ -static const struct samsung_fixed_factor_clock exynos5440_fixed_factor_clks[] __initconst = { - FFACTOR(0, "div250", "ppll", 1, 4, 0), - FFACTOR(0, "div200", "ppll", 1, 5, 0), - FFACTOR(0, "div125", "div250", 1, 2, 0), -}; - -/* mux clocks */ -static const struct samsung_mux_clock exynos5440_mux_clks[] __initconst = { - MUX(0, "mout_spi", mout_spi_p, MISC_DOUT1, 5, 1), - MUX(CLK_ARM_CLK, "arm_clk", mout_armclk_p, CPU_CLK_STATUS, 0, 1), -}; - -/* divider clocks */ -static const struct samsung_div_clock exynos5440_div_clks[] __initconst = { - DIV(CLK_SPI_BAUD, "div_spi", "mout_spi", MISC_DOUT1, 3, 2), -}; - -/* gate clocks */ -static const struct samsung_gate_clock exynos5440_gate_clks[] __initconst = { - GATE(CLK_PB0_250, "pb0_250", "div250", CLKEN_OV_VAL, 3, 0, 0), - GATE(CLK_PR0_250, "pr0_250", "div250", CLKEN_OV_VAL, 4, 0, 0), - GATE(CLK_PR1_250, "pr1_250", "div250", CLKEN_OV_VAL, 5, 0, 0), - GATE(CLK_B_250, "b_250", "div250", CLKEN_OV_VAL, 9, 0, 0), - GATE(CLK_B_125, "b_125", "div125", CLKEN_OV_VAL, 10, 0, 0), - GATE(CLK_B_200, "b_200", "div200", CLKEN_OV_VAL, 11, 0, 0), - GATE(CLK_SATA, "sata", "div200", CLKEN_OV_VAL, 12, 0, 0), - GATE(CLK_USB, "usb", "div200", CLKEN_OV_VAL, 13, 0, 0), - GATE(CLK_GMAC0, "gmac0", "div200", CLKEN_OV_VAL, 14, 0, 0), - GATE(CLK_CS250, "cs250", "div250", CLKEN_OV_VAL, 19, 0, 0), - GATE(CLK_PB0_250_O, "pb0_250_o", "pb0_250", CLKEN_OV_VAL, 3, 0, 0), - GATE(CLK_PR0_250_O, "pr0_250_o", "pr0_250", CLKEN_OV_VAL, 4, 0, 0), - GATE(CLK_PR1_250_O, "pr1_250_o", "pr1_250", CLKEN_OV_VAL, 5, 0, 0), - GATE(CLK_B_250_O, "b_250_o", "b_250", CLKEN_OV_VAL, 9, 0, 0), - GATE(CLK_B_125_O, "b_125_o", "b_125", CLKEN_OV_VAL, 10, 0, 0), - GATE(CLK_B_200_O, "b_200_o", "b_200", CLKEN_OV_VAL, 11, 0, 0), - GATE(CLK_SATA_O, "sata_o", "sata", CLKEN_OV_VAL, 12, 0, 0), - GATE(CLK_USB_O, "usb_o", "usb", CLKEN_OV_VAL, 13, 0, 0), - GATE(CLK_GMAC0_O, "gmac0_o", "gmac", CLKEN_OV_VAL, 14, 0, 0), - GATE(CLK_CS250_O, "cs250_o", "cs250", CLKEN_OV_VAL, 19, 0, 0), -}; - -static const struct of_device_id ext_clk_match[] __initconst = { - { .compatible = "samsung,clock-xtal", .data = (void *)0, }, - {}, -}; - -static int exynos5440_clk_restart_notify(struct notifier_block *this, - unsigned long code, void *unused) -{ - u32 val, status; - - status = readl_relaxed(reg_base + 0xbc); - val = readl_relaxed(reg_base + 0xcc); - val = (val & 0xffff0000) | (status & 0xffff); - writel_relaxed(val, reg_base + 0xcc); - - return NOTIFY_DONE; -} - -/* - * Exynos5440 Clock restart notifier, handles restart functionality - */ -static struct notifier_block exynos5440_clk_restart_handler = { - .notifier_call = exynos5440_clk_restart_notify, - .priority = 128, -}; - -static const struct samsung_pll_clock exynos5440_plls[] __initconst = { - PLL(pll_2550x, CLK_CPLLA, "cplla", "xtal", 0, 0x4c, NULL), - PLL(pll_2550x, CLK_CPLLB, "cpllb", "xtal", 0, 0x50, NULL), -}; - -/* - * Clock aliases for legacy clkdev look-up. - */ -static const struct samsung_clock_alias exynos5440_aliases[] __initconst = { - ALIAS(CLK_ARM_CLK, NULL, "armclk"), -}; - -/* register exynos5440 clocks */ -static void __init exynos5440_clk_init(struct device_node *np) -{ - struct samsung_clk_provider *ctx; - - reg_base = of_iomap(np, 0); - if (!reg_base) { - pr_err("%s: failed to map clock controller registers," - " aborting clock initialization\n", __func__); - return; - } - - ctx = samsung_clk_init(np, reg_base, CLK_NR_CLKS); - - samsung_clk_of_register_fixed_ext(ctx, exynos5440_fixed_rate_ext_clks, - ARRAY_SIZE(exynos5440_fixed_rate_ext_clks), ext_clk_match); - - samsung_clk_register_pll(ctx, exynos5440_plls, - ARRAY_SIZE(exynos5440_plls), ctx->reg_base); - - samsung_clk_register_fixed_rate(ctx, exynos5440_fixed_rate_clks, - ARRAY_SIZE(exynos5440_fixed_rate_clks)); - samsung_clk_register_fixed_factor(ctx, exynos5440_fixed_factor_clks, - ARRAY_SIZE(exynos5440_fixed_factor_clks)); - samsung_clk_register_mux(ctx, exynos5440_mux_clks, - ARRAY_SIZE(exynos5440_mux_clks)); - samsung_clk_register_div(ctx, exynos5440_div_clks, - ARRAY_SIZE(exynos5440_div_clks)); - samsung_clk_register_gate(ctx, exynos5440_gate_clks, - ARRAY_SIZE(exynos5440_gate_clks)); - samsung_clk_register_alias(ctx, exynos5440_aliases, - ARRAY_SIZE(exynos5440_aliases)); - - samsung_clk_of_add_provider(np, ctx); - - if (register_restart_handler(&exynos5440_clk_restart_handler)) - pr_warn("exynos5440 clock can't register restart handler\n"); - - pr_info("Exynos5440: arm_clk = %ldHz\n", _get_rate("arm_clk")); - pr_info("exynos5440 clock initialization complete\n"); -} -CLK_OF_DECLARE(exynos5440_clk, "samsung,exynos5440-clock", exynos5440_clk_init); diff --git a/drivers/clk/ti/clk-7xx.c b/drivers/clk/ti/clk-7xx.c index fb249a1637a5..71a122b2dc67 100644 --- a/drivers/clk/ti/clk-7xx.c +++ b/drivers/clk/ti/clk-7xx.c @@ -708,6 +708,7 @@ static const struct omap_clkctrl_reg_data dra7_wkupaon_clkctrl_regs[] __initcons { DRA7_COUNTER_32K_CLKCTRL, NULL, 0, "wkupaon_iclk_mux" }, { DRA7_UART10_CLKCTRL, dra7_uart10_bit_data, CLKF_SW_SUP, "wkupaon_cm:clk:0060:24" }, { DRA7_DCAN1_CLKCTRL, dra7_dcan1_bit_data, CLKF_SW_SUP, "wkupaon_cm:clk:0068:24" }, + { DRA7_ADC_CLKCTRL, NULL, CLKF_SW_SUP, "mcan_clk"}, { 0 }, }; diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm index 52f5f1a2040c..0cd8eb76ad59 100644 --- a/drivers/cpufreq/Kconfig.arm +++ b/drivers/cpufreq/Kconfig.arm @@ -71,20 +71,6 @@ config ARM_BRCMSTB_AVS_CPUFREQ Say Y, if you have a Broadcom SoC with AVS support for DFS or DVFS. -config ARM_EXYNOS5440_CPUFREQ - tristate "SAMSUNG EXYNOS5440" - depends on SOC_EXYNOS5440 - depends on HAVE_CLK && OF - select PM_OPP - default y - help - This adds the CPUFreq driver for Samsung EXYNOS5440 - SoC. The nature of exynos5440 clock controller is - different than previous exynos controllers so not using - the common exynos framework. - - If in doubt, say N. - config ARM_HIGHBANK_CPUFREQ tristate "Calxeda Highbank-based" depends on ARCH_HIGHBANK && CPUFREQ_DT && REGULATOR diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index fb4a2ecac43b..c1ffeabe4ecf 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -56,7 +56,6 @@ obj-$(CONFIG_ARM_ARMADA_37XX_CPUFREQ) += armada-37xx-cpufreq.o obj-$(CONFIG_ARM_BRCMSTB_AVS_CPUFREQ) += brcmstb-avs-cpufreq.o obj-$(CONFIG_ACPI_CPPC_CPUFREQ) += cppc_cpufreq.o obj-$(CONFIG_ARCH_DAVINCI) += davinci-cpufreq.o -obj-$(CONFIG_ARM_EXYNOS5440_CPUFREQ) += exynos5440-cpufreq.o obj-$(CONFIG_ARM_HIGHBANK_CPUFREQ) += highbank-cpufreq.o obj-$(CONFIG_ARM_IMX6Q_CPUFREQ) += imx6q-cpufreq.o obj-$(CONFIG_ARM_KIRKWOOD_CPUFREQ) += kirkwood-cpufreq.o diff --git a/drivers/cpufreq/exynos5440-cpufreq.c b/drivers/cpufreq/exynos5440-cpufreq.c deleted file mode 100644 index 932caa386ece..000000000000 --- a/drivers/cpufreq/exynos5440-cpufreq.c +++ /dev/null @@ -1,452 +0,0 @@ -/* - * Copyright (c) 2013 Samsung Electronics Co., Ltd. - * http://www.samsung.com - * - * Amit Daniel Kachhap <amit.daniel@samsung.com> - * - * EXYNOS5440 - CPU frequency scaling support - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. -*/ - -#include <linux/clk.h> -#include <linux/cpu.h> -#include <linux/cpufreq.h> -#include <linux/err.h> -#include <linux/interrupt.h> -#include <linux/io.h> -#include <linux/module.h> -#include <linux/of_address.h> -#include <linux/of_irq.h> -#include <linux/pm_opp.h> -#include <linux/platform_device.h> -#include <linux/slab.h> - -/* Register definitions */ -#define XMU_DVFS_CTRL 0x0060 -#define XMU_PMU_P0_7 0x0064 -#define XMU_C0_3_PSTATE 0x0090 -#define XMU_P_LIMIT 0x00a0 -#define XMU_P_STATUS 0x00a4 -#define XMU_PMUEVTEN 0x00d0 -#define XMU_PMUIRQEN 0x00d4 -#define XMU_PMUIRQ 0x00d8 - -/* PMU mask and shift definations */ -#define P_VALUE_MASK 0x7 - -#define XMU_DVFS_CTRL_EN_SHIFT 0 - -#define P0_7_CPUCLKDEV_SHIFT 21 -#define P0_7_CPUCLKDEV_MASK 0x7 -#define P0_7_ATBCLKDEV_SHIFT 18 -#define P0_7_ATBCLKDEV_MASK 0x7 -#define P0_7_CSCLKDEV_SHIFT 15 -#define P0_7_CSCLKDEV_MASK 0x7 -#define P0_7_CPUEMA_SHIFT 28 -#define P0_7_CPUEMA_MASK 0xf -#define P0_7_L2EMA_SHIFT 24 -#define P0_7_L2EMA_MASK 0xf -#define P0_7_VDD_SHIFT 8 -#define P0_7_VDD_MASK 0x7f -#define P0_7_FREQ_SHIFT 0 -#define P0_7_FREQ_MASK 0xff - -#define C0_3_PSTATE_VALID_SHIFT 8 -#define C0_3_PSTATE_CURR_SHIFT 4 -#define C0_3_PSTATE_NEW_SHIFT 0 - -#define PSTATE_CHANGED_EVTEN_SHIFT 0 - -#define PSTATE_CHANGED_IRQEN_SHIFT 0 - -#define PSTATE_CHANGED_SHIFT 0 - -/* some constant values for clock divider calculation */ -#define CPU_DIV_FREQ_MAX 500 -#define CPU_DBG_FREQ_MAX 375 -#define CPU_ATB_FREQ_MAX 500 - -#define PMIC_LOW_VOLT 0x30 -#define PMIC_HIGH_VOLT 0x28 - -#define CPUEMA_HIGH 0x2 -#define CPUEMA_MID 0x4 -#define CPUEMA_LOW 0x7 - -#define L2EMA_HIGH 0x1 -#define L2EMA_MID 0x3 -#define L2EMA_LOW 0x4 - -#define DIV_TAB_MAX 2 -/* frequency unit is 20MHZ */ -#define FREQ_UNIT 20 -#define MAX_VOLTAGE 1550000 /* In microvolt */ -#define VOLTAGE_STEP 12500 /* In microvolt */ - -#define CPUFREQ_NAME "exynos5440_dvfs" -#define DEF_TRANS_LATENCY 100000 - -enum cpufreq_level_index { - L0, L1, L2, L3, L4, - L5, L6, L7, L8, L9, -}; -#define CPUFREQ_LEVEL_END (L7 + 1) - -struct exynos_dvfs_data { - void __iomem *base; - struct resource *mem; - int irq; - struct clk *cpu_clk; - unsigned int latency; - struct cpufreq_frequency_table *freq_table; - unsigned int freq_count; - struct device *dev; - bool dvfs_enabled; - struct work_struct irq_work; -}; - -static struct exynos_dvfs_data *dvfs_info; -static DEFINE_MUTEX(cpufreq_lock); -static struct cpufreq_freqs freqs; - -static int init_div_table(void) -{ - struct cpufreq_frequency_table *pos, *freq_tbl = dvfs_info->freq_table; - unsigned int tmp, clk_div, ema_div, freq, volt_id, idx; - struct dev_pm_opp *opp; - - cpufreq_for_each_entry_idx(pos, freq_tbl, idx) { - opp = dev_pm_opp_find_freq_exact(dvfs_info->dev, - pos->frequency * 1000, true); - if (IS_ERR(opp)) { - dev_err(dvfs_info->dev, - "failed to find valid OPP for %u KHZ\n", - pos->frequency); - return PTR_ERR(opp); - } - - freq = pos->frequency / 1000; /* In MHZ */ - clk_div = ((freq / CPU_DIV_FREQ_MAX) & P0_7_CPUCLKDEV_MASK) - << P0_7_CPUCLKDEV_SHIFT; - clk_div |= ((freq / CPU_ATB_FREQ_MAX) & P0_7_ATBCLKDEV_MASK) - << P0_7_ATBCLKDEV_SHIFT; - clk_div |= ((freq / CPU_DBG_FREQ_MAX) & P0_7_CSCLKDEV_MASK) - << P0_7_CSCLKDEV_SHIFT; - - /* Calculate EMA */ - volt_id = dev_pm_opp_get_voltage(opp); - - volt_id = (MAX_VOLTAGE - volt_id) / VOLTAGE_STEP; - if (volt_id < PMIC_HIGH_VOLT) { - ema_div = (CPUEMA_HIGH << P0_7_CPUEMA_SHIFT) | - (L2EMA_HIGH << P0_7_L2EMA_SHIFT); - } else if (volt_id > PMIC_LOW_VOLT) { - ema_div = (CPUEMA_LOW << P0_7_CPUEMA_SHIFT) | - (L2EMA_LOW << P0_7_L2EMA_SHIFT); - } else { - ema_div = (CPUEMA_MID << P0_7_CPUEMA_SHIFT) | - (L2EMA_MID << P0_7_L2EMA_SHIFT); - } - - tmp = (clk_div | ema_div | (volt_id << P0_7_VDD_SHIFT) - | ((freq / FREQ_UNIT) << P0_7_FREQ_SHIFT)); - - __raw_writel(tmp, dvfs_info->base + XMU_PMU_P0_7 + 4 * idx); - dev_pm_opp_put(opp); - } - - return 0; -} - -static void exynos_enable_dvfs(unsigned int cur_frequency) -{ - unsigned int tmp, cpu; - struct cpufreq_frequency_table *freq_table = dvfs_info->freq_table; - struct cpufreq_frequency_table *pos; - /* Disable DVFS */ - __raw_writel(0, dvfs_info->base + XMU_DVFS_CTRL); - - /* Enable PSTATE Change Event */ - tmp = __raw_readl(dvfs_info->base + XMU_PMUEVTEN); - tmp |= (1 << PSTATE_CHANGED_EVTEN_SHIFT); - __raw_writel(tmp, dvfs_info->base + XMU_PMUEVTEN); - - /* Enable PSTATE Change IRQ */ - tmp = __raw_readl(dvfs_info->base + XMU_PMUIRQEN); - tmp |= (1 << PSTATE_CHANGED_IRQEN_SHIFT); - __raw_writel(tmp, dvfs_info->base + XMU_PMUIRQEN); - - /* Set initial performance index */ - cpufreq_for_each_entry(pos, freq_table) - if (pos->frequency == cur_frequency) - break; - - if (pos->frequency == CPUFREQ_TABLE_END) { - dev_crit(dvfs_info->dev, "Boot up frequency not supported\n"); - /* Assign the highest frequency */ - pos = freq_table; - cur_frequency = pos->frequency; - } - - dev_info(dvfs_info->dev, "Setting dvfs initial frequency = %uKHZ", - cur_frequency); - - for (cpu = 0; cpu < CONFIG_NR_CPUS; cpu++) { - tmp = __raw_readl(dvfs_info->base + XMU_C0_3_PSTATE + cpu * 4); - tmp &= ~(P_VALUE_MASK << C0_3_PSTATE_NEW_SHIFT); - tmp |= ((pos - freq_table) << C0_3_PSTATE_NEW_SHIFT); - __raw_writel(tmp, dvfs_info->base + XMU_C0_3_PSTATE + cpu * 4); - } - - /* Enable DVFS */ - __raw_writel(1 << XMU_DVFS_CTRL_EN_SHIFT, - dvfs_info->base + XMU_DVFS_CTRL); -} - -static int exynos_target(struct cpufreq_policy *policy, unsigned int index) -{ - unsigned int tmp; - int i; - struct cpufreq_frequency_table *freq_table = dvfs_info->freq_table; - - mutex_lock(&cpufreq_lock); - - freqs.old = policy->cur; - freqs.new = freq_table[index].frequency; - - cpufreq_freq_transition_begin(policy, &freqs); - - /* Set the target frequency in all C0_3_PSTATE register */ - for_each_cpu(i, policy->cpus) { - tmp = __raw_readl(dvfs_info->base + XMU_C0_3_PSTATE + i * 4); - tmp &= ~(P_VALUE_MASK << C0_3_PSTATE_NEW_SHIFT); - tmp |= (index << C0_3_PSTATE_NEW_SHIFT); - - __raw_writel(tmp, dvfs_info->base + XMU_C0_3_PSTATE + i * 4); - } - mutex_unlock(&cpufreq_lock); - return 0; -} - -static void exynos_cpufreq_work(struct work_struct *work) -{ - unsigned int cur_pstate, index; - struct cpufreq_policy *policy = cpufreq_cpu_get(0); /* boot CPU */ - struct cpufreq_frequency_table *freq_table = dvfs_info->freq_table; - - /* Ensure we can access cpufreq structures */ - if (unlikely(dvfs_info->dvfs_enabled == false)) - goto skip_work; - - mutex_lock(&cpufreq_lock); - freqs.old = policy->cur; - - cur_pstate = __raw_readl(dvfs_info->base + XMU_P_STATUS); - if (cur_pstate >> C0_3_PSTATE_VALID_SHIFT & 0x1) - index = (cur_pstate >> C0_3_PSTATE_CURR_SHIFT) & P_VALUE_MASK; - else - index = (cur_pstate >> C0_3_PSTATE_NEW_SHIFT) & P_VALUE_MASK; - - if (likely(index < dvfs_info->freq_count)) { - freqs.new = freq_table[index].frequency; - } else { - dev_crit(dvfs_info->dev, "New frequency out of range\n"); - freqs.new = freqs.old; - } - cpufreq_freq_transition_end(policy, &freqs, 0); - - cpufreq_cpu_put(policy); - mutex_unlock(&cpufreq_lock); -skip_work: - enable_irq(dvfs_info->irq); -} - -static irqreturn_t exynos_cpufreq_irq(int irq, void *id) -{ - unsigned int tmp; - - tmp = __raw_readl(dvfs_info->base + XMU_PMUIRQ); - if (tmp >> PSTATE_CHANGED_SHIFT & 0x1) { - __raw_writel(tmp, dvfs_info->base + XMU_PMUIRQ); - disable_irq_nosync(irq); - schedule_work(&dvfs_info->irq_work); - } - return IRQ_HANDLED; -} - -static void exynos_sort_descend_freq_table(void) -{ - struct cpufreq_frequency_table *freq_tbl = dvfs_info->freq_table; - int i = 0, index; - unsigned int tmp_freq; - /* - * Exynos5440 clock controller state logic expects the cpufreq table to - * be in descending order. But the OPP library constructs the table in - * ascending order. So to make the table descending we just need to - * swap the i element with the N - i element. - */ - for (i = 0; i < dvfs_info->freq_count / 2; i++) { - index = dvfs_info->freq_count - i - 1; - tmp_freq = freq_tbl[i].frequency; - freq_tbl[i].frequency = freq_tbl[index].frequency; - freq_tbl[index].frequency = tmp_freq; - } -} - -static int exynos_cpufreq_cpu_init(struct cpufreq_policy *policy) -{ - policy->clk = dvfs_info->cpu_clk; - return cpufreq_generic_init(policy, dvfs_info->freq_table, - dvfs_info->latency); -} - -static struct cpufreq_driver exynos_driver = { - .flags = CPUFREQ_STICKY | CPUFREQ_ASYNC_NOTIFICATION | - CPUFREQ_NEED_INITIAL_FREQ_CHECK, - .verify = cpufreq_generic_frequency_table_verify, - .target_index = exynos_target, - .get = cpufreq_generic_get, - .init = exynos_cpufreq_cpu_init, - .name = CPUFREQ_NAME, - .attr = cpufreq_generic_attr, -}; - -static const struct of_device_id exynos_cpufreq_match[] = { - { - .compatible = "samsung,exynos5440-cpufreq", - }, - {}, -}; -MODULE_DEVICE_TABLE(of, exynos_cpufreq_match); - -static int exynos_cpufreq_probe(struct platform_device *pdev) -{ - int ret = -EINVAL; - struct device_node *np; - struct resource res; - unsigned int cur_frequency; - - np = pdev->dev.of_node; - if (!np) - return -ENODEV; - - dvfs_info = devm_kzalloc(&pdev->dev, sizeof(*dvfs_info), GFP_KERNEL); - if (!dvfs_info) { - ret = -ENOMEM; - goto err_put_node; - } - - dvfs_info->dev = &pdev->dev; - - ret = of_address_to_resource(np, 0, &res); - if (ret) - goto err_put_node; - - dvfs_info->base = devm_ioremap_resource(dvfs_info->dev, &res); - if (IS_ERR(dvfs_info->base)) { - ret = PTR_ERR(dvfs_info->base); - goto err_put_node; - } - - dvfs_info->irq = irq_of_parse_and_map(np, 0); - if (!dvfs_info->irq) { - dev_err(dvfs_info->dev, "No cpufreq irq found\n"); - ret = -ENODEV; - goto err_put_node; - } - - ret = dev_pm_opp_of_add_table(dvfs_info->dev); - if (ret) { - dev_err(dvfs_info->dev, "failed to init OPP table: %d\n", ret); - goto err_put_node; - } - - ret = dev_pm_opp_init_cpufreq_table(dvfs_info->dev, - &dvfs_info->freq_table); - if (ret) { - dev_err(dvfs_info->dev, - "failed to init cpufreq table: %d\n", ret); - goto err_free_opp; - } - dvfs_info->freq_count = dev_pm_opp_get_opp_count(dvfs_info->dev); - exynos_sort_descend_freq_table(); - - if (of_property_read_u32(np, "clock-latency", &dvfs_info->latency)) - dvfs_info->latency = DEF_TRANS_LATENCY; - - dvfs_info->cpu_clk = devm_clk_get(dvfs_info->dev, "armclk"); - if (IS_ERR(dvfs_info->cpu_clk)) { - dev_err(dvfs_info->dev, "Failed to get cpu clock\n"); - ret = PTR_ERR(dvfs_info->cpu_clk); - goto err_free_table; - } - - cur_frequency = clk_get_rate(dvfs_info->cpu_clk); - if (!cur_frequency) { - dev_err(dvfs_info->dev, "Failed to get clock rate\n"); - ret = -EINVAL; - goto err_free_table; - } - cur_frequency /= 1000; - - INIT_WORK(&dvfs_info->irq_work, exynos_cpufreq_work); - ret = devm_request_irq(dvfs_info->dev, dvfs_info->irq, - exynos_cpufreq_irq, IRQF_TRIGGER_NONE, - CPUFREQ_NAME, dvfs_info); - if (ret) { - dev_err(dvfs_info->dev, "Failed to register IRQ\n"); - goto err_free_table; - } - - ret = init_div_table(); - if (ret) { - dev_err(dvfs_info->dev, "Failed to initialise div table\n"); - goto err_free_table; - } - - exynos_enable_dvfs(cur_frequency); - ret = cpufreq_register_driver(&exynos_driver); - if (ret) { - dev_err(dvfs_info->dev, - "%s: failed to register cpufreq driver\n", __func__); - goto err_free_table; - } - - of_node_put(np); - dvfs_info->dvfs_enabled = true; - return 0; - -err_free_table: - dev_pm_opp_free_cpufreq_table(dvfs_info->dev, &dvfs_info->freq_table); -err_free_opp: - dev_pm_opp_of_remove_table(dvfs_info->dev); -err_put_node: - of_node_put(np); - dev_err(&pdev->dev, "%s: failed initialization\n", __func__); - return ret; -} - -static int exynos_cpufreq_remove(struct platform_device *pdev) -{ - cpufreq_unregister_driver(&exynos_driver); - dev_pm_opp_free_cpufreq_table(dvfs_info->dev, &dvfs_info->freq_table); - dev_pm_opp_of_remove_table(dvfs_info->dev); - return 0; -} - -static struct platform_driver exynos_cpufreq_platdrv = { - .driver = { - .name = "exynos5440-cpufreq", - .of_match_table = exynos_cpufreq_match, - }, - .probe = exynos_cpufreq_probe, - .remove = exynos_cpufreq_remove, -}; -module_platform_driver(exynos_cpufreq_platdrv); - -MODULE_AUTHOR("Amit Daniel Kachhap <amit.daniel@samsung.com>"); -MODULE_DESCRIPTION("Exynos5440 cpufreq driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/crypto/caam/sg_sw_qm2.h b/drivers/crypto/caam/sg_sw_qm2.h index 31b440757146..b5b4c12179df 100644 --- a/drivers/crypto/caam/sg_sw_qm2.h +++ b/drivers/crypto/caam/sg_sw_qm2.h @@ -35,7 +35,7 @@ #ifndef _SG_SW_QM2_H_ #define _SG_SW_QM2_H_ -#include "../../../drivers/staging/fsl-mc/include/dpaa2-fd.h" +#include <soc/fsl/dpaa2-fd.h> static inline void dma_to_qm_sg_one(struct dpaa2_sg_entry *qm_sg_ptr, dma_addr_t dma, u32 len, u16 offset) diff --git a/drivers/crypto/caam/sg_sw_sec4.h b/drivers/crypto/caam/sg_sw_sec4.h index e586ffab8358..dbfa9fce33e0 100644 --- a/drivers/crypto/caam/sg_sw_sec4.h +++ b/drivers/crypto/caam/sg_sw_sec4.h @@ -12,7 +12,7 @@ #include "ctrl.h" #include "regs.h" #include "sg_sw_qm2.h" -#include "../../../drivers/staging/fsl-mc/include/dpaa2-fd.h" +#include <soc/fsl/dpaa2-fd.h> struct sec4_sg_entry { u64 ptr; diff --git a/drivers/crypto/vmx/ghashp8-ppc.pl b/drivers/crypto/vmx/ghashp8-ppc.pl index f746af271460..38b06503ede0 100644 --- a/drivers/crypto/vmx/ghashp8-ppc.pl +++ b/drivers/crypto/vmx/ghashp8-ppc.pl @@ -129,9 +129,9 @@ $code=<<___; le?vperm $IN,$IN,$IN,$lemask vxor $zero,$zero,$zero - vpmsumd $Xl,$IN,$Hl # H.lo·Xi.lo - vpmsumd $Xm,$IN,$H # H.hi·Xi.lo+H.lo·Xi.hi - vpmsumd $Xh,$IN,$Hh # H.hi·Xi.hi + vpmsumd $Xl,$IN,$Hl # H.lo·Xi.lo + vpmsumd $Xm,$IN,$H # H.hi·Xi.lo+H.lo·Xi.hi + vpmsumd $Xh,$IN,$Hh # H.hi·Xi.hi vpmsumd $t2,$Xl,$xC2 # 1st phase @@ -187,11 +187,11 @@ $code=<<___; .align 5 Loop: subic $len,$len,16 - vpmsumd $Xl,$IN,$Hl # H.lo·Xi.lo + vpmsumd $Xl,$IN,$Hl # H.lo·Xi.lo subfe. r0,r0,r0 # borrow?-1:0 - vpmsumd $Xm,$IN,$H # H.hi·Xi.lo+H.lo·Xi.hi + vpmsumd $Xm,$IN,$H # H.hi·Xi.lo+H.lo·Xi.hi and r0,r0,$len - vpmsumd $Xh,$IN,$Hh # H.hi·Xi.hi + vpmsumd $Xh,$IN,$Hh # H.hi·Xi.hi add $inp,$inp,r0 vpmsumd $t2,$Xl,$xC2 # 1st phase diff --git a/drivers/firmware/arm_scmi/perf.c b/drivers/firmware/arm_scmi/perf.c index 2a219b1261b1..721e6c57beae 100644 --- a/drivers/firmware/arm_scmi/perf.c +++ b/drivers/firmware/arm_scmi/perf.c @@ -363,8 +363,6 @@ static int scmi_dvfs_device_opps_add(const struct scmi_handle *handle, return domain; dom = pi->dom_info + domain; - if (!dom) - return -EIO; for (opp = dom->opp, idx = 0; idx < dom->opp_count; idx++, opp++) { freq = opp->perf * dom->mult_factor; @@ -394,9 +392,6 @@ static int scmi_dvfs_transition_latency_get(const struct scmi_handle *handle, return domain; dom = pi->dom_info + domain; - if (!dom) - return -EIO; - /* uS to nS */ return dom->opp[dom->opp_count - 1].trans_latency_us * 1000; } diff --git a/drivers/firmware/efi/efi-bgrt.c b/drivers/firmware/efi/efi-bgrt.c index 50793fda7819..b22ccfb0c991 100644 --- a/drivers/firmware/efi/efi-bgrt.c +++ b/drivers/firmware/efi/efi-bgrt.c @@ -20,7 +20,7 @@ #include <linux/efi-bgrt.h> struct acpi_table_bgrt bgrt_tab; -size_t __initdata bgrt_image_size; +size_t bgrt_image_size; struct bmp_header { u16 id; diff --git a/drivers/firmware/psci_checker.c b/drivers/firmware/psci_checker.c index bb1c068bff19..346943657962 100644 --- a/drivers/firmware/psci_checker.c +++ b/drivers/firmware/psci_checker.c @@ -77,28 +77,6 @@ static int psci_ops_check(void) return 0; } -static int find_cpu_groups(const struct cpumask *cpus, - const struct cpumask **cpu_groups) -{ - unsigned int nb = 0; - cpumask_var_t tmp; - - if (!alloc_cpumask_var(&tmp, GFP_KERNEL)) - return -ENOMEM; - cpumask_copy(tmp, cpus); - - while (!cpumask_empty(tmp)) { - const struct cpumask *cpu_group = - topology_core_cpumask(cpumask_any(tmp)); - - cpu_groups[nb++] = cpu_group; - cpumask_andnot(tmp, tmp, cpu_group); - } - - free_cpumask_var(tmp); - return nb; -} - /* * offlined_cpus is a temporary array but passing it as an argument avoids * multiple allocations. @@ -166,29 +144,66 @@ static unsigned int down_and_up_cpus(const struct cpumask *cpus, return err; } +static void free_cpu_groups(int num, cpumask_var_t **pcpu_groups) +{ + int i; + cpumask_var_t *cpu_groups = *pcpu_groups; + + for (i = 0; i < num; ++i) + free_cpumask_var(cpu_groups[i]); + kfree(cpu_groups); +} + +static int alloc_init_cpu_groups(cpumask_var_t **pcpu_groups) +{ + int num_groups = 0; + cpumask_var_t tmp, *cpu_groups; + + if (!alloc_cpumask_var(&tmp, GFP_KERNEL)) + return -ENOMEM; + + cpu_groups = kcalloc(nb_available_cpus, sizeof(cpu_groups), + GFP_KERNEL); + if (!cpu_groups) + return -ENOMEM; + + cpumask_copy(tmp, cpu_online_mask); + + while (!cpumask_empty(tmp)) { + const struct cpumask *cpu_group = + topology_core_cpumask(cpumask_any(tmp)); + + if (!alloc_cpumask_var(&cpu_groups[num_groups], GFP_KERNEL)) { + free_cpu_groups(num_groups, &cpu_groups); + return -ENOMEM; + } + cpumask_copy(cpu_groups[num_groups++], cpu_group); + cpumask_andnot(tmp, tmp, cpu_group); + } + + free_cpumask_var(tmp); + *pcpu_groups = cpu_groups; + + return num_groups; +} + static int hotplug_tests(void) { - int err; - cpumask_var_t offlined_cpus; - int i, nb_cpu_group; - const struct cpumask **cpu_groups; + int i, nb_cpu_group, err = -ENOMEM; + cpumask_var_t offlined_cpus, *cpu_groups; char *page_buf; - err = -ENOMEM; if (!alloc_cpumask_var(&offlined_cpus, GFP_KERNEL)) return err; - /* We may have up to nb_available_cpus cpu_groups. */ - cpu_groups = kmalloc_array(nb_available_cpus, sizeof(*cpu_groups), - GFP_KERNEL); - if (!cpu_groups) + + nb_cpu_group = alloc_init_cpu_groups(&cpu_groups); + if (nb_cpu_group < 0) goto out_free_cpus; page_buf = (char *)__get_free_page(GFP_KERNEL); if (!page_buf) goto out_free_cpu_groups; err = 0; - nb_cpu_group = find_cpu_groups(cpu_online_mask, cpu_groups); - /* * Of course the last CPU cannot be powered down and cpu_down() should * refuse doing that. @@ -212,7 +227,7 @@ static int hotplug_tests(void) free_page((unsigned long)page_buf); out_free_cpu_groups: - kfree(cpu_groups); + free_cpu_groups(nb_cpu_group, &cpu_groups); out_free_cpus: free_cpumask_var(offlined_cpus); return err; diff --git a/drivers/firmware/raspberrypi.c b/drivers/firmware/raspberrypi.c index 6692888f04cf..a200a2174611 100644 --- a/drivers/firmware/raspberrypi.c +++ b/drivers/firmware/raspberrypi.c @@ -21,6 +21,10 @@ #define MBOX_DATA28(msg) ((msg) & ~0xf) #define MBOX_CHAN_PROPERTY 8 +#define MAX_RPI_FW_PROP_BUF_SIZE 32 + +static struct platform_device *rpi_hwmon; + struct rpi_firmware { struct mbox_client cl; struct mbox_chan *chan; /* The property channel. */ @@ -143,18 +147,22 @@ int rpi_firmware_property(struct rpi_firmware *fw, /* Single tags are very small (generally 8 bytes), so the * stack should be safe. */ - u8 data[buf_size + sizeof(struct rpi_firmware_property_tag_header)]; + u8 data[sizeof(struct rpi_firmware_property_tag_header) + + MAX_RPI_FW_PROP_BUF_SIZE]; struct rpi_firmware_property_tag_header *header = (struct rpi_firmware_property_tag_header *)data; int ret; + if (WARN_ON(buf_size > sizeof(data) - sizeof(*header))) + return -EINVAL; + header->tag = tag; header->buf_size = buf_size; header->req_resp_size = 0; memcpy(data + sizeof(struct rpi_firmware_property_tag_header), tag_data, buf_size); - ret = rpi_firmware_property_list(fw, &data, sizeof(data)); + ret = rpi_firmware_property_list(fw, &data, buf_size + sizeof(*header)); memcpy(tag_data, data + sizeof(struct rpi_firmware_property_tag_header), buf_size); @@ -183,6 +191,20 @@ rpi_firmware_print_firmware_revision(struct rpi_firmware *fw) } } +static void +rpi_register_hwmon_driver(struct device *dev, struct rpi_firmware *fw) +{ + u32 packet; + int ret = rpi_firmware_property(fw, RPI_FIRMWARE_GET_THROTTLED, + &packet, sizeof(packet)); + + if (ret) + return; + + rpi_hwmon = platform_device_register_data(dev, "raspberrypi-hwmon", + -1, NULL, 0); +} + static int rpi_firmware_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -209,6 +231,7 @@ static int rpi_firmware_probe(struct platform_device *pdev) platform_set_drvdata(pdev, fw); rpi_firmware_print_firmware_revision(fw); + rpi_register_hwmon_driver(dev, fw); return 0; } @@ -217,6 +240,8 @@ static int rpi_firmware_remove(struct platform_device *pdev) { struct rpi_firmware *fw = platform_get_drvdata(pdev); + platform_device_unregister(rpi_hwmon); + rpi_hwmon = NULL; mbox_free_channel(fw->chan); return 0; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c index 8a707d8bbb1c..f92597c292fe 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gpuvm.c @@ -206,11 +206,9 @@ static int amdgpu_amdkfd_remove_eviction_fence(struct amdgpu_bo *bo, struct amdgpu_amdkfd_fence ***ef_list, unsigned int *ef_count) { - struct reservation_object_list *fobj; - struct reservation_object *resv; - unsigned int i = 0, j = 0, k = 0, shared_count; - unsigned int count = 0; - struct amdgpu_amdkfd_fence **fence_list; + struct reservation_object *resv = bo->tbo.resv; + struct reservation_object_list *old, *new; + unsigned int i, j, k; if (!ef && !ef_list) return -EINVAL; @@ -220,76 +218,67 @@ static int amdgpu_amdkfd_remove_eviction_fence(struct amdgpu_bo *bo, *ef_count = 0; } - resv = bo->tbo.resv; - fobj = reservation_object_get_list(resv); - - if (!fobj) + old = reservation_object_get_list(resv); + if (!old) return 0; - preempt_disable(); - write_seqcount_begin(&resv->seq); + new = kmalloc(offsetof(typeof(*new), shared[old->shared_max]), + GFP_KERNEL); + if (!new) + return -ENOMEM; - /* Go through all the shared fences in the resevation object. If - * ef is specified and it exists in the list, remove it and reduce the - * count. If ef is not specified, then get the count of eviction fences - * present. + /* Go through all the shared fences in the resevation object and sort + * the interesting ones to the end of the list. */ - shared_count = fobj->shared_count; - for (i = 0; i < shared_count; ++i) { + for (i = 0, j = old->shared_count, k = 0; i < old->shared_count; ++i) { struct dma_fence *f; - f = rcu_dereference_protected(fobj->shared[i], + f = rcu_dereference_protected(old->shared[i], reservation_object_held(resv)); - if (ef) { - if (f->context == ef->base.context) { - dma_fence_put(f); - fobj->shared_count--; - } else { - RCU_INIT_POINTER(fobj->shared[j++], f); - } - } else if (to_amdgpu_amdkfd_fence(f)) - count++; + if ((ef && f->context == ef->base.context) || + (!ef && to_amdgpu_amdkfd_fence(f))) + RCU_INIT_POINTER(new->shared[--j], f); + else + RCU_INIT_POINTER(new->shared[k++], f); } - write_seqcount_end(&resv->seq); - preempt_enable(); - - if (ef || !count) - return 0; - - /* Alloc memory for count number of eviction fence pointers. Fill the - * ef_list array and ef_count - */ - fence_list = kcalloc(count, sizeof(struct amdgpu_amdkfd_fence *), - GFP_KERNEL); - if (!fence_list) - return -ENOMEM; + new->shared_max = old->shared_max; + new->shared_count = k; - preempt_disable(); - write_seqcount_begin(&resv->seq); + if (!ef) { + unsigned int count = old->shared_count - j; - j = 0; - for (i = 0; i < shared_count; ++i) { - struct dma_fence *f; - struct amdgpu_amdkfd_fence *efence; - - f = rcu_dereference_protected(fobj->shared[i], - reservation_object_held(resv)); + /* Alloc memory for count number of eviction fence pointers. + * Fill the ef_list array and ef_count + */ + *ef_list = kcalloc(count, sizeof(**ef_list), GFP_KERNEL); + *ef_count = count; - efence = to_amdgpu_amdkfd_fence(f); - if (efence) { - fence_list[k++] = efence; - fobj->shared_count--; - } else { - RCU_INIT_POINTER(fobj->shared[j++], f); + if (!*ef_list) { + kfree(new); + return -ENOMEM; } } + /* Install the new fence list, seqcount provides the barriers */ + preempt_disable(); + write_seqcount_begin(&resv->seq); + RCU_INIT_POINTER(resv->fence, new); write_seqcount_end(&resv->seq); preempt_enable(); - *ef_list = fence_list; - *ef_count = k; + /* Drop the references to the removed fences or move them to ef_list */ + for (i = j, k = 0; i < old->shared_count; ++i) { + struct dma_fence *f; + + f = rcu_dereference_protected(new->shared[i], + reservation_object_held(resv)); + if (!ef) + (*ef_list)[k++] = to_amdgpu_amdkfd_fence(f); + else + dma_fence_put(f); + } + kfree_rcu(old, rcu); return 0; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 1e66dfd0e39c..8ab5ccbc14ac 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -2274,7 +2274,7 @@ bool amdgpu_device_asic_has_dc_support(enum amd_asic_type asic_type) case CHIP_VEGA10: case CHIP_VEGA12: case CHIP_VEGA20: -#ifdef CONFIG_X86 +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) case CHIP_RAVEN: #endif return amdgpu_dc != 0; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c index 86a0715d9431..1cafe8d83a4d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c @@ -53,9 +53,8 @@ static int amdgpu_sched_process_priority_override(struct amdgpu_device *adev, int fd, enum drm_sched_priority priority) { - struct file *filp = fcheck(fd); + struct file *filp = fget(fd); struct drm_file *file; - struct pid *pid; struct amdgpu_fpriv *fpriv; struct amdgpu_ctx *ctx; uint32_t id; @@ -63,20 +62,12 @@ static int amdgpu_sched_process_priority_override(struct amdgpu_device *adev, if (!filp) return -EINVAL; - pid = get_pid(((struct drm_file *)filp->private_data)->pid); + file = filp->private_data; + fpriv = file->driver_priv; + idr_for_each_entry(&fpriv->ctx_mgr.ctx_handles, ctx, id) + amdgpu_ctx_priority_override(ctx, priority); - mutex_lock(&adev->ddev->filelist_mutex); - list_for_each_entry(file, &adev->ddev->filelist, lhead) { - if (file->pid != pid) - continue; - - fpriv = file->driver_priv; - idr_for_each_entry(&fpriv->ctx_mgr.ctx_handles, ctx, id) - amdgpu_ctx_priority_override(ctx, priority); - } - mutex_unlock(&adev->ddev->filelist_mutex); - - put_pid(pid); + fput(filp); return 0; } diff --git a/drivers/gpu/drm/amd/amdgpu/vega20_reg_init.c b/drivers/gpu/drm/amd/amdgpu/vega20_reg_init.c index 52778de93ab0..2d4473557b0d 100644 --- a/drivers/gpu/drm/amd/amdgpu/vega20_reg_init.c +++ b/drivers/gpu/drm/amd/amdgpu/vega20_reg_init.c @@ -38,6 +38,7 @@ int vega20_reg_base_init(struct amdgpu_device *adev) adev->reg_offset[ATHUB_HWIP][i] = (uint32_t *)(&(ATHUB_BASE.instance[i])); adev->reg_offset[NBIO_HWIP][i] = (uint32_t *)(&(NBIO_BASE.instance[i])); adev->reg_offset[MP0_HWIP][i] = (uint32_t *)(&(MP0_BASE.instance[i])); + adev->reg_offset[MP1_HWIP][i] = (uint32_t *)(&(MP1_BASE.instance[i])); adev->reg_offset[UVD_HWIP][i] = (uint32_t *)(&(UVD_BASE.instance[i])); adev->reg_offset[VCE_HWIP][i] = (uint32_t *)(&(VCE_BASE.instance[i])); adev->reg_offset[DF_HWIP][i] = (uint32_t *)(&(DF_BASE.instance[i])); @@ -46,6 +47,8 @@ int vega20_reg_base_init(struct amdgpu_device *adev) adev->reg_offset[SDMA0_HWIP][i] = (uint32_t *)(&(SDMA0_BASE.instance[i])); adev->reg_offset[SDMA1_HWIP][i] = (uint32_t *)(&(SDMA1_BASE.instance[i])); adev->reg_offset[SMUIO_HWIP][i] = (uint32_t *)(&(SMUIO_BASE.instance[i])); + adev->reg_offset[NBIF_HWIP][i] = (uint32_t *)(&(NBIO_BASE.instance[i])); + adev->reg_offset[THM_HWIP][i] = (uint32_t *)(&(THM_BASE.instance[i])); } return 0; } diff --git a/drivers/gpu/drm/amd/amdgpu/vi.c b/drivers/gpu/drm/amd/amdgpu/vi.c index 42c8ad105b05..88b57a5e9489 100644 --- a/drivers/gpu/drm/amd/amdgpu/vi.c +++ b/drivers/gpu/drm/amd/amdgpu/vi.c @@ -112,8 +112,8 @@ static u32 vi_smc_rreg(struct amdgpu_device *adev, u32 reg) u32 r; spin_lock_irqsave(&adev->smc_idx_lock, flags); - WREG32(mmSMC_IND_INDEX_11, (reg)); - r = RREG32(mmSMC_IND_DATA_11); + WREG32_NO_KIQ(mmSMC_IND_INDEX_11, (reg)); + r = RREG32_NO_KIQ(mmSMC_IND_DATA_11); spin_unlock_irqrestore(&adev->smc_idx_lock, flags); return r; } diff --git a/drivers/gpu/drm/amd/display/Kconfig b/drivers/gpu/drm/amd/display/Kconfig index 325083b0297e..ed654a76c76a 100644 --- a/drivers/gpu/drm/amd/display/Kconfig +++ b/drivers/gpu/drm/amd/display/Kconfig @@ -4,11 +4,17 @@ menu "Display Engine Configuration" config DRM_AMD_DC bool "AMD DC - Enable new display engine" default y + select DRM_AMD_DC_DCN1_0 if X86 && !(KCOV_INSTRUMENT_ALL && KCOV_ENABLE_COMPARISONS) help Choose this option if you want to use the new display engine support for AMDGPU. This adds required support for Vega and Raven ASICs. +config DRM_AMD_DC_DCN1_0 + def_bool n + help + RV family support for display engine + config DEBUG_KERNEL_DC bool "Enable kgdb break in DC" depends on DRM_AMD_DC 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 34f34823bab5..800f481a6995 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -58,9 +58,7 @@ #include <drm/drm_fb_helper.h> #include <drm/drm_edid.h> -#include "modules/inc/mod_freesync.h" - -#ifdef CONFIG_X86 +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) #include "ivsrcid/irqsrcs_dcn_1_0.h" #include "dcn/dcn_1_0_offset.h" @@ -1192,7 +1190,7 @@ static int dce110_register_irq_handlers(struct amdgpu_device *adev) return 0; } -#ifdef CONFIG_X86 +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) /* Register IRQ sources and initialize IRQ callbacks */ static int dcn10_register_irq_handlers(struct amdgpu_device *adev) { @@ -1532,7 +1530,7 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev) goto fail; } break; -#ifdef CONFIG_X86 +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) case CHIP_RAVEN: if (dcn10_register_irq_handlers(dm->adev)) { DRM_ERROR("DM: Failed to initialize IRQ\n"); @@ -1716,7 +1714,7 @@ static int dm_early_init(void *handle) adev->mode_info.num_dig = 6; adev->mode_info.plane_type = dm_plane_type_default; break; -#ifdef CONFIG_X86 +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) case CHIP_RAVEN: adev->mode_info.num_crtc = 4; adev->mode_info.num_hpd = 4; diff --git a/drivers/gpu/drm/amd/display/dc/Makefile b/drivers/gpu/drm/amd/display/dc/Makefile index 532a515fda9a..aed538a4d1ba 100644 --- a/drivers/gpu/drm/amd/display/dc/Makefile +++ b/drivers/gpu/drm/amd/display/dc/Makefile @@ -25,7 +25,7 @@ DC_LIBS = basics bios calcs dce gpio i2caux irq virtual -ifdef CONFIG_X86 +ifdef CONFIG_DRM_AMD_DC_DCN1_0 DC_LIBS += dcn10 dml endif diff --git a/drivers/gpu/drm/amd/display/dc/bios/command_table_helper2.c b/drivers/gpu/drm/amd/display/dc/bios/command_table_helper2.c index 770ff89ba7e1..bbbcef566c55 100644 --- a/drivers/gpu/drm/amd/display/dc/bios/command_table_helper2.c +++ b/drivers/gpu/drm/amd/display/dc/bios/command_table_helper2.c @@ -55,7 +55,7 @@ bool dal_bios_parser_init_cmd_tbl_helper2( case DCE_VERSION_11_22: *h = dal_cmd_tbl_helper_dce112_get_table2(); return true; -#ifdef CONFIG_X86 +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) case DCN_VERSION_1_0: *h = dal_cmd_tbl_helper_dce112_get_table2(); return true; diff --git a/drivers/gpu/drm/amd/display/dc/calcs/Makefile b/drivers/gpu/drm/amd/display/dc/calcs/Makefile index 416500e51b8d..95f332ee3e7e 100644 --- a/drivers/gpu/drm/amd/display/dc/calcs/Makefile +++ b/drivers/gpu/drm/amd/display/dc/calcs/Makefile @@ -38,7 +38,7 @@ CFLAGS_dcn_calc_math.o := $(calcs_ccflags) -Wno-tautological-compare BW_CALCS = dce_calcs.o bw_fixed.o custom_float.o -ifdef CONFIG_X86 +ifdef CONFIG_DRM_AMD_DC_DCN1_0 BW_CALCS += dcn_calcs.o dcn_calc_math.o dcn_calc_auto.o endif diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index 733ac224e7fd..6ae050dc3220 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -52,6 +52,8 @@ #include "dm_helpers.h" #include "mem_input.h" #include "hubp.h" + +#include "dc_link_dp.h" #define DC_LOGGER \ dc->ctx->logger @@ -419,8 +421,17 @@ void dc_link_set_preferred_link_settings(struct dc *dc, struct dc_link_settings *link_setting, struct dc_link *link) { - link->preferred_link_setting = *link_setting; - dp_retrain_link_dp_test(link, link_setting, false); + struct dc_link_settings store_settings = *link_setting; + struct dc_stream_state *link_stream = + link->dc->current_state->res_ctx.pipe_ctx[0].stream; + + link->preferred_link_setting = store_settings; + if (link_stream) + decide_link_settings(link_stream, &store_settings); + + if ((store_settings.lane_count != LANE_COUNT_UNKNOWN) && + (store_settings.link_rate != LINK_RATE_UNKNOWN)) + dp_retrain_link_dp_test(link, &store_settings, false); } void dc_link_enable_hpd(const struct dc_link *link) @@ -476,7 +487,7 @@ static void destruct(struct dc *dc) kfree(dc->bw_dceip); dc->bw_dceip = NULL; -#ifdef CONFIG_X86 +#ifdef CONFIG_DRM_AMD_DC_DCN1_0 kfree(dc->dcn_soc); dc->dcn_soc = NULL; @@ -492,7 +503,7 @@ static bool construct(struct dc *dc, struct dc_context *dc_ctx; struct bw_calcs_dceip *dc_dceip; struct bw_calcs_vbios *dc_vbios; -#ifdef CONFIG_X86 +#ifdef CONFIG_DRM_AMD_DC_DCN1_0 struct dcn_soc_bounding_box *dcn_soc; struct dcn_ip_params *dcn_ip; #endif @@ -514,7 +525,7 @@ static bool construct(struct dc *dc, } dc->bw_vbios = dc_vbios; -#ifdef CONFIG_X86 +#ifdef CONFIG_DRM_AMD_DC_DCN1_0 dcn_soc = kzalloc(sizeof(*dcn_soc), GFP_KERNEL); if (!dcn_soc) { dm_error("%s: failed to create dcn_soc\n", __func__); diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_debug.c b/drivers/gpu/drm/amd/display/dc/core/dc_debug.c index caece7c13bc6..e1ebdf7b5eaf 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_debug.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_debug.c @@ -348,7 +348,7 @@ void context_clock_trace( struct dc *dc, struct dc_state *context) { -#ifdef CONFIG_X86 +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) DC_LOGGER_INIT(dc->ctx->logger); CLOCK_TRACE("Current: dispclk_khz:%d max_dppclk_khz:%d dcfclk_khz:%d\n" "dcfclk_deep_sleep_khz:%d fclk_khz:%d socclk_khz:%d\n", diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link.c b/drivers/gpu/drm/amd/display/dc/core/dc_link.c index 326b3e99b7e4..567867915d32 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c @@ -1039,9 +1039,6 @@ static bool construct( link->link_id = bios->funcs->get_connector_id(bios, init_params->connector_index); - if (dc_ctx->dc_bios->integrated_info) - link->dp_ss_off = !!dc_ctx->dc_bios->integrated_info->dp_ss_control; - if (link->link_id.type != OBJECT_TYPE_CONNECTOR) { dm_error("%s: Invalid Connector ObjectID from Adapter Service for connector index:%d! type %d expected %d\n", __func__, init_params->connector_index, @@ -1049,6 +1046,9 @@ static bool construct( goto create_fail; } + if (link->dc->res_pool->funcs->link_init) + link->dc->res_pool->funcs->link_init(link); + hpd_gpio = get_hpd_gpio(link->ctx->dc_bios, link->link_id, link->ctx->gpio_service); if (hpd_gpio != NULL) diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c index 1644f2a946b0..ea6beccfd89d 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c @@ -41,7 +41,7 @@ #include "dce100/dce100_resource.h" #include "dce110/dce110_resource.h" #include "dce112/dce112_resource.h" -#ifdef CONFIG_X86 +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) #include "dcn10/dcn10_resource.h" #endif #include "dce120/dce120_resource.h" @@ -85,7 +85,7 @@ enum dce_version resource_parse_asic_id(struct hw_asic_id asic_id) case FAMILY_AI: dc_version = DCE_VERSION_12_0; break; -#ifdef CONFIG_X86 +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) case FAMILY_RV: dc_version = DCN_VERSION_1_0; break; @@ -136,7 +136,7 @@ struct resource_pool *dc_create_resource_pool( num_virtual_links, dc); break; -#ifdef CONFIG_X86 +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) case DCN_VERSION_1_0: res_pool = dcn10_create_resource_pool( num_virtual_links, dc); @@ -1251,7 +1251,7 @@ static struct pipe_ctx *acquire_free_pipe_for_stream( } -#ifdef CONFIG_X86 +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) static int acquire_first_split_pipe( struct resource_context *res_ctx, const struct resource_pool *pool, @@ -1322,7 +1322,7 @@ bool dc_add_plane_to_context( free_pipe = acquire_free_pipe_for_stream(context, pool, stream); -#ifdef CONFIG_X86 +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) if (!free_pipe) { int pipe_idx = acquire_first_split_pipe(&context->res_ctx, pool, stream); if (pipe_idx >= 0) @@ -1920,7 +1920,7 @@ enum dc_status resource_map_pool_resources( /* acquire new resources */ pipe_idx = acquire_first_free_pipe(&context->res_ctx, pool, stream); -#ifdef CONFIG_X86 +#ifdef CONFIG_DRM_AMD_DC_DCN1_0 if (pipe_idx < 0) pipe_idx = acquire_first_split_pipe(&context->res_ctx, pool, stream); #endif diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index e2f033d420a0..6c9990bef267 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -294,7 +294,7 @@ struct dc { /* Inputs into BW and WM calculations. */ struct bw_calcs_dceip *bw_dceip; struct bw_calcs_vbios *bw_vbios; -#ifdef CONFIG_X86 +#ifdef CONFIG_DRM_AMD_DC_DCN1_0 struct dcn_soc_bounding_box *dcn_soc; struct dcn_ip_params *dcn_ip; struct display_mode_lib dml; diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c b/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c index 439dcf3b596c..ca137757a69e 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c @@ -592,7 +592,7 @@ static uint32_t dce110_get_pix_clk_dividers( case DCE_VERSION_11_2: case DCE_VERSION_11_22: case DCE_VERSION_12_0: -#ifdef CONFIG_X86 +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) case DCN_VERSION_1_0: #endif @@ -909,7 +909,7 @@ static bool dce110_program_pix_clk( struct dce110_clk_src *clk_src = TO_DCE110_CLK_SRC(clock_source); struct bp_pixel_clock_parameters bp_pc_params = {0}; -#ifdef CONFIG_X86 +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) if (IS_FPGA_MAXIMUS_DC(clock_source->ctx->dce_environment)) { unsigned int inst = pix_clk_params->controller_id - CONTROLLER_ID_D0; unsigned dp_dto_ref_kHz = 700000; @@ -982,7 +982,7 @@ static bool dce110_program_pix_clk( case DCE_VERSION_11_2: case DCE_VERSION_11_22: case DCE_VERSION_12_0: -#ifdef CONFIG_X86 +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) case DCN_VERSION_1_0: #endif diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.h b/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.h index 801bb65707b3..c45e2f76189e 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.h @@ -55,7 +55,7 @@ CS_SF(PHYPLLA_PIXCLK_RESYNC_CNTL, PHYPLLA_DCCG_DEEP_COLOR_CNTL, mask_sh),\ CS_SF(PHYPLLA_PIXCLK_RESYNC_CNTL, PHYPLLA_PIXCLK_DOUBLE_RATE_ENABLE, mask_sh) -#ifdef CONFIG_X86 +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) #define CS_COMMON_REG_LIST_DCN1_0(index, pllid) \ SRI(PIXCLK_RESYNC_CNTL, PHYPLL, pllid),\ diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c index 684da3db7568..fb1f373d08a1 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c @@ -30,7 +30,7 @@ #include "bios_parser_interface.h" #include "dc.h" #include "dmcu.h" -#ifdef CONFIG_X86 +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) #include "dcn_calcs.h" #endif #include "core_types.h" @@ -106,7 +106,8 @@ enum dentist_base_divider_id { DENTIST_BASE_DID_1 = 0x08, DENTIST_BASE_DID_2 = 0x40, DENTIST_BASE_DID_3 = 0x60, - DENTIST_MAX_DID = 0x80 + DENTIST_BASE_DID_4 = 0x7e, + DENTIST_MAX_DID = 0x7f }; /* Starting point and step size for each divider range.*/ @@ -117,6 +118,8 @@ enum dentist_divider_range { DENTIST_DIVIDER_RANGE_2_STEP = 2, /* 0.50 */ DENTIST_DIVIDER_RANGE_3_START = 128, /* 32.00 */ DENTIST_DIVIDER_RANGE_3_STEP = 4, /* 1.00 */ + DENTIST_DIVIDER_RANGE_4_START = 248, /* 62.00 */ + DENTIST_DIVIDER_RANGE_4_STEP = 264, /* 66.00 */ DENTIST_DIVIDER_RANGE_SCALE_FACTOR = 4 }; @@ -133,9 +136,12 @@ static int dentist_get_divider_from_did(int did) } else if (did < DENTIST_BASE_DID_3) { return DENTIST_DIVIDER_RANGE_2_START + DENTIST_DIVIDER_RANGE_2_STEP * (did - DENTIST_BASE_DID_2); - } else { + } else if (did < DENTIST_BASE_DID_4) { return DENTIST_DIVIDER_RANGE_3_START + DENTIST_DIVIDER_RANGE_3_STEP * (did - DENTIST_BASE_DID_3); + } else { + return DENTIST_DIVIDER_RANGE_4_START + DENTIST_DIVIDER_RANGE_4_STEP + * (did - DENTIST_BASE_DID_4); } } @@ -478,7 +484,7 @@ static void dce12_update_clocks(struct dccg *dccg, } } -#ifdef CONFIG_X86 +#ifdef CONFIG_DRM_AMD_DC_DCN1_0 static int dcn1_determine_dppclk_threshold(struct dccg *dccg, struct dc_clocks *new_clocks) { bool request_dpp_div = new_clocks->dispclk_khz > new_clocks->dppclk_khz; @@ -668,7 +674,7 @@ static void dce_update_clocks(struct dccg *dccg, } } -#ifdef CONFIG_X86 +#ifdef CONFIG_DRM_AMD_DC_DCN1_0 static const struct display_clock_funcs dcn1_funcs = { .get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz, .set_dispclk = dce112_set_clock, @@ -823,7 +829,7 @@ struct dccg *dce120_dccg_create(struct dc_context *ctx) return &clk_dce->base; } -#ifdef CONFIG_X86 +#ifdef CONFIG_DRM_AMD_DC_DCN1_0 struct dccg *dcn1_dccg_create(struct dc_context *ctx) { struct dc_debug_options *debug = &ctx->dc->debug; diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.h b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.h index e5e44adc6c27..8a6b2d328467 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.h +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clocks.h @@ -111,7 +111,7 @@ struct dccg *dce112_dccg_create( struct dccg *dce120_dccg_create(struct dc_context *ctx); -#ifdef CONFIG_X86 +#ifdef CONFIG_DRM_AMD_DC_DCN1_0 struct dccg *dcn1_dccg_create(struct dc_context *ctx); #endif diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c b/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c index ca7989e4932b..dea40b322191 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c @@ -316,7 +316,7 @@ static void dce_get_psr_wait_loop( return; } -#ifdef CONFIG_X86 +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) static void dcn10_get_dmcu_state(struct dmcu *dmcu) { struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu); @@ -743,7 +743,7 @@ static const struct dmcu_funcs dce_funcs = { .is_dmcu_initialized = dce_is_dmcu_initialized }; -#ifdef CONFIG_X86 +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) static const struct dmcu_funcs dcn10_funcs = { .dmcu_init = dcn10_dmcu_init, .load_iram = dcn10_dmcu_load_iram, @@ -795,7 +795,7 @@ struct dmcu *dce_dmcu_create( return &dmcu_dce->base; } -#ifdef CONFIG_X86 +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) struct dmcu *dcn10_dmcu_create( struct dc_context *ctx, const struct dce_dmcu_registers *regs, diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c index b139b4017820..91642e684858 100644 --- a/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c +++ b/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c @@ -135,7 +135,7 @@ static void dce110_update_generic_info_packet( AFMT_GENERIC0_UPDATE, (packet_index == 0), AFMT_GENERIC2_UPDATE, (packet_index == 2)); } -#ifdef CONFIG_X86 +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) if (REG(AFMT_VBI_PACKET_CONTROL1)) { switch (packet_index) { case 0: @@ -229,7 +229,7 @@ static void dce110_update_hdmi_info_packet( HDMI_GENERIC1_SEND, send, HDMI_GENERIC1_LINE, line); break; -#ifdef CONFIG_X86 +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) case 4: if (REG(HDMI_GENERIC_PACKET_CONTROL2)) REG_UPDATE_3(HDMI_GENERIC_PACKET_CONTROL2, @@ -274,7 +274,7 @@ static void dce110_stream_encoder_dp_set_stream_attribute( struct dc_crtc_timing *crtc_timing, enum dc_color_space output_color_space) { -#ifdef CONFIG_X86 +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) uint32_t h_active_start; uint32_t v_active_start; uint32_t misc0 = 0; @@ -317,7 +317,7 @@ static void dce110_stream_encoder_dp_set_stream_attribute( if (enc110->se_mask->DP_VID_M_DOUBLE_VALUE_EN) REG_UPDATE(DP_VID_TIMING, DP_VID_M_DOUBLE_VALUE_EN, 1); -#ifdef CONFIG_X86 +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) if (enc110->se_mask->DP_VID_N_MUL) REG_UPDATE(DP_VID_TIMING, DP_VID_N_MUL, 1); #endif @@ -328,7 +328,7 @@ static void dce110_stream_encoder_dp_set_stream_attribute( break; } -#ifdef CONFIG_X86 +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) if (REG(DP_MSA_MISC)) misc1 = REG_READ(DP_MSA_MISC); #endif @@ -362,7 +362,7 @@ static void dce110_stream_encoder_dp_set_stream_attribute( /* set dynamic range and YCbCr range */ -#ifdef CONFIG_X86 +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) switch (crtc_timing->display_color_depth) { case COLOR_DEPTH_666: colorimetry_bpc = 0; @@ -441,7 +441,7 @@ static void dce110_stream_encoder_dp_set_stream_attribute( DP_DYN_RANGE, dynamic_range_rgb, DP_YCBCR_RANGE, dynamic_range_ycbcr); -#ifdef CONFIG_X86 +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) if (REG(DP_MSA_COLORIMETRY)) REG_SET(DP_MSA_COLORIMETRY, 0, DP_MSA_MISC0, misc0); @@ -476,7 +476,7 @@ static void dce110_stream_encoder_dp_set_stream_attribute( crtc_timing->v_front_porch; -#ifdef CONFIG_X86 +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) /* start at begining of left border */ if (REG(DP_MSA_TIMING_PARAM2)) REG_SET_2(DP_MSA_TIMING_PARAM2, 0, @@ -751,7 +751,7 @@ static void dce110_stream_encoder_update_hdmi_info_packets( dce110_update_hdmi_info_packet(enc110, 3, &info_frame->hdrsmd); } -#ifdef CONFIG_X86 +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) if (enc110->se_mask->HDMI_DB_DISABLE) { /* for bring up, disable dp double TODO */ if (REG(HDMI_DB_CONTROL)) @@ -789,7 +789,7 @@ static void dce110_stream_encoder_stop_hdmi_info_packets( HDMI_GENERIC1_LINE, 0, HDMI_GENERIC1_SEND, 0); -#ifdef CONFIG_X86 +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) /* stop generic packets 2 & 3 on HDMI */ if (REG(HDMI_GENERIC_PACKET_CONTROL2)) REG_SET_6(HDMI_GENERIC_PACKET_CONTROL2, 0, 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 5450d4d38e8a..14384d9675a8 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 @@ -1250,7 +1250,7 @@ static void program_scaler(const struct dc *dc, { struct tg_color color = {0}; -#ifdef CONFIG_X86 +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) /* TOFPGA */ if (pipe_ctx->plane_res.xfm->funcs->transform_set_pixel_storage_depth == NULL) return; @@ -1588,7 +1588,13 @@ void dce110_enable_accelerated_mode(struct dc *dc, struct dc_state *context) bool can_eDP_fast_boot_optimize = false; if (edp_link) { - can_eDP_fast_boot_optimize = + /* this seems to cause blank screens on DCE8 */ + if ((dc->ctx->dce_version == DCE_VERSION_8_0) || + (dc->ctx->dce_version == DCE_VERSION_8_1) || + (dc->ctx->dce_version == DCE_VERSION_8_3)) + can_eDP_fast_boot_optimize = false; + else + can_eDP_fast_boot_optimize = edp_link->link_enc->funcs->is_dig_enabled(edp_link->link_enc); } diff --git a/drivers/gpu/drm/amd/display/dc/gpio/Makefile b/drivers/gpu/drm/amd/display/dc/gpio/Makefile index b9d9930a4974..562ee189d780 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/Makefile +++ b/drivers/gpu/drm/amd/display/dc/gpio/Makefile @@ -61,7 +61,7 @@ AMD_DISPLAY_FILES += $(AMD_DAL_GPIO_DCE120) ############################################################################### # DCN 1x ############################################################################### -ifdef CONFIG_X86 +ifdef CONFIG_DRM_AMD_DC_DCN1_0 GPIO_DCN10 = hw_translate_dcn10.o hw_factory_dcn10.o AMD_DAL_GPIO_DCN10 = $(addprefix $(AMDDALPATH)/dc/gpio/dcn10/,$(GPIO_DCN10)) diff --git a/drivers/gpu/drm/amd/display/dc/gpio/hw_factory.c b/drivers/gpu/drm/amd/display/dc/gpio/hw_factory.c index 83df779984e5..0caee3523017 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/hw_factory.c +++ b/drivers/gpu/drm/amd/display/dc/gpio/hw_factory.c @@ -43,7 +43,7 @@ #include "dce80/hw_factory_dce80.h" #include "dce110/hw_factory_dce110.h" #include "dce120/hw_factory_dce120.h" -#ifdef CONFIG_X86 +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) #include "dcn10/hw_factory_dcn10.h" #endif @@ -81,7 +81,7 @@ bool dal_hw_factory_init( case DCE_VERSION_12_0: dal_hw_factory_dce120_init(factory); return true; -#ifdef CONFIG_X86 +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) case DCN_VERSION_1_0: dal_hw_factory_dcn10_init(factory); return true; diff --git a/drivers/gpu/drm/amd/display/dc/gpio/hw_translate.c b/drivers/gpu/drm/amd/display/dc/gpio/hw_translate.c index e7541310480b..55c707488541 100644 --- a/drivers/gpu/drm/amd/display/dc/gpio/hw_translate.c +++ b/drivers/gpu/drm/amd/display/dc/gpio/hw_translate.c @@ -43,7 +43,7 @@ #include "dce80/hw_translate_dce80.h" #include "dce110/hw_translate_dce110.h" #include "dce120/hw_translate_dce120.h" -#ifdef CONFIG_X86 +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) #include "dcn10/hw_translate_dcn10.h" #endif @@ -78,7 +78,7 @@ bool dal_hw_translate_init( case DCE_VERSION_12_0: dal_hw_translate_dce120_init(translate); return true; -#ifdef CONFIG_X86 +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) case DCN_VERSION_1_0: dal_hw_translate_dcn10_init(translate); return true; diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/Makefile b/drivers/gpu/drm/amd/display/dc/i2caux/Makefile index a851d07f0190..352885cb4d07 100644 --- a/drivers/gpu/drm/amd/display/dc/i2caux/Makefile +++ b/drivers/gpu/drm/amd/display/dc/i2caux/Makefile @@ -71,7 +71,7 @@ AMD_DISPLAY_FILES += $(AMD_DAL_I2CAUX_DCE112) ############################################################################### # DCN 1.0 family ############################################################################### -ifdef CONFIG_X86 +ifdef CONFIG_DRM_AMD_DC_DCN1_0 I2CAUX_DCN1 = i2caux_dcn10.o AMD_DAL_I2CAUX_DCN1 = $(addprefix $(AMDDALPATH)/dc/i2caux/dcn10/,$(I2CAUX_DCN1)) diff --git a/drivers/gpu/drm/amd/display/dc/i2caux/i2caux.c b/drivers/gpu/drm/amd/display/dc/i2caux/i2caux.c index f7ed355fc84f..9b0bcc6b769b 100644 --- a/drivers/gpu/drm/amd/display/dc/i2caux/i2caux.c +++ b/drivers/gpu/drm/amd/display/dc/i2caux/i2caux.c @@ -59,7 +59,7 @@ #include "dce120/i2caux_dce120.h" -#ifdef CONFIG_X86 +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) #include "dcn10/i2caux_dcn10.h" #endif @@ -91,7 +91,7 @@ struct i2caux *dal_i2caux_create( return dal_i2caux_dce100_create(ctx); case DCE_VERSION_12_0: return dal_i2caux_dce120_create(ctx); -#ifdef CONFIG_X86 +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) case DCN_VERSION_1_0: return dal_i2caux_dcn10_create(ctx); #endif 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 9f33306f9014..c0b9ca13393b 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/core_types.h +++ b/drivers/gpu/drm/amd/display/dc/inc/core_types.h @@ -33,7 +33,7 @@ #include "dc_bios_types.h" #include "mem_input.h" #include "hubp.h" -#ifdef CONFIG_X86 +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) #include "mpc.h" #endif @@ -92,6 +92,7 @@ struct resource_context; struct resource_funcs { void (*destroy)(struct resource_pool **pool); + void (*link_init)(struct dc_link *link); struct link_encoder *(*link_enc_create)( const struct encoder_init_data *init); @@ -221,7 +222,7 @@ struct pipe_ctx { struct pipe_ctx *top_pipe; struct pipe_ctx *bottom_pipe; -#ifdef CONFIG_X86 +#ifdef CONFIG_DRM_AMD_DC_DCN1_0 struct _vcs_dpi_display_dlg_regs_st dlg_regs; struct _vcs_dpi_display_ttu_regs_st ttu_regs; struct _vcs_dpi_display_rq_regs_st rq_regs; @@ -276,7 +277,7 @@ struct dc_state { /* Note: these are big structures, do *not* put on stack! */ struct dm_pp_display_configuration pp_display_cfg; -#ifdef CONFIG_X86 +#ifdef CONFIG_DRM_AMD_DC_DCN1_0 struct dcn_bw_internal_vars dcn_bw_vars; #endif diff --git a/drivers/gpu/drm/amd/display/dc/irq/Makefile b/drivers/gpu/drm/amd/display/dc/irq/Makefile index a76ee600ecee..498515aad4a5 100644 --- a/drivers/gpu/drm/amd/display/dc/irq/Makefile +++ b/drivers/gpu/drm/amd/display/dc/irq/Makefile @@ -60,7 +60,7 @@ AMD_DISPLAY_FILES += $(AMD_DAL_IRQ_DCE12) ############################################################################### # DCN 1x ############################################################################### -ifdef CONFIG_X86 +ifdef CONFIG_DRM_AMD_DC_DCN1_0 IRQ_DCN1 = irq_service_dcn10.o AMD_DAL_IRQ_DCN1 = $(addprefix $(AMDDALPATH)/dc/irq/dcn10/,$(IRQ_DCN1)) diff --git a/drivers/gpu/drm/amd/display/dc/irq/irq_service.c b/drivers/gpu/drm/amd/display/dc/irq/irq_service.c index ae3fd0a235ba..604bea01fc13 100644 --- a/drivers/gpu/drm/amd/display/dc/irq/irq_service.c +++ b/drivers/gpu/drm/amd/display/dc/irq/irq_service.c @@ -36,7 +36,7 @@ #include "dce120/irq_service_dce120.h" -#ifdef CONFIG_X86 +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) #include "dcn10/irq_service_dcn10.h" #endif diff --git a/drivers/gpu/drm/amd/display/dc/os_types.h b/drivers/gpu/drm/amd/display/dc/os_types.h index c9fce9066ad8..a407892905af 100644 --- a/drivers/gpu/drm/amd/display/dc/os_types.h +++ b/drivers/gpu/drm/amd/display/dc/os_types.h @@ -48,7 +48,7 @@ #define dm_error(fmt, ...) DRM_ERROR(fmt, ##__VA_ARGS__) -#ifdef CONFIG_X86 +#if defined(CONFIG_DRM_AMD_DC_DCN1_0) #include <asm/fpu/api.h> #endif diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/hardwaremanager.c b/drivers/gpu/drm/amd/powerplay/hwmgr/hardwaremanager.c index 53207e76b0f3..6ef3c875fedd 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/hardwaremanager.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/hardwaremanager.c @@ -75,10 +75,12 @@ int phm_set_power_state(struct pp_hwmgr *hwmgr, int phm_enable_dynamic_state_management(struct pp_hwmgr *hwmgr) { + struct amdgpu_device *adev = NULL; int ret = -EINVAL;; PHM_FUNC_CHECK(hwmgr); + adev = hwmgr->adev; - if (smum_is_dpm_running(hwmgr)) { + if (smum_is_dpm_running(hwmgr) && !amdgpu_passthrough(adev)) { pr_info("dpm has been enabled\n"); return 0; } diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 5dc742b27ca0..3c9fc99648b7 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -116,6 +116,9 @@ static const struct edid_quirk { /* CPT panel of Asus UX303LA reports 8 bpc, but is a 6 bpc panel */ { "CPT", 0x17df, EDID_QUIRK_FORCE_6BPC }, + /* SDC panel of Lenovo B50-80 reports 8 bpc, but is a 6 bpc panel */ + { "SDC", 0x3652, EDID_QUIRK_FORCE_6BPC }, + /* Belinea 10 15 55 */ { "MAX", 1516, EDID_QUIRK_PREFER_LARGE_60 }, { "MAX", 0x77e, EDID_QUIRK_PREFER_LARGE_60 }, diff --git a/drivers/gpu/drm/gma500/framebuffer.c b/drivers/gpu/drm/gma500/framebuffer.c index 2f00a37684a2..adefae58b5fc 100644 --- a/drivers/gpu/drm/gma500/framebuffer.c +++ b/drivers/gpu/drm/gma500/framebuffer.c @@ -108,7 +108,7 @@ static int psbfb_pan(struct fb_var_screeninfo *var, struct fb_info *info) return 0; } -static int psbfb_vm_fault(struct vm_fault *vmf) +static vm_fault_t psbfb_vm_fault(struct vm_fault *vmf) { struct vm_area_struct *vma = vmf->vma; struct psb_framebuffer *psbfb = vma->vm_private_data; @@ -118,7 +118,7 @@ static int psbfb_vm_fault(struct vm_fault *vmf) int page_num; int i; unsigned long address; - int ret; + vm_fault_t ret = VM_FAULT_SIGBUS; unsigned long pfn; unsigned long phys_addr = (unsigned long)dev_priv->stolen_base + gtt->offset; @@ -131,18 +131,14 @@ static int psbfb_vm_fault(struct vm_fault *vmf) for (i = 0; i < page_num; i++) { pfn = (phys_addr >> PAGE_SHIFT); - ret = vm_insert_mixed(vma, address, + ret = vmf_insert_mixed(vma, address, __pfn_to_pfn_t(pfn, PFN_DEV)); - if (unlikely((ret == -EBUSY) || (ret != 0 && i > 0))) + if (unlikely(ret & VM_FAULT_ERROR)) break; - else if (unlikely(ret != 0)) { - ret = (ret == -ENOMEM) ? VM_FAULT_OOM : VM_FAULT_SIGBUS; - return ret; - } address += PAGE_SIZE; phys_addr += PAGE_SIZE; } - return VM_FAULT_NOPAGE; + return ret; } static void psbfb_vm_open(struct vm_area_struct *vma) diff --git a/drivers/gpu/drm/gma500/gem.c b/drivers/gpu/drm/gma500/gem.c index 913bf4c256fa..576f1b272f23 100644 --- a/drivers/gpu/drm/gma500/gem.c +++ b/drivers/gpu/drm/gma500/gem.c @@ -134,12 +134,13 @@ int psb_gem_dumb_create(struct drm_file *file, struct drm_device *dev, * vma->vm_private_data points to the GEM object that is backing this * mapping. */ -int psb_gem_fault(struct vm_fault *vmf) +vm_fault_t psb_gem_fault(struct vm_fault *vmf) { struct vm_area_struct *vma = vmf->vma; struct drm_gem_object *obj; struct gtt_range *r; - int ret; + int err; + vm_fault_t ret; unsigned long pfn; pgoff_t page_offset; struct drm_device *dev; @@ -158,9 +159,10 @@ int psb_gem_fault(struct vm_fault *vmf) /* For now the mmap pins the object and it stays pinned. As things stand that will do us no harm */ if (r->mmapping == 0) { - ret = psb_gtt_pin(r); - if (ret < 0) { - dev_err(dev->dev, "gma500: pin failed: %d\n", ret); + err = psb_gtt_pin(r); + if (err < 0) { + dev_err(dev->dev, "gma500: pin failed: %d\n", err); + ret = vmf_error(err); goto fail; } r->mmapping = 1; @@ -175,18 +177,9 @@ int psb_gem_fault(struct vm_fault *vmf) pfn = (dev_priv->stolen_base + r->offset) >> PAGE_SHIFT; else pfn = page_to_pfn(r->pages[page_offset]); - ret = vm_insert_pfn(vma, vmf->address, pfn); - + ret = vmf_insert_pfn(vma, vmf->address, pfn); fail: mutex_unlock(&dev_priv->mmap_mutex); - switch (ret) { - case 0: - case -ERESTARTSYS: - case -EINTR: - return VM_FAULT_NOPAGE; - case -ENOMEM: - return VM_FAULT_OOM; - default: - return VM_FAULT_SIGBUS; - } + + return ret; } diff --git a/drivers/gpu/drm/gma500/psb_drv.h b/drivers/gpu/drm/gma500/psb_drv.h index e8300f509023..93d2f4000d2f 100644 --- a/drivers/gpu/drm/gma500/psb_drv.h +++ b/drivers/gpu/drm/gma500/psb_drv.h @@ -21,6 +21,7 @@ #define _PSB_DRV_H_ #include <linux/kref.h> +#include <linux/mm_types.h> #include <drm/drmP.h> #include <drm/drm_global.h> @@ -749,7 +750,7 @@ extern int psb_gem_get_aperture(struct drm_device *dev, void *data, struct drm_file *file); extern int psb_gem_dumb_create(struct drm_file *file, struct drm_device *dev, struct drm_mode_create_dumb *args); -extern int psb_gem_fault(struct vm_fault *vmf); +extern vm_fault_t psb_gem_fault(struct vm_fault *vmf); /* psb_device.c */ extern const struct psb_ops psb_chip_ops; diff --git a/drivers/gpu/drm/i915/i915_utils.h b/drivers/gpu/drm/i915/i915_utils.h index 00165ad55fb3..395dd2511568 100644 --- a/drivers/gpu/drm/i915/i915_utils.h +++ b/drivers/gpu/drm/i915/i915_utils.h @@ -43,7 +43,7 @@ #define MISSING_CASE(x) WARN(1, "Missing case (%s == %ld)\n", \ __stringify(x), (long)(x)) -#if GCC_VERSION >= 70000 +#if defined(GCC_VERSION) && GCC_VERSION >= 70000 #define add_overflows(A, B) \ __builtin_add_overflow_p((A), (B), (typeof((A) + (B)))0) #else diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index 5b5d0a24e713..97964f7f2ace 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -1385,6 +1385,9 @@ static const struct panel_desc innolux_tv123wam = { .width = 259, .height = 173, }, + .delay = { + .unprepare = 500, + }, }; static const struct drm_display_mode innolux_zj070na_01p_mode = { diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index ccf42663a908..81da17a42dc9 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig @@ -1320,6 +1320,16 @@ config SENSORS_PWM_FAN This driver can also be built as a module. If so, the module will be called pwm-fan. +config SENSORS_RASPBERRYPI_HWMON + tristate "Raspberry Pi voltage monitor" + depends on RASPBERRYPI_FIRMWARE || (COMPILE_TEST && !RASPBERRYPI_FIRMWARE) + help + If you say yes here you get support for voltage sensor on the + Raspberry Pi. + + This driver can also be built as a module. If so, the module + will be called raspberrypi-hwmon. + config SENSORS_SHT15 tristate "Sensiron humidity and temperature sensors. SHT15 and compat." depends on GPIOLIB || COMPILE_TEST diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index 842c92f83ce6..93f7f41ea4ad 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile @@ -143,6 +143,7 @@ obj-$(CONFIG_SENSORS_PC87427) += pc87427.o obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o obj-$(CONFIG_SENSORS_POWR1220) += powr1220.o obj-$(CONFIG_SENSORS_PWM_FAN) += pwm-fan.o +obj-$(CONFIG_SENSORS_RASPBERRYPI_HWMON) += raspberrypi-hwmon.o obj-$(CONFIG_SENSORS_S3C) += s3c-hwmon.o obj-$(CONFIG_SENSORS_SCH56XX_COMMON)+= sch56xx-common.o obj-$(CONFIG_SENSORS_SCH5627) += sch5627.o diff --git a/drivers/hwmon/raspberrypi-hwmon.c b/drivers/hwmon/raspberrypi-hwmon.c new file mode 100644 index 000000000000..fb4e4a6bb1f6 --- /dev/null +++ b/drivers/hwmon/raspberrypi-hwmon.c @@ -0,0 +1,166 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Raspberry Pi voltage sensor driver + * + * Based on firmware/raspberrypi.c by Noralf Trønnes + * + * Copyright (C) 2018 Stefan Wahren <stefan.wahren@i2se.com> + */ +#include <linux/device.h> +#include <linux/err.h> +#include <linux/hwmon.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/workqueue.h> +#include <soc/bcm2835/raspberrypi-firmware.h> + +#define UNDERVOLTAGE_STICKY_BIT BIT(16) + +struct rpi_hwmon_data { + struct device *hwmon_dev; + struct rpi_firmware *fw; + u32 last_throttled; + struct delayed_work get_values_poll_work; +}; + +static void rpi_firmware_get_throttled(struct rpi_hwmon_data *data) +{ + u32 new_uv, old_uv, value; + int ret; + + /* Request firmware to clear sticky bits */ + value = 0xffff; + + ret = rpi_firmware_property(data->fw, RPI_FIRMWARE_GET_THROTTLED, + &value, sizeof(value)); + if (ret) { + dev_err_once(data->hwmon_dev, "Failed to get throttled (%d)\n", + ret); + return; + } + + new_uv = value & UNDERVOLTAGE_STICKY_BIT; + old_uv = data->last_throttled & UNDERVOLTAGE_STICKY_BIT; + data->last_throttled = value; + + if (new_uv == old_uv) + return; + + if (new_uv) + dev_crit(data->hwmon_dev, "Undervoltage detected!\n"); + else + dev_info(data->hwmon_dev, "Voltage normalised\n"); + + sysfs_notify(&data->hwmon_dev->kobj, NULL, "in0_lcrit_alarm"); +} + +static void get_values_poll(struct work_struct *work) +{ + struct rpi_hwmon_data *data; + + data = container_of(work, struct rpi_hwmon_data, + get_values_poll_work.work); + + rpi_firmware_get_throttled(data); + + /* + * We can't run faster than the sticky shift (100ms) since we get + * flipping in the sticky bits that are cleared. + */ + schedule_delayed_work(&data->get_values_poll_work, 2 * HZ); +} + +static int rpi_read(struct device *dev, enum hwmon_sensor_types type, + u32 attr, int channel, long *val) +{ + struct rpi_hwmon_data *data = dev_get_drvdata(dev); + + *val = !!(data->last_throttled & UNDERVOLTAGE_STICKY_BIT); + return 0; +} + +static umode_t rpi_is_visible(const void *_data, enum hwmon_sensor_types type, + u32 attr, int channel) +{ + return 0444; +} + +static const u32 rpi_in_config[] = { + HWMON_I_LCRIT_ALARM, + 0 +}; + +static const struct hwmon_channel_info rpi_in = { + .type = hwmon_in, + .config = rpi_in_config, +}; + +static const struct hwmon_channel_info *rpi_info[] = { + &rpi_in, + NULL +}; + +static const struct hwmon_ops rpi_hwmon_ops = { + .is_visible = rpi_is_visible, + .read = rpi_read, +}; + +static const struct hwmon_chip_info rpi_chip_info = { + .ops = &rpi_hwmon_ops, + .info = rpi_info, +}; + +static int rpi_hwmon_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct rpi_hwmon_data *data; + int ret; + + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + /* Parent driver assure that firmware is correct */ + data->fw = dev_get_drvdata(dev->parent); + + /* Init throttled */ + ret = rpi_firmware_property(data->fw, RPI_FIRMWARE_GET_THROTTLED, + &data->last_throttled, + sizeof(data->last_throttled)); + + data->hwmon_dev = devm_hwmon_device_register_with_info(dev, "rpi_volt", + data, + &rpi_chip_info, + NULL); + + INIT_DELAYED_WORK(&data->get_values_poll_work, get_values_poll); + platform_set_drvdata(pdev, data); + + if (!PTR_ERR_OR_ZERO(data->hwmon_dev)) + schedule_delayed_work(&data->get_values_poll_work, 2 * HZ); + + return PTR_ERR_OR_ZERO(data->hwmon_dev); +} + +static int rpi_hwmon_remove(struct platform_device *pdev) +{ + struct rpi_hwmon_data *data = platform_get_drvdata(pdev); + + cancel_delayed_work_sync(&data->get_values_poll_work); + + return 0; +} + +static struct platform_driver rpi_hwmon_driver = { + .probe = rpi_hwmon_probe, + .remove = rpi_hwmon_remove, + .driver = { + .name = "raspberrypi-hwmon", + }, +}; +module_platform_driver(rpi_hwmon_driver); + +MODULE_AUTHOR("Stefan Wahren <stefan.wahren@i2se.com>"); +MODULE_DESCRIPTION("Raspberry Pi voltage sensor driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/hwtracing/intel_th/msu.c b/drivers/hwtracing/intel_th/msu.c index 634f58042c77..d293e55553bd 100644 --- a/drivers/hwtracing/intel_th/msu.c +++ b/drivers/hwtracing/intel_th/msu.c @@ -1182,7 +1182,7 @@ static void msc_mmap_close(struct vm_area_struct *vma) mutex_unlock(&msc->buf_mutex); } -static int msc_mmap_fault(struct vm_fault *vmf) +static vm_fault_t msc_mmap_fault(struct vm_fault *vmf) { struct msc_iter *iter = vmf->vma->vm_file->private_data; struct msc *msc = iter->msc; diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index 72c94c60fdd1..bed6ba63c983 100644 --- a/drivers/i2c/Makefile +++ b/drivers/i2c/Makefile @@ -18,4 +18,3 @@ obj-$(CONFIG_I2C_STUB) += i2c-stub.o obj-$(CONFIG_I2C_SLAVE_EEPROM) += i2c-slave-eeprom.o ccflags-$(CONFIG_I2C_DEBUG_CORE) := -DDEBUG -CFLAGS_i2c-core-base.o := -Wno-deprecated-declarations diff --git a/drivers/i2c/busses/i2c-emev2.c b/drivers/i2c/busses/i2c-emev2.c index ba9b6ea48a31..35b302d983e0 100644 --- a/drivers/i2c/busses/i2c-emev2.c +++ b/drivers/i2c/busses/i2c-emev2.c @@ -1,13 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0 /* * I2C driver for the Renesas EMEV2 SoC * * Copyright (C) 2015 Wolfram Sang <wsa@sang-engineering.com> * Copyright 2013 Codethink Ltd. * Copyright 2010-2015 Renesas Electronics Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. */ #include <linux/clk.h> diff --git a/drivers/i2c/busses/i2c-highlander.c b/drivers/i2c/busses/i2c-highlander.c index 56dc69e7349f..ff340d7ae2e5 100644 --- a/drivers/i2c/busses/i2c-highlander.c +++ b/drivers/i2c/busses/i2c-highlander.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Renesas Solutions Highlander FPGA I2C/SMBus support. * @@ -6,10 +7,6 @@ * Copyright (C) 2008 Paul Mundt * Copyright (C) 2008 Renesas Solutions Corp. * Copyright (C) 2008 Atom Create Engineering Co., Ltd. - * - * This file is subject to the terms and conditions of the GNU General - * Public License version 2. See the file "COPYING" in the main directory - * of this archive for more details. */ #include <linux/module.h> #include <linux/interrupt.h> diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c index 88444ef74943..87f9caacba85 100644 --- a/drivers/i2c/busses/i2c-ocores.c +++ b/drivers/i2c/busses/i2c-ocores.c @@ -2,7 +2,7 @@ * i2c-ocores.c: I2C bus driver for OpenCores I2C controller * (https://opencores.org/project/i2c/overview) * - * Peter Korsgaard <jacmet@sunsite.dk> + * Peter Korsgaard <peter@korsgaard.com> * * Support for the GRLIB port of the controller by * Andreas Larsson <andreas@gaisler.com> @@ -576,7 +576,7 @@ static struct platform_driver ocores_i2c_driver = { module_platform_driver(ocores_i2c_driver); -MODULE_AUTHOR("Peter Korsgaard <jacmet@sunsite.dk>"); +MODULE_AUTHOR("Peter Korsgaard <peter@korsgaard.com>"); MODULE_DESCRIPTION("OpenCores I2C bus driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:ocores-i2c"); diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c index 43ad933df0f0..52cf42b32f0a 100644 --- a/drivers/i2c/busses/i2c-rcar.c +++ b/drivers/i2c/busses/i2c-rcar.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Driver for the Renesas R-Car I2C unit * @@ -9,15 +10,6 @@ * * This file is based on the drivers/i2c/busses/i2c-sh7760.c * (c) 2005-2008 MSC Vertriebsges.m.b.H, Manuel Lauss <mlau@msc-ge.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include <linux/bitops.h> #include <linux/clk.h> diff --git a/drivers/i2c/busses/i2c-riic.c b/drivers/i2c/busses/i2c-riic.c index 5f1fca7880b1..b75ff144b570 100644 --- a/drivers/i2c/busses/i2c-riic.c +++ b/drivers/i2c/busses/i2c-riic.c @@ -1,12 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Renesas RIIC driver * * Copyright (C) 2013 Wolfram Sang <wsa@sang-engineering.com> * Copyright (C) 2013 Renesas Solutions Corp. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. */ /* diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index 9c7f6f8ceb22..439e8778f849 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * SuperH Mobile I2C Controller * @@ -7,15 +8,6 @@ * * Portions of the code based on out-of-tree driver i2c-sh7343.c * Copyright (c) 2006 Carlos Munoz <carlos@kenati.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include <linux/clk.h> diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c index 5a937109a289..f15737763608 100644 --- a/drivers/i2c/i2c-core-base.c +++ b/drivers/i2c/i2c-core-base.c @@ -62,7 +62,7 @@ /* * core_lock protects i2c_adapter_idr, and guarantees that device detection, - * deletion of detected devices, and attach_adapter calls are serialized + * deletion of detected devices are serialized */ static DEFINE_MUTEX(core_lock); static DEFINE_IDR(i2c_adapter_idr); @@ -1124,15 +1124,6 @@ static int i2c_do_add_adapter(struct i2c_driver *driver, /* Detect supported devices on that bus, and instantiate them */ i2c_detect(adap, driver); - /* Let legacy drivers scan this bus for matching devices */ - if (driver->attach_adapter) { - dev_warn(&adap->dev, "%s: attach_adapter method is deprecated\n", - driver->driver.name); - dev_warn(&adap->dev, - "Please use another way to instantiate your i2c_client\n"); - /* We ignore the return code; if it fails, too bad */ - driver->attach_adapter(adap); - } return 0; } diff --git a/drivers/iio/dac/ltc2632.c b/drivers/iio/dac/ltc2632.c index 28e9b7656b20..15d498fc4758 100644 --- a/drivers/iio/dac/ltc2632.c +++ b/drivers/iio/dac/ltc2632.c @@ -1,7 +1,7 @@ /* * LTC2632 Digital to analog convertors spi driver * - * Copyright 2017 Maxime Roussin-Bélanger + * Copyright 2017 Maxime Roussin-Bélanger * expanded by Silvan Murer <silvan.murer@gmail.com> * * Licensed under the GPL-2. diff --git a/drivers/infiniband/Kconfig b/drivers/infiniband/Kconfig index d160d2d1f3a3..abb6660c099c 100644 --- a/drivers/infiniband/Kconfig +++ b/drivers/infiniband/Kconfig @@ -36,7 +36,7 @@ config INFINIBAND_USER_ACCESS rdma-core <https://github.com/linux-rdma/rdma-core>. config INFINIBAND_USER_ACCESS_UCM - bool "Userspace CM (UCM, DEPRECATED)" + tristate "Userspace CM (UCM, DEPRECATED)" depends on BROKEN || COMPILE_TEST depends on INFINIBAND_USER_ACCESS help diff --git a/drivers/infiniband/hw/hfi1/affinity.c b/drivers/infiniband/hw/hfi1/affinity.c index fbe7198a715a..bedd5fba33b0 100644 --- a/drivers/infiniband/hw/hfi1/affinity.c +++ b/drivers/infiniband/hw/hfi1/affinity.c @@ -198,7 +198,7 @@ int node_affinity_init(void) while ((dev = pci_get_device(ids->vendor, ids->device, dev))) { node = pcibus_to_node(dev->bus); if (node < 0) - node = numa_node_id(); + goto out; hfi1_per_node_cntr[node]++; } @@ -206,6 +206,18 @@ int node_affinity_init(void) } return 0; + +out: + /* + * Invalid PCI NUMA node information found, note it, and populate + * our database 1:1. + */ + pr_err("HFI: Invalid PCI NUMA node. Performance may be affected\n"); + pr_err("HFI: System BIOS may need to be upgraded\n"); + for (node = 0; node < node_affinity.num_possible_nodes; node++) + hfi1_per_node_cntr[node] = 1; + + return 0; } static void node_affinity_destroy(struct hfi1_affinity_node *entry) @@ -622,8 +634,14 @@ int hfi1_dev_affinity_init(struct hfi1_devdata *dd) int curr_cpu, possible, i, ret; bool new_entry = false; - if (node < 0) - node = numa_node_id(); + /* + * If the BIOS does not have the NUMA node information set, select + * NUMA 0 so we get consistent performance. + */ + if (node < 0) { + dd_dev_err(dd, "Invalid PCI NUMA node. Performance may be affected\n"); + node = 0; + } dd->node = node; local_mask = cpumask_of_node(dd->node); diff --git a/drivers/input/serio/ams_delta_serio.c b/drivers/input/serio/ams_delta_serio.c index 3df501c3421b..f8663d7891f2 100644 --- a/drivers/input/serio/ams_delta_serio.c +++ b/drivers/input/serio/ams_delta_serio.c @@ -20,32 +20,33 @@ * However, when used with the E3 mailboard that producecs non-standard * scancodes, a custom key table must be prepared and loaded from userspace. */ -#include <linux/gpio.h> #include <linux/irq.h> +#include <linux/platform_data/ams-delta-fiq.h> +#include <linux/platform_device.h> +#include <linux/regulator/consumer.h> #include <linux/serio.h> #include <linux/slab.h> #include <linux/module.h> -#include <asm/mach-types.h> -#include <mach/board-ams-delta.h> - -#include <mach/ams-delta-fiq.h> +#define DRIVER_NAME "ams-delta-serio" MODULE_AUTHOR("Matt Callow"); MODULE_DESCRIPTION("AMS Delta (E3) keyboard port driver"); MODULE_LICENSE("GPL"); -static struct serio *ams_delta_serio; +struct ams_delta_serio { + struct serio *serio; + struct regulator *vcc; + unsigned int *fiq_buffer; +}; -static int check_data(int data) +static int check_data(struct serio *serio, int data) { int i, parity = 0; /* check valid stop bit */ if (!(data & 0x400)) { - dev_warn(&ams_delta_serio->dev, - "invalid stop bit, data=0x%X\n", - data); + dev_warn(&serio->dev, "invalid stop bit, data=0x%X\n", data); return SERIO_FRAME; } /* calculate the parity */ @@ -55,9 +56,9 @@ static int check_data(int data) } /* it should be odd */ if (!(parity & 0x01)) { - dev_warn(&ams_delta_serio->dev, - "parity check failed, data=0x%X parity=0x%X\n", - data, parity); + dev_warn(&serio->dev, + "parity check failed, data=0x%X parity=0x%X\n", data, + parity); return SERIO_PARITY; } return 0; @@ -65,127 +66,130 @@ static int check_data(int data) static irqreturn_t ams_delta_serio_interrupt(int irq, void *dev_id) { - int *circ_buff = &fiq_buffer[FIQ_CIRC_BUFF]; + struct ams_delta_serio *priv = dev_id; + int *circ_buff = &priv->fiq_buffer[FIQ_CIRC_BUFF]; int data, dfl; u8 scancode; - fiq_buffer[FIQ_IRQ_PEND] = 0; + priv->fiq_buffer[FIQ_IRQ_PEND] = 0; /* * Read data from the circular buffer, check it * and then pass it on the serio */ - while (fiq_buffer[FIQ_KEYS_CNT] > 0) { + while (priv->fiq_buffer[FIQ_KEYS_CNT] > 0) { - data = circ_buff[fiq_buffer[FIQ_HEAD_OFFSET]++]; - fiq_buffer[FIQ_KEYS_CNT]--; - if (fiq_buffer[FIQ_HEAD_OFFSET] == fiq_buffer[FIQ_BUF_LEN]) - fiq_buffer[FIQ_HEAD_OFFSET] = 0; + data = circ_buff[priv->fiq_buffer[FIQ_HEAD_OFFSET]++]; + priv->fiq_buffer[FIQ_KEYS_CNT]--; + if (priv->fiq_buffer[FIQ_HEAD_OFFSET] == + priv->fiq_buffer[FIQ_BUF_LEN]) + priv->fiq_buffer[FIQ_HEAD_OFFSET] = 0; - dfl = check_data(data); + dfl = check_data(priv->serio, data); scancode = (u8) (data >> 1) & 0xFF; - serio_interrupt(ams_delta_serio, scancode, dfl); + serio_interrupt(priv->serio, scancode, dfl); } return IRQ_HANDLED; } static int ams_delta_serio_open(struct serio *serio) { - /* enable keyboard */ - gpio_set_value(AMS_DELTA_GPIO_PIN_KEYBRD_PWR, 1); + struct ams_delta_serio *priv = serio->port_data; - return 0; + /* enable keyboard */ + return regulator_enable(priv->vcc); } static void ams_delta_serio_close(struct serio *serio) { + struct ams_delta_serio *priv = serio->port_data; + /* disable keyboard */ - gpio_set_value(AMS_DELTA_GPIO_PIN_KEYBRD_PWR, 0); + regulator_disable(priv->vcc); } -static const struct gpio ams_delta_gpios[] __initconst_or_module = { - { - .gpio = AMS_DELTA_GPIO_PIN_KEYBRD_DATA, - .flags = GPIOF_DIR_IN, - .label = "serio-data", - }, - { - .gpio = AMS_DELTA_GPIO_PIN_KEYBRD_CLK, - .flags = GPIOF_DIR_IN, - .label = "serio-clock", - }, - { - .gpio = AMS_DELTA_GPIO_PIN_KEYBRD_PWR, - .flags = GPIOF_OUT_INIT_LOW, - .label = "serio-power", - }, - { - .gpio = AMS_DELTA_GPIO_PIN_KEYBRD_DATAOUT, - .flags = GPIOF_OUT_INIT_LOW, - .label = "serio-dataout", - }, -}; - -static int __init ams_delta_serio_init(void) +static int ams_delta_serio_init(struct platform_device *pdev) { - int err; - - if (!machine_is_ams_delta()) - return -ENODEV; + struct ams_delta_serio *priv; + struct serio *serio; + int irq, err; - ams_delta_serio = kzalloc(sizeof(struct serio), GFP_KERNEL); - if (!ams_delta_serio) + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) return -ENOMEM; - ams_delta_serio->id.type = SERIO_8042; - ams_delta_serio->open = ams_delta_serio_open; - ams_delta_serio->close = ams_delta_serio_close; - strlcpy(ams_delta_serio->name, "AMS DELTA keyboard adapter", - sizeof(ams_delta_serio->name)); - strlcpy(ams_delta_serio->phys, "GPIO/serio0", - sizeof(ams_delta_serio->phys)); - - err = gpio_request_array(ams_delta_gpios, - ARRAY_SIZE(ams_delta_gpios)); - if (err) { - pr_err("ams_delta_serio: Couldn't request gpio pins\n"); - goto serio; + priv->fiq_buffer = pdev->dev.platform_data; + if (!priv->fiq_buffer) + return -EINVAL; + + priv->vcc = devm_regulator_get(&pdev->dev, "vcc"); + if (IS_ERR(priv->vcc)) { + err = PTR_ERR(priv->vcc); + dev_err(&pdev->dev, "regulator request failed (%d)\n", err); + /* + * When running on a non-dt platform and requested regulator + * is not available, devm_regulator_get() never returns + * -EPROBE_DEFER as it is not able to justify if the regulator + * may still appear later. On the other hand, the board can + * still set full constriants flag at late_initcall in order + * to instruct devm_regulator_get() to returnn a dummy one + * if sufficient. Hence, if we get -ENODEV here, let's convert + * it to -EPROBE_DEFER and wait for the board to decide or + * let Deferred Probe infrastructure handle this error. + */ + if (err == -ENODEV) + err = -EPROBE_DEFER; + return err; } - err = request_irq(gpio_to_irq(AMS_DELTA_GPIO_PIN_KEYBRD_CLK), - ams_delta_serio_interrupt, IRQ_TYPE_EDGE_RISING, - "ams-delta-serio", 0); + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return -ENXIO; + + err = devm_request_irq(&pdev->dev, irq, ams_delta_serio_interrupt, + IRQ_TYPE_EDGE_RISING, DRIVER_NAME, priv); if (err < 0) { - pr_err("ams_delta_serio: couldn't request gpio interrupt %d\n", - gpio_to_irq(AMS_DELTA_GPIO_PIN_KEYBRD_CLK)); - goto gpio; + dev_err(&pdev->dev, "IRQ request failed (%d)\n", err); + return err; } - /* - * Since GPIO register handling for keyboard clock pin is performed - * at FIQ level, switch back from edge to simple interrupt handler - * to avoid bad interaction. - */ - irq_set_handler(gpio_to_irq(AMS_DELTA_GPIO_PIN_KEYBRD_CLK), - handle_simple_irq); - serio_register_port(ams_delta_serio); - dev_info(&ams_delta_serio->dev, "%s\n", ams_delta_serio->name); + serio = kzalloc(sizeof(*serio), GFP_KERNEL); + if (!serio) + return -ENOMEM; + + priv->serio = serio; + + serio->id.type = SERIO_8042; + serio->open = ams_delta_serio_open; + serio->close = ams_delta_serio_close; + strlcpy(serio->name, "AMS DELTA keyboard adapter", sizeof(serio->name)); + strlcpy(serio->phys, dev_name(&pdev->dev), sizeof(serio->phys)); + serio->dev.parent = &pdev->dev; + serio->port_data = priv; + + serio_register_port(serio); + + platform_set_drvdata(pdev, priv); + + dev_info(&serio->dev, "%s\n", serio->name); return 0; -gpio: - gpio_free_array(ams_delta_gpios, - ARRAY_SIZE(ams_delta_gpios)); -serio: - kfree(ams_delta_serio); - return err; } -module_init(ams_delta_serio_init); -static void __exit ams_delta_serio_exit(void) +static int ams_delta_serio_exit(struct platform_device *pdev) { - serio_unregister_port(ams_delta_serio); - free_irq(gpio_to_irq(AMS_DELTA_GPIO_PIN_KEYBRD_CLK), 0); - gpio_free_array(ams_delta_gpios, - ARRAY_SIZE(ams_delta_gpios)); + struct ams_delta_serio *priv = platform_get_drvdata(pdev); + + serio_unregister_port(priv->serio); + + return 0; } -module_exit(ams_delta_serio_exit); + +static struct platform_driver ams_delta_serio_driver = { + .probe = ams_delta_serio_init, + .remove = ams_delta_serio_exit, + .driver = { + .name = DRIVER_NAME + }, +}; +module_platform_driver(ams_delta_serio_driver); diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig index 689ffe538370..c60395b7470f 100644 --- a/drivers/iommu/Kconfig +++ b/drivers/iommu/Kconfig @@ -60,6 +60,27 @@ config IOMMU_IO_PGTABLE_ARMV7S_SELFTEST endmenu +config IOMMU_DEBUGFS + bool "Export IOMMU internals in DebugFS" + depends on DEBUG_FS + help + Allows exposure of IOMMU device internals. This option enables + the use of debugfs by IOMMU drivers as required. Devices can, + at initialization time, cause the IOMMU code to create a top-level + debug/iommu directory, and then populate a subdirectory with + entries as required. + +config IOMMU_DEFAULT_PASSTHROUGH + bool "IOMMU passthrough by default" + depends on IOMMU_API + help + Enable passthrough by default, removing the need to pass in + iommu.passthrough=on or iommu=pt through command line. If this + is enabled, you can still disable with iommu.passthrough=off + or iommu=nopt depending on the architecture. + + If unsure, say N here. + config IOMMU_IOVA tristate @@ -135,6 +156,18 @@ config AMD_IOMMU_V2 hardware. Select this option if you want to use devices that support the PCI PRI and PASID interface. +config AMD_IOMMU_DEBUGFS + bool "Enable AMD IOMMU internals in DebugFS" + depends on AMD_IOMMU && IOMMU_DEBUGFS + ---help--- + !!!WARNING!!! !!!WARNING!!! !!!WARNING!!! !!!WARNING!!! + + DO NOT ENABLE THIS OPTION UNLESS YOU REALLY, -REALLY- KNOW WHAT YOU ARE DOING!!! + Exposes AMD IOMMU device internals in DebugFS. + + This option is -NOT- intended for production environments, and should + not generally be enabled. + # Intel IOMMU support config DMAR_TABLE bool @@ -284,8 +317,8 @@ config IPMMU_VMSA select IOMMU_IO_PGTABLE_LPAE select ARM_DMA_USE_IOMMU help - Support for the Renesas VMSA-compatible IPMMU Renesas found in the - R-Mobile APE6 and R-Car H2/M2 SoCs. + Support for the Renesas VMSA-compatible IPMMU found in the R-Mobile + APE6, R-Car Gen2, and R-Car Gen3 SoCs. If unsure, say N. diff --git a/drivers/iommu/Makefile b/drivers/iommu/Makefile index 1fb695854809..ab5eba6edf82 100644 --- a/drivers/iommu/Makefile +++ b/drivers/iommu/Makefile @@ -2,6 +2,7 @@ obj-$(CONFIG_IOMMU_API) += iommu.o obj-$(CONFIG_IOMMU_API) += iommu-traces.o obj-$(CONFIG_IOMMU_API) += iommu-sysfs.o +obj-$(CONFIG_IOMMU_DEBUGFS) += iommu-debugfs.o obj-$(CONFIG_IOMMU_DMA) += dma-iommu.o obj-$(CONFIG_IOMMU_IO_PGTABLE) += io-pgtable.o obj-$(CONFIG_IOMMU_IO_PGTABLE_ARMV7S) += io-pgtable-arm-v7s.o @@ -10,11 +11,12 @@ obj-$(CONFIG_IOMMU_IOVA) += iova.o obj-$(CONFIG_OF_IOMMU) += of_iommu.o obj-$(CONFIG_MSM_IOMMU) += msm_iommu.o obj-$(CONFIG_AMD_IOMMU) += amd_iommu.o amd_iommu_init.o +obj-$(CONFIG_AMD_IOMMU_DEBUGFS) += amd_iommu_debugfs.o obj-$(CONFIG_AMD_IOMMU_V2) += amd_iommu_v2.o obj-$(CONFIG_ARM_SMMU) += arm-smmu.o obj-$(CONFIG_ARM_SMMU_V3) += arm-smmu-v3.o obj-$(CONFIG_DMAR_TABLE) += dmar.o -obj-$(CONFIG_INTEL_IOMMU) += intel-iommu.o +obj-$(CONFIG_INTEL_IOMMU) += intel-iommu.o intel-pasid.o obj-$(CONFIG_INTEL_IOMMU_SVM) += intel-svm.o obj-$(CONFIG_IPMMU_VMSA) += ipmmu-vmsa.o obj-$(CONFIG_IRQ_REMAP) += intel_irq_remapping.o irq_remapping.o diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c index 60b2eab29cd8..4e04fff23977 100644 --- a/drivers/iommu/amd_iommu.c +++ b/drivers/iommu/amd_iommu.c @@ -1404,6 +1404,8 @@ static u64 *fetch_pte(struct protection_domain *domain, int level; u64 *pte; + *page_size = 0; + if (address > PM_LEVEL_SIZE(domain->mode)) return NULL; @@ -1944,12 +1946,6 @@ static int __attach_device(struct iommu_dev_data *dev_data, { int ret; - /* - * Must be called with IRQs disabled. Warn here to detect early - * when its not. - */ - WARN_ON(!irqs_disabled()); - /* lock domain */ spin_lock(&domain->lock); @@ -2115,12 +2111,6 @@ static void __detach_device(struct iommu_dev_data *dev_data) { struct protection_domain *domain; - /* - * Must be called with IRQs disabled. Warn here to detect early - * when its not. - */ - WARN_ON(!irqs_disabled()); - domain = dev_data->domain; spin_lock(&domain->lock); @@ -2405,9 +2395,9 @@ static void __unmap_single(struct dma_ops_domain *dma_dom, } if (amd_iommu_unmap_flush) { - dma_ops_free_iova(dma_dom, dma_addr, pages); domain_flush_tlb(&dma_dom->domain); domain_flush_complete(&dma_dom->domain); + dma_ops_free_iova(dma_dom, dma_addr, pages); } else { pages = __roundup_pow_of_two(pages); queue_iova(&dma_dom->iovad, dma_addr >> PAGE_SHIFT, pages, 0); @@ -3192,7 +3182,6 @@ const struct iommu_ops amd_iommu_ops = { .detach_dev = amd_iommu_detach_device, .map = amd_iommu_map, .unmap = amd_iommu_unmap, - .map_sg = default_iommu_map_sg, .iova_to_phys = amd_iommu_iova_to_phys, .add_device = amd_iommu_add_device, .remove_device = amd_iommu_remove_device, @@ -3874,7 +3863,8 @@ static void irte_ga_prepare(void *entry, irte->lo.fields_remap.int_type = delivery_mode; irte->lo.fields_remap.dm = dest_mode; irte->hi.fields.vector = vector; - irte->lo.fields_remap.destination = dest_apicid; + irte->lo.fields_remap.destination = APICID_TO_IRTE_DEST_LO(dest_apicid); + irte->hi.fields.destination = APICID_TO_IRTE_DEST_HI(dest_apicid); irte->lo.fields_remap.valid = 1; } @@ -3927,7 +3917,10 @@ static void irte_ga_set_affinity(void *entry, u16 devid, u16 index, if (!irte->lo.fields_remap.guest_mode) { irte->hi.fields.vector = vector; - irte->lo.fields_remap.destination = dest_apicid; + irte->lo.fields_remap.destination = + APICID_TO_IRTE_DEST_LO(dest_apicid); + irte->hi.fields.destination = + APICID_TO_IRTE_DEST_HI(dest_apicid); modify_irte_ga(devid, index, irte, NULL); } } @@ -4344,7 +4337,10 @@ static int amd_ir_set_vcpu_affinity(struct irq_data *data, void *vcpu_info) irte->lo.val = 0; irte->hi.fields.vector = cfg->vector; irte->lo.fields_remap.guest_mode = 0; - irte->lo.fields_remap.destination = cfg->dest_apicid; + irte->lo.fields_remap.destination = + APICID_TO_IRTE_DEST_LO(cfg->dest_apicid); + irte->hi.fields.destination = + APICID_TO_IRTE_DEST_HI(cfg->dest_apicid); irte->lo.fields_remap.int_type = apic->irq_delivery_mode; irte->lo.fields_remap.dm = apic->irq_dest_mode; @@ -4461,8 +4457,12 @@ int amd_iommu_update_ga(int cpu, bool is_run, void *data) raw_spin_lock_irqsave(&table->lock, flags); if (ref->lo.fields_vapic.guest_mode) { - if (cpu >= 0) - ref->lo.fields_vapic.destination = cpu; + if (cpu >= 0) { + ref->lo.fields_vapic.destination = + APICID_TO_IRTE_DEST_LO(cpu); + ref->hi.fields.destination = + APICID_TO_IRTE_DEST_HI(cpu); + } ref->lo.fields_vapic.is_run = is_run; barrier(); } diff --git a/drivers/iommu/amd_iommu_debugfs.c b/drivers/iommu/amd_iommu_debugfs.c new file mode 100644 index 000000000000..c6a5c737ef09 --- /dev/null +++ b/drivers/iommu/amd_iommu_debugfs.c @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * AMD IOMMU driver + * + * Copyright (C) 2018 Advanced Micro Devices, Inc. + * + * Author: Gary R Hook <gary.hook@amd.com> + */ + +#include <linux/debugfs.h> +#include <linux/iommu.h> +#include <linux/pci.h> +#include "amd_iommu_proto.h" +#include "amd_iommu_types.h" + +static struct dentry *amd_iommu_debugfs; +static DEFINE_MUTEX(amd_iommu_debugfs_lock); + +#define MAX_NAME_LEN 20 + +void amd_iommu_debugfs_setup(struct amd_iommu *iommu) +{ + char name[MAX_NAME_LEN + 1]; + + mutex_lock(&amd_iommu_debugfs_lock); + if (!amd_iommu_debugfs) + amd_iommu_debugfs = debugfs_create_dir("amd", + iommu_debugfs_dir); + mutex_unlock(&amd_iommu_debugfs_lock); + + snprintf(name, MAX_NAME_LEN, "iommu%02d", iommu->index); + iommu->debugfs = debugfs_create_dir(name, amd_iommu_debugfs); +} diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c index 904c575d1677..84b3e4445d46 100644 --- a/drivers/iommu/amd_iommu_init.c +++ b/drivers/iommu/amd_iommu_init.c @@ -153,6 +153,7 @@ bool amd_iommu_dump; bool amd_iommu_irq_remap __read_mostly; int amd_iommu_guest_ir = AMD_IOMMU_GUEST_IR_VAPIC; +static int amd_iommu_xt_mode = IRQ_REMAP_X2APIC_MODE; static bool amd_iommu_detected; static bool __initdata amd_iommu_disabled; @@ -280,9 +281,9 @@ static void clear_translation_pre_enabled(struct amd_iommu *iommu) static void init_translation_status(struct amd_iommu *iommu) { - u32 ctrl; + u64 ctrl; - ctrl = readl(iommu->mmio_base + MMIO_CONTROL_OFFSET); + ctrl = readq(iommu->mmio_base + MMIO_CONTROL_OFFSET); if (ctrl & (1<<CONTROL_IOMMU_EN)) iommu->flags |= AMD_IOMMU_FLAG_TRANS_PRE_ENABLED; } @@ -386,30 +387,30 @@ static void iommu_set_device_table(struct amd_iommu *iommu) /* Generic functions to enable/disable certain features of the IOMMU. */ static void iommu_feature_enable(struct amd_iommu *iommu, u8 bit) { - u32 ctrl; + u64 ctrl; - ctrl = readl(iommu->mmio_base + MMIO_CONTROL_OFFSET); - ctrl |= (1 << bit); - writel(ctrl, iommu->mmio_base + MMIO_CONTROL_OFFSET); + ctrl = readq(iommu->mmio_base + MMIO_CONTROL_OFFSET); + ctrl |= (1ULL << bit); + writeq(ctrl, iommu->mmio_base + MMIO_CONTROL_OFFSET); } static void iommu_feature_disable(struct amd_iommu *iommu, u8 bit) { - u32 ctrl; + u64 ctrl; - ctrl = readl(iommu->mmio_base + MMIO_CONTROL_OFFSET); - ctrl &= ~(1 << bit); - writel(ctrl, iommu->mmio_base + MMIO_CONTROL_OFFSET); + ctrl = readq(iommu->mmio_base + MMIO_CONTROL_OFFSET); + ctrl &= ~(1ULL << bit); + writeq(ctrl, iommu->mmio_base + MMIO_CONTROL_OFFSET); } static void iommu_set_inv_tlb_timeout(struct amd_iommu *iommu, int timeout) { - u32 ctrl; + u64 ctrl; - ctrl = readl(iommu->mmio_base + MMIO_CONTROL_OFFSET); + ctrl = readq(iommu->mmio_base + MMIO_CONTROL_OFFSET); ctrl &= ~CTRL_INV_TO_MASK; ctrl |= (timeout << CONTROL_INV_TIMEOUT) & CTRL_INV_TO_MASK; - writel(ctrl, iommu->mmio_base + MMIO_CONTROL_OFFSET); + writeq(ctrl, iommu->mmio_base + MMIO_CONTROL_OFFSET); } /* Function to enable the hardware */ @@ -827,6 +828,19 @@ static int iommu_init_ga(struct amd_iommu *iommu) return ret; } +static void iommu_enable_xt(struct amd_iommu *iommu) +{ +#ifdef CONFIG_IRQ_REMAP + /* + * XT mode (32-bit APIC destination ID) requires + * GA mode (128-bit IRTE support) as a prerequisite. + */ + if (AMD_IOMMU_GUEST_IR_GA(amd_iommu_guest_ir) && + amd_iommu_xt_mode == IRQ_REMAP_X2APIC_MODE) + iommu_feature_enable(iommu, CONTROL_XT_EN); +#endif /* CONFIG_IRQ_REMAP */ +} + static void iommu_enable_gt(struct amd_iommu *iommu) { if (!iommu_feature(iommu, FEATURE_GT)) @@ -1507,6 +1521,8 @@ static int __init init_iommu_one(struct amd_iommu *iommu, struct ivhd_header *h) iommu->mmio_phys_end = MMIO_CNTR_CONF_OFFSET; if (((h->efr_attr & (0x1 << IOMMU_FEAT_GASUP_SHIFT)) == 0)) amd_iommu_guest_ir = AMD_IOMMU_GUEST_IR_LEGACY; + if (((h->efr_attr & (0x1 << IOMMU_FEAT_XTSUP_SHIFT)) == 0)) + amd_iommu_xt_mode = IRQ_REMAP_XAPIC_MODE; break; case 0x11: case 0x40: @@ -1516,6 +1532,8 @@ static int __init init_iommu_one(struct amd_iommu *iommu, struct ivhd_header *h) iommu->mmio_phys_end = MMIO_CNTR_CONF_OFFSET; if (((h->efr_reg & (0x1 << IOMMU_EFR_GASUP_SHIFT)) == 0)) amd_iommu_guest_ir = AMD_IOMMU_GUEST_IR_LEGACY; + if (((h->efr_reg & (0x1 << IOMMU_EFR_XTSUP_SHIFT)) == 0)) + amd_iommu_xt_mode = IRQ_REMAP_XAPIC_MODE; break; default: return -EINVAL; @@ -1832,6 +1850,8 @@ static void print_iommu_info(void) pr_info("AMD-Vi: Interrupt remapping enabled\n"); if (AMD_IOMMU_GUEST_IR_VAPIC(amd_iommu_guest_ir)) pr_info("AMD-Vi: virtual APIC enabled\n"); + if (amd_iommu_xt_mode == IRQ_REMAP_X2APIC_MODE) + pr_info("AMD-Vi: X2APIC enabled\n"); } } @@ -2168,6 +2188,7 @@ static void early_enable_iommu(struct amd_iommu *iommu) iommu_enable_event_buffer(iommu); iommu_set_exclusion_range(iommu); iommu_enable_ga(iommu); + iommu_enable_xt(iommu); iommu_enable(iommu); iommu_flush_all_caches(iommu); } @@ -2212,6 +2233,7 @@ static void early_enable_iommus(void) iommu_enable_command_buffer(iommu); iommu_enable_event_buffer(iommu); iommu_enable_ga(iommu); + iommu_enable_xt(iommu); iommu_set_device_table(iommu); iommu_flush_all_caches(iommu); } @@ -2691,8 +2713,7 @@ int __init amd_iommu_enable(void) return ret; irq_remapping_enabled = 1; - - return 0; + return amd_iommu_xt_mode; } void amd_iommu_disable(void) @@ -2721,6 +2742,7 @@ int __init amd_iommu_enable_faulting(void) */ static int __init amd_iommu_init(void) { + struct amd_iommu *iommu; int ret; ret = iommu_go_to_state(IOMMU_INITIALIZED); @@ -2730,14 +2752,15 @@ static int __init amd_iommu_init(void) disable_iommus(); free_iommu_resources(); } else { - struct amd_iommu *iommu; - uninit_device_table_dma(); for_each_iommu(iommu) iommu_flush_all_caches(iommu); } } + for_each_iommu(iommu) + amd_iommu_debugfs_setup(iommu); + return ret; } diff --git a/drivers/iommu/amd_iommu_proto.h b/drivers/iommu/amd_iommu_proto.h index 640c286a0ab9..a8cd0296fb16 100644 --- a/drivers/iommu/amd_iommu_proto.h +++ b/drivers/iommu/amd_iommu_proto.h @@ -33,6 +33,12 @@ extern void amd_iommu_uninit_devices(void); extern void amd_iommu_init_notifier(void); extern int amd_iommu_init_api(void); +#ifdef CONFIG_AMD_IOMMU_DEBUGFS +void amd_iommu_debugfs_setup(struct amd_iommu *iommu); +#else +static inline void amd_iommu_debugfs_setup(struct amd_iommu *iommu) {} +#endif + /* Needed for interrupt remapping */ extern int amd_iommu_prepare(void); extern int amd_iommu_enable(void); diff --git a/drivers/iommu/amd_iommu_types.h b/drivers/iommu/amd_iommu_types.h index 986cbe0cc189..e2b342e65a7b 100644 --- a/drivers/iommu/amd_iommu_types.h +++ b/drivers/iommu/amd_iommu_types.h @@ -161,6 +161,7 @@ #define CONTROL_GAM_EN 0x19ULL #define CONTROL_GALOG_EN 0x1CULL #define CONTROL_GAINT_EN 0x1DULL +#define CONTROL_XT_EN 0x32ULL #define CTRL_INV_TO_MASK (7 << CONTROL_INV_TIMEOUT) #define CTRL_INV_TO_NONE 0 @@ -378,9 +379,11 @@ #define IOMMU_CAP_EFR 27 /* IOMMU Feature Reporting Field (for IVHD type 10h */ +#define IOMMU_FEAT_XTSUP_SHIFT 0 #define IOMMU_FEAT_GASUP_SHIFT 6 /* IOMMU Extended Feature Register (EFR) */ +#define IOMMU_EFR_XTSUP_SHIFT 2 #define IOMMU_EFR_GASUP_SHIFT 7 #define MAX_DOMAIN_ID 65536 @@ -437,7 +440,6 @@ extern struct kmem_cache *amd_iommu_irq_cache; #define APERTURE_RANGE_INDEX(a) ((a) >> APERTURE_RANGE_SHIFT) #define APERTURE_PAGE_INDEX(a) (((a) >> 21) & 0x3fULL) - /* * This struct is used to pass information about * incoming PPR faults around. @@ -594,6 +596,11 @@ struct amd_iommu { u32 flags; volatile u64 __aligned(8) cmd_sem; + +#ifdef CONFIG_AMD_IOMMU_DEBUGFS + /* DebugFS Info */ + struct dentry *debugfs; +#endif }; static inline struct amd_iommu *dev_to_amd_iommu(struct device *dev) @@ -810,6 +817,9 @@ union irte { } fields; }; +#define APICID_TO_IRTE_DEST_LO(x) (x & 0xffffff) +#define APICID_TO_IRTE_DEST_HI(x) ((x >> 24) & 0xff) + union irte_ga_lo { u64 val; @@ -823,8 +833,8 @@ union irte_ga_lo { dm : 1, /* ------ */ guest_mode : 1, - destination : 8, - rsvd : 48; + destination : 24, + ga_tag : 32; } fields_remap; /* For guest vAPIC */ @@ -837,8 +847,7 @@ union irte_ga_lo { is_run : 1, /* ------ */ guest_mode : 1, - destination : 8, - rsvd2 : 16, + destination : 24, ga_tag : 32; } fields_vapic; }; @@ -849,7 +858,8 @@ union irte_ga_hi { u64 vector : 8, rsvd_1 : 4, ga_root_ptr : 40, - rsvd_2 : 12; + rsvd_2 : 4, + destination : 8; } fields; }; diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c index 22bdabd3d8e0..5059d09f3202 100644 --- a/drivers/iommu/arm-smmu-v3.c +++ b/drivers/iommu/arm-smmu-v3.c @@ -24,6 +24,7 @@ #include <linux/acpi_iort.h> #include <linux/bitfield.h> #include <linux/bitops.h> +#include <linux/crash_dump.h> #include <linux/delay.h> #include <linux/dma-iommu.h> #include <linux/err.h> @@ -366,7 +367,7 @@ #define MSI_IOVA_BASE 0x8000000 #define MSI_IOVA_LENGTH 0x100000 -static bool disable_bypass; +static bool disable_bypass = 1; module_param_named(disable_bypass, disable_bypass, bool, S_IRUGO); MODULE_PARM_DESC(disable_bypass, "Disable bypass streams such that incoming transactions from devices that are not attached to an iommu domain will report an abort back to the device and will not be allowed to pass through the SMMU."); @@ -1301,6 +1302,7 @@ static irqreturn_t arm_smmu_priq_thread(int irq, void *dev) /* Sync our overflow flag, as we believe we're up to speed */ q->cons = Q_OVF(q, q->prod) | Q_WRP(q, q->cons) | Q_IDX(q, q->cons); + writel(q->cons, q->cons_reg); return IRQ_HANDLED; } @@ -1997,7 +1999,6 @@ static struct iommu_ops arm_smmu_ops = { .attach_dev = arm_smmu_attach_dev, .map = arm_smmu_map, .unmap = arm_smmu_unmap, - .map_sg = default_iommu_map_sg, .flush_iotlb_all = arm_smmu_iotlb_sync, .iotlb_sync = arm_smmu_iotlb_sync, .iova_to_phys = arm_smmu_iova_to_phys, @@ -2211,8 +2212,12 @@ static int arm_smmu_update_gbpa(struct arm_smmu_device *smmu, u32 set, u32 clr) reg &= ~clr; reg |= set; writel_relaxed(reg | GBPA_UPDATE, gbpa); - return readl_relaxed_poll_timeout(gbpa, reg, !(reg & GBPA_UPDATE), - 1, ARM_SMMU_POLL_TIMEOUT_US); + ret = readl_relaxed_poll_timeout(gbpa, reg, !(reg & GBPA_UPDATE), + 1, ARM_SMMU_POLL_TIMEOUT_US); + + if (ret) + dev_err(smmu->dev, "GBPA not responding to update\n"); + return ret; } static void arm_smmu_free_msis(void *data) @@ -2392,8 +2397,15 @@ static int arm_smmu_device_reset(struct arm_smmu_device *smmu, bool bypass) /* Clear CR0 and sync (disables SMMU and queue processing) */ reg = readl_relaxed(smmu->base + ARM_SMMU_CR0); - if (reg & CR0_SMMUEN) + if (reg & CR0_SMMUEN) { + if (is_kdump_kernel()) { + arm_smmu_update_gbpa(smmu, GBPA_ABORT, 0); + arm_smmu_device_disable(smmu); + return -EBUSY; + } + dev_warn(smmu->dev, "SMMU currently enabled! Resetting...\n"); + } ret = arm_smmu_device_disable(smmu); if (ret) @@ -2491,10 +2503,8 @@ static int arm_smmu_device_reset(struct arm_smmu_device *smmu, bool bypass) enables |= CR0_SMMUEN; } else { ret = arm_smmu_update_gbpa(smmu, 0, GBPA_ABORT); - if (ret) { - dev_err(smmu->dev, "GBPA not responding to update\n"); + if (ret) return ret; - } } ret = arm_smmu_write_reg_sync(smmu, enables, ARM_SMMU_CR0, ARM_SMMU_CR0ACK); diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index c73cfce1ccc0..fd1b80ef9490 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -1562,7 +1562,6 @@ static struct iommu_ops arm_smmu_ops = { .attach_dev = arm_smmu_attach_dev, .map = arm_smmu_map, .unmap = arm_smmu_unmap, - .map_sg = default_iommu_map_sg, .flush_iotlb_all = arm_smmu_iotlb_sync, .iotlb_sync = arm_smmu_iotlb_sync, .iova_to_phys = arm_smmu_iova_to_phys, @@ -2103,12 +2102,16 @@ static int arm_smmu_device_probe(struct platform_device *pdev) if (err) return err; - if (smmu->version == ARM_SMMU_V2 && - smmu->num_context_banks != smmu->num_context_irqs) { - dev_err(dev, - "found only %d context interrupt(s) but %d required\n", - smmu->num_context_irqs, smmu->num_context_banks); - return -ENODEV; + if (smmu->version == ARM_SMMU_V2) { + if (smmu->num_context_banks > smmu->num_context_irqs) { + dev_err(dev, + "found only %d context irq(s) but %d required\n", + smmu->num_context_irqs, smmu->num_context_banks); + return -ENODEV; + } + + /* Ignore superfluous interrupts */ + smmu->num_context_irqs = smmu->num_context_banks; } for (i = 0; i < smmu->num_global_irqs; ++i) { diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c index 75456b5aa825..d9c748b6f9e4 100644 --- a/drivers/iommu/dmar.c +++ b/drivers/iommu/dmar.c @@ -1339,8 +1339,8 @@ void qi_flush_iotlb(struct intel_iommu *iommu, u16 did, u64 addr, qi_submit_sync(&desc, iommu); } -void qi_flush_dev_iotlb(struct intel_iommu *iommu, u16 sid, u16 qdep, - u64 addr, unsigned mask) +void qi_flush_dev_iotlb(struct intel_iommu *iommu, u16 sid, u16 pfsid, + u16 qdep, u64 addr, unsigned mask) { struct qi_desc desc; @@ -1355,7 +1355,7 @@ void qi_flush_dev_iotlb(struct intel_iommu *iommu, u16 sid, u16 qdep, qdep = 0; desc.low = QI_DEV_IOTLB_SID(sid) | QI_DEV_IOTLB_QDEP(qdep) | - QI_DIOTLB_TYPE; + QI_DIOTLB_TYPE | QI_DEV_IOTLB_PFSID(pfsid); qi_submit_sync(&desc, iommu); } diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c index b128cb4372d3..1bd0cd7168df 100644 --- a/drivers/iommu/exynos-iommu.c +++ b/drivers/iommu/exynos-iommu.c @@ -1332,7 +1332,6 @@ static const struct iommu_ops exynos_iommu_ops = { .detach_dev = exynos_iommu_detach_device, .map = exynos_iommu_map, .unmap = exynos_iommu_unmap, - .map_sg = default_iommu_map_sg, .iova_to_phys = exynos_iommu_iova_to_phys, .device_group = generic_device_group, .add_device = exynos_iommu_add_device, diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index 6a237d18fabf..5f3f10cf9d9d 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c @@ -52,6 +52,7 @@ #include <asm/iommu.h> #include "irq_remapping.h" +#include "intel-pasid.h" #define ROOT_SIZE VTD_PAGE_SIZE #define CONTEXT_SIZE VTD_PAGE_SIZE @@ -379,60 +380,6 @@ static int hw_pass_through = 1; for (idx = 0; idx < g_num_of_iommus; idx++) \ if (domain->iommu_refcnt[idx]) -struct dmar_domain { - int nid; /* node id */ - - unsigned iommu_refcnt[DMAR_UNITS_SUPPORTED]; - /* Refcount of devices per iommu */ - - - u16 iommu_did[DMAR_UNITS_SUPPORTED]; - /* Domain ids per IOMMU. Use u16 since - * domain ids are 16 bit wide according - * to VT-d spec, section 9.3 */ - - bool has_iotlb_device; - struct list_head devices; /* all devices' list */ - struct iova_domain iovad; /* iova's that belong to this domain */ - - struct dma_pte *pgd; /* virtual address */ - int gaw; /* max guest address width */ - - /* adjusted guest address width, 0 is level 2 30-bit */ - int agaw; - - int flags; /* flags to find out type of domain */ - - int iommu_coherency;/* indicate coherency of iommu access */ - int iommu_snooping; /* indicate snooping control feature*/ - int iommu_count; /* reference count of iommu */ - int iommu_superpage;/* Level of superpages supported: - 0 == 4KiB (no superpages), 1 == 2MiB, - 2 == 1GiB, 3 == 512GiB, 4 == 1TiB */ - u64 max_addr; /* maximum mapped address */ - - struct iommu_domain domain; /* generic domain data structure for - iommu core */ -}; - -/* PCI domain-device relationship */ -struct device_domain_info { - struct list_head link; /* link to domain siblings */ - struct list_head global; /* link to global list */ - u8 bus; /* PCI bus number */ - u8 devfn; /* PCI devfn number */ - u8 pasid_supported:3; - u8 pasid_enabled:1; - u8 pri_supported:1; - u8 pri_enabled:1; - u8 ats_supported:1; - u8 ats_enabled:1; - u8 ats_qdep; - struct device *dev; /* it's NULL for PCIe-to-PCI bridge */ - struct intel_iommu *iommu; /* IOMMU used by this device */ - struct dmar_domain *domain; /* pointer to domain */ -}; - struct dmar_rmrr_unit { struct list_head list; /* list of rmrr units */ struct acpi_dmar_header *hdr; /* ACPI header */ @@ -523,6 +470,27 @@ EXPORT_SYMBOL_GPL(intel_iommu_gfx_mapped); static DEFINE_SPINLOCK(device_domain_lock); static LIST_HEAD(device_domain_list); +/* + * Iterate over elements in device_domain_list and call the specified + * callback @fn against each element. This helper should only be used + * in the context where the device_domain_lock has already been holden. + */ +int for_each_device_domain(int (*fn)(struct device_domain_info *info, + void *data), void *data) +{ + int ret = 0; + struct device_domain_info *info; + + assert_spin_locked(&device_domain_lock); + list_for_each_entry(info, &device_domain_list, global) { + ret = fn(info, data); + if (ret) + return ret; + } + + return 0; +} + const struct iommu_ops intel_iommu_ops; static bool translation_pre_enabled(struct intel_iommu *iommu) @@ -629,7 +597,7 @@ static void set_iommu_domain(struct intel_iommu *iommu, u16 did, domains[did & 0xff] = domain; } -static inline void *alloc_pgtable_page(int node) +void *alloc_pgtable_page(int node) { struct page *page; void *vaddr = NULL; @@ -640,7 +608,7 @@ static inline void *alloc_pgtable_page(int node) return vaddr; } -static inline void free_pgtable_page(void *vaddr) +void free_pgtable_page(void *vaddr) { free_page((unsigned long)vaddr); } @@ -723,7 +691,7 @@ int iommu_calculate_agaw(struct intel_iommu *iommu) } /* This functionin only returns single iommu in a domain */ -static struct intel_iommu *domain_get_iommu(struct dmar_domain *domain) +struct intel_iommu *domain_get_iommu(struct dmar_domain *domain) { int iommu_id; @@ -1501,6 +1469,20 @@ static void iommu_enable_dev_iotlb(struct device_domain_info *info) return; pdev = to_pci_dev(info->dev); + /* For IOMMU that supports device IOTLB throttling (DIT), we assign + * PFSID to the invalidation desc of a VF such that IOMMU HW can gauge + * queue depth at PF level. If DIT is not set, PFSID will be treated as + * reserved, which should be set to 0. + */ + if (!ecap_dit(info->iommu->ecap)) + info->pfsid = 0; + else { + struct pci_dev *pf_pdev; + + /* pdev will be returned if device is not a vf */ + pf_pdev = pci_physfn(pdev); + info->pfsid = PCI_DEVID(pf_pdev->bus->number, pf_pdev->devfn); + } #ifdef CONFIG_INTEL_IOMMU_SVM /* The PCIe spec, in its wisdom, declares that the behaviour of @@ -1566,7 +1548,8 @@ static void iommu_flush_dev_iotlb(struct dmar_domain *domain, sid = info->bus << 8 | info->devfn; qdep = info->ats_qdep; - qi_flush_dev_iotlb(info->iommu, sid, qdep, addr, mask); + qi_flush_dev_iotlb(info->iommu, sid, info->pfsid, + qdep, addr, mask); } spin_unlock_irqrestore(&device_domain_lock, flags); } @@ -1800,7 +1783,7 @@ static void free_dmar_iommu(struct intel_iommu *iommu) if (pasid_enabled(iommu)) { if (ecap_prs(iommu->ecap)) intel_svm_finish_prq(iommu); - intel_svm_free_pasid_tables(iommu); + intel_svm_exit(iommu); } #endif } @@ -2495,6 +2478,7 @@ static struct dmar_domain *dmar_insert_one_dev_info(struct intel_iommu *iommu, info->dev = dev; info->domain = domain; info->iommu = iommu; + info->pasid_table = NULL; if (dev && dev_is_pci(dev)) { struct pci_dev *pdev = to_pci_dev(info->dev); @@ -2552,6 +2536,15 @@ static struct dmar_domain *dmar_insert_one_dev_info(struct intel_iommu *iommu, list_add(&info->global, &device_domain_list); if (dev) dev->archdata.iommu = info; + + if (dev && dev_is_pci(dev) && info->pasid_supported) { + ret = intel_pasid_alloc_table(dev); + if (ret) { + __dmar_remove_one_dev_info(info); + spin_unlock_irqrestore(&device_domain_lock, flags); + return NULL; + } + } spin_unlock_irqrestore(&device_domain_lock, flags); if (dev && domain_context_mapping(domain, dev)) { @@ -3304,6 +3297,18 @@ static int __init init_dmars(void) } for_each_active_iommu(iommu, drhd) { + /* + * Find the max pasid size of all IOMMU's in the system. + * We need to ensure the system pasid table is no bigger + * than the smallest supported. + */ + if (pasid_enabled(iommu)) { + u32 temp = 2 << ecap_pss(iommu->ecap); + + intel_pasid_max_id = min_t(u32, temp, + intel_pasid_max_id); + } + g_iommus[iommu->seq_id] = iommu; intel_iommu_init_qi(iommu); @@ -3359,7 +3364,7 @@ static int __init init_dmars(void) hw_pass_through = 0; #ifdef CONFIG_INTEL_IOMMU_SVM if (pasid_enabled(iommu)) - intel_svm_alloc_pasid_tables(iommu); + intel_svm_init(iommu); #endif } @@ -3526,7 +3531,7 @@ static unsigned long intel_alloc_iova(struct device *dev, return iova_pfn; } -static struct dmar_domain *get_valid_domain_for_dev(struct device *dev) +struct dmar_domain *get_valid_domain_for_dev(struct device *dev) { struct dmar_domain *domain, *tmp; struct dmar_rmrr_unit *rmrr; @@ -4354,7 +4359,7 @@ static int intel_iommu_add(struct dmar_drhd_unit *dmaru) #ifdef CONFIG_INTEL_IOMMU_SVM if (pasid_enabled(iommu)) - intel_svm_alloc_pasid_tables(iommu); + intel_svm_init(iommu); #endif if (dmaru->ignored) { @@ -4906,6 +4911,7 @@ static void __dmar_remove_one_dev_info(struct device_domain_info *info) if (info->dev) { iommu_disable_dev_iotlb(info); domain_context_clear(iommu, info->dev); + intel_pasid_free_table(info->dev); } unlink_domain_info(info); @@ -5231,22 +5237,16 @@ static void intel_iommu_put_resv_regions(struct device *dev, #ifdef CONFIG_INTEL_IOMMU_SVM #define MAX_NR_PASID_BITS (20) -static inline unsigned long intel_iommu_get_pts(struct intel_iommu *iommu) +static inline unsigned long intel_iommu_get_pts(struct device *dev) { - /* - * Convert ecap_pss to extend context entry pts encoding, also - * respect the soft pasid_max value set by the iommu. - * - number of PASID bits = ecap_pss + 1 - * - number of PASID table entries = 2^(pts + 5) - * Therefore, pts = ecap_pss - 4 - * e.g. KBL ecap_pss = 0x13, PASID has 20 bits, pts = 15 - */ - if (ecap_pss(iommu->ecap) < 5) + int pts, max_pasid; + + max_pasid = intel_pasid_get_dev_max_id(dev); + pts = find_first_bit((unsigned long *)&max_pasid, MAX_NR_PASID_BITS); + if (pts < 5) return 0; - /* pasid_max is encoded as actual number of entries not the bits */ - return find_first_bit((unsigned long *)&iommu->pasid_max, - MAX_NR_PASID_BITS) - 5; + return pts - 5; } int intel_iommu_enable_pasid(struct intel_iommu *iommu, struct intel_svm_dev *sdev) @@ -5282,8 +5282,8 @@ int intel_iommu_enable_pasid(struct intel_iommu *iommu, struct intel_svm_dev *sd if (!(ctx_lo & CONTEXT_PASIDE)) { if (iommu->pasid_state_table) context[1].hi = (u64)virt_to_phys(iommu->pasid_state_table); - context[1].lo = (u64)virt_to_phys(iommu->pasid_table) | - intel_iommu_get_pts(iommu); + context[1].lo = (u64)virt_to_phys(info->pasid_table->table) | + intel_iommu_get_pts(sdev->dev); wmb(); /* CONTEXT_TT_MULTI_LEVEL and CONTEXT_TT_DEV_IOTLB are both @@ -5350,11 +5350,6 @@ struct intel_iommu *intel_svm_device_to_iommu(struct device *dev) return NULL; } - if (!iommu->pasid_table) { - dev_err(dev, "PASID not enabled on IOMMU; cannot enable SVM\n"); - return NULL; - } - return iommu; } #endif /* CONFIG_INTEL_IOMMU_SVM */ @@ -5367,7 +5362,6 @@ const struct iommu_ops intel_iommu_ops = { .detach_dev = intel_iommu_detach_device, .map = intel_iommu_map, .unmap = intel_iommu_unmap, - .map_sg = default_iommu_map_sg, .iova_to_phys = intel_iommu_iova_to_phys, .add_device = intel_iommu_add_device, .remove_device = intel_iommu_remove_device, diff --git a/drivers/iommu/intel-pasid.c b/drivers/iommu/intel-pasid.c new file mode 100644 index 000000000000..fe95c9bd4d33 --- /dev/null +++ b/drivers/iommu/intel-pasid.c @@ -0,0 +1,239 @@ +// SPDX-License-Identifier: GPL-2.0 +/** + * intel-pasid.c - PASID idr, table and entry manipulation + * + * Copyright (C) 2018 Intel Corporation + * + * Author: Lu Baolu <baolu.lu@linux.intel.com> + */ + +#define pr_fmt(fmt) "DMAR: " fmt + +#include <linux/dmar.h> +#include <linux/intel-iommu.h> +#include <linux/iommu.h> +#include <linux/memory.h> +#include <linux/pci.h> +#include <linux/pci-ats.h> +#include <linux/spinlock.h> + +#include "intel-pasid.h" + +/* + * Intel IOMMU system wide PASID name space: + */ +static DEFINE_SPINLOCK(pasid_lock); +u32 intel_pasid_max_id = PASID_MAX; +static DEFINE_IDR(pasid_idr); + +int intel_pasid_alloc_id(void *ptr, int start, int end, gfp_t gfp) +{ + int ret, min, max; + + min = max_t(int, start, PASID_MIN); + max = min_t(int, end, intel_pasid_max_id); + + WARN_ON(in_interrupt()); + idr_preload(gfp); + spin_lock(&pasid_lock); + ret = idr_alloc(&pasid_idr, ptr, min, max, GFP_ATOMIC); + spin_unlock(&pasid_lock); + idr_preload_end(); + + return ret; +} + +void intel_pasid_free_id(int pasid) +{ + spin_lock(&pasid_lock); + idr_remove(&pasid_idr, pasid); + spin_unlock(&pasid_lock); +} + +void *intel_pasid_lookup_id(int pasid) +{ + void *p; + + spin_lock(&pasid_lock); + p = idr_find(&pasid_idr, pasid); + spin_unlock(&pasid_lock); + + return p; +} + +/* + * Per device pasid table management: + */ +static inline void +device_attach_pasid_table(struct device_domain_info *info, + struct pasid_table *pasid_table) +{ + info->pasid_table = pasid_table; + list_add(&info->table, &pasid_table->dev); +} + +static inline void +device_detach_pasid_table(struct device_domain_info *info, + struct pasid_table *pasid_table) +{ + info->pasid_table = NULL; + list_del(&info->table); +} + +struct pasid_table_opaque { + struct pasid_table **pasid_table; + int segment; + int bus; + int devfn; +}; + +static int search_pasid_table(struct device_domain_info *info, void *opaque) +{ + struct pasid_table_opaque *data = opaque; + + if (info->iommu->segment == data->segment && + info->bus == data->bus && + info->devfn == data->devfn && + info->pasid_table) { + *data->pasid_table = info->pasid_table; + return 1; + } + + return 0; +} + +static int get_alias_pasid_table(struct pci_dev *pdev, u16 alias, void *opaque) +{ + struct pasid_table_opaque *data = opaque; + + data->segment = pci_domain_nr(pdev->bus); + data->bus = PCI_BUS_NUM(alias); + data->devfn = alias & 0xff; + + return for_each_device_domain(&search_pasid_table, data); +} + +/* + * Allocate a pasid table for @dev. It should be called in a + * single-thread context. + */ +int intel_pasid_alloc_table(struct device *dev) +{ + struct device_domain_info *info; + struct pasid_table *pasid_table; + struct pasid_table_opaque data; + struct page *pages; + size_t size, count; + int ret, order; + + info = dev->archdata.iommu; + if (WARN_ON(!info || !dev_is_pci(dev) || + !info->pasid_supported || info->pasid_table)) + return -EINVAL; + + /* DMA alias device already has a pasid table, use it: */ + data.pasid_table = &pasid_table; + ret = pci_for_each_dma_alias(to_pci_dev(dev), + &get_alias_pasid_table, &data); + if (ret) + goto attach_out; + + pasid_table = kzalloc(sizeof(*pasid_table), GFP_ATOMIC); + if (!pasid_table) + return -ENOMEM; + INIT_LIST_HEAD(&pasid_table->dev); + + size = sizeof(struct pasid_entry); + count = min_t(int, pci_max_pasids(to_pci_dev(dev)), intel_pasid_max_id); + order = get_order(size * count); + pages = alloc_pages_node(info->iommu->node, + GFP_ATOMIC | __GFP_ZERO, + order); + if (!pages) + return -ENOMEM; + + pasid_table->table = page_address(pages); + pasid_table->order = order; + pasid_table->max_pasid = count; + +attach_out: + device_attach_pasid_table(info, pasid_table); + + return 0; +} + +void intel_pasid_free_table(struct device *dev) +{ + struct device_domain_info *info; + struct pasid_table *pasid_table; + + info = dev->archdata.iommu; + if (!info || !dev_is_pci(dev) || + !info->pasid_supported || !info->pasid_table) + return; + + pasid_table = info->pasid_table; + device_detach_pasid_table(info, pasid_table); + + if (!list_empty(&pasid_table->dev)) + return; + + free_pages((unsigned long)pasid_table->table, pasid_table->order); + kfree(pasid_table); +} + +struct pasid_table *intel_pasid_get_table(struct device *dev) +{ + struct device_domain_info *info; + + info = dev->archdata.iommu; + if (!info) + return NULL; + + return info->pasid_table; +} + +int intel_pasid_get_dev_max_id(struct device *dev) +{ + struct device_domain_info *info; + + info = dev->archdata.iommu; + if (!info || !info->pasid_table) + return 0; + + return info->pasid_table->max_pasid; +} + +struct pasid_entry *intel_pasid_get_entry(struct device *dev, int pasid) +{ + struct pasid_table *pasid_table; + struct pasid_entry *entries; + + pasid_table = intel_pasid_get_table(dev); + if (WARN_ON(!pasid_table || pasid < 0 || + pasid >= intel_pasid_get_dev_max_id(dev))) + return NULL; + + entries = pasid_table->table; + + return &entries[pasid]; +} + +/* + * Interfaces for PASID table entry manipulation: + */ +static inline void pasid_clear_entry(struct pasid_entry *pe) +{ + WRITE_ONCE(pe->val, 0); +} + +void intel_pasid_clear_entry(struct device *dev, int pasid) +{ + struct pasid_entry *pe; + + pe = intel_pasid_get_entry(dev, pasid); + if (WARN_ON(!pe)) + return; + + pasid_clear_entry(pe); +} diff --git a/drivers/iommu/intel-pasid.h b/drivers/iommu/intel-pasid.h new file mode 100644 index 000000000000..1c05ed6fc5a5 --- /dev/null +++ b/drivers/iommu/intel-pasid.h @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * intel-pasid.h - PASID idr, table and entry header + * + * Copyright (C) 2018 Intel Corporation + * + * Author: Lu Baolu <baolu.lu@linux.intel.com> + */ + +#ifndef __INTEL_PASID_H +#define __INTEL_PASID_H + +#define PASID_MIN 0x1 +#define PASID_MAX 0x100000 + +struct pasid_entry { + u64 val; +}; + +/* The representative of a PASID table */ +struct pasid_table { + void *table; /* pasid table pointer */ + int order; /* page order of pasid table */ + int max_pasid; /* max pasid */ + struct list_head dev; /* device list */ +}; + +extern u32 intel_pasid_max_id; +int intel_pasid_alloc_id(void *ptr, int start, int end, gfp_t gfp); +void intel_pasid_free_id(int pasid); +void *intel_pasid_lookup_id(int pasid); +int intel_pasid_alloc_table(struct device *dev); +void intel_pasid_free_table(struct device *dev); +struct pasid_table *intel_pasid_get_table(struct device *dev); +int intel_pasid_get_dev_max_id(struct device *dev); +struct pasid_entry *intel_pasid_get_entry(struct device *dev, int pasid); +void intel_pasid_clear_entry(struct device *dev, int pasid); + +#endif /* __INTEL_PASID_H */ diff --git a/drivers/iommu/intel-svm.c b/drivers/iommu/intel-svm.c index 7d65aab36a96..4a03e5090952 100644 --- a/drivers/iommu/intel-svm.c +++ b/drivers/iommu/intel-svm.c @@ -27,21 +27,19 @@ #include <linux/mm_types.h> #include <asm/page.h> +#include "intel-pasid.h" + #define PASID_ENTRY_P BIT_ULL(0) #define PASID_ENTRY_FLPM_5LP BIT_ULL(9) #define PASID_ENTRY_SRE BIT_ULL(11) static irqreturn_t prq_event_thread(int irq, void *d); -struct pasid_entry { - u64 val; -}; - struct pasid_state_entry { u64 val; }; -int intel_svm_alloc_pasid_tables(struct intel_iommu *iommu) +int intel_svm_init(struct intel_iommu *iommu) { struct page *pages; int order; @@ -66,15 +64,6 @@ int intel_svm_alloc_pasid_tables(struct intel_iommu *iommu) iommu->pasid_max = 0x20000; order = get_order(sizeof(struct pasid_entry) * iommu->pasid_max); - pages = alloc_pages(GFP_KERNEL | __GFP_ZERO, order); - if (!pages) { - pr_warn("IOMMU: %s: Failed to allocate PASID table\n", - iommu->name); - return -ENOMEM; - } - iommu->pasid_table = page_address(pages); - pr_info("%s: Allocated order %d PASID table.\n", iommu->name, order); - if (ecap_dis(iommu->ecap)) { /* Just making it explicit... */ BUILD_BUG_ON(sizeof(struct pasid_entry) != sizeof(struct pasid_state_entry)); @@ -86,24 +75,18 @@ int intel_svm_alloc_pasid_tables(struct intel_iommu *iommu) iommu->name); } - idr_init(&iommu->pasid_idr); - return 0; } -int intel_svm_free_pasid_tables(struct intel_iommu *iommu) +int intel_svm_exit(struct intel_iommu *iommu) { int order = get_order(sizeof(struct pasid_entry) * iommu->pasid_max); - if (iommu->pasid_table) { - free_pages((unsigned long)iommu->pasid_table, order); - iommu->pasid_table = NULL; - } if (iommu->pasid_state_table) { free_pages((unsigned long)iommu->pasid_state_table, order); iommu->pasid_state_table = NULL; } - idr_destroy(&iommu->pasid_idr); + return 0; } @@ -279,11 +262,9 @@ static void intel_mm_release(struct mmu_notifier *mn, struct mm_struct *mm) * page) so that we end up taking a fault that the hardware really * *has* to handle gracefully without affecting other processes. */ - svm->iommu->pasid_table[svm->pasid].val = 0; - wmb(); - rcu_read_lock(); list_for_each_entry_rcu(sdev, &svm->devs, list) { + intel_pasid_clear_entry(sdev->dev, svm->pasid); intel_flush_pasid_dev(svm, sdev, svm->pasid); intel_flush_svm_range_dev(svm, sdev, 0, -1, 0, !svm->mm); } @@ -299,10 +280,12 @@ static const struct mmu_notifier_ops intel_mmuops = { }; static DEFINE_MUTEX(pasid_mutex); +static LIST_HEAD(global_svm_list); int intel_svm_bind_mm(struct device *dev, int *pasid, int flags, struct svm_dev_ops *ops) { struct intel_iommu *iommu = intel_svm_device_to_iommu(dev); + struct pasid_entry *entry; struct intel_svm_dev *sdev; struct intel_svm *svm = NULL; struct mm_struct *mm = NULL; @@ -310,7 +293,7 @@ int intel_svm_bind_mm(struct device *dev, int *pasid, int flags, struct svm_dev_ int pasid_max; int ret; - if (WARN_ON(!iommu || !iommu->pasid_table)) + if (!iommu) return -EINVAL; if (dev_is_pci(dev)) { @@ -330,13 +313,13 @@ int intel_svm_bind_mm(struct device *dev, int *pasid, int flags, struct svm_dev_ mutex_lock(&pasid_mutex); if (pasid && !(flags & SVM_FLAG_PRIVATE_PASID)) { - int i; + struct intel_svm *t; - idr_for_each_entry(&iommu->pasid_idr, svm, i) { - if (svm->mm != mm || - (svm->flags & SVM_FLAG_PRIVATE_PASID)) + list_for_each_entry(t, &global_svm_list, list) { + if (t->mm != mm || (t->flags & SVM_FLAG_PRIVATE_PASID)) continue; + svm = t; if (svm->pasid >= pasid_max) { dev_warn(dev, "Limited PASID width. Cannot use existing PASID %d\n", @@ -388,13 +371,13 @@ int intel_svm_bind_mm(struct device *dev, int *pasid, int flags, struct svm_dev_ } svm->iommu = iommu; - if (pasid_max > iommu->pasid_max) - pasid_max = iommu->pasid_max; + if (pasid_max > intel_pasid_max_id) + pasid_max = intel_pasid_max_id; /* Do not use PASID 0 in caching mode (virtualised IOMMU) */ - ret = idr_alloc(&iommu->pasid_idr, svm, - !!cap_caching_mode(iommu->cap), - pasid_max - 1, GFP_KERNEL); + ret = intel_pasid_alloc_id(svm, + !!cap_caching_mode(iommu->cap), + pasid_max - 1, GFP_KERNEL); if (ret < 0) { kfree(svm); kfree(sdev); @@ -405,11 +388,12 @@ int intel_svm_bind_mm(struct device *dev, int *pasid, int flags, struct svm_dev_ svm->mm = mm; svm->flags = flags; INIT_LIST_HEAD_RCU(&svm->devs); + INIT_LIST_HEAD(&svm->list); ret = -ENOMEM; if (mm) { ret = mmu_notifier_register(&svm->notifier, mm); if (ret) { - idr_remove(&svm->iommu->pasid_idr, svm->pasid); + intel_pasid_free_id(svm->pasid); kfree(svm); kfree(sdev); goto out; @@ -421,7 +405,8 @@ int intel_svm_bind_mm(struct device *dev, int *pasid, int flags, struct svm_dev_ if (cpu_feature_enabled(X86_FEATURE_LA57)) pasid_entry_val |= PASID_ENTRY_FLPM_5LP; - iommu->pasid_table[svm->pasid].val = pasid_entry_val; + entry = intel_pasid_get_entry(dev, svm->pasid); + entry->val = pasid_entry_val; wmb(); @@ -431,6 +416,8 @@ int intel_svm_bind_mm(struct device *dev, int *pasid, int flags, struct svm_dev_ */ if (cap_caching_mode(iommu->cap)) intel_flush_pasid_dev(svm, sdev, svm->pasid); + + list_add_tail(&svm->list, &global_svm_list); } list_add_rcu(&sdev->list, &svm->devs); @@ -454,10 +441,10 @@ int intel_svm_unbind_mm(struct device *dev, int pasid) mutex_lock(&pasid_mutex); iommu = intel_svm_device_to_iommu(dev); - if (!iommu || !iommu->pasid_table) + if (!iommu) goto out; - svm = idr_find(&iommu->pasid_idr, pasid); + svm = intel_pasid_lookup_id(pasid); if (!svm) goto out; @@ -477,15 +464,15 @@ int intel_svm_unbind_mm(struct device *dev, int pasid) intel_flush_pasid_dev(svm, sdev, svm->pasid); intel_flush_svm_range_dev(svm, sdev, 0, -1, 0, !svm->mm); kfree_rcu(sdev, rcu); + intel_pasid_clear_entry(dev, svm->pasid); if (list_empty(&svm->devs)) { - svm->iommu->pasid_table[svm->pasid].val = 0; - wmb(); - - idr_remove(&svm->iommu->pasid_idr, svm->pasid); + intel_pasid_free_id(svm->pasid); if (svm->mm) mmu_notifier_unregister(&svm->notifier, svm->mm); + list_del(&svm->list); + /* We mandate that no page faults may be outstanding * for the PASID when intel_svm_unbind_mm() is called. * If that is not obeyed, subtle errors will happen. @@ -512,10 +499,10 @@ int intel_svm_is_pasid_valid(struct device *dev, int pasid) mutex_lock(&pasid_mutex); iommu = intel_svm_device_to_iommu(dev); - if (!iommu || !iommu->pasid_table) + if (!iommu) goto out; - svm = idr_find(&iommu->pasid_idr, pasid); + svm = intel_pasid_lookup_id(pasid); if (!svm) goto out; @@ -614,7 +601,7 @@ static irqreturn_t prq_event_thread(int irq, void *d) if (!svm || svm->pasid != req->pasid) { rcu_read_lock(); - svm = idr_find(&iommu->pasid_idr, req->pasid); + svm = intel_pasid_lookup_id(req->pasid); /* It *can't* go away, because the driver is not permitted * to unbind the mm while any page faults are outstanding. * So we only need RCU to protect the internal idr code. */ diff --git a/drivers/iommu/io-pgtable-arm-v7s.c b/drivers/iommu/io-pgtable-arm-v7s.c index 50e3a9fcf43e..b5948ba6b3b3 100644 --- a/drivers/iommu/io-pgtable-arm-v7s.c +++ b/drivers/iommu/io-pgtable-arm-v7s.c @@ -192,6 +192,7 @@ static void *__arm_v7s_alloc_table(int lvl, gfp_t gfp, { struct io_pgtable_cfg *cfg = &data->iop.cfg; struct device *dev = cfg->iommu_dev; + phys_addr_t phys; dma_addr_t dma; size_t size = ARM_V7S_TABLE_SIZE(lvl); void *table = NULL; @@ -200,6 +201,10 @@ static void *__arm_v7s_alloc_table(int lvl, gfp_t gfp, table = (void *)__get_dma_pages(__GFP_ZERO, get_order(size)); else if (lvl == 2) table = kmem_cache_zalloc(data->l2_tables, gfp | GFP_DMA); + phys = virt_to_phys(table); + if (phys != (arm_v7s_iopte)phys) + /* Doesn't fit in PTE */ + goto out_free; if (table && !(cfg->quirks & IO_PGTABLE_QUIRK_NO_DMA)) { dma = dma_map_single(dev, table, size, DMA_TO_DEVICE); if (dma_mapping_error(dev, dma)) @@ -209,7 +214,7 @@ static void *__arm_v7s_alloc_table(int lvl, gfp_t gfp, * address directly, so if the DMA layer suggests otherwise by * translating or truncating them, that bodes very badly... */ - if (dma != virt_to_phys(table)) + if (dma != phys) goto out_unmap; } kmemleak_ignore(table); diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c index 010a254305dd..88641b4560bc 100644 --- a/drivers/iommu/io-pgtable-arm.c +++ b/drivers/iommu/io-pgtable-arm.c @@ -237,7 +237,8 @@ static void *__arm_lpae_alloc_pages(size_t size, gfp_t gfp, void *pages; VM_BUG_ON((gfp & __GFP_HIGHMEM)); - p = alloc_pages_node(dev_to_node(dev), gfp | __GFP_ZERO, order); + p = alloc_pages_node(dev ? dev_to_node(dev) : NUMA_NO_NODE, + gfp | __GFP_ZERO, order); if (!p) return NULL; diff --git a/drivers/iommu/iommu-debugfs.c b/drivers/iommu/iommu-debugfs.c new file mode 100644 index 000000000000..3b1bf88fd1b0 --- /dev/null +++ b/drivers/iommu/iommu-debugfs.c @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * IOMMU debugfs core infrastructure + * + * Copyright (C) 2018 Advanced Micro Devices, Inc. + * + * Author: Gary R Hook <gary.hook@amd.com> + */ + +#include <linux/pci.h> +#include <linux/iommu.h> +#include <linux/debugfs.h> + +struct dentry *iommu_debugfs_dir; + +/** + * iommu_debugfs_setup - create the top-level iommu directory in debugfs + * + * Provide base enablement for using debugfs to expose internal data of an + * IOMMU driver. When called, this function creates the + * /sys/kernel/debug/iommu directory. + * + * Emit a strong warning at boot time to indicate that this feature is + * enabled. + * + * This function is called from iommu_init; drivers may then call + * iommu_debugfs_new_driver_dir() to instantiate a vendor-specific + * directory to be used to expose internal data. + */ +void iommu_debugfs_setup(void) +{ + if (!iommu_debugfs_dir) { + iommu_debugfs_dir = debugfs_create_dir("iommu", NULL); + pr_warn("\n"); + pr_warn("*************************************************************\n"); + pr_warn("** NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE **\n"); + pr_warn("** **\n"); + pr_warn("** IOMMU DebugFS SUPPORT HAS BEEN ENABLED IN THIS KERNEL **\n"); + pr_warn("** **\n"); + pr_warn("** This means that this kernel is built to expose internal **\n"); + pr_warn("** IOMMU data structures, which may compromise security on **\n"); + pr_warn("** your system. **\n"); + pr_warn("** **\n"); + pr_warn("** If you see this message and you are not debugging the **\n"); + pr_warn("** kernel, report this immediately to your vendor! **\n"); + pr_warn("** **\n"); + pr_warn("** NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE **\n"); + pr_warn("*************************************************************\n"); + } +} + +/** + * iommu_debugfs_new_driver_dir - create a vendor directory under debugfs/iommu + * @vendor: name of the vendor-specific subdirectory to create + * + * This function is called by an IOMMU driver to create the top-level debugfs + * directory for that driver. + * + * Return: upon success, a pointer to the dentry for the new directory. + * NULL in case of failure. + */ +struct dentry *iommu_debugfs_new_driver_dir(const char *vendor) +{ + return debugfs_create_dir(vendor, iommu_debugfs_dir); +} +EXPORT_SYMBOL_GPL(iommu_debugfs_new_driver_dir); diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 63b37563db7e..8c15c5980299 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -36,7 +36,11 @@ static struct kset *iommu_group_kset; static DEFINE_IDA(iommu_group_ida); +#ifdef CONFIG_IOMMU_DEFAULT_PASSTHROUGH +static unsigned int iommu_def_domain_type = IOMMU_DOMAIN_IDENTITY; +#else static unsigned int iommu_def_domain_type = IOMMU_DOMAIN_DMA; +#endif struct iommu_callback_data { const struct iommu_ops *ops; @@ -294,11 +298,39 @@ static ssize_t iommu_group_show_resv_regions(struct iommu_group *group, return (str - buf); } +static ssize_t iommu_group_show_type(struct iommu_group *group, + char *buf) +{ + char *type = "unknown\n"; + + if (group->default_domain) { + switch (group->default_domain->type) { + case IOMMU_DOMAIN_BLOCKED: + type = "blocked\n"; + break; + case IOMMU_DOMAIN_IDENTITY: + type = "identity\n"; + break; + case IOMMU_DOMAIN_UNMANAGED: + type = "unmanaged\n"; + break; + case IOMMU_DOMAIN_DMA: + type = "DMA"; + break; + } + } + strcpy(buf, type); + + return strlen(type); +} + static IOMMU_GROUP_ATTR(name, S_IRUGO, iommu_group_show_name, NULL); static IOMMU_GROUP_ATTR(reserved_regions, 0444, iommu_group_show_resv_regions, NULL); +static IOMMU_GROUP_ATTR(type, 0444, iommu_group_show_type, NULL); + static void iommu_group_release(struct kobject *kobj) { struct iommu_group *group = to_iommu_group(kobj); @@ -380,6 +412,10 @@ struct iommu_group *iommu_group_alloc(void) if (ret) return ERR_PTR(ret); + ret = iommu_group_create_file(group, &iommu_group_attr_type); + if (ret) + return ERR_PTR(ret); + pr_debug("Allocated group %d\n", group->id); return group; @@ -1637,8 +1673,8 @@ size_t iommu_unmap_fast(struct iommu_domain *domain, } EXPORT_SYMBOL_GPL(iommu_unmap_fast); -size_t default_iommu_map_sg(struct iommu_domain *domain, unsigned long iova, - struct scatterlist *sg, unsigned int nents, int prot) +size_t iommu_map_sg(struct iommu_domain *domain, unsigned long iova, + struct scatterlist *sg, unsigned int nents, int prot) { struct scatterlist *s; size_t mapped = 0; @@ -1678,7 +1714,7 @@ out_err: return 0; } -EXPORT_SYMBOL_GPL(default_iommu_map_sg); +EXPORT_SYMBOL_GPL(iommu_map_sg); int iommu_domain_window_enable(struct iommu_domain *domain, u32 wnd_nr, phys_addr_t paddr, u64 size, int prot) @@ -1748,6 +1784,8 @@ static int __init iommu_init(void) NULL, kernel_kobj); BUG_ON(!iommu_group_kset); + iommu_debugfs_setup(); + return 0; } core_initcall(iommu_init); diff --git a/drivers/iommu/ipmmu-vmsa.c b/drivers/iommu/ipmmu-vmsa.c index f026aa16d5f1..22b94f8a9a04 100644 --- a/drivers/iommu/ipmmu-vmsa.c +++ b/drivers/iommu/ipmmu-vmsa.c @@ -47,6 +47,7 @@ struct ipmmu_features { unsigned int number_of_contexts; bool setup_imbuscr; bool twobit_imttbcr_sl0; + bool reserved_context; }; struct ipmmu_vmsa_device { @@ -73,7 +74,7 @@ struct ipmmu_vmsa_domain { struct io_pgtable_ops *iop; unsigned int context_id; - spinlock_t lock; /* Protects mappings */ + struct mutex mutex; /* Protects mappings */ }; static struct ipmmu_vmsa_domain *to_vmsa_domain(struct iommu_domain *dom) @@ -194,7 +195,9 @@ static struct ipmmu_vmsa_device *to_ipmmu(struct device *dev) #define IMPMBA(n) (0x0280 + ((n) * 4)) #define IMPMBD(n) (0x02c0 + ((n) * 4)) -#define IMUCTR(n) (0x0300 + ((n) * 16)) +#define IMUCTR(n) ((n) < 32 ? IMUCTR0(n) : IMUCTR32(n)) +#define IMUCTR0(n) (0x0300 + ((n) * 16)) +#define IMUCTR32(n) (0x0600 + (((n) - 32) * 16)) #define IMUCTR_FIXADDEN (1 << 31) #define IMUCTR_FIXADD_MASK (0xff << 16) #define IMUCTR_FIXADD_SHIFT 16 @@ -204,7 +207,9 @@ static struct ipmmu_vmsa_device *to_ipmmu(struct device *dev) #define IMUCTR_FLUSH (1 << 1) #define IMUCTR_MMUEN (1 << 0) -#define IMUASID(n) (0x0308 + ((n) * 16)) +#define IMUASID(n) ((n) < 32 ? IMUASID0(n) : IMUASID32(n)) +#define IMUASID0(n) (0x0308 + ((n) * 16)) +#define IMUASID32(n) (0x0608 + (((n) - 32) * 16)) #define IMUASID_ASID8_MASK (0xff << 8) #define IMUASID_ASID8_SHIFT 8 #define IMUASID_ASID0_MASK (0xff << 0) @@ -595,7 +600,7 @@ static struct iommu_domain *__ipmmu_domain_alloc(unsigned type) if (!domain) return NULL; - spin_lock_init(&domain->lock); + mutex_init(&domain->mutex); return &domain->io_domain; } @@ -641,7 +646,6 @@ static int ipmmu_attach_device(struct iommu_domain *io_domain, struct iommu_fwspec *fwspec = dev->iommu_fwspec; struct ipmmu_vmsa_device *mmu = to_ipmmu(dev); struct ipmmu_vmsa_domain *domain = to_vmsa_domain(io_domain); - unsigned long flags; unsigned int i; int ret = 0; @@ -650,7 +654,7 @@ static int ipmmu_attach_device(struct iommu_domain *io_domain, return -ENXIO; } - spin_lock_irqsave(&domain->lock, flags); + mutex_lock(&domain->mutex); if (!domain->mmu) { /* The domain hasn't been used yet, initialize it. */ @@ -674,7 +678,7 @@ static int ipmmu_attach_device(struct iommu_domain *io_domain, } else dev_info(dev, "Reusing IPMMU context %u\n", domain->context_id); - spin_unlock_irqrestore(&domain->lock, flags); + mutex_unlock(&domain->mutex); if (ret < 0) return ret; @@ -756,8 +760,12 @@ static bool ipmmu_slave_whitelist(struct device *dev) return false; } -static const struct soc_device_attribute soc_r8a7795[] = { +static const struct soc_device_attribute soc_rcar_gen3[] = { { .soc_id = "r8a7795", }, + { .soc_id = "r8a7796", }, + { .soc_id = "r8a77965", }, + { .soc_id = "r8a77970", }, + { .soc_id = "r8a77995", }, { /* sentinel */ } }; @@ -765,7 +773,7 @@ static int ipmmu_of_xlate(struct device *dev, struct of_phandle_args *spec) { /* For R-Car Gen3 use a white list to opt-in slave devices */ - if (soc_device_match(soc_r8a7795) && !ipmmu_slave_whitelist(dev)) + if (soc_device_match(soc_rcar_gen3) && !ipmmu_slave_whitelist(dev)) return -ENODEV; iommu_fwspec_add_ids(dev, spec->args, 1); @@ -889,7 +897,6 @@ static const struct iommu_ops ipmmu_ops = { .unmap = ipmmu_unmap, .flush_iotlb_all = ipmmu_iotlb_sync, .iotlb_sync = ipmmu_iotlb_sync, - .map_sg = default_iommu_map_sg, .iova_to_phys = ipmmu_iova_to_phys, .add_device = ipmmu_add_device, .remove_device = ipmmu_remove_device, @@ -917,14 +924,16 @@ static const struct ipmmu_features ipmmu_features_default = { .number_of_contexts = 1, /* software only tested with one context */ .setup_imbuscr = true, .twobit_imttbcr_sl0 = false, + .reserved_context = false, }; -static const struct ipmmu_features ipmmu_features_r8a7795 = { +static const struct ipmmu_features ipmmu_features_rcar_gen3 = { .use_ns_alias_offset = false, .has_cache_leaf_nodes = true, .number_of_contexts = 8, .setup_imbuscr = false, .twobit_imttbcr_sl0 = true, + .reserved_context = true, }; static const struct of_device_id ipmmu_of_ids[] = { @@ -933,7 +942,19 @@ static const struct of_device_id ipmmu_of_ids[] = { .data = &ipmmu_features_default, }, { .compatible = "renesas,ipmmu-r8a7795", - .data = &ipmmu_features_r8a7795, + .data = &ipmmu_features_rcar_gen3, + }, { + .compatible = "renesas,ipmmu-r8a7796", + .data = &ipmmu_features_rcar_gen3, + }, { + .compatible = "renesas,ipmmu-r8a77965", + .data = &ipmmu_features_rcar_gen3, + }, { + .compatible = "renesas,ipmmu-r8a77970", + .data = &ipmmu_features_rcar_gen3, + }, { + .compatible = "renesas,ipmmu-r8a77995", + .data = &ipmmu_features_rcar_gen3, }, { /* Terminator */ }, @@ -955,7 +976,7 @@ static int ipmmu_probe(struct platform_device *pdev) } mmu->dev = &pdev->dev; - mmu->num_utlbs = 32; + mmu->num_utlbs = 48; spin_lock_init(&mmu->lock); bitmap_zero(mmu->ctx, IPMMU_CTX_MAX); mmu->features = of_device_get_match_data(&pdev->dev); @@ -1018,6 +1039,11 @@ static int ipmmu_probe(struct platform_device *pdev) } ipmmu_device_reset(mmu); + + if (mmu->features->reserved_context) { + dev_info(&pdev->dev, "IPMMU context 0 is reserved\n"); + set_bit(0, mmu->ctx); + } } /* @@ -1081,12 +1107,19 @@ static struct platform_driver ipmmu_driver = { static int __init ipmmu_init(void) { + struct device_node *np; static bool setup_done; int ret; if (setup_done) return 0; + np = of_find_matching_node(NULL, ipmmu_of_ids); + if (!np) + return 0; + + of_node_put(np); + ret = platform_driver_register(&ipmmu_driver); if (ret < 0) return ret; diff --git a/drivers/iommu/msm_iommu.c b/drivers/iommu/msm_iommu.c index 27377742600d..fc5f0b53adaf 100644 --- a/drivers/iommu/msm_iommu.c +++ b/drivers/iommu/msm_iommu.c @@ -395,20 +395,15 @@ static int msm_iommu_add_device(struct device *dev) struct msm_iommu_dev *iommu; struct iommu_group *group; unsigned long flags; - int ret = 0; spin_lock_irqsave(&msm_iommu_lock, flags); - iommu = find_iommu_for_dev(dev); + spin_unlock_irqrestore(&msm_iommu_lock, flags); + if (iommu) iommu_device_link(&iommu->iommu, dev); else - ret = -ENODEV; - - spin_unlock_irqrestore(&msm_iommu_lock, flags); - - if (ret) - return ret; + return -ENODEV; group = iommu_group_get_for_dev(dev); if (IS_ERR(group)) @@ -425,13 +420,12 @@ static void msm_iommu_remove_device(struct device *dev) unsigned long flags; spin_lock_irqsave(&msm_iommu_lock, flags); - iommu = find_iommu_for_dev(dev); + spin_unlock_irqrestore(&msm_iommu_lock, flags); + if (iommu) iommu_device_unlink(&iommu->iommu, dev); - spin_unlock_irqrestore(&msm_iommu_lock, flags); - iommu_group_remove_device(dev); } @@ -708,7 +702,6 @@ static struct iommu_ops msm_iommu_ops = { .detach_dev = msm_iommu_detach_dev, .map = msm_iommu_map, .unmap = msm_iommu_unmap, - .map_sg = default_iommu_map_sg, .iova_to_phys = msm_iommu_iova_to_phys, .add_device = msm_iommu_add_device, .remove_device = msm_iommu_remove_device, diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c index f2832a10fcea..f9f69f7111a9 100644 --- a/drivers/iommu/mtk_iommu.c +++ b/drivers/iommu/mtk_iommu.c @@ -495,7 +495,6 @@ static struct iommu_ops mtk_iommu_ops = { .detach_dev = mtk_iommu_detach_device, .map = mtk_iommu_map, .unmap = mtk_iommu_unmap, - .map_sg = default_iommu_map_sg, .flush_iotlb_all = mtk_iommu_iotlb_sync, .iotlb_sync = mtk_iommu_iotlb_sync, .iova_to_phys = mtk_iommu_iova_to_phys, diff --git a/drivers/iommu/mtk_iommu_v1.c b/drivers/iommu/mtk_iommu_v1.c index a7c2a973784f..676c029494e4 100644 --- a/drivers/iommu/mtk_iommu_v1.c +++ b/drivers/iommu/mtk_iommu_v1.c @@ -531,7 +531,6 @@ static struct iommu_ops mtk_iommu_ops = { .detach_dev = mtk_iommu_detach_device, .map = mtk_iommu_map, .unmap = mtk_iommu_unmap, - .map_sg = default_iommu_map_sg, .iova_to_phys = mtk_iommu_iova_to_phys, .add_device = mtk_iommu_add_device, .remove_device = mtk_iommu_remove_device, diff --git a/drivers/iommu/omap-iommu.c b/drivers/iommu/omap-iommu.c index af4a8e7fcd27..d2fb347aa4ff 100644 --- a/drivers/iommu/omap-iommu.c +++ b/drivers/iommu/omap-iommu.c @@ -550,7 +550,7 @@ static u32 *iopte_alloc(struct omap_iommu *obj, u32 *iopgd, pte_ready: iopte = iopte_offset(iopgd, da); - *pt_dma = virt_to_phys(iopte); + *pt_dma = iopgd_page_paddr(iopgd); dev_vdbg(obj->dev, "%s: da:%08x pgd:%p *pgd:%08x pte:%p *pte:%08x\n", __func__, da, iopgd, *iopgd, iopte, *iopte); @@ -738,7 +738,7 @@ static size_t iopgtable_clear_entry_core(struct omap_iommu *obj, u32 da) } bytes *= nent; memset(iopte, 0, nent * sizeof(*iopte)); - pt_dma = virt_to_phys(iopte); + pt_dma = iopgd_page_paddr(iopgd); flush_iopte_range(obj->dev, pt_dma, pt_offset, nent); /* @@ -1548,7 +1548,6 @@ static const struct iommu_ops omap_iommu_ops = { .detach_dev = omap_iommu_detach_dev, .map = omap_iommu_map, .unmap = omap_iommu_unmap, - .map_sg = default_iommu_map_sg, .iova_to_phys = omap_iommu_iova_to_phys, .add_device = omap_iommu_add_device, .remove_device = omap_iommu_remove_device, diff --git a/drivers/iommu/qcom_iommu.c b/drivers/iommu/qcom_iommu.c index b48aee82d14b..ee70e9921cf1 100644 --- a/drivers/iommu/qcom_iommu.c +++ b/drivers/iommu/qcom_iommu.c @@ -590,7 +590,6 @@ static const struct iommu_ops qcom_iommu_ops = { .detach_dev = qcom_iommu_detach_dev, .map = qcom_iommu_map, .unmap = qcom_iommu_unmap, - .map_sg = default_iommu_map_sg, .flush_iotlb_all = qcom_iommu_iotlb_sync, .iotlb_sync = qcom_iommu_iotlb_sync, .iova_to_phys = qcom_iommu_iova_to_phys, diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c index de8d3bf91b23..d393160e3e38 100644 --- a/drivers/iommu/rockchip-iommu.c +++ b/drivers/iommu/rockchip-iommu.c @@ -1110,7 +1110,6 @@ static const struct iommu_ops rk_iommu_ops = { .detach_dev = rk_iommu_detach_device, .map = rk_iommu_map, .unmap = rk_iommu_unmap, - .map_sg = default_iommu_map_sg, .add_device = rk_iommu_add_device, .remove_device = rk_iommu_remove_device, .iova_to_phys = rk_iommu_iova_to_phys, diff --git a/drivers/iommu/tegra-gart.c b/drivers/iommu/tegra-gart.c index a004f6da35f2..7b1361d57a17 100644 --- a/drivers/iommu/tegra-gart.c +++ b/drivers/iommu/tegra-gart.c @@ -377,7 +377,6 @@ static const struct iommu_ops gart_iommu_ops = { .remove_device = gart_iommu_remove_device, .device_group = generic_device_group, .map = gart_iommu_map, - .map_sg = default_iommu_map_sg, .unmap = gart_iommu_unmap, .iova_to_phys = gart_iommu_iova_to_phys, .pgsize_bitmap = GART_IOMMU_PGSIZES, diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c index 44d40bc771b5..0d03341317c4 100644 --- a/drivers/iommu/tegra-smmu.c +++ b/drivers/iommu/tegra-smmu.c @@ -876,7 +876,6 @@ static const struct iommu_ops tegra_smmu_ops = { .device_group = tegra_smmu_device_group, .map = tegra_smmu_map, .unmap = tegra_smmu_unmap, - .map_sg = default_iommu_map_sg, .iova_to_phys = tegra_smmu_iova_to_phys, .of_xlate = tegra_smmu_of_xlate, .pgsize_bitmap = SZ_4K, diff --git a/drivers/irqchip/irq-xtensa-mx.c b/drivers/irqchip/irq-xtensa-mx.c index a15a9510c904..e539500752d4 100644 --- a/drivers/irqchip/irq-xtensa-mx.c +++ b/drivers/irqchip/irq-xtensa-mx.c @@ -98,14 +98,12 @@ static void xtensa_mx_irq_unmask(struct irq_data *d) static void xtensa_mx_irq_enable(struct irq_data *d) { - variant_irq_enable(d->hwirq); xtensa_mx_irq_unmask(d); } static void xtensa_mx_irq_disable(struct irq_data *d) { xtensa_mx_irq_mask(d); - variant_irq_disable(d->hwirq); } static void xtensa_mx_irq_ack(struct irq_data *d) diff --git a/drivers/irqchip/irq-xtensa-pic.c b/drivers/irqchip/irq-xtensa-pic.c index f728755fa292..000cb5462bcf 100644 --- a/drivers/irqchip/irq-xtensa-pic.c +++ b/drivers/irqchip/irq-xtensa-pic.c @@ -55,14 +55,12 @@ static void xtensa_irq_unmask(struct irq_data *d) static void xtensa_irq_enable(struct irq_data *d) { - variant_irq_enable(d->hwirq); xtensa_irq_unmask(d); } static void xtensa_irq_disable(struct irq_data *d) { xtensa_irq_mask(d); - variant_irq_disable(d->hwirq); } static void xtensa_irq_ack(struct irq_data *d) diff --git a/drivers/macintosh/therm_windtunnel.c b/drivers/macintosh/therm_windtunnel.c index 68dcbcb4fc5b..8c744578122a 100644 --- a/drivers/macintosh/therm_windtunnel.c +++ b/drivers/macintosh/therm_windtunnel.c @@ -432,7 +432,6 @@ static struct i2c_driver g4fan_driver = { .driver = { .name = "therm_windtunnel", }, - .attach_adapter = do_attach, .probe = do_probe, .remove = do_remove, .id_table = therm_windtunnel_id, @@ -445,7 +444,29 @@ static struct i2c_driver g4fan_driver = { static int therm_of_probe(struct platform_device *dev) { - return i2c_add_driver( &g4fan_driver ); + struct i2c_adapter *adap; + int ret, i = 0; + + adap = i2c_get_adapter(0); + if (!adap) + return -EPROBE_DEFER; + + ret = i2c_add_driver(&g4fan_driver); + if (ret) { + i2c_put_adapter(adap); + return ret; + } + + /* We assume Macs have consecutive I2C bus numbers starting at 0 */ + while (adap) { + do_attach(adap); + if (x.running) + return 0; + i2c_put_adapter(adap); + adap = i2c_get_adapter(++i); + } + + return -ENODEV; } static int diff --git a/drivers/memory/tegra/mc.c b/drivers/memory/tegra/mc.c index bb93cc53554e..bd25faf6d13d 100644 --- a/drivers/memory/tegra/mc.c +++ b/drivers/memory/tegra/mc.c @@ -672,13 +672,6 @@ static int tegra_mc_probe(struct platform_device *pdev) return err; } - err = tegra_mc_reset_setup(mc); - if (err < 0) { - dev_err(&pdev->dev, "failed to register reset controller: %d\n", - err); - return err; - } - mc->irq = platform_get_irq(pdev, 0); if (mc->irq < 0) { dev_err(&pdev->dev, "interrupt not specified\n"); @@ -697,13 +690,16 @@ static int tegra_mc_probe(struct platform_device *pdev) return err; } + err = tegra_mc_reset_setup(mc); + if (err < 0) + dev_err(&pdev->dev, "failed to register reset controller: %d\n", + err); + if (IS_ENABLED(CONFIG_TEGRA_IOMMU_SMMU)) { mc->smmu = tegra_smmu_probe(&pdev->dev, mc->soc->smmu, mc); - if (IS_ERR(mc->smmu)) { + if (IS_ERR(mc->smmu)) dev_err(&pdev->dev, "failed to probe SMMU: %ld\n", PTR_ERR(mc->smmu)); - return PTR_ERR(mc->smmu); - } } return 0; diff --git a/drivers/memory/ti-emif-pm.c b/drivers/memory/ti-emif-pm.c index 632651f4b6e8..2250d03ea17f 100644 --- a/drivers/memory/ti-emif-pm.c +++ b/drivers/memory/ti-emif-pm.c @@ -249,6 +249,34 @@ static const struct of_device_id ti_emif_of_match[] = { }; MODULE_DEVICE_TABLE(of, ti_emif_of_match); +#ifdef CONFIG_PM_SLEEP +static int ti_emif_resume(struct device *dev) +{ + unsigned long tmp = + __raw_readl((void *)emif_instance->ti_emif_sram_virt); + + /* + * Check to see if what we are copying is already present in the + * first byte at the destination, only copy if it is not which + * indicates we have lost context and sram no longer contains + * the PM code + */ + if (tmp != ti_emif_sram) + ti_emif_push_sram(dev, emif_instance); + + return 0; +} + +static int ti_emif_suspend(struct device *dev) +{ + /* + * The contents will be present in DDR hence no need to + * explicitly save + */ + return 0; +} +#endif /* CONFIG_PM_SLEEP */ + static int ti_emif_probe(struct platform_device *pdev) { int ret; @@ -308,12 +336,17 @@ static int ti_emif_remove(struct platform_device *pdev) return 0; } +static const struct dev_pm_ops ti_emif_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(ti_emif_suspend, ti_emif_resume) +}; + static struct platform_driver ti_emif_driver = { .probe = ti_emif_probe, .remove = ti_emif_remove, .driver = { .name = KBUILD_MODNAME, .of_match_table = of_match_ptr(ti_emif_of_match), + .pm = &ti_emif_pm_ops, }, }; module_platform_driver(ti_emif_driver); diff --git a/drivers/mtd/ubi/cdev.c b/drivers/mtd/ubi/cdev.c index 45c329694a5e..22547d7a84ea 100644 --- a/drivers/mtd/ubi/cdev.c +++ b/drivers/mtd/ubi/cdev.c @@ -367,6 +367,10 @@ static ssize_t vol_cdev_write(struct file *file, const char __user *buf, return count; } + /* + * We voluntarily do not take into account the skip_check flag + * as we want to make sure what we wrote was correctly written. + */ err = ubi_check_volume(ubi, vol->vol_id); if (err < 0) return err; @@ -622,6 +626,13 @@ static int verify_mkvol_req(const struct ubi_device *ubi, req->vol_type != UBI_STATIC_VOLUME) goto bad; + if (req->flags & ~UBI_VOL_VALID_FLGS) + goto bad; + + if (req->flags & UBI_VOL_SKIP_CRC_CHECK_FLG && + req->vol_type != UBI_STATIC_VOLUME) + goto bad; + if (req->alignment > ubi->leb_size) goto bad; diff --git a/drivers/mtd/ubi/kapi.c b/drivers/mtd/ubi/kapi.c index d4b2e8744498..e9e9ecbcedcc 100644 --- a/drivers/mtd/ubi/kapi.c +++ b/drivers/mtd/ubi/kapi.c @@ -202,7 +202,7 @@ struct ubi_volume_desc *ubi_open_volume(int ubi_num, int vol_id, int mode) desc->mode = mode; mutex_lock(&ubi->ckvol_mutex); - if (!vol->checked) { + if (!vol->checked && !vol->skip_check) { /* This is the first open - check the volume */ err = ubi_check_volume(ubi, vol_id); if (err < 0) { diff --git a/drivers/mtd/ubi/ubi-media.h b/drivers/mtd/ubi/ubi-media.h index 195ff8ca8211..b5fe8f82281b 100644 --- a/drivers/mtd/ubi/ubi-media.h +++ b/drivers/mtd/ubi/ubi-media.h @@ -45,6 +45,11 @@ enum { * Volume flags used in the volume table record. * * @UBI_VTBL_AUTORESIZE_FLG: auto-resize this volume + * @UBI_VTBL_SKIP_CRC_CHECK_FLG: skip the CRC check done on a static volume at + * open time. Should only be set on volumes that + * are used by upper layers doing this kind of + * check. Main use-case for this flag is + * boot-time reduction * * %UBI_VTBL_AUTORESIZE_FLG flag can be set only for one volume in the volume * table. UBI automatically re-sizes the volume which has this flag and makes @@ -76,6 +81,7 @@ enum { */ enum { UBI_VTBL_AUTORESIZE_FLG = 0x01, + UBI_VTBL_SKIP_CRC_CHECK_FLG = 0x02, }; /* diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h index f5ba97c46160..d47b9e436e67 100644 --- a/drivers/mtd/ubi/ubi.h +++ b/drivers/mtd/ubi/ubi.h @@ -327,6 +327,9 @@ struct ubi_eba_leb_desc { * atomic LEB change * * @eba_tbl: EBA table of this volume (LEB->PEB mapping) + * @skip_check: %1 if CRC check of this static volume should be skipped. + * Directly reflects the presence of the + * %UBI_VTBL_SKIP_CRC_CHECK_FLG flag in the vtbl entry * @checked: %1 if this static volume was checked * @corrupted: %1 if the volume is corrupted (static volumes only) * @upd_marker: %1 if the update marker is set for this volume @@ -374,6 +377,7 @@ struct ubi_volume { void *upd_buf; struct ubi_eba_table *eba_tbl; + unsigned int skip_check:1; unsigned int checked:1; unsigned int corrupted:1; unsigned int upd_marker:1; diff --git a/drivers/mtd/ubi/vmt.c b/drivers/mtd/ubi/vmt.c index 0be516780e92..729588b94e41 100644 --- a/drivers/mtd/ubi/vmt.c +++ b/drivers/mtd/ubi/vmt.c @@ -174,6 +174,9 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req) vol->dev.class = &ubi_class; vol->dev.groups = volume_dev_groups; + if (req->flags & UBI_VOL_SKIP_CRC_CHECK_FLG) + vol->skip_check = 1; + spin_lock(&ubi->volumes_lock); if (vol_id == UBI_VOL_NUM_AUTO) { /* Find unused volume ID */ @@ -299,6 +302,10 @@ int ubi_create_volume(struct ubi_device *ubi, struct ubi_mkvol_req *req) vtbl_rec.vol_type = UBI_VID_DYNAMIC; else vtbl_rec.vol_type = UBI_VID_STATIC; + + if (vol->skip_check) + vtbl_rec.flags |= UBI_VTBL_SKIP_CRC_CHECK_FLG; + memcpy(vtbl_rec.name, vol->name, vol->name_len); err = ubi_change_vtbl_record(ubi, vol_id, &vtbl_rec); @@ -733,6 +740,11 @@ static int self_check_volume(struct ubi_device *ubi, int vol_id) ubi_err(ubi, "bad used_bytes"); goto fail; } + + if (vol->skip_check) { + ubi_err(ubi, "bad skip_check"); + goto fail; + } } else { if (vol->used_ebs < 0 || vol->used_ebs > vol->reserved_pebs) { ubi_err(ubi, "bad used_ebs"); diff --git a/drivers/mtd/ubi/vtbl.c b/drivers/mtd/ubi/vtbl.c index 94d7a865b135..1bc82154bb18 100644 --- a/drivers/mtd/ubi/vtbl.c +++ b/drivers/mtd/ubi/vtbl.c @@ -560,6 +560,9 @@ static int init_volumes(struct ubi_device *ubi, vol->name[vol->name_len] = '\0'; vol->vol_id = i; + if (vtbl[i].flags & UBI_VTBL_SKIP_CRC_CHECK_FLG) + vol->skip_check = 1; + if (vtbl[i].flags & UBI_VTBL_AUTORESIZE_FLG) { /* Auto re-size flag may be set only for one volume */ if (ubi->autoresize_vol_id != -1) { @@ -579,6 +582,16 @@ static int init_volumes(struct ubi_device *ubi, reserved_pebs += vol->reserved_pebs; /* + * We use ubi->peb_count and not vol->reserved_pebs because + * we want to keep the code simple. Otherwise we'd have to + * resize/check the bitmap upon volume resize too. + * Allocating a few bytes more does not hurt. + */ + err = ubi_fastmap_init_checkmap(vol, ubi->peb_count); + if (err) + return err; + + /* * In case of dynamic volume UBI knows nothing about how many * data is stored there. So assume the whole volume is used. */ @@ -620,16 +633,6 @@ static int init_volumes(struct ubi_device *ubi, (long long)(vol->used_ebs - 1) * vol->usable_leb_size; vol->used_bytes += av->last_data_size; vol->last_eb_bytes = av->last_data_size; - - /* - * We use ubi->peb_count and not vol->reserved_pebs because - * we want to keep the code simple. Otherwise we'd have to - * resize/check the bitmap upon volume resize too. - * Allocating a few bytes more does not hurt. - */ - err = ubi_fastmap_init_checkmap(vol, ubi->peb_count); - if (err) - return err; } /* And add the layout volume */ diff --git a/drivers/net/ethernet/smsc/smc911x.c b/drivers/net/ethernet/smsc/smc911x.c index 05157442a980..b1b53f6c452f 100644 --- a/drivers/net/ethernet/smsc/smc911x.c +++ b/drivers/net/ethernet/smsc/smc911x.c @@ -74,7 +74,6 @@ static const char version[] = #include <linux/skbuff.h> #include <linux/dmaengine.h> -#include <linux/dma/pxa-dma.h> #include <asm/io.h> @@ -1795,7 +1794,6 @@ static int smc911x_probe(struct net_device *dev) #ifdef SMC_USE_DMA struct dma_slave_config config; dma_cap_mask_t mask; - struct pxad_param param; #endif DBG(SMC_DEBUG_FUNC, dev, "--> %s\n", __func__); @@ -1971,15 +1969,8 @@ static int smc911x_probe(struct net_device *dev) dma_cap_zero(mask); dma_cap_set(DMA_SLAVE, mask); - param.prio = PXAD_PRIO_LOWEST; - param.drcmr = -1UL; - - lp->rxdma = - dma_request_slave_channel_compat(mask, pxad_filter_fn, - ¶m, &dev->dev, "rx"); - lp->txdma = - dma_request_slave_channel_compat(mask, pxad_filter_fn, - ¶m, &dev->dev, "tx"); + lp->rxdma = dma_request_channel(mask, NULL, NULL); + lp->txdma = dma_request_channel(mask, NULL, NULL); lp->rxdma_active = 0; lp->txdma_active = 0; diff --git a/drivers/net/ethernet/smsc/smc91x.c b/drivers/net/ethernet/smsc/smc91x.c index 080428762858..b944828f9ea3 100644 --- a/drivers/net/ethernet/smsc/smc91x.c +++ b/drivers/net/ethernet/smsc/smc91x.c @@ -2019,17 +2019,10 @@ static int smc_probe(struct net_device *dev, void __iomem *ioaddr, # endif if (lp->cfg.flags & SMC91X_USE_DMA) { dma_cap_mask_t mask; - struct pxad_param param; dma_cap_zero(mask); dma_cap_set(DMA_SLAVE, mask); - param.prio = PXAD_PRIO_LOWEST; - param.drcmr = -1UL; - - lp->dma_chan = - dma_request_slave_channel_compat(mask, pxad_filter_fn, - ¶m, &dev->dev, - "data"); + lp->dma_chan = dma_request_channel(mask, NULL, NULL); } #endif diff --git a/drivers/net/ethernet/smsc/smc91x.h b/drivers/net/ethernet/smsc/smc91x.h index b337ee97e0c0..a27352229fc2 100644 --- a/drivers/net/ethernet/smsc/smc91x.h +++ b/drivers/net/ethernet/smsc/smc91x.h @@ -301,7 +301,6 @@ struct smc_local { * as RX which can overrun memory and lose packets. */ #include <linux/dma-mapping.h> -#include <linux/dma/pxa-dma.h> #ifdef SMC_insl #undef SMC_insl diff --git a/drivers/platform/mellanox/Kconfig b/drivers/platform/mellanox/Kconfig index 591bccdeaff9..cd8a90846063 100644 --- a/drivers/platform/mellanox/Kconfig +++ b/drivers/platform/mellanox/Kconfig @@ -23,4 +23,15 @@ config MLXREG_HOTPLUG This driver handles hot-plug events for the power suppliers, power cables and fans on the wide range Mellanox IB and Ethernet systems. +config MLXREG_IO + tristate "Mellanox platform register access driver support" + depends on REGMAP + depends on HWMON + help + This driver allows access to Mellanox programmable device register + space through sysfs interface. The sets of registers for sysfs access + are defined per system type bases and include the registers related + to system resets operation, system reset causes monitoring and some + kinds of mux selection. + endif # MELLANOX_PLATFORM diff --git a/drivers/platform/mellanox/Makefile b/drivers/platform/mellanox/Makefile index 7c8385e497a8..57074d9c722c 100644 --- a/drivers/platform/mellanox/Makefile +++ b/drivers/platform/mellanox/Makefile @@ -4,3 +4,4 @@ # Mellanox Platform-Specific Drivers # obj-$(CONFIG_MLXREG_HOTPLUG) += mlxreg-hotplug.o +obj-$(CONFIG_MLXREG_IO) += mlxreg-io.o diff --git a/drivers/platform/mellanox/mlxreg-hotplug.c b/drivers/platform/mellanox/mlxreg-hotplug.c index ac97aa020db3..b6d44550d98c 100644 --- a/drivers/platform/mellanox/mlxreg-hotplug.c +++ b/drivers/platform/mellanox/mlxreg-hotplug.c @@ -50,9 +50,8 @@ #define MLXREG_HOTPLUG_MASK_OFF 2 #define MLXREG_HOTPLUG_AGGR_MASK_OFF 1 -/* ASIC health parameters. */ -#define MLXREG_HOTPLUG_HEALTH_MASK 0x02 -#define MLXREG_HOTPLUG_RST_CNTR 3 +/* ASIC good health mask. */ +#define MLXREG_HOTPLUG_GOOD_HEALTH_MASK 0x02 #define MLXREG_HOTPLUG_ATTRS_MAX 24 #define MLXREG_HOTPLUG_NOT_ASSERT 3 @@ -103,6 +102,9 @@ static int mlxreg_hotplug_device_create(struct mlxreg_hotplug_priv_data *priv, { struct mlxreg_core_hotplug_platform_data *pdata; + /* Notify user by sending hwmon uevent. */ + kobject_uevent(&priv->hwmon->kobj, KOBJ_CHANGE); + /* * Return if adapter number is negative. It could be in case hotplug * event is not associated with hotplug device. @@ -134,8 +136,13 @@ static int mlxreg_hotplug_device_create(struct mlxreg_hotplug_priv_data *priv, return 0; } -static void mlxreg_hotplug_device_destroy(struct mlxreg_core_data *data) +static void +mlxreg_hotplug_device_destroy(struct mlxreg_hotplug_priv_data *priv, + struct mlxreg_core_data *data) { + /* Notify user by sending hwmon uevent. */ + kobject_uevent(&priv->hwmon->kobj, KOBJ_CHANGE); + if (data->hpdev.client) { i2c_unregister_device(data->hpdev.client); data->hpdev.client = NULL; @@ -278,14 +285,14 @@ mlxreg_hotplug_work_helper(struct mlxreg_hotplug_priv_data *priv, data = item->data + bit; if (regval & BIT(bit)) { if (item->inversed) - mlxreg_hotplug_device_destroy(data); + mlxreg_hotplug_device_destroy(priv, data); else mlxreg_hotplug_device_create(priv, data); } else { if (item->inversed) mlxreg_hotplug_device_create(priv, data); else - mlxreg_hotplug_device_destroy(data); + mlxreg_hotplug_device_destroy(priv, data); } } @@ -325,21 +332,40 @@ mlxreg_hotplug_health_work_helper(struct mlxreg_hotplug_priv_data *priv, goto out; regval &= data->mask; - item->cache = regval; - if (regval == MLXREG_HOTPLUG_HEALTH_MASK) { - if ((data->health_cntr++ == MLXREG_HOTPLUG_RST_CNTR) || - !priv->after_probe) { + + if (item->cache == regval) + goto ack_event; + + /* + * ASIC health indication is provided through two bits. Bits + * value 0x2 indicates that ASIC reached the good health, value + * 0x0 indicates ASIC the bad health or dormant state and value + * 0x3 indicates the booting state. During ASIC reset it should + * pass the following states: dormant -> booting -> good. + */ + if (regval == MLXREG_HOTPLUG_GOOD_HEALTH_MASK) { + if (!data->attached) { + /* + * ASIC is in steady state. Connect associated + * device, if configured. + */ mlxreg_hotplug_device_create(priv, data); data->attached = true; } } else { if (data->attached) { - mlxreg_hotplug_device_destroy(data); + /* + * ASIC health is failed after ASIC has been + * in steady state. Disconnect associated + * device, if it has been connected. + */ + mlxreg_hotplug_device_destroy(priv, data); data->attached = false; data->health_cntr = 0; } } - + item->cache = regval; +ack_event: /* Acknowledge event. */ ret = regmap_write(priv->regmap, data->reg + MLXREG_HOTPLUG_EVENT_OFF, 0); @@ -551,7 +577,7 @@ static void mlxreg_hotplug_unset_irq(struct mlxreg_hotplug_priv_data *priv) /* Remove all the attached devices in group. */ count = item->count; for (j = 0; j < count; j++, data++) - mlxreg_hotplug_device_destroy(data); + mlxreg_hotplug_device_destroy(priv, data); } } @@ -616,10 +642,6 @@ static int mlxreg_hotplug_probe(struct platform_device *pdev) disable_irq(priv->irq); spin_lock_init(&priv->lock); INIT_DELAYED_WORK(&priv->dwork_irq, mlxreg_hotplug_work_handler); - /* Perform initial interrupts setup. */ - mlxreg_hotplug_set_irq(priv); - - priv->after_probe = true; dev_set_drvdata(&pdev->dev, priv); err = mlxreg_hotplug_attr_init(priv); @@ -637,6 +659,10 @@ static int mlxreg_hotplug_probe(struct platform_device *pdev) return PTR_ERR(priv->hwmon); } + /* Perform initial interrupts setup. */ + mlxreg_hotplug_set_irq(priv); + priv->after_probe = true; + return 0; } diff --git a/drivers/platform/mellanox/mlxreg-io.c b/drivers/platform/mellanox/mlxreg-io.c new file mode 100644 index 000000000000..acfaf64ffde6 --- /dev/null +++ b/drivers/platform/mellanox/mlxreg-io.c @@ -0,0 +1,245 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Mellanox register access driver + * + * Copyright (C) 2018 Mellanox Technologies + * Copyright (C) 2018 Vadim Pasternak <vadimp@mellanox.com> + */ + +#include <linux/bitops.h> +#include <linux/device.h> +#include <linux/hwmon.h> +#include <linux/hwmon-sysfs.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/platform_data/mlxreg.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> + +/* Attribute parameters. */ +#define MLXREG_IO_ATT_SIZE 10 +#define MLXREG_IO_ATT_NUM 48 + +/** + * struct mlxreg_io_priv_data - driver's private data: + * + * @pdev: platform device; + * @pdata: platform data; + * @hwmon: hwmon device; + * @mlxreg_io_attr: sysfs attributes array; + * @mlxreg_io_dev_attr: sysfs sensor device attribute array; + * @group: sysfs attribute group; + * @groups: list of sysfs attribute group for hwmon registration; + */ +struct mlxreg_io_priv_data { + struct platform_device *pdev; + struct mlxreg_core_platform_data *pdata; + struct device *hwmon; + struct attribute *mlxreg_io_attr[MLXREG_IO_ATT_NUM + 1]; + struct sensor_device_attribute mlxreg_io_dev_attr[MLXREG_IO_ATT_NUM]; + struct attribute_group group; + const struct attribute_group *groups[2]; +}; + +static int +mlxreg_io_get_reg(void *regmap, struct mlxreg_core_data *data, u32 in_val, + bool rw_flag, u32 *regval) +{ + int ret; + + ret = regmap_read(regmap, data->reg, regval); + if (ret) + goto access_error; + + /* + * There are three kinds of attributes: single bit, full register's + * bits and bit sequence. For the first kind field mask indicates which + * bits are not related and field bit is set zero. For the second kind + * field mask is set to zero and field bit is set with all bits one. + * No special handling for such kind of attributes - pass value as is. + * For the third kind, field mask indicates which bits are related and + * field bit is set to the first bit number (from 1 to 32) is the bit + * sequence. + */ + if (!data->bit) { + /* Single bit. */ + if (rw_flag) { + /* For show: expose effective bit value as 0 or 1. */ + *regval = !!(*regval & ~data->mask); + } else { + /* For store: set effective bit value. */ + *regval &= data->mask; + if (in_val) + *regval |= ~data->mask; + } + } else if (data->mask) { + /* Bit sequence. */ + if (rw_flag) { + /* For show: mask and shift right. */ + *regval = ror32(*regval & data->mask, (data->bit - 1)); + } else { + /* For store: shift to the position and mask. */ + in_val = rol32(in_val, data->bit - 1) & data->mask; + /* Clear relevant bits and set them to new value. */ + *regval = (*regval & ~data->mask) | in_val; + } + } + +access_error: + return ret; +} + +static ssize_t +mlxreg_io_attr_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct mlxreg_io_priv_data *priv = dev_get_drvdata(dev); + int index = to_sensor_dev_attr(attr)->index; + struct mlxreg_core_data *data = priv->pdata->data + index; + u32 regval = 0; + int ret; + + ret = mlxreg_io_get_reg(priv->pdata->regmap, data, 0, true, ®val); + if (ret) + goto access_error; + + return sprintf(buf, "%u\n", regval); + +access_error: + return ret; +} + +static ssize_t +mlxreg_io_attr_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t len) +{ + struct mlxreg_io_priv_data *priv = dev_get_drvdata(dev); + int index = to_sensor_dev_attr(attr)->index; + struct mlxreg_core_data *data = priv->pdata->data + index; + u32 input_val, regval; + int ret; + + if (len > MLXREG_IO_ATT_SIZE) + return -EINVAL; + + /* Convert buffer to input value. */ + ret = kstrtou32(buf, len, &input_val); + if (ret) + return ret; + + ret = mlxreg_io_get_reg(priv->pdata->regmap, data, input_val, false, + ®val); + if (ret) + goto access_error; + + ret = regmap_write(priv->pdata->regmap, data->reg, regval); + if (ret) + goto access_error; + + return len; + +access_error: + dev_err(&priv->pdev->dev, "Bus access error\n"); + return ret; +} + +static struct device_attribute mlxreg_io_devattr_rw = { + .show = mlxreg_io_attr_show, + .store = mlxreg_io_attr_store, +}; + +static int mlxreg_io_attr_init(struct mlxreg_io_priv_data *priv) +{ + int i; + + priv->group.attrs = devm_kcalloc(&priv->pdev->dev, + priv->pdata->counter, + sizeof(struct attribute *), + GFP_KERNEL); + if (!priv->group.attrs) + return -ENOMEM; + + for (i = 0; i < priv->pdata->counter; i++) { + priv->mlxreg_io_attr[i] = + &priv->mlxreg_io_dev_attr[i].dev_attr.attr; + memcpy(&priv->mlxreg_io_dev_attr[i].dev_attr, + &mlxreg_io_devattr_rw, sizeof(struct device_attribute)); + + /* Set attribute name as a label. */ + priv->mlxreg_io_attr[i]->name = + devm_kasprintf(&priv->pdev->dev, GFP_KERNEL, + priv->pdata->data[i].label); + + if (!priv->mlxreg_io_attr[i]->name) { + dev_err(&priv->pdev->dev, "Memory allocation failed for sysfs attribute %d.\n", + i + 1); + return -ENOMEM; + } + + priv->mlxreg_io_dev_attr[i].dev_attr.attr.mode = + priv->pdata->data[i].mode; + priv->mlxreg_io_dev_attr[i].dev_attr.attr.name = + priv->mlxreg_io_attr[i]->name; + priv->mlxreg_io_dev_attr[i].index = i; + sysfs_attr_init(&priv->mlxreg_io_dev_attr[i].dev_attr.attr); + } + + priv->group.attrs = priv->mlxreg_io_attr; + priv->groups[0] = &priv->group; + priv->groups[1] = NULL; + + return 0; +} + +static int mlxreg_io_probe(struct platform_device *pdev) +{ + struct mlxreg_io_priv_data *priv; + int err; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->pdata = dev_get_platdata(&pdev->dev); + if (!priv->pdata) { + dev_err(&pdev->dev, "Failed to get platform data.\n"); + return -EINVAL; + } + + priv->pdev = pdev; + + err = mlxreg_io_attr_init(priv); + if (err) { + dev_err(&priv->pdev->dev, "Failed to allocate attributes: %d\n", + err); + return err; + } + + priv->hwmon = devm_hwmon_device_register_with_groups(&pdev->dev, + "mlxreg_io", + priv, + priv->groups); + if (IS_ERR(priv->hwmon)) { + dev_err(&pdev->dev, "Failed to register hwmon device %ld\n", + PTR_ERR(priv->hwmon)); + return PTR_ERR(priv->hwmon); + } + + dev_set_drvdata(&pdev->dev, priv); + + return 0; +} + +static struct platform_driver mlxreg_io_driver = { + .driver = { + .name = "mlxreg-io", + }, + .probe = mlxreg_io_probe, +}; + +module_platform_driver(mlxreg_io_driver); + +MODULE_AUTHOR("Vadim Pasternak <vadimp@mellanox.com>"); +MODULE_DESCRIPTION("Mellanox regmap I/O access driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:mlxreg-io"); diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 107d336453b2..0c1aa6c314f5 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -1196,16 +1196,16 @@ config INTEL_TURBO_MAX_3 This driver is only required when the system is not using Hardware P-States (HWP). In HWP mode, priority can be read from ACPI tables. -config SILEAD_DMI - bool "Tablets with Silead touchscreens" +config TOUCHSCREEN_DMI + bool "DMI based touchscreen configuration info" depends on ACPI && DMI && I2C=y && TOUCHSCREEN_SILEAD ---help--- - Certain ACPI based tablets with Silead touchscreens do not have - enough data in ACPI tables for the touchscreen driver to handle - the touchscreen properly, as OEMs expected the data to be baked - into the tablet model specific version of the driver shipped - with the OS-image for the device. This option supplies the missing - information. Enable this for x86 tablets with Silead touchscreens. + Certain ACPI based tablets with e.g. Silead or Chipone touchscreens + do not have enough data in ACPI tables for the touchscreen driver to + handle the touchscreen properly, as OEMs expect the data to be baked + into the tablet model specific version of the driver shipped with the + the OS-image for the device. This option supplies the missing info. + Enable this for x86 tablets with Silead or Chipone touchscreens. config INTEL_CHTDC_TI_PWRBTN tristate "Intel Cherry Trail Dollar Cove TI power button driver" diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index 50dc8f280914..e6d1becf81ce 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -78,7 +78,7 @@ obj-$(CONFIG_INTEL_SMARTCONNECT) += intel-smartconnect.o obj-$(CONFIG_PVPANIC) += pvpanic.o obj-$(CONFIG_ALIENWARE_WMI) += alienware-wmi.o obj-$(CONFIG_INTEL_PMC_IPC) += intel_pmc_ipc.o -obj-$(CONFIG_SILEAD_DMI) += silead_dmi.o +obj-$(CONFIG_TOUCHSCREEN_DMI) += touchscreen_dmi.o obj-$(CONFIG_SURFACE_PRO3_BUTTON) += surfacepro3_button.o obj-$(CONFIG_SURFACE_3_BUTTON) += surface3_button.o obj-$(CONFIG_INTEL_PUNIT_IPC) += intel_punit_ipc.o diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index 8952173dd380..fcfeadd1301f 100644 --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c @@ -672,10 +672,7 @@ static void __init find_quirks(void) static bool has_cap(u32 cap) { - if ((interface->capability & cap) != 0) - return 1; - - return 0; + return interface->capability & cap; } /* @@ -2216,7 +2213,7 @@ static int __init acer_wmi_init(void) if (wmi_has_guid(AMW0_GUID1) && !dmi_check_system(amw0_whitelist) && quirks == &quirk_unknown) { - pr_err("Unsupported machine has AMW0_GUID1, unable to load\n"); + pr_debug("Unsupported machine has AMW0_GUID1, unable to load\n"); return -ENODEV; } diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c index 136ff2b4cce5..db2af09067db 100644 --- a/drivers/platform/x86/asus-nb-wmi.c +++ b/drivers/platform/x86/asus-nb-wmi.c @@ -496,6 +496,7 @@ static const struct key_entry asus_nb_wmi_keymap[] = { { KE_KEY, 0xC4, { KEY_KBDILLUMUP } }, { KE_KEY, 0xC5, { KEY_KBDILLUMDOWN } }, { KE_IGNORE, 0xC6, }, /* Ambient Light Sensor notification */ + { KE_KEY, 0xFA, { KEY_PROG2 } }, /* Lid flip action */ { KE_END, 0}, }; diff --git a/drivers/platform/x86/asus-wireless.c b/drivers/platform/x86/asus-wireless.c index 6afd011de9e5..7458f7602d5e 100644 --- a/drivers/platform/x86/asus-wireless.c +++ b/drivers/platform/x86/asus-wireless.c @@ -52,13 +52,12 @@ static const struct acpi_device_id device_ids[] = { }; MODULE_DEVICE_TABLE(acpi, device_ids); -static u64 asus_wireless_method(acpi_handle handle, const char *method, - int param) +static acpi_status asus_wireless_method(acpi_handle handle, const char *method, + int param, u64 *ret) { struct acpi_object_list p; union acpi_object obj; acpi_status s; - u64 ret; acpi_handle_debug(handle, "Evaluating method %s, parameter %#x\n", method, param); @@ -67,24 +66,27 @@ static u64 asus_wireless_method(acpi_handle handle, const char *method, p.count = 1; p.pointer = &obj; - s = acpi_evaluate_integer(handle, (acpi_string) method, &p, &ret); + s = acpi_evaluate_integer(handle, (acpi_string) method, &p, ret); if (ACPI_FAILURE(s)) acpi_handle_err(handle, "Failed to eval method %s, param %#x (%d)\n", method, param, s); - acpi_handle_debug(handle, "%s returned %#llx\n", method, ret); - return ret; + else + acpi_handle_debug(handle, "%s returned %#llx\n", method, *ret); + + return s; } static enum led_brightness led_state_get(struct led_classdev *led) { struct asus_wireless_data *data; - int s; + acpi_status s; + u64 ret; data = container_of(led, struct asus_wireless_data, led); s = asus_wireless_method(acpi_device_handle(data->adev), "HSWC", - data->hswc_params->status); - if (s == data->hswc_params->on) + data->hswc_params->status, &ret); + if (ACPI_SUCCESS(s) && ret == data->hswc_params->on) return LED_FULL; return LED_OFF; } @@ -92,10 +94,11 @@ static enum led_brightness led_state_get(struct led_classdev *led) static void led_state_update(struct work_struct *work) { struct asus_wireless_data *data; + u64 ret; data = container_of(work, struct asus_wireless_data, led_work); asus_wireless_method(acpi_device_handle(data->adev), "HSWC", - data->led_state); + data->led_state, &ret); } static void led_state_set(struct led_classdev *led, enum led_brightness value) @@ -167,6 +170,7 @@ static int asus_wireless_add(struct acpi_device *adev) data->led.brightness_get = led_state_get; data->led.flags = LED_CORE_SUSPENDRESUME; data->led.max_brightness = 1; + data->led.default_trigger = "rfkill-none"; err = devm_led_classdev_register(&adev->dev, &data->led); if (err) destroy_workqueue(data->wq); diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index d67f32a29bb4..2d6e272315a8 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -67,6 +67,7 @@ MODULE_LICENSE("GPL"); #define NOTIFY_BRNDOWN_MAX 0x2e #define NOTIFY_KBD_BRTUP 0xc4 #define NOTIFY_KBD_BRTDWN 0xc5 +#define NOTIFY_KBD_BRTTOGGLE 0xc7 /* WMI Methods */ #define ASUS_WMI_METHODID_SPEC 0x43455053 /* BIOS SPECification */ @@ -470,6 +471,7 @@ static void kbd_led_update(struct work_struct *work) ctrl_param = 0x80 | (asus->kbd_led_wk & 0x7F); asus_wmi_set_devstate(ASUS_WMI_DEVID_KBD_BACKLIGHT, ctrl_param, NULL); + led_classdev_notify_brightness_hw_changed(&asus->kbd_led, asus->kbd_led_wk); } static int kbd_led_read(struct asus_wmi *asus, int *level, int *env) @@ -500,15 +502,16 @@ static int kbd_led_read(struct asus_wmi *asus, int *level, int *env) return retval; } -static void kbd_led_set(struct led_classdev *led_cdev, - enum led_brightness value) +static void do_kbd_led_set(struct led_classdev *led_cdev, int value) { struct asus_wmi *asus; + int max_level; asus = container_of(led_cdev, struct asus_wmi, kbd_led); + max_level = asus->kbd_led.max_brightness; - if (value > asus->kbd_led.max_brightness) - value = asus->kbd_led.max_brightness; + if (value > max_level) + value = max_level; else if (value < 0) value = 0; @@ -516,6 +519,12 @@ static void kbd_led_set(struct led_classdev *led_cdev, queue_work(asus->led_workqueue, &asus->kbd_led_work); } +static void kbd_led_set(struct led_classdev *led_cdev, + enum led_brightness value) +{ + do_kbd_led_set(led_cdev, value); +} + static enum led_brightness kbd_led_get(struct led_classdev *led_cdev) { struct asus_wmi *asus; @@ -666,6 +675,7 @@ static int asus_wmi_led_init(struct asus_wmi *asus) asus->kbd_led_wk = led_val; asus->kbd_led.name = "asus::kbd_backlight"; + asus->kbd_led.flags = LED_BRIGHT_HW_CHANGED; asus->kbd_led.brightness_set = kbd_led_set; asus->kbd_led.brightness_get = kbd_led_get; asus->kbd_led.max_brightness = 3; @@ -1754,6 +1764,22 @@ static void asus_wmi_notify(u32 value, void *context) } } + if (code == NOTIFY_KBD_BRTUP) { + do_kbd_led_set(&asus->kbd_led, asus->kbd_led_wk + 1); + goto exit; + } + if (code == NOTIFY_KBD_BRTDWN) { + do_kbd_led_set(&asus->kbd_led, asus->kbd_led_wk - 1); + goto exit; + } + if (code == NOTIFY_KBD_BRTTOGGLE) { + if (asus->kbd_led_wk == asus->kbd_led.max_brightness) + do_kbd_led_set(&asus->kbd_led, 0); + else + do_kbd_led_set(&asus->kbd_led, asus->kbd_led_wk + 1); + goto exit; + } + if (is_display_toggle(code) && asus->driver->quirks->no_display_toggle) goto exit; diff --git a/drivers/platform/x86/dell-smbios-base.c b/drivers/platform/x86/dell-smbios-base.c index 9dc282ed5a9e..0537d44d45a6 100644 --- a/drivers/platform/x86/dell-smbios-base.c +++ b/drivers/platform/x86/dell-smbios-base.c @@ -212,6 +212,12 @@ int dell_smbios_call_filter(struct device *d, if ((buffer->cmd_class == CLASS_TOKEN_READ || buffer->cmd_class == CLASS_TOKEN_WRITE) && buffer->cmd_select < 3) { + /* tokens enabled ? */ + if (!da_tokens) { + dev_dbg(d, "no token support on this system\n"); + return -EINVAL; + } + /* find the matching token ID */ for (i = 0; i < da_num_tokens; i++) { if (da_tokens[i].location != buffer->input[0]) @@ -315,6 +321,9 @@ struct calling_interface_token *dell_smbios_find_token(int tokenid) { int i; + if (!da_tokens) + return NULL; + for (i = 0; i < da_num_tokens; i++) { if (da_tokens[i].tokenID == tokenid) return &da_tokens[i]; @@ -565,11 +574,6 @@ static int __init dell_smbios_init(void) dmi_walk(find_tokens, NULL); - if (!da_tokens) { - pr_info("Unable to find dmi tokens\n"); - return -ENODEV; - } - ret = platform_driver_register(&platform_driver); if (ret) goto fail_platform_driver; @@ -583,13 +587,6 @@ static int __init dell_smbios_init(void) if (ret) goto fail_platform_device_add; - /* duplicate tokens will cause problems building sysfs files */ - zero_duplicates(&platform_device->dev); - - ret = build_tokens_sysfs(platform_device); - if (ret) - goto fail_create_group; - /* register backends */ wmi = init_dell_smbios_wmi(); if (wmi) @@ -600,7 +597,16 @@ static int __init dell_smbios_init(void) if (wmi && smm) { pr_err("No SMBIOS backends available (wmi: %d, smm: %d)\n", wmi, smm); - goto fail_sysfs; + goto fail_create_group; + } + + if (da_tokens) { + /* duplicate tokens will cause problems building sysfs files */ + zero_duplicates(&platform_device->dev); + + ret = build_tokens_sysfs(platform_device); + if (ret) + goto fail_sysfs; } return 0; @@ -628,7 +634,8 @@ static void __exit dell_smbios_exit(void) exit_dell_smbios_smm(); mutex_lock(&smbios_mutex); if (platform_device) { - free_group(platform_device); + if (da_tokens) + free_group(platform_device); platform_device_unregister(platform_device); platform_driver_unregister(&platform_driver); } diff --git a/drivers/platform/x86/dell-smbios-smm.c b/drivers/platform/x86/dell-smbios-smm.c index e9e9da556318..97a90bebc360 100644 --- a/drivers/platform/x86/dell-smbios-smm.c +++ b/drivers/platform/x86/dell-smbios-smm.c @@ -24,7 +24,7 @@ static int da_command_address; static int da_command_code; static struct calling_interface_buffer *buffer; -struct platform_device *platform_device; +static struct platform_device *platform_device; static DEFINE_MUTEX(smm_mutex); static const struct dmi_system_id dell_device_table[] __initconst = { @@ -82,7 +82,7 @@ static void find_cmd_address(const struct dmi_header *dm, void *dummy) } } -int dell_smbios_smm_call(struct calling_interface_buffer *input) +static int dell_smbios_smm_call(struct calling_interface_buffer *input) { struct smi_cmd command; size_t size; diff --git a/drivers/platform/x86/dell-smbios-wmi.c b/drivers/platform/x86/dell-smbios-wmi.c index fbefedb1c172..88afe5651d24 100644 --- a/drivers/platform/x86/dell-smbios-wmi.c +++ b/drivers/platform/x86/dell-smbios-wmi.c @@ -82,7 +82,7 @@ static int run_smbios_call(struct wmi_device *wdev) return 0; } -int dell_smbios_wmi_call(struct calling_interface_buffer *buffer) +static int dell_smbios_wmi_call(struct calling_interface_buffer *buffer) { struct wmi_smbios_priv *priv; size_t difference; diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c index 45b7cb01f410..d4f1259ff5a2 100644 --- a/drivers/platform/x86/ideapad-laptop.c +++ b/drivers/platform/x86/ideapad-laptop.c @@ -1133,10 +1133,17 @@ static const struct dmi_system_id no_hw_rfkill_list[] = { }, }, { - .ident = "Lenovo Legion Y520-15IKBN", + .ident = "Lenovo Legion Y520-15IKB", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), - DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Y520-15IKBN"), + DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Y520-15IKB"), + }, + }, + { + .ident = "Lenovo Y520-15IKBM", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Y520-15IKBM"), }, }, { @@ -1154,6 +1161,13 @@ static const struct dmi_system_id no_hw_rfkill_list[] = { }, }, { + .ident = "Lenovo Y720-15IKBM", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Y720-15IKBM"), + }, + }, + { .ident = "Lenovo Yoga 2 11 / 13 / Pro", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), diff --git a/drivers/platform/x86/intel-hid.c b/drivers/platform/x86/intel-hid.c index b5adba227783..6cf9b7fa5bf0 100644 --- a/drivers/platform/x86/intel-hid.c +++ b/drivers/platform/x86/intel-hid.c @@ -96,13 +96,140 @@ struct intel_hid_priv { bool wakeup_mode; }; -static int intel_hid_set_enable(struct device *device, bool enable) +#define HID_EVENT_FILTER_UUID "eeec56b3-4442-408f-a792-4edd4d758054" + +enum intel_hid_dsm_fn_codes { + INTEL_HID_DSM_FN_INVALID, + INTEL_HID_DSM_BTNL_FN, + INTEL_HID_DSM_HDMM_FN, + INTEL_HID_DSM_HDSM_FN, + INTEL_HID_DSM_HDEM_FN, + INTEL_HID_DSM_BTNS_FN, + INTEL_HID_DSM_BTNE_FN, + INTEL_HID_DSM_HEBC_V1_FN, + INTEL_HID_DSM_VGBS_FN, + INTEL_HID_DSM_HEBC_V2_FN, + INTEL_HID_DSM_FN_MAX +}; + +static const char *intel_hid_dsm_fn_to_method[INTEL_HID_DSM_FN_MAX] = { + NULL, + "BTNL", + "HDMM", + "HDSM", + "HDEM", + "BTNS", + "BTNE", + "HEBC", + "VGBS", + "HEBC" +}; + +static unsigned long long intel_hid_dsm_fn_mask; +static guid_t intel_dsm_guid; + +static bool intel_hid_execute_method(acpi_handle handle, + enum intel_hid_dsm_fn_codes fn_index, + unsigned long long arg) { + union acpi_object *obj, argv4, req; acpi_status status; + char *method_name; - status = acpi_execute_simple_method(ACPI_HANDLE(device), "HDSM", - enable); - if (ACPI_FAILURE(status)) { + if (fn_index <= INTEL_HID_DSM_FN_INVALID || + fn_index >= INTEL_HID_DSM_FN_MAX) + return false; + + method_name = (char *)intel_hid_dsm_fn_to_method[fn_index]; + + if (!(intel_hid_dsm_fn_mask & fn_index)) + goto skip_dsm_exec; + + /* All methods expects a package with one integer element */ + req.type = ACPI_TYPE_INTEGER; + req.integer.value = arg; + + argv4.type = ACPI_TYPE_PACKAGE; + argv4.package.count = 1; + argv4.package.elements = &req; + + obj = acpi_evaluate_dsm(handle, &intel_dsm_guid, 1, fn_index, &argv4); + if (obj) { + acpi_handle_debug(handle, "Exec DSM Fn code: %d[%s] success\n", + fn_index, method_name); + ACPI_FREE(obj); + return true; + } + +skip_dsm_exec: + status = acpi_execute_simple_method(handle, method_name, arg); + if (ACPI_SUCCESS(status)) + return true; + + return false; +} + +static bool intel_hid_evaluate_method(acpi_handle handle, + enum intel_hid_dsm_fn_codes fn_index, + unsigned long long *result) +{ + union acpi_object *obj; + acpi_status status; + char *method_name; + + if (fn_index <= INTEL_HID_DSM_FN_INVALID || + fn_index >= INTEL_HID_DSM_FN_MAX) + return false; + + method_name = (char *)intel_hid_dsm_fn_to_method[fn_index]; + + if (!(intel_hid_dsm_fn_mask & fn_index)) + goto skip_dsm_eval; + + obj = acpi_evaluate_dsm_typed(handle, &intel_dsm_guid, + 1, fn_index, + NULL, ACPI_TYPE_INTEGER); + if (obj) { + *result = obj->integer.value; + acpi_handle_debug(handle, + "Eval DSM Fn code: %d[%s] results: 0x%llx\n", + fn_index, method_name, *result); + ACPI_FREE(obj); + return true; + } + +skip_dsm_eval: + status = acpi_evaluate_integer(handle, method_name, NULL, result); + if (ACPI_SUCCESS(status)) + return true; + + return false; +} + +static void intel_hid_init_dsm(acpi_handle handle) +{ + union acpi_object *obj; + + guid_parse(HID_EVENT_FILTER_UUID, &intel_dsm_guid); + + obj = acpi_evaluate_dsm_typed(handle, &intel_dsm_guid, 1, 0, NULL, + ACPI_TYPE_BUFFER); + if (obj) { + intel_hid_dsm_fn_mask = *obj->buffer.pointer; + ACPI_FREE(obj); + } + + acpi_handle_debug(handle, "intel_hid_dsm_fn_mask = %llx\n", + intel_hid_dsm_fn_mask); +} + +static int intel_hid_set_enable(struct device *device, bool enable) +{ + acpi_handle handle = ACPI_HANDLE(device); + + /* Enable|disable features - power button is always enabled */ + if (!intel_hid_execute_method(handle, INTEL_HID_DSM_HDSM_FN, + enable)) { dev_warn(device, "failed to %sable hotkeys\n", enable ? "en" : "dis"); return -EIO; @@ -129,9 +256,8 @@ static void intel_button_array_enable(struct device *device, bool enable) } /* Enable|disable features - power button is always enabled */ - status = acpi_execute_simple_method(handle, "BTNE", - enable ? button_cap : 1); - if (ACPI_FAILURE(status)) + if (!intel_hid_execute_method(handle, INTEL_HID_DSM_BTNE_FN, + enable ? button_cap : 1)) dev_warn(device, "failed to set button capability\n"); } @@ -217,7 +343,6 @@ static void notify_handler(acpi_handle handle, u32 event, void *context) struct platform_device *device = context; struct intel_hid_priv *priv = dev_get_drvdata(&device->dev); unsigned long long ev_index; - acpi_status status; if (priv->wakeup_mode) { /* @@ -269,8 +394,8 @@ wakeup: return; } - status = acpi_evaluate_integer(handle, "HDEM", NULL, &ev_index); - if (ACPI_FAILURE(status)) { + if (!intel_hid_evaluate_method(handle, INTEL_HID_DSM_HDEM_FN, + &ev_index)) { dev_warn(&device->dev, "failed to get event index\n"); return; } @@ -284,17 +409,24 @@ static bool button_array_present(struct platform_device *device) { acpi_handle handle = ACPI_HANDLE(&device->dev); unsigned long long event_cap; - acpi_status status; - bool supported = false; - status = acpi_evaluate_integer(handle, "HEBC", NULL, &event_cap); - if (ACPI_SUCCESS(status) && (event_cap & 0x20000)) - supported = true; + if (intel_hid_evaluate_method(handle, INTEL_HID_DSM_HEBC_V2_FN, + &event_cap)) { + /* Check presence of 5 button array or v2 power button */ + if (event_cap & 0x60000) + return true; + } + + if (intel_hid_evaluate_method(handle, INTEL_HID_DSM_HEBC_V1_FN, + &event_cap)) { + if (event_cap & 0x20000) + return true; + } if (dmi_check_system(button_array_table)) - supported = true; + return true; - return supported; + return false; } static int intel_hid_probe(struct platform_device *device) @@ -305,8 +437,9 @@ static int intel_hid_probe(struct platform_device *device) acpi_status status; int err; - status = acpi_evaluate_integer(handle, "HDMM", NULL, &mode); - if (ACPI_FAILURE(status)) { + intel_hid_init_dsm(handle); + + if (!intel_hid_evaluate_method(handle, INTEL_HID_DSM_HDMM_FN, &mode)) { dev_warn(&device->dev, "failed to read mode\n"); return -ENODEV; } @@ -352,13 +485,16 @@ static int intel_hid_probe(struct platform_device *device) goto err_remove_notify; if (priv->array) { + unsigned long long dummy; + intel_button_array_enable(&device->dev, true); /* Call button load method to enable HID power button */ - status = acpi_evaluate_object(handle, "BTNL", NULL, NULL); - if (ACPI_FAILURE(status)) + if (!intel_hid_evaluate_method(handle, INTEL_HID_DSM_BTNL_FN, + &dummy)) { dev_warn(&device->dev, "failed to enable HID power button\n"); + } } device_init_wakeup(&device->dev, true); diff --git a/drivers/platform/x86/intel-vbtn.c b/drivers/platform/x86/intel-vbtn.c index c13780b8dabb..06cd7e818ed5 100644 --- a/drivers/platform/x86/intel-vbtn.c +++ b/drivers/platform/x86/intel-vbtn.c @@ -17,6 +17,7 @@ /* When NOT in tablet mode, VGBS returns with the flag 0x40 */ #define TABLET_MODE_FLAG 0x40 +#define DOCK_MODE_FLAG 0x80 MODULE_LICENSE("GPL"); MODULE_AUTHOR("AceLan Kao"); @@ -38,6 +39,8 @@ static const struct key_entry intel_vbtn_keymap[] = { { KE_IGNORE, 0xC7, { KEY_VOLUMEDOWN } }, /* volume-down key release */ { KE_KEY, 0xC8, { KEY_ROTATE_LOCK_TOGGLE } }, /* rotate-lock key press */ { KE_KEY, 0xC9, { KEY_ROTATE_LOCK_TOGGLE } }, /* rotate-lock key release */ + { KE_SW, 0xCA, { .sw = { SW_DOCK, 1 } } }, /* Docked */ + { KE_SW, 0xCB, { .sw = { SW_DOCK, 0 } } }, /* Undocked */ { KE_SW, 0xCC, { .sw = { SW_TABLET_MODE, 1 } } }, /* Tablet */ { KE_SW, 0xCD, { .sw = { SW_TABLET_MODE, 0 } } }, /* Laptop */ { KE_END }, @@ -121,6 +124,8 @@ static void detect_tablet_mode(struct platform_device *device) m = !(obj->integer.value & TABLET_MODE_FLAG); input_report_switch(priv->input_dev, SW_TABLET_MODE, m); + m = (obj->integer.value & DOCK_MODE_FLAG) ? 1 : 0; + input_report_switch(priv->input_dev, SW_DOCK, m); out: kfree(vgbs_output.pointer); } diff --git a/drivers/platform/x86/intel_ips.c b/drivers/platform/x86/intel_ips.c index 014fc1634a3d..c5ece7ef08c6 100644 --- a/drivers/platform/x86/intel_ips.c +++ b/drivers/platform/x86/intel_ips.c @@ -858,10 +858,7 @@ static u16 read_mgtv(struct ips_driver *ips) static u16 read_ptv(struct ips_driver *ips) { - u16 val, slope, offset; - - slope = (ips->pta_val & PTA_SLOPE_MASK) >> PTA_SLOPE_SHIFT; - offset = ips->pta_val & PTA_OFFSET_MASK; + u16 val; val = thm_readw(THM_PTV) & PTV_MASK; diff --git a/drivers/platform/x86/intel_pmc_core.c b/drivers/platform/x86/intel_pmc_core.c index 43bbe74743d9..2d272a3e0176 100644 --- a/drivers/platform/x86/intel_pmc_core.c +++ b/drivers/platform/x86/intel_pmc_core.c @@ -196,9 +196,67 @@ static const struct pmc_bit_map cnp_pfear_map[] = { {} }; +static const struct pmc_bit_map cnp_slps0_dbg0_map[] = { + {"AUDIO_D3", BIT(0)}, + {"OTG_D3", BIT(1)}, + {"XHCI_D3", BIT(2)}, + {"LPIO_D3", BIT(3)}, + {"SDX_D3", BIT(4)}, + {"SATA_D3", BIT(5)}, + {"UFS0_D3", BIT(6)}, + {"UFS1_D3", BIT(7)}, + {"EMMC_D3", BIT(8)}, + {} +}; + +static const struct pmc_bit_map cnp_slps0_dbg1_map[] = { + {"SDIO_PLL_OFF", BIT(0)}, + {"USB2_PLL_OFF", BIT(1)}, + {"AUDIO_PLL_OFF", BIT(2)}, + {"OC_PLL_OFF", BIT(3)}, + {"MAIN_PLL_OFF", BIT(4)}, + {"XOSC_OFF", BIT(5)}, + {"LPC_CLKS_GATED", BIT(6)}, + {"PCIE_CLKREQS_IDLE", BIT(7)}, + {"AUDIO_ROSC_OFF", BIT(8)}, + {"HPET_XOSC_CLK_REQ", BIT(9)}, + {"PMC_ROSC_SLOW_CLK", BIT(10)}, + {"AON2_ROSC_GATED", BIT(11)}, + {"CLKACKS_DEASSERTED", BIT(12)}, + {} +}; + +static const struct pmc_bit_map cnp_slps0_dbg2_map[] = { + {"MPHY_CORE_GATED", BIT(0)}, + {"CSME_GATED", BIT(1)}, + {"USB2_SUS_GATED", BIT(2)}, + {"DYN_FLEX_IO_IDLE", BIT(3)}, + {"GBE_NO_LINK", BIT(4)}, + {"THERM_SEN_DISABLED", BIT(5)}, + {"PCIE_LOW_POWER", BIT(6)}, + {"ISH_VNNAON_REQ_ACT", BIT(7)}, + {"ISH_VNN_REQ_ACT", BIT(8)}, + {"CNV_VNNAON_REQ_ACT", BIT(9)}, + {"CNV_VNN_REQ_ACT", BIT(10)}, + {"NPK_VNNON_REQ_ACT", BIT(11)}, + {"PMSYNC_STATE_IDLE", BIT(12)}, + {"ALST_GT_THRES", BIT(13)}, + {"PMC_ARC_PG_READY", BIT(14)}, + {} +}; + +static const struct pmc_bit_map *cnp_slps0_dbg_maps[] = { + cnp_slps0_dbg0_map, + cnp_slps0_dbg1_map, + cnp_slps0_dbg2_map, + NULL, +}; + static const struct pmc_reg_map cnp_reg_map = { .pfear_sts = cnp_pfear_map, .slp_s0_offset = CNP_PMC_SLP_S0_RES_COUNTER_OFFSET, + .slps0_dbg_maps = cnp_slps0_dbg_maps, + .slps0_dbg_offset = CNP_PMC_SLPS0_DBG_OFFSET, .ltr_ignore_offset = CNP_PMC_LTR_IGNORE_OFFSET, .regmap_length = CNP_PMC_MMIO_REG_LEN, .ppfear0_offset = CNP_PMC_HOST_PPFEAR0A, @@ -252,6 +310,8 @@ static int pmc_core_check_read_lock_bit(void) } #if IS_ENABLED(CONFIG_DEBUG_FS) +static bool slps0_dbg_latch; + static void pmc_core_display_map(struct seq_file *s, int index, u8 pf_reg, const struct pmc_bit_map *pf_map) { @@ -481,6 +541,57 @@ static const struct file_operations pmc_core_ltr_ignore_ops = { .release = single_release, }; +static void pmc_core_slps0_dbg_latch(struct pmc_dev *pmcdev, bool reset) +{ + const struct pmc_reg_map *map = pmcdev->map; + u32 fd; + + mutex_lock(&pmcdev->lock); + + if (!reset && !slps0_dbg_latch) + goto out_unlock; + + fd = pmc_core_reg_read(pmcdev, map->slps0_dbg_offset); + if (reset) + fd &= ~CNP_PMC_LATCH_SLPS0_EVENTS; + else + fd |= CNP_PMC_LATCH_SLPS0_EVENTS; + pmc_core_reg_write(pmcdev, map->slps0_dbg_offset, fd); + + slps0_dbg_latch = 0; + +out_unlock: + mutex_unlock(&pmcdev->lock); +} + +static int pmc_core_slps0_dbg_show(struct seq_file *s, void *unused) +{ + struct pmc_dev *pmcdev = s->private; + const struct pmc_bit_map **maps = pmcdev->map->slps0_dbg_maps; + const struct pmc_bit_map *map; + int offset; + u32 data; + + pmc_core_slps0_dbg_latch(pmcdev, false); + offset = pmcdev->map->slps0_dbg_offset; + while (*maps) { + map = *maps; + data = pmc_core_reg_read(pmcdev, offset); + offset += 4; + while (map->name) { + seq_printf(s, "SLP_S0_DBG: %-32s\tState: %s\n", + map->name, + data & map->bit_mask ? + "Yes" : "No"); + ++map; + } + ++maps; + } + pmc_core_slps0_dbg_latch(pmcdev, true); + return 0; +} +DEFINE_SHOW_ATTRIBUTE(pmc_core_slps0_dbg); + static void pmc_core_dbgfs_unregister(struct pmc_dev *pmcdev) { debugfs_remove_recursive(pmcdev->dbgfs_dir); @@ -514,6 +625,15 @@ static int pmc_core_dbgfs_register(struct pmc_dev *pmcdev) 0444, dir, pmcdev, &pmc_core_mphy_pg_ops); + if (pmcdev->map->slps0_dbg_maps) { + debugfs_create_file("slp_s0_debug_status", 0444, + dir, pmcdev, + &pmc_core_slps0_dbg_fops); + + debugfs_create_bool("slp_s0_dbg_latch", 0644, + dir, &slps0_dbg_latch); + } + return 0; } #else diff --git a/drivers/platform/x86/intel_pmc_core.h b/drivers/platform/x86/intel_pmc_core.h index 5fa5f97870aa..93a7e99e1f8b 100644 --- a/drivers/platform/x86/intel_pmc_core.h +++ b/drivers/platform/x86/intel_pmc_core.h @@ -127,12 +127,14 @@ enum ppfear_regs { #define CNP_PMC_SLP_S0_RES_COUNTER_OFFSET 0x193C #define CNP_PMC_LTR_IGNORE_OFFSET 0x1B0C #define CNP_PMC_PM_CFG_OFFSET 0x1818 +#define CNP_PMC_SLPS0_DBG_OFFSET 0x10B4 /* Cannonlake: PGD PFET Enable Ack Status Register(s) start */ #define CNP_PMC_HOST_PPFEAR0A 0x1D90 #define CNP_PMC_MMIO_REG_LEN 0x2000 #define CNP_PPFEAR_NUM_ENTRIES 8 #define CNP_PMC_READ_DISABLE_BIT 22 +#define CNP_PMC_LATCH_SLPS0_EVENTS BIT(31) struct pmc_bit_map { const char *name; @@ -145,6 +147,7 @@ struct pmc_bit_map { * @pfear_sts: Maps name of IP block to PPFEAR* bit * @mphy_sts: Maps name of MPHY lane to MPHY status lane status bit * @pll_sts: Maps name of PLL to corresponding bit status + * @slps0_dbg_maps: Array of SLP_S0_DBG* registers containing debug info * @slp_s0_offset: PWRMBASE offset to read SLP_S0 residency * @ltr_ignore_offset: PWRMBASE offset to read/write LTR ignore bit * @regmap_length: Length of memory to map from PWRMBASE address to access @@ -153,6 +156,7 @@ struct pmc_bit_map { * PPFEAR * @pm_cfg_offset: PWRMBASE offset to PM_CFG register * @pm_read_disable_bit: Bit index to read PMC_READ_DISABLE + * @slps0_dbg_offset: PWRMBASE offset to SLP_S0_DEBUG_REG* * * Each PCH has unique set of register offsets and bit indexes. This structure * captures them to have a common implementation. @@ -161,6 +165,7 @@ struct pmc_reg_map { const struct pmc_bit_map *pfear_sts; const struct pmc_bit_map *mphy_sts; const struct pmc_bit_map *pll_sts; + const struct pmc_bit_map **slps0_dbg_maps; const u32 slp_s0_offset; const u32 ltr_ignore_offset; const int regmap_length; @@ -168,6 +173,7 @@ struct pmc_reg_map { const int ppfear_buckets; const u32 pm_cfg_offset; const int pm_read_disable_bit; + const u32 slps0_dbg_offset; }; /** diff --git a/drivers/platform/x86/intel_punit_ipc.c b/drivers/platform/x86/intel_punit_ipc.c index f1afc0ebbc68..2efeab650345 100644 --- a/drivers/platform/x86/intel_punit_ipc.c +++ b/drivers/platform/x86/intel_punit_ipc.c @@ -18,6 +18,7 @@ #include <linux/bitops.h> #include <linux/device.h> #include <linux/interrupt.h> +#include <linux/io.h> #include <linux/platform_device.h> #include <asm/intel_punit_ipc.h> diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c index a0fd9aa6d932..d89936c93ba0 100644 --- a/drivers/platform/x86/mlx-platform.c +++ b/drivers/platform/x86/mlx-platform.c @@ -47,15 +47,26 @@ /* LPC bus IO offsets */ #define MLXPLAT_CPLD_LPC_I2C_BASE_ADRR 0x2000 #define MLXPLAT_CPLD_LPC_REG_BASE_ADRR 0x2500 +#define MLXPLAT_CPLD_LPC_REG_CPLD1_VER_OFFSET 0x00 +#define MLXPLAT_CPLD_LPC_REG_CPLD2_VER_OFFSET 0x01 +#define MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET 0x1d #define MLXPLAT_CPLD_LPC_REG_LED1_OFFSET 0x20 #define MLXPLAT_CPLD_LPC_REG_LED2_OFFSET 0x21 #define MLXPLAT_CPLD_LPC_REG_LED3_OFFSET 0x22 #define MLXPLAT_CPLD_LPC_REG_LED4_OFFSET 0x23 #define MLXPLAT_CPLD_LPC_REG_LED5_OFFSET 0x24 +#define MLXPLAT_CPLD_LPC_REG_GP1_OFFSET 0x30 +#define MLXPLAT_CPLD_LPC_REG_WP1_OFFSET 0x31 +#define MLXPLAT_CPLD_LPC_REG_GP2_OFFSET 0x32 +#define MLXPLAT_CPLD_LPC_REG_WP2_OFFSET 0x33 +#define MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET 0x37 #define MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET 0x3a #define MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET 0x3b #define MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET 0x40 #define MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET 0x41 +#define MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET 0x50 +#define MLXPLAT_CPLD_LPC_REG_ASIC_EVENT_OFFSET 0x51 +#define MLXPLAT_CPLD_LPC_REG_ASIC_MASK_OFFSET 0x52 #define MLXPLAT_CPLD_LPC_REG_PSU_OFFSET 0x58 #define MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET 0x59 #define MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET 0x5a @@ -65,9 +76,23 @@ #define MLXPLAT_CPLD_LPC_REG_FAN_OFFSET 0x88 #define MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET 0x89 #define MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET 0x8a +#define MLXPLAT_CPLD_LPC_REG_PWM1_OFFSET 0xe3 +#define MLXPLAT_CPLD_LPC_REG_TACHO1_OFFSET 0xe4 +#define MLXPLAT_CPLD_LPC_REG_TACHO2_OFFSET 0xe5 +#define MLXPLAT_CPLD_LPC_REG_TACHO3_OFFSET 0xe6 +#define MLXPLAT_CPLD_LPC_REG_TACHO4_OFFSET 0xe7 +#define MLXPLAT_CPLD_LPC_REG_TACHO5_OFFSET 0xe8 +#define MLXPLAT_CPLD_LPC_REG_TACHO6_OFFSET 0xe9 +#define MLXPLAT_CPLD_LPC_REG_TACHO7_OFFSET 0xea +#define MLXPLAT_CPLD_LPC_REG_TACHO8_OFFSET 0xeb +#define MLXPLAT_CPLD_LPC_REG_TACHO9_OFFSET 0xec +#define MLXPLAT_CPLD_LPC_REG_TACHO10_OFFSET 0xed +#define MLXPLAT_CPLD_LPC_REG_TACHO11_OFFSET 0xee +#define MLXPLAT_CPLD_LPC_REG_TACHO12_OFFSET 0xef #define MLXPLAT_CPLD_LPC_IO_RANGE 0x100 #define MLXPLAT_CPLD_LPC_I2C_CH1_OFF 0xdb #define MLXPLAT_CPLD_LPC_I2C_CH2_OFF 0xda + #define MLXPLAT_CPLD_LPC_PIO_OFFSET 0x10000UL #define MLXPLAT_CPLD_LPC_REG1 ((MLXPLAT_CPLD_LPC_REG_BASE_ADRR + \ MLXPLAT_CPLD_LPC_I2C_CH1_OFF) | \ @@ -77,17 +102,20 @@ MLXPLAT_CPLD_LPC_PIO_OFFSET) /* Masks for aggregation, psu, pwr and fan event in CPLD related registers. */ +#define MLXPLAT_CPLD_AGGR_ASIC_MASK_DEF 0x04 #define MLXPLAT_CPLD_AGGR_PSU_MASK_DEF 0x08 #define MLXPLAT_CPLD_AGGR_PWR_MASK_DEF 0x08 #define MLXPLAT_CPLD_AGGR_FAN_MASK_DEF 0x40 -#define MLXPLAT_CPLD_AGGR_MASK_DEF (MLXPLAT_CPLD_AGGR_PSU_MASK_DEF | \ +#define MLXPLAT_CPLD_AGGR_MASK_DEF (MLXPLAT_CPLD_AGGR_ASIC_MASK_DEF | \ + MLXPLAT_CPLD_AGGR_PSU_MASK_DEF | \ MLXPLAT_CPLD_AGGR_FAN_MASK_DEF) +#define MLXPLAT_CPLD_AGGR_ASIC_MASK_NG 0x01 #define MLXPLAT_CPLD_AGGR_MASK_NG_DEF 0x04 -#define MLXPLAT_CPLD_LOW_AGGR_MASK_LOW 0xc0 -#define MLXPLAT_CPLD_AGGR_MASK_MSN21XX 0x04 +#define MLXPLAT_CPLD_LOW_AGGR_MASK_LOW 0xc1 #define MLXPLAT_CPLD_PSU_MASK GENMASK(1, 0) #define MLXPLAT_CPLD_PWR_MASK GENMASK(1, 0) #define MLXPLAT_CPLD_FAN_MASK GENMASK(3, 0) +#define MLXPLAT_CPLD_ASIC_MASK GENMASK(1, 0) #define MLXPLAT_CPLD_FAN_NG_MASK GENMASK(5, 0) #define MLXPLAT_CPLD_LED_LO_NIBBLE_MASK GENMASK(7, 4) #define MLXPLAT_CPLD_LED_HI_NIBBLE_MASK GENMASK(3, 0) @@ -122,12 +150,16 @@ * @pdev_mux - array of mux platform devices * @pdev_hotplug - hotplug platform devices * @pdev_led - led platform devices + * @pdev_io_regs - register access platform devices + * @pdev_fan - FAN platform devices */ struct mlxplat_priv { struct platform_device *pdev_i2c; struct platform_device *pdev_mux[MLXPLAT_CPLD_LPC_MUX_DEVS]; struct platform_device *pdev_hotplug; struct platform_device *pdev_led; + struct platform_device *pdev_io_regs; + struct platform_device *pdev_fan; }; /* Regions for LPC I2C controller and LPC base register space */ @@ -288,6 +320,15 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_fan_items_data[] = { }, }; +static struct mlxreg_core_data mlxplat_mlxcpld_default_asic_items_data[] = { + { + .label = "asic1", + .reg = MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET, + .mask = MLXPLAT_CPLD_ASIC_MASK, + .hpdev.nr = MLXPLAT_CPLD_NR_NONE, + }, +}; + static struct mlxreg_core_item mlxplat_mlxcpld_default_items[] = { { .data = mlxplat_mlxcpld_default_psu_items_data, @@ -316,6 +357,15 @@ static struct mlxreg_core_item mlxplat_mlxcpld_default_items[] = { .inversed = 1, .health = false, }, + { + .data = mlxplat_mlxcpld_default_asic_items_data, + .aggr_mask = MLXPLAT_CPLD_AGGR_ASIC_MASK_DEF, + .reg = MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET, + .mask = MLXPLAT_CPLD_ASIC_MASK, + .count = ARRAY_SIZE(mlxplat_mlxcpld_default_asic_items_data), + .inversed = 0, + .health = true, + }, }; static @@ -324,6 +374,8 @@ struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_default_data = { .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_items), .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET, .mask = MLXPLAT_CPLD_AGGR_MASK_DEF, + .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET, + .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW, }; static struct mlxreg_core_data mlxplat_mlxcpld_msn21xx_pwr_items_data[] = { @@ -352,6 +404,15 @@ static struct mlxreg_core_item mlxplat_mlxcpld_msn21xx_items[] = { .inversed = 0, .health = false, }, + { + .data = mlxplat_mlxcpld_default_asic_items_data, + .aggr_mask = MLXPLAT_CPLD_AGGR_ASIC_MASK_DEF, + .reg = MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET, + .mask = MLXPLAT_CPLD_ASIC_MASK, + .count = ARRAY_SIZE(mlxplat_mlxcpld_default_asic_items_data), + .inversed = 0, + .health = true, + }, }; static @@ -454,6 +515,15 @@ static struct mlxreg_core_item mlxplat_mlxcpld_msn274x_items[] = { .inversed = 1, .health = false, }, + { + .data = mlxplat_mlxcpld_default_asic_items_data, + .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, + .reg = MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET, + .mask = MLXPLAT_CPLD_ASIC_MASK, + .count = ARRAY_SIZE(mlxplat_mlxcpld_default_asic_items_data), + .inversed = 0, + .health = true, + }, }; static @@ -492,6 +562,15 @@ static struct mlxreg_core_item mlxplat_mlxcpld_msn201x_items[] = { .inversed = 0, .health = false, }, + { + .data = mlxplat_mlxcpld_default_asic_items_data, + .aggr_mask = MLXPLAT_CPLD_AGGR_ASIC_MASK_DEF, + .reg = MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET, + .mask = MLXPLAT_CPLD_ASIC_MASK, + .count = ARRAY_SIZE(mlxplat_mlxcpld_default_asic_items_data), + .inversed = 0, + .health = true, + }, }; static @@ -589,6 +668,15 @@ static struct mlxreg_core_item mlxplat_mlxcpld_default_ng_items[] = { .inversed = 1, .health = false, }, + { + .data = mlxplat_mlxcpld_default_asic_items_data, + .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF, + .reg = MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET, + .mask = MLXPLAT_CPLD_ASIC_MASK, + .count = ARRAY_SIZE(mlxplat_mlxcpld_default_asic_items_data), + .inversed = 0, + .health = true, + }, }; static @@ -813,6 +901,278 @@ static struct mlxreg_core_platform_data mlxplat_default_ng_led_data = { .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_led_data), }; +/* Platform register access default */ +static struct mlxreg_core_data mlxplat_mlxcpld_default_regs_io_data[] = { + { + .label = "cpld1_version", + .reg = MLXPLAT_CPLD_LPC_REG_CPLD1_VER_OFFSET, + .bit = GENMASK(7, 0), + .mode = 0444, + }, + { + .label = "cpld2_version", + .reg = MLXPLAT_CPLD_LPC_REG_CPLD2_VER_OFFSET, + .bit = GENMASK(7, 0), + .mode = 0444, + }, + { + .label = "reset_long_pb", + .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(0), + .mode = 0444, + }, + { + .label = "reset_short_pb", + .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(1), + .mode = 0444, + }, + { + .label = "reset_aux_pwr_or_ref", + .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(2), + .mode = 0444, + }, + { + .label = "reset_main_pwr_fail", + .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(3), + .mode = 0444, + }, + { + .label = "reset_sw_reset", + .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(4), + .mode = 0444, + }, + { + .label = "reset_fw_reset", + .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(5), + .mode = 0444, + }, + { + .label = "reset_hotswap_or_wd", + .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(6), + .mode = 0444, + }, + { + .label = "reset_asic_thermal", + .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(7), + .mode = 0444, + }, + { + .label = "psu1_on", + .reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(0), + .mode = 0200, + }, + { + .label = "psu2_on", + .reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(1), + .mode = 0200, + }, + { + .label = "pwr_cycle", + .reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(2), + .mode = 0200, + }, + { + .label = "pwr_down", + .reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(3), + .mode = 0200, + }, + { + .label = "select_iio", + .reg = MLXPLAT_CPLD_LPC_REG_GP2_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(6), + .mode = 0644, + }, + { + .label = "asic_health", + .reg = MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET, + .mask = MLXPLAT_CPLD_ASIC_MASK, + .bit = 1, + .mode = 0444, + }, +}; + +static struct mlxreg_core_platform_data mlxplat_default_regs_io_data = { + .data = mlxplat_mlxcpld_default_regs_io_data, + .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_regs_io_data), +}; + +/* Platform register access MSN21xx, MSN201x, MSN274x systems families data */ +static struct mlxreg_core_data mlxplat_mlxcpld_msn21xx_regs_io_data[] = { + { + .label = "cpld1_version", + .reg = MLXPLAT_CPLD_LPC_REG_CPLD1_VER_OFFSET, + .bit = GENMASK(7, 0), + .mode = 0444, + }, + { + .label = "cpld2_version", + .reg = MLXPLAT_CPLD_LPC_REG_CPLD2_VER_OFFSET, + .bit = GENMASK(7, 0), + .mode = 0444, + }, + { + .label = "reset_long_pb", + .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(0), + .mode = 0444, + }, + { + .label = "reset_short_pb", + .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(1), + .mode = 0444, + }, + { + .label = "reset_aux_pwr_or_ref", + .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(2), + .mode = 0444, + }, + { + .label = "reset_sw_reset", + .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(3), + .mode = 0444, + }, + { + .label = "reset_main_pwr_fail", + .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(4), + .mode = 0444, + }, + { + .label = "reset_asic_thermal", + .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(5), + .mode = 0444, + }, + { + .label = "reset_hotswap_or_halt", + .reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(6), + .mode = 0444, + }, + { + .label = "psu1_on", + .reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(0), + .mode = 0200, + }, + { + .label = "psu2_on", + .reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(1), + .mode = 0200, + }, + { + .label = "pwr_cycle", + .reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(2), + .mode = 0200, + }, + { + .label = "pwr_down", + .reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, + .mask = GENMASK(7, 0) & ~BIT(3), + .mode = 0200, + }, + { + .label = "asic_health", + .reg = MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET, + .mask = MLXPLAT_CPLD_ASIC_MASK, + .bit = 1, + .mode = 0444, + }, +}; + +static struct mlxreg_core_platform_data mlxplat_msn21xx_regs_io_data = { + .data = mlxplat_mlxcpld_msn21xx_regs_io_data, + .counter = ARRAY_SIZE(mlxplat_mlxcpld_msn21xx_regs_io_data), +}; + +/* Platform FAN default */ +static struct mlxreg_core_data mlxplat_mlxcpld_default_fan_data[] = { + { + .label = "pwm1", + .reg = MLXPLAT_CPLD_LPC_REG_PWM1_OFFSET, + }, + { + .label = "tacho1", + .reg = MLXPLAT_CPLD_LPC_REG_TACHO1_OFFSET, + .mask = GENMASK(7, 0), + }, + { + .label = "tacho2", + .reg = MLXPLAT_CPLD_LPC_REG_TACHO2_OFFSET, + .mask = GENMASK(7, 0), + }, + { + .label = "tacho3", + .reg = MLXPLAT_CPLD_LPC_REG_TACHO3_OFFSET, + .mask = GENMASK(7, 0), + }, + { + .label = "tacho4", + .reg = MLXPLAT_CPLD_LPC_REG_TACHO4_OFFSET, + .mask = GENMASK(7, 0), + }, + { + .label = "tacho5", + .reg = MLXPLAT_CPLD_LPC_REG_TACHO5_OFFSET, + .mask = GENMASK(7, 0), + }, + { + .label = "tacho6", + .reg = MLXPLAT_CPLD_LPC_REG_TACHO6_OFFSET, + .mask = GENMASK(7, 0), + }, + { + .label = "tacho7", + .reg = MLXPLAT_CPLD_LPC_REG_TACHO7_OFFSET, + .mask = GENMASK(7, 0), + }, + { + .label = "tacho8", + .reg = MLXPLAT_CPLD_LPC_REG_TACHO8_OFFSET, + .mask = GENMASK(7, 0), + }, + { + .label = "tacho9", + .reg = MLXPLAT_CPLD_LPC_REG_TACHO9_OFFSET, + .mask = GENMASK(7, 0), + }, + { + .label = "tacho10", + .reg = MLXPLAT_CPLD_LPC_REG_TACHO10_OFFSET, + .mask = GENMASK(7, 0), + }, + { + .label = "tacho11", + .reg = MLXPLAT_CPLD_LPC_REG_TACHO11_OFFSET, + .mask = GENMASK(7, 0), + }, + { + .label = "tacho12", + .reg = MLXPLAT_CPLD_LPC_REG_TACHO12_OFFSET, + .mask = GENMASK(7, 0), + }, +}; + +static struct mlxreg_core_platform_data mlxplat_default_fan_data = { + .data = mlxplat_mlxcpld_default_fan_data, + .counter = ARRAY_SIZE(mlxplat_mlxcpld_default_fan_data), +}; static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg) { @@ -822,14 +1182,22 @@ static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg) case MLXPLAT_CPLD_LPC_REG_LED3_OFFSET: case MLXPLAT_CPLD_LPC_REG_LED4_OFFSET: case MLXPLAT_CPLD_LPC_REG_LED5_OFFSET: + case MLXPLAT_CPLD_LPC_REG_GP1_OFFSET: + case MLXPLAT_CPLD_LPC_REG_WP1_OFFSET: + case MLXPLAT_CPLD_LPC_REG_GP2_OFFSET: + case MLXPLAT_CPLD_LPC_REG_WP2_OFFSET: case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET: case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_ASIC_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_ASIC_MASK_OFFSET: case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET: case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET: case MLXPLAT_CPLD_LPC_REG_PWR_EVENT_OFFSET: case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET: case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET: case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_PWM1_OFFSET: + case MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET: return true; } return false; @@ -838,15 +1206,25 @@ static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg) static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg) { switch (reg) { + case MLXPLAT_CPLD_LPC_REG_CPLD1_VER_OFFSET: + case MLXPLAT_CPLD_LPC_REG_CPLD2_VER_OFFSET: + case MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET: case MLXPLAT_CPLD_LPC_REG_LED1_OFFSET: case MLXPLAT_CPLD_LPC_REG_LED2_OFFSET: case MLXPLAT_CPLD_LPC_REG_LED3_OFFSET: case MLXPLAT_CPLD_LPC_REG_LED4_OFFSET: case MLXPLAT_CPLD_LPC_REG_LED5_OFFSET: + case MLXPLAT_CPLD_LPC_REG_GP1_OFFSET: + case MLXPLAT_CPLD_LPC_REG_WP1_OFFSET: + case MLXPLAT_CPLD_LPC_REG_GP2_OFFSET: + case MLXPLAT_CPLD_LPC_REG_WP2_OFFSET: case MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET: case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET: case MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET: case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET: + case MLXPLAT_CPLD_LPC_REG_ASIC_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_ASIC_MASK_OFFSET: case MLXPLAT_CPLD_LPC_REG_PSU_OFFSET: case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET: case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET: @@ -856,6 +1234,20 @@ static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg) case MLXPLAT_CPLD_LPC_REG_FAN_OFFSET: case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET: case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_PWM1_OFFSET: + case MLXPLAT_CPLD_LPC_REG_TACHO1_OFFSET: + case MLXPLAT_CPLD_LPC_REG_TACHO2_OFFSET: + case MLXPLAT_CPLD_LPC_REG_TACHO3_OFFSET: + case MLXPLAT_CPLD_LPC_REG_TACHO4_OFFSET: + case MLXPLAT_CPLD_LPC_REG_TACHO5_OFFSET: + case MLXPLAT_CPLD_LPC_REG_TACHO6_OFFSET: + case MLXPLAT_CPLD_LPC_REG_TACHO7_OFFSET: + case MLXPLAT_CPLD_LPC_REG_TACHO8_OFFSET: + case MLXPLAT_CPLD_LPC_REG_TACHO9_OFFSET: + case MLXPLAT_CPLD_LPC_REG_TACHO10_OFFSET: + case MLXPLAT_CPLD_LPC_REG_TACHO11_OFFSET: + case MLXPLAT_CPLD_LPC_REG_TACHO12_OFFSET: + case MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET: return true; } return false; @@ -864,15 +1256,23 @@ static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg) static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg) { switch (reg) { + case MLXPLAT_CPLD_LPC_REG_CPLD1_VER_OFFSET: + case MLXPLAT_CPLD_LPC_REG_CPLD2_VER_OFFSET: + case MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET: case MLXPLAT_CPLD_LPC_REG_LED1_OFFSET: case MLXPLAT_CPLD_LPC_REG_LED2_OFFSET: case MLXPLAT_CPLD_LPC_REG_LED3_OFFSET: case MLXPLAT_CPLD_LPC_REG_LED4_OFFSET: case MLXPLAT_CPLD_LPC_REG_LED5_OFFSET: + case MLXPLAT_CPLD_LPC_REG_GP1_OFFSET: + case MLXPLAT_CPLD_LPC_REG_GP2_OFFSET: case MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET: case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET: case MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET: case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET: + case MLXPLAT_CPLD_LPC_REG_ASIC_EVENT_OFFSET: + case MLXPLAT_CPLD_LPC_REG_ASIC_MASK_OFFSET: case MLXPLAT_CPLD_LPC_REG_PSU_OFFSET: case MLXPLAT_CPLD_LPC_REG_PSU_EVENT_OFFSET: case MLXPLAT_CPLD_LPC_REG_PSU_MASK_OFFSET: @@ -882,11 +1282,31 @@ static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg) case MLXPLAT_CPLD_LPC_REG_FAN_OFFSET: case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET: case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET: + case MLXPLAT_CPLD_LPC_REG_PWM1_OFFSET: + case MLXPLAT_CPLD_LPC_REG_TACHO1_OFFSET: + case MLXPLAT_CPLD_LPC_REG_TACHO2_OFFSET: + case MLXPLAT_CPLD_LPC_REG_TACHO3_OFFSET: + case MLXPLAT_CPLD_LPC_REG_TACHO4_OFFSET: + case MLXPLAT_CPLD_LPC_REG_TACHO5_OFFSET: + case MLXPLAT_CPLD_LPC_REG_TACHO6_OFFSET: + case MLXPLAT_CPLD_LPC_REG_TACHO7_OFFSET: + case MLXPLAT_CPLD_LPC_REG_TACHO8_OFFSET: + case MLXPLAT_CPLD_LPC_REG_TACHO9_OFFSET: + case MLXPLAT_CPLD_LPC_REG_TACHO10_OFFSET: + case MLXPLAT_CPLD_LPC_REG_TACHO11_OFFSET: + case MLXPLAT_CPLD_LPC_REG_TACHO12_OFFSET: + case MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET: return true; } return false; } +static const struct reg_default mlxplat_mlxcpld_regmap_default[] = { + { MLXPLAT_CPLD_LPC_REG_WP1_OFFSET, 0x00 }, + { MLXPLAT_CPLD_LPC_REG_WP2_OFFSET, 0x00 }, + { MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET, 0x00 }, +}; + struct mlxplat_mlxcpld_regmap_context { void __iomem *base; }; @@ -919,6 +1339,8 @@ static const struct regmap_config mlxplat_mlxcpld_regmap_config = { .writeable_reg = mlxplat_mlxcpld_writeable_reg, .readable_reg = mlxplat_mlxcpld_readable_reg, .volatile_reg = mlxplat_mlxcpld_volatile_reg, + .reg_defaults = mlxplat_mlxcpld_regmap_default, + .num_reg_defaults = ARRAY_SIZE(mlxplat_mlxcpld_regmap_default), .reg_read = mlxplat_mlxcpld_reg_read, .reg_write = mlxplat_mlxcpld_reg_write, }; @@ -930,6 +1352,8 @@ static struct resource mlxplat_mlxcpld_resources[] = { static struct platform_device *mlxplat_dev; static struct mlxreg_core_hotplug_platform_data *mlxplat_hotplug; static struct mlxreg_core_platform_data *mlxplat_led; +static struct mlxreg_core_platform_data *mlxplat_regs_io; +static struct mlxreg_core_platform_data *mlxplat_fan; static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi) { @@ -944,6 +1368,7 @@ static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi) mlxplat_hotplug->deferred_nr = mlxplat_default_channels[i - 1][MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; mlxplat_led = &mlxplat_default_led_data; + mlxplat_regs_io = &mlxplat_default_regs_io_data; return 1; }; @@ -961,6 +1386,7 @@ static int __init mlxplat_dmi_msn21xx_matched(const struct dmi_system_id *dmi) mlxplat_hotplug->deferred_nr = mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; mlxplat_led = &mlxplat_msn21xx_led_data; + mlxplat_regs_io = &mlxplat_msn21xx_regs_io_data; return 1; }; @@ -978,6 +1404,7 @@ static int __init mlxplat_dmi_msn274x_matched(const struct dmi_system_id *dmi) mlxplat_hotplug->deferred_nr = mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; mlxplat_led = &mlxplat_default_led_data; + mlxplat_regs_io = &mlxplat_msn21xx_regs_io_data; return 1; }; @@ -995,6 +1422,7 @@ static int __init mlxplat_dmi_msn201x_matched(const struct dmi_system_id *dmi) mlxplat_hotplug->deferred_nr = mlxplat_default_channels[i - 1][MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; mlxplat_led = &mlxplat_default_ng_led_data; + mlxplat_regs_io = &mlxplat_msn21xx_regs_io_data; return 1; }; @@ -1012,6 +1440,7 @@ static int __init mlxplat_dmi_qmb7xx_matched(const struct dmi_system_id *dmi) mlxplat_hotplug->deferred_nr = mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1]; mlxplat_led = &mlxplat_msn21xx_led_data; + mlxplat_fan = &mlxplat_default_fan_data; return 1; }; @@ -1163,7 +1592,7 @@ static int mlxplat_mlxcpld_verify_bus_topology(int *nr) static int __init mlxplat_init(void) { struct mlxplat_priv *priv; - int i, nr, err; + int i, j, nr, err; if (!dmi_check_system(mlxplat_dmi_table)) return -ENODEV; @@ -1233,6 +1662,15 @@ static int __init mlxplat_init(void) goto fail_platform_mux_register; } + /* Set default registers. */ + for (j = 0; j < mlxplat_mlxcpld_regmap_config.num_reg_defaults; j++) { + err = regmap_write(mlxplat_hotplug->regmap, + mlxplat_mlxcpld_regmap_default[j].reg, + mlxplat_mlxcpld_regmap_default[j].def); + if (err) + goto fail_platform_mux_register; + } + /* Add LED driver. */ mlxplat_led->regmap = mlxplat_hotplug->regmap; priv->pdev_led = platform_device_register_resndata( @@ -1244,14 +1682,48 @@ static int __init mlxplat_init(void) goto fail_platform_hotplug_register; } + /* Add registers io access driver. */ + if (mlxplat_regs_io) { + mlxplat_regs_io->regmap = mlxplat_hotplug->regmap; + priv->pdev_io_regs = platform_device_register_resndata( + &mlxplat_dev->dev, "mlxreg-io", + PLATFORM_DEVID_NONE, NULL, 0, + mlxplat_regs_io, + sizeof(*mlxplat_regs_io)); + if (IS_ERR(priv->pdev_io_regs)) { + err = PTR_ERR(priv->pdev_io_regs); + goto fail_platform_led_register; + } + } + + /* Add FAN driver. */ + if (mlxplat_fan) { + mlxplat_fan->regmap = mlxplat_hotplug->regmap; + priv->pdev_fan = platform_device_register_resndata( + &mlxplat_dev->dev, "mlxreg-fan", + PLATFORM_DEVID_NONE, NULL, 0, + mlxplat_fan, + sizeof(*mlxplat_fan)); + if (IS_ERR(priv->pdev_fan)) { + err = PTR_ERR(priv->pdev_fan); + goto fail_platform_io_regs_register; + } + } + /* Sync registers with hardware. */ regcache_mark_dirty(mlxplat_hotplug->regmap); err = regcache_sync(mlxplat_hotplug->regmap); if (err) - goto fail_platform_led_register; + goto fail_platform_fan_register; return 0; +fail_platform_fan_register: + if (mlxplat_fan) + platform_device_unregister(priv->pdev_fan); +fail_platform_io_regs_register: + if (mlxplat_regs_io) + platform_device_unregister(priv->pdev_io_regs); fail_platform_led_register: platform_device_unregister(priv->pdev_led); fail_platform_hotplug_register: @@ -1272,6 +1744,10 @@ static void __exit mlxplat_exit(void) struct mlxplat_priv *priv = platform_get_drvdata(mlxplat_dev); int i; + if (priv->pdev_fan) + platform_device_unregister(priv->pdev_fan); + if (priv->pdev_io_regs) + platform_device_unregister(priv->pdev_io_regs); platform_device_unregister(priv->pdev_led); platform_device_unregister(priv->pdev_hotplug); diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index d556e95c532c..fde08a997557 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -336,6 +336,7 @@ static struct { u32 second_fan:1; u32 beep_needs_two_args:1; u32 mixer_no_level_control:1; + u32 battery_force_primary:1; u32 input_device_registered:1; u32 platform_drv_registered:1; u32 platform_drv_attrs_registered:1; @@ -344,7 +345,6 @@ static struct { u32 sensors_pdev_attrs_registered:1; u32 hotkey_poll_active:1; u32 has_adaptive_kbd:1; - u32 battery:1; } tp_features; static struct { @@ -359,9 +359,9 @@ struct thinkpad_id_data { char *bios_version_str; /* Something like 1ZET51WW (1.03z) */ char *ec_version_str; /* Something like 1ZHT51WW-1.04a */ - u16 bios_model; /* 1Y = 0x5931, 0 = unknown */ - u16 ec_model; - u16 bios_release; /* 1ZETK1WW = 0x314b, 0 = unknown */ + u32 bios_model; /* 1Y = 0x3159, 0 = unknown */ + u32 ec_model; + u16 bios_release; /* 1ZETK1WW = 0x4b31, 0 = unknown */ u16 ec_release; char *model_str; /* ThinkPad T43 */ @@ -445,17 +445,20 @@ do { \ /* * Quirk handling helpers * - * ThinkPad IDs and versions seen in the field so far - * are two-characters from the set [0-9A-Z], i.e. base 36. + * ThinkPad IDs and versions seen in the field so far are + * two or three characters from the set [0-9A-Z], i.e. base 36. * * We use values well outside that range as specials. */ -#define TPACPI_MATCH_ANY 0xffffU +#define TPACPI_MATCH_ANY 0xffffffffU +#define TPACPI_MATCH_ANY_VERSION 0xffffU #define TPACPI_MATCH_UNKNOWN 0U -/* TPID('1', 'Y') == 0x5931 */ -#define TPID(__c1, __c2) (((__c2) << 8) | (__c1)) +/* TPID('1', 'Y') == 0x3159 */ +#define TPID(__c1, __c2) (((__c1) << 8) | (__c2)) +#define TPID3(__c1, __c2, __c3) (((__c1) << 16) | ((__c2) << 8) | (__c3)) +#define TPVER TPID #define TPACPI_Q_IBM(__id1, __id2, __quirk) \ { .vendor = PCI_VENDOR_ID_IBM, \ @@ -469,6 +472,12 @@ do { \ .ec = TPACPI_MATCH_ANY, \ .quirks = (__quirk) } +#define TPACPI_Q_LNV3(__id1, __id2, __id3, __quirk) \ + { .vendor = PCI_VENDOR_ID_LENOVO, \ + .bios = TPID3(__id1, __id2, __id3), \ + .ec = TPACPI_MATCH_ANY, \ + .quirks = (__quirk) } + #define TPACPI_QEC_LNV(__id1, __id2, __quirk) \ { .vendor = PCI_VENDOR_ID_LENOVO, \ .bios = TPACPI_MATCH_ANY, \ @@ -477,8 +486,8 @@ do { \ struct tpacpi_quirk { unsigned int vendor; - u16 bios; - u16 ec; + u32 bios; + u32 ec; unsigned long quirks; }; @@ -1648,16 +1657,16 @@ static void tpacpi_remove_driver_attributes(struct device_driver *drv) { .vendor = (__v), \ .bios = TPID(__id1, __id2), \ .ec = TPACPI_MATCH_ANY, \ - .quirks = TPACPI_MATCH_ANY << 16 \ - | (__bv1) << 8 | (__bv2) } + .quirks = TPACPI_MATCH_ANY_VERSION << 16 \ + | TPVER(__bv1, __bv2) } #define TPV_Q_X(__v, __bid1, __bid2, __bv1, __bv2, \ __eid, __ev1, __ev2) \ { .vendor = (__v), \ .bios = TPID(__bid1, __bid2), \ .ec = __eid, \ - .quirks = (__ev1) << 24 | (__ev2) << 16 \ - | (__bv1) << 8 | (__bv2) } + .quirks = TPVER(__ev1, __ev2) << 16 \ + | TPVER(__bv1, __bv2) } #define TPV_QI0(__id1, __id2, __bv1, __bv2) \ TPV_Q(PCI_VENDOR_ID_IBM, __id1, __id2, __bv1, __bv2) @@ -1799,7 +1808,7 @@ static void __init tpacpi_check_outdated_fw(void) /* note that unknown versions are set to 0x0000 and we use that */ if ((bios_version > thinkpad_id.bios_release) || (ec_version > thinkpad_id.ec_release && - ec_version != TPACPI_MATCH_ANY)) { + ec_version != TPACPI_MATCH_ANY_VERSION)) { /* * The changelogs would let us track down the exact * reason, but it is just too much of a pain to track @@ -1929,7 +1938,7 @@ enum { /* hot key scan codes (derived from ACPI DSDT) */ /* first new observed key (star, favorites) is 0x1311 */ TP_ACPI_HOTKEYSCAN_STAR = 69, TP_ACPI_HOTKEYSCAN_CLIPPING_TOOL2, - TP_ACPI_HOTKEYSCAN_UNK25, + TP_ACPI_HOTKEYSCAN_CALCULATOR, TP_ACPI_HOTKEYSCAN_BLUETOOTH, TP_ACPI_HOTKEYSCAN_KEYBOARD, @@ -3450,7 +3459,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) KEY_FAVORITES, /* Favorite app, 0x311 */ KEY_RESERVED, /* Clipping tool */ - KEY_RESERVED, + KEY_CALC, /* Calculator (above numpad, P52) */ KEY_BLUETOOTH, /* Bluetooth */ KEY_KEYBOARD /* Keyboard, 0x315 */ }, @@ -9366,7 +9375,9 @@ static int tpacpi_battery_probe(int battery) { int ret = 0; - memset(&battery_info, 0, sizeof(struct tpacpi_battery_driver_data)); + memset(&battery_info.batteries[battery], 0, + sizeof(battery_info.batteries[battery])); + /* * 1) Get the current start threshold * 2) Check for support @@ -9421,7 +9432,8 @@ static int tpacpi_battery_probe(int battery) static int tpacpi_battery_get_id(const char *battery_name) { - if (strcmp(battery_name, "BAT0") == 0) + if (strcmp(battery_name, "BAT0") == 0 || + tp_features.battery_force_primary) return BAT_PRIMARY; if (strcmp(battery_name, "BAT1") == 0) return BAT_SECONDARY; @@ -9597,8 +9609,26 @@ static struct acpi_battery_hook battery_hook = { /* Subdriver init/exit */ +static const struct tpacpi_quirk battery_quirk_table[] __initconst = { + /* + * Individual addressing is broken on models that expose the + * primary battery as BAT1. + */ + TPACPI_Q_LNV('J', '7', true), /* B5400 */ + TPACPI_Q_LNV('J', 'I', true), /* Thinkpad 11e */ + TPACPI_Q_LNV3('R', '0', 'B', true), /* Thinkpad 11e gen 3 */ + TPACPI_Q_LNV3('R', '0', 'C', true), /* Thinkpad 13 */ + TPACPI_Q_LNV3('R', '0', 'J', true), /* Thinkpad 13 gen 2 */ +}; + static int __init tpacpi_battery_init(struct ibm_init_struct *ibm) { + memset(&battery_info, 0, sizeof(battery_info)); + + tp_features.battery_force_primary = tpacpi_check_quirks( + battery_quirk_table, + ARRAY_SIZE(battery_quirk_table)); + battery_hook_register(&battery_hook); return 0; } @@ -9809,36 +9839,37 @@ err_out: /* Probing */ -static bool __pure __init tpacpi_is_fw_digit(const char c) +static char __init tpacpi_parse_fw_id(const char * const s, + u32 *model, u16 *release) { - return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z'); -} + int i; + + if (!s || strlen(s) < 8) + goto invalid; + + for (i = 0; i < 8; i++) + if (!((s[i] >= '0' && s[i] <= '9') || + (s[i] >= 'A' && s[i] <= 'Z'))) + goto invalid; -static bool __pure __init tpacpi_is_valid_fw_id(const char * const s, - const char t) -{ /* * Most models: xxyTkkWW (#.##c) * Ancient 570/600 and -SL lacks (#.##c) */ - if (s && strlen(s) >= 8 && - tpacpi_is_fw_digit(s[0]) && - tpacpi_is_fw_digit(s[1]) && - s[2] == t && - (s[3] == 'T' || s[3] == 'N') && - tpacpi_is_fw_digit(s[4]) && - tpacpi_is_fw_digit(s[5])) - return true; + if (s[3] == 'T' || s[3] == 'N') { + *model = TPID(s[0], s[1]); + *release = TPVER(s[4], s[5]); + return s[2]; /* New models: xxxyTkkW (#.##c); T550 and some others */ - return s && strlen(s) >= 8 && - tpacpi_is_fw_digit(s[0]) && - tpacpi_is_fw_digit(s[1]) && - tpacpi_is_fw_digit(s[2]) && - s[3] == t && - (s[4] == 'T' || s[4] == 'N') && - tpacpi_is_fw_digit(s[5]) && - tpacpi_is_fw_digit(s[6]); + } else if (s[4] == 'T' || s[4] == 'N') { + *model = TPID3(s[0], s[1], s[2]); + *release = TPVER(s[5], s[6]); + return s[3]; + } + +invalid: + return '\0'; } /* returns 0 - probe ok, or < 0 - probe error. @@ -9850,6 +9881,7 @@ static int __must_check __init get_thinkpad_model_data( const struct dmi_device *dev = NULL; char ec_fw_string[18]; char const *s; + char t; if (!tp) return -EINVAL; @@ -9869,15 +9901,11 @@ static int __must_check __init get_thinkpad_model_data( return -ENOMEM; /* Really ancient ThinkPad 240X will fail this, which is fine */ - if (!(tpacpi_is_valid_fw_id(tp->bios_version_str, 'E') || - tpacpi_is_valid_fw_id(tp->bios_version_str, 'C'))) + t = tpacpi_parse_fw_id(tp->bios_version_str, + &tp->bios_model, &tp->bios_release); + if (t != 'E' && t != 'C') return 0; - tp->bios_model = tp->bios_version_str[0] - | (tp->bios_version_str[1] << 8); - tp->bios_release = (tp->bios_version_str[4] << 8) - | tp->bios_version_str[5]; - /* * ThinkPad T23 or newer, A31 or newer, R50e or newer, * X32 or newer, all Z series; Some models must have an @@ -9896,12 +9924,9 @@ static int __must_check __init get_thinkpad_model_data( if (!tp->ec_version_str) return -ENOMEM; - if (tpacpi_is_valid_fw_id(ec_fw_string, 'H')) { - tp->ec_model = ec_fw_string[0] - | (ec_fw_string[1] << 8); - tp->ec_release = (ec_fw_string[4] << 8) - | ec_fw_string[5]; - } else { + t = tpacpi_parse_fw_id(ec_fw_string, + &tp->ec_model, &tp->ec_release); + if (t != 'H') { pr_notice("ThinkPad firmware release %s doesn't match the known patterns\n", ec_fw_string); pr_notice("please report this to %s\n", diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index eef76bfa5d73..e366977bda41 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c @@ -34,6 +34,7 @@ #define TOSHIBA_ACPI_VERSION "0.24" #define PROC_INTERFACE_VERSION 1 +#include <linux/compiler.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/moduleparam.h> @@ -1682,7 +1683,7 @@ static const struct file_operations keys_proc_fops = { .write = keys_proc_write, }; -static int version_proc_show(struct seq_file *m, void *v) +static int __maybe_unused version_proc_show(struct seq_file *m, void *v) { seq_printf(m, "driver: %s\n", TOSHIBA_ACPI_VERSION); seq_printf(m, "proc_interface: %d\n", PROC_INTERFACE_VERSION); @@ -1836,6 +1837,7 @@ static ssize_t kbd_backlight_mode_store(struct device *dev, return ret; toshiba->kbd_mode = mode; + toshiba_acpi->kbd_mode = mode; /* * Some laptop models with the second generation backlit @@ -1852,7 +1854,7 @@ static ssize_t kbd_backlight_mode_store(struct device *dev, * event via genetlink. */ if (toshiba->kbd_type == 2 && - !toshiba_acpi->kbd_event_generated) + !toshiba->kbd_event_generated) schedule_work(&kbd_bl_work); } @@ -2413,16 +2415,21 @@ static const struct attribute_group toshiba_attr_group = { static void toshiba_acpi_kbd_bl_work(struct work_struct *work) { - struct acpi_device *acpi_dev = toshiba_acpi->acpi_dev; - /* Update the sysfs entries */ - if (sysfs_update_group(&acpi_dev->dev.kobj, + if (sysfs_update_group(&toshiba_acpi->acpi_dev->dev.kobj, &toshiba_attr_group)) pr_err("Unable to update sysfs entries\n"); + /* Notify LED subsystem about keyboard backlight change */ + if (toshiba_acpi->kbd_type == 2 && + toshiba_acpi->kbd_mode != SCI_KBD_MODE_AUTO) + led_classdev_notify_brightness_hw_changed(&toshiba_acpi->kbd_led, + (toshiba_acpi->kbd_mode == SCI_KBD_MODE_ON) ? + LED_FULL : LED_OFF); + /* Emulate the keyboard backlight event */ - acpi_bus_generate_netlink_event(acpi_dev->pnp.device_class, - dev_name(&acpi_dev->dev), + acpi_bus_generate_netlink_event(toshiba_acpi->acpi_dev->pnp.device_class, + dev_name(&toshiba_acpi->acpi_dev->dev), 0x92, 0); } @@ -3119,9 +3126,12 @@ static int toshiba_acpi_add(struct acpi_device *acpi_dev) /* * Only register the LED if KBD illumination is supported * and the keyboard backlight operation mode is set to FN-Z + * or we detect a second gen keyboard backlight */ - if (dev->kbd_illum_supported && dev->kbd_mode == SCI_KBD_MODE_FNZ) { + if (dev->kbd_illum_supported && + (dev->kbd_mode == SCI_KBD_MODE_FNZ || dev->kbd_type == 2)) { dev->kbd_led.name = "toshiba::kbd_backlight"; + dev->kbd_led.flags = LED_BRIGHT_HW_CHANGED; dev->kbd_led.max_brightness = 1; dev->kbd_led.brightness_set = toshiba_kbd_backlight_set; dev->kbd_led.brightness_get = toshiba_kbd_backlight_get; @@ -3237,11 +3247,16 @@ static void toshiba_acpi_notify(struct acpi_device *acpi_dev, u32 event) pr_info("SATA power event received %x\n", event); break; case 0x92: /* Keyboard backlight mode changed */ - toshiba_acpi->kbd_event_generated = true; + dev->kbd_event_generated = true; /* Update sysfs entries */ if (sysfs_update_group(&acpi_dev->dev.kobj, &toshiba_attr_group)) pr_err("Unable to update sysfs entries\n"); + /* Notify LED subsystem about keyboard backlight change */ + if (dev->kbd_type == 2 && dev->kbd_mode != SCI_KBD_MODE_AUTO) + led_classdev_notify_brightness_hw_changed(&dev->kbd_led, + (dev->kbd_mode == SCI_KBD_MODE_ON) ? + LED_FULL : LED_OFF); break; case 0x85: /* Unknown */ case 0x8d: /* Unknown */ diff --git a/drivers/platform/x86/silead_dmi.c b/drivers/platform/x86/touchscreen_dmi.c index 853a7ce4601c..cb204f973491 100644 --- a/drivers/platform/x86/silead_dmi.c +++ b/drivers/platform/x86/touchscreen_dmi.c @@ -1,5 +1,5 @@ /* - * Silead touchscreen driver DMI based configuration code + * Touchscreen driver DMI based configuration code * * Copyright (c) 2017 Red Hat Inc. * @@ -20,95 +20,147 @@ #include <linux/property.h> #include <linux/string.h> -struct silead_ts_dmi_data { +struct ts_dmi_data { const char *acpi_name; const struct property_entry *properties; }; -static const struct property_entry cube_iwork8_air_props[] = { - PROPERTY_ENTRY_U32("touchscreen-size-x", 1660), - PROPERTY_ENTRY_U32("touchscreen-size-y", 900), +/* NOTE: Please keep all entries sorted alphabetically */ + +static const struct property_entry chuwi_hi8_props[] = { + PROPERTY_ENTRY_U32("touchscreen-size-x", 1665), + PROPERTY_ENTRY_U32("touchscreen-size-y", 1140), PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"), - PROPERTY_ENTRY_STRING("firmware-name", "gsl3670-cube-iwork8-air.fw"), - PROPERTY_ENTRY_U32("silead,max-fingers", 10), + PROPERTY_ENTRY_BOOL("silead,home-button"), + PROPERTY_ENTRY_STRING("firmware-name", "gsl1680-chuwi-hi8.fw"), { } }; -static const struct silead_ts_dmi_data cube_iwork8_air_data = { +static const struct ts_dmi_data chuwi_hi8_data = { + .acpi_name = "MSSL0001:00", + .properties = chuwi_hi8_props, +}; + +static const struct property_entry chuwi_hi8_pro_props[] = { + PROPERTY_ENTRY_U32("touchscreen-size-x", 1728), + PROPERTY_ENTRY_U32("touchscreen-size-y", 1148), + PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"), + PROPERTY_ENTRY_STRING("firmware-name", "gsl3680-chuwi-hi8-pro.fw"), + PROPERTY_ENTRY_BOOL("silead,home-button"), + { } +}; + +static const struct ts_dmi_data chuwi_hi8_pro_data = { .acpi_name = "MSSL1680:00", - .properties = cube_iwork8_air_props, + .properties = chuwi_hi8_pro_props, }; -static const struct property_entry jumper_ezpad_mini3_props[] = { - PROPERTY_ENTRY_U32("touchscreen-size-x", 1700), - PROPERTY_ENTRY_U32("touchscreen-size-y", 1150), +static const struct property_entry chuwi_vi8_props[] = { + PROPERTY_ENTRY_U32("touchscreen-size-x", 1724), + PROPERTY_ENTRY_U32("touchscreen-size-y", 1140), PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"), - PROPERTY_ENTRY_STRING("firmware-name", "gsl3676-jumper-ezpad-mini3.fw"), + PROPERTY_ENTRY_STRING("firmware-name", "gsl3676-chuwi-vi8.fw"), PROPERTY_ENTRY_U32("silead,max-fingers", 10), + PROPERTY_ENTRY_BOOL("silead,home-button"), { } }; -static const struct silead_ts_dmi_data jumper_ezpad_mini3_data = { - .acpi_name = "MSSL1680:00", - .properties = jumper_ezpad_mini3_props, +static const struct ts_dmi_data chuwi_vi8_data = { + .acpi_name = "MSSL1680:00", + .properties = chuwi_vi8_props, }; -static const struct property_entry jumper_ezpad_6_pro_props[] = { - PROPERTY_ENTRY_U32("touchscreen-size-x", 1980), - PROPERTY_ENTRY_U32("touchscreen-size-y", 1500), - PROPERTY_ENTRY_STRING("firmware-name", "gsl3692-jumper-ezpad-6-pro.fw"), +static const struct property_entry chuwi_vi10_props[] = { + PROPERTY_ENTRY_U32("touchscreen-min-x", 0), + PROPERTY_ENTRY_U32("touchscreen-min-y", 4), + PROPERTY_ENTRY_U32("touchscreen-size-x", 1858), + PROPERTY_ENTRY_U32("touchscreen-size-y", 1280), + PROPERTY_ENTRY_STRING("firmware-name", "gsl3680-chuwi-vi10.fw"), PROPERTY_ENTRY_U32("silead,max-fingers", 10), PROPERTY_ENTRY_BOOL("silead,home-button"), { } }; -static const struct silead_ts_dmi_data jumper_ezpad_6_pro_data = { +static const struct ts_dmi_data chuwi_vi10_data = { + .acpi_name = "MSSL0002:00", + .properties = chuwi_vi10_props, +}; + +static const struct property_entry connect_tablet9_props[] = { + PROPERTY_ENTRY_U32("touchscreen-min-x", 9), + PROPERTY_ENTRY_U32("touchscreen-min-y", 8), + PROPERTY_ENTRY_U32("touchscreen-size-x", 1664), + PROPERTY_ENTRY_U32("touchscreen-size-y", 878), + PROPERTY_ENTRY_BOOL("touchscreen-inverted-y"), + PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"), + PROPERTY_ENTRY_STRING("firmware-name", "gsl1680-connect-tablet9.fw"), + PROPERTY_ENTRY_U32("silead,max-fingers", 10), + { } +}; + +static const struct ts_dmi_data connect_tablet9_data = { + .acpi_name = "MSSL1680:00", + .properties = connect_tablet9_props, +}; + +static const struct property_entry cube_iwork8_air_props[] = { + PROPERTY_ENTRY_U32("touchscreen-size-x", 1660), + PROPERTY_ENTRY_U32("touchscreen-size-y", 900), + PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"), + PROPERTY_ENTRY_STRING("firmware-name", "gsl3670-cube-iwork8-air.fw"), + PROPERTY_ENTRY_U32("silead,max-fingers", 10), + { } +}; + +static const struct ts_dmi_data cube_iwork8_air_data = { .acpi_name = "MSSL1680:00", - .properties = jumper_ezpad_6_pro_props, + .properties = cube_iwork8_air_props, }; -static const struct property_entry dexp_ursus_7w_props[] = { - PROPERTY_ENTRY_U32("touchscreen-size-x", 890), - PROPERTY_ENTRY_U32("touchscreen-size-y", 630), - PROPERTY_ENTRY_STRING("firmware-name", "gsl1686-dexp-ursus-7w.fw"), +static const struct property_entry cube_knote_i1101_props[] = { + PROPERTY_ENTRY_U32("touchscreen-min-x", 20), + PROPERTY_ENTRY_U32("touchscreen-min-y", 22), + PROPERTY_ENTRY_U32("touchscreen-size-x", 1961), + PROPERTY_ENTRY_U32("touchscreen-size-y", 1513), + PROPERTY_ENTRY_STRING("firmware-name", "gsl3692-cube-knote-i1101.fw"), PROPERTY_ENTRY_U32("silead,max-fingers", 10), PROPERTY_ENTRY_BOOL("silead,home-button"), { } }; -static const struct silead_ts_dmi_data dexp_ursus_7w_data = { +static const struct ts_dmi_data cube_knote_i1101_data = { .acpi_name = "MSSL1680:00", - .properties = dexp_ursus_7w_props, + .properties = cube_knote_i1101_props, }; -static const struct property_entry surftab_twin_10_1_st10432_8_props[] = { - PROPERTY_ENTRY_U32("touchscreen-size-x", 1900), - PROPERTY_ENTRY_U32("touchscreen-size-y", 1280), - PROPERTY_ENTRY_U32("touchscreen-inverted-y", 1), - PROPERTY_ENTRY_STRING("firmware-name", - "gsl3670-surftab-twin-10-1-st10432-8.fw"), +static const struct property_entry dexp_ursus_7w_props[] = { + PROPERTY_ENTRY_U32("touchscreen-size-x", 890), + PROPERTY_ENTRY_U32("touchscreen-size-y", 630), + PROPERTY_ENTRY_STRING("firmware-name", "gsl1686-dexp-ursus-7w.fw"), PROPERTY_ENTRY_U32("silead,max-fingers", 10), + PROPERTY_ENTRY_BOOL("silead,home-button"), { } }; -static const struct silead_ts_dmi_data surftab_twin_10_1_st10432_8_data = { +static const struct ts_dmi_data dexp_ursus_7w_data = { .acpi_name = "MSSL1680:00", - .properties = surftab_twin_10_1_st10432_8_props, + .properties = dexp_ursus_7w_props, }; -static const struct property_entry surftab_wintron70_st70416_6_props[] = { - PROPERTY_ENTRY_U32("touchscreen-size-x", 884), - PROPERTY_ENTRY_U32("touchscreen-size-y", 632), +static const struct property_entry digma_citi_e200_props[] = { + PROPERTY_ENTRY_U32("touchscreen-size-x", 1980), + PROPERTY_ENTRY_U32("touchscreen-size-y", 1500), + PROPERTY_ENTRY_BOOL("touchscreen-inverted-y"), PROPERTY_ENTRY_STRING("firmware-name", - "gsl1686-surftab-wintron70-st70416-6.fw"), + "gsl1686-digma_citi_e200.fw"), PROPERTY_ENTRY_U32("silead,max-fingers", 10), PROPERTY_ENTRY_BOOL("silead,home-button"), { } }; -static const struct silead_ts_dmi_data surftab_wintron70_st70416_6_data = { +static const struct ts_dmi_data digma_citi_e200_data = { .acpi_name = "MSSL1680:00", - .properties = surftab_wintron70_st70416_6_props, + .properties = digma_citi_e200_props, }; static const struct property_entry gp_electronic_t701_props[] = { @@ -121,162 +173,181 @@ static const struct property_entry gp_electronic_t701_props[] = { { } }; -static const struct silead_ts_dmi_data gp_electronic_t701_data = { +static const struct ts_dmi_data gp_electronic_t701_data = { .acpi_name = "MSSL1680:00", .properties = gp_electronic_t701_props, }; -static const struct property_entry pipo_w2s_props[] = { - PROPERTY_ENTRY_U32("touchscreen-size-x", 1660), - PROPERTY_ENTRY_U32("touchscreen-size-y", 880), - PROPERTY_ENTRY_BOOL("touchscreen-inverted-x"), +static const struct property_entry itworks_tw891_props[] = { + PROPERTY_ENTRY_U32("touchscreen-size-x", 1600), + PROPERTY_ENTRY_U32("touchscreen-size-y", 890), + PROPERTY_ENTRY_BOOL("touchscreen-inverted-y"), PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"), - PROPERTY_ENTRY_STRING("firmware-name", - "gsl1680-pipo-w2s.fw"), + PROPERTY_ENTRY_STRING("firmware-name", "gsl3670-itworks-tw891.fw"), { } }; -static const struct silead_ts_dmi_data pipo_w2s_data = { +static const struct ts_dmi_data itworks_tw891_data = { .acpi_name = "MSSL1680:00", - .properties = pipo_w2s_props, + .properties = itworks_tw891_props, }; -static const struct property_entry pov_mobii_wintab_p800w_v20_props[] = { - PROPERTY_ENTRY_U32("touchscreen-min-x", 32), - PROPERTY_ENTRY_U32("touchscreen-min-y", 16), - PROPERTY_ENTRY_U32("touchscreen-size-x", 1692), - PROPERTY_ENTRY_U32("touchscreen-size-y", 1146), - PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"), - PROPERTY_ENTRY_STRING("firmware-name", - "gsl3680-pov-mobii-wintab-p800w-v20.fw"), +static const struct property_entry jumper_ezpad_6_pro_props[] = { + PROPERTY_ENTRY_U32("touchscreen-size-x", 1980), + PROPERTY_ENTRY_U32("touchscreen-size-y", 1500), + PROPERTY_ENTRY_STRING("firmware-name", "gsl3692-jumper-ezpad-6-pro.fw"), PROPERTY_ENTRY_U32("silead,max-fingers", 10), PROPERTY_ENTRY_BOOL("silead,home-button"), { } }; -static const struct silead_ts_dmi_data pov_mobii_wintab_p800w_v20_data = { +static const struct ts_dmi_data jumper_ezpad_6_pro_data = { .acpi_name = "MSSL1680:00", - .properties = pov_mobii_wintab_p800w_v20_props, + .properties = jumper_ezpad_6_pro_props, }; -static const struct property_entry pov_mobii_wintab_p800w_v21_props[] = { - PROPERTY_ENTRY_U32("touchscreen-size-x", 1800), +static const struct property_entry jumper_ezpad_mini3_props[] = { + PROPERTY_ENTRY_U32("touchscreen-size-x", 1700), PROPERTY_ENTRY_U32("touchscreen-size-y", 1150), PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"), - PROPERTY_ENTRY_STRING("firmware-name", - "gsl3692-pov-mobii-wintab-p800w.fw"), - PROPERTY_ENTRY_BOOL("silead,home-button"), + PROPERTY_ENTRY_STRING("firmware-name", "gsl3676-jumper-ezpad-mini3.fw"), + PROPERTY_ENTRY_U32("silead,max-fingers", 10), { } }; -static const struct silead_ts_dmi_data pov_mobii_wintab_p800w_v21_data = { +static const struct ts_dmi_data jumper_ezpad_mini3_data = { .acpi_name = "MSSL1680:00", - .properties = pov_mobii_wintab_p800w_v21_props, + .properties = jumper_ezpad_mini3_props, }; -static const struct property_entry itworks_tw891_props[] = { - PROPERTY_ENTRY_U32("touchscreen-size-x", 1600), - PROPERTY_ENTRY_U32("touchscreen-size-y", 890), +static const struct property_entry onda_obook_20_plus_props[] = { + PROPERTY_ENTRY_U32("touchscreen-size-x", 1728), + PROPERTY_ENTRY_U32("touchscreen-size-y", 1148), + PROPERTY_ENTRY_BOOL("touchscreen-inverted-x"), PROPERTY_ENTRY_BOOL("touchscreen-inverted-y"), PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"), - PROPERTY_ENTRY_STRING("firmware-name", "gsl3670-itworks-tw891.fw"), + PROPERTY_ENTRY_STRING("firmware-name", "gsl3676-onda-obook-20-plus.fw"), + PROPERTY_ENTRY_U32("silead,max-fingers", 10), + PROPERTY_ENTRY_BOOL("silead,home-button"), { } }; -static const struct silead_ts_dmi_data itworks_tw891_data = { +static const struct ts_dmi_data onda_obook_20_plus_data = { .acpi_name = "MSSL1680:00", - .properties = itworks_tw891_props, + .properties = onda_obook_20_plus_props, }; -static const struct property_entry chuwi_hi8_pro_props[] = { - PROPERTY_ENTRY_U32("touchscreen-size-x", 1728), - PROPERTY_ENTRY_U32("touchscreen-size-y", 1148), +static const struct property_entry onda_v820w_32g_props[] = { + PROPERTY_ENTRY_U32("touchscreen-size-x", 1665), + PROPERTY_ENTRY_U32("touchscreen-size-y", 1140), PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"), - PROPERTY_ENTRY_STRING("firmware-name", "gsl3680-chuwi-hi8-pro.fw"), + PROPERTY_ENTRY_STRING("firmware-name", + "gsl1680-onda-v820w-32g.fw"), + PROPERTY_ENTRY_U32("silead,max-fingers", 10), PROPERTY_ENTRY_BOOL("silead,home-button"), { } }; -static const struct silead_ts_dmi_data chuwi_hi8_pro_data = { +static const struct ts_dmi_data onda_v820w_32g_data = { .acpi_name = "MSSL1680:00", - .properties = chuwi_hi8_pro_props, + .properties = onda_v820w_32g_props, }; -static const struct property_entry digma_citi_e200_props[] = { - PROPERTY_ENTRY_U32("touchscreen-size-x", 1980), - PROPERTY_ENTRY_U32("touchscreen-size-y", 1500), - PROPERTY_ENTRY_BOOL("touchscreen-inverted-y"), +static const struct property_entry onda_v891w_v1_props[] = { + PROPERTY_ENTRY_U32("touchscreen-min-x", 46), + PROPERTY_ENTRY_U32("touchscreen-min-y", 8), + PROPERTY_ENTRY_U32("touchscreen-size-x", 1676), + PROPERTY_ENTRY_U32("touchscreen-size-y", 1130), PROPERTY_ENTRY_STRING("firmware-name", - "gsl1686-digma_citi_e200.fw"), + "gsl3680-onda-v891w-v1.fw"), PROPERTY_ENTRY_U32("silead,max-fingers", 10), PROPERTY_ENTRY_BOOL("silead,home-button"), { } }; -static const struct silead_ts_dmi_data digma_citi_e200_data = { +static const struct ts_dmi_data onda_v891w_v1_data = { .acpi_name = "MSSL1680:00", - .properties = digma_citi_e200_props, + .properties = onda_v891w_v1_props, }; -static const struct property_entry onda_obook_20_plus_props[] = { - PROPERTY_ENTRY_U32("touchscreen-size-x", 1728), - PROPERTY_ENTRY_U32("touchscreen-size-y", 1148), - PROPERTY_ENTRY_BOOL("touchscreen-inverted-x"), +static const struct property_entry onda_v891w_v3_props[] = { + PROPERTY_ENTRY_U32("touchscreen-min-x", 35), + PROPERTY_ENTRY_U32("touchscreen-min-y", 15), + PROPERTY_ENTRY_U32("touchscreen-size-x", 1625), + PROPERTY_ENTRY_U32("touchscreen-size-y", 1135), PROPERTY_ENTRY_BOOL("touchscreen-inverted-y"), - PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"), - PROPERTY_ENTRY_STRING("firmware-name", "gsl3676-onda-obook-20-plus.fw"), + PROPERTY_ENTRY_STRING("firmware-name", + "gsl3676-onda-v891w-v3.fw"), PROPERTY_ENTRY_U32("silead,max-fingers", 10), PROPERTY_ENTRY_BOOL("silead,home-button"), { } }; -static const struct silead_ts_dmi_data onda_obook_20_plus_data = { +static const struct ts_dmi_data onda_v891w_v3_data = { .acpi_name = "MSSL1680:00", - .properties = onda_obook_20_plus_props, + .properties = onda_v891w_v3_props, }; -static const struct property_entry chuwi_hi8_props[] = { - PROPERTY_ENTRY_U32("touchscreen-size-x", 1665), - PROPERTY_ENTRY_U32("touchscreen-size-y", 1140), +static const struct property_entry pipo_w2s_props[] = { + PROPERTY_ENTRY_U32("touchscreen-size-x", 1660), + PROPERTY_ENTRY_U32("touchscreen-size-y", 880), + PROPERTY_ENTRY_BOOL("touchscreen-inverted-x"), PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"), - PROPERTY_ENTRY_BOOL("silead,home-button"), - PROPERTY_ENTRY_STRING("firmware-name", "gsl1680-chuwi-hi8.fw"), + PROPERTY_ENTRY_STRING("firmware-name", + "gsl1680-pipo-w2s.fw"), { } }; -static const struct silead_ts_dmi_data chuwi_hi8_data = { - .acpi_name = "MSSL0001:00", - .properties = chuwi_hi8_props, +static const struct ts_dmi_data pipo_w2s_data = { + .acpi_name = "MSSL1680:00", + .properties = pipo_w2s_props, }; -static const struct property_entry chuwi_vi8_props[] = { - PROPERTY_ENTRY_U32("touchscreen-size-x", 1724), - PROPERTY_ENTRY_U32("touchscreen-size-y", 1140), +static const struct property_entry pov_mobii_wintab_p800w_v20_props[] = { + PROPERTY_ENTRY_U32("touchscreen-min-x", 32), + PROPERTY_ENTRY_U32("touchscreen-min-y", 16), + PROPERTY_ENTRY_U32("touchscreen-size-x", 1692), + PROPERTY_ENTRY_U32("touchscreen-size-y", 1146), PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"), - PROPERTY_ENTRY_STRING("firmware-name", "gsl3676-chuwi-vi8.fw"), + PROPERTY_ENTRY_STRING("firmware-name", + "gsl3680-pov-mobii-wintab-p800w-v20.fw"), PROPERTY_ENTRY_U32("silead,max-fingers", 10), PROPERTY_ENTRY_BOOL("silead,home-button"), { } }; -static const struct silead_ts_dmi_data chuwi_vi8_data = { - .acpi_name = "MSSL1680:00", - .properties = chuwi_vi8_props, +static const struct ts_dmi_data pov_mobii_wintab_p800w_v20_data = { + .acpi_name = "MSSL1680:00", + .properties = pov_mobii_wintab_p800w_v20_props, }; -static const struct property_entry trekstor_primebook_c13_props[] = { - PROPERTY_ENTRY_U32("touchscreen-size-x", 2624), - PROPERTY_ENTRY_U32("touchscreen-size-y", 1920), +static const struct property_entry pov_mobii_wintab_p800w_v21_props[] = { + PROPERTY_ENTRY_U32("touchscreen-size-x", 1800), + PROPERTY_ENTRY_U32("touchscreen-size-y", 1150), + PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"), PROPERTY_ENTRY_STRING("firmware-name", - "gsl1680-trekstor-primebook-c13.fw"), + "gsl3692-pov-mobii-wintab-p800w.fw"), + PROPERTY_ENTRY_BOOL("silead,home-button"), + { } +}; + +static const struct ts_dmi_data pov_mobii_wintab_p800w_v21_data = { + .acpi_name = "MSSL1680:00", + .properties = pov_mobii_wintab_p800w_v21_props, +}; + +static const struct property_entry teclast_x3_plus_props[] = { + PROPERTY_ENTRY_U32("touchscreen-size-x", 1980), + PROPERTY_ENTRY_U32("touchscreen-size-y", 1500), + PROPERTY_ENTRY_STRING("firmware-name", "gsl1680-teclast-x3-plus.fw"), PROPERTY_ENTRY_U32("silead,max-fingers", 10), PROPERTY_ENTRY_BOOL("silead,home-button"), { } }; -static const struct silead_ts_dmi_data trekstor_primebook_c13_data = { +static const struct ts_dmi_data teclast_x3_plus_data = { .acpi_name = "MSSL1680:00", - .properties = trekstor_primebook_c13_props, + .properties = teclast_x3_plus_props, }; static const struct property_entry teclast_x98plus2_props[] = { @@ -290,156 +361,162 @@ static const struct property_entry teclast_x98plus2_props[] = { { } }; -static const struct silead_ts_dmi_data teclast_x98plus2_data = { +static const struct ts_dmi_data teclast_x98plus2_data = { .acpi_name = "MSSL1680:00", .properties = teclast_x98plus2_props, }; -static const struct property_entry teclast_x3_plus_props[] = { - PROPERTY_ENTRY_U32("touchscreen-size-x", 1980), - PROPERTY_ENTRY_U32("touchscreen-size-y", 1500), - PROPERTY_ENTRY_STRING("firmware-name", "gsl1680-teclast-x3-plus.fw"), +static const struct property_entry trekstor_primebook_c13_props[] = { + PROPERTY_ENTRY_U32("touchscreen-size-x", 2624), + PROPERTY_ENTRY_U32("touchscreen-size-y", 1920), + PROPERTY_ENTRY_STRING("firmware-name", + "gsl1680-trekstor-primebook-c13.fw"), PROPERTY_ENTRY_U32("silead,max-fingers", 10), PROPERTY_ENTRY_BOOL("silead,home-button"), { } }; -static const struct silead_ts_dmi_data teclast_x3_plus_data = { +static const struct ts_dmi_data trekstor_primebook_c13_data = { .acpi_name = "MSSL1680:00", - .properties = teclast_x3_plus_props, + .properties = trekstor_primebook_c13_props, }; -static const struct property_entry onda_v891w_v1_props[] = { - PROPERTY_ENTRY_U32("touchscreen-min-x", 46), - PROPERTY_ENTRY_U32("touchscreen-min-y", 8), - PROPERTY_ENTRY_U32("touchscreen-size-x", 1676), - PROPERTY_ENTRY_U32("touchscreen-size-y", 1130), +static const struct property_entry trekstor_surftab_twin_10_1_props[] = { + PROPERTY_ENTRY_U32("touchscreen-size-x", 1900), + PROPERTY_ENTRY_U32("touchscreen-size-y", 1280), + PROPERTY_ENTRY_U32("touchscreen-inverted-y", 1), PROPERTY_ENTRY_STRING("firmware-name", - "gsl3680-onda-v891w-v1.fw"), + "gsl3670-surftab-twin-10-1-st10432-8.fw"), + PROPERTY_ENTRY_U32("silead,max-fingers", 10), + { } +}; + +static const struct ts_dmi_data trekstor_surftab_twin_10_1_data = { + .acpi_name = "MSSL1680:00", + .properties = trekstor_surftab_twin_10_1_props, +}; + +static const struct property_entry trekstor_surftab_wintron70_props[] = { + PROPERTY_ENTRY_U32("touchscreen-size-x", 884), + PROPERTY_ENTRY_U32("touchscreen-size-y", 632), + PROPERTY_ENTRY_STRING("firmware-name", + "gsl1686-surftab-wintron70-st70416-6.fw"), PROPERTY_ENTRY_U32("silead,max-fingers", 10), PROPERTY_ENTRY_BOOL("silead,home-button"), { } }; -static const struct silead_ts_dmi_data onda_v891w_v1_data = { +static const struct ts_dmi_data trekstor_surftab_wintron70_data = { .acpi_name = "MSSL1680:00", - .properties = onda_v891w_v1_props, + .properties = trekstor_surftab_wintron70_props, }; -static const struct dmi_system_id silead_ts_dmi_table[] = { +/* NOTE: Please keep this table sorted alphabetically */ +static const struct dmi_system_id touchscreen_dmi_table[] = { { - /* CUBE iwork8 Air */ - .driver_data = (void *)&cube_iwork8_air_data, + /* Chuwi Hi8 */ + .driver_data = (void *)&chuwi_hi8_data, .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "cube"), - DMI_MATCH(DMI_PRODUCT_NAME, "i1-TF"), - DMI_MATCH(DMI_BOARD_NAME, "Cherry Trail CR"), + DMI_MATCH(DMI_SYS_VENDOR, "ilife"), + DMI_MATCH(DMI_PRODUCT_NAME, "S806"), }, }, { - /* Jumper EZpad mini3 */ - .driver_data = (void *)&jumper_ezpad_mini3_data, + /* Chuwi Hi8 (H1D_S806_206) */ + .driver_data = (void *)&chuwi_hi8_data, .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Insyde"), - /* jumperx.T87.KFBNEEA02 with the version-nr dropped */ - DMI_MATCH(DMI_BIOS_VERSION, "jumperx.T87.KFBNEEA"), + DMI_MATCH(DMI_PRODUCT_NAME, "BayTrail"), + DMI_MATCH(DMI_BIOS_VERSION, "H1D_S806_206"), }, }, { - /* Jumper EZpad 6 Pro */ - .driver_data = (void *)&jumper_ezpad_6_pro_data, + /* Chuwi Hi8 Pro (CWI513) */ + .driver_data = (void *)&chuwi_hi8_pro_data, .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Jumper"), - DMI_MATCH(DMI_PRODUCT_NAME, "EZpad"), - DMI_MATCH(DMI_BIOS_VERSION, "5.12"), - /* Above matches are too generic, add bios-date match */ - DMI_MATCH(DMI_BIOS_DATE, "08/18/2017"), + DMI_MATCH(DMI_SYS_VENDOR, "Hampoo"), + DMI_MATCH(DMI_PRODUCT_NAME, "X1D3_C806N"), }, }, { - /* DEXP Ursus 7W */ - .driver_data = (void *)&dexp_ursus_7w_data, + /* Chuwi Vi8 (CWI506) */ + .driver_data = (void *)&chuwi_vi8_data, .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Insyde"), - DMI_MATCH(DMI_PRODUCT_NAME, "7W"), + DMI_MATCH(DMI_PRODUCT_NAME, "i86"), + DMI_MATCH(DMI_BIOS_VERSION, "CHUWI.D86JLBNR"), }, }, { - /* TrekStor SurfTab twin 10.1 ST10432-8 */ - .driver_data = (void *)&surftab_twin_10_1_st10432_8_data, + /* Chuwi Vi10 (CWI505) */ + .driver_data = (void *)&chuwi_vi10_data, .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "TrekStor"), - DMI_MATCH(DMI_PRODUCT_NAME, "SurfTab twin 10.1"), + DMI_MATCH(DMI_BOARD_VENDOR, "Hampoo"), + DMI_MATCH(DMI_BOARD_NAME, "BYT-PF02"), + DMI_MATCH(DMI_SYS_VENDOR, "ilife"), + DMI_MATCH(DMI_PRODUCT_NAME, "S165"), }, }, { - /* Trekstor Surftab Wintron 7.0 ST70416-6 */ - .driver_data = (void *)&surftab_wintron70_st70416_6_data, + /* Connect Tablet 9 */ + .driver_data = (void *)&connect_tablet9_data, .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Insyde"), - DMI_MATCH(DMI_PRODUCT_NAME, "ST70416-6"), - /* Exact match, different versions need different fw */ - DMI_MATCH(DMI_BIOS_VERSION, "TREK.G.WI71C.JGBMRBA04"), + DMI_MATCH(DMI_SYS_VENDOR, "Connect"), + DMI_MATCH(DMI_PRODUCT_NAME, "Tablet 9"), }, }, { - /* Trekstor Surftab Wintron 7.0 ST70416-6, newer BIOS */ - .driver_data = (void *)&surftab_wintron70_st70416_6_data, + /* CUBE iwork8 Air */ + .driver_data = (void *)&cube_iwork8_air_data, .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "TrekStor"), - DMI_MATCH(DMI_PRODUCT_NAME, - "SurfTab wintron 7.0 ST70416-6"), - /* Exact match, different versions need different fw */ - DMI_MATCH(DMI_BIOS_VERSION, "TREK.G.WI71C.JGBMRBA05"), + DMI_MATCH(DMI_SYS_VENDOR, "cube"), + DMI_MATCH(DMI_PRODUCT_NAME, "i1-TF"), + DMI_MATCH(DMI_BOARD_NAME, "Cherry Trail CR"), }, }, { - /* Ployer Momo7w (same hardware as the Trekstor ST70416-6) */ - .driver_data = (void *)&surftab_wintron70_st70416_6_data, + /* Cube KNote i1101 */ + .driver_data = (void *)&cube_knote_i1101_data, .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Shenzhen PLOYER"), - DMI_MATCH(DMI_PRODUCT_NAME, "MOMO7W"), - /* Exact match, different versions need different fw */ - DMI_MATCH(DMI_BIOS_VERSION, "MOMO.G.WI71C.MABMRBA02"), + DMI_MATCH(DMI_BOARD_VENDOR, "Hampoo"), + DMI_MATCH(DMI_BOARD_NAME, "L1W6_I1101"), + DMI_MATCH(DMI_SYS_VENDOR, "ALLDOCUBE"), + DMI_MATCH(DMI_PRODUCT_NAME, "i1101"), }, }, { - /* GP-electronic T701 */ - .driver_data = (void *)&gp_electronic_t701_data, + /* DEXP Ursus 7W */ + .driver_data = (void *)&dexp_ursus_7w_data, .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Insyde"), - DMI_MATCH(DMI_PRODUCT_NAME, "T701"), - DMI_MATCH(DMI_BIOS_VERSION, "BYT70A.YNCHENG.WIN.007"), + DMI_MATCH(DMI_PRODUCT_NAME, "7W"), }, }, { - /* Pipo W2S */ - .driver_data = (void *)&pipo_w2s_data, + /* Digma Citi E200 */ + .driver_data = (void *)&digma_citi_e200_data, .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "PIPO"), - DMI_MATCH(DMI_PRODUCT_NAME, "W2S"), + DMI_MATCH(DMI_SYS_VENDOR, "Digma"), + DMI_MATCH(DMI_PRODUCT_NAME, "CITI E200"), + DMI_MATCH(DMI_BOARD_NAME, "Cherry Trail CR"), }, }, { - /* Point of View mobii wintab p800w (v2.0) */ - .driver_data = (void *)&pov_mobii_wintab_p800w_v20_data, + /* GP-electronic T701 */ + .driver_data = (void *)&gp_electronic_t701_data, .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"), - DMI_MATCH(DMI_BOARD_NAME, "Aptio CRB"), - DMI_MATCH(DMI_BIOS_VERSION, "3BAIR1014"), - /* Above matches are too generic, add bios-date match */ - DMI_MATCH(DMI_BIOS_DATE, "10/24/2014"), + DMI_MATCH(DMI_SYS_VENDOR, "Insyde"), + DMI_MATCH(DMI_PRODUCT_NAME, "T701"), + DMI_MATCH(DMI_BIOS_VERSION, "BYT70A.YNCHENG.WIN.007"), }, }, { - /* Point of View mobii wintab p800w (v2.1) */ - .driver_data = (void *)&pov_mobii_wintab_p800w_v21_data, + /* I.T.Works TW701 (same hardware as the Trekstor ST70416-6) */ + .driver_data = (void *)&trekstor_surftab_wintron70_data, .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"), - DMI_MATCH(DMI_BOARD_NAME, "Aptio CRB"), - DMI_MATCH(DMI_BIOS_VERSION, "3BAIR1013"), - /* Above matches are too generic, add bios-date match */ - DMI_MATCH(DMI_BIOS_DATE, "08/22/2014"), + DMI_MATCH(DMI_SYS_VENDOR, "Insyde"), + DMI_MATCH(DMI_PRODUCT_NAME, "i71c"), + DMI_MATCH(DMI_BIOS_VERSION, "itWORKS.G.WI71C.JGBMRB"), }, }, { @@ -451,20 +528,23 @@ static const struct dmi_system_id silead_ts_dmi_table[] = { }, }, { - /* Chuwi Hi8 Pro */ - .driver_data = (void *)&chuwi_hi8_pro_data, + /* Jumper EZpad 6 Pro */ + .driver_data = (void *)&jumper_ezpad_6_pro_data, .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Hampoo"), - DMI_MATCH(DMI_PRODUCT_NAME, "X1D3_C806N"), + DMI_MATCH(DMI_SYS_VENDOR, "Jumper"), + DMI_MATCH(DMI_PRODUCT_NAME, "EZpad"), + DMI_MATCH(DMI_BIOS_VERSION, "5.12"), + /* Above matches are too generic, add bios-date match */ + DMI_MATCH(DMI_BIOS_DATE, "08/18/2017"), }, }, { - /* Digma Citi E200 */ - .driver_data = (void *)&digma_citi_e200_data, + /* Jumper EZpad mini3 */ + .driver_data = (void *)&jumper_ezpad_mini3_data, .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Digma"), - DMI_MATCH(DMI_PRODUCT_NAME, "CITI E200"), - DMI_MATCH(DMI_BOARD_NAME, "Cherry Trail CR"), + DMI_MATCH(DMI_SYS_VENDOR, "Insyde"), + /* jumperx.T87.KFBNEEA02 with the version-nr dropped */ + DMI_MATCH(DMI_BIOS_VERSION, "jumperx.T87.KFBNEEA"), }, }, { @@ -476,45 +556,71 @@ static const struct dmi_system_id silead_ts_dmi_table[] = { }, }, { - /* Chuwi Hi8 */ - .driver_data = (void *)&chuwi_hi8_data, + /* ONDA V820w DualOS */ + .driver_data = (void *)&onda_v820w_32g_data, .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "ilife"), - DMI_MATCH(DMI_PRODUCT_NAME, "S806"), + DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "ONDA"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "V820w DualOS") }, }, { - /* Chuwi Hi8 (H1D_S806_206) */ - .driver_data = (void *)&chuwi_hi8_data, + /* ONDA V891w revision P891WBEBV1B00 aka v1 */ + .driver_data = (void *)&onda_v891w_v1_data, .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Insyde"), - DMI_MATCH(DMI_PRODUCT_NAME, "BayTrail"), - DMI_MATCH(DMI_BIOS_VERSION, "H1D_S806_206"), + DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "ONDA"), + DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONDA Tablet"), + DMI_EXACT_MATCH(DMI_BOARD_VERSION, "V001"), + /* Exact match, different versions need different fw */ + DMI_EXACT_MATCH(DMI_BIOS_VERSION, "ONDA.W89EBBN08"), }, }, { - /* Chuwi Vi8 (CWI506) */ - .driver_data = (void *)&chuwi_vi8_data, + /* ONDA V891w Dual OS P891DCF2V1A01274 64GB */ + .driver_data = (void *)&onda_v891w_v3_data, .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Insyde"), - DMI_MATCH(DMI_PRODUCT_NAME, "i86"), - DMI_MATCH(DMI_BIOS_VERSION, "CHUWI.D86JLBNR"), + DMI_MATCH(DMI_PRODUCT_NAME, "ONDA Tablet"), + DMI_MATCH(DMI_BIOS_VERSION, "ONDA.D890HBBNR0A"), }, }, { - /* Trekstor Primebook C13 */ - .driver_data = (void *)&trekstor_primebook_c13_data, + /* Pipo W2S */ + .driver_data = (void *)&pipo_w2s_data, .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "TREKSTOR"), - DMI_MATCH(DMI_PRODUCT_NAME, "Primebook C13"), + DMI_MATCH(DMI_SYS_VENDOR, "PIPO"), + DMI_MATCH(DMI_PRODUCT_NAME, "W2S"), }, }, { - /* Teclast X98 Plus II */ - .driver_data = (void *)&teclast_x98plus2_data, + /* Ployer Momo7w (same hardware as the Trekstor ST70416-6) */ + .driver_data = (void *)&trekstor_surftab_wintron70_data, .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "TECLAST"), - DMI_MATCH(DMI_PRODUCT_NAME, "X98 Plus II"), + DMI_MATCH(DMI_SYS_VENDOR, "Shenzhen PLOYER"), + DMI_MATCH(DMI_PRODUCT_NAME, "MOMO7W"), + /* Exact match, different versions need different fw */ + DMI_MATCH(DMI_BIOS_VERSION, "MOMO.G.WI71C.MABMRBA02"), + }, + }, + { + /* Point of View mobii wintab p800w (v2.0) */ + .driver_data = (void *)&pov_mobii_wintab_p800w_v20_data, + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"), + DMI_MATCH(DMI_BOARD_NAME, "Aptio CRB"), + DMI_MATCH(DMI_BIOS_VERSION, "3BAIR1014"), + /* Above matches are too generic, add bios-date match */ + DMI_MATCH(DMI_BIOS_DATE, "10/24/2014"), + }, + }, + { + /* Point of View mobii wintab p800w (v2.1) */ + .driver_data = (void *)&pov_mobii_wintab_p800w_v21_data, + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"), + DMI_MATCH(DMI_BOARD_NAME, "Aptio CRB"), + DMI_MATCH(DMI_BIOS_VERSION, "3BAIR1013"), + /* Above matches are too generic, add bios-date match */ + DMI_MATCH(DMI_BIOS_DATE, "08/22/2014"), }, }, { @@ -527,52 +633,77 @@ static const struct dmi_system_id silead_ts_dmi_table[] = { }, }, { - /* I.T.Works TW701 */ - .driver_data = (void *)&surftab_wintron70_st70416_6_data, + /* Teclast X98 Plus II */ + .driver_data = (void *)&teclast_x98plus2_data, .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Insyde"), - DMI_MATCH(DMI_PRODUCT_NAME, "i71c"), - DMI_MATCH(DMI_BIOS_VERSION, "itWORKS.G.WI71C.JGBMRB"), + DMI_MATCH(DMI_SYS_VENDOR, "TECLAST"), + DMI_MATCH(DMI_PRODUCT_NAME, "X98 Plus II"), }, }, { - /* Yours Y8W81, same case and touchscreen as Chuwi Vi8 */ - .driver_data = (void *)&chuwi_vi8_data, + /* Trekstor Primebook C13 */ + .driver_data = (void *)&trekstor_primebook_c13_data, .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "YOURS"), - DMI_MATCH(DMI_PRODUCT_NAME, "Y8W81"), + DMI_MATCH(DMI_SYS_VENDOR, "TREKSTOR"), + DMI_MATCH(DMI_PRODUCT_NAME, "Primebook C13"), }, }, { - /* ONDA V891w revision P891WBEBV1B00 aka v1 */ - .driver_data = (void *)&onda_v891w_v1_data, + /* TrekStor SurfTab twin 10.1 ST10432-8 */ + .driver_data = (void *)&trekstor_surftab_twin_10_1_data, .matches = { - DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "ONDA"), - DMI_EXACT_MATCH(DMI_BOARD_NAME, "ONDA Tablet"), - DMI_EXACT_MATCH(DMI_BOARD_VERSION, "V001"), + DMI_MATCH(DMI_SYS_VENDOR, "TrekStor"), + DMI_MATCH(DMI_PRODUCT_NAME, "SurfTab twin 10.1"), + }, + }, + { + /* Trekstor Surftab Wintron 7.0 ST70416-6 */ + .driver_data = (void *)&trekstor_surftab_wintron70_data, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Insyde"), + DMI_MATCH(DMI_PRODUCT_NAME, "ST70416-6"), /* Exact match, different versions need different fw */ - DMI_EXACT_MATCH(DMI_BIOS_VERSION, "ONDA.W89EBBN08"), + DMI_MATCH(DMI_BIOS_VERSION, "TREK.G.WI71C.JGBMRBA04"), + }, + }, + { + /* Trekstor Surftab Wintron 7.0 ST70416-6, newer BIOS */ + .driver_data = (void *)&trekstor_surftab_wintron70_data, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "TrekStor"), + DMI_MATCH(DMI_PRODUCT_NAME, + "SurfTab wintron 7.0 ST70416-6"), + /* Exact match, different versions need different fw */ + DMI_MATCH(DMI_BIOS_VERSION, "TREK.G.WI71C.JGBMRBA05"), + }, + }, + { + /* Yours Y8W81, same case and touchscreen as Chuwi Vi8 */ + .driver_data = (void *)&chuwi_vi8_data, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "YOURS"), + DMI_MATCH(DMI_PRODUCT_NAME, "Y8W81"), }, }, { }, }; -static const struct silead_ts_dmi_data *silead_ts_data; +static const struct ts_dmi_data *ts_data; -static void silead_ts_dmi_add_props(struct i2c_client *client) +static void ts_dmi_add_props(struct i2c_client *client) { struct device *dev = &client->dev; int error; if (has_acpi_companion(dev) && - !strncmp(silead_ts_data->acpi_name, client->name, I2C_NAME_SIZE)) { - error = device_add_properties(dev, silead_ts_data->properties); + !strncmp(ts_data->acpi_name, client->name, I2C_NAME_SIZE)) { + error = device_add_properties(dev, ts_data->properties); if (error) dev_err(dev, "failed to add properties: %d\n", error); } } -static int silead_ts_dmi_notifier_call(struct notifier_block *nb, +static int ts_dmi_notifier_call(struct notifier_block *nb, unsigned long action, void *data) { struct device *dev = data; @@ -582,7 +713,7 @@ static int silead_ts_dmi_notifier_call(struct notifier_block *nb, case BUS_NOTIFY_ADD_DEVICE: client = i2c_verify_client(dev); if (client) - silead_ts_dmi_add_props(client); + ts_dmi_add_props(client); break; default: @@ -592,22 +723,22 @@ static int silead_ts_dmi_notifier_call(struct notifier_block *nb, return 0; } -static struct notifier_block silead_ts_dmi_notifier = { - .notifier_call = silead_ts_dmi_notifier_call, +static struct notifier_block ts_dmi_notifier = { + .notifier_call = ts_dmi_notifier_call, }; -static int __init silead_ts_dmi_init(void) +static int __init ts_dmi_init(void) { const struct dmi_system_id *dmi_id; int error; - dmi_id = dmi_first_match(silead_ts_dmi_table); + dmi_id = dmi_first_match(touchscreen_dmi_table); if (!dmi_id) return 0; /* Not an error */ - silead_ts_data = dmi_id->driver_data; + ts_data = dmi_id->driver_data; - error = bus_register_notifier(&i2c_bus_type, &silead_ts_dmi_notifier); + error = bus_register_notifier(&i2c_bus_type, &ts_dmi_notifier); if (error) pr_err("%s: failed to register i2c bus notifier: %d\n", __func__, error); @@ -620,4 +751,4 @@ static int __init silead_ts_dmi_init(void) * itself is ready (which happens at postcore initcall level), but before * ACPI starts enumerating devices (at subsys initcall level). */ -arch_initcall(silead_ts_dmi_init); +arch_initcall(ts_dmi_init); diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index 8e3d0146ff8c..04791ea5d97b 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c @@ -895,7 +895,6 @@ static int wmi_dev_probe(struct device *dev) struct wmi_driver *wdriver = container_of(dev->driver, struct wmi_driver, driver); int ret = 0; - int count; char *buf; if (ACPI_FAILURE(wmi_method_enable(wblock, 1))) @@ -917,9 +916,8 @@ static int wmi_dev_probe(struct device *dev) goto probe_failure; } - count = get_order(wblock->req_buf_size); - wblock->handler_data = (void *)__get_free_pages(GFP_KERNEL, - count); + wblock->handler_data = kmalloc(wblock->req_buf_size, + GFP_KERNEL); if (!wblock->handler_data) { ret = -ENOMEM; goto probe_failure; @@ -964,8 +962,7 @@ static int wmi_dev_remove(struct device *dev) if (wdriver->filter_callback) { misc_deregister(&wblock->char_dev); kfree(wblock->char_dev.name); - free_pages((unsigned long)wblock->handler_data, - get_order(wblock->req_buf_size)); + kfree(wblock->handler_data); } if (wdriver->remove) diff --git a/drivers/power/reset/ltc2952-poweroff.c b/drivers/power/reset/ltc2952-poweroff.c index 6b911b6b10a6..c484584745bc 100644 --- a/drivers/power/reset/ltc2952-poweroff.c +++ b/drivers/power/reset/ltc2952-poweroff.c @@ -2,7 +2,7 @@ * LTC2952 (PowerPath) driver * * Copyright (C) 2014, Xsens Technologies BV <info@xsens.com> - * Maintainer: René Moll <linux@r-moll.nl> + * Maintainer: René Moll <linux@r-moll.nl> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -319,6 +319,6 @@ static struct platform_driver ltc2952_poweroff_driver = { module_platform_driver(ltc2952_poweroff_driver); -MODULE_AUTHOR("René Moll <rene.moll@xsens.com>"); +MODULE_AUTHOR("René Moll <rene.moll@xsens.com>"); MODULE_DESCRIPTION("LTC PowerPath power-off driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index a4d262db9945..504d252716f2 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -286,7 +286,7 @@ config PWM_MTK_DISP config PWM_MEDIATEK tristate "MediaTek PWM support" - depends on ARCH_MEDIATEK || COMPILE_TEST + depends on ARCH_MEDIATEK || RALINK || COMPILE_TEST help Generic PWM framework driver for Mediatek ARM SoC. diff --git a/drivers/pwm/pwm-berlin.c b/drivers/pwm/pwm-berlin.c index 771859aca4be..7c8d6a168ceb 100644 --- a/drivers/pwm/pwm-berlin.c +++ b/drivers/pwm/pwm-berlin.c @@ -21,8 +21,18 @@ #define BERLIN_PWM_EN 0x0 #define BERLIN_PWM_ENABLE BIT(0) #define BERLIN_PWM_CONTROL 0x4 -#define BERLIN_PWM_PRESCALE_MASK 0x7 -#define BERLIN_PWM_PRESCALE_MAX 4096 +/* + * The prescaler claims to support 8 different moduli, configured using the + * low three bits of PWM_CONTROL. (Sequentially, they are 1, 4, 8, 16, 64, + * 256, 1024, and 4096.) However, the moduli from 4 to 1024 appear to be + * implemented by internally shifting TCNT left without adding additional + * bits. So, the max TCNT that actually works for a modulus of 4 is 0x3fff; + * for 8, 0x1fff; and so on. This means that those moduli are entirely + * useless, as we could just do the shift ourselves. The 4096 modulus is + * implemented with a real prescaler, so we do use that, but we treat it + * as a flag instead of pretending the modulus is actually configurable. + */ +#define BERLIN_PWM_PRESCALE_4096 0x7 #define BERLIN_PWM_INVERT_POLARITY BIT(3) #define BERLIN_PWM_DUTY 0x8 #define BERLIN_PWM_TCNT 0xc @@ -46,10 +56,6 @@ static inline struct berlin_pwm_chip *to_berlin_pwm_chip(struct pwm_chip *chip) return container_of(chip, struct berlin_pwm_chip, chip); } -static const u32 prescaler_table[] = { - 1, 4, 8, 16, 64, 256, 1024, 4096 -}; - static inline u32 berlin_pwm_readl(struct berlin_pwm_chip *chip, unsigned int channel, unsigned long offset) { @@ -86,33 +92,32 @@ static int berlin_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm_dev, int duty_ns, int period_ns) { struct berlin_pwm_chip *pwm = to_berlin_pwm_chip(chip); - unsigned int prescale; + bool prescale_4096 = false; u32 value, duty, period; - u64 cycles, tmp; + u64 cycles; cycles = clk_get_rate(pwm->clk); cycles *= period_ns; do_div(cycles, NSEC_PER_SEC); - for (prescale = 0; prescale < ARRAY_SIZE(prescaler_table); prescale++) { - tmp = cycles; - do_div(tmp, prescaler_table[prescale]); + if (cycles > BERLIN_PWM_MAX_TCNT) { + prescale_4096 = true; + cycles >>= 12; // Prescaled by 4096 - if (tmp <= BERLIN_PWM_MAX_TCNT) - break; + if (cycles > BERLIN_PWM_MAX_TCNT) + return -ERANGE; } - if (tmp > BERLIN_PWM_MAX_TCNT) - return -ERANGE; - - period = tmp; - cycles = tmp * duty_ns; + period = cycles; + cycles *= duty_ns; do_div(cycles, period_ns); duty = cycles; value = berlin_pwm_readl(pwm, pwm_dev->hwpwm, BERLIN_PWM_CONTROL); - value &= ~BERLIN_PWM_PRESCALE_MASK; - value |= prescale; + if (prescale_4096) + value |= BERLIN_PWM_PRESCALE_4096; + else + value &= ~BERLIN_PWM_PRESCALE_4096; berlin_pwm_writel(pwm, pwm_dev->hwpwm, value, BERLIN_PWM_CONTROL); berlin_pwm_writel(pwm, pwm_dev->hwpwm, duty, BERLIN_PWM_DUTY); diff --git a/drivers/pwm/pwm-cros-ec.c b/drivers/pwm/pwm-cros-ec.c index 9c13694eaa24..98f6ac6cf6ab 100644 --- a/drivers/pwm/pwm-cros-ec.c +++ b/drivers/pwm/pwm-cros-ec.c @@ -1,11 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* - * Copyright (C) 2016 Google, Inc - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2, as published by - * the Free Software Foundation. - * * Expose a PWM controlled by the ChromeOS EC to the host processor. + * + * Copyright (C) 2016 Google, Inc. */ #include <linux/module.h> diff --git a/drivers/pwm/pwm-fsl-ftm.c b/drivers/pwm/pwm-fsl-ftm.c index 557b4ea16796..883378d055c6 100644 --- a/drivers/pwm/pwm-fsl-ftm.c +++ b/drivers/pwm/pwm-fsl-ftm.c @@ -16,6 +16,7 @@ #include <linux/module.h> #include <linux/mutex.h> #include <linux/of_address.h> +#include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/pm.h> #include <linux/pwm.h> @@ -75,6 +76,10 @@ enum fsl_pwm_clk { FSL_PWM_CLK_MAX }; +struct fsl_ftm_soc { + bool has_enable_bits; +}; + struct fsl_pwm_chip { struct pwm_chip chip; @@ -87,7 +92,10 @@ struct fsl_pwm_chip { int period_ns; + struct clk *ipg_clk; struct clk *clk[FSL_PWM_CLK_MAX]; + + const struct fsl_ftm_soc *soc; }; static inline struct fsl_pwm_chip *to_fsl_chip(struct pwm_chip *chip) @@ -97,16 +105,32 @@ static inline struct fsl_pwm_chip *to_fsl_chip(struct pwm_chip *chip) static int fsl_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) { + int ret; struct fsl_pwm_chip *fpc = to_fsl_chip(chip); - return clk_prepare_enable(fpc->clk[FSL_PWM_CLK_SYS]); + ret = clk_prepare_enable(fpc->ipg_clk); + if (!ret && fpc->soc->has_enable_bits) { + mutex_lock(&fpc->lock); + regmap_update_bits(fpc->regmap, FTM_SC, BIT(pwm->hwpwm + 16), + BIT(pwm->hwpwm + 16)); + mutex_unlock(&fpc->lock); + } + + return ret; } static void fsl_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) { struct fsl_pwm_chip *fpc = to_fsl_chip(chip); - clk_disable_unprepare(fpc->clk[FSL_PWM_CLK_SYS]); + if (fpc->soc->has_enable_bits) { + mutex_lock(&fpc->lock); + regmap_update_bits(fpc->regmap, FTM_SC, BIT(pwm->hwpwm + 16), + 0); + mutex_unlock(&fpc->lock); + } + + clk_disable_unprepare(fpc->ipg_clk); } static int fsl_pwm_calculate_default_ps(struct fsl_pwm_chip *fpc, @@ -363,7 +387,7 @@ static int fsl_pwm_init(struct fsl_pwm_chip *fpc) { int ret; - ret = clk_prepare_enable(fpc->clk[FSL_PWM_CLK_SYS]); + ret = clk_prepare_enable(fpc->ipg_clk); if (ret) return ret; @@ -371,7 +395,7 @@ static int fsl_pwm_init(struct fsl_pwm_chip *fpc) regmap_write(fpc->regmap, FTM_OUTINIT, 0x00); regmap_write(fpc->regmap, FTM_OUTMASK, 0xFF); - clk_disable_unprepare(fpc->clk[FSL_PWM_CLK_SYS]); + clk_disable_unprepare(fpc->ipg_clk); return 0; } @@ -408,6 +432,7 @@ static int fsl_pwm_probe(struct platform_device *pdev) mutex_init(&fpc->lock); + fpc->soc = of_device_get_match_data(&pdev->dev); fpc->chip.dev = &pdev->dev; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -441,6 +466,15 @@ static int fsl_pwm_probe(struct platform_device *pdev) if (IS_ERR(fpc->clk[FSL_PWM_CLK_CNTEN])) return PTR_ERR(fpc->clk[FSL_PWM_CLK_CNTEN]); + /* + * ipg_clk is the interface clock for the IP. If not provided, use the + * ftm_sys clock as the default. + */ + fpc->ipg_clk = devm_clk_get(&pdev->dev, "ipg"); + if (IS_ERR(fpc->ipg_clk)) + fpc->ipg_clk = fpc->clk[FSL_PWM_CLK_SYS]; + + fpc->chip.ops = &fsl_pwm_ops; fpc->chip.of_xlate = of_pwm_xlate_with_flags; fpc->chip.of_pwm_n_cells = 3; @@ -480,7 +514,7 @@ static int fsl_pwm_suspend(struct device *dev) if (!test_bit(PWMF_REQUESTED, &pwm->flags)) continue; - clk_disable_unprepare(fpc->clk[FSL_PWM_CLK_SYS]); + clk_disable_unprepare(fpc->ipg_clk); if (!pwm_is_enabled(pwm)) continue; @@ -503,7 +537,7 @@ static int fsl_pwm_resume(struct device *dev) if (!test_bit(PWMF_REQUESTED, &pwm->flags)) continue; - clk_prepare_enable(fpc->clk[FSL_PWM_CLK_SYS]); + clk_prepare_enable(fpc->ipg_clk); if (!pwm_is_enabled(pwm)) continue; @@ -524,8 +558,17 @@ static const struct dev_pm_ops fsl_pwm_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(fsl_pwm_suspend, fsl_pwm_resume) }; +static const struct fsl_ftm_soc vf610_ftm_pwm = { + .has_enable_bits = false, +}; + +static const struct fsl_ftm_soc imx8qm_ftm_pwm = { + .has_enable_bits = true, +}; + static const struct of_device_id fsl_pwm_dt_ids[] = { - { .compatible = "fsl,vf610-ftm-pwm", }, + { .compatible = "fsl,vf610-ftm-pwm", .data = &vf610_ftm_pwm }, + { .compatible = "fsl,imx8qm-ftm-pwm", .data = &imx8qm_ftm_pwm }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, fsl_pwm_dt_ids); diff --git a/drivers/pwm/pwm-imx.c b/drivers/pwm/pwm-imx.c index 08cbe8120588..1d5242c9cde0 100644 --- a/drivers/pwm/pwm-imx.c +++ b/drivers/pwm/pwm-imx.c @@ -1,10 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 /* * simple driver for PWM (Pulse Width Modulator) controller * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * * Derived from pxa PWM driver by eric miao <eric.miao@marvell.com> */ diff --git a/drivers/pwm/pwm-mediatek.c b/drivers/pwm/pwm-mediatek.c index 328c124773b2..eb6674ce995f 100644 --- a/drivers/pwm/pwm-mediatek.c +++ b/drivers/pwm/pwm-mediatek.c @@ -57,6 +57,7 @@ static const char * const mtk_pwm_clk_name[MTK_CLK_MAX] = { struct mtk_pwm_platform_data { unsigned int num_pwms; bool pwm45_fixup; + bool has_clks; }; /** @@ -86,6 +87,9 @@ static int mtk_pwm_clk_enable(struct pwm_chip *chip, struct pwm_device *pwm) struct mtk_pwm_chip *pc = to_mtk_pwm_chip(chip); int ret; + if (!pc->soc->has_clks) + return 0; + ret = clk_prepare_enable(pc->clks[MTK_CLK_TOP]); if (ret < 0) return ret; @@ -112,6 +116,9 @@ static void mtk_pwm_clk_disable(struct pwm_chip *chip, struct pwm_device *pwm) { struct mtk_pwm_chip *pc = to_mtk_pwm_chip(chip); + if (!pc->soc->has_clks) + return; + clk_disable_unprepare(pc->clks[MTK_CLK_PWM1 + pwm->hwpwm]); clk_disable_unprepare(pc->clks[MTK_CLK_MAIN]); clk_disable_unprepare(pc->clks[MTK_CLK_TOP]); @@ -239,7 +246,7 @@ static int mtk_pwm_probe(struct platform_device *pdev) if (IS_ERR(pc->regs)) return PTR_ERR(pc->regs); - for (i = 0; i < data->num_pwms + 2; i++) { + for (i = 0; i < data->num_pwms + 2 && pc->soc->has_clks; i++) { pc->clks[i] = devm_clk_get(&pdev->dev, mtk_pwm_clk_name[i]); if (IS_ERR(pc->clks[i])) { dev_err(&pdev->dev, "clock: %s fail: %ld\n", @@ -274,22 +281,32 @@ static int mtk_pwm_remove(struct platform_device *pdev) static const struct mtk_pwm_platform_data mt2712_pwm_data = { .num_pwms = 8, .pwm45_fixup = false, + .has_clks = true, }; static const struct mtk_pwm_platform_data mt7622_pwm_data = { .num_pwms = 6, .pwm45_fixup = false, + .has_clks = true, }; static const struct mtk_pwm_platform_data mt7623_pwm_data = { .num_pwms = 5, .pwm45_fixup = true, + .has_clks = true, +}; + +static const struct mtk_pwm_platform_data mt7628_pwm_data = { + .num_pwms = 4, + .pwm45_fixup = true, + .has_clks = false, }; static const struct of_device_id mtk_pwm_of_match[] = { { .compatible = "mediatek,mt2712-pwm", .data = &mt2712_pwm_data }, { .compatible = "mediatek,mt7622-pwm", .data = &mt7622_pwm_data }, { .compatible = "mediatek,mt7623-pwm", .data = &mt7623_pwm_data }, + { .compatible = "mediatek,mt7628-pwm", .data = &mt7628_pwm_data }, { }, }; MODULE_DEVICE_TABLE(of, mtk_pwm_of_match); diff --git a/drivers/pwm/pwm-meson.c b/drivers/pwm/pwm-meson.c index 822860b4801a..c1ed641b3e26 100644 --- a/drivers/pwm/pwm-meson.c +++ b/drivers/pwm/pwm-meson.c @@ -458,7 +458,6 @@ static int meson_pwm_init_channels(struct meson_pwm *meson, struct meson_pwm_channel *channels) { struct device *dev = meson->chip.dev; - struct device_node *np = dev->of_node; struct clk_init_data init; unsigned int i; char name[255]; @@ -467,7 +466,7 @@ static int meson_pwm_init_channels(struct meson_pwm *meson, for (i = 0; i < meson->chip.npwm; i++) { struct meson_pwm_channel *channel = &channels[i]; - snprintf(name, sizeof(name), "%pOF#mux%u", np, i); + snprintf(name, sizeof(name), "%s#mux%u", dev_name(dev), i); init.name = name; init.ops = &clk_mux_ops; diff --git a/drivers/pwm/pwm-mxs.c b/drivers/pwm/pwm-mxs.c index a6017ad9926c..04c0f6b95c1a 100644 --- a/drivers/pwm/pwm-mxs.c +++ b/drivers/pwm/pwm-mxs.c @@ -1,12 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * Copyright 2012 Freescale Semiconductor, Inc. - * - * The code contained herein is licensed under the GNU General Public - * License. You may obtain a copy of the GNU General Public License - * Version 2 or later at the following locations: - * - * http://www.opensource.org/licenses/gpl-license.html - * http://www.gnu.org/copyleft/gpl.html */ #include <linux/clk.h> diff --git a/drivers/pwm/pwm-omap-dmtimer.c b/drivers/pwm/pwm-omap-dmtimer.c index 665da3c8fbce..f45798679e3c 100644 --- a/drivers/pwm/pwm-omap-dmtimer.c +++ b/drivers/pwm/pwm-omap-dmtimer.c @@ -264,8 +264,9 @@ static int pwm_omap_dmtimer_probe(struct platform_device *pdev) timer_pdata = dev_get_platdata(&timer_pdev->dev); if (!timer_pdata) { - dev_err(&pdev->dev, "dmtimer pdata structure NULL\n"); - ret = -EINVAL; + dev_dbg(&pdev->dev, + "dmtimer pdata structure NULL, deferring probe\n"); + ret = -EPROBE_DEFER; goto put; } diff --git a/drivers/pwm/pwm-stm32-lp.c b/drivers/pwm/pwm-stm32-lp.c index 7c13e2505080..0059b24cfdc3 100644 --- a/drivers/pwm/pwm-stm32-lp.c +++ b/drivers/pwm/pwm-stm32-lp.c @@ -217,10 +217,8 @@ static int stm32_pwm_lp_probe(struct platform_device *pdev) static int stm32_pwm_lp_remove(struct platform_device *pdev) { struct stm32_pwm_lp *priv = platform_get_drvdata(pdev); - unsigned int i; - for (i = 0; i < priv->chip.npwm; i++) - pwm_disable(&priv->chip.pwms[i]); + pwm_disable(&priv->chip.pwms[0]); return pwmchip_remove(&priv->chip); } diff --git a/drivers/pwm/pwm-tiehrpwm.c b/drivers/pwm/pwm-tiehrpwm.c index 4c22cb395040..f7b8a86fa5c5 100644 --- a/drivers/pwm/pwm-tiehrpwm.c +++ b/drivers/pwm/pwm-tiehrpwm.c @@ -33,10 +33,6 @@ #define TBCTL 0x00 #define TBPRD 0x0A -#define TBCTL_RUN_MASK (BIT(15) | BIT(14)) -#define TBCTL_STOP_NEXT 0 -#define TBCTL_STOP_ON_CYCLE BIT(14) -#define TBCTL_FREE_RUN (BIT(15) | BIT(14)) #define TBCTL_PRDLD_MASK BIT(3) #define TBCTL_PRDLD_SHDW 0 #define TBCTL_PRDLD_IMDT BIT(3) @@ -360,7 +356,7 @@ static int ehrpwm_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) /* Channels polarity can be configured from action qualifier module */ configure_polarity(pc, pwm->hwpwm); - /* Enable TBCLK before enabling PWM device */ + /* Enable TBCLK */ ret = clk_enable(pc->tbclk); if (ret) { dev_err(chip->dev, "Failed to enable TBCLK for %s: %d\n", @@ -368,9 +364,6 @@ static int ehrpwm_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) return ret; } - /* Enable time counter for free_run */ - ehrpwm_modify(pc->mmio_base, TBCTL, TBCTL_RUN_MASK, TBCTL_FREE_RUN); - return 0; } @@ -388,6 +381,8 @@ static void ehrpwm_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) aqcsfrc_mask = AQCSFRC_CSFA_MASK; } + /* Update shadow register first before modifying active register */ + ehrpwm_modify(pc->mmio_base, AQCSFRC, aqcsfrc_mask, aqcsfrc_val); /* * Changes to immediate action on Action Qualifier. This puts * Action Qualifier control on PWM output from next TBCLK @@ -400,9 +395,6 @@ static void ehrpwm_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) /* Disabling TBCLK on PWM disable */ clk_disable(pc->tbclk); - /* Stop Time base counter */ - ehrpwm_modify(pc->mmio_base, TBCTL, TBCTL_RUN_MASK, TBCTL_STOP_NEXT); - /* Disable clock on PWM disable */ pm_runtime_put_sync(chip->dev); } diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index c0b292be1b72..a70262cb7e56 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -82,6 +82,15 @@ config RESET_PISTACHIO help This enables the reset driver for ImgTec Pistachio SoCs. +config RESET_QCOM_AOSS + bool "Qcom AOSS Reset Driver" + depends on ARCH_QCOM || COMPILE_TEST + help + This enables the AOSS (always on subsystem) reset driver + for Qualcomm SDM845 SoCs. Say Y if you want to control + reset signals provided by AOSS for Modem, Venus, ADSP, + GPU, Camera, Wireless, Display subsystem. Otherwise, say N. + config RESET_SIMPLE bool "Simple Reset Controller Driver" if COMPILE_TEST default ARCH_SOCFPGA || ARCH_STM32 || ARCH_STRATIX10 || ARCH_SUNXI || ARCH_ZX || ARCH_ASPEED @@ -138,6 +147,16 @@ config RESET_UNIPHIER Say Y if you want to control reset signals provided by System Control block, Media I/O block, Peripheral Block. +config RESET_UNIPHIER_USB3 + tristate "USB3 reset driver for UniPhier SoCs" + depends on (ARCH_UNIPHIER || COMPILE_TEST) && OF + default ARCH_UNIPHIER + select RESET_SIMPLE + help + Support for the USB3 core reset on UniPhier SoCs. + Say Y if you want to control reset signals provided by + USB3 glue layer. + config RESET_ZYNQ bool "ZYNQ Reset Driver" if COMPILE_TEST default ARCH_ZYNQ diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index c1261dcfe9ad..0676b6b1976f 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile @@ -14,11 +14,13 @@ obj-$(CONFIG_RESET_LPC18XX) += reset-lpc18xx.o obj-$(CONFIG_RESET_MESON) += reset-meson.o obj-$(CONFIG_RESET_OXNAS) += reset-oxnas.o obj-$(CONFIG_RESET_PISTACHIO) += reset-pistachio.o +obj-$(CONFIG_RESET_QCOM_AOSS) += reset-qcom-aoss.o obj-$(CONFIG_RESET_SIMPLE) += reset-simple.o obj-$(CONFIG_RESET_STM32MP157) += reset-stm32mp1.o obj-$(CONFIG_RESET_SUNXI) += reset-sunxi.o obj-$(CONFIG_RESET_TI_SCI) += reset-ti-sci.o obj-$(CONFIG_RESET_TI_SYSCON) += reset-ti-syscon.o obj-$(CONFIG_RESET_UNIPHIER) += reset-uniphier.o +obj-$(CONFIG_RESET_UNIPHIER_USB3) += reset-uniphier-usb3.o obj-$(CONFIG_RESET_ZYNQ) += reset-zynq.o diff --git a/drivers/reset/reset-qcom-aoss.c b/drivers/reset/reset-qcom-aoss.c new file mode 100644 index 000000000000..36db96750450 --- /dev/null +++ b/drivers/reset/reset-qcom-aoss.c @@ -0,0 +1,133 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2018 The Linux Foundation. All rights reserved. + */ + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/reset-controller.h> +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/of_device.h> +#include <dt-bindings/reset/qcom,sdm845-aoss.h> + +struct qcom_aoss_reset_map { + unsigned int reg; +}; + +struct qcom_aoss_desc { + const struct qcom_aoss_reset_map *resets; + size_t num_resets; +}; + +struct qcom_aoss_reset_data { + struct reset_controller_dev rcdev; + void __iomem *base; + const struct qcom_aoss_desc *desc; +}; + +static const struct qcom_aoss_reset_map sdm845_aoss_resets[] = { + [AOSS_CC_MSS_RESTART] = {0x10000}, + [AOSS_CC_CAMSS_RESTART] = {0x11000}, + [AOSS_CC_VENUS_RESTART] = {0x12000}, + [AOSS_CC_GPU_RESTART] = {0x13000}, + [AOSS_CC_DISPSS_RESTART] = {0x14000}, + [AOSS_CC_WCSS_RESTART] = {0x20000}, + [AOSS_CC_LPASS_RESTART] = {0x30000}, +}; + +static const struct qcom_aoss_desc sdm845_aoss_desc = { + .resets = sdm845_aoss_resets, + .num_resets = ARRAY_SIZE(sdm845_aoss_resets), +}; + +static inline struct qcom_aoss_reset_data *to_qcom_aoss_reset_data( + struct reset_controller_dev *rcdev) +{ + return container_of(rcdev, struct qcom_aoss_reset_data, rcdev); +} + +static int qcom_aoss_control_assert(struct reset_controller_dev *rcdev, + unsigned long idx) +{ + struct qcom_aoss_reset_data *data = to_qcom_aoss_reset_data(rcdev); + const struct qcom_aoss_reset_map *map = &data->desc->resets[idx]; + + writel(1, data->base + map->reg); + /* Wait 6 32kHz sleep cycles for reset */ + usleep_range(200, 300); + return 0; +} + +static int qcom_aoss_control_deassert(struct reset_controller_dev *rcdev, + unsigned long idx) +{ + struct qcom_aoss_reset_data *data = to_qcom_aoss_reset_data(rcdev); + const struct qcom_aoss_reset_map *map = &data->desc->resets[idx]; + + writel(0, data->base + map->reg); + /* Wait 6 32kHz sleep cycles for reset */ + usleep_range(200, 300); + return 0; +} + +static int qcom_aoss_control_reset(struct reset_controller_dev *rcdev, + unsigned long idx) +{ + qcom_aoss_control_assert(rcdev, idx); + + return qcom_aoss_control_deassert(rcdev, idx); +} + +static const struct reset_control_ops qcom_aoss_reset_ops = { + .reset = qcom_aoss_control_reset, + .assert = qcom_aoss_control_assert, + .deassert = qcom_aoss_control_deassert, +}; + +static int qcom_aoss_reset_probe(struct platform_device *pdev) +{ + struct qcom_aoss_reset_data *data; + struct device *dev = &pdev->dev; + const struct qcom_aoss_desc *desc; + struct resource *res; + + desc = of_device_get_match_data(dev); + if (!desc) + return -EINVAL; + + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->desc = desc; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + data->base = devm_ioremap_resource(dev, res); + if (IS_ERR(data->base)) + return PTR_ERR(data->base); + + data->rcdev.owner = THIS_MODULE; + data->rcdev.ops = &qcom_aoss_reset_ops; + data->rcdev.nr_resets = desc->num_resets; + data->rcdev.of_node = dev->of_node; + + return devm_reset_controller_register(dev, &data->rcdev); +} + +static const struct of_device_id qcom_aoss_reset_of_match[] = { + { .compatible = "qcom,sdm845-aoss-cc", .data = &sdm845_aoss_desc }, + {} +}; + +static struct platform_driver qcom_aoss_reset_driver = { + .probe = qcom_aoss_reset_probe, + .driver = { + .name = "qcom_aoss_reset", + .of_match_table = qcom_aoss_reset_of_match, + }, +}; + +builtin_platform_driver(qcom_aoss_reset_driver); + +MODULE_DESCRIPTION("Qualcomm AOSS Reset Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/reset/reset-simple.c b/drivers/reset/reset-simple.c index f7ce8910a392..a91107fc9e27 100644 --- a/drivers/reset/reset-simple.c +++ b/drivers/reset/reset-simple.c @@ -87,6 +87,7 @@ const struct reset_control_ops reset_simple_ops = { .deassert = reset_simple_deassert, .status = reset_simple_status, }; +EXPORT_SYMBOL_GPL(reset_simple_ops); /** * struct reset_simple_devdata - simple reset controller properties diff --git a/drivers/reset/reset-uniphier-usb3.c b/drivers/reset/reset-uniphier-usb3.c new file mode 100644 index 000000000000..ffa1b19b594d --- /dev/null +++ b/drivers/reset/reset-uniphier-usb3.c @@ -0,0 +1,171 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// reset-uniphier-usb3.c - USB3 reset driver for UniPhier +// Copyright 2018 Socionext Inc. +// Author: Kunihiko Hayashi <hayashi.kunihiko@socionext.com> + +#include <linux/clk.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/reset.h> + +#include "reset-simple.h" + +#define MAX_CLKS 2 +#define MAX_RSTS 2 + +struct uniphier_usb3_reset_soc_data { + int nclks; + const char * const *clock_names; + int nrsts; + const char * const *reset_names; +}; + +struct uniphier_usb3_reset_priv { + struct clk_bulk_data clk[MAX_CLKS]; + struct reset_control *rst[MAX_RSTS]; + struct reset_simple_data rdata; + const struct uniphier_usb3_reset_soc_data *data; +}; + +static int uniphier_usb3_reset_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct uniphier_usb3_reset_priv *priv; + struct resource *res; + resource_size_t size; + const char *name; + int i, ret, nr; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->data = of_device_get_match_data(dev); + if (WARN_ON(!priv->data || priv->data->nclks > MAX_CLKS || + priv->data->nrsts > MAX_RSTS)) + return -EINVAL; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + size = resource_size(res); + priv->rdata.membase = devm_ioremap_resource(dev, res); + if (IS_ERR(priv->rdata.membase)) + return PTR_ERR(priv->rdata.membase); + + for (i = 0; i < priv->data->nclks; i++) + priv->clk[i].id = priv->data->clock_names[i]; + ret = devm_clk_bulk_get(dev, priv->data->nclks, priv->clk); + if (ret) + return ret; + + for (i = 0; i < priv->data->nrsts; i++) { + name = priv->data->reset_names[i]; + priv->rst[i] = devm_reset_control_get_shared(dev, name); + if (IS_ERR(priv->rst[i])) + return PTR_ERR(priv->rst[i]); + } + + ret = clk_bulk_prepare_enable(priv->data->nclks, priv->clk); + if (ret) + return ret; + + for (nr = 0; nr < priv->data->nrsts; nr++) { + ret = reset_control_deassert(priv->rst[nr]); + if (ret) + goto out_rst_assert; + } + + spin_lock_init(&priv->rdata.lock); + priv->rdata.rcdev.owner = THIS_MODULE; + priv->rdata.rcdev.nr_resets = size * BITS_PER_BYTE; + priv->rdata.rcdev.ops = &reset_simple_ops; + priv->rdata.rcdev.of_node = dev->of_node; + priv->rdata.active_low = true; + + platform_set_drvdata(pdev, priv); + + ret = devm_reset_controller_register(dev, &priv->rdata.rcdev); + if (ret) + goto out_rst_assert; + + return 0; + +out_rst_assert: + while (nr--) + reset_control_assert(priv->rst[nr]); + + clk_bulk_disable_unprepare(priv->data->nclks, priv->clk); + + return ret; +} + +static int uniphier_usb3_reset_remove(struct platform_device *pdev) +{ + struct uniphier_usb3_reset_priv *priv = platform_get_drvdata(pdev); + int i; + + for (i = 0; i < priv->data->nrsts; i++) + reset_control_assert(priv->rst[i]); + + clk_bulk_disable_unprepare(priv->data->nclks, priv->clk); + + return 0; +} + +static const char * const uniphier_pro4_clock_reset_names[] = { + "gio", "link", +}; + +static const struct uniphier_usb3_reset_soc_data uniphier_pro4_data = { + .nclks = ARRAY_SIZE(uniphier_pro4_clock_reset_names), + .clock_names = uniphier_pro4_clock_reset_names, + .nrsts = ARRAY_SIZE(uniphier_pro4_clock_reset_names), + .reset_names = uniphier_pro4_clock_reset_names, +}; + +static const char * const uniphier_pxs2_clock_reset_names[] = { + "link", +}; + +static const struct uniphier_usb3_reset_soc_data uniphier_pxs2_data = { + .nclks = ARRAY_SIZE(uniphier_pxs2_clock_reset_names), + .clock_names = uniphier_pxs2_clock_reset_names, + .nrsts = ARRAY_SIZE(uniphier_pxs2_clock_reset_names), + .reset_names = uniphier_pxs2_clock_reset_names, +}; + +static const struct of_device_id uniphier_usb3_reset_match[] = { + { + .compatible = "socionext,uniphier-pro4-usb3-reset", + .data = &uniphier_pro4_data, + }, + { + .compatible = "socionext,uniphier-pxs2-usb3-reset", + .data = &uniphier_pxs2_data, + }, + { + .compatible = "socionext,uniphier-ld20-usb3-reset", + .data = &uniphier_pxs2_data, + }, + { + .compatible = "socionext,uniphier-pxs3-usb3-reset", + .data = &uniphier_pxs2_data, + }, + { /* Sentinel */ } +}; +MODULE_DEVICE_TABLE(of, uniphier_usb3_reset_match); + +static struct platform_driver uniphier_usb3_reset_driver = { + .probe = uniphier_usb3_reset_probe, + .remove = uniphier_usb3_reset_remove, + .driver = { + .name = "uniphier-usb3-reset", + .of_match_table = uniphier_usb3_reset_match, + }, +}; +module_platform_driver(uniphier_usb3_reset_driver); + +MODULE_AUTHOR("Kunihiko Hayashi <hayashi.kunihiko@socionext.com>"); +MODULE_DESCRIPTION("UniPhier USB3 Reset Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/reset/reset-uniphier.c b/drivers/reset/reset-uniphier.c index e9030ff1bf2f..5605745663ae 100644 --- a/drivers/reset/reset-uniphier.c +++ b/drivers/reset/reset-uniphier.c @@ -202,6 +202,12 @@ static const struct uniphier_reset_data uniphier_pro5_sd_reset_data[] = { #define UNIPHIER_PERI_RESET_FI2C(id, ch) \ UNIPHIER_RESETX((id), 0x114, 24 + (ch)) +#define UNIPHIER_PERI_RESET_SCSSI(id) \ + UNIPHIER_RESETX((id), 0x110, 17) + +#define UNIPHIER_PERI_RESET_MCSSI(id) \ + UNIPHIER_RESETX((id), 0x114, 14) + static const struct uniphier_reset_data uniphier_ld4_peri_reset_data[] = { UNIPHIER_PERI_RESET_UART(0, 0), UNIPHIER_PERI_RESET_UART(1, 1), @@ -212,6 +218,7 @@ static const struct uniphier_reset_data uniphier_ld4_peri_reset_data[] = { UNIPHIER_PERI_RESET_I2C(6, 2), UNIPHIER_PERI_RESET_I2C(7, 3), UNIPHIER_PERI_RESET_I2C(8, 4), + UNIPHIER_PERI_RESET_SCSSI(11), UNIPHIER_RESET_END, }; @@ -227,6 +234,8 @@ static const struct uniphier_reset_data uniphier_pro4_peri_reset_data[] = { UNIPHIER_PERI_RESET_FI2C(8, 4), UNIPHIER_PERI_RESET_FI2C(9, 5), UNIPHIER_PERI_RESET_FI2C(10, 6), + UNIPHIER_PERI_RESET_SCSSI(11), + UNIPHIER_PERI_RESET_MCSSI(12), UNIPHIER_RESET_END, }; diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index bf27fc4d1335..ec891bc7d10a 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -34,6 +34,7 @@ #include <linux/crypto.h> #include <linux/mod_devicetable.h> #include <linux/debugfs.h> +#include <linux/ctype.h> #include "ap_bus.h" #include "ap_debug.h" @@ -43,19 +44,34 @@ */ int ap_domain_index = -1; /* Adjunct Processor Domain Index */ static DEFINE_SPINLOCK(ap_domain_lock); -module_param_named(domain, ap_domain_index, int, S_IRUSR|S_IRGRP); +module_param_named(domain, ap_domain_index, int, 0440); MODULE_PARM_DESC(domain, "domain index for ap devices"); EXPORT_SYMBOL(ap_domain_index); -static int ap_thread_flag = 0; -module_param_named(poll_thread, ap_thread_flag, int, S_IRUSR|S_IRGRP); +static int ap_thread_flag; +module_param_named(poll_thread, ap_thread_flag, int, 0440); MODULE_PARM_DESC(poll_thread, "Turn on/off poll thread, default is 0 (off)."); +static char *apm_str; +module_param_named(apmask, apm_str, charp, 0440); +MODULE_PARM_DESC(apmask, "AP bus adapter mask."); + +static char *aqm_str; +module_param_named(aqmask, aqm_str, charp, 0440); +MODULE_PARM_DESC(aqmask, "AP bus domain mask."); + static struct device *ap_root_device; DEFINE_SPINLOCK(ap_list_lock); LIST_HEAD(ap_card_list); +/* Default permissions (card and domain masking) */ +static struct ap_perms { + DECLARE_BITMAP(apm, AP_DEVICES); + DECLARE_BITMAP(aqm, AP_DOMAINS); +} ap_perms; +static DEFINE_MUTEX(ap_perms_mutex); + static struct ap_config_info *ap_configuration; static bool initialised; @@ -78,22 +94,26 @@ static DECLARE_WORK(ap_scan_work, ap_scan_bus); static void ap_tasklet_fn(unsigned long); static DECLARE_TASKLET(ap_tasklet, ap_tasklet_fn, 0); static DECLARE_WAIT_QUEUE_HEAD(ap_poll_wait); -static struct task_struct *ap_poll_kthread = NULL; +static struct task_struct *ap_poll_kthread; static DEFINE_MUTEX(ap_poll_thread_mutex); static DEFINE_SPINLOCK(ap_poll_timer_lock); static struct hrtimer ap_poll_timer; -/* In LPAR poll with 4kHz frequency. Poll every 250000 nanoseconds. - * If z/VM change to 1500000 nanoseconds to adjust to z/VM polling.*/ +/* + * In LPAR poll with 4kHz frequency. Poll every 250000 nanoseconds. + * If z/VM change to 1500000 nanoseconds to adjust to z/VM polling. + */ static unsigned long long poll_timeout = 250000; /* Suspend flag */ static int ap_suspend_flag; /* Maximum domain id */ static int ap_max_domain_id; -/* Flag to check if domain was set through module parameter domain=. This is +/* + * Flag to check if domain was set through module parameter domain=. This is * important when supsend and resume is done in a z/VM environment where the - * domain might change. */ -static int user_set_domain = 0; + * domain might change. + */ +static int user_set_domain; static struct bus_type ap_bus_type; /* Adapter interrupt definitions */ @@ -531,7 +551,7 @@ static int ap_bus_match(struct device *dev, struct device_driver *drv) * It sets up a single environment variable DEV_TYPE which contains the * hardware device type. */ -static int ap_uevent (struct device *dev, struct kobj_uevent_env *env) +static int ap_uevent(struct device *dev, struct kobj_uevent_env *env) { struct ap_device *ap_dev = to_ap_dev(dev); int retval = 0; @@ -570,7 +590,7 @@ static int ap_dev_resume(struct device *dev) static void ap_bus_suspend(void) { - AP_DBF(DBF_DEBUG, "ap_bus_suspend running\n"); + AP_DBF(DBF_DEBUG, "%s running\n", __func__); ap_suspend_flag = 1; /* @@ -607,7 +627,7 @@ static void ap_bus_resume(void) { int rc; - AP_DBF(DBF_DEBUG, "ap_bus_resume running\n"); + AP_DBF(DBF_DEBUG, "%s running\n", __func__); /* remove all queue devices */ bus_for_each_dev(&ap_bus_type, NULL, NULL, @@ -666,11 +686,97 @@ static struct bus_type ap_bus_type = { .pm = &ap_bus_pm_ops, }; +static int __ap_revise_reserved(struct device *dev, void *dummy) +{ + int rc, card, queue, devres, drvres; + + if (is_queue_dev(dev)) { + card = AP_QID_CARD(to_ap_queue(dev)->qid); + queue = AP_QID_QUEUE(to_ap_queue(dev)->qid); + mutex_lock(&ap_perms_mutex); + devres = test_bit_inv(card, ap_perms.apm) + && test_bit_inv(queue, ap_perms.aqm); + mutex_unlock(&ap_perms_mutex); + drvres = to_ap_drv(dev->driver)->flags + & AP_DRIVER_FLAG_DEFAULT; + if (!!devres != !!drvres) { + AP_DBF(DBF_DEBUG, "reprobing queue=%02x.%04x\n", + card, queue); + rc = device_reprobe(dev); + } + } + + return 0; +} + +static void ap_bus_revise_bindings(void) +{ + bus_for_each_dev(&ap_bus_type, NULL, NULL, __ap_revise_reserved); +} + +int ap_owned_by_def_drv(int card, int queue) +{ + int rc = 0; + + if (card < 0 || card >= AP_DEVICES || queue < 0 || queue >= AP_DOMAINS) + return -EINVAL; + + mutex_lock(&ap_perms_mutex); + + if (test_bit_inv(card, ap_perms.apm) + && test_bit_inv(queue, ap_perms.aqm)) + rc = 1; + + mutex_unlock(&ap_perms_mutex); + + return rc; +} +EXPORT_SYMBOL(ap_owned_by_def_drv); + +int ap_apqn_in_matrix_owned_by_def_drv(unsigned long *apm, + unsigned long *aqm) +{ + int card, queue, rc = 0; + + mutex_lock(&ap_perms_mutex); + + for (card = 0; !rc && card < AP_DEVICES; card++) + if (test_bit_inv(card, apm) && + test_bit_inv(card, ap_perms.apm)) + for (queue = 0; !rc && queue < AP_DOMAINS; queue++) + if (test_bit_inv(queue, aqm) && + test_bit_inv(queue, ap_perms.aqm)) + rc = 1; + + mutex_unlock(&ap_perms_mutex); + + return rc; +} +EXPORT_SYMBOL(ap_apqn_in_matrix_owned_by_def_drv); + static int ap_device_probe(struct device *dev) { struct ap_device *ap_dev = to_ap_dev(dev); struct ap_driver *ap_drv = to_ap_drv(dev->driver); - int rc; + int card, queue, devres, drvres, rc; + + if (is_queue_dev(dev)) { + /* + * If the apqn is marked as reserved/used by ap bus and + * default drivers, only probe with drivers with the default + * flag set. If it is not marked, only probe with drivers + * with the default flag not set. + */ + card = AP_QID_CARD(to_ap_queue(dev)->qid); + queue = AP_QID_QUEUE(to_ap_queue(dev)->qid); + mutex_lock(&ap_perms_mutex); + devres = test_bit_inv(card, ap_perms.apm) + && test_bit_inv(queue, ap_perms.aqm); + mutex_unlock(&ap_perms_mutex); + drvres = ap_drv->flags & AP_DRIVER_FLAG_DEFAULT; + if (!!devres != !!drvres) + return -ENODEV; + } /* Add queue/card to list of active queues/cards */ spin_lock_bh(&ap_list_lock); @@ -751,8 +857,163 @@ void ap_bus_force_rescan(void) EXPORT_SYMBOL(ap_bus_force_rescan); /* + * hex2bitmap() - parse hex mask string and set bitmap. + * Valid strings are "0x012345678" with at least one valid hex number. + * Rest of the bitmap to the right is padded with 0. No spaces allowed + * within the string, the leading 0x may be omitted. + * Returns the bitmask with exactly the bits set as given by the hex + * string (both in big endian order). + */ +static int hex2bitmap(const char *str, unsigned long *bitmap, int bits) +{ + int i, n, b; + + /* bits needs to be a multiple of 8 */ + if (bits & 0x07) + return -EINVAL; + + memset(bitmap, 0, bits / 8); + + if (str[0] == '0' && str[1] == 'x') + str++; + if (*str == 'x') + str++; + + for (i = 0; isxdigit(*str) && i < bits; str++) { + b = hex_to_bin(*str); + for (n = 0; n < 4; n++) + if (b & (0x08 >> n)) + set_bit_inv(i + n, bitmap); + i += 4; + } + + if (*str == '\n') + str++; + if (*str) + return -EINVAL; + return 0; +} + +/* + * str2clrsetmasks() - parse bitmask argument and set the clear and + * the set bitmap mask. A concatenation (done with ',') of these terms + * is recognized: + * +<bitnr>[-<bitnr>] or -<bitnr>[-<bitnr>] + * <bitnr> may be any valid number (hex, decimal or octal) in the range + * 0...bits-1; the leading + or - is required. Here are some examples: + * +0-15,+32,-128,-0xFF + * -0-255,+1-16,+0x128 + * +1,+2,+3,+4,-5,-7-10 + * Returns a clear and a set bitmask. Every positive value in the string + * results in a bit set in the set mask and every negative value in the + * string results in a bit SET in the clear mask. As a bit may be touched + * more than once, the last 'operation' wins: +0-255,-128 = all but bit + * 128 set in the set mask, only bit 128 set in the clear mask. + */ +static int str2clrsetmasks(const char *str, + unsigned long *clrmap, + unsigned long *setmap, + int bits) +{ + int a, i, z; + char *np, sign; + + /* bits needs to be a multiple of 8 */ + if (bits & 0x07) + return -EINVAL; + + memset(clrmap, 0, bits / 8); + memset(setmap, 0, bits / 8); + + while (*str) { + sign = *str++; + if (sign != '+' && sign != '-') + return -EINVAL; + a = z = simple_strtoul(str, &np, 0); + if (str == np || a >= bits) + return -EINVAL; + str = np; + if (*str == '-') { + z = simple_strtoul(++str, &np, 0); + if (str == np || a > z || z >= bits) + return -EINVAL; + str = np; + } + for (i = a; i <= z; i++) + if (sign == '+') { + set_bit_inv(i, setmap); + clear_bit_inv(i, clrmap); + } else { + clear_bit_inv(i, setmap); + set_bit_inv(i, clrmap); + } + while (*str == ',' || *str == '\n') + str++; + } + + return 0; +} + +/* + * process_mask_arg() - parse a bitmap string and clear/set the + * bits in the bitmap accordingly. The string may be given as + * absolute value, a hex string like 0x1F2E3D4C5B6A" simple over- + * writing the current content of the bitmap. Or as relative string + * like "+1-16,-32,-0x40,+128" where only single bits or ranges of + * bits are cleared or set. Distinction is done based on the very + * first character which may be '+' or '-' for the relative string + * and othewise assume to be an absolute value string. If parsing fails + * a negative errno value is returned. All arguments and bitmaps are + * big endian order. + */ +static int process_mask_arg(const char *str, + unsigned long *bitmap, int bits, + struct mutex *lock) +{ + int i; + + /* bits needs to be a multiple of 8 */ + if (bits & 0x07) + return -EINVAL; + + if (*str == '+' || *str == '-') { + DECLARE_BITMAP(clrm, bits); + DECLARE_BITMAP(setm, bits); + + i = str2clrsetmasks(str, clrm, setm, bits); + if (i) + return i; + if (mutex_lock_interruptible(lock)) + return -ERESTARTSYS; + for (i = 0; i < bits; i++) { + if (test_bit_inv(i, clrm)) + clear_bit_inv(i, bitmap); + if (test_bit_inv(i, setm)) + set_bit_inv(i, bitmap); + } + } else { + DECLARE_BITMAP(setm, bits); + + i = hex2bitmap(str, setm, bits); + if (i) + return i; + if (mutex_lock_interruptible(lock)) + return -ERESTARTSYS; + for (i = 0; i < bits; i++) + if (test_bit_inv(i, setm)) + set_bit_inv(i, bitmap); + else + clear_bit_inv(i, bitmap); + } + mutex_unlock(lock); + + return 0; +} + +/* * AP bus attributes. */ + static ssize_t ap_domain_show(struct bus_type *bus, char *buf) { return snprintf(buf, PAGE_SIZE, "%d\n", ap_domain_index); @@ -764,7 +1025,8 @@ static ssize_t ap_domain_store(struct bus_type *bus, int domain; if (sscanf(buf, "%i\n", &domain) != 1 || - domain < 0 || domain > ap_max_domain_id) + domain < 0 || domain > ap_max_domain_id || + !test_bit_inv(domain, ap_perms.aqm)) return -EINVAL; spin_lock_bh(&ap_domain_lock); ap_domain_index = domain; @@ -775,7 +1037,7 @@ static ssize_t ap_domain_store(struct bus_type *bus, return count; } -static BUS_ATTR(ap_domain, 0644, ap_domain_show, ap_domain_store); +static BUS_ATTR_RW(ap_domain); static ssize_t ap_control_domain_mask_show(struct bus_type *bus, char *buf) { @@ -790,8 +1052,7 @@ static ssize_t ap_control_domain_mask_show(struct bus_type *bus, char *buf) ap_configuration->adm[6], ap_configuration->adm[7]); } -static BUS_ATTR(ap_control_domain_mask, 0444, - ap_control_domain_mask_show, NULL); +static BUS_ATTR_RO(ap_control_domain_mask); static ssize_t ap_usage_domain_mask_show(struct bus_type *bus, char *buf) { @@ -806,13 +1067,7 @@ static ssize_t ap_usage_domain_mask_show(struct bus_type *bus, char *buf) ap_configuration->aqm[6], ap_configuration->aqm[7]); } -static BUS_ATTR(ap_usage_domain_mask, 0444, - ap_usage_domain_mask_show, NULL); - -static ssize_t ap_config_time_show(struct bus_type *bus, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%d\n", ap_config_time); -} +static BUS_ATTR_RO(ap_usage_domain_mask); static ssize_t ap_interrupts_show(struct bus_type *bus, char *buf) { @@ -820,10 +1075,15 @@ static ssize_t ap_interrupts_show(struct bus_type *bus, char *buf) ap_using_interrupts() ? 1 : 0); } -static BUS_ATTR(ap_interrupts, 0444, ap_interrupts_show, NULL); +static BUS_ATTR_RO(ap_interrupts); + +static ssize_t config_time_show(struct bus_type *bus, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", ap_config_time); +} -static ssize_t ap_config_time_store(struct bus_type *bus, - const char *buf, size_t count) +static ssize_t config_time_store(struct bus_type *bus, + const char *buf, size_t count) { int time; @@ -834,15 +1094,15 @@ static ssize_t ap_config_time_store(struct bus_type *bus, return count; } -static BUS_ATTR(config_time, 0644, ap_config_time_show, ap_config_time_store); +static BUS_ATTR_RW(config_time); -static ssize_t ap_poll_thread_show(struct bus_type *bus, char *buf) +static ssize_t poll_thread_show(struct bus_type *bus, char *buf) { return snprintf(buf, PAGE_SIZE, "%d\n", ap_poll_kthread ? 1 : 0); } -static ssize_t ap_poll_thread_store(struct bus_type *bus, - const char *buf, size_t count) +static ssize_t poll_thread_store(struct bus_type *bus, + const char *buf, size_t count) { int flag, rc; @@ -857,7 +1117,7 @@ static ssize_t ap_poll_thread_store(struct bus_type *bus, return count; } -static BUS_ATTR(poll_thread, 0644, ap_poll_thread_show, ap_poll_thread_store); +static BUS_ATTR_RW(poll_thread); static ssize_t poll_timeout_show(struct bus_type *bus, char *buf) { @@ -886,7 +1146,7 @@ static ssize_t poll_timeout_store(struct bus_type *bus, const char *buf, return count; } -static BUS_ATTR(poll_timeout, 0644, poll_timeout_show, poll_timeout_store); +static BUS_ATTR_RW(poll_timeout); static ssize_t ap_max_domain_id_show(struct bus_type *bus, char *buf) { @@ -899,7 +1159,69 @@ static ssize_t ap_max_domain_id_show(struct bus_type *bus, char *buf) return snprintf(buf, PAGE_SIZE, "%d\n", max_domain_id); } -static BUS_ATTR(ap_max_domain_id, 0444, ap_max_domain_id_show, NULL); +static BUS_ATTR_RO(ap_max_domain_id); + +static ssize_t apmask_show(struct bus_type *bus, char *buf) +{ + int rc; + + if (mutex_lock_interruptible(&ap_perms_mutex)) + return -ERESTARTSYS; + rc = snprintf(buf, PAGE_SIZE, + "0x%016lx%016lx%016lx%016lx\n", + ap_perms.apm[0], ap_perms.apm[1], + ap_perms.apm[2], ap_perms.apm[3]); + mutex_unlock(&ap_perms_mutex); + + return rc; +} + +static ssize_t apmask_store(struct bus_type *bus, const char *buf, + size_t count) +{ + int rc; + + rc = process_mask_arg(buf, ap_perms.apm, AP_DEVICES, &ap_perms_mutex); + if (rc) + return rc; + + ap_bus_revise_bindings(); + + return count; +} + +static BUS_ATTR_RW(apmask); + +static ssize_t aqmask_show(struct bus_type *bus, char *buf) +{ + int rc; + + if (mutex_lock_interruptible(&ap_perms_mutex)) + return -ERESTARTSYS; + rc = snprintf(buf, PAGE_SIZE, + "0x%016lx%016lx%016lx%016lx\n", + ap_perms.aqm[0], ap_perms.aqm[1], + ap_perms.aqm[2], ap_perms.aqm[3]); + mutex_unlock(&ap_perms_mutex); + + return rc; +} + +static ssize_t aqmask_store(struct bus_type *bus, const char *buf, + size_t count) +{ + int rc; + + rc = process_mask_arg(buf, ap_perms.aqm, AP_DOMAINS, &ap_perms_mutex); + if (rc) + return rc; + + ap_bus_revise_bindings(); + + return count; +} + +static BUS_ATTR_RW(aqmask); static struct bus_attribute *const ap_bus_attrs[] = { &bus_attr_ap_domain, @@ -910,6 +1232,8 @@ static struct bus_attribute *const ap_bus_attrs[] = { &bus_attr_ap_interrupts, &bus_attr_poll_timeout, &bus_attr_ap_max_domain_id, + &bus_attr_apmask, + &bus_attr_aqmask, NULL, }; @@ -938,7 +1262,8 @@ static int ap_select_domain(void) best_domain = -1; max_count = 0; for (i = 0; i < AP_DOMAINS; i++) { - if (!ap_test_config_domain(i)) + if (!ap_test_config_domain(i) || + !test_bit_inv(i, ap_perms.aqm)) continue; count = 0; for (j = 0; j < AP_DEVICES; j++) { @@ -956,7 +1281,7 @@ static int ap_select_domain(void) best_domain = i; } } - if (best_domain >= 0){ + if (best_domain >= 0) { ap_domain_index = best_domain; AP_DBF(DBF_DEBUG, "new ap_domain_index=%d\n", ap_domain_index); spin_unlock_bh(&ap_domain_lock); @@ -1038,7 +1363,7 @@ static void ap_scan_bus(struct work_struct *unused) unsigned int func = 0; int rc, id, dom, borked, domains, defdomdevs = 0; - AP_DBF(DBF_DEBUG, "ap_scan_bus running\n"); + AP_DBF(DBF_DEBUG, "%s running\n", __func__); ap_query_configuration(ap_configuration); if (ap_select_domain() != 0) @@ -1163,7 +1488,8 @@ static void ap_scan_bus(struct work_struct *unused) } /* end device loop */ if (defdomdevs < 1) - AP_DBF(DBF_INFO, "no queue device with default domain %d available\n", + AP_DBF(DBF_INFO, + "no queue device with default domain %d available\n", ap_domain_index); out: @@ -1187,6 +1513,27 @@ static int __init ap_debug_init(void) return 0; } +static void __init ap_perms_init(void) +{ + /* all resources useable if no kernel parameter string given */ + memset(&ap_perms.apm, 0xFF, sizeof(ap_perms.apm)); + memset(&ap_perms.aqm, 0xFF, sizeof(ap_perms.aqm)); + + /* apm kernel parameter string */ + if (apm_str) { + memset(&ap_perms.apm, 0, sizeof(ap_perms.apm)); + process_mask_arg(apm_str, ap_perms.apm, AP_DEVICES, + &ap_perms_mutex); + } + + /* aqm kernel parameter string */ + if (aqm_str) { + memset(&ap_perms.aqm, 0, sizeof(ap_perms.aqm)); + process_mask_arg(aqm_str, ap_perms.aqm, AP_DOMAINS, + &ap_perms_mutex); + } +} + /** * ap_module_init(): The module initialization code. * @@ -1201,11 +1548,14 @@ static int __init ap_module_init(void) if (rc) return rc; - if (ap_instructions_available() != 0) { + if (!ap_instructions_available()) { pr_warn("The hardware system does not support AP instructions\n"); return -ENODEV; } + /* set up the AP permissions (ap and aq masks) */ + ap_perms_init(); + /* Get AP configuration data if available */ ap_init_configuration(); @@ -1214,7 +1564,9 @@ static int __init ap_module_init(void) ap_max_domain_id ? ap_max_domain_id : AP_DOMAINS - 1; else max_domain_id = 15; - if (ap_domain_index < -1 || ap_domain_index > max_domain_id) { + if (ap_domain_index < -1 || ap_domain_index > max_domain_id || + (ap_domain_index >= 0 && + !test_bit_inv(ap_domain_index, ap_perms.aqm))) { pr_warn("%d is not a valid cryptographic domain\n", ap_domain_index); ap_domain_index = -1; diff --git a/drivers/s390/crypto/ap_bus.h b/drivers/s390/crypto/ap_bus.h index 936541937e15..5246cd8c16a6 100644 --- a/drivers/s390/crypto/ap_bus.h +++ b/drivers/s390/crypto/ap_bus.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * Copyright IBM Corp. 2006, 2012 * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com> @@ -117,9 +117,18 @@ enum ap_wait { struct ap_device; struct ap_message; +/* + * The ap driver struct includes a flags field which holds some info for + * the ap bus about the driver. Currently only one flag is supported and + * used: The DEFAULT flag marks an ap driver as a default driver which is + * used together with the apmask and aqmask whitelisting of the ap bus. + */ +#define AP_DRIVER_FLAG_DEFAULT 0x0001 + struct ap_driver { struct device_driver driver; struct ap_device_id *ids; + unsigned int flags; int (*probe)(struct ap_device *); void (*remove)(struct ap_device *); @@ -167,7 +176,7 @@ struct ap_queue { int pendingq_count; /* # requests on pendingq list. */ int requestq_count; /* # requests on requestq list. */ int total_request_count; /* # requests ever for this AP device.*/ - int request_timeout; /* Request timout in jiffies. */ + int request_timeout; /* Request timeout in jiffies. */ struct timer_list timeout; /* Timer for request timeouts. */ struct list_head pendingq; /* List of message sent to AP queue. */ struct list_head requestq; /* List of message yet to be sent. */ @@ -248,4 +257,27 @@ void ap_queue_resume(struct ap_device *ap_dev); struct ap_card *ap_card_create(int id, int queue_depth, int raw_device_type, int comp_device_type, unsigned int functions); +/* + * check APQN for owned/reserved by ap bus and default driver(s). + * Checks if this APQN is or will be in use by the ap bus + * and the default set of drivers. + * If yes, returns 1, if not returns 0. On error a negative + * errno value is returned. + */ +int ap_owned_by_def_drv(int card, int queue); + +/* + * check 'matrix' of APQNs for owned/reserved by ap bus and + * default driver(s). + * Checks if there is at least one APQN in the given 'matrix' + * marked as owned/reserved by the ap bus and default driver(s). + * If such an APQN is found the return value is 1, otherwise + * 0 is returned. On error a negative errno value is returned. + * The parameter apm is a bitmask which should be declared + * as DECLARE_BITMAP(apm, AP_DEVICES), the aqm parameter is + * similar, should be declared as DECLARE_BITMAP(aqm, AP_DOMAINS). + */ +int ap_apqn_in_matrix_owned_by_def_drv(unsigned long *apm, + unsigned long *aqm); + #endif /* _AP_BUS_H_ */ diff --git a/drivers/s390/crypto/ap_card.c b/drivers/s390/crypto/ap_card.c index c13e43292cb7..63b4cc6cd7e5 100644 --- a/drivers/s390/crypto/ap_card.c +++ b/drivers/s390/crypto/ap_card.c @@ -18,35 +18,35 @@ /* * AP card related attributes. */ -static ssize_t ap_hwtype_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t hwtype_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct ap_card *ac = to_ap_card(dev); return snprintf(buf, PAGE_SIZE, "%d\n", ac->ap_dev.device_type); } -static DEVICE_ATTR(hwtype, 0444, ap_hwtype_show, NULL); +static DEVICE_ATTR_RO(hwtype); -static ssize_t ap_raw_hwtype_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t raw_hwtype_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct ap_card *ac = to_ap_card(dev); return snprintf(buf, PAGE_SIZE, "%d\n", ac->raw_hwtype); } -static DEVICE_ATTR(raw_hwtype, 0444, ap_raw_hwtype_show, NULL); +static DEVICE_ATTR_RO(raw_hwtype); -static ssize_t ap_depth_show(struct device *dev, struct device_attribute *attr, - char *buf) +static ssize_t depth_show(struct device *dev, struct device_attribute *attr, + char *buf) { struct ap_card *ac = to_ap_card(dev); return snprintf(buf, PAGE_SIZE, "%d\n", ac->queue_depth); } -static DEVICE_ATTR(depth, 0444, ap_depth_show, NULL); +static DEVICE_ATTR_RO(depth); static ssize_t ap_functions_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -58,9 +58,9 @@ static ssize_t ap_functions_show(struct device *dev, static DEVICE_ATTR_RO(ap_functions); -static ssize_t ap_req_count_show(struct device *dev, - struct device_attribute *attr, - char *buf) +static ssize_t request_count_show(struct device *dev, + struct device_attribute *attr, + char *buf) { struct ap_card *ac = to_ap_card(dev); unsigned int req_cnt; @@ -72,9 +72,9 @@ static ssize_t ap_req_count_show(struct device *dev, return snprintf(buf, PAGE_SIZE, "%d\n", req_cnt); } -static ssize_t ap_req_count_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t request_count_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { struct ap_card *ac = to_ap_card(dev); struct ap_queue *aq; @@ -88,10 +88,10 @@ static ssize_t ap_req_count_store(struct device *dev, return count; } -static DEVICE_ATTR(request_count, 0644, ap_req_count_show, ap_req_count_store); +static DEVICE_ATTR_RW(request_count); -static ssize_t ap_requestq_count_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t requestq_count_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct ap_card *ac = to_ap_card(dev); struct ap_queue *aq; @@ -105,10 +105,10 @@ static ssize_t ap_requestq_count_show(struct device *dev, return snprintf(buf, PAGE_SIZE, "%d\n", reqq_cnt); } -static DEVICE_ATTR(requestq_count, 0444, ap_requestq_count_show, NULL); +static DEVICE_ATTR_RO(requestq_count); -static ssize_t ap_pendingq_count_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t pendingq_count_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct ap_card *ac = to_ap_card(dev); struct ap_queue *aq; @@ -122,15 +122,15 @@ static ssize_t ap_pendingq_count_show(struct device *dev, return snprintf(buf, PAGE_SIZE, "%d\n", penq_cnt); } -static DEVICE_ATTR(pendingq_count, 0444, ap_pendingq_count_show, NULL); +static DEVICE_ATTR_RO(pendingq_count); -static ssize_t ap_modalias_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t modalias_show(struct device *dev, + struct device_attribute *attr, char *buf) { return sprintf(buf, "ap:t%02X\n", to_ap_dev(dev)->device_type); } -static DEVICE_ATTR(modalias, 0444, ap_modalias_show, NULL); +static DEVICE_ATTR_RO(modalias); static struct attribute *ap_card_dev_attrs[] = { &dev_attr_hwtype.attr, diff --git a/drivers/s390/crypto/ap_queue.c b/drivers/s390/crypto/ap_queue.c index e365171fe28f..66f7334bcb03 100644 --- a/drivers/s390/crypto/ap_queue.c +++ b/drivers/s390/crypto/ap_queue.c @@ -462,9 +462,9 @@ EXPORT_SYMBOL(ap_queue_resume); /* * AP queue related attributes. */ -static ssize_t ap_req_count_show(struct device *dev, - struct device_attribute *attr, - char *buf) +static ssize_t request_count_show(struct device *dev, + struct device_attribute *attr, + char *buf) { struct ap_queue *aq = to_ap_queue(dev); unsigned int req_cnt; @@ -475,9 +475,9 @@ static ssize_t ap_req_count_show(struct device *dev, return snprintf(buf, PAGE_SIZE, "%d\n", req_cnt); } -static ssize_t ap_req_count_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t request_count_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { struct ap_queue *aq = to_ap_queue(dev); @@ -488,10 +488,10 @@ static ssize_t ap_req_count_store(struct device *dev, return count; } -static DEVICE_ATTR(request_count, 0644, ap_req_count_show, ap_req_count_store); +static DEVICE_ATTR_RW(request_count); -static ssize_t ap_requestq_count_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t requestq_count_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct ap_queue *aq = to_ap_queue(dev); unsigned int reqq_cnt = 0; @@ -502,10 +502,10 @@ static ssize_t ap_requestq_count_show(struct device *dev, return snprintf(buf, PAGE_SIZE, "%d\n", reqq_cnt); } -static DEVICE_ATTR(requestq_count, 0444, ap_requestq_count_show, NULL); +static DEVICE_ATTR_RO(requestq_count); -static ssize_t ap_pendingq_count_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t pendingq_count_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct ap_queue *aq = to_ap_queue(dev); unsigned int penq_cnt = 0; @@ -516,10 +516,10 @@ static ssize_t ap_pendingq_count_show(struct device *dev, return snprintf(buf, PAGE_SIZE, "%d\n", penq_cnt); } -static DEVICE_ATTR(pendingq_count, 0444, ap_pendingq_count_show, NULL); +static DEVICE_ATTR_RO(pendingq_count); -static ssize_t ap_reset_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t reset_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct ap_queue *aq = to_ap_queue(dev); int rc = 0; @@ -541,10 +541,10 @@ static ssize_t ap_reset_show(struct device *dev, return rc; } -static DEVICE_ATTR(reset, 0444, ap_reset_show, NULL); +static DEVICE_ATTR_RO(reset); -static ssize_t ap_interrupt_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t interrupt_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct ap_queue *aq = to_ap_queue(dev); int rc = 0; @@ -560,7 +560,7 @@ static ssize_t ap_interrupt_show(struct device *dev, return rc; } -static DEVICE_ATTR(interrupt, 0444, ap_interrupt_show, NULL); +static DEVICE_ATTR_RO(interrupt); static struct attribute *ap_queue_dev_attrs[] = { &dev_attr_request_count.attr, diff --git a/drivers/s390/crypto/pkey_api.c b/drivers/s390/crypto/pkey_api.c index e663432395c1..1b4001e0285f 100644 --- a/drivers/s390/crypto/pkey_api.c +++ b/drivers/s390/crypto/pkey_api.c @@ -82,20 +82,20 @@ static int check_secaeskeytoken(const u8 *token, int keybitsize) if (t->type != 0x01) { DEBUG_ERR( - "check_secaeskeytoken secure token check failed, type mismatch 0x%02x != 0x01\n", - (int) t->type); + "%s secure token check failed, type mismatch 0x%02x != 0x01\n", + __func__, (int) t->type); return -EINVAL; } if (t->version != 0x04) { DEBUG_ERR( - "check_secaeskeytoken secure token check failed, version mismatch 0x%02x != 0x04\n", - (int) t->version); + "%s secure token check failed, version mismatch 0x%02x != 0x04\n", + __func__, (int) t->version); return -EINVAL; } if (keybitsize > 0 && t->bitsize != keybitsize) { DEBUG_ERR( - "check_secaeskeytoken secure token check failed, bitsize mismatch %d != %d\n", - (int) t->bitsize, keybitsize); + "%s secure token check failed, bitsize mismatch %d != %d\n", + __func__, (int) t->bitsize, keybitsize); return -EINVAL; } @@ -270,8 +270,8 @@ int pkey_genseckey(u16 cardnr, u16 domain, break; default: DEBUG_ERR( - "pkey_genseckey unknown/unsupported keytype %d\n", - keytype); + "%s unknown/unsupported keytype %d\n", + __func__, keytype); rc = -EINVAL; goto out; } @@ -290,15 +290,16 @@ int pkey_genseckey(u16 cardnr, u16 domain, rc = _zcrypt_send_cprb(&xcrb); if (rc) { DEBUG_ERR( - "pkey_genseckey zcrypt_send_cprb (cardnr=%d domain=%d) failed with errno %d\n", - (int) cardnr, (int) domain, rc); + "%s zcrypt_send_cprb (cardnr=%d domain=%d) failed with errno %d\n", + __func__, (int) cardnr, (int) domain, rc); goto out; } /* check response returncode and reasoncode */ if (prepcblk->ccp_rtcode != 0) { DEBUG_ERR( - "pkey_genseckey secure key generate failure, card response %d/%d\n", + "%s secure key generate failure, card response %d/%d\n", + __func__, (int) prepcblk->ccp_rtcode, (int) prepcblk->ccp_rscode); rc = -EIO; @@ -315,8 +316,8 @@ int pkey_genseckey(u16 cardnr, u16 domain, - sizeof(prepparm->lv3.keyblock.tokattr); if (seckeysize != SECKEYBLOBSIZE) { DEBUG_ERR( - "pkey_genseckey secure token size mismatch %d != %d bytes\n", - seckeysize, SECKEYBLOBSIZE); + "%s secure token size mismatch %d != %d bytes\n", + __func__, seckeysize, SECKEYBLOBSIZE); rc = -EIO; goto out; } @@ -407,8 +408,8 @@ int pkey_clr2seckey(u16 cardnr, u16 domain, u32 keytype, break; default: DEBUG_ERR( - "pkey_clr2seckey unknown/unsupported keytype %d\n", - keytype); + "%s unknown/unsupported keytype %d\n", + __func__, keytype); rc = -EINVAL; goto out; } @@ -427,15 +428,16 @@ int pkey_clr2seckey(u16 cardnr, u16 domain, u32 keytype, rc = _zcrypt_send_cprb(&xcrb); if (rc) { DEBUG_ERR( - "pkey_clr2seckey zcrypt_send_cprb (cardnr=%d domain=%d) failed with errno %d\n", - (int) cardnr, (int) domain, rc); + "%s zcrypt_send_cprb (cardnr=%d domain=%d) failed with errno %d\n", + __func__, (int) cardnr, (int) domain, rc); goto out; } /* check response returncode and reasoncode */ if (prepcblk->ccp_rtcode != 0) { DEBUG_ERR( - "pkey_clr2seckey clear key import failure, card response %d/%d\n", + "%s clear key import failure, card response %d/%d\n", + __func__, (int) prepcblk->ccp_rtcode, (int) prepcblk->ccp_rscode); rc = -EIO; @@ -452,8 +454,8 @@ int pkey_clr2seckey(u16 cardnr, u16 domain, u32 keytype, - sizeof(prepparm->lv3.keyblock.tokattr); if (seckeysize != SECKEYBLOBSIZE) { DEBUG_ERR( - "pkey_clr2seckey secure token size mismatch %d != %d bytes\n", - seckeysize, SECKEYBLOBSIZE); + "%s secure token size mismatch %d != %d bytes\n", + __func__, seckeysize, SECKEYBLOBSIZE); rc = -EIO; goto out; } @@ -553,15 +555,16 @@ int pkey_sec2protkey(u16 cardnr, u16 domain, rc = _zcrypt_send_cprb(&xcrb); if (rc) { DEBUG_ERR( - "pkey_sec2protkey zcrypt_send_cprb (cardnr=%d domain=%d) failed with errno %d\n", - (int) cardnr, (int) domain, rc); + "%s zcrypt_send_cprb (cardnr=%d domain=%d) failed with errno %d\n", + __func__, (int) cardnr, (int) domain, rc); goto out; } /* check response returncode and reasoncode */ if (prepcblk->ccp_rtcode != 0) { DEBUG_ERR( - "pkey_sec2protkey unwrap secure key failure, card response %d/%d\n", + "%s unwrap secure key failure, card response %d/%d\n", + __func__, (int) prepcblk->ccp_rtcode, (int) prepcblk->ccp_rscode); rc = -EIO; @@ -569,7 +572,8 @@ int pkey_sec2protkey(u16 cardnr, u16 domain, } if (prepcblk->ccp_rscode != 0) { DEBUG_WARN( - "pkey_sec2protkey unwrap secure key warning, card response %d/%d\n", + "%s unwrap secure key warning, card response %d/%d\n", + __func__, (int) prepcblk->ccp_rtcode, (int) prepcblk->ccp_rscode); } @@ -581,8 +585,8 @@ int pkey_sec2protkey(u16 cardnr, u16 domain, /* check the returned keyblock */ if (prepparm->lv3.keyblock.version != 0x01) { DEBUG_ERR( - "pkey_sec2protkey reply param keyblock version mismatch 0x%02x != 0x01\n", - (int) prepparm->lv3.keyblock.version); + "%s reply param keyblock version mismatch 0x%02x != 0x01\n", + __func__, (int) prepparm->lv3.keyblock.version); rc = -EIO; goto out; } @@ -599,8 +603,8 @@ int pkey_sec2protkey(u16 cardnr, u16 domain, protkey->type = PKEY_KEYTYPE_AES_256; break; default: - DEBUG_ERR("pkey_sec2protkey unknown/unsupported keytype %d\n", - prepparm->lv3.keyblock.keylen); + DEBUG_ERR("%s unknown/unsupported keytype %d\n", + __func__, prepparm->lv3.keyblock.keylen); rc = -EIO; goto out; } @@ -638,8 +642,8 @@ int pkey_clr2protkey(u32 keytype, fc = CPACF_PCKMO_ENC_AES_256_KEY; break; default: - DEBUG_ERR("pkey_clr2protkey unknown/unsupported keytype %d\n", - keytype); + DEBUG_ERR("%s unknown/unsupported keytype %d\n", + __func__, keytype); return -EINVAL; } @@ -713,15 +717,16 @@ static int query_crypto_facility(u16 cardnr, u16 domain, rc = _zcrypt_send_cprb(&xcrb); if (rc) { DEBUG_ERR( - "query_crypto_facility zcrypt_send_cprb (cardnr=%d domain=%d) failed with errno %d\n", - (int) cardnr, (int) domain, rc); + "%s zcrypt_send_cprb (cardnr=%d domain=%d) failed with errno %d\n", + __func__, (int) cardnr, (int) domain, rc); goto out; } /* check response returncode and reasoncode */ if (prepcblk->ccp_rtcode != 0) { DEBUG_ERR( - "query_crypto_facility unwrap secure key failure, card response %d/%d\n", + "%s unwrap secure key failure, card response %d/%d\n", + __func__, (int) prepcblk->ccp_rtcode, (int) prepcblk->ccp_rscode); rc = -EIO; @@ -993,7 +998,7 @@ int pkey_skey2pkey(const struct pkey_seckey *seckey, } if (rc) - DEBUG_DBG("pkey_skey2pkey failed rc=%d\n", rc); + DEBUG_DBG("%s failed rc=%d\n", __func__, rc); return rc; } @@ -1030,7 +1035,7 @@ int pkey_verifykey(const struct pkey_seckey *seckey, if (rc) goto out; if (t->mkvp == mkvp[1]) { - DEBUG_DBG("pkey_verifykey secure key has old mkvp\n"); + DEBUG_DBG("%s secure key has old mkvp\n", __func__); if (pattributes) *pattributes |= PKEY_VERIFY_ATTR_OLD_MKVP; } @@ -1041,7 +1046,7 @@ int pkey_verifykey(const struct pkey_seckey *seckey, *pdomain = domain; out: - DEBUG_DBG("pkey_verifykey rc=%d\n", rc); + DEBUG_DBG("%s rc=%d\n", __func__, rc); return rc; } EXPORT_SYMBOL(pkey_verifykey); @@ -1064,7 +1069,7 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd, return -EFAULT; rc = pkey_genseckey(kgs.cardnr, kgs.domain, kgs.keytype, &kgs.seckey); - DEBUG_DBG("pkey_ioctl pkey_genseckey()=%d\n", rc); + DEBUG_DBG("%s pkey_genseckey()=%d\n", __func__, rc); if (rc) break; if (copy_to_user(ugs, &kgs, sizeof(kgs))) @@ -1079,7 +1084,7 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd, return -EFAULT; rc = pkey_clr2seckey(kcs.cardnr, kcs.domain, kcs.keytype, &kcs.clrkey, &kcs.seckey); - DEBUG_DBG("pkey_ioctl pkey_clr2seckey()=%d\n", rc); + DEBUG_DBG("%s pkey_clr2seckey()=%d\n", __func__, rc); if (rc) break; if (copy_to_user(ucs, &kcs, sizeof(kcs))) @@ -1095,7 +1100,7 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd, return -EFAULT; rc = pkey_sec2protkey(ksp.cardnr, ksp.domain, &ksp.seckey, &ksp.protkey); - DEBUG_DBG("pkey_ioctl pkey_sec2protkey()=%d\n", rc); + DEBUG_DBG("%s pkey_sec2protkey()=%d\n", __func__, rc); if (rc) break; if (copy_to_user(usp, &ksp, sizeof(ksp))) @@ -1110,7 +1115,7 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd, return -EFAULT; rc = pkey_clr2protkey(kcp.keytype, &kcp.clrkey, &kcp.protkey); - DEBUG_DBG("pkey_ioctl pkey_clr2protkey()=%d\n", rc); + DEBUG_DBG("%s pkey_clr2protkey()=%d\n", __func__, rc); if (rc) break; if (copy_to_user(ucp, &kcp, sizeof(kcp))) @@ -1126,7 +1131,7 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd, return -EFAULT; rc = pkey_findcard(&kfc.seckey, &kfc.cardnr, &kfc.domain, 1); - DEBUG_DBG("pkey_ioctl pkey_findcard()=%d\n", rc); + DEBUG_DBG("%s pkey_findcard()=%d\n", __func__, rc); if (rc) break; if (copy_to_user(ufc, &kfc, sizeof(kfc))) @@ -1140,7 +1145,7 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd, if (copy_from_user(&ksp, usp, sizeof(ksp))) return -EFAULT; rc = pkey_skey2pkey(&ksp.seckey, &ksp.protkey); - DEBUG_DBG("pkey_ioctl pkey_skey2pkey()=%d\n", rc); + DEBUG_DBG("%s pkey_skey2pkey()=%d\n", __func__, rc); if (rc) break; if (copy_to_user(usp, &ksp, sizeof(ksp))) @@ -1155,7 +1160,7 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd, return -EFAULT; rc = pkey_verifykey(&kvk.seckey, &kvk.cardnr, &kvk.domain, &kvk.keysize, &kvk.attributes); - DEBUG_DBG("pkey_ioctl pkey_verifykey()=%d\n", rc); + DEBUG_DBG("%s pkey_verifykey()=%d\n", __func__, rc); if (rc) break; if (copy_to_user(uvk, &kvk, sizeof(kvk))) diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c index febcdb5135bf..e6854127b434 100644 --- a/drivers/s390/crypto/zcrypt_api.c +++ b/drivers/s390/crypto/zcrypt_api.c @@ -50,7 +50,7 @@ EXPORT_TRACEPOINT_SYMBOL(s390_zcrypt_req); EXPORT_TRACEPOINT_SYMBOL(s390_zcrypt_rep); static int zcrypt_hwrng_seed = 1; -module_param_named(hwrng_seed, zcrypt_hwrng_seed, int, S_IRUSR|S_IRGRP); +module_param_named(hwrng_seed, zcrypt_hwrng_seed, int, 0440); MODULE_PARM_DESC(hwrng_seed, "Turn on/off hwrng auto seed, default is 1 (on)."); DEFINE_SPINLOCK(zcrypt_list_lock); @@ -182,7 +182,8 @@ static inline void zcrypt_drop_queue(struct zcrypt_card *zc, static inline bool zcrypt_card_compare(struct zcrypt_card *zc, struct zcrypt_card *pref_zc, - unsigned weight, unsigned pref_weight) + unsigned int weight, + unsigned int pref_weight) { if (!pref_zc) return false; @@ -196,7 +197,8 @@ static inline bool zcrypt_card_compare(struct zcrypt_card *zc, static inline bool zcrypt_queue_compare(struct zcrypt_queue *zq, struct zcrypt_queue *pref_zq, - unsigned weight, unsigned pref_weight) + unsigned int weight, + unsigned int pref_weight) { if (!pref_zq) return false; @@ -792,6 +794,7 @@ static long zcrypt_unlocked_ioctl(struct file *filp, unsigned int cmd, case ICARSAMODEXPO: { struct ica_rsa_modexpo __user *umex = (void __user *) arg; struct ica_rsa_modexpo mex; + if (copy_from_user(&mex, umex, sizeof(mex))) return -EFAULT; do { @@ -811,6 +814,7 @@ static long zcrypt_unlocked_ioctl(struct file *filp, unsigned int cmd, case ICARSACRT: { struct ica_rsa_modexpo_crt __user *ucrt = (void __user *) arg; struct ica_rsa_modexpo_crt crt; + if (copy_from_user(&crt, ucrt, sizeof(crt))) return -EFAULT; do { @@ -830,6 +834,7 @@ static long zcrypt_unlocked_ioctl(struct file *filp, unsigned int cmd, case ZSECSENDCPRB: { struct ica_xcRB __user *uxcRB = (void __user *) arg; struct ica_xcRB xcRB; + if (copy_from_user(&xcRB, uxcRB, sizeof(xcRB))) return -EFAULT; do { @@ -849,6 +854,7 @@ static long zcrypt_unlocked_ioctl(struct file *filp, unsigned int cmd, case ZSENDEP11CPRB: { struct ep11_urb __user *uxcrb = (void __user *)arg; struct ep11_urb xcrb; + if (copy_from_user(&xcrb, uxcrb, sizeof(xcrb))) return -EFAULT; do { @@ -1037,7 +1043,7 @@ static long trans_modexpo_crt32(struct file *filp, unsigned int cmd, return -EFAULT; crt64.inputdata = compat_ptr(crt32.inputdata); crt64.inputdatalength = crt32.inputdatalength; - crt64.outputdata= compat_ptr(crt32.outputdata); + crt64.outputdata = compat_ptr(crt32.outputdata); crt64.outputdatalength = crt32.outputdatalength; crt64.bp_key = compat_ptr(crt32.bp_key); crt64.bq_key = compat_ptr(crt32.bq_key); @@ -1063,20 +1069,20 @@ struct compat_ica_xcRB { unsigned int user_defined; unsigned short request_ID; unsigned int request_control_blk_length; - unsigned char padding1[16 - sizeof (compat_uptr_t)]; + unsigned char padding1[16 - sizeof(compat_uptr_t)]; compat_uptr_t request_control_blk_addr; unsigned int request_data_length; - char padding2[16 - sizeof (compat_uptr_t)]; + char padding2[16 - sizeof(compat_uptr_t)]; compat_uptr_t request_data_address; unsigned int reply_control_blk_length; - char padding3[16 - sizeof (compat_uptr_t)]; + char padding3[16 - sizeof(compat_uptr_t)]; compat_uptr_t reply_control_blk_addr; unsigned int reply_data_length; - char padding4[16 - sizeof (compat_uptr_t)]; + char padding4[16 - sizeof(compat_uptr_t)]; compat_uptr_t reply_data_addr; unsigned short priority_window; unsigned int status; -} __attribute__((packed)); +} __packed; static long trans_xcRB32(struct file *filp, unsigned int cmd, unsigned long arg) @@ -1120,7 +1126,7 @@ static long trans_xcRB32(struct file *filp, unsigned int cmd, xcRB32.reply_data_length = xcRB64.reply_data_length; xcRB32.status = xcRB64.status; if (copy_to_user(uxcRB32, &xcRB32, sizeof(xcRB32))) - return -EFAULT; + return -EFAULT; return rc; } @@ -1182,10 +1188,10 @@ static int zcrypt_rng_data_read(struct hwrng *rng, u32 *data) rc = zcrypt_rng((char *) zcrypt_rng_buffer); if (rc < 0) return -EIO; - zcrypt_rng_buffer_index = rc / sizeof *data; + zcrypt_rng_buffer_index = rc / sizeof(*data); } *data = zcrypt_rng_buffer[--zcrypt_rng_buffer_index]; - return sizeof *data; + return sizeof(*data); } static struct hwrng zcrypt_rng_dev = { diff --git a/drivers/s390/crypto/zcrypt_api.h b/drivers/s390/crypto/zcrypt_api.h index f149a8fee60d..a848625c1a5a 100644 --- a/drivers/s390/crypto/zcrypt_api.h +++ b/drivers/s390/crypto/zcrypt_api.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * zcrypt 2.1.0 * diff --git a/drivers/s390/crypto/zcrypt_card.c b/drivers/s390/crypto/zcrypt_card.c index da2c8dfd4d74..40cd4c1c2de8 100644 --- a/drivers/s390/crypto/zcrypt_card.c +++ b/drivers/s390/crypto/zcrypt_card.c @@ -38,28 +38,28 @@ * Device attributes common for all crypto card devices. */ -static ssize_t zcrypt_card_type_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t type_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct zcrypt_card *zc = to_ap_card(dev)->private; return snprintf(buf, PAGE_SIZE, "%s\n", zc->type_string); } -static DEVICE_ATTR(type, 0444, zcrypt_card_type_show, NULL); +static DEVICE_ATTR_RO(type); -static ssize_t zcrypt_card_online_show(struct device *dev, - struct device_attribute *attr, - char *buf) +static ssize_t online_show(struct device *dev, + struct device_attribute *attr, + char *buf) { struct zcrypt_card *zc = to_ap_card(dev)->private; return snprintf(buf, PAGE_SIZE, "%d\n", zc->online); } -static ssize_t zcrypt_card_online_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t online_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { struct zcrypt_card *zc = to_ap_card(dev)->private; struct zcrypt_queue *zq; @@ -80,19 +80,18 @@ static ssize_t zcrypt_card_online_store(struct device *dev, return count; } -static DEVICE_ATTR(online, 0644, zcrypt_card_online_show, - zcrypt_card_online_store); +static DEVICE_ATTR_RW(online); -static ssize_t zcrypt_card_load_show(struct device *dev, - struct device_attribute *attr, - char *buf) +static ssize_t load_show(struct device *dev, + struct device_attribute *attr, + char *buf) { struct zcrypt_card *zc = to_ap_card(dev)->private; return snprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&zc->load)); } -static DEVICE_ATTR(load, 0444, zcrypt_card_load_show, NULL); +static DEVICE_ATTR_RO(load); static struct attribute *zcrypt_card_attrs[] = { &dev_attr_type.attr, diff --git a/drivers/s390/crypto/zcrypt_cca_key.h b/drivers/s390/crypto/zcrypt_cca_key.h index 1752622b95f7..e5b5c02c9d67 100644 --- a/drivers/s390/crypto/zcrypt_cca_key.h +++ b/drivers/s390/crypto/zcrypt_cca_key.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * zcrypt 2.1.0 * @@ -31,7 +31,7 @@ struct cca_token_hdr { unsigned char version; unsigned short token_length; unsigned char reserved[4]; -} __attribute__((packed)); +} __packed; #define CCA_TKN_HDR_ID_EXT 0x1E @@ -51,7 +51,7 @@ struct cca_public_sec { unsigned short exponent_len; unsigned short modulus_bit_len; unsigned short modulus_byte_len; /* In a private key, this is 0 */ -} __attribute__((packed)); +} __packed; /** * mapping for the cca private CRT key 'token' @@ -85,7 +85,7 @@ struct cca_pvt_ext_CRT_sec { unsigned short pad_len; unsigned char reserved4[52]; unsigned char confounder[8]; -} __attribute__((packed)); +} __packed; #define CCA_PVT_EXT_CRT_SEC_ID_PVT 0x08 #define CCA_PVT_EXT_CRT_SEC_FMT_CL 0x40 @@ -114,7 +114,7 @@ static inline int zcrypt_type6_mex_key_en(struct ica_rsa_modexpo *mex, void *p) struct cca_token_hdr pubHdr; struct cca_public_sec pubSec; char exponent[0]; - } __attribute__((packed)) *key = p; + } __packed *key = p; unsigned char *temp; int i; @@ -183,7 +183,7 @@ static inline int zcrypt_type6_crt_key(struct ica_rsa_modexpo_crt *crt, void *p) struct cca_token_hdr token; struct cca_pvt_ext_CRT_sec pvt; char key_parts[0]; - } __attribute__((packed)) *key = p; + } __packed *key = p; struct cca_public_sec *pub; int short_len, long_len, pad_len, key_len, size; diff --git a/drivers/s390/crypto/zcrypt_cex2a.c b/drivers/s390/crypto/zcrypt_cex2a.c index e701194d3611..f4ae5fa30ec9 100644 --- a/drivers/s390/crypto/zcrypt_cex2a.c +++ b/drivers/s390/crypto/zcrypt_cex2a.c @@ -145,6 +145,7 @@ static struct ap_driver zcrypt_cex2a_card_driver = { .probe = zcrypt_cex2a_card_probe, .remove = zcrypt_cex2a_card_remove, .ids = zcrypt_cex2a_card_ids, + .flags = AP_DRIVER_FLAG_DEFAULT, }; /** @@ -208,6 +209,7 @@ static struct ap_driver zcrypt_cex2a_queue_driver = { .suspend = ap_queue_suspend, .resume = ap_queue_resume, .ids = zcrypt_cex2a_queue_ids, + .flags = AP_DRIVER_FLAG_DEFAULT, }; int __init zcrypt_cex2a_init(void) diff --git a/drivers/s390/crypto/zcrypt_cex2a.h b/drivers/s390/crypto/zcrypt_cex2a.h index c3c116777c93..66d58bc87c66 100644 --- a/drivers/s390/crypto/zcrypt_cex2a.h +++ b/drivers/s390/crypto/zcrypt_cex2a.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * zcrypt 2.1.0 * @@ -30,7 +30,7 @@ struct type50_hdr { unsigned char reserved2; unsigned char ignored; unsigned short reserved3; -} __attribute__((packed)); +} __packed; #define TYPE50_TYPE_CODE 0x50 @@ -49,7 +49,7 @@ struct type50_meb1_msg { unsigned char exponent[128]; unsigned char modulus[128]; unsigned char message[128]; -} __attribute__((packed)); +} __packed; /* Mod-Exp, with a large modulus */ struct type50_meb2_msg { @@ -59,7 +59,7 @@ struct type50_meb2_msg { unsigned char exponent[256]; unsigned char modulus[256]; unsigned char message[256]; -} __attribute__((packed)); +} __packed; /* Mod-Exp, with a larger modulus */ struct type50_meb3_msg { @@ -69,7 +69,7 @@ struct type50_meb3_msg { unsigned char exponent[512]; unsigned char modulus[512]; unsigned char message[512]; -} __attribute__((packed)); +} __packed; /* CRT, with a small modulus */ struct type50_crb1_msg { @@ -82,7 +82,7 @@ struct type50_crb1_msg { unsigned char dq[64]; unsigned char u[64]; unsigned char message[128]; -} __attribute__((packed)); +} __packed; /* CRT, with a large modulus */ struct type50_crb2_msg { @@ -95,7 +95,7 @@ struct type50_crb2_msg { unsigned char dq[128]; unsigned char u[128]; unsigned char message[256]; -} __attribute__((packed)); +} __packed; /* CRT, with a larger modulus */ struct type50_crb3_msg { @@ -108,7 +108,7 @@ struct type50_crb3_msg { unsigned char dq[256]; unsigned char u[256]; unsigned char message[512]; -} __attribute__((packed)); +} __packed; /** * The type 80 response family is associated with a CEX2A card. @@ -128,7 +128,7 @@ struct type80_hdr { unsigned char code; /* 0x00 */ unsigned char reserved2[3]; unsigned char reserved3[8]; -} __attribute__((packed)); +} __packed; int zcrypt_cex2a_init(void); void zcrypt_cex2a_exit(void); diff --git a/drivers/s390/crypto/zcrypt_cex4.c b/drivers/s390/crypto/zcrypt_cex4.c index f305538334ad..35d58dbbc4da 100644 --- a/drivers/s390/crypto/zcrypt_cex4.c +++ b/drivers/s390/crypto/zcrypt_cex4.c @@ -214,6 +214,7 @@ static struct ap_driver zcrypt_cex4_card_driver = { .probe = zcrypt_cex4_card_probe, .remove = zcrypt_cex4_card_remove, .ids = zcrypt_cex4_card_ids, + .flags = AP_DRIVER_FLAG_DEFAULT, }; /** @@ -283,6 +284,7 @@ static struct ap_driver zcrypt_cex4_queue_driver = { .suspend = ap_queue_suspend, .resume = ap_queue_resume, .ids = zcrypt_cex4_queue_ids, + .flags = AP_DRIVER_FLAG_DEFAULT, }; int __init zcrypt_cex4_init(void) diff --git a/drivers/s390/crypto/zcrypt_error.h b/drivers/s390/crypto/zcrypt_error.h index 01598d83c60a..6f7ebc1dbe10 100644 --- a/drivers/s390/crypto/zcrypt_error.h +++ b/drivers/s390/crypto/zcrypt_error.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * zcrypt 2.1.0 * diff --git a/drivers/s390/crypto/zcrypt_msgtype50.c b/drivers/s390/crypto/zcrypt_msgtype50.c index afe1b2bcd7ec..f159662c907b 100644 --- a/drivers/s390/crypto/zcrypt_msgtype50.c +++ b/drivers/s390/crypto/zcrypt_msgtype50.c @@ -27,13 +27,14 @@ #include "zcrypt_error.h" #include "zcrypt_msgtype50.h" -#define CEX3A_MAX_MOD_SIZE 512 /* 4096 bits */ +/* 4096 bits */ +#define CEX3A_MAX_MOD_SIZE 512 -#define CEX2A_MAX_RESPONSE_SIZE 0x110 /* max outputdatalength + type80_hdr */ +/* max outputdatalength + type80_hdr */ +#define CEX2A_MAX_RESPONSE_SIZE 0x110 -#define CEX3A_MAX_RESPONSE_SIZE 0x210 /* 512 bit modulus - * (max outputdatalength) + - * type80_hdr*/ +/* 512 bit modulus, (max outputdatalength) + type80_hdr */ +#define CEX3A_MAX_RESPONSE_SIZE 0x210 MODULE_AUTHOR("IBM Corporation"); MODULE_DESCRIPTION("Cryptographic Accelerator (message type 50), " \ @@ -209,6 +210,7 @@ static int ICAMEX_msg_to_type50MEX_msg(struct zcrypt_queue *zq, if (mod_len <= 128) { struct type50_meb1_msg *meb1 = ap_msg->message; + memset(meb1, 0, sizeof(*meb1)); ap_msg->length = sizeof(*meb1); meb1->header.msg_type_code = TYPE50_TYPE_CODE; @@ -219,6 +221,7 @@ static int ICAMEX_msg_to_type50MEX_msg(struct zcrypt_queue *zq, inp = meb1->message + sizeof(meb1->message) - mod_len; } else if (mod_len <= 256) { struct type50_meb2_msg *meb2 = ap_msg->message; + memset(meb2, 0, sizeof(*meb2)); ap_msg->length = sizeof(*meb2); meb2->header.msg_type_code = TYPE50_TYPE_CODE; @@ -229,6 +232,7 @@ static int ICAMEX_msg_to_type50MEX_msg(struct zcrypt_queue *zq, inp = meb2->message + sizeof(meb2->message) - mod_len; } else if (mod_len <= 512) { struct type50_meb3_msg *meb3 = ap_msg->message; + memset(meb3, 0, sizeof(*meb3)); ap_msg->length = sizeof(*meb3); meb3->header.msg_type_code = TYPE50_TYPE_CODE; @@ -274,6 +278,7 @@ static int ICACRT_msg_to_type50CRT_msg(struct zcrypt_queue *zq, */ if (mod_len <= 128) { /* up to 1024 bit key size */ struct type50_crb1_msg *crb1 = ap_msg->message; + memset(crb1, 0, sizeof(*crb1)); ap_msg->length = sizeof(*crb1); crb1->header.msg_type_code = TYPE50_TYPE_CODE; @@ -287,6 +292,7 @@ static int ICACRT_msg_to_type50CRT_msg(struct zcrypt_queue *zq, inp = crb1->message + sizeof(crb1->message) - mod_len; } else if (mod_len <= 256) { /* up to 2048 bit key size */ struct type50_crb2_msg *crb2 = ap_msg->message; + memset(crb2, 0, sizeof(*crb2)); ap_msg->length = sizeof(*crb2); crb2->header.msg_type_code = TYPE50_TYPE_CODE; @@ -301,6 +307,7 @@ static int ICACRT_msg_to_type50CRT_msg(struct zcrypt_queue *zq, } else if ((mod_len <= 512) && /* up to 4096 bit key size */ (zq->zcard->max_mod_size == CEX3A_MAX_MOD_SIZE)) { struct type50_crb3_msg *crb3 = ap_msg->message; + memset(crb3, 0, sizeof(*crb3)); ap_msg->length = sizeof(*crb3); crb3->header.msg_type_code = TYPE50_TYPE_CODE; diff --git a/drivers/s390/crypto/zcrypt_msgtype50.h b/drivers/s390/crypto/zcrypt_msgtype50.h index 0a36545cfb8e..8530f652ea4f 100644 --- a/drivers/s390/crypto/zcrypt_msgtype50.h +++ b/drivers/s390/crypto/zcrypt_msgtype50.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * zcrypt 2.1.0 * @@ -17,10 +17,10 @@ #define MSGTYPE50_NAME "zcrypt_msgtype50" #define MSGTYPE50_VARIANT_DEFAULT 0 -#define MSGTYPE50_CRB2_MAX_MSG_SIZE 0x390 /*sizeof(struct type50_crb2_msg)*/ -#define MSGTYPE50_CRB3_MAX_MSG_SIZE 0x710 /*sizeof(struct type50_crb3_msg)*/ +#define MSGTYPE50_CRB2_MAX_MSG_SIZE 0x390 /* sizeof(struct type50_crb2_msg) */ +#define MSGTYPE50_CRB3_MAX_MSG_SIZE 0x710 /* sizeof(struct type50_crb3_msg) */ -#define MSGTYPE_ADJUSTMENT 0x08 /*type04 extension (not needed in type50)*/ +#define MSGTYPE_ADJUSTMENT 0x08 /* type04 extension (not needed in type50) */ unsigned int get_rsa_modex_fc(struct ica_rsa_modexpo *, int *); unsigned int get_rsa_crt_fc(struct ica_rsa_modexpo_crt *, int *); diff --git a/drivers/s390/crypto/zcrypt_msgtype6.c b/drivers/s390/crypto/zcrypt_msgtype6.c index e70ae078c86b..2101776a8148 100644 --- a/drivers/s390/crypto/zcrypt_msgtype6.c +++ b/drivers/s390/crypto/zcrypt_msgtype6.c @@ -421,8 +421,10 @@ static int XCRB_msg_to_type6CPRB_msgX(struct ap_message *ap_msg, if (ap_msg->length > MSGTYPE06_MAX_MSG_SIZE) return -EINVAL; - /* Overflow check - sum must be greater (or equal) than the largest operand */ + /* + * Overflow check + * sum must be greater (or equal) than the largest operand + */ req_sumlen = CEIL4(xcRB->request_control_blk_length) + xcRB->request_data_length; if ((CEIL4(xcRB->request_control_blk_length) <= @@ -442,8 +444,10 @@ static int XCRB_msg_to_type6CPRB_msgX(struct ap_message *ap_msg, if (replylen > MSGTYPE06_MAX_MSG_SIZE) return -EINVAL; - /* Overflow check - sum must be greater (or equal) than the largest operand */ + /* + * Overflow check + * sum must be greater (or equal) than the largest operand + */ resp_sumlen = CEIL4(xcRB->reply_control_blk_length) + xcRB->reply_data_length; if ((CEIL4(xcRB->reply_control_blk_length) <= xcRB->reply_data_length) ? @@ -454,7 +458,7 @@ static int XCRB_msg_to_type6CPRB_msgX(struct ap_message *ap_msg, /* prepare type6 header */ msg->hdr = static_type6_hdrX; - memcpy(msg->hdr.agent_id , &(xcRB->agent_ID), sizeof(xcRB->agent_ID)); + memcpy(msg->hdr.agent_id, &(xcRB->agent_ID), sizeof(xcRB->agent_ID)); msg->hdr.ToCardLen1 = xcRB->request_control_blk_length; if (xcRB->request_data_length) { msg->hdr.offset2 = msg->hdr.offset1 + rcblen; @@ -806,8 +810,10 @@ static int convert_response_ica(struct zcrypt_queue *zq, if (msg->cprbx.cprb_ver_id == 0x02) return convert_type86_ica(zq, reply, outputdata, outputdatalength); - /* Fall through, no break, incorrect cprb version is an unknown - * response */ + /* + * Fall through, no break, incorrect cprb version is an unknown + * response + */ default: /* Unknown response type, this should NEVER EVER happen */ zq->online = 0; pr_err("Cryptographic device %02x.%04x failed and was set offline\n", @@ -840,8 +846,10 @@ static int convert_response_xcrb(struct zcrypt_queue *zq, } if (msg->cprbx.cprb_ver_id == 0x02) return convert_type86_xcrb(zq, reply, xcRB); - /* Fall through, no break, incorrect cprb version is an unknown - * response */ + /* + * Fall through, no break, incorrect cprb version is an unknown + * response + */ default: /* Unknown response type, this should NEVER EVER happen */ xcRB->status = 0x0008044DL; /* HDD_InvalidParm */ zq->online = 0; @@ -901,8 +909,10 @@ static int convert_response_rng(struct zcrypt_queue *zq, return -EINVAL; if (msg->cprbx.cprb_ver_id == 0x02) return convert_type86_rng(zq, reply, data); - /* Fall through, no break, incorrect cprb version is an unknown - * response */ + /* + * Fall through, no break, incorrect cprb version is an unknown + * response + */ default: /* Unknown response type, this should NEVER EVER happen */ zq->online = 0; pr_err("Cryptographic device %02x.%04x failed and was set offline\n", @@ -1004,7 +1014,7 @@ static void zcrypt_msgtype6_receive_ep11(struct ap_queue *aq, } } else { memcpy(msg->message, reply->message, sizeof(error_reply)); - } + } out: complete(&(resp_type->work)); } diff --git a/drivers/s390/crypto/zcrypt_msgtype6.h b/drivers/s390/crypto/zcrypt_msgtype6.h index d314f4525518..e4c2f37d7ad9 100644 --- a/drivers/s390/crypto/zcrypt_msgtype6.h +++ b/drivers/s390/crypto/zcrypt_msgtype6.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * zcrypt 2.1.0 * diff --git a/drivers/s390/crypto/zcrypt_pcixcc.c b/drivers/s390/crypto/zcrypt_pcixcc.c index 159b0a0dd211..94d9f7224aea 100644 --- a/drivers/s390/crypto/zcrypt_pcixcc.c +++ b/drivers/s390/crypto/zcrypt_pcixcc.c @@ -95,7 +95,7 @@ static int zcrypt_pcixcc_rng_supported(struct ap_queue *aq) struct type86_hdr hdr; struct type86_fmt2_ext fmt2; struct CPRBX cprbx; - } __attribute__((packed)) *reply; + } __packed *reply; struct { struct type6_hdr hdr; struct CPRBX cprbx; @@ -104,7 +104,7 @@ static int zcrypt_pcixcc_rng_supported(struct ap_queue *aq) char rule[8]; short int verb_length; short int key_length; - } __packed * msg; + } __packed *msg; int rc, i; ap_init_message(&ap_msg); @@ -223,6 +223,7 @@ static struct ap_driver zcrypt_pcixcc_card_driver = { .probe = zcrypt_pcixcc_card_probe, .remove = zcrypt_pcixcc_card_remove, .ids = zcrypt_pcixcc_card_ids, + .flags = AP_DRIVER_FLAG_DEFAULT, }; /** @@ -286,6 +287,7 @@ static struct ap_driver zcrypt_pcixcc_queue_driver = { .suspend = ap_queue_suspend, .resume = ap_queue_resume, .ids = zcrypt_pcixcc_queue_ids, + .flags = AP_DRIVER_FLAG_DEFAULT, }; int __init zcrypt_pcixcc_init(void) diff --git a/drivers/s390/crypto/zcrypt_pcixcc.h b/drivers/s390/crypto/zcrypt_pcixcc.h index d678a3af83a7..cf73a0f91e9c 100644 --- a/drivers/s390/crypto/zcrypt_pcixcc.h +++ b/drivers/s390/crypto/zcrypt_pcixcc.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * zcrypt 2.1.0 * diff --git a/drivers/s390/crypto/zcrypt_queue.c b/drivers/s390/crypto/zcrypt_queue.c index 91a52f268353..8df82c6ef66e 100644 --- a/drivers/s390/crypto/zcrypt_queue.c +++ b/drivers/s390/crypto/zcrypt_queue.c @@ -38,18 +38,18 @@ * Device attributes common for all crypto queue devices. */ -static ssize_t zcrypt_queue_online_show(struct device *dev, - struct device_attribute *attr, - char *buf) +static ssize_t online_show(struct device *dev, + struct device_attribute *attr, + char *buf) { struct zcrypt_queue *zq = to_ap_queue(dev)->private; return snprintf(buf, PAGE_SIZE, "%d\n", zq->online); } -static ssize_t zcrypt_queue_online_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t online_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { struct zcrypt_queue *zq = to_ap_queue(dev)->private; struct zcrypt_card *zc = zq->zcard; @@ -72,19 +72,18 @@ static ssize_t zcrypt_queue_online_store(struct device *dev, return count; } -static DEVICE_ATTR(online, 0644, zcrypt_queue_online_show, - zcrypt_queue_online_store); +static DEVICE_ATTR_RW(online); -static ssize_t zcrypt_queue_load_show(struct device *dev, - struct device_attribute *attr, - char *buf) +static ssize_t load_show(struct device *dev, + struct device_attribute *attr, + char *buf) { struct zcrypt_queue *zq = to_ap_queue(dev)->private; return snprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&zq->load)); } -static DEVICE_ATTR(load, 0444, zcrypt_queue_load_show, NULL); +static DEVICE_ATTR_RO(load); static struct attribute *zcrypt_queue_attrs[] = { &dev_attr_online.attr, diff --git a/drivers/soc/bcm/brcmstb/pm/pm-arm.c b/drivers/soc/bcm/brcmstb/pm/pm-arm.c index dcf8c8065508..a5577dd5eb08 100644 --- a/drivers/soc/bcm/brcmstb/pm/pm-arm.c +++ b/drivers/soc/bcm/brcmstb/pm/pm-arm.c @@ -628,10 +628,26 @@ static const struct of_device_id ddr_shimphy_dt_ids[] = { static const struct of_device_id brcmstb_memc_of_match[] = { { + .compatible = "brcm,brcmstb-memc-ddr-rev-b.2.1", + .data = &ddr_seq, + }, + { .compatible = "brcm,brcmstb-memc-ddr-rev-b.2.2", .data = &ddr_seq_b22, }, { + .compatible = "brcm,brcmstb-memc-ddr-rev-b.2.3", + .data = &ddr_seq_b22, + }, + { + .compatible = "brcm,brcmstb-memc-ddr-rev-b.3.0", + .data = &ddr_seq_b22, + }, + { + .compatible = "brcm,brcmstb-memc-ddr-rev-b.3.1", + .data = &ddr_seq_b22, + }, + { .compatible = "brcm,brcmstb-memc-ddr", .data = &ddr_seq, }, diff --git a/drivers/soc/fsl/Kconfig b/drivers/soc/fsl/Kconfig index 7a9fb9baa66d..8f80e8bbf29e 100644 --- a/drivers/soc/fsl/Kconfig +++ b/drivers/soc/fsl/Kconfig @@ -1,7 +1,9 @@ # -# Freescale SOC drivers +# NXP/Freescale QorIQ series SOC drivers # +menu "NXP/Freescale QorIQ SoC drivers" + source "drivers/soc/fsl/qbman/Kconfig" source "drivers/soc/fsl/qe/Kconfig" @@ -16,3 +18,14 @@ config FSL_GUTS Initially only reading SVR and registering soc device are supported. Other guts accesses, such as reading RCW, should eventually be moved into this driver as well. + +config FSL_MC_DPIO + tristate "QorIQ DPAA2 DPIO driver" + depends on FSL_MC_BUS + help + Driver for the DPAA2 DPIO object. A DPIO provides queue and + buffer management facilities for software to interact with + other DPAA2 objects. This driver does not expose the DPIO + objects individually, but groups them under a service layer + API. +endmenu diff --git a/drivers/soc/fsl/Makefile b/drivers/soc/fsl/Makefile index 44b3bebef24a..803ef1bfb5ff 100644 --- a/drivers/soc/fsl/Makefile +++ b/drivers/soc/fsl/Makefile @@ -6,3 +6,4 @@ obj-$(CONFIG_FSL_DPAA) += qbman/ obj-$(CONFIG_QUICC_ENGINE) += qe/ obj-$(CONFIG_CPM) += qe/ obj-$(CONFIG_FSL_GUTS) += guts.o +obj-$(CONFIG_FSL_MC_DPIO) += dpio/ diff --git a/drivers/staging/fsl-mc/bus/dpio/Makefile b/drivers/soc/fsl/dpio/Makefile index b9ff24c76582..b9ff24c76582 100644 --- a/drivers/staging/fsl-mc/bus/dpio/Makefile +++ b/drivers/soc/fsl/dpio/Makefile diff --git a/drivers/staging/fsl-mc/bus/dpio/dpio-cmd.h b/drivers/soc/fsl/dpio/dpio-cmd.h index ab8f82ee7ee5..ab8f82ee7ee5 100644 --- a/drivers/staging/fsl-mc/bus/dpio/dpio-cmd.h +++ b/drivers/soc/fsl/dpio/dpio-cmd.h diff --git a/drivers/staging/fsl-mc/bus/dpio/dpio-driver.c b/drivers/soc/fsl/dpio/dpio-driver.c index 11a90a90d827..b60b77bfaffa 100644 --- a/drivers/staging/fsl-mc/bus/dpio/dpio-driver.c +++ b/drivers/soc/fsl/dpio/dpio-driver.c @@ -16,7 +16,7 @@ #include <linux/io.h> #include <linux/fsl/mc.h> -#include "../../include/dpaa2-io.h" +#include <soc/fsl/dpaa2-io.h> #include "qbman-portal.h" #include "dpio.h" diff --git a/drivers/staging/fsl-mc/bus/dpio/dpio-service.c b/drivers/soc/fsl/dpio/dpio-service.c index 14ed2beb7432..9b17f72349ed 100644 --- a/drivers/staging/fsl-mc/bus/dpio/dpio-service.c +++ b/drivers/soc/fsl/dpio/dpio-service.c @@ -6,7 +6,7 @@ */ #include <linux/types.h> #include <linux/fsl/mc.h> -#include "../../include/dpaa2-io.h" +#include <soc/fsl/dpaa2-io.h> #include <linux/init.h> #include <linux/module.h> #include <linux/platform_device.h> diff --git a/drivers/staging/fsl-mc/bus/dpio/dpio.c b/drivers/soc/fsl/dpio/dpio.c index ff37c80e11a0..ff37c80e11a0 100644 --- a/drivers/staging/fsl-mc/bus/dpio/dpio.c +++ b/drivers/soc/fsl/dpio/dpio.c diff --git a/drivers/staging/fsl-mc/bus/dpio/dpio.h b/drivers/soc/fsl/dpio/dpio.h index 49194c8e45f1..49194c8e45f1 100644 --- a/drivers/staging/fsl-mc/bus/dpio/dpio.h +++ b/drivers/soc/fsl/dpio/dpio.h diff --git a/drivers/staging/fsl-mc/bus/dpio/qbman-portal.c b/drivers/soc/fsl/dpio/qbman-portal.c index 116fafb28640..cf1d448ea468 100644 --- a/drivers/staging/fsl-mc/bus/dpio/qbman-portal.c +++ b/drivers/soc/fsl/dpio/qbman-portal.c @@ -8,7 +8,7 @@ #include <asm/cacheflush.h> #include <linux/io.h> #include <linux/slab.h> -#include "../../include/dpaa2-global.h" +#include <soc/fsl/dpaa2-global.h> #include "qbman-portal.h" diff --git a/drivers/staging/fsl-mc/bus/dpio/qbman-portal.h b/drivers/soc/fsl/dpio/qbman-portal.h index 69db3c818742..89d1dd9969b6 100644 --- a/drivers/staging/fsl-mc/bus/dpio/qbman-portal.h +++ b/drivers/soc/fsl/dpio/qbman-portal.h @@ -7,7 +7,7 @@ #ifndef __FSL_QBMAN_PORTAL_H #define __FSL_QBMAN_PORTAL_H -#include "../../include/dpaa2-fd.h" +#include <soc/fsl/dpaa2-fd.h> struct dpaa2_dq; struct qbman_swp; diff --git a/drivers/soc/fsl/qbman/Kconfig b/drivers/soc/fsl/qbman/Kconfig index fb4e6bf0a0c4..d570cb5fd381 100644 --- a/drivers/soc/fsl/qbman/Kconfig +++ b/drivers/soc/fsl/qbman/Kconfig @@ -1,5 +1,5 @@ menuconfig FSL_DPAA - bool "Freescale DPAA 1.x support" + bool "QorIQ DPAA1 framework support" depends on (FSL_SOC_BOOKE || ARCH_LAYERSCAPE) select GENERIC_ALLOCATOR help diff --git a/drivers/soc/fsl/qe/Kconfig b/drivers/soc/fsl/qe/Kconfig index 73a2e08b47ef..fabba17e9d65 100644 --- a/drivers/soc/fsl/qe/Kconfig +++ b/drivers/soc/fsl/qe/Kconfig @@ -3,7 +3,7 @@ # config QUICC_ENGINE - bool "Freescale QUICC Engine (QE) Support" + bool "QUICC Engine (QE) framework support" depends on FSL_SOC && PPC32 select GENERIC_ALLOCATOR select CRC32 diff --git a/drivers/soc/fsl/qe/gpio.c b/drivers/soc/fsl/qe/gpio.c index 3b27075c21a7..819bed0f5667 100644 --- a/drivers/soc/fsl/qe/gpio.c +++ b/drivers/soc/fsl/qe/gpio.c @@ -83,6 +83,33 @@ static void qe_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val) spin_unlock_irqrestore(&qe_gc->lock, flags); } +static void qe_gpio_set_multiple(struct gpio_chip *gc, + unsigned long *mask, unsigned long *bits) +{ + struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); + struct qe_gpio_chip *qe_gc = gpiochip_get_data(gc); + struct qe_pio_regs __iomem *regs = mm_gc->regs; + unsigned long flags; + int i; + + spin_lock_irqsave(&qe_gc->lock, flags); + + for (i = 0; i < gc->ngpio; i++) { + if (*mask == 0) + break; + if (__test_and_clear_bit(i, mask)) { + if (test_bit(i, bits)) + qe_gc->cpdata |= (1U << (QE_PIO_PINS - 1 - i)); + else + qe_gc->cpdata &= ~(1U << (QE_PIO_PINS - 1 - i)); + } + } + + out_be32(®s->cpdata, qe_gc->cpdata); + + spin_unlock_irqrestore(&qe_gc->lock, flags); +} + static int qe_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio) { struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); @@ -298,6 +325,7 @@ static int __init qe_add_gpiochips(void) gc->direction_output = qe_gpio_dir_out; gc->get = qe_gpio_get; gc->set = qe_gpio_set; + gc->set_multiple = qe_gpio_set_multiple; ret = of_mm_gpiochip_add_data(np, mm_gc, qe_gc); if (ret) diff --git a/drivers/soc/imx/gpc.c b/drivers/soc/imx/gpc.c index 546960a18d60..b3da635970ea 100644 --- a/drivers/soc/imx/gpc.c +++ b/drivers/soc/imx/gpc.c @@ -54,7 +54,6 @@ struct imx_pm_domain { unsigned int reg_offs; signed char cntr_pdn_bit; unsigned int ipg_rate_mhz; - unsigned int flags; }; static inline struct imx_pm_domain * @@ -69,9 +68,6 @@ static int imx6_pm_domain_power_off(struct generic_pm_domain *genpd) int iso, iso2sw; u32 val; - if (pd->flags & PGC_DOMAIN_FLAG_NO_PD) - return -EBUSY; - /* Read ISO and ISO2SW power down delays */ regmap_read(pd->regmap, pd->reg_offs + GPC_PGC_PUPSCR_OFFS, &val); iso = val & 0x3f; @@ -295,26 +291,31 @@ static struct imx_pm_domain imx_gpc_domains[] = { struct imx_gpc_dt_data { int num_domains; bool err009619_present; + bool err006287_present; }; static const struct imx_gpc_dt_data imx6q_dt_data = { .num_domains = 2, .err009619_present = false, + .err006287_present = false, }; static const struct imx_gpc_dt_data imx6qp_dt_data = { .num_domains = 2, .err009619_present = true, + .err006287_present = false, }; static const struct imx_gpc_dt_data imx6sl_dt_data = { .num_domains = 3, .err009619_present = false, + .err006287_present = true, }; static const struct imx_gpc_dt_data imx6sx_dt_data = { .num_domains = 4, .err009619_present = false, + .err006287_present = false, }; static const struct of_device_id imx_gpc_dt_ids[] = { @@ -434,8 +435,13 @@ static int imx_gpc_probe(struct platform_device *pdev) /* Disable PU power down in normal operation if ERR009619 is present */ if (of_id_data->err009619_present) - imx_gpc_domains[GPC_PGC_DOMAIN_PU].flags |= - PGC_DOMAIN_FLAG_NO_PD; + imx_gpc_domains[GPC_PGC_DOMAIN_PU].base.flags |= + GENPD_FLAG_ALWAYS_ON; + + /* Keep DISP always on if ERR006287 is present */ + if (of_id_data->err006287_present) + imx_gpc_domains[GPC_PGC_DOMAIN_DISPLAY].base.flags |= + GENPD_FLAG_ALWAYS_ON; if (!pgc_node) { ret = imx_gpc_old_dt_init(&pdev->dev, regmap, diff --git a/drivers/soc/mediatek/mtk-pmic-wrap.c b/drivers/soc/mediatek/mtk-pmic-wrap.c index 2afae64061d8..4e931fdf4d09 100644 --- a/drivers/soc/mediatek/mtk-pmic-wrap.c +++ b/drivers/soc/mediatek/mtk-pmic-wrap.c @@ -146,6 +146,21 @@ static const u32 mt6397_regs[] = { [PWRAP_DEW_CIPHER_SWRST] = 0xbc24, }; +static const u32 mt6351_regs[] = { + [PWRAP_DEW_DIO_EN] = 0x02F2, + [PWRAP_DEW_READ_TEST] = 0x02F4, + [PWRAP_DEW_WRITE_TEST] = 0x02F6, + [PWRAP_DEW_CRC_EN] = 0x02FA, + [PWRAP_DEW_CRC_VAL] = 0x02FC, + [PWRAP_DEW_CIPHER_KEY_SEL] = 0x0300, + [PWRAP_DEW_CIPHER_IV_SEL] = 0x0302, + [PWRAP_DEW_CIPHER_EN] = 0x0304, + [PWRAP_DEW_CIPHER_RDY] = 0x0306, + [PWRAP_DEW_CIPHER_MODE] = 0x0308, + [PWRAP_DEW_CIPHER_SWRST] = 0x030A, + [PWRAP_DEW_RDDMY_NO] = 0x030C, +}; + enum pwrap_regs { PWRAP_MUX_SEL, PWRAP_WRAP_EN, @@ -366,6 +381,39 @@ static int mt2701_regs[] = { [PWRAP_ADC_RDATA_ADDR2] = 0x154, }; +static int mt6797_regs[] = { + [PWRAP_MUX_SEL] = 0x0, + [PWRAP_WRAP_EN] = 0x4, + [PWRAP_DIO_EN] = 0x8, + [PWRAP_SIDLY] = 0xC, + [PWRAP_RDDMY] = 0x10, + [PWRAP_CSHEXT_WRITE] = 0x18, + [PWRAP_CSHEXT_READ] = 0x1C, + [PWRAP_CSLEXT_START] = 0x20, + [PWRAP_CSLEXT_END] = 0x24, + [PWRAP_STAUPD_PRD] = 0x28, + [PWRAP_HARB_HPRIO] = 0x50, + [PWRAP_HIPRIO_ARB_EN] = 0x54, + [PWRAP_MAN_EN] = 0x60, + [PWRAP_MAN_CMD] = 0x64, + [PWRAP_WACS0_EN] = 0x70, + [PWRAP_WACS1_EN] = 0x84, + [PWRAP_WACS2_EN] = 0x98, + [PWRAP_INIT_DONE2] = 0x9C, + [PWRAP_WACS2_CMD] = 0xA0, + [PWRAP_WACS2_RDATA] = 0xA4, + [PWRAP_WACS2_VLDCLR] = 0xA8, + [PWRAP_INT_EN] = 0xC0, + [PWRAP_INT_FLG_RAW] = 0xC4, + [PWRAP_INT_FLG] = 0xC8, + [PWRAP_INT_CLR] = 0xCC, + [PWRAP_TIMER_EN] = 0xF4, + [PWRAP_WDT_UNIT] = 0xFC, + [PWRAP_WDT_SRC_EN] = 0x100, + [PWRAP_DCM_EN] = 0x1CC, + [PWRAP_DCM_DBC_PRD] = 0x1D4, +}; + static int mt7622_regs[] = { [PWRAP_MUX_SEL] = 0x0, [PWRAP_WRAP_EN] = 0x4, @@ -635,12 +683,14 @@ static int mt8135_regs[] = { enum pmic_type { PMIC_MT6323, + PMIC_MT6351, PMIC_MT6380, PMIC_MT6397, }; enum pwrap_type { PWRAP_MT2701, + PWRAP_MT6797, PWRAP_MT7622, PWRAP_MT8135, PWRAP_MT8173, @@ -1067,6 +1117,7 @@ static int pwrap_init_cipher(struct pmic_wrapper *wrp) pwrap_writel(wrp, 1, PWRAP_CIPHER_START); break; case PWRAP_MT2701: + case PWRAP_MT6797: case PWRAP_MT8173: pwrap_writel(wrp, 1, PWRAP_CIPHER_EN); break; @@ -1080,8 +1131,6 @@ static int pwrap_init_cipher(struct pmic_wrapper *wrp) pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_CIPHER_SWRST], 0x0); pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_CIPHER_KEY_SEL], 0x1); pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_CIPHER_IV_SEL], 0x2); - pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_CIPHER_LOAD], 0x1); - pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_CIPHER_START], 0x1); switch (wrp->slave->type) { case PMIC_MT6397: @@ -1091,6 +1140,7 @@ static int pwrap_init_cipher(struct pmic_wrapper *wrp) 0x1); break; case PMIC_MT6323: + case PMIC_MT6351: pwrap_write(wrp, wrp->slave->dew_regs[PWRAP_DEW_CIPHER_EN], 0x1); break; @@ -1367,6 +1417,15 @@ static const struct pwrap_slv_type pmic_mt6397 = { .pwrap_write = pwrap_write16, }; +static const struct pwrap_slv_type pmic_mt6351 = { + .dew_regs = mt6351_regs, + .type = PMIC_MT6351, + .regmap = &pwrap_regmap_config16, + .caps = 0, + .pwrap_read = pwrap_read16, + .pwrap_write = pwrap_write16, +}; + static const struct of_device_id of_slave_match_tbl[] = { { .compatible = "mediatek,mt6323", @@ -1381,6 +1440,9 @@ static const struct of_device_id of_slave_match_tbl[] = { .compatible = "mediatek,mt6397", .data = &pmic_mt6397, }, { + .compatible = "mediatek,mt6351", + .data = &pmic_mt6351, + }, { /* sentinel */ } }; @@ -1398,6 +1460,18 @@ static const struct pmic_wrapper_type pwrap_mt2701 = { .init_soc_specific = pwrap_mt2701_init_soc_specific, }; +static const struct pmic_wrapper_type pwrap_mt6797 = { + .regs = mt6797_regs, + .type = PWRAP_MT6797, + .arb_en_all = 0x01fff, + .int_en_all = 0xffffffc6, + .spi_w = PWRAP_MAN_CMD_SPI_WRITE, + .wdt_src = PWRAP_WDT_SRC_MASK_ALL, + .has_bridge = 0, + .init_reg_clock = pwrap_common_init_reg_clock, + .init_soc_specific = NULL, +}; + static const struct pmic_wrapper_type pwrap_mt7622 = { .regs = mt7622_regs, .type = PWRAP_MT7622, @@ -1439,6 +1513,9 @@ static const struct of_device_id of_pwrap_match_tbl[] = { .compatible = "mediatek,mt2701-pwrap", .data = &pwrap_mt2701, }, { + .compatible = "mediatek,mt6797-pwrap", + .data = &pwrap_mt6797, + }, { .compatible = "mediatek,mt7622-pwrap", .data = &pwrap_mt7622, }, { diff --git a/drivers/soc/renesas/Makefile b/drivers/soc/renesas/Makefile index 7dc0f20d7907..c37b0803c1b6 100644 --- a/drivers/soc/renesas/Makefile +++ b/drivers/soc/renesas/Makefile @@ -18,6 +18,9 @@ obj-$(CONFIG_SYSC_R8A77970) += r8a77970-sysc.o obj-$(CONFIG_SYSC_R8A77980) += r8a77980-sysc.o obj-$(CONFIG_SYSC_R8A77990) += r8a77990-sysc.o obj-$(CONFIG_SYSC_R8A77995) += r8a77995-sysc.o +ifdef CONFIG_SMP +obj-$(CONFIG_ARCH_R9A06G032) += r9a06g032-smp.o +endif # Family obj-$(CONFIG_RST_RCAR) += rcar-rst.o diff --git a/drivers/soc/renesas/r9a06g032-smp.c b/drivers/soc/renesas/r9a06g032-smp.c new file mode 100644 index 000000000000..a1926e8d73f2 --- /dev/null +++ b/drivers/soc/renesas/r9a06g032-smp.c @@ -0,0 +1,96 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * R9A06G032 Second CA7 enabler. + * + * Copyright (C) 2018 Renesas Electronics Europe Limited + * + * Michel Pollet <michel.pollet@bp.renesas.com>, <buserror@gmail.com> + * Derived from actions,s500-smp + */ + +#include <linux/io.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/smp.h> + +/* + * The second CPU is parked in ROM at boot time. It requires waking it after + * writing an address into the BOOTADDR register of sysctrl. + * + * So the default value of the "cpu-release-addr" corresponds to BOOTADDR... + * + * *However* the BOOTADDR register is not available when the kernel + * starts in NONSEC mode. + * + * So for NONSEC mode, the bootloader re-parks the second CPU into a pen + * in SRAM, and changes the "cpu-release-addr" of linux's DT to a SRAM address, + * which is not restricted. + */ + +static void __iomem *cpu_bootaddr; + +static DEFINE_SPINLOCK(cpu_lock); + +static int +r9a06g032_smp_boot_secondary(unsigned int cpu, + struct task_struct *idle) +{ + if (!cpu_bootaddr) + return -ENODEV; + + spin_lock(&cpu_lock); + + writel(__pa_symbol(secondary_startup), cpu_bootaddr); + arch_send_wakeup_ipi_mask(cpumask_of(cpu)); + + spin_unlock(&cpu_lock); + + return 0; +} + +static void __init r9a06g032_smp_prepare_cpus(unsigned int max_cpus) +{ + struct device_node *dn; + int ret = -EINVAL, dns; + u32 bootaddr; + + dn = of_get_cpu_node(1, NULL); + if (!dn) { + pr_err("CPU#1: missing device tree node\n"); + return; + } + /* + * Determine the address from which the CPU is polling. + * The bootloader *does* change this property. + * Note: The property can be either 64 or 32 bits, so handle both cases + */ + if (of_find_property(dn, "cpu-release-addr", &dns)) { + if (dns == sizeof(u64)) { + u64 temp; + + ret = of_property_read_u64(dn, + "cpu-release-addr", &temp); + bootaddr = temp; + } else { + ret = of_property_read_u32(dn, + "cpu-release-addr", + &bootaddr); + } + } + of_node_put(dn); + if (ret) { + pr_err("CPU#1: invalid cpu-release-addr property\n"); + return; + } + pr_info("CPU#1: cpu-release-addr %08x\n", bootaddr); + + cpu_bootaddr = ioremap(bootaddr, sizeof(bootaddr)); +} + +static const struct smp_operations r9a06g032_smp_ops __initconst = { + .smp_prepare_cpus = r9a06g032_smp_prepare_cpus, + .smp_boot_secondary = r9a06g032_smp_boot_secondary, +}; + +CPU_METHOD_OF_DECLARE(r9a06g032_smp, + "renesas,r9a06g032-smp", &r9a06g032_smp_ops); diff --git a/drivers/soc/renesas/rcar-sysc.c b/drivers/soc/renesas/rcar-sysc.c index 50d03d8b4f9a..029188e8be6e 100644 --- a/drivers/soc/renesas/rcar-sysc.c +++ b/drivers/soc/renesas/rcar-sysc.c @@ -58,6 +58,12 @@ #define RCAR_PD_ALWAYS_ON 32 /* Always-on power area */ +struct rcar_sysc_ch { + u16 chan_offs; + u8 chan_bit; + u8 isr_bit; +}; + static void __iomem *rcar_sysc_base; static DEFINE_SPINLOCK(rcar_sysc_lock); /* SMP CPUs + I/O devices */ @@ -143,12 +149,12 @@ static int rcar_sysc_power(const struct rcar_sysc_ch *sysc_ch, bool on) return ret; } -int rcar_sysc_power_down(const struct rcar_sysc_ch *sysc_ch) +static int rcar_sysc_power_down(const struct rcar_sysc_ch *sysc_ch) { return rcar_sysc_power(sysc_ch, false); } -int rcar_sysc_power_up(const struct rcar_sysc_ch *sysc_ch) +static int rcar_sysc_power_up(const struct rcar_sysc_ch *sysc_ch) { return rcar_sysc_power(sysc_ch, true); } @@ -315,6 +321,8 @@ struct rcar_pm_domains { struct generic_pm_domain *domains[RCAR_PD_ALWAYS_ON + 1]; }; +static struct genpd_onecell_data *rcar_sysc_onecell_data; + static int __init rcar_sysc_pd_init(void) { const struct rcar_sysc_info *info; @@ -326,9 +334,6 @@ static int __init rcar_sysc_pd_init(void) unsigned int i; int error; - if (rcar_sysc_base) - return 0; - np = of_find_matching_node_and_match(NULL, rcar_sysc_matches, &match); if (!np) return -ENODEV; @@ -361,6 +366,7 @@ static int __init rcar_sysc_pd_init(void) domains->onecell_data.domains = domains->domains; domains->onecell_data.num_domains = ARRAY_SIZE(domains->domains); + rcar_sysc_onecell_data = &domains->onecell_data; for (i = 0, syscier = 0; i < info->num_areas; i++) syscier |= BIT(info->areas[i].isr_bit); @@ -448,27 +454,39 @@ void __init rcar_sysc_nullify(struct rcar_sysc_area *areas, } } -void __init rcar_sysc_init(phys_addr_t base, u32 syscier) +#ifdef CONFIG_ARCH_R8A7779 +static int rcar_sysc_power_cpu(unsigned int idx, bool on) { - u32 syscimr; + struct generic_pm_domain *genpd; + struct rcar_sysc_pd *pd; + unsigned int i; - if (!rcar_sysc_pd_init()) - return; + if (!rcar_sysc_onecell_data) + return -ENODEV; - rcar_sysc_base = ioremap_nocache(base, PAGE_SIZE); + for (i = 0; i < rcar_sysc_onecell_data->num_domains; i++) { + genpd = rcar_sysc_onecell_data->domains[i]; + if (!genpd) + continue; - /* - * Mask all interrupt sources to prevent the CPU from receiving them. - * Make sure not to clear reserved bits that were set before. - */ - syscimr = ioread32(rcar_sysc_base + SYSCIMR); - syscimr |= syscier; - pr_debug("%s: syscimr = 0x%08x\n", __func__, syscimr); - iowrite32(syscimr, rcar_sysc_base + SYSCIMR); + pd = to_rcar_pd(genpd); + if (!(pd->flags & PD_CPU) || pd->ch.chan_bit != idx) + continue; - /* - * SYSC needs all interrupt sources enabled to control power. - */ - pr_debug("%s: syscier = 0x%08x\n", __func__, syscier); - iowrite32(syscier, rcar_sysc_base + SYSCIER); + return on ? rcar_sysc_power_up(&pd->ch) + : rcar_sysc_power_down(&pd->ch); + } + + return -ENOENT; +} + +int rcar_sysc_power_down_cpu(unsigned int cpu) +{ + return rcar_sysc_power_cpu(cpu, false); +} + +int rcar_sysc_power_up_cpu(unsigned int cpu) +{ + return rcar_sysc_power_cpu(cpu, true); } +#endif /* CONFIG_ARCH_R8A7779 */ diff --git a/drivers/soc/sunxi/sunxi_sram.c b/drivers/soc/sunxi/sunxi_sram.c index 882be5ed7e84..b4b0f3480bd3 100644 --- a/drivers/soc/sunxi/sunxi_sram.c +++ b/drivers/soc/sunxi/sunxi_sram.c @@ -17,6 +17,7 @@ #include <linux/of_address.h> #include <linux/of_device.h> #include <linux/platform_device.h> +#include <linux/regmap.h> #include <linux/soc/sunxi/sunxi_sram.h> @@ -63,6 +64,12 @@ static struct sunxi_sram_desc sun4i_a10_sram_a3_a4 = { SUNXI_SRAM_MAP(1, 1, "emac")), }; +static struct sunxi_sram_desc sun4i_a10_sram_c1 = { + .data = SUNXI_SRAM_DATA("C1", 0x0, 0x0, 31, + SUNXI_SRAM_MAP(0, 0, "cpu"), + SUNXI_SRAM_MAP(0x7fffffff, 1, "ve")), +}; + static struct sunxi_sram_desc sun4i_a10_sram_d = { .data = SUNXI_SRAM_DATA("D", 0x4, 0x0, 1, SUNXI_SRAM_MAP(0, 0, "cpu"), @@ -81,6 +88,10 @@ static const struct of_device_id sunxi_sram_dt_ids[] = { .data = &sun4i_a10_sram_a3_a4.data, }, { + .compatible = "allwinner,sun4i-a10-sram-c1", + .data = &sun4i_a10_sram_c1.data, + }, + { .compatible = "allwinner,sun4i-a10-sram-d", .data = &sun4i_a10_sram_d.data, }, @@ -281,13 +292,51 @@ int sunxi_sram_release(struct device *dev) } EXPORT_SYMBOL(sunxi_sram_release); +struct sunxi_sramc_variant { + bool has_emac_clock; +}; + +static const struct sunxi_sramc_variant sun4i_a10_sramc_variant = { + /* Nothing special */ +}; + +static const struct sunxi_sramc_variant sun50i_a64_sramc_variant = { + .has_emac_clock = true, +}; + +#define SUNXI_SRAM_EMAC_CLOCK_REG 0x30 +static bool sunxi_sram_regmap_accessible_reg(struct device *dev, + unsigned int reg) +{ + if (reg == SUNXI_SRAM_EMAC_CLOCK_REG) + return true; + return false; +} + +static struct regmap_config sunxi_sram_emac_clock_regmap = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, + /* last defined register */ + .max_register = SUNXI_SRAM_EMAC_CLOCK_REG, + /* other devices have no business accessing other registers */ + .readable_reg = sunxi_sram_regmap_accessible_reg, + .writeable_reg = sunxi_sram_regmap_accessible_reg, +}; + static int sunxi_sram_probe(struct platform_device *pdev) { struct resource *res; struct dentry *d; + struct regmap *emac_clock; + const struct sunxi_sramc_variant *variant; sram_dev = &pdev->dev; + variant = of_device_get_match_data(&pdev->dev); + if (!variant) + return -EINVAL; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(base)) @@ -300,12 +349,46 @@ static int sunxi_sram_probe(struct platform_device *pdev) if (!d) return -ENOMEM; + if (variant->has_emac_clock) { + emac_clock = devm_regmap_init_mmio(&pdev->dev, base, + &sunxi_sram_emac_clock_regmap); + + if (IS_ERR(emac_clock)) + return PTR_ERR(emac_clock); + } + return 0; } static const struct of_device_id sunxi_sram_dt_match[] = { - { .compatible = "allwinner,sun4i-a10-sram-controller" }, - { .compatible = "allwinner,sun50i-a64-sram-controller" }, + { + .compatible = "allwinner,sun4i-a10-sram-controller", + .data = &sun4i_a10_sramc_variant, + }, + { + .compatible = "allwinner,sun4i-a10-system-control", + .data = &sun4i_a10_sramc_variant, + }, + { + .compatible = "allwinner,sun5i-a13-system-control", + .data = &sun4i_a10_sramc_variant, + }, + { + .compatible = "allwinner,sun8i-a23-system-control", + .data = &sun4i_a10_sramc_variant, + }, + { + .compatible = "allwinner,sun8i-h3-system-control", + .data = &sun4i_a10_sramc_variant, + }, + { + .compatible = "allwinner,sun50i-a64-sram-controller", + .data = &sun50i_a64_sramc_variant, + }, + { + .compatible = "allwinner,sun50i-a64-system-control", + .data = &sun50i_a64_sramc_variant, + }, { }, }; MODULE_DEVICE_TABLE(of, sunxi_sram_dt_match); diff --git a/drivers/soc/ti/Kconfig b/drivers/soc/ti/Kconfig index 92770d84a288..be4570baad96 100644 --- a/drivers/soc/ti/Kconfig +++ b/drivers/soc/ti/Kconfig @@ -1,3 +1,17 @@ +# 64-bit ARM SoCs from TI +if ARM64 + +if ARCH_K3 + +config ARCH_K3_AM6_SOC + bool "K3 AM6 SoC" + help + Enable support for TI's AM6 SoC Family support + +endif + +endif + # # TI SOC drivers # diff --git a/drivers/soc/ti/pm33xx.c b/drivers/soc/ti/pm33xx.c index 652739c7f718..d0dab323651f 100644 --- a/drivers/soc/ti/pm33xx.c +++ b/drivers/soc/ti/pm33xx.c @@ -41,6 +41,8 @@ static struct am33xx_pm_sram_addr *pm_sram; static struct device *pm33xx_dev; static struct wkup_m3_ipc *m3_ipc; +static unsigned long suspend_wfi_flags; + static u32 sram_suspend_address(unsigned long addr) { return ((unsigned long)am33xx_do_wfi_sram + @@ -53,7 +55,7 @@ static int am33xx_pm_suspend(suspend_state_t suspend_state) int i, ret = 0; ret = pm_ops->soc_suspend((unsigned long)suspend_state, - am33xx_do_wfi_sram); + am33xx_do_wfi_sram, suspend_wfi_flags); if (ret) { dev_err(pm33xx_dev, "PM: Kernel suspend failure\n"); @@ -227,6 +229,7 @@ static int am33xx_push_sram_idle(void) ro_sram_data.amx3_pm_sram_data_virt = ocmcram_location_data; ro_sram_data.amx3_pm_sram_data_phys = gen_pool_virt_to_phys(sram_pool_data, ocmcram_location_data); + ro_sram_data.rtc_base_virt = pm_ops->get_rtc_base_addr(); /* Save physical address to calculate resume offset during pm init */ am33xx_do_wfi_sram_phys = gen_pool_virt_to_phys(sram_pool, @@ -310,6 +313,17 @@ static int am33xx_pm_probe(struct platform_device *pdev) suspend_set_ops(&am33xx_pm_ops); #endif /* CONFIG_SUSPEND */ + /* + * For a system suspend we must flush the caches, we want + * the DDR in self-refresh, we want to save the context + * of the EMIF, and we want the wkup_m3 to handle low-power + * transition. + */ + suspend_wfi_flags |= WFI_FLAG_FLUSH_CACHE; + suspend_wfi_flags |= WFI_FLAG_SELF_REFRESH; + suspend_wfi_flags |= WFI_FLAG_SAVE_EMIF; + suspend_wfi_flags |= WFI_FLAG_WAKE_M3; + ret = pm_ops->init(); if (ret) { dev_err(dev, "Unable to call core pm init!\n"); diff --git a/drivers/soc/ti/wkup_m3_ipc.c b/drivers/soc/ti/wkup_m3_ipc.c index 369aef5e7228..f5cb8c0af09f 100644 --- a/drivers/soc/ti/wkup_m3_ipc.c +++ b/drivers/soc/ti/wkup_m3_ipc.c @@ -46,6 +46,7 @@ #define M3_BASELINE_VERSION 0x191 #define M3_STATUS_RESP_MASK (0xffff << 16) #define M3_FW_VERSION_MASK 0xffff +#define M3_WAKE_SRC_MASK 0xff #define M3_STATE_UNKNOWN 0 #define M3_STATE_RESET 1 @@ -55,6 +56,23 @@ static struct wkup_m3_ipc *m3_ipc_state; +static const struct wkup_m3_wakeup_src wakeups[] = { + {.irq_nr = 35, .src = "USB0_PHY"}, + {.irq_nr = 36, .src = "USB1_PHY"}, + {.irq_nr = 40, .src = "I2C0"}, + {.irq_nr = 41, .src = "RTC Timer"}, + {.irq_nr = 42, .src = "RTC Alarm"}, + {.irq_nr = 43, .src = "Timer0"}, + {.irq_nr = 44, .src = "Timer1"}, + {.irq_nr = 45, .src = "UART"}, + {.irq_nr = 46, .src = "GPIO0"}, + {.irq_nr = 48, .src = "MPU_WAKE"}, + {.irq_nr = 49, .src = "WDT0"}, + {.irq_nr = 50, .src = "WDT1"}, + {.irq_nr = 51, .src = "ADC_TSC"}, + {.irq_nr = 0, .src = "Unknown"}, +}; + static void am33xx_txev_eoi(struct wkup_m3_ipc *m3_ipc) { writel(AM33XX_M3_TXEV_ACK, @@ -329,12 +347,45 @@ static int wkup_m3_finish_low_power(struct wkup_m3_ipc *m3_ipc) return 0; } +/** + * wkup_m3_request_wake_src - Get the wakeup source info passed from wkup_m3 + * @m3_ipc: Pointer to wkup_m3_ipc context + */ +static const char *wkup_m3_request_wake_src(struct wkup_m3_ipc *m3_ipc) +{ + unsigned int wakeup_src_idx; + int j, val; + + val = wkup_m3_ctrl_ipc_read(m3_ipc, 6); + + wakeup_src_idx = val & M3_WAKE_SRC_MASK; + + for (j = 0; j < ARRAY_SIZE(wakeups) - 1; j++) { + if (wakeups[j].irq_nr == wakeup_src_idx) + return wakeups[j].src; + } + return wakeups[j].src; +} + +/** + * wkup_m3_set_rtc_only - Set the rtc_only flag + * @wkup_m3_wakeup: struct wkup_m3_wakeup_src * gets assigned the + * wakeup src value + */ +static void wkup_m3_set_rtc_only(struct wkup_m3_ipc *m3_ipc) +{ + if (m3_ipc_state) + m3_ipc_state->is_rtc_only = true; +} + static struct wkup_m3_ipc_ops ipc_ops = { .set_mem_type = wkup_m3_set_mem_type, .set_resume_address = wkup_m3_set_resume_address, .prepare_low_power = wkup_m3_prepare_low_power, .finish_low_power = wkup_m3_finish_low_power, .request_pm_status = wkup_m3_request_pm_status, + .request_wake_src = wkup_m3_request_wake_src, + .set_rtc_only = wkup_m3_set_rtc_only, }; /** @@ -484,6 +535,30 @@ static int wkup_m3_ipc_remove(struct platform_device *pdev) return 0; } +static int __maybe_unused wkup_m3_ipc_suspend(struct device *dev) +{ + /* + * Nothing needs to be done on suspend even with rtc_only flag set + */ + return 0; +} + +static int __maybe_unused wkup_m3_ipc_resume(struct device *dev) +{ + if (m3_ipc_state->is_rtc_only) { + rproc_shutdown(m3_ipc_state->rproc); + rproc_boot(m3_ipc_state->rproc); + } + + m3_ipc_state->is_rtc_only = false; + + return 0; +} + +static const struct dev_pm_ops wkup_m3_ipc_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(wkup_m3_ipc_suspend, wkup_m3_ipc_resume) +}; + static const struct of_device_id wkup_m3_ipc_of_match[] = { { .compatible = "ti,am3352-wkup-m3-ipc", }, { .compatible = "ti,am4372-wkup-m3-ipc", }, @@ -497,6 +572,7 @@ static struct platform_driver wkup_m3_ipc_driver = { .driver = { .name = "wkup_m3_ipc", .of_match_table = wkup_m3_ipc_of_match, + .pm = &wkup_m3_ipc_pm_ops, }, }; diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index 396fb3d56398..1abf76be2aa8 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -90,8 +90,6 @@ source "drivers/staging/clocking-wizard/Kconfig" source "drivers/staging/fbtft/Kconfig" -source "drivers/staging/fsl-mc/Kconfig" - source "drivers/staging/fsl-dpaa2/Kconfig" source "drivers/staging/wilc1000/Kconfig" diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index ad7b4ca412ef..ab0cbe8815b1 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -35,7 +35,6 @@ obj-$(CONFIG_GS_FPGABOOT) += gs_fpgaboot/ obj-$(CONFIG_UNISYSSPAR) += unisys/ obj-$(CONFIG_COMMON_CLK_XLNX_CLKWZRD) += clocking-wizard/ obj-$(CONFIG_FB_TFT) += fbtft/ -obj-$(CONFIG_FSL_MC_BUS) += fsl-mc/ obj-$(CONFIG_FSL_DPAA2) += fsl-dpaa2/ obj-$(CONFIG_WILC1000) += wilc1000/ obj-$(CONFIG_MOST) += most/ diff --git a/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c b/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c index e2dac44eccbe..9329fcad95ac 100644 --- a/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c +++ b/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.c @@ -426,7 +426,7 @@ static int build_sg_fd(struct dpaa2_eth_priv *priv, dpaa2_fd_set_format(fd, dpaa2_fd_sg); dpaa2_fd_set_addr(fd, addr); dpaa2_fd_set_len(fd, skb->len); - dpaa2_fd_set_ctrl(fd, DPAA2_FD_CTRL_PTA | DPAA2_FD_CTRL_PTV1); + dpaa2_fd_set_ctrl(fd, FD_CTRL_PTA | FD_CTRL_PTV1); if (priv->tx_tstamp && skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) enable_tx_tstamp(fd, sgt_buf); @@ -479,7 +479,7 @@ static int build_single_fd(struct dpaa2_eth_priv *priv, dpaa2_fd_set_offset(fd, (u16)(skb->data - buffer_start)); dpaa2_fd_set_len(fd, skb->len); dpaa2_fd_set_format(fd, dpaa2_fd_single); - dpaa2_fd_set_ctrl(fd, DPAA2_FD_CTRL_PTA | DPAA2_FD_CTRL_PTV1); + dpaa2_fd_set_ctrl(fd, FD_CTRL_PTA | FD_CTRL_PTV1); if (priv->tx_tstamp && skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) enable_tx_tstamp(fd, buffer_start); diff --git a/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.h b/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.h index 506466778b2c..d54cb0b99d08 100644 --- a/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.h +++ b/drivers/staging/fsl-dpaa2/ethernet/dpaa2-eth.h @@ -10,8 +10,8 @@ #include <linux/if_vlan.h> #include <linux/fsl/mc.h> -#include "../../fsl-mc/include/dpaa2-io.h" -#include "../../fsl-mc/include/dpaa2-fd.h" +#include <soc/fsl/dpaa2-io.h> +#include <soc/fsl/dpaa2-fd.h> #include "dpni.h" #include "dpni-cmd.h" @@ -97,21 +97,13 @@ struct dpaa2_eth_swa { #define DPAA2_FD_FRC_FAICFDV 0x0400 /* Error bits in FD CTRL */ -#define DPAA2_FD_CTRL_UFD 0x00000004 -#define DPAA2_FD_CTRL_SBE 0x00000008 -#define DPAA2_FD_CTRL_FSE 0x00000020 -#define DPAA2_FD_CTRL_FAERR 0x00000040 - -#define DPAA2_FD_RX_ERR_MASK (DPAA2_FD_CTRL_SBE | \ - DPAA2_FD_CTRL_FAERR) -#define DPAA2_FD_TX_ERR_MASK (DPAA2_FD_CTRL_UFD | \ - DPAA2_FD_CTRL_SBE | \ - DPAA2_FD_CTRL_FSE | \ - DPAA2_FD_CTRL_FAERR) +#define DPAA2_FD_RX_ERR_MASK (FD_CTRL_SBE | FD_CTRL_FAERR) +#define DPAA2_FD_TX_ERR_MASK (FD_CTRL_UFD | \ + FD_CTRL_SBE | \ + FD_CTRL_FSE | \ + FD_CTRL_FAERR) /* Annotation bits in FD CTRL */ -#define DPAA2_FD_CTRL_PTA 0x00800000 -#define DPAA2_FD_CTRL_PTV1 0x00400000 #define DPAA2_FD_CTRL_ASAL 0x00020000 /* ASAL = 128B */ /* Frame annotation status */ diff --git a/drivers/staging/fsl-mc/Kconfig b/drivers/staging/fsl-mc/Kconfig deleted file mode 100644 index 3002229bec1b..000000000000 --- a/drivers/staging/fsl-mc/Kconfig +++ /dev/null @@ -1,2 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -source "drivers/staging/fsl-mc/bus/Kconfig" diff --git a/drivers/staging/fsl-mc/Makefile b/drivers/staging/fsl-mc/Makefile deleted file mode 100644 index 14683889dabd..000000000000 --- a/drivers/staging/fsl-mc/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# Freescale Management Complex (MC) bus drivers -obj-$(CONFIG_FSL_MC_BUS) += bus/ diff --git a/drivers/staging/fsl-mc/bus/Kconfig b/drivers/staging/fsl-mc/bus/Kconfig deleted file mode 100644 index 342453035269..000000000000 --- a/drivers/staging/fsl-mc/bus/Kconfig +++ /dev/null @@ -1,16 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# -# DPAA2 fsl-mc bus -# -# Copyright (C) 2014-2016 Freescale Semiconductor, Inc. -# - -config FSL_MC_DPIO - tristate "QorIQ DPAA2 DPIO driver" - depends on FSL_MC_BUS - help - Driver for the DPAA2 DPIO object. A DPIO provides queue and - buffer management facilities for software to interact with - other DPAA2 objects. This driver does not expose the DPIO - objects individually, but groups them under a service layer - API. diff --git a/drivers/staging/fsl-mc/bus/Makefile b/drivers/staging/fsl-mc/bus/Makefile deleted file mode 100644 index 21d8ebc8ce21..000000000000 --- a/drivers/staging/fsl-mc/bus/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# -# Freescale Management Complex (MC) bus drivers -# -# Copyright (C) 2014 Freescale Semiconductor, Inc. -# - -# MC DPIO driver -obj-$(CONFIG_FSL_MC_DPIO) += dpio/ diff --git a/drivers/staging/fsl-mc/bus/dpio/dpio-driver.txt b/drivers/staging/fsl-mc/bus/dpio/dpio-driver.txt deleted file mode 100644 index 72ba9da3d179..000000000000 --- a/drivers/staging/fsl-mc/bus/dpio/dpio-driver.txt +++ /dev/null @@ -1,135 +0,0 @@ -Copyright 2016 NXP - -Introduction ------------- - -A DPAA2 DPIO (Data Path I/O) is a hardware object that provides -interfaces to enqueue and dequeue frames to/from network interfaces -and other accelerators. A DPIO also provides hardware buffer -pool management for network interfaces. - -This document provides an overview the Linux DPIO driver, its -subcomponents, and its APIs. - -See Documentation/networking/dpaa2/overview.rst for a general overview of DPAA2 -and the general DPAA2 driver architecture in Linux. - -Driver Overview ---------------- - -The DPIO driver is bound to DPIO objects discovered on the fsl-mc bus and -provides services that: - A) allow other drivers, such as the Ethernet driver, to enqueue and dequeue - frames for their respective objects - B) allow drivers to register callbacks for data availability notifications - when data becomes available on a queue or channel - C) allow drivers to manage hardware buffer pools - -The Linux DPIO driver consists of 3 primary components-- - DPIO object driver-- fsl-mc driver that manages the DPIO object - DPIO service-- provides APIs to other Linux drivers for services - QBman portal interface-- sends portal commands, gets responses - - fsl-mc other - bus drivers - | | - +---+----+ +------+-----+ - |DPIO obj| |DPIO service| - | driver |---| (DPIO) | - +--------+ +------+-----+ - | - +------+-----+ - | QBman | - | portal i/f | - +------------+ - | - hardware - -The diagram below shows how the DPIO driver components fit with the other -DPAA2 Linux driver components: - +------------+ - | OS Network | - | Stack | - +------------+ +------------+ - | Allocator |. . . . . . . | Ethernet | - |(DPMCP,DPBP)| | (DPNI) | - +-.----------+ +---+---+----+ - . . ^ | - . . <data avail, | |<enqueue, - . . tx confirm> | | dequeue> - +-------------+ . | | - | DPRC driver | . +--------+ +------------+ - | (DPRC) | . . |DPIO obj| |DPIO service| - +----------+--+ | driver |-| (DPIO) | - | +--------+ +------+-----+ - |<dev add/remove> +------|-----+ - | | QBman | - +----+--------------+ | portal i/f | - | MC-bus driver | +------------+ - | | | - | /soc/fsl-mc | | - +-------------------+ | - | - =========================================|=========|======================== - +-+--DPIO---|-----------+ - | | | - | QBman Portal | - +-----------------------+ - - ============================================================================ - - -DPIO Object Driver (dpio-driver.c) ----------------------------------- - - The dpio-driver component registers with the fsl-mc bus to handle objects of - type "dpio". The implementation of probe() handles basic initialization - of the DPIO including mapping of the DPIO regions (the QBman SW portal) - and initializing interrupts and registering irq handlers. The dpio-driver - registers the probed DPIO with dpio-service. - -DPIO service (dpio-service.c, dpaa2-io.h) ------------------------------------------- - - The dpio service component provides queuing, notification, and buffers - management services to DPAA2 drivers, such as the Ethernet driver. A system - will typically allocate 1 DPIO object per CPU to allow queuing operations - to happen simultaneously across all CPUs. - - Notification handling - dpaa2_io_service_register() - dpaa2_io_service_deregister() - dpaa2_io_service_rearm() - - Queuing - dpaa2_io_service_pull_fq() - dpaa2_io_service_pull_channel() - dpaa2_io_service_enqueue_fq() - dpaa2_io_service_enqueue_qd() - dpaa2_io_store_create() - dpaa2_io_store_destroy() - dpaa2_io_store_next() - - Buffer pool management - dpaa2_io_service_release() - dpaa2_io_service_acquire() - -QBman portal interface (qbman-portal.c) ---------------------------------------- - - The qbman-portal component provides APIs to do the low level hardware - bit twiddling for operations such as: - -initializing Qman software portals - -building and sending portal commands - -portal interrupt configuration and processing - - The qbman-portal APIs are not public to other drivers, and are - only used by dpio-service. - -Other (dpaa2-fd.h, dpaa2-global.h) ----------------------------------- - - Frame descriptor and scatter-gather definitions and the APIs used to - manipulate them are defined in dpaa2-fd.h. - - Dequeue result struct and parsing APIs are defined in dpaa2-global.h. diff --git a/drivers/staging/fsl-mc/include/dpaa2-fd.h b/drivers/staging/fsl-mc/include/dpaa2-fd.h deleted file mode 100644 index b55b89ba4eda..000000000000 --- a/drivers/staging/fsl-mc/include/dpaa2-fd.h +++ /dev/null @@ -1,426 +0,0 @@ -/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */ -/* - * Copyright 2014-2016 Freescale Semiconductor Inc. - * Copyright 2016 NXP - * - */ -#ifndef __FSL_DPAA2_FD_H -#define __FSL_DPAA2_FD_H - -#include <linux/kernel.h> - -/** - * DOC: DPAA2 FD - Frame Descriptor APIs for DPAA2 - * - * Frame Descriptors (FDs) are used to describe frame data in the DPAA2. - * Frames can be enqueued and dequeued to Frame Queues (FQs) which are consumed - * by the various DPAA accelerators (WRIOP, SEC, PME, DCE) - * - * There are three types of frames: single, scatter gather, and frame lists. - * - * The set of APIs in this file must be used to create, manipulate and - * query Frame Descriptors. - */ - -/** - * struct dpaa2_fd - Struct describing FDs - * @words: for easier/faster copying the whole FD structure - * @addr: address in the FD - * @len: length in the FD - * @bpid: buffer pool ID - * @format_offset: format, offset, and short-length fields - * @frc: frame context - * @ctrl: control bits...including dd, sc, va, err, etc - * @flc: flow context address - * - * This structure represents the basic Frame Descriptor used in the system. - */ -struct dpaa2_fd { - union { - u32 words[8]; - struct dpaa2_fd_simple { - __le64 addr; - __le32 len; - __le16 bpid; - __le16 format_offset; - __le32 frc; - __le32 ctrl; - __le64 flc; - } simple; - }; -}; - -#define FD_SHORT_LEN_FLAG_MASK 0x1 -#define FD_SHORT_LEN_FLAG_SHIFT 14 -#define FD_SHORT_LEN_MASK 0x3FFFF -#define FD_OFFSET_MASK 0x0FFF -#define FD_FORMAT_MASK 0x3 -#define FD_FORMAT_SHIFT 12 -#define FD_BPID_MASK 0x3FFF -#define SG_SHORT_LEN_FLAG_MASK 0x1 -#define SG_SHORT_LEN_FLAG_SHIFT 14 -#define SG_SHORT_LEN_MASK 0x1FFFF -#define SG_OFFSET_MASK 0x0FFF -#define SG_FORMAT_MASK 0x3 -#define SG_FORMAT_SHIFT 12 -#define SG_BPID_MASK 0x3FFF -#define SG_FINAL_FLAG_MASK 0x1 -#define SG_FINAL_FLAG_SHIFT 15 - -enum dpaa2_fd_format { - dpaa2_fd_single = 0, - dpaa2_fd_list, - dpaa2_fd_sg -}; - -/** - * dpaa2_fd_get_addr() - get the addr field of frame descriptor - * @fd: the given frame descriptor - * - * Return the address in the frame descriptor. - */ -static inline dma_addr_t dpaa2_fd_get_addr(const struct dpaa2_fd *fd) -{ - return (dma_addr_t)le64_to_cpu(fd->simple.addr); -} - -/** - * dpaa2_fd_set_addr() - Set the addr field of frame descriptor - * @fd: the given frame descriptor - * @addr: the address needs to be set in frame descriptor - */ -static inline void dpaa2_fd_set_addr(struct dpaa2_fd *fd, dma_addr_t addr) -{ - fd->simple.addr = cpu_to_le64(addr); -} - -/** - * dpaa2_fd_get_frc() - Get the frame context in the frame descriptor - * @fd: the given frame descriptor - * - * Return the frame context field in the frame descriptor. - */ -static inline u32 dpaa2_fd_get_frc(const struct dpaa2_fd *fd) -{ - return le32_to_cpu(fd->simple.frc); -} - -/** - * dpaa2_fd_set_frc() - Set the frame context in the frame descriptor - * @fd: the given frame descriptor - * @frc: the frame context needs to be set in frame descriptor - */ -static inline void dpaa2_fd_set_frc(struct dpaa2_fd *fd, u32 frc) -{ - fd->simple.frc = cpu_to_le32(frc); -} - -/** - * dpaa2_fd_get_ctrl() - Get the control bits in the frame descriptor - * @fd: the given frame descriptor - * - * Return the control bits field in the frame descriptor. - */ -static inline u32 dpaa2_fd_get_ctrl(const struct dpaa2_fd *fd) -{ - return le32_to_cpu(fd->simple.ctrl); -} - -/** - * dpaa2_fd_set_ctrl() - Set the control bits in the frame descriptor - * @fd: the given frame descriptor - * @ctrl: the control bits to be set in the frame descriptor - */ -static inline void dpaa2_fd_set_ctrl(struct dpaa2_fd *fd, u32 ctrl) -{ - fd->simple.ctrl = cpu_to_le32(ctrl); -} - -/** - * dpaa2_fd_get_flc() - Get the flow context in the frame descriptor - * @fd: the given frame descriptor - * - * Return the flow context in the frame descriptor. - */ -static inline dma_addr_t dpaa2_fd_get_flc(const struct dpaa2_fd *fd) -{ - return (dma_addr_t)le64_to_cpu(fd->simple.flc); -} - -/** - * dpaa2_fd_set_flc() - Set the flow context field of frame descriptor - * @fd: the given frame descriptor - * @flc_addr: the flow context needs to be set in frame descriptor - */ -static inline void dpaa2_fd_set_flc(struct dpaa2_fd *fd, dma_addr_t flc_addr) -{ - fd->simple.flc = cpu_to_le64(flc_addr); -} - -static inline bool dpaa2_fd_short_len(const struct dpaa2_fd *fd) -{ - return !!((le16_to_cpu(fd->simple.format_offset) >> - FD_SHORT_LEN_FLAG_SHIFT) & FD_SHORT_LEN_FLAG_MASK); -} - -/** - * dpaa2_fd_get_len() - Get the length in the frame descriptor - * @fd: the given frame descriptor - * - * Return the length field in the frame descriptor. - */ -static inline u32 dpaa2_fd_get_len(const struct dpaa2_fd *fd) -{ - if (dpaa2_fd_short_len(fd)) - return le32_to_cpu(fd->simple.len) & FD_SHORT_LEN_MASK; - - return le32_to_cpu(fd->simple.len); -} - -/** - * dpaa2_fd_set_len() - Set the length field of frame descriptor - * @fd: the given frame descriptor - * @len: the length needs to be set in frame descriptor - */ -static inline void dpaa2_fd_set_len(struct dpaa2_fd *fd, u32 len) -{ - fd->simple.len = cpu_to_le32(len); -} - -/** - * dpaa2_fd_get_offset() - Get the offset field in the frame descriptor - * @fd: the given frame descriptor - * - * Return the offset. - */ -static inline uint16_t dpaa2_fd_get_offset(const struct dpaa2_fd *fd) -{ - return le16_to_cpu(fd->simple.format_offset) & FD_OFFSET_MASK; -} - -/** - * dpaa2_fd_set_offset() - Set the offset field of frame descriptor - * @fd: the given frame descriptor - * @offset: the offset needs to be set in frame descriptor - */ -static inline void dpaa2_fd_set_offset(struct dpaa2_fd *fd, uint16_t offset) -{ - fd->simple.format_offset &= cpu_to_le16(~FD_OFFSET_MASK); - fd->simple.format_offset |= cpu_to_le16(offset); -} - -/** - * dpaa2_fd_get_format() - Get the format field in the frame descriptor - * @fd: the given frame descriptor - * - * Return the format. - */ -static inline enum dpaa2_fd_format dpaa2_fd_get_format( - const struct dpaa2_fd *fd) -{ - return (enum dpaa2_fd_format)((le16_to_cpu(fd->simple.format_offset) - >> FD_FORMAT_SHIFT) & FD_FORMAT_MASK); -} - -/** - * dpaa2_fd_set_format() - Set the format field of frame descriptor - * @fd: the given frame descriptor - * @format: the format needs to be set in frame descriptor - */ -static inline void dpaa2_fd_set_format(struct dpaa2_fd *fd, - enum dpaa2_fd_format format) -{ - fd->simple.format_offset &= - cpu_to_le16(~(FD_FORMAT_MASK << FD_FORMAT_SHIFT)); - fd->simple.format_offset |= cpu_to_le16(format << FD_FORMAT_SHIFT); -} - -/** - * dpaa2_fd_get_bpid() - Get the bpid field in the frame descriptor - * @fd: the given frame descriptor - * - * Return the buffer pool id. - */ -static inline uint16_t dpaa2_fd_get_bpid(const struct dpaa2_fd *fd) -{ - return le16_to_cpu(fd->simple.bpid) & FD_BPID_MASK; -} - -/** - * dpaa2_fd_set_bpid() - Set the bpid field of frame descriptor - * @fd: the given frame descriptor - * @bpid: buffer pool id to be set - */ -static inline void dpaa2_fd_set_bpid(struct dpaa2_fd *fd, uint16_t bpid) -{ - fd->simple.bpid &= cpu_to_le16(~(FD_BPID_MASK)); - fd->simple.bpid |= cpu_to_le16(bpid); -} - -/** - * struct dpaa2_sg_entry - the scatter-gathering structure - * @addr: address of the sg entry - * @len: length in this sg entry - * @bpid: buffer pool id - * @format_offset: format and offset fields - */ -struct dpaa2_sg_entry { - __le64 addr; - __le32 len; - __le16 bpid; - __le16 format_offset; -}; - -enum dpaa2_sg_format { - dpaa2_sg_single = 0, - dpaa2_sg_frame_data, - dpaa2_sg_sgt_ext -}; - -/* Accessors for SG entry fields */ - -/** - * dpaa2_sg_get_addr() - Get the address from SG entry - * @sg: the given scatter-gathering object - * - * Return the address. - */ -static inline dma_addr_t dpaa2_sg_get_addr(const struct dpaa2_sg_entry *sg) -{ - return (dma_addr_t)le64_to_cpu(sg->addr); -} - -/** - * dpaa2_sg_set_addr() - Set the address in SG entry - * @sg: the given scatter-gathering object - * @addr: the address to be set - */ -static inline void dpaa2_sg_set_addr(struct dpaa2_sg_entry *sg, dma_addr_t addr) -{ - sg->addr = cpu_to_le64(addr); -} - -static inline bool dpaa2_sg_short_len(const struct dpaa2_sg_entry *sg) -{ - return !!((le16_to_cpu(sg->format_offset) >> SG_SHORT_LEN_FLAG_SHIFT) - & SG_SHORT_LEN_FLAG_MASK); -} - -/** - * dpaa2_sg_get_len() - Get the length in SG entry - * @sg: the given scatter-gathering object - * - * Return the length. - */ -static inline u32 dpaa2_sg_get_len(const struct dpaa2_sg_entry *sg) -{ - if (dpaa2_sg_short_len(sg)) - return le32_to_cpu(sg->len) & SG_SHORT_LEN_MASK; - - return le32_to_cpu(sg->len); -} - -/** - * dpaa2_sg_set_len() - Set the length in SG entry - * @sg: the given scatter-gathering object - * @len: the length to be set - */ -static inline void dpaa2_sg_set_len(struct dpaa2_sg_entry *sg, u32 len) -{ - sg->len = cpu_to_le32(len); -} - -/** - * dpaa2_sg_get_offset() - Get the offset in SG entry - * @sg: the given scatter-gathering object - * - * Return the offset. - */ -static inline u16 dpaa2_sg_get_offset(const struct dpaa2_sg_entry *sg) -{ - return le16_to_cpu(sg->format_offset) & SG_OFFSET_MASK; -} - -/** - * dpaa2_sg_set_offset() - Set the offset in SG entry - * @sg: the given scatter-gathering object - * @offset: the offset to be set - */ -static inline void dpaa2_sg_set_offset(struct dpaa2_sg_entry *sg, - u16 offset) -{ - sg->format_offset &= cpu_to_le16(~SG_OFFSET_MASK); - sg->format_offset |= cpu_to_le16(offset); -} - -/** - * dpaa2_sg_get_format() - Get the SG format in SG entry - * @sg: the given scatter-gathering object - * - * Return the format. - */ -static inline enum dpaa2_sg_format - dpaa2_sg_get_format(const struct dpaa2_sg_entry *sg) -{ - return (enum dpaa2_sg_format)((le16_to_cpu(sg->format_offset) - >> SG_FORMAT_SHIFT) & SG_FORMAT_MASK); -} - -/** - * dpaa2_sg_set_format() - Set the SG format in SG entry - * @sg: the given scatter-gathering object - * @format: the format to be set - */ -static inline void dpaa2_sg_set_format(struct dpaa2_sg_entry *sg, - enum dpaa2_sg_format format) -{ - sg->format_offset &= cpu_to_le16(~(SG_FORMAT_MASK << SG_FORMAT_SHIFT)); - sg->format_offset |= cpu_to_le16(format << SG_FORMAT_SHIFT); -} - -/** - * dpaa2_sg_get_bpid() - Get the buffer pool id in SG entry - * @sg: the given scatter-gathering object - * - * Return the bpid. - */ -static inline u16 dpaa2_sg_get_bpid(const struct dpaa2_sg_entry *sg) -{ - return le16_to_cpu(sg->bpid) & SG_BPID_MASK; -} - -/** - * dpaa2_sg_set_bpid() - Set the buffer pool id in SG entry - * @sg: the given scatter-gathering object - * @bpid: the bpid to be set - */ -static inline void dpaa2_sg_set_bpid(struct dpaa2_sg_entry *sg, u16 bpid) -{ - sg->bpid &= cpu_to_le16(~(SG_BPID_MASK)); - sg->bpid |= cpu_to_le16(bpid); -} - -/** - * dpaa2_sg_is_final() - Check final bit in SG entry - * @sg: the given scatter-gathering object - * - * Return bool. - */ -static inline bool dpaa2_sg_is_final(const struct dpaa2_sg_entry *sg) -{ - return !!(le16_to_cpu(sg->format_offset) >> SG_FINAL_FLAG_SHIFT); -} - -/** - * dpaa2_sg_set_final() - Set the final bit in SG entry - * @sg: the given scatter-gathering object - * @final: the final boolean to be set - */ -static inline void dpaa2_sg_set_final(struct dpaa2_sg_entry *sg, bool final) -{ - sg->format_offset &= cpu_to_le16((~(SG_FINAL_FLAG_MASK - << SG_FINAL_FLAG_SHIFT)) & 0xFFFF); - sg->format_offset |= cpu_to_le16(final << SG_FINAL_FLAG_SHIFT); -} - -#endif /* __FSL_DPAA2_FD_H */ diff --git a/drivers/staging/fsl-mc/include/dpaa2-global.h b/drivers/staging/fsl-mc/include/dpaa2-global.h deleted file mode 100644 index 9bc0713346a8..000000000000 --- a/drivers/staging/fsl-mc/include/dpaa2-global.h +++ /dev/null @@ -1,177 +0,0 @@ -/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */ -/* - * Copyright 2014-2016 Freescale Semiconductor Inc. - * Copyright 2016 NXP - * - */ -#ifndef __FSL_DPAA2_GLOBAL_H -#define __FSL_DPAA2_GLOBAL_H - -#include <linux/types.h> -#include <linux/cpumask.h> -#include "dpaa2-fd.h" - -struct dpaa2_dq { - union { - struct common { - u8 verb; - u8 reserved[63]; - } common; - struct dq { - u8 verb; - u8 stat; - __le16 seqnum; - __le16 oprid; - u8 reserved; - u8 tok; - __le32 fqid; - u32 reserved2; - __le32 fq_byte_cnt; - __le32 fq_frm_cnt; - __le64 fqd_ctx; - u8 fd[32]; - } dq; - struct scn { - u8 verb; - u8 stat; - u8 state; - u8 reserved; - __le32 rid_tok; - __le64 ctx; - } scn; - }; -}; - -/* Parsing frame dequeue results */ -/* FQ empty */ -#define DPAA2_DQ_STAT_FQEMPTY 0x80 -/* FQ held active */ -#define DPAA2_DQ_STAT_HELDACTIVE 0x40 -/* FQ force eligible */ -#define DPAA2_DQ_STAT_FORCEELIGIBLE 0x20 -/* valid frame */ -#define DPAA2_DQ_STAT_VALIDFRAME 0x10 -/* FQ ODP enable */ -#define DPAA2_DQ_STAT_ODPVALID 0x04 -/* volatile dequeue */ -#define DPAA2_DQ_STAT_VOLATILE 0x02 -/* volatile dequeue command is expired */ -#define DPAA2_DQ_STAT_EXPIRED 0x01 - -#define DQ_FQID_MASK 0x00FFFFFF -#define DQ_FRAME_COUNT_MASK 0x00FFFFFF - -/** - * dpaa2_dq_flags() - Get the stat field of dequeue response - * @dq: the dequeue result. - */ -static inline u32 dpaa2_dq_flags(const struct dpaa2_dq *dq) -{ - return dq->dq.stat; -} - -/** - * dpaa2_dq_is_pull() - Check whether the dq response is from a pull - * command. - * @dq: the dequeue result - * - * Return 1 for volatile(pull) dequeue, 0 for static dequeue. - */ -static inline int dpaa2_dq_is_pull(const struct dpaa2_dq *dq) -{ - return (int)(dpaa2_dq_flags(dq) & DPAA2_DQ_STAT_VOLATILE); -} - -/** - * dpaa2_dq_is_pull_complete() - Check whether the pull command is completed. - * @dq: the dequeue result - * - * Return boolean. - */ -static inline bool dpaa2_dq_is_pull_complete(const struct dpaa2_dq *dq) -{ - return !!(dpaa2_dq_flags(dq) & DPAA2_DQ_STAT_EXPIRED); -} - -/** - * dpaa2_dq_seqnum() - Get the seqnum field in dequeue response - * @dq: the dequeue result - * - * seqnum is valid only if VALIDFRAME flag is TRUE - * - * Return seqnum. - */ -static inline u16 dpaa2_dq_seqnum(const struct dpaa2_dq *dq) -{ - return le16_to_cpu(dq->dq.seqnum); -} - -/** - * dpaa2_dq_odpid() - Get the odpid field in dequeue response - * @dq: the dequeue result - * - * odpid is valid only if ODPVALID flag is TRUE. - * - * Return odpid. - */ -static inline u16 dpaa2_dq_odpid(const struct dpaa2_dq *dq) -{ - return le16_to_cpu(dq->dq.oprid); -} - -/** - * dpaa2_dq_fqid() - Get the fqid in dequeue response - * @dq: the dequeue result - * - * Return fqid. - */ -static inline u32 dpaa2_dq_fqid(const struct dpaa2_dq *dq) -{ - return le32_to_cpu(dq->dq.fqid) & DQ_FQID_MASK; -} - -/** - * dpaa2_dq_byte_count() - Get the byte count in dequeue response - * @dq: the dequeue result - * - * Return the byte count remaining in the FQ. - */ -static inline u32 dpaa2_dq_byte_count(const struct dpaa2_dq *dq) -{ - return le32_to_cpu(dq->dq.fq_byte_cnt); -} - -/** - * dpaa2_dq_frame_count() - Get the frame count in dequeue response - * @dq: the dequeue result - * - * Return the frame count remaining in the FQ. - */ -static inline u32 dpaa2_dq_frame_count(const struct dpaa2_dq *dq) -{ - return le32_to_cpu(dq->dq.fq_frm_cnt) & DQ_FRAME_COUNT_MASK; -} - -/** - * dpaa2_dq_fd_ctx() - Get the frame queue context in dequeue response - * @dq: the dequeue result - * - * Return the frame queue context. - */ -static inline u64 dpaa2_dq_fqd_ctx(const struct dpaa2_dq *dq) -{ - return le64_to_cpu(dq->dq.fqd_ctx); -} - -/** - * dpaa2_dq_fd() - Get the frame descriptor in dequeue response - * @dq: the dequeue result - * - * Return the frame descriptor. - */ -static inline const struct dpaa2_fd *dpaa2_dq_fd(const struct dpaa2_dq *dq) -{ - return (const struct dpaa2_fd *)&dq->dq.fd[0]; -} - -#endif /* __FSL_DPAA2_GLOBAL_H */ diff --git a/drivers/staging/fsl-mc/include/dpaa2-io.h b/drivers/staging/fsl-mc/include/dpaa2-io.h deleted file mode 100644 index ab51e40d11db..000000000000 --- a/drivers/staging/fsl-mc/include/dpaa2-io.h +++ /dev/null @@ -1,115 +0,0 @@ -/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */ -/* - * Copyright 2014-2016 Freescale Semiconductor Inc. - * Copyright NXP - * - */ -#ifndef __FSL_DPAA2_IO_H -#define __FSL_DPAA2_IO_H - -#include <linux/types.h> -#include <linux/cpumask.h> -#include <linux/irqreturn.h> - -#include "dpaa2-fd.h" -#include "dpaa2-global.h" - -struct dpaa2_io; -struct dpaa2_io_store; -struct device; - -/** - * DOC: DPIO Service - * - * The DPIO service provides APIs for users to interact with the datapath - * by enqueueing and dequeing frame descriptors. - * - * The following set of APIs can be used to enqueue and dequeue frames - * as well as producing notification callbacks when data is available - * for dequeue. - */ - -#define DPAA2_IO_ANY_CPU -1 - -/** - * struct dpaa2_io_desc - The DPIO descriptor - * @receives_notifications: Use notificaton mode. Non-zero if the DPIO - * has a channel. - * @has_8prio: Set to non-zero for channel with 8 priority WQs. Ignored - * unless receives_notification is TRUE. - * @cpu: The cpu index that at least interrupt handlers will - * execute on. - * @stash_affinity: The stash affinity for this portal favour 'cpu' - * @regs_cena: The cache enabled regs. - * @regs_cinh: The cache inhibited regs - * @dpio_id: The dpio index - * @qman_version: The qman version - * - * Describes the attributes and features of the DPIO object. - */ -struct dpaa2_io_desc { - int receives_notifications; - int has_8prio; - int cpu; - void *regs_cena; - void __iomem *regs_cinh; - int dpio_id; - u32 qman_version; -}; - -struct dpaa2_io *dpaa2_io_create(const struct dpaa2_io_desc *desc); - -void dpaa2_io_down(struct dpaa2_io *d); - -irqreturn_t dpaa2_io_irq(struct dpaa2_io *obj); - -struct dpaa2_io *dpaa2_io_service_select(int cpu); - -/** - * struct dpaa2_io_notification_ctx - The DPIO notification context structure - * @cb: The callback to be invoked when the notification arrives - * @is_cdan: Zero for FQDAN, non-zero for CDAN - * @id: FQID or channel ID, needed for rearm - * @desired_cpu: The cpu on which the notifications will show up. Use - * DPAA2_IO_ANY_CPU if don't care - * @dpio_id: The dpio index - * @qman64: The 64-bit context value shows up in the FQDAN/CDAN. - * @node: The list node - * @dpio_private: The dpio object internal to dpio_service - * - * Used when a FQDAN/CDAN registration is made by drivers. - */ -struct dpaa2_io_notification_ctx { - void (*cb)(struct dpaa2_io_notification_ctx *ctx); - int is_cdan; - u32 id; - int desired_cpu; - int dpio_id; - u64 qman64; - struct list_head node; - void *dpio_private; -}; - -int dpaa2_io_service_register(struct dpaa2_io *service, - struct dpaa2_io_notification_ctx *ctx); -void dpaa2_io_service_deregister(struct dpaa2_io *service, - struct dpaa2_io_notification_ctx *ctx); -int dpaa2_io_service_rearm(struct dpaa2_io *service, - struct dpaa2_io_notification_ctx *ctx); - -int dpaa2_io_service_pull_channel(struct dpaa2_io *d, u32 channelid, - struct dpaa2_io_store *s); - -int dpaa2_io_service_enqueue_qd(struct dpaa2_io *d, u32 qdid, u8 prio, - u16 qdbin, const struct dpaa2_fd *fd); -int dpaa2_io_service_release(struct dpaa2_io *d, u32 bpid, - const u64 *buffers, unsigned int num_buffers); -int dpaa2_io_service_acquire(struct dpaa2_io *d, u32 bpid, - u64 *buffers, unsigned int num_buffers); - -struct dpaa2_io_store *dpaa2_io_store_create(unsigned int max_frames, - struct device *dev); -void dpaa2_io_store_destroy(struct dpaa2_io_store *s); -struct dpaa2_dq *dpaa2_io_store_next(struct dpaa2_io_store *s, int *is_last); - -#endif /* __FSL_DPAA2_IO_H */ diff --git a/drivers/tee/optee/Kconfig b/drivers/tee/optee/Kconfig index 0126de898036..3c59e19029be 100644 --- a/drivers/tee/optee/Kconfig +++ b/drivers/tee/optee/Kconfig @@ -5,3 +5,11 @@ config OPTEE help This implements the OP-TEE Trusted Execution Environment (TEE) driver. + +config OPTEE_SHM_NUM_PRIV_PAGES + int "Private Shared Memory Pages" + default 1 + depends on OPTEE + help + This sets the number of private shared memory pages to be + used by OP-TEE TEE driver. diff --git a/drivers/tee/optee/core.c b/drivers/tee/optee/core.c index e5fd5ed217da..e1aafe842d66 100644 --- a/drivers/tee/optee/core.c +++ b/drivers/tee/optee/core.c @@ -32,7 +32,7 @@ #define DRIVER_NAME "optee" -#define OPTEE_SHM_NUM_PRIV_PAGES 1 +#define OPTEE_SHM_NUM_PRIV_PAGES CONFIG_OPTEE_SHM_NUM_PRIV_PAGES /** * optee_from_msg_param() - convert from OPTEE_MSG parameters to diff --git a/drivers/tee/optee/rpc.c b/drivers/tee/optee/rpc.c index 41aea12e2bcc..b45c73dd37a5 100644 --- a/drivers/tee/optee/rpc.c +++ b/drivers/tee/optee/rpc.c @@ -48,7 +48,7 @@ static void handle_rpc_func_cmd_get_time(struct optee_msg_arg *arg) OPTEE_MSG_ATTR_TYPE_VALUE_OUTPUT) goto bad; - getnstimeofday64(&ts); + ktime_get_real_ts64(&ts); arg->params[0].u.value.a = ts.tv_sec; arg->params[0].u.value.b = ts.tv_nsec; diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index 82979880f985..0e69edc77d18 100644 --- a/drivers/thermal/Kconfig +++ b/drivers/thermal/Kconfig @@ -360,7 +360,7 @@ config INTEL_SOC_DTS_IOSF_CORE config INTEL_SOC_DTS_THERMAL tristate "Intel SoCs DTS thermal driver" - depends on X86 && PCI + depends on X86 && PCI && ACPI select INTEL_SOC_DTS_IOSF_CORE select THERMAL_WRITABLE_TRIPS help diff --git a/drivers/thermal/intel_powerclamp.c b/drivers/thermal/intel_powerclamp.c index 4540e892b61d..cde891c54cde 100644 --- a/drivers/thermal/intel_powerclamp.c +++ b/drivers/thermal/intel_powerclamp.c @@ -28,7 +28,7 @@ * case of external interrupts without need for ack, clamping down * cpu in non-irq context does not reduce irq. for majority of the * cases, clamping down cpu does help reduce irq as well, we should - * be able to differenciate the two cases and give a quantitative + * be able to differentiate the two cases and give a quantitative * solution for the irqs that we can control. perhaps based on * get_cpu_iowait_time_us() * diff --git a/drivers/thermal/intel_soc_dts_thermal.c b/drivers/thermal/intel_soc_dts_thermal.c index c27868b2c6af..1e47511a6bd5 100644 --- a/drivers/thermal/intel_soc_dts_thermal.c +++ b/drivers/thermal/intel_soc_dts_thermal.c @@ -15,6 +15,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include <linux/acpi.h> #include <linux/module.h> #include <linux/interrupt.h> #include <asm/cpu_device_id.h> @@ -31,6 +32,7 @@ MODULE_PARM_DESC(crit_offset, /* IRQ 86 is a fixed APIC interrupt for BYT DTS Aux threshold notifications */ #define BYT_SOC_DTS_APIC_IRQ 86 +static int soc_dts_thres_gsi; static int soc_dts_thres_irq; static struct intel_soc_dts_sensors *soc_dts; @@ -65,7 +67,21 @@ static int __init intel_soc_thermal_init(void) return err; } - soc_dts_thres_irq = (int)match_cpu->driver_data; + soc_dts_thres_gsi = (int)match_cpu->driver_data; + if (soc_dts_thres_gsi) { + /* + * Note the flags here MUST match the firmware defaults, rather + * then the request_irq flags, otherwise we get an EBUSY error. + */ + soc_dts_thres_irq = acpi_register_gsi(NULL, soc_dts_thres_gsi, + ACPI_LEVEL_SENSITIVE, + ACPI_ACTIVE_LOW); + if (soc_dts_thres_irq < 0) { + pr_warn("intel_soc_dts: Could not get IRQ for GSI %d, err %d\n", + soc_dts_thres_gsi, soc_dts_thres_irq); + soc_dts_thres_irq = 0; + } + } if (soc_dts_thres_irq) { err = request_threaded_irq(soc_dts_thres_irq, NULL, @@ -90,8 +106,10 @@ static int __init intel_soc_thermal_init(void) return 0; error_trips: - if (soc_dts_thres_irq) + if (soc_dts_thres_irq) { free_irq(soc_dts_thres_irq, soc_dts); + acpi_unregister_gsi(soc_dts_thres_gsi); + } intel_soc_dts_iosf_exit(soc_dts); return err; @@ -99,8 +117,10 @@ error_trips: static void __exit intel_soc_thermal_exit(void) { - if (soc_dts_thres_irq) + if (soc_dts_thres_irq) { free_irq(soc_dts_thres_irq, soc_dts); + acpi_unregister_gsi(soc_dts_thres_gsi); + } intel_soc_dts_iosf_exit(soc_dts); } diff --git a/drivers/tty/hvc/hvc_opal.c b/drivers/tty/hvc/hvc_opal.c index f631f8bee308..77baf895108f 100644 --- a/drivers/tty/hvc/hvc_opal.c +++ b/drivers/tty/hvc/hvc_opal.c @@ -52,6 +52,7 @@ static u32 hvc_opal_boot_termno; static const struct hv_ops hvc_opal_raw_ops = { .get_chars = opal_get_chars, .put_chars = opal_put_chars, + .flush = opal_flush_chars, .notifier_add = notifier_add_irq, .notifier_del = notifier_del_irq, .notifier_hangup = notifier_hangup_irq, @@ -141,6 +142,7 @@ static int hvc_opal_hvsi_tiocmset(struct hvc_struct *hp, unsigned int set, static const struct hv_ops hvc_opal_hvsi_ops = { .get_chars = hvc_opal_hvsi_get_chars, .put_chars = hvc_opal_hvsi_put_chars, + .flush = opal_flush_chars, .notifier_add = hvc_opal_hvsi_open, .notifier_del = hvc_opal_hvsi_close, .notifier_hangup = hvc_opal_hvsi_hangup, diff --git a/drivers/usb/host/ehci-exynos.c b/drivers/usb/host/ehci-exynos.c index d9145a8f35d2..8e3bab1e0c1f 100644 --- a/drivers/usb/host/ehci-exynos.c +++ b/drivers/usb/host/ehci-exynos.c @@ -161,16 +161,10 @@ static int exynos_ehci_probe(struct platform_device *pdev) } exynos_ehci = to_exynos_ehci(hcd); - if (of_device_is_compatible(pdev->dev.of_node, - "samsung,exynos5440-ehci")) - goto skip_phy; - err = exynos_ehci_get_phy(&pdev->dev, exynos_ehci); if (err) goto fail_clk; -skip_phy: - exynos_ehci->clk = devm_clk_get(&pdev->dev, "usbhost"); if (IS_ERR(exynos_ehci->clk)) { @@ -304,7 +298,6 @@ static const struct dev_pm_ops exynos_ehci_pm_ops = { #ifdef CONFIG_OF static const struct of_device_id exynos_ehci_match[] = { { .compatible = "samsung,exynos4210-ehci" }, - { .compatible = "samsung,exynos5440-ehci" }, {}, }; MODULE_DEVICE_TABLE(of, exynos_ehci_match); diff --git a/drivers/usb/host/ohci-exynos.c b/drivers/usb/host/ohci-exynos.c index a39fae41bc70..c0c4dcca6f3c 100644 --- a/drivers/usb/host/ohci-exynos.c +++ b/drivers/usb/host/ohci-exynos.c @@ -130,15 +130,10 @@ static int exynos_ohci_probe(struct platform_device *pdev) exynos_ohci = to_exynos_ohci(hcd); - if (of_device_is_compatible(pdev->dev.of_node, - "samsung,exynos5440-ohci")) - goto skip_phy; - err = exynos_ohci_get_phy(&pdev->dev, exynos_ohci); if (err) goto fail_clk; -skip_phy: exynos_ohci->clk = devm_clk_get(&pdev->dev, "usbhost"); if (IS_ERR(exynos_ohci->clk)) { @@ -270,7 +265,6 @@ static const struct dev_pm_ops exynos_ohci_pm_ops = { #ifdef CONFIG_OF static const struct of_device_id exynos_ohci_match[] = { { .compatible = "samsung,exynos4210-ohci" }, - { .compatible = "samsung,exynos5440-ohci" }, {}, }; MODULE_DEVICE_TABLE(of, exynos_ohci_match); diff --git a/drivers/vhost/Kconfig b/drivers/vhost/Kconfig index cfdecea5078f..b580885243f7 100644 --- a/drivers/vhost/Kconfig +++ b/drivers/vhost/Kconfig @@ -12,7 +12,7 @@ config VHOST_NET config VHOST_SCSI tristate "VHOST_SCSI TCM fabric driver" - depends on TARGET_CORE && EVENTFD && m + depends on TARGET_CORE && EVENTFD select VHOST default n ---help--- diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c index 76f8d649147b..c24bb690680b 100644 --- a/drivers/vhost/scsi.c +++ b/drivers/vhost/scsi.c @@ -55,7 +55,7 @@ #define VHOST_SCSI_DEFAULT_TAGS 256 #define VHOST_SCSI_PREALLOC_SGLS 2048 #define VHOST_SCSI_PREALLOC_UPAGES 2048 -#define VHOST_SCSI_PREALLOC_PROT_SGLS 512 +#define VHOST_SCSI_PREALLOC_PROT_SGLS 2048 struct vhost_scsi_inflight { /* Wait for the flush operation to finish */ diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig index e91edef98633..787792c3d08d 100644 --- a/drivers/video/console/Kconfig +++ b/drivers/video/console/Kconfig @@ -152,7 +152,7 @@ config FRAMEBUFFER_CONSOLE_ROTATION config FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER bool "Framebuffer Console Deferred Takeover" - depends on FRAMEBUFFER_CONSOLE=y && DUMMY_CONSOLE=y + depends on FB=y && FRAMEBUFFER_CONSOLE && DUMMY_CONSOLE help If enabled this defers the framebuffer console taking over the console from the dummy console until the first text is displayed on diff --git a/drivers/video/console/dummycon.c b/drivers/video/console/dummycon.c index 0254251fdd79..45ad925ad5f8 100644 --- a/drivers/video/console/dummycon.c +++ b/drivers/video/console/dummycon.c @@ -38,13 +38,11 @@ void dummycon_register_output_notifier(struct notifier_block *nb) if (dummycon_putc_called) nb->notifier_call(nb, 0, NULL); } -EXPORT_SYMBOL_GPL(dummycon_register_output_notifier); void dummycon_unregister_output_notifier(struct notifier_block *nb) { raw_notifier_chain_unregister(&dummycon_output_nh, nb); } -EXPORT_SYMBOL_GPL(dummycon_unregister_output_notifier); static void dummycon_putc(struct vc_data *vc, int c, int ypos, int xpos) { diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index f09e17b60e45..09731b2f6815 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c @@ -112,6 +112,11 @@ EXPORT_SYMBOL(vgacon_text_force); static int __init text_mode(char *str) { vgacon_text_mode_force = true; + + pr_warning("You have booted with nomodeset. This means your GPU drivers are DISABLED\n"); + pr_warning("Any video related functionality will be severely degraded, and you may not even be able to suspend the system properly\n"); + pr_warning("Unless you actually understand what nomodeset does, you should reboot without enabling it\n"); + return 1; } diff --git a/drivers/video/fbdev/amifb.c b/drivers/video/fbdev/amifb.c index cc11c6061298..0777aff211e5 100644 --- a/drivers/video/fbdev/amifb.c +++ b/drivers/video/fbdev/amifb.c @@ -2303,7 +2303,7 @@ static void ami_build_copper(struct fb_info *info) ami_rebuild_copper(info->par); } - +#ifndef MODULE static void __init amifb_setup_mcap(char *spec) { char *p; @@ -2368,7 +2368,7 @@ static int __init amifb_setup(char *options) return 0; } - +#endif static int amifb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c index 5fb156bdcf4e..75ebbbf0a1fb 100644 --- a/drivers/video/fbdev/core/fbcon.c +++ b/drivers/video/fbdev/core/fbcon.c @@ -2234,8 +2234,8 @@ static int fbcon_switch(struct vc_data *vc) * * info->currcon = vc->vc_num; */ - for (i = 0; i < FB_MAX; i++) { - if (registered_fb[i] != NULL && registered_fb[i]->fbcon_par) { + for_each_registered_fb(i) { + if (registered_fb[i]->fbcon_par) { struct fbcon_ops *o = registered_fb[i]->fbcon_par; o->currcon = vc->vc_num; @@ -3124,11 +3124,9 @@ static int fbcon_fb_unregistered(struct fb_info *info) if (idx == info_idx) { info_idx = -1; - for (i = 0; i < FB_MAX; i++) { - if (registered_fb[i] != NULL) { - info_idx = i; - break; - } + for_each_registered_fb(i) { + info_idx = i; + break; } } @@ -3594,13 +3592,24 @@ static int fbcon_init_device(void) } #ifdef CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER +static void fbcon_register_existing_fbs(struct work_struct *work) +{ + int i; + + console_lock(); + + for_each_registered_fb(i) + fbcon_fb_registered(registered_fb[i]); + + console_unlock(); +} + static struct notifier_block fbcon_output_nb; +static DECLARE_WORK(fbcon_deferred_takeover_work, fbcon_register_existing_fbs); static int fbcon_output_notifier(struct notifier_block *nb, unsigned long action, void *data) { - int i; - WARN_CONSOLE_UNLOCKED(); pr_info("fbcon: Taking over console\n"); @@ -3609,45 +3618,37 @@ static int fbcon_output_notifier(struct notifier_block *nb, deferred_takeover = false; logo_shown = FBCON_LOGO_DONTSHOW; - for (i = 0; i < FB_MAX; i++) { - if (registered_fb[i]) - fbcon_fb_registered(registered_fb[i]); - } + /* We may get called in atomic context */ + schedule_work(&fbcon_deferred_takeover_work); return NOTIFY_OK; } - -static void fbcon_register_output_notifier(void) -{ - fbcon_output_nb.notifier_call = fbcon_output_notifier; - dummycon_register_output_notifier(&fbcon_output_nb); -} -#else -static inline void fbcon_register_output_notifier(void) {} #endif static void fbcon_start(void) { + WARN_CONSOLE_UNLOCKED(); + +#ifdef CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER + if (conswitchp != &dummy_con) + deferred_takeover = false; + if (deferred_takeover) { - fbcon_register_output_notifier(); + fbcon_output_nb.notifier_call = fbcon_output_notifier; + dummycon_register_output_notifier(&fbcon_output_nb); return; } +#endif if (num_registered_fb) { int i; - console_lock(); - - for (i = 0; i < FB_MAX; i++) { - if (registered_fb[i] != NULL) { - info_idx = i; - break; - } + for_each_registered_fb(i) { + info_idx = i; + break; } do_fbcon_takeover(0); - console_unlock(); - } } @@ -3669,15 +3670,12 @@ static void fbcon_exit(void) kfree((void *)softback_buf); softback_buf = 0UL; - for (i = 0; i < FB_MAX; i++) { + for_each_registered_fb(i) { int pending = 0; mapped = 0; info = registered_fb[i]; - if (info == NULL) - continue; - if (info->queue.func) pending = cancel_work_sync(&info->queue); DPRINTK("fbcon: %s pending work\n", (pending ? "canceled" : @@ -3733,8 +3731,8 @@ void __init fb_console_init(void) for (i = 0; i < MAX_NR_CONSOLES; i++) con2fb_map[i] = -1; - console_unlock(); fbcon_start(); + console_unlock(); } #ifdef MODULE diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c index 609438d2465b..20405421a5ed 100644 --- a/drivers/video/fbdev/core/fbmem.c +++ b/drivers/video/fbdev/core/fbmem.c @@ -1347,6 +1347,7 @@ static long fb_compat_ioctl(struct file *file, unsigned int cmd, case FBIOGET_CON2FBMAP: case FBIOPUT_CON2FBMAP: arg = (unsigned long) compat_ptr(arg); + /* fall through */ case FBIOBLANK: ret = do_fb_ioctl(info, cmd, arg); break; @@ -1593,10 +1594,8 @@ static int do_remove_conflicting_framebuffers(struct apertures_struct *a, int i, ret; /* check all firmware fbs and kick off if the base addr overlaps */ - for (i = 0 ; i < FB_MAX; i++) { + for_each_registered_fb(i) { struct apertures_struct *gen_aper; - if (!registered_fb[i]) - continue; if (!(registered_fb[i]->flags & FBINFO_MISC_FIRMWARE)) continue; @@ -1691,25 +1690,30 @@ static int do_register_framebuffer(struct fb_info *fb_info) event.info = fb_info; if (!lockless_register_fb) console_lock(); + else + atomic_inc(&ignore_console_lock_warning); if (!lock_fb_info(fb_info)) { - if (!lockless_register_fb) - console_unlock(); - return -ENODEV; + ret = -ENODEV; + goto unlock_console; } + ret = 0; fb_notifier_call_chain(FB_EVENT_FB_REGISTERED, &event); unlock_fb_info(fb_info); +unlock_console: if (!lockless_register_fb) console_unlock(); - return 0; + else + atomic_dec(&ignore_console_lock_warning); + return ret; } -static int do_unregister_framebuffer(struct fb_info *fb_info) +static int unbind_console(struct fb_info *fb_info) { struct fb_event event; - int i, ret = 0; + int ret; + int i = fb_info->node; - i = fb_info->node; if (i < 0 || i >= FB_MAX || registered_fb[i] != fb_info) return -EINVAL; @@ -1724,17 +1728,29 @@ static int do_unregister_framebuffer(struct fb_info *fb_info) unlock_fb_info(fb_info); console_unlock(); + return ret; +} + +static int __unlink_framebuffer(struct fb_info *fb_info); + +static int do_unregister_framebuffer(struct fb_info *fb_info) +{ + struct fb_event event; + int ret; + + ret = unbind_console(fb_info); + if (ret) return -EINVAL; pm_vt_switch_unregister(fb_info->dev); - unlink_framebuffer(fb_info); + __unlink_framebuffer(fb_info); if (fb_info->pixmap.addr && (fb_info->pixmap.flags & FB_PIXMAP_DEFAULT)) kfree(fb_info->pixmap.addr); fb_destroy_modelist(&fb_info->modelist); - registered_fb[i] = NULL; + registered_fb[fb_info->node] = NULL; num_registered_fb--; fb_cleanup_device(fb_info); event.info = fb_info; @@ -1747,7 +1763,7 @@ static int do_unregister_framebuffer(struct fb_info *fb_info) return 0; } -int unlink_framebuffer(struct fb_info *fb_info) +static int __unlink_framebuffer(struct fb_info *fb_info) { int i; @@ -1759,6 +1775,20 @@ int unlink_framebuffer(struct fb_info *fb_info) device_destroy(fb_class, MKDEV(FB_MAJOR, i)); fb_info->dev = NULL; } + + return 0; +} + +int unlink_framebuffer(struct fb_info *fb_info) +{ + int ret; + + ret = __unlink_framebuffer(fb_info); + if (ret) + return ret; + + unbind_console(fb_info); + return 0; } EXPORT_SYMBOL(unlink_framebuffer); diff --git a/drivers/video/fbdev/core/modedb.c b/drivers/video/fbdev/core/modedb.c index 2510fa728d77..283d9307df21 100644 --- a/drivers/video/fbdev/core/modedb.c +++ b/drivers/video/fbdev/core/modedb.c @@ -628,45 +628,47 @@ static int fb_try_mode(struct fb_var_screeninfo *var, struct fb_info *info, } /** - * fb_find_mode - finds a valid video mode - * @var: frame buffer user defined part of display - * @info: frame buffer info structure - * @mode_option: string video mode to find - * @db: video mode database - * @dbsize: size of @db - * @default_mode: default video mode to fall back to - * @default_bpp: default color depth in bits per pixel + * fb_find_mode - finds a valid video mode + * @var: frame buffer user defined part of display + * @info: frame buffer info structure + * @mode_option: string video mode to find + * @db: video mode database + * @dbsize: size of @db + * @default_mode: default video mode to fall back to + * @default_bpp: default color depth in bits per pixel * - * Finds a suitable video mode, starting with the specified mode - * in @mode_option with fallback to @default_mode. If - * @default_mode fails, all modes in the video mode database will - * be tried. + * Finds a suitable video mode, starting with the specified mode + * in @mode_option with fallback to @default_mode. If + * @default_mode fails, all modes in the video mode database will + * be tried. * - * Valid mode specifiers for @mode_option: + * Valid mode specifiers for @mode_option:: * - * <xres>x<yres>[M][R][-<bpp>][@<refresh>][i][m] or - * <name>[-<bpp>][@<refresh>] + * <xres>x<yres>[M][R][-<bpp>][@<refresh>][i][p][m] + * + * or :: * - * with <xres>, <yres>, <bpp> and <refresh> decimal numbers and - * <name> a string. + * <name>[-<bpp>][@<refresh>] * - * If 'M' is present after yres (and before refresh/bpp if present), - * the function will compute the timings using VESA(tm) Coordinated - * Video Timings (CVT). If 'R' is present after 'M', will compute with - * reduced blanking (for flatpanels). If 'i' is present, compute - * interlaced mode. If 'm' is present, add margins equal to 1.8% - * of xres rounded down to 8 pixels, and 1.8% of yres. The char - * 'i' and 'm' must be after 'M' and 'R'. Example: + * with <xres>, <yres>, <bpp> and <refresh> decimal numbers and + * <name> a string. * - * 1024x768MR-8@60m - Reduced blank with margins at 60Hz. + * If 'M' is present after yres (and before refresh/bpp if present), + * the function will compute the timings using VESA(tm) Coordinated + * Video Timings (CVT). If 'R' is present after 'M', will compute with + * reduced blanking (for flatpanels). If 'i' or 'p' are present, compute + * interlaced or progressive mode. If 'm' is present, add margins equal + * to 1.8% of xres rounded down to 8 pixels, and 1.8% of yres. The char + * 'i', 'p' and 'm' must be after 'M' and 'R'. Example:: * - * NOTE: The passed struct @var is _not_ cleared! This allows you - * to supply values for e.g. the grayscale and accel_flags fields. + * 1024x768MR-8@60m - Reduced blank with margins at 60Hz. * - * Returns zero for failure, 1 if using specified @mode_option, - * 2 if using specified @mode_option with an ignored refresh rate, - * 3 if default mode is used, 4 if fall back to any valid mode. + * NOTE: The passed struct @var is _not_ cleared! This allows you + * to supply values for e.g. the grayscale and accel_flags fields. * + * Returns zero for failure, 1 if using specified @mode_option, + * 2 if using specified @mode_option with an ignored refresh rate, + * 3 if default mode is used, 4 if fall back to any valid mode. */ int fb_find_mode(struct fb_var_screeninfo *var, @@ -697,7 +699,8 @@ int fb_find_mode(struct fb_var_screeninfo *var, unsigned int namelen = strlen(name); int res_specified = 0, bpp_specified = 0, refresh_specified = 0; unsigned int xres = 0, yres = 0, bpp = default_bpp, refresh = 0; - int yres_specified = 0, cvt = 0, rb = 0, interlace = 0; + int yres_specified = 0, cvt = 0, rb = 0; + int interlace_specified = 0, interlace = 0; int margins = 0; u32 best, diff, tdiff; @@ -748,9 +751,17 @@ int fb_find_mode(struct fb_var_screeninfo *var, if (!cvt) margins = 1; break; + case 'p': + if (!cvt) { + interlace = 0; + interlace_specified = 1; + } + break; case 'i': - if (!cvt) + if (!cvt) { interlace = 1; + interlace_specified = 1; + } break; default: goto done; @@ -819,11 +830,21 @@ done: if ((name_matches(db[i], name, namelen) || (res_specified && res_matches(db[i], xres, yres))) && !fb_try_mode(var, info, &db[i], bpp)) { - if (refresh_specified && db[i].refresh == refresh) - return 1; + const int db_interlace = (db[i].vmode & + FB_VMODE_INTERLACED ? 1 : 0); + int score = abs(db[i].refresh - refresh); + + if (interlace_specified) + score += abs(db_interlace - interlace); + + if (!interlace_specified || + db_interlace == interlace) + if (refresh_specified && + db[i].refresh == refresh) + return 1; - if (abs(db[i].refresh - refresh) < diff) { - diff = abs(db[i].refresh - refresh); + if (score < diff) { + diff = score; best = i; } } diff --git a/drivers/video/fbdev/efifb.c b/drivers/video/fbdev/efifb.c index c6f78d27947b..3946649b85c8 100644 --- a/drivers/video/fbdev/efifb.c +++ b/drivers/video/fbdev/efifb.c @@ -9,16 +9,39 @@ #include <linux/kernel.h> #include <linux/efi.h> +#include <linux/efi-bgrt.h> #include <linux/errno.h> #include <linux/fb.h> #include <linux/pci.h> #include <linux/platform_device.h> +#include <linux/printk.h> #include <linux/screen_info.h> #include <video/vga.h> #include <asm/efi.h> #include <drm/drm_utils.h> /* For drm_get_panel_orientation_quirk */ #include <drm/drm_connector.h> /* For DRM_MODE_PANEL_ORIENTATION_* */ +struct bmp_file_header { + u16 id; + u32 file_size; + u32 reserved; + u32 bitmap_offset; +} __packed; + +struct bmp_dib_header { + u32 dib_header_size; + s32 width; + s32 height; + u16 planes; + u16 bpp; + u32 compression; + u32 bitmap_size; + u32 horz_resolution; + u32 vert_resolution; + u32 colors_used; + u32 colors_important; +} __packed; + static bool request_mem_succeeded = false; static u64 mem_flags = EFI_MEMORY_WC | EFI_MEMORY_UC; @@ -66,6 +89,164 @@ static int efifb_setcolreg(unsigned regno, unsigned red, unsigned green, return 0; } +/* + * If fbcon deffered console takeover is configured, the intent is for the + * framebuffer to show the boot graphics (e.g. vendor logo) until there is some + * (error) message to display. But the boot graphics may have been destroyed by + * e.g. option ROM output, detect this and restore the boot graphics. + */ +#if defined CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER && \ + defined CONFIG_ACPI_BGRT +static void efifb_copy_bmp(u8 *src, u32 *dst, int width, struct screen_info *si) +{ + u8 r, g, b; + + while (width--) { + b = *src++; + g = *src++; + r = *src++; + *dst++ = (r << si->red_pos) | + (g << si->green_pos) | + (b << si->blue_pos); + } +} + +#ifdef CONFIG_X86 +/* + * On x86 some firmwares use a low non native resolution for the display when + * they have shown some text messages. While keeping the bgrt filled with info + * for the native resolution. If the bgrt image intended for the native + * resolution still fits, it will be displayed very close to the right edge of + * the display looking quite bad. This function checks for this. + */ +static bool efifb_bgrt_sanity_check(struct screen_info *si, u32 bmp_width) +{ + static const int default_resolutions[][2] = { + { 800, 600 }, + { 1024, 768 }, + { 1280, 1024 }, + }; + u32 i, right_margin; + + for (i = 0; i < ARRAY_SIZE(default_resolutions); i++) { + if (default_resolutions[i][0] == si->lfb_width && + default_resolutions[i][1] == si->lfb_height) + break; + } + /* If not a default resolution used for textmode, this should be fine */ + if (i >= ARRAY_SIZE(default_resolutions)) + return true; + + /* If the right margin is 5 times smaller then the left one, reject */ + right_margin = si->lfb_width - (bgrt_tab.image_offset_x + bmp_width); + if (right_margin < (bgrt_tab.image_offset_x / 5)) + return false; + + return true; +} +#else +static bool efifb_bgrt_sanity_check(struct screen_info *si, u32 bmp_width) +{ + return true; +} +#endif + +static void efifb_show_boot_graphics(struct fb_info *info) +{ + u32 bmp_width, bmp_height, bmp_pitch, screen_pitch, dst_x, y, src_y; + struct screen_info *si = &screen_info; + struct bmp_file_header *file_header; + struct bmp_dib_header *dib_header; + void *bgrt_image = NULL; + u8 *dst = info->screen_base; + + if (!bgrt_tab.image_address) { + pr_info("efifb: No BGRT, not showing boot graphics\n"); + return; + } + + /* Avoid flashing the logo if we're going to print std probe messages */ + if (console_loglevel > CONSOLE_LOGLEVEL_QUIET) + return; + + /* bgrt_tab.status is unreliable, so we don't check it */ + + if (si->lfb_depth != 32) { + pr_info("efifb: not 32 bits, not showing boot graphics\n"); + return; + } + + bgrt_image = memremap(bgrt_tab.image_address, bgrt_image_size, + MEMREMAP_WB); + if (!bgrt_image) { + pr_warn("efifb: Ignoring BGRT: failed to map image memory\n"); + return; + } + + if (bgrt_image_size < (sizeof(*file_header) + sizeof(*dib_header))) + goto error; + + file_header = bgrt_image; + if (file_header->id != 0x4d42 || file_header->reserved != 0) + goto error; + + dib_header = bgrt_image + sizeof(*file_header); + if (dib_header->dib_header_size != 40 || dib_header->width < 0 || + dib_header->planes != 1 || dib_header->bpp != 24 || + dib_header->compression != 0) + goto error; + + bmp_width = dib_header->width; + bmp_height = abs(dib_header->height); + bmp_pitch = round_up(3 * bmp_width, 4); + screen_pitch = si->lfb_linelength; + + if ((file_header->bitmap_offset + bmp_pitch * bmp_height) > + bgrt_image_size) + goto error; + + if ((bgrt_tab.image_offset_x + bmp_width) > si->lfb_width || + (bgrt_tab.image_offset_y + bmp_height) > si->lfb_height) + goto error; + + if (!efifb_bgrt_sanity_check(si, bmp_width)) + goto error; + + pr_info("efifb: showing boot graphics\n"); + + for (y = 0; y < si->lfb_height; y++, dst += si->lfb_linelength) { + /* Only background? */ + if (y < bgrt_tab.image_offset_y || + y >= (bgrt_tab.image_offset_y + bmp_height)) { + memset(dst, 0, 4 * si->lfb_width); + continue; + } + + src_y = y - bgrt_tab.image_offset_y; + /* Positive header height means upside down row order */ + if (dib_header->height > 0) + src_y = (bmp_height - 1) - src_y; + + memset(dst, 0, bgrt_tab.image_offset_x * 4); + dst_x = bgrt_tab.image_offset_x; + efifb_copy_bmp(bgrt_image + file_header->bitmap_offset + + src_y * bmp_pitch, + (u32 *)dst + dst_x, bmp_width, si); + dst_x += bmp_width; + memset((u32 *)dst + dst_x, 0, (si->lfb_width - dst_x) * 4); + } + + memunmap(bgrt_image); + return; + +error: + memunmap(bgrt_image); + pr_warn("efifb: Ignoring BGRT: unexpected or invalid BMP data\n"); +} +#else +static inline void efifb_show_boot_graphics(struct fb_info *info) {} +#endif + static void efifb_destroy(struct fb_info *info) { if (info->screen_base) { @@ -311,6 +492,8 @@ static int efifb_probe(struct platform_device *dev) goto err_release_fb; } + efifb_show_boot_graphics(info); + pr_info("efifb: framebuffer at 0x%lx, using %dk, total %dk\n", efifb_fix.smem_start, size_remap/1024, size_total/1024); pr_info("efifb: mode is %dx%dx%d, linelength=%d, pages=%d\n", diff --git a/drivers/video/fbdev/fsl-diu-fb.c b/drivers/video/fbdev/fsl-diu-fb.c index 1bfd13cbd4e3..bc9eb8afc313 100644 --- a/drivers/video/fbdev/fsl-diu-fb.c +++ b/drivers/video/fbdev/fsl-diu-fb.c @@ -360,6 +360,10 @@ struct mfb_info { * @ad[]: Area Descriptors for each real AOI * @gamma: gamma color table * @cursor: hardware cursor data + * @blank_cursor: blank cursor for hiding cursor + * @next_cursor: scratch space to build load cursor + * @edid_data: EDID information buffer + * @has_edid: whether or not the EDID buffer is valid * * This data structure must be allocated with 32-byte alignment, so that the * internal fields can be aligned properly. @@ -381,6 +385,8 @@ struct fsl_diu_data { __le16 cursor[MAX_CURS * MAX_CURS] __aligned(32); /* Blank cursor data -- used to hide the cursor */ __le16 blank_cursor[MAX_CURS * MAX_CURS] __aligned(32); + /* Scratch cursor data -- used to build new cursor */ + __le16 next_cursor[MAX_CURS * MAX_CURS] __aligned(32); uint8_t edid_data[EDID_LENGTH]; bool has_edid; } __aligned(32); @@ -1056,13 +1062,17 @@ static int fsl_diu_cursor(struct fb_info *info, struct fb_cursor *cursor) * FB_CUR_SETSHAPE - the cursor bitmask has changed */ if (cursor->set & (FB_CUR_SETSHAPE | FB_CUR_SETCMAP | FB_CUR_SETIMAGE)) { + /* + * Determine the size of the cursor image data. Normally, + * it's 8x16. + */ unsigned int image_size = - DIV_ROUND_UP(cursor->image.width, 8) * cursor->image.height; + DIV_ROUND_UP(cursor->image.width, 8) * + cursor->image.height; unsigned int image_words = DIV_ROUND_UP(image_size, sizeof(uint32_t)); unsigned int bg_idx = cursor->image.bg_color; unsigned int fg_idx = cursor->image.fg_color; - uint8_t buffer[image_size]; uint32_t *image, *source, *mask; uint16_t fg, bg; unsigned int i; @@ -1070,13 +1080,6 @@ static int fsl_diu_cursor(struct fb_info *info, struct fb_cursor *cursor) if (info->state != FBINFO_STATE_RUNNING) return 0; - /* - * Determine the size of the cursor image data. Normally, - * it's 8x16. - */ - image_size = DIV_ROUND_UP(cursor->image.width, 8) * - cursor->image.height; - bg = ((info->cmap.red[bg_idx] & 0xf8) << 7) | ((info->cmap.green[bg_idx] & 0xf8) << 2) | ((info->cmap.blue[bg_idx] & 0xf8) >> 3) | @@ -1088,7 +1091,7 @@ static int fsl_diu_cursor(struct fb_info *info, struct fb_cursor *cursor) 1 << 15; /* Use 32-bit operations on the data to improve performance */ - image = (uint32_t *)buffer; + image = (uint32_t *)data->next_cursor; source = (uint32_t *)cursor->image.data; mask = (uint32_t *)cursor->mask; diff --git a/drivers/video/fbdev/goldfishfb.c b/drivers/video/fbdev/goldfishfb.c index 3b70044773b6..4377e3442638 100644 --- a/drivers/video/fbdev/goldfishfb.c +++ b/drivers/video/fbdev/goldfishfb.c @@ -26,6 +26,7 @@ #include <linux/interrupt.h> #include <linux/ioport.h> #include <linux/platform_device.h> +#include <linux/acpi.h> enum { FB_GET_WIDTH = 0x00, @@ -124,6 +125,7 @@ static int goldfish_fb_check_var(struct fb_var_screeninfo *var, static int goldfish_fb_set_par(struct fb_info *info) { struct goldfish_fb *fb = container_of(info, struct goldfish_fb, fb); + if (fb->rotation != fb->fb.var.rotate) { info->fix.line_length = info->var.xres * 2; fb->rotation = fb->fb.var.rotate; @@ -148,13 +150,14 @@ static int goldfish_fb_pan_display(struct fb_var_screeninfo *var, wait_event_timeout(fb->wait, fb->base_update_count != base_update_count, HZ / 15); if (fb->base_update_count == base_update_count) - pr_err("goldfish_fb_pan_display: timeout waiting for base update\n"); + pr_err("%s: timeout waiting for base update\n", __func__); return 0; } static int goldfish_fb_blank(int blank, struct fb_info *info) { struct goldfish_fb *fb = container_of(info, struct goldfish_fb, fb); + switch (blank) { case FB_BLANK_NORMAL: writel(1, fb->reg_base + FB_SET_BLANK); @@ -234,7 +237,7 @@ static int goldfish_fb_probe(struct platform_device *pdev) fb->fb.var.activate = FB_ACTIVATE_NOW; fb->fb.var.height = readl(fb->reg_base + FB_GET_PHYS_HEIGHT); fb->fb.var.width = readl(fb->reg_base + FB_GET_PHYS_WIDTH); - fb->fb.var.pixclock = 10000; + fb->fb.var.pixclock = 0; fb->fb.var.red.offset = 11; fb->fb.var.red.length = 5; @@ -301,6 +304,7 @@ static int goldfish_fb_remove(struct platform_device *pdev) dma_free_coherent(&pdev->dev, framesize, (void *)fb->fb.screen_base, fb->fb.fix.smem_start); iounmap(fb->reg_base); + kfree(fb); return 0; } @@ -310,12 +314,19 @@ static const struct of_device_id goldfish_fb_of_match[] = { }; MODULE_DEVICE_TABLE(of, goldfish_fb_of_match); +static const struct acpi_device_id goldfish_fb_acpi_match[] = { + { "GFSH0004", 0 }, + { }, +}; +MODULE_DEVICE_TABLE(acpi, goldfish_fb_acpi_match); + static struct platform_driver goldfish_fb_driver = { .probe = goldfish_fb_probe, .remove = goldfish_fb_remove, .driver = { .name = "goldfish_fb", .of_match_table = goldfish_fb_of_match, + .acpi_match_table = ACPI_PTR(goldfish_fb_acpi_match), } }; diff --git a/drivers/video/fbdev/i740fb.c b/drivers/video/fbdev/i740fb.c index 7bc5f6056c77..f6d7b04d6dff 100644 --- a/drivers/video/fbdev/i740fb.c +++ b/drivers/video/fbdev/i740fb.c @@ -429,6 +429,7 @@ static int i740fb_decode_var(const struct fb_var_screeninfo *var, break; case 9 ... 15: bpp = 15; + /* fall through */ case 16: if ((1000000 / var->pixclock) > DACSPEED16) { dev_err(info->device, "requested pixclock %i MHz out of range (max. %i MHz at 15/16bpp)\n", diff --git a/drivers/video/fbdev/metronomefb.c b/drivers/video/fbdev/metronomefb.c index 9085e9525341..bb4fee52e501 100644 --- a/drivers/video/fbdev/metronomefb.c +++ b/drivers/video/fbdev/metronomefb.c @@ -233,7 +233,7 @@ static int load_waveform(u8 *mem, size_t size, int m, int t, /* check temperature range table checksum */ cksum_idx = sizeof(*wfm_hdr) + wfm_hdr->trc + 1; - if (cksum_idx > size) + if (cksum_idx >= size) return -EINVAL; cksum = calc_cksum(sizeof(*wfm_hdr), cksum_idx, mem); if (cksum != mem[cksum_idx]) { @@ -245,7 +245,7 @@ static int load_waveform(u8 *mem, size_t size, int m, int t, /* check waveform mode table address checksum */ wmta = get_unaligned_le32(wfm_hdr->wmta) & 0x00FFFFFF; cksum_idx = wmta + m*4 + 3; - if (cksum_idx > size) + if (cksum_idx >= size) return -EINVAL; cksum = calc_cksum(cksum_idx - 3, cksum_idx, mem); if (cksum != mem[cksum_idx]) { @@ -257,7 +257,7 @@ static int load_waveform(u8 *mem, size_t size, int m, int t, /* check waveform temperature table address checksum */ tta = get_unaligned_le32(mem + wmta + m * 4) & 0x00FFFFFF; cksum_idx = tta + trn*4 + 3; - if (cksum_idx > size) + if (cksum_idx >= size) return -EINVAL; cksum = calc_cksum(cksum_idx - 3, cksum_idx, mem); if (cksum != mem[cksum_idx]) { @@ -270,7 +270,7 @@ static int load_waveform(u8 *mem, size_t size, int m, int t, metromem buffer. this does runlength decoding of the waveform */ wfm_idx = get_unaligned_le32(mem + tta + trn * 4) & 0x00FFFFFF; owfm_idx = wfm_idx; - if (wfm_idx > size) + if (wfm_idx >= size) return -EINVAL; while (wfm_idx < size) { unsigned char rl; @@ -292,7 +292,7 @@ static int load_waveform(u8 *mem, size_t size, int m, int t, } cksum_idx = wfm_idx; - if (cksum_idx > size) + if (cksum_idx >= size) return -EINVAL; cksum = calc_cksum(owfm_idx, cksum_idx, mem); if (cksum != mem[cksum_idx]) { diff --git a/drivers/video/fbdev/omap/omapfb_main.c b/drivers/video/fbdev/omap/omapfb_main.c index 585f39efcff6..1c75f4806ed3 100644 --- a/drivers/video/fbdev/omap/omapfb_main.c +++ b/drivers/video/fbdev/omap/omapfb_main.c @@ -958,7 +958,7 @@ int omapfb_register_client(struct omapfb_notifier_block *omapfb_nb, { int r; - if ((unsigned)omapfb_nb->plane_idx > OMAPFB_PLANE_NUM) + if ((unsigned)omapfb_nb->plane_idx >= OMAPFB_PLANE_NUM) return -EINVAL; if (!notifier_inited) { diff --git a/drivers/video/fbdev/omap2/omapfb/Makefile b/drivers/video/fbdev/omap2/omapfb/Makefile index 602edfed09df..f54c3f56b641 100644 --- a/drivers/video/fbdev/omap2/omapfb/Makefile +++ b/drivers/video/fbdev/omap2/omapfb/Makefile @@ -2,5 +2,5 @@ obj-$(CONFIG_OMAP2_VRFB) += vrfb.o obj-y += dss/ obj-y += displays/ -obj-$(CONFIG_FB_OMAP2) += omapfb.o -omapfb-y := omapfb-main.o omapfb-sysfs.o omapfb-ioctl.o +obj-$(CONFIG_FB_OMAP2) += omap2fb.o +omap2fb-y := omapfb-main.o omapfb-sysfs.o omapfb-ioctl.o diff --git a/drivers/video/fbdev/omap2/omapfb/displays/encoder-tpd12s015.c b/drivers/video/fbdev/omap2/omapfb/displays/encoder-tpd12s015.c index 3079a3df8c37..47f0459e3551 100644 --- a/drivers/video/fbdev/omap2/omapfb/displays/encoder-tpd12s015.c +++ b/drivers/video/fbdev/omap2/omapfb/displays/encoder-tpd12s015.c @@ -219,7 +219,7 @@ static int tpd_probe_of(struct platform_device *pdev) static int tpd_probe(struct platform_device *pdev) { - struct omap_dss_device *in, *dssdev; + struct omap_dss_device *dssdev; struct panel_drv_data *ddata; int r; struct gpio_desc *gpio; @@ -238,25 +238,30 @@ static int tpd_probe(struct platform_device *pdev) return -ENODEV; } - gpio = devm_gpiod_get_index_optional(&pdev->dev, NULL, 0, GPIOD_OUT_LOW); - if (IS_ERR(gpio)) + if (IS_ERR(gpio)) { + r = PTR_ERR(gpio); goto err_gpio; + } ddata->ct_cp_hpd_gpio = gpio; gpio = devm_gpiod_get_index_optional(&pdev->dev, NULL, 1, GPIOD_OUT_LOW); - if (IS_ERR(gpio)) + if (IS_ERR(gpio)) { + r = PTR_ERR(gpio); goto err_gpio; + } ddata->ls_oe_gpio = gpio; gpio = devm_gpiod_get_index(&pdev->dev, NULL, 2, GPIOD_IN); - if (IS_ERR(gpio)) + if (IS_ERR(gpio)) { + r = PTR_ERR(gpio); goto err_gpio; + } ddata->hpd_gpio = gpio; @@ -268,8 +273,6 @@ static int tpd_probe(struct platform_device *pdev) dssdev->owner = THIS_MODULE; dssdev->port_num = 1; - in = ddata->in; - r = omapdss_register_output(dssdev); if (r) { dev_err(&pdev->dev, "Failed to register output\n"); diff --git a/drivers/video/fbdev/omap2/omapfb/dss/dispc.c b/drivers/video/fbdev/omap2/omapfb/dss/dispc.c index fb605aefd9b1..a06d9c25765c 100644 --- a/drivers/video/fbdev/omap2/omapfb/dss/dispc.c +++ b/drivers/video/fbdev/omap2/omapfb/dss/dispc.c @@ -1858,7 +1858,7 @@ static s32 pixinc(int pixels, u8 ps) return 1 - (-pixels + 1) * ps; else BUG(); - return 0; + return 0; } static void calc_vrfb_rotation_offset(u8 rotation, bool mirror, @@ -1905,6 +1905,7 @@ static void calc_vrfb_rotation_offset(u8 rotation, bool mirror, if (color_mode == OMAP_DSS_COLOR_YUV2 || color_mode == OMAP_DSS_COLOR_UYVY) width = width >> 1; + /* fall through */ case OMAP_DSS_ROT_90: case OMAP_DSS_ROT_270: *offset1 = 0; @@ -1927,6 +1928,7 @@ static void calc_vrfb_rotation_offset(u8 rotation, bool mirror, if (color_mode == OMAP_DSS_COLOR_YUV2 || color_mode == OMAP_DSS_COLOR_UYVY) width = width >> 1; + /* fall through */ case OMAP_DSS_ROT_90 + 4: case OMAP_DSS_ROT_270 + 4: *offset1 = 0; diff --git a/drivers/video/fbdev/omap2/omapfb/omapfb-main.c b/drivers/video/fbdev/omap2/omapfb/omapfb-main.c index 3e7887c53d7c..b8b5b4ac0e09 100644 --- a/drivers/video/fbdev/omap2/omapfb/omapfb-main.c +++ b/drivers/video/fbdev/omap2/omapfb/omapfb-main.c @@ -893,6 +893,7 @@ int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl, / (var->bits_per_pixel >> 2); break; } + /* fall through */ default: screen_width = fix->line_length / (var->bits_per_pixel >> 3); break; diff --git a/drivers/video/fbdev/pm2fb.c b/drivers/video/fbdev/pm2fb.c index bd6c2f5f6095..1dcf02e12af4 100644 --- a/drivers/video/fbdev/pm2fb.c +++ b/drivers/video/fbdev/pm2fb.c @@ -233,8 +233,10 @@ static u32 to3264(u32 timing, int bpp, int is64) switch (bpp) { case 24: timing *= 3; + /* fall through */ case 8: timing >>= 1; + /* fall through */ case 16: timing >>= 1; case 32: diff --git a/drivers/video/fbdev/pxa3xx-gcu.c b/drivers/video/fbdev/pxa3xx-gcu.c index 0955622a1227..69cfb337c857 100644 --- a/drivers/video/fbdev/pxa3xx-gcu.c +++ b/drivers/video/fbdev/pxa3xx-gcu.c @@ -44,6 +44,7 @@ #include <linux/clk.h> #include <linux/fs.h> #include <linux/io.h> +#include <linux/of.h> #include "pxa3xx-gcu.h" @@ -703,11 +704,20 @@ static int pxa3xx_gcu_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_OF +static const struct of_device_id pxa3xx_gcu_of_match[] = { + { .compatible = "marvell,pxa300-gcu", }, + { } +}; +MODULE_DEVICE_TABLE(of, pxa3xx_gcu_of_match); +#endif + static struct platform_driver pxa3xx_gcu_driver = { .probe = pxa3xx_gcu_probe, .remove = pxa3xx_gcu_remove, .driver = { .name = DRV_NAME, + .of_match_table = of_match_ptr(pxa3xx_gcu_of_match), }, }; diff --git a/drivers/video/fbdev/pxafb.c b/drivers/video/fbdev/pxafb.c index 76722a59f55e..bbed039617a4 100644 --- a/drivers/video/fbdev/pxafb.c +++ b/drivers/video/fbdev/pxafb.c @@ -56,6 +56,7 @@ #include <linux/freezer.h> #include <linux/console.h> #include <linux/of_graph.h> +#include <linux/regulator/consumer.h> #include <video/of_display_timing.h> #include <video/videomode.h> @@ -1423,6 +1424,21 @@ static inline void __pxafb_lcd_power(struct pxafb_info *fbi, int on) if (fbi->lcd_power) fbi->lcd_power(on, &fbi->fb.var); + + if (fbi->lcd_supply && fbi->lcd_supply_enabled != on) { + int ret; + + if (on) + ret = regulator_enable(fbi->lcd_supply); + else + ret = regulator_disable(fbi->lcd_supply); + + if (ret < 0) + pr_warn("Unable to %s LCD supply regulator: %d\n", + on ? "enable" : "disable", ret); + else + fbi->lcd_supply_enabled = on; + } } static void pxafb_enable_controller(struct pxafb_info *fbi) @@ -1799,19 +1815,17 @@ static struct pxafb_info *pxafb_init_fbinfo(struct device *dev, void *addr; /* Alloc the pxafb_info and pseudo_palette in one step */ - fbi = kmalloc(sizeof(struct pxafb_info) + sizeof(u32) * 16, GFP_KERNEL); + fbi = devm_kzalloc(dev, sizeof(struct pxafb_info) + sizeof(u32) * 16, + GFP_KERNEL); if (!fbi) - return NULL; + return ERR_PTR(-ENOMEM); - memset(fbi, 0, sizeof(struct pxafb_info)); fbi->dev = dev; fbi->inf = inf; - fbi->clk = clk_get(dev, NULL); - if (IS_ERR(fbi->clk)) { - kfree(fbi); - return NULL; - } + fbi->clk = devm_clk_get(dev, NULL); + if (IS_ERR(fbi->clk)) + return ERR_CAST(fbi->clk); strcpy(fbi->fb.fix.id, PXA_NAME); @@ -2128,8 +2142,9 @@ static int of_get_pxafb_display(struct device *dev, struct device_node *disp, return -EINVAL; ret = -ENOMEM; - info->modes = kmalloc_array(timings->num_timings, - sizeof(info->modes[0]), GFP_KERNEL); + info->modes = devm_kcalloc(dev, timings->num_timings, + sizeof(info->modes[0]), + GFP_KERNEL); if (!info->modes) goto out; info->num_modes = timings->num_timings; @@ -2288,10 +2303,9 @@ static int pxafb_probe(struct platform_device *dev) } fbi = pxafb_init_fbinfo(&dev->dev, inf); - if (!fbi) { - /* only reason for pxafb_init_fbinfo to fail is kmalloc */ + if (IS_ERR(fbi)) { dev_err(&dev->dev, "Failed to initialize framebuffer device\n"); - ret = -ENOMEM; + ret = PTR_ERR(fbi); goto failed; } @@ -2301,25 +2315,26 @@ static int pxafb_probe(struct platform_device *dev) fbi->backlight_power = inf->pxafb_backlight_power; fbi->lcd_power = inf->pxafb_lcd_power; + fbi->lcd_supply = devm_regulator_get_optional(&dev->dev, "lcd"); + if (IS_ERR(fbi->lcd_supply)) { + if (PTR_ERR(fbi->lcd_supply) == -EPROBE_DEFER) + return -EPROBE_DEFER; + + fbi->lcd_supply = NULL; + } + r = platform_get_resource(dev, IORESOURCE_MEM, 0); if (r == NULL) { dev_err(&dev->dev, "no I/O memory resource defined\n"); ret = -ENODEV; - goto failed_fbi; - } - - r = request_mem_region(r->start, resource_size(r), dev->name); - if (r == NULL) { - dev_err(&dev->dev, "failed to request I/O memory\n"); - ret = -EBUSY; - goto failed_fbi; + goto failed; } - fbi->mmio_base = ioremap(r->start, resource_size(r)); - if (fbi->mmio_base == NULL) { - dev_err(&dev->dev, "failed to map I/O memory\n"); + fbi->mmio_base = devm_ioremap_resource(&dev->dev, r); + if (IS_ERR(fbi->mmio_base)) { + dev_err(&dev->dev, "failed to get I/O memory\n"); ret = -EBUSY; - goto failed_free_res; + goto failed; } fbi->dma_buff_size = PAGE_ALIGN(sizeof(struct pxafb_dma_buff)); @@ -2328,7 +2343,7 @@ static int pxafb_probe(struct platform_device *dev) if (fbi->dma_buff == NULL) { dev_err(&dev->dev, "failed to allocate memory for DMA\n"); ret = -ENOMEM; - goto failed_free_io; + goto failed; } ret = pxafb_init_video_memory(fbi); @@ -2345,7 +2360,7 @@ static int pxafb_probe(struct platform_device *dev) goto failed_free_mem; } - ret = request_irq(irq, pxafb_handle_irq, 0, "LCD", fbi); + ret = devm_request_irq(&dev->dev, irq, pxafb_handle_irq, 0, "LCD", fbi); if (ret) { dev_err(&dev->dev, "request_irq failed: %d\n", ret); ret = -EBUSY; @@ -2355,7 +2370,7 @@ static int pxafb_probe(struct platform_device *dev) ret = pxafb_smart_init(fbi); if (ret) { dev_err(&dev->dev, "failed to initialize smartpanel\n"); - goto failed_free_irq; + goto failed_free_mem; } /* @@ -2365,13 +2380,13 @@ static int pxafb_probe(struct platform_device *dev) ret = pxafb_check_var(&fbi->fb.var, &fbi->fb); if (ret) { dev_err(&dev->dev, "failed to get suitable mode\n"); - goto failed_free_irq; + goto failed_free_mem; } ret = pxafb_set_par(&fbi->fb); if (ret) { dev_err(&dev->dev, "Failed to set parameters\n"); - goto failed_free_irq; + goto failed_free_mem; } platform_set_drvdata(dev, fbi); @@ -2404,20 +2419,11 @@ static int pxafb_probe(struct platform_device *dev) failed_free_cmap: if (fbi->fb.cmap.len) fb_dealloc_cmap(&fbi->fb.cmap); -failed_free_irq: - free_irq(irq, fbi); failed_free_mem: free_pages_exact(fbi->video_mem, fbi->video_mem_size); failed_free_dma: dma_free_coherent(&dev->dev, fbi->dma_buff_size, fbi->dma_buff, fbi->dma_buff_phys); -failed_free_io: - iounmap(fbi->mmio_base); -failed_free_res: - release_mem_region(r->start, resource_size(r)); -failed_fbi: - clk_put(fbi->clk); - kfree(fbi); failed: return ret; } @@ -2425,8 +2431,6 @@ failed: static int pxafb_remove(struct platform_device *dev) { struct pxafb_info *fbi = platform_get_drvdata(dev); - struct resource *r; - int irq; struct fb_info *info; if (!fbi) @@ -2442,22 +2446,11 @@ static int pxafb_remove(struct platform_device *dev) if (fbi->fb.cmap.len) fb_dealloc_cmap(&fbi->fb.cmap); - irq = platform_get_irq(dev, 0); - free_irq(irq, fbi); - free_pages_exact(fbi->video_mem, fbi->video_mem_size); dma_free_wc(&dev->dev, fbi->dma_buff_size, fbi->dma_buff, fbi->dma_buff_phys); - iounmap(fbi->mmio_base); - - r = platform_get_resource(dev, IORESOURCE_MEM, 0); - release_mem_region(r->start, resource_size(r)); - - clk_put(fbi->clk); - kfree(fbi); - return 0; } diff --git a/drivers/video/fbdev/pxafb.h b/drivers/video/fbdev/pxafb.h index 5dc414e26fc8..b641289c8a99 100644 --- a/drivers/video/fbdev/pxafb.h +++ b/drivers/video/fbdev/pxafb.h @@ -165,6 +165,9 @@ struct pxafb_info { struct notifier_block freq_policy; #endif + struct regulator *lcd_supply; + bool lcd_supply_enabled; + void (*lcd_power)(int, struct fb_var_screeninfo *); void (*backlight_power)(int); diff --git a/drivers/video/fbdev/simplefb.c b/drivers/video/fbdev/simplefb.c index a3c44ecf4523..9a9d748b07f2 100644 --- a/drivers/video/fbdev/simplefb.c +++ b/drivers/video/fbdev/simplefb.c @@ -27,8 +27,8 @@ #include <linux/platform_data/simplefb.h> #include <linux/platform_device.h> #include <linux/clk.h> -#include <linux/clk-provider.h> #include <linux/of.h> +#include <linux/of_clk.h> #include <linux/of_platform.h> #include <linux/parser.h> #include <linux/regulator/consumer.h> diff --git a/drivers/video/fbdev/tdfxfb.c b/drivers/video/fbdev/tdfxfb.c index dec1fed9880e..fbbf26b170f7 100644 --- a/drivers/video/fbdev/tdfxfb.c +++ b/drivers/video/fbdev/tdfxfb.c @@ -522,6 +522,7 @@ static int tdfxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) case 32: var->transp.offset = 24; var->transp.length = 8; + /* fall through */ case 24: var->red.offset = 16; var->green.offset = 8; diff --git a/drivers/video/fbdev/tridentfb.c b/drivers/video/fbdev/tridentfb.c index 284706184b1b..f4b745590600 100644 --- a/drivers/video/fbdev/tridentfb.c +++ b/drivers/video/fbdev/tridentfb.c @@ -777,9 +777,6 @@ static int get_nativex(struct tridentfb_par *par) case 3: x = 800; y = 600; break; - case 4: - x = 1400; y = 1050; - break; case 1: default: x = 640; y = 480; diff --git a/drivers/video/fbdev/udlfb.c b/drivers/video/fbdev/udlfb.c index f365d4862015..afbd6101c78e 100644 --- a/drivers/video/fbdev/udlfb.c +++ b/drivers/video/fbdev/udlfb.c @@ -25,8 +25,8 @@ #include <linux/fb.h> #include <linux/vmalloc.h> #include <linux/slab.h> -#include <linux/prefetch.h> #include <linux/delay.h> +#include <asm/unaligned.h> #include <video/udlfb.h> #include "edid.h" @@ -72,6 +72,13 @@ static bool fb_defio = 1; /* Detect mmap writes using page faults */ static bool shadow = 1; /* Optionally disable shadow framebuffer */ static int pixel_limit; /* Optionally force a pixel resolution limit */ +struct dlfb_deferred_free { + struct list_head list; + void *mem; +}; + +static int dlfb_realloc_framebuffer(struct dlfb_data *dlfb, struct fb_info *info, u32 new_len); + /* dlfb keeps a list of urbs for efficient bulk transfers */ static void dlfb_urb_completion(struct urb *urb); static struct urb *dlfb_get_urb(struct dlfb_data *dlfb); @@ -367,9 +374,6 @@ static int dlfb_trim_hline(const u8 *bback, const u8 **bfront, int *width_bytes) int start = width; int end = width; - prefetch((void *) front); - prefetch((void *) back); - for (j = 0; j < width; j++) { if (back[j] != front[j]) { start = j; @@ -423,7 +427,9 @@ static void dlfb_compress_hline( const uint16_t *const pixel_end, uint32_t *device_address_ptr, uint8_t **command_buffer_ptr, - const uint8_t *const cmd_buffer_end) + const uint8_t *const cmd_buffer_end, + unsigned long back_buffer_offset, + int *ident_ptr) { const uint16_t *pixel = *pixel_start_ptr; uint32_t dev_addr = *device_address_ptr; @@ -436,7 +442,13 @@ static void dlfb_compress_hline( const uint16_t *raw_pixel_start = NULL; const uint16_t *cmd_pixel_start, *cmd_pixel_end = NULL; - prefetchw((void *) cmd); /* pull in one cache line at least */ + if (back_buffer_offset && + *pixel == *(u16 *)((u8 *)pixel + back_buffer_offset)) { + pixel++; + dev_addr += BPP; + (*ident_ptr)++; + continue; + } *cmd++ = 0xAF; *cmd++ = 0x6B; @@ -450,29 +462,39 @@ static void dlfb_compress_hline( raw_pixels_count_byte = cmd++; /* we'll know this later */ raw_pixel_start = pixel; - cmd_pixel_end = pixel + min(MAX_CMD_PIXELS + 1, - min((int)(pixel_end - pixel), - (int)(cmd_buffer_end - cmd) / BPP)); + cmd_pixel_end = pixel + min3(MAX_CMD_PIXELS + 1UL, + (unsigned long)(pixel_end - pixel), + (unsigned long)(cmd_buffer_end - 1 - cmd) / BPP); - prefetch_range((void *) pixel, (cmd_pixel_end - pixel) * BPP); + if (back_buffer_offset) { + /* note: the framebuffer may change under us, so we must test for underflow */ + while (cmd_pixel_end - 1 > pixel && + *(cmd_pixel_end - 1) == *(u16 *)((u8 *)(cmd_pixel_end - 1) + back_buffer_offset)) + cmd_pixel_end--; + } while (pixel < cmd_pixel_end) { const uint16_t * const repeating_pixel = pixel; + u16 pixel_value = *pixel; - *cmd++ = *pixel >> 8; - *cmd++ = *pixel; + put_unaligned_be16(pixel_value, cmd); + if (back_buffer_offset) + *(u16 *)((u8 *)pixel + back_buffer_offset) = pixel_value; + cmd += 2; pixel++; if (unlikely((pixel < cmd_pixel_end) && - (*pixel == *repeating_pixel))) { + (*pixel == pixel_value))) { /* go back and fill in raw pixel count */ *raw_pixels_count_byte = ((repeating_pixel - raw_pixel_start) + 1) & 0xFF; - while ((pixel < cmd_pixel_end) - && (*pixel == *repeating_pixel)) { + do { + if (back_buffer_offset) + *(u16 *)((u8 *)pixel + back_buffer_offset) = pixel_value; pixel++; - } + } while ((pixel < cmd_pixel_end) && + (*pixel == pixel_value)); /* immediately after raw data is repeat byte */ *cmd++ = ((pixel - repeating_pixel) - 1) & 0xFF; @@ -486,13 +508,16 @@ static void dlfb_compress_hline( if (pixel > raw_pixel_start) { /* finalize last RAW span */ *raw_pixels_count_byte = (pixel-raw_pixel_start) & 0xFF; + } else { + /* undo unused byte */ + cmd--; } *cmd_pixels_count_byte = (pixel - cmd_pixel_start) & 0xFF; - dev_addr += (pixel - cmd_pixel_start) * BPP; + dev_addr += (u8 *)pixel - (u8 *)cmd_pixel_start; } - if (cmd_buffer_end <= MIN_RLX_CMD_BYTES + cmd) { + if (cmd_buffer_end - MIN_RLX_CMD_BYTES <= cmd) { /* Fill leftover bytes with no-ops */ if (cmd_buffer_end > cmd) memset(cmd, 0xAF, cmd_buffer_end - cmd); @@ -520,6 +545,7 @@ static int dlfb_render_hline(struct dlfb_data *dlfb, struct urb **urb_ptr, struct urb *urb = *urb_ptr; u8 *cmd = *urb_buf_ptr; u8 *cmd_end = (u8 *) urb->transfer_buffer + urb->transfer_buffer_length; + unsigned long back_buffer_offset = 0; line_start = (u8 *) (front + byte_offset); next_pixel = line_start; @@ -530,6 +556,8 @@ static int dlfb_render_hline(struct dlfb_data *dlfb, struct urb **urb_ptr, const u8 *back_start = (u8 *) (dlfb->backing_buffer + byte_offset); + back_buffer_offset = (unsigned long)back_start - (unsigned long)line_start; + *ident_ptr += dlfb_trim_hline(back_start, &next_pixel, &byte_width); @@ -538,16 +566,14 @@ static int dlfb_render_hline(struct dlfb_data *dlfb, struct urb **urb_ptr, dev_addr += offset; back_start += offset; line_start += offset; - - memcpy((char *)back_start, (char *) line_start, - byte_width); } while (next_pixel < line_end) { dlfb_compress_hline((const uint16_t **) &next_pixel, (const uint16_t *) line_end, &dev_addr, - (u8 **) &cmd, (u8 *) cmd_end); + (u8 **) &cmd, (u8 *) cmd_end, back_buffer_offset, + ident_ptr); if (cmd >= cmd_end) { int len = cmd - (u8 *) urb->transfer_buffer; @@ -610,8 +636,11 @@ static int dlfb_handle_damage(struct dlfb_data *dlfb, int x, int y, } if (cmd > (char *) urb->transfer_buffer) { + int len; + if (cmd < (char *) urb->transfer_buffer + urb->transfer_buffer_length) + *cmd++ = 0xAF; /* Send partial buffer remaining before exiting */ - int len = cmd - (char *) urb->transfer_buffer; + len = cmd - (char *) urb->transfer_buffer; ret = dlfb_submit_urb(dlfb, urb, len); bytes_sent += len; } else @@ -735,8 +764,11 @@ static void dlfb_dpy_deferred_io(struct fb_info *info, } if (cmd > (char *) urb->transfer_buffer) { + int len; + if (cmd < (char *) urb->transfer_buffer + urb->transfer_buffer_length) + *cmd++ = 0xAF; /* Send partial buffer remaining before exiting */ - int len = cmd - (char *) urb->transfer_buffer; + len = cmd - (char *) urb->transfer_buffer; dlfb_submit_urb(dlfb, urb, len); bytes_sent += len; } else @@ -917,19 +949,17 @@ static void dlfb_free(struct kref *kref) { struct dlfb_data *dlfb = container_of(kref, struct dlfb_data, kref); + while (!list_empty(&dlfb->deferred_free)) { + struct dlfb_deferred_free *d = list_entry(dlfb->deferred_free.next, struct dlfb_deferred_free, list); + list_del(&d->list); + vfree(d->mem); + kfree(d); + } vfree(dlfb->backing_buffer); kfree(dlfb->edid); kfree(dlfb); } -static void dlfb_release_urb_work(struct work_struct *work) -{ - struct urb_node *unode = container_of(work, struct urb_node, - release_urb_work.work); - - up(&unode->dlfb->urbs.limit_sem); -} - static void dlfb_free_framebuffer(struct dlfb_data *dlfb) { struct fb_info *info = dlfb->info; @@ -1018,10 +1048,6 @@ static int dlfb_ops_check_var(struct fb_var_screeninfo *var, struct fb_videomode mode; struct dlfb_data *dlfb = info->par; - /* TODO: support dynamically changing framebuffer size */ - if ((var->xres * var->yres * 2) > info->fix.smem_len) - return -EINVAL; - /* set device-specific elements of var unrelated to mode */ dlfb_var_color_format(var); @@ -1039,22 +1065,42 @@ static int dlfb_ops_set_par(struct fb_info *info) int result; u16 *pix_framebuffer; int i; + struct fb_var_screeninfo fvs; + u32 line_length = info->var.xres * (info->var.bits_per_pixel / 8); + + /* clear the activate field because it causes spurious miscompares */ + fvs = info->var; + fvs.activate = 0; + fvs.vmode &= ~FB_VMODE_SMOOTH_XPAN; + + if (!memcmp(&dlfb->current_mode, &fvs, sizeof(struct fb_var_screeninfo))) + return 0; + + result = dlfb_realloc_framebuffer(dlfb, info, info->var.yres * line_length); + if (result) + return result; result = dlfb_set_video_mode(dlfb, &info->var); - if ((result == 0) && (dlfb->fb_count == 0)) { + if (result) + return result; + + dlfb->current_mode = fvs; + info->fix.line_length = line_length; + + if (dlfb->fb_count == 0) { /* paint greenscreen */ pix_framebuffer = (u16 *) info->screen_base; for (i = 0; i < info->fix.smem_len / 2; i++) pix_framebuffer[i] = 0x37e6; - - dlfb_handle_damage(dlfb, 0, 0, info->var.xres, info->var.yres, - info->screen_base); } - return result; + dlfb_handle_damage(dlfb, 0, 0, info->var.xres, info->var.yres, + info->screen_base); + + return 0; } /* To fonzi the jukebox (e.g. make blanking changes take effect) */ @@ -1129,21 +1175,29 @@ static struct fb_ops dlfb_ops = { }; +static void dlfb_deferred_vfree(struct dlfb_data *dlfb, void *mem) +{ + struct dlfb_deferred_free *d = kmalloc(sizeof(struct dlfb_deferred_free), GFP_KERNEL); + if (!d) + return; + d->mem = mem; + list_add(&d->list, &dlfb->deferred_free); +} + /* * Assumes &info->lock held by caller * Assumes no active clients have framebuffer open */ -static int dlfb_realloc_framebuffer(struct dlfb_data *dlfb, struct fb_info *info) +static int dlfb_realloc_framebuffer(struct dlfb_data *dlfb, struct fb_info *info, u32 new_len) { - int old_len = info->fix.smem_len; - int new_len; - unsigned char *old_fb = info->screen_base; + u32 old_len = info->fix.smem_len; + const void *old_fb = (const void __force *)info->screen_base; unsigned char *new_fb; unsigned char *new_back = NULL; - new_len = info->fix.line_length * info->var.yres; + new_len = PAGE_ALIGN(new_len); - if (PAGE_ALIGN(new_len) > old_len) { + if (new_len > old_len) { /* * Alloc system memory for virtual framebuffer */ @@ -1152,14 +1206,15 @@ static int dlfb_realloc_framebuffer(struct dlfb_data *dlfb, struct fb_info *info dev_err(info->dev, "Virtual framebuffer alloc failed\n"); return -ENOMEM; } + memset(new_fb, 0xff, new_len); if (info->screen_base) { memcpy(new_fb, old_fb, old_len); - vfree(info->screen_base); + dlfb_deferred_vfree(dlfb, (void __force *)info->screen_base); } - info->screen_base = new_fb; - info->fix.smem_len = PAGE_ALIGN(new_len); + info->screen_base = (char __iomem *)new_fb; + info->fix.smem_len = new_len; info->fix.smem_start = (unsigned long) new_fb; info->flags = udlfb_info_flags; @@ -1175,7 +1230,7 @@ static int dlfb_realloc_framebuffer(struct dlfb_data *dlfb, struct fb_info *info dev_info(info->dev, "No shadow/backing buffer allocated\n"); else { - vfree(dlfb->backing_buffer); + dlfb_deferred_vfree(dlfb, dlfb->backing_buffer); dlfb->backing_buffer = new_back; } } @@ -1327,11 +1382,6 @@ static int dlfb_setup_modes(struct dlfb_data *dlfb, * with mode size info, we can now alloc our framebuffer. */ memcpy(&info->fix, &dlfb_fix, sizeof(dlfb_fix)); - info->fix.line_length = info->var.xres * - (info->var.bits_per_pixel / 8); - - result = dlfb_realloc_framebuffer(dlfb, info); - } else result = -EINVAL; @@ -1419,7 +1469,10 @@ static ssize_t edid_store( if (!dlfb->edid || memcmp(src, dlfb->edid, src_size)) return -EINVAL; - dlfb_ops_set_par(fb_info); + ret = dlfb_ops_set_par(fb_info); + if (ret) + return ret; + return src_size; } @@ -1579,6 +1632,7 @@ static int dlfb_usb_probe(struct usb_interface *intf, } kref_init(&dlfb->kref); /* matching kref_put in usb .disconnect fn */ + INIT_LIST_HEAD(&dlfb->deferred_free); dlfb->udev = usbdev; usb_set_intfdata(intf, dlfb); @@ -1649,7 +1703,8 @@ static void dlfb_init_framebuffer_work(struct work_struct *work) dlfb->info = info; info->par = dlfb; info->pseudo_palette = dlfb->pseudo_palette; - info->fbops = &dlfb_ops; + dlfb->ops = dlfb_ops; + info->fbops = &dlfb->ops; retval = fb_alloc_cmap(&info->cmap, 256, 0); if (retval < 0) { @@ -1675,7 +1730,9 @@ static void dlfb_init_framebuffer_work(struct work_struct *work) dlfb_select_std_channel(dlfb); dlfb_ops_check_var(&info->var, info); - dlfb_ops_set_par(info); + retval = dlfb_ops_set_par(info); + if (retval) + goto error; retval = register_framebuffer(info); if (retval < 0) { @@ -1789,14 +1846,7 @@ static void dlfb_urb_completion(struct urb *urb) dlfb->urbs.available++; spin_unlock_irqrestore(&dlfb->urbs.lock, flags); - /* - * When using fb_defio, we deadlock if up() is called - * while another is waiting. So queue to another process. - */ - if (fb_defio) - schedule_delayed_work(&unode->release_urb_work, 0); - else - up(&dlfb->urbs.limit_sem); + up(&dlfb->urbs.limit_sem); } static void dlfb_free_urb_list(struct dlfb_data *dlfb) @@ -1805,23 +1855,17 @@ static void dlfb_free_urb_list(struct dlfb_data *dlfb) struct list_head *node; struct urb_node *unode; struct urb *urb; - int ret; - unsigned long flags; /* keep waiting and freeing, until we've got 'em all */ while (count--) { + down(&dlfb->urbs.limit_sem); - /* Getting interrupted means a leak, but ok at disconnect */ - ret = down_interruptible(&dlfb->urbs.limit_sem); - if (ret) - break; - - spin_lock_irqsave(&dlfb->urbs.lock, flags); + spin_lock_irq(&dlfb->urbs.lock); node = dlfb->urbs.list.next; /* have reserved one with sem */ list_del_init(node); - spin_unlock_irqrestore(&dlfb->urbs.lock, flags); + spin_unlock_irq(&dlfb->urbs.lock); unode = list_entry(node, struct urb_node, entry); urb = unode->urb; @@ -1838,25 +1882,27 @@ static void dlfb_free_urb_list(struct dlfb_data *dlfb) static int dlfb_alloc_urb_list(struct dlfb_data *dlfb, int count, size_t size) { - int i = 0; struct urb *urb; struct urb_node *unode; char *buf; + size_t wanted_size = count * size; spin_lock_init(&dlfb->urbs.lock); +retry: dlfb->urbs.size = size; INIT_LIST_HEAD(&dlfb->urbs.list); - while (i < count) { + sema_init(&dlfb->urbs.limit_sem, 0); + dlfb->urbs.count = 0; + dlfb->urbs.available = 0; + + while (dlfb->urbs.count * size < wanted_size) { unode = kzalloc(sizeof(*unode), GFP_KERNEL); if (!unode) break; unode->dlfb = dlfb; - INIT_DELAYED_WORK(&unode->release_urb_work, - dlfb_release_urb_work); - urb = usb_alloc_urb(0, GFP_KERNEL); if (!urb) { kfree(unode); @@ -1864,11 +1910,16 @@ static int dlfb_alloc_urb_list(struct dlfb_data *dlfb, int count, size_t size) } unode->urb = urb; - buf = usb_alloc_coherent(dlfb->udev, MAX_TRANSFER, GFP_KERNEL, + buf = usb_alloc_coherent(dlfb->udev, size, GFP_KERNEL, &urb->transfer_dma); if (!buf) { kfree(unode); usb_free_urb(urb); + if (size > PAGE_SIZE) { + size /= 2; + dlfb_free_urb_list(dlfb); + goto retry; + } break; } @@ -1879,14 +1930,12 @@ static int dlfb_alloc_urb_list(struct dlfb_data *dlfb, int count, size_t size) list_add_tail(&unode->entry, &dlfb->urbs.list); - i++; + up(&dlfb->urbs.limit_sem); + dlfb->urbs.count++; + dlfb->urbs.available++; } - sema_init(&dlfb->urbs.limit_sem, i); - dlfb->urbs.count = i; - dlfb->urbs.available = i; - - return i; + return dlfb->urbs.count; } static struct urb *dlfb_get_urb(struct dlfb_data *dlfb) @@ -1894,7 +1943,6 @@ static struct urb *dlfb_get_urb(struct dlfb_data *dlfb) int ret; struct list_head *entry; struct urb_node *unode; - unsigned long flags; /* Wait for an in-flight buffer to complete and get re-queued */ ret = down_timeout(&dlfb->urbs.limit_sem, GET_URB_TIMEOUT); @@ -1906,14 +1954,14 @@ static struct urb *dlfb_get_urb(struct dlfb_data *dlfb) return NULL; } - spin_lock_irqsave(&dlfb->urbs.lock, flags); + spin_lock_irq(&dlfb->urbs.lock); BUG_ON(list_empty(&dlfb->urbs.list)); /* reserved one with limit_sem */ entry = dlfb->urbs.list.next; list_del_init(entry); dlfb->urbs.available--; - spin_unlock_irqrestore(&dlfb->urbs.lock, flags); + spin_unlock_irq(&dlfb->urbs.lock); unode = list_entry(entry, struct urb_node, entry); return unode->urb; diff --git a/drivers/video/fbdev/via/lcd.c b/drivers/video/fbdev/via/lcd.c index 5d21ff436ec8..b9305d73a1e5 100644 --- a/drivers/video/fbdev/via/lcd.c +++ b/drivers/video/fbdev/via/lcd.c @@ -758,6 +758,7 @@ static void set_lcd_output_path(int set_iga, int output_interface) viaparinfo->chip_info->gfx_chip_name)) viafb_write_reg_mask(CR97, VIACR, 0x84, BIT7 + BIT2 + BIT1 + BIT0); + /* fall through */ case INTERFACE_DVP0: case INTERFACE_DVP1: case INTERFACE_DFP_HIGH: diff --git a/drivers/video/fbdev/via/viafbdev.c b/drivers/video/fbdev/via/viafbdev.c index d2f785068ef4..7bb7e90b8f00 100644 --- a/drivers/video/fbdev/via/viafbdev.c +++ b/drivers/video/fbdev/via/viafbdev.c @@ -19,6 +19,7 @@ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#include <linux/compiler.h> #include <linux/module.h> #include <linux/seq_file.h> #include <linux/slab.h> @@ -1468,7 +1469,7 @@ static const struct file_operations viafb_vt1636_proc_fops = { #endif /* CONFIG_FB_VIA_DIRECT_PROCFS */ -static int viafb_sup_odev_proc_show(struct seq_file *m, void *v) +static int __maybe_unused viafb_sup_odev_proc_show(struct seq_file *m, void *v) { via_odev_to_seq(m, supported_odev_map[ viaparinfo->shared->chip_info.gfx_chip_name]); diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c index 3988c0914322..d1c1f6283729 100644 --- a/drivers/virtio/virtio_balloon.c +++ b/drivers/virtio/virtio_balloon.c @@ -27,7 +27,6 @@ #include <linux/slab.h> #include <linux/module.h> #include <linux/balloon_compaction.h> -#include <linux/oom.h> #include <linux/wait.h> #include <linux/mm.h> #include <linux/mount.h> @@ -40,13 +39,8 @@ */ #define VIRTIO_BALLOON_PAGES_PER_PAGE (unsigned)(PAGE_SIZE >> VIRTIO_BALLOON_PFN_SHIFT) #define VIRTIO_BALLOON_ARRAY_PFNS_MAX 256 -#define OOM_VBALLOON_DEFAULT_PAGES 256 #define VIRTBALLOON_OOM_NOTIFY_PRIORITY 80 -static int oom_pages = OOM_VBALLOON_DEFAULT_PAGES; -module_param(oom_pages, int, S_IRUSR | S_IWUSR); -MODULE_PARM_DESC(oom_pages, "pages to free on OOM"); - #ifdef CONFIG_BALLOON_COMPACTION static struct vfsmount *balloon_mnt; #endif @@ -86,8 +80,8 @@ struct virtio_balloon { /* Memory statistics */ struct virtio_balloon_stat stats[VIRTIO_BALLOON_S_NR]; - /* To register callback in oom notifier call chain */ - struct notifier_block nb; + /* To register a shrinker to shrink memory upon memory pressure */ + struct shrinker shrinker; }; static struct virtio_device_id id_table[] = { @@ -365,38 +359,6 @@ static void update_balloon_size(struct virtio_balloon *vb) &actual); } -/* - * virtballoon_oom_notify - release pages when system is under severe - * memory pressure (called from out_of_memory()) - * @self : notifier block struct - * @dummy: not used - * @parm : returned - number of freed pages - * - * The balancing of memory by use of the virtio balloon should not cause - * the termination of processes while there are pages in the balloon. - * If virtio balloon manages to release some memory, it will make the - * system return and retry the allocation that forced the OOM killer - * to run. - */ -static int virtballoon_oom_notify(struct notifier_block *self, - unsigned long dummy, void *parm) -{ - struct virtio_balloon *vb; - unsigned long *freed; - unsigned num_freed_pages; - - vb = container_of(self, struct virtio_balloon, nb); - if (!virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_DEFLATE_ON_OOM)) - return NOTIFY_OK; - - freed = parm; - num_freed_pages = leak_balloon(vb, oom_pages); - update_balloon_size(vb); - *freed += num_freed_pages; - - return NOTIFY_OK; -} - static void update_balloon_stats_func(struct work_struct *work) { struct virtio_balloon *vb; @@ -455,9 +417,13 @@ static int init_vqs(struct virtio_balloon *vb) num_stats = update_balloon_stats(vb); sg_init_one(&sg, vb->stats, sizeof(vb->stats[0]) * num_stats); - if (virtqueue_add_outbuf(vb->stats_vq, &sg, 1, vb, GFP_KERNEL) - < 0) - BUG(); + err = virtqueue_add_outbuf(vb->stats_vq, &sg, 1, vb, + GFP_KERNEL); + if (err) { + dev_warn(&vb->vdev->dev, "%s: add stat_vq failed\n", + __func__); + return err; + } virtqueue_kick(vb->stats_vq); } return 0; @@ -546,6 +512,52 @@ static struct file_system_type balloon_fs = { #endif /* CONFIG_BALLOON_COMPACTION */ +static unsigned long virtio_balloon_shrinker_scan(struct shrinker *shrinker, + struct shrink_control *sc) +{ + unsigned long pages_to_free, pages_freed = 0; + struct virtio_balloon *vb = container_of(shrinker, + struct virtio_balloon, shrinker); + + pages_to_free = sc->nr_to_scan * VIRTIO_BALLOON_PAGES_PER_PAGE; + + /* + * One invocation of leak_balloon can deflate at most + * VIRTIO_BALLOON_ARRAY_PFNS_MAX balloon pages, so we call it + * multiple times to deflate pages till reaching pages_to_free. + */ + while (vb->num_pages && pages_to_free) { + pages_to_free -= pages_freed; + pages_freed += leak_balloon(vb, pages_to_free); + } + update_balloon_size(vb); + + return pages_freed / VIRTIO_BALLOON_PAGES_PER_PAGE; +} + +static unsigned long virtio_balloon_shrinker_count(struct shrinker *shrinker, + struct shrink_control *sc) +{ + struct virtio_balloon *vb = container_of(shrinker, + struct virtio_balloon, shrinker); + + return vb->num_pages / VIRTIO_BALLOON_PAGES_PER_PAGE; +} + +static void virtio_balloon_unregister_shrinker(struct virtio_balloon *vb) +{ + unregister_shrinker(&vb->shrinker); +} + +static int virtio_balloon_register_shrinker(struct virtio_balloon *vb) +{ + vb->shrinker.scan_objects = virtio_balloon_shrinker_scan; + vb->shrinker.count_objects = virtio_balloon_shrinker_count; + vb->shrinker.seeks = DEFAULT_SEEKS; + + return register_shrinker(&vb->shrinker); +} + static int virtballoon_probe(struct virtio_device *vdev) { struct virtio_balloon *vb; @@ -557,7 +569,7 @@ static int virtballoon_probe(struct virtio_device *vdev) return -EINVAL; } - vdev->priv = vb = kmalloc(sizeof(*vb), GFP_KERNEL); + vdev->priv = vb = kzalloc(sizeof(*vb), GFP_KERNEL); if (!vb) { err = -ENOMEM; goto out; @@ -566,8 +578,6 @@ static int virtballoon_probe(struct virtio_device *vdev) INIT_WORK(&vb->update_balloon_stats_work, update_balloon_stats_func); INIT_WORK(&vb->update_balloon_size_work, update_balloon_size_func); spin_lock_init(&vb->stop_update_lock); - vb->stop_update = false; - vb->num_pages = 0; mutex_init(&vb->balloon_lock); init_waitqueue_head(&vb->acked); vb->vdev = vdev; @@ -578,17 +588,10 @@ static int virtballoon_probe(struct virtio_device *vdev) if (err) goto out_free_vb; - vb->nb.notifier_call = virtballoon_oom_notify; - vb->nb.priority = VIRTBALLOON_OOM_NOTIFY_PRIORITY; - err = register_oom_notifier(&vb->nb); - if (err < 0) - goto out_del_vqs; - #ifdef CONFIG_BALLOON_COMPACTION balloon_mnt = kern_mount(&balloon_fs); if (IS_ERR(balloon_mnt)) { err = PTR_ERR(balloon_mnt); - unregister_oom_notifier(&vb->nb); goto out_del_vqs; } @@ -597,13 +600,19 @@ static int virtballoon_probe(struct virtio_device *vdev) if (IS_ERR(vb->vb_dev_info.inode)) { err = PTR_ERR(vb->vb_dev_info.inode); kern_unmount(balloon_mnt); - unregister_oom_notifier(&vb->nb); - vb->vb_dev_info.inode = NULL; goto out_del_vqs; } vb->vb_dev_info.inode->i_mapping->a_ops = &balloon_aops; #endif - + /* + * We continue to use VIRTIO_BALLOON_F_DEFLATE_ON_OOM to decide if a + * shrinker needs to be registered to relieve memory pressure. + */ + if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_DEFLATE_ON_OOM)) { + err = virtio_balloon_register_shrinker(vb); + if (err) + goto out_del_vqs; + } virtio_device_ready(vdev); if (towards_target(vb)) @@ -635,8 +644,8 @@ static void virtballoon_remove(struct virtio_device *vdev) { struct virtio_balloon *vb = vdev->priv; - unregister_oom_notifier(&vb->nb); - + if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_DEFLATE_ON_OOM)) + virtio_balloon_unregister_shrinker(vb); spin_lock_irq(&vb->stop_update_lock); vb->stop_update = true; spin_unlock_irq(&vb->stop_update_lock); diff --git a/drivers/virtio/virtio_mmio.c b/drivers/virtio/virtio_mmio.c index 67763d3c7abf..4cd9ea5c75be 100644 --- a/drivers/virtio/virtio_mmio.c +++ b/drivers/virtio/virtio_mmio.c @@ -397,9 +397,23 @@ static struct virtqueue *vm_setup_vq(struct virtio_device *vdev, unsigned index, /* Activate the queue */ writel(virtqueue_get_vring_size(vq), vm_dev->base + VIRTIO_MMIO_QUEUE_NUM); if (vm_dev->version == 1) { + u64 q_pfn = virtqueue_get_desc_addr(vq) >> PAGE_SHIFT; + + /* + * virtio-mmio v1 uses a 32bit QUEUE PFN. If we have something + * that doesn't fit in 32bit, fail the setup rather than + * pretending to be successful. + */ + if (q_pfn >> 32) { + dev_err(&vdev->dev, + "platform bug: legacy virtio-mmio must not be used with RAM above 0x%llxGB\n", + 0x1ULL << (32 + PAGE_SHIFT - 30)); + err = -E2BIG; + goto error_bad_pfn; + } + writel(PAGE_SIZE, vm_dev->base + VIRTIO_MMIO_QUEUE_ALIGN); - writel(virtqueue_get_desc_addr(vq) >> PAGE_SHIFT, - vm_dev->base + VIRTIO_MMIO_QUEUE_PFN); + writel(q_pfn, vm_dev->base + VIRTIO_MMIO_QUEUE_PFN); } else { u64 addr; @@ -430,6 +444,8 @@ static struct virtqueue *vm_setup_vq(struct virtio_device *vdev, unsigned index, return vq; +error_bad_pfn: + vring_del_virtqueue(vq); error_new_virtqueue: if (vm_dev->version == 1) { writel(0, vm_dev->base + VIRTIO_MMIO_QUEUE_PFN); diff --git a/drivers/virtio/virtio_pci_legacy.c b/drivers/virtio/virtio_pci_legacy.c index 2780886e8ba3..de062fb201bc 100644 --- a/drivers/virtio/virtio_pci_legacy.c +++ b/drivers/virtio/virtio_pci_legacy.c @@ -122,6 +122,7 @@ static struct virtqueue *setup_vq(struct virtio_pci_device *vp_dev, struct virtqueue *vq; u16 num; int err; + u64 q_pfn; /* Select the queue we're interested in */ iowrite16(index, vp_dev->ioaddr + VIRTIO_PCI_QUEUE_SEL); @@ -141,9 +142,17 @@ static struct virtqueue *setup_vq(struct virtio_pci_device *vp_dev, if (!vq) return ERR_PTR(-ENOMEM); + q_pfn = virtqueue_get_desc_addr(vq) >> VIRTIO_PCI_QUEUE_ADDR_SHIFT; + if (q_pfn >> 32) { + dev_err(&vp_dev->pci_dev->dev, + "platform bug: legacy virtio-mmio must not be used with RAM above 0x%llxGB\n", + 0x1ULL << (32 + PAGE_SHIFT - 30)); + err = -E2BIG; + goto out_del_vq; + } + /* activate the queue */ - iowrite32(virtqueue_get_desc_addr(vq) >> VIRTIO_PCI_QUEUE_ADDR_SHIFT, - vp_dev->ioaddr + VIRTIO_PCI_QUEUE_PFN); + iowrite32(q_pfn, vp_dev->ioaddr + VIRTIO_PCI_QUEUE_PFN); vq->priv = (void __force *)vp_dev->ioaddr + VIRTIO_PCI_QUEUE_NOTIFY; @@ -160,6 +169,7 @@ static struct virtqueue *setup_vq(struct virtio_pci_device *vp_dev, out_deactivate: iowrite32(0, vp_dev->ioaddr + VIRTIO_PCI_QUEUE_PFN); +out_del_vq: vring_del_virtqueue(vq); return ERR_PTR(err); } diff --git a/drivers/watchdog/kempld_wdt.c b/drivers/watchdog/kempld_wdt.c index 2f3b049ea301..e268add43010 100644 --- a/drivers/watchdog/kempld_wdt.c +++ b/drivers/watchdog/kempld_wdt.c @@ -146,12 +146,7 @@ static int kempld_wdt_set_stage_timeout(struct kempld_wdt_data *wdt_data, u32 remainder; u8 stage_cfg; -#if GCC_VERSION < 40400 - /* work around a bug compiling do_div() */ - prescaler = READ_ONCE(kempld_prescaler[PRESCALER_21]); -#else prescaler = kempld_prescaler[PRESCALER_21]; -#endif if (!stage) return -EINVAL; diff --git a/drivers/xen/mcelog.c b/drivers/xen/mcelog.c index 262835ace35d..b8bf61abb65b 100644 --- a/drivers/xen/mcelog.c +++ b/drivers/xen/mcelog.c @@ -288,7 +288,6 @@ static int mc_queue_handle(uint32_t flags) int ret = 0; mc_op.cmd = XEN_MC_fetch; - mc_op.interface_version = XEN_MCA_INTERFACE_VERSION; set_xen_guest_handle(mc_op.u.mc_fetch.data, &g_mi); do { mc_op.u.mc_fetch.flags = flags; @@ -358,7 +357,6 @@ static int bind_virq_for_mce(void) /* Fetch physical CPU Numbers */ mc_op.cmd = XEN_MC_physcpuinfo; - mc_op.interface_version = XEN_MCA_INTERFACE_VERSION; set_xen_guest_handle(mc_op.u.mc_physcpuinfo.info, g_physinfo); ret = HYPERVISOR_mca(&mc_op); if (ret) { diff --git a/drivers/xen/xen-acpi-processor.c b/drivers/xen/xen-acpi-processor.c index b29f4e40851f..fbb9137c7d02 100644 --- a/drivers/xen/xen-acpi-processor.c +++ b/drivers/xen/xen-acpi-processor.c @@ -362,6 +362,12 @@ read_acpi_id(acpi_handle handle, u32 lvl, void *context, void **rv) default: return AE_OK; } + if (invalid_phys_cpuid(acpi_get_phys_id(handle, + acpi_type == ACPI_TYPE_DEVICE, + acpi_id))) { + pr_debug("CPU with ACPI ID %u is unavailable\n", acpi_id); + return AE_OK; + } /* There are more ACPI Processor objects than in x2APIC or MADT. * This can happen with incorrect ACPI SSDT declerations. */ if (acpi_id >= nr_acpi_bits) { |