diff options
Diffstat (limited to 'drivers')
385 files changed, 8463 insertions, 4584 deletions
diff --git a/drivers/acpi/prmt.c b/drivers/acpi/prmt.c index 31cf9aee5edd..1f6007abcf18 100644 --- a/drivers/acpi/prmt.c +++ b/drivers/acpi/prmt.c @@ -292,6 +292,12 @@ void __init init_prmt(void) int mc = acpi_table_parse_entries(ACPI_SIG_PRMT, sizeof(struct acpi_table_prmt) + sizeof (struct acpi_table_prmt_header), 0, acpi_parse_prmt, 0); + /* + * Return immediately if PRMT table is not present or no PRM module found. + */ + if (mc <= 0) + return; + pr_info("PRM: found %u modules\n", mc); status = acpi_install_address_space_handler(ACPI_ROOT_OBJECT, diff --git a/drivers/acpi/x86/s2idle.c b/drivers/acpi/x86/s2idle.c index fbdbef0ab552..3a308461246a 100644 --- a/drivers/acpi/x86/s2idle.c +++ b/drivers/acpi/x86/s2idle.c @@ -452,7 +452,7 @@ int acpi_s2idle_prepare_late(void) if (lps0_dsm_func_mask_microsoft > 0) { acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_OFF, lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft); - acpi_sleep_run_lps0_dsm(ACPI_LPS0_MS_EXIT, + acpi_sleep_run_lps0_dsm(ACPI_LPS0_MS_ENTRY, lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft); acpi_sleep_run_lps0_dsm(ACPI_LPS0_ENTRY, lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft); @@ -479,7 +479,7 @@ void acpi_s2idle_restore_early(void) if (lps0_dsm_func_mask_microsoft > 0) { acpi_sleep_run_lps0_dsm(ACPI_LPS0_EXIT, lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft); - acpi_sleep_run_lps0_dsm(ACPI_LPS0_MS_ENTRY, + acpi_sleep_run_lps0_dsm(ACPI_LPS0_MS_EXIT, lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft); acpi_sleep_run_lps0_dsm(ACPI_LPS0_SCREEN_ON, lps0_dsm_func_mask_microsoft, lps0_dsm_guid_microsoft); diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index a934c679e6ce..f10688e83226 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -435,7 +435,7 @@ static void genpd_restore_performance_state(struct device *dev, int dev_pm_genpd_set_performance_state(struct device *dev, unsigned int state) { struct generic_pm_domain *genpd; - int ret; + int ret = 0; genpd = dev_to_genpd_safe(dev); if (!genpd) @@ -446,7 +446,13 @@ int dev_pm_genpd_set_performance_state(struct device *dev, unsigned int state) return -EINVAL; genpd_lock(genpd); - ret = genpd_set_performance_state(dev, state); + if (pm_runtime_suspended(dev)) { + dev_gpd_data(dev)->rpm_pstate = state; + } else { + ret = genpd_set_performance_state(dev, state); + if (!ret) + dev_gpd_data(dev)->rpm_pstate = 0; + } genpd_unlock(genpd); return ret; diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h index 0097696c31de..b1905916f7af 100644 --- a/drivers/base/regmap/internal.h +++ b/drivers/base/regmap/internal.h @@ -53,6 +53,10 @@ struct regmap { spinlock_t spinlock; unsigned long spinlock_flags; }; + struct { + raw_spinlock_t raw_spinlock; + unsigned long raw_spinlock_flags; + }; }; regmap_lock lock; regmap_unlock unlock; diff --git a/drivers/base/regmap/regmap-debugfs.c b/drivers/base/regmap/regmap-debugfs.c index 211a335a608d..ad684d37c2da 100644 --- a/drivers/base/regmap/regmap-debugfs.c +++ b/drivers/base/regmap/regmap-debugfs.c @@ -368,7 +368,7 @@ static ssize_t regmap_reg_ranges_read_file(struct file *file, char *buf; char *entry; int ret; - unsigned entry_len; + unsigned int entry_len; if (*ppos < 0 || !count) return -EINVAL; diff --git a/drivers/base/regmap/regmap-mmio.c b/drivers/base/regmap/regmap-mmio.c index f9cd51afb9d2..71f16be7e717 100644 --- a/drivers/base/regmap/regmap-mmio.c +++ b/drivers/base/regmap/regmap-mmio.c @@ -15,7 +15,7 @@ struct regmap_mmio_context { void __iomem *regs; - unsigned val_bytes; + unsigned int val_bytes; bool relaxed_mmio; bool attached_clk; diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index fe3e38dd5324..21a0c2562ec0 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -533,6 +533,23 @@ __releases(&map->spinlock) spin_unlock_irqrestore(&map->spinlock, map->spinlock_flags); } +static void regmap_lock_raw_spinlock(void *__map) +__acquires(&map->raw_spinlock) +{ + struct regmap *map = __map; + unsigned long flags; + + raw_spin_lock_irqsave(&map->raw_spinlock, flags); + map->raw_spinlock_flags = flags; +} + +static void regmap_unlock_raw_spinlock(void *__map) +__releases(&map->raw_spinlock) +{ + struct regmap *map = __map; + raw_spin_unlock_irqrestore(&map->raw_spinlock, map->raw_spinlock_flags); +} + static void dev_get_regmap_release(struct device *dev, void *res) { /* @@ -770,11 +787,19 @@ struct regmap *__regmap_init(struct device *dev, } else { if ((bus && bus->fast_io) || config->fast_io) { - spin_lock_init(&map->spinlock); - map->lock = regmap_lock_spinlock; - map->unlock = regmap_unlock_spinlock; - lockdep_set_class_and_name(&map->spinlock, - lock_key, lock_name); + if (config->use_raw_spinlock) { + raw_spin_lock_init(&map->raw_spinlock); + map->lock = regmap_lock_raw_spinlock; + map->unlock = regmap_unlock_raw_spinlock; + lockdep_set_class_and_name(&map->raw_spinlock, + lock_key, lock_name); + } else { + spin_lock_init(&map->spinlock); + map->lock = regmap_lock_spinlock; + map->unlock = regmap_unlock_spinlock; + lockdep_set_class_and_name(&map->spinlock, + lock_key, lock_name); + } } else { mutex_init(&map->mutex); map->lock = regmap_lock_mutex; @@ -1126,10 +1151,10 @@ skip_format_initialization: /* Make sure, that this register range has no selector or data window within its boundary */ for (j = 0; j < config->num_ranges; j++) { - unsigned sel_reg = config->ranges[j].selector_reg; - unsigned win_min = config->ranges[j].window_start; - unsigned win_max = win_min + - config->ranges[j].window_len - 1; + unsigned int sel_reg = config->ranges[j].selector_reg; + unsigned int win_min = config->ranges[j].window_start; + unsigned int win_max = win_min + + config->ranges[j].window_len - 1; /* Allow data window inside its own virtual range */ if (j == i) @@ -1298,7 +1323,7 @@ EXPORT_SYMBOL_GPL(devm_regmap_field_alloc); */ int regmap_field_bulk_alloc(struct regmap *regmap, struct regmap_field **rm_field, - struct reg_field *reg_field, + const struct reg_field *reg_field, int num_fields) { struct regmap_field *rf; @@ -1334,7 +1359,7 @@ EXPORT_SYMBOL_GPL(regmap_field_bulk_alloc); int devm_regmap_field_bulk_alloc(struct device *dev, struct regmap *regmap, struct regmap_field **rm_field, - struct reg_field *reg_field, + const struct reg_field *reg_field, int num_fields) { struct regmap_field *rf; @@ -1667,7 +1692,7 @@ static int _regmap_raw_write_impl(struct regmap *map, unsigned int reg, if (ret) { dev_err(map->dev, "Error in caching of register: %x ret: %d\n", - reg + i, ret); + reg + regmap_get_offset(map, i), ret); return ret; } } diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index 63056cfd4b62..fbb3a558139f 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -213,7 +213,7 @@ config BLK_DEV_LOOP_MIN_COUNT dynamically allocated with the /dev/loop-control interface. config BLK_DEV_CRYPTOLOOP - tristate "Cryptoloop Support" + tristate "Cryptoloop Support (DEPRECATED)" select CRYPTO select CRYPTO_CBC depends on BLK_DEV_LOOP @@ -225,7 +225,7 @@ config BLK_DEV_CRYPTOLOOP WARNING: This device is not safe for journaled file systems like ext3 or Reiserfs. Please use the Device Mapper crypto module instead, which can be configured to be on-disk compatible with the - cryptoloop device. + cryptoloop device. cryptoloop support will be removed in Linux 5.16. source "drivers/block/drbd/Kconfig" diff --git a/drivers/block/cryptoloop.c b/drivers/block/cryptoloop.c index 3cabc335ae74..f0a91faa43a8 100644 --- a/drivers/block/cryptoloop.c +++ b/drivers/block/cryptoloop.c @@ -189,6 +189,8 @@ init_cryptoloop(void) if (rc) printk(KERN_ERR "cryptoloop: loop_register_transfer failed\n"); + else + pr_warn("the cryptoloop driver has been deprecated and will be removed in in Linux 5.16\n"); return rc; } diff --git a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c index 9b3298926356..675327df6aff 100644 --- a/drivers/block/paride/pd.c +++ b/drivers/block/paride/pd.c @@ -892,7 +892,7 @@ static void pd_probe_drive(struct pd_unit *disk) return; p = blk_mq_alloc_disk(&disk->tag_set, disk); - if (!p) { + if (IS_ERR(p)) { blk_mq_free_tag_set(&disk->tag_set); return; } diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c index 4b49df2dfd23..afb37aac09e8 100644 --- a/drivers/block/virtio_blk.c +++ b/drivers/block/virtio_blk.c @@ -692,6 +692,28 @@ static const struct blk_mq_ops virtio_mq_ops = { static unsigned int virtblk_queue_depth; module_param_named(queue_depth, virtblk_queue_depth, uint, 0444); +static int virtblk_validate(struct virtio_device *vdev) +{ + u32 blk_size; + + if (!vdev->config->get) { + dev_err(&vdev->dev, "%s failure: config access disabled\n", + __func__); + return -EINVAL; + } + + if (!virtio_has_feature(vdev, VIRTIO_BLK_F_BLK_SIZE)) + return 0; + + blk_size = virtio_cread32(vdev, + offsetof(struct virtio_blk_config, blk_size)); + + if (blk_size < SECTOR_SIZE || blk_size > PAGE_SIZE) + __virtio_clear_bit(vdev, VIRTIO_BLK_F_BLK_SIZE); + + return 0; +} + static int virtblk_probe(struct virtio_device *vdev) { struct virtio_blk *vblk; @@ -703,12 +725,6 @@ static int virtblk_probe(struct virtio_device *vdev) u8 physical_block_exp, alignment_offset; unsigned int queue_depth; - if (!vdev->config->get) { - dev_err(&vdev->dev, "%s failure: config access disabled\n", - __func__); - return -EINVAL; - } - err = ida_simple_get(&vd_index_ida, 0, minor_to_index(1 << MINORBITS), GFP_KERNEL); if (err < 0) @@ -823,6 +839,14 @@ static int virtblk_probe(struct virtio_device *vdev) else blk_size = queue_logical_block_size(q); + if (unlikely(blk_size < SECTOR_SIZE || blk_size > PAGE_SIZE)) { + dev_err(&vdev->dev, + "block size is changed unexpectedly, now is %u\n", + blk_size); + err = -EINVAL; + goto err_cleanup_disk; + } + /* Use topology information if available */ err = virtio_cread_feature(vdev, VIRTIO_BLK_F_TOPOLOGY, struct virtio_blk_config, physical_block_exp, @@ -881,6 +905,8 @@ static int virtblk_probe(struct virtio_device *vdev) device_add_disk(&vdev->dev, vblk->disk, virtblk_attr_groups); return 0; +err_cleanup_disk: + blk_cleanup_disk(vblk->disk); out_free_tags: blk_mq_free_tag_set(&vblk->tag_set); out_free_vq: @@ -983,6 +1009,7 @@ static struct virtio_driver virtio_blk = { .driver.name = KBUILD_MODNAME, .driver.owner = THIS_MODULE, .id_table = id_table, + .validate = virtblk_validate, .probe = virtblk_probe, .remove = virtblk_remove, .config_changed = virtblk_config_changed, diff --git a/drivers/bus/mhi/core/internal.h b/drivers/bus/mhi/core/internal.h index bc239a11aa69..5b9ea66b92dc 100644 --- a/drivers/bus/mhi/core/internal.h +++ b/drivers/bus/mhi/core/internal.h @@ -682,7 +682,7 @@ void mhi_rddm_prepare(struct mhi_controller *mhi_cntrl, struct image_info *img_info); void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl); int mhi_prepare_channel(struct mhi_controller *mhi_cntrl, - struct mhi_chan *mhi_chan, unsigned int flags); + struct mhi_chan *mhi_chan); int mhi_init_chan_ctxt(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan); void mhi_deinit_chan_ctxt(struct mhi_controller *mhi_cntrl, diff --git a/drivers/bus/mhi/core/main.c b/drivers/bus/mhi/core/main.c index 84448233f64c..fc9196f11cb7 100644 --- a/drivers/bus/mhi/core/main.c +++ b/drivers/bus/mhi/core/main.c @@ -1430,7 +1430,7 @@ exit_unprepare_channel: } int mhi_prepare_channel(struct mhi_controller *mhi_cntrl, - struct mhi_chan *mhi_chan, unsigned int flags) + struct mhi_chan *mhi_chan) { int ret = 0; struct device *dev = &mhi_chan->mhi_dev->dev; @@ -1455,9 +1455,6 @@ int mhi_prepare_channel(struct mhi_controller *mhi_cntrl, if (ret) goto error_pm_state; - if (mhi_chan->dir == DMA_FROM_DEVICE) - mhi_chan->pre_alloc = !!(flags & MHI_CH_INBOUND_ALLOC_BUFS); - /* Pre-allocate buffer for xfer ring */ if (mhi_chan->pre_alloc) { int nr_el = get_nr_avail_ring_elements(mhi_cntrl, @@ -1613,7 +1610,7 @@ void mhi_reset_chan(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan) } /* Move channel to start state */ -int mhi_prepare_for_transfer(struct mhi_device *mhi_dev, unsigned int flags) +int mhi_prepare_for_transfer(struct mhi_device *mhi_dev) { int ret, dir; struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl; @@ -1624,7 +1621,7 @@ int mhi_prepare_for_transfer(struct mhi_device *mhi_dev, unsigned int flags) if (!mhi_chan) continue; - ret = mhi_prepare_channel(mhi_cntrl, mhi_chan, flags); + ret = mhi_prepare_channel(mhi_cntrl, mhi_chan); if (ret) goto error_open_chan; } diff --git a/drivers/bus/ti-sysc.c b/drivers/bus/ti-sysc.c index 0ef98e3ba341..148a4dd8cb9a 100644 --- a/drivers/bus/ti-sysc.c +++ b/drivers/bus/ti-sysc.c @@ -3097,8 +3097,10 @@ static int sysc_probe(struct platform_device *pdev) return error; error = sysc_check_active_timer(ddata); - if (error == -EBUSY) + if (error == -ENXIO) ddata->reserved = true; + else if (error) + return error; error = sysc_get_clocks(ddata); if (error) diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig index 3f166c8a4099..239eca4d6805 100644 --- a/drivers/char/hw_random/Kconfig +++ b/drivers/char/hw_random/Kconfig @@ -524,6 +524,20 @@ config HW_RANDOM_XIPHERA To compile this driver as a module, choose M here: the module will be called xiphera-trng. +config HW_RANDOM_ARM_SMCCC_TRNG + tristate "Arm SMCCC TRNG firmware interface support" + depends on HAVE_ARM_SMCCC_DISCOVERY + default HW_RANDOM + help + Say 'Y' to enable the True Random Number Generator driver using + the Arm SMCCC TRNG firmware interface. This reads entropy from + higher exception levels (firmware, hypervisor). Uses SMCCC for + communicating with the firmware: + https://developer.arm.com/documentation/den0098/latest/ + + To compile this driver as a module, choose M here: the + module will be called arm_smccc_trng. + endif # HW_RANDOM config UML_RANDOM diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile index 8933fada74f2..a5a1c765a394 100644 --- a/drivers/char/hw_random/Makefile +++ b/drivers/char/hw_random/Makefile @@ -45,3 +45,4 @@ obj-$(CONFIG_HW_RANDOM_OPTEE) += optee-rng.o obj-$(CONFIG_HW_RANDOM_NPCM) += npcm-rng.o obj-$(CONFIG_HW_RANDOM_CCTRNG) += cctrng.o obj-$(CONFIG_HW_RANDOM_XIPHERA) += xiphera-trng.o +obj-$(CONFIG_HW_RANDOM_ARM_SMCCC_TRNG) += arm_smccc_trng.o diff --git a/drivers/char/hw_random/amd-rng.c b/drivers/char/hw_random/amd-rng.c index d8d4ef5214a1..c22d4184bb61 100644 --- a/drivers/char/hw_random/amd-rng.c +++ b/drivers/char/hw_random/amd-rng.c @@ -124,7 +124,7 @@ static struct hwrng amd_rng = { .read = amd_rng_read, }; -static int __init mod_init(void) +static int __init amd_rng_mod_init(void) { int err; struct pci_dev *pdev = NULL; @@ -188,7 +188,7 @@ out: return err; } -static void __exit mod_exit(void) +static void __exit amd_rng_mod_exit(void) { struct amd768_priv *priv; @@ -203,8 +203,8 @@ static void __exit mod_exit(void) kfree(priv); } -module_init(mod_init); -module_exit(mod_exit); +module_init(amd_rng_mod_init); +module_exit(amd_rng_mod_exit); MODULE_AUTHOR("The Linux Kernel team"); MODULE_DESCRIPTION("H/W RNG driver for AMD chipsets"); diff --git a/drivers/char/hw_random/arm_smccc_trng.c b/drivers/char/hw_random/arm_smccc_trng.c new file mode 100644 index 000000000000..b24ac39a903b --- /dev/null +++ b/drivers/char/hw_random/arm_smccc_trng.c @@ -0,0 +1,123 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Randomness driver for the ARM SMCCC TRNG Firmware Interface + * https://developer.arm.com/documentation/den0098/latest/ + * + * Copyright (C) 2020 Arm Ltd. + * + * The ARM TRNG firmware interface specifies a protocol to read entropy + * from a higher exception level, to abstract from any machine specific + * implemenations and allow easier use in hypervisors. + * + * The firmware interface is realised using the SMCCC specification. + */ + +#include <linux/bits.h> +#include <linux/device.h> +#include <linux/hw_random.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/arm-smccc.h> + +#ifdef CONFIG_ARM64 +#define ARM_SMCCC_TRNG_RND ARM_SMCCC_TRNG_RND64 +#define MAX_BITS_PER_CALL (3 * 64UL) +#else +#define ARM_SMCCC_TRNG_RND ARM_SMCCC_TRNG_RND32 +#define MAX_BITS_PER_CALL (3 * 32UL) +#endif + +/* We don't want to allow the firmware to stall us forever. */ +#define SMCCC_TRNG_MAX_TRIES 20 + +#define SMCCC_RET_TRNG_INVALID_PARAMETER -2 +#define SMCCC_RET_TRNG_NO_ENTROPY -3 + +static int copy_from_registers(char *buf, struct arm_smccc_res *res, + size_t bytes) +{ + unsigned int chunk, copied; + + if (bytes == 0) + return 0; + + chunk = min(bytes, sizeof(long)); + memcpy(buf, &res->a3, chunk); + copied = chunk; + if (copied >= bytes) + return copied; + + chunk = min((bytes - copied), sizeof(long)); + memcpy(&buf[copied], &res->a2, chunk); + copied += chunk; + if (copied >= bytes) + return copied; + + chunk = min((bytes - copied), sizeof(long)); + memcpy(&buf[copied], &res->a1, chunk); + + return copied + chunk; +} + +static int smccc_trng_read(struct hwrng *rng, void *data, size_t max, bool wait) +{ + struct arm_smccc_res res; + u8 *buf = data; + unsigned int copied = 0; + int tries = 0; + + while (copied < max) { + size_t bits = min_t(size_t, (max - copied) * BITS_PER_BYTE, + MAX_BITS_PER_CALL); + + arm_smccc_1_1_invoke(ARM_SMCCC_TRNG_RND, bits, &res); + if ((int)res.a0 < 0) + return (int)res.a0; + + switch ((int)res.a0) { + case SMCCC_RET_SUCCESS: + copied += copy_from_registers(buf + copied, &res, + bits / BITS_PER_BYTE); + tries = 0; + break; + case SMCCC_RET_TRNG_NO_ENTROPY: + if (!wait) + return copied; + tries++; + if (tries >= SMCCC_TRNG_MAX_TRIES) + return copied; + cond_resched(); + break; + } + } + + return copied; +} + +static int smccc_trng_probe(struct platform_device *pdev) +{ + struct hwrng *trng; + + trng = devm_kzalloc(&pdev->dev, sizeof(*trng), GFP_KERNEL); + if (!trng) + return -ENOMEM; + + trng->name = "smccc_trng"; + trng->read = smccc_trng_read; + + platform_set_drvdata(pdev, trng); + + return devm_hwrng_register(&pdev->dev, trng); +} + +static struct platform_driver smccc_trng_driver = { + .driver = { + .name = "smccc_trng", + }, + .probe = smccc_trng_probe, +}; +module_platform_driver(smccc_trng_driver); + +MODULE_ALIAS("platform:smccc_trng"); +MODULE_AUTHOR("Andre Przywara"); +MODULE_LICENSE("GPL"); diff --git a/drivers/char/hw_random/geode-rng.c b/drivers/char/hw_random/geode-rng.c index e1d421a36a13..138ce434f86b 100644 --- a/drivers/char/hw_random/geode-rng.c +++ b/drivers/char/hw_random/geode-rng.c @@ -83,7 +83,7 @@ static struct hwrng geode_rng = { }; -static int __init mod_init(void) +static int __init geode_rng_init(void) { int err = -ENODEV; struct pci_dev *pdev = NULL; @@ -124,7 +124,7 @@ err_unmap: goto out; } -static void __exit mod_exit(void) +static void __exit geode_rng_exit(void) { void __iomem *mem = (void __iomem *)geode_rng.priv; @@ -132,8 +132,8 @@ static void __exit mod_exit(void) iounmap(mem); } -module_init(mod_init); -module_exit(mod_exit); +module_init(geode_rng_init); +module_exit(geode_rng_exit); MODULE_DESCRIPTION("H/W RNG driver for AMD Geode LX CPUs"); MODULE_LICENSE("GPL"); diff --git a/drivers/char/hw_random/intel-rng.c b/drivers/char/hw_random/intel-rng.c index d740b8814bf3..7b171cb3b825 100644 --- a/drivers/char/hw_random/intel-rng.c +++ b/drivers/char/hw_random/intel-rng.c @@ -325,7 +325,7 @@ PFX "RNG, try using the 'no_fwh_detect' option.\n"; } -static int __init mod_init(void) +static int __init intel_rng_mod_init(void) { int err = -ENODEV; int i; @@ -403,7 +403,7 @@ out: } -static void __exit mod_exit(void) +static void __exit intel_rng_mod_exit(void) { void __iomem *mem = (void __iomem *)intel_rng.priv; @@ -411,8 +411,8 @@ static void __exit mod_exit(void) iounmap(mem); } -module_init(mod_init); -module_exit(mod_exit); +module_init(intel_rng_mod_init); +module_exit(intel_rng_mod_exit); MODULE_DESCRIPTION("H/W RNG driver for Intel chipsets"); MODULE_LICENSE("GPL"); diff --git a/drivers/char/hw_random/via-rng.c b/drivers/char/hw_random/via-rng.c index 39943bc3651a..7444cc146e86 100644 --- a/drivers/char/hw_random/via-rng.c +++ b/drivers/char/hw_random/via-rng.c @@ -192,7 +192,7 @@ static struct hwrng via_rng = { }; -static int __init mod_init(void) +static int __init via_rng_mod_init(void) { int err; @@ -209,13 +209,13 @@ static int __init mod_init(void) out: return err; } -module_init(mod_init); +module_init(via_rng_mod_init); -static void __exit mod_exit(void) +static void __exit via_rng_mod_exit(void) { hwrng_unregister(&via_rng); } -module_exit(mod_exit); +module_exit(via_rng_mod_exit); static struct x86_cpu_id __maybe_unused via_rng_cpu_id[] = { X86_MATCH_FEATURE(X86_FEATURE_XSTORE, NULL), diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig index 4308f9ca7a43..d6ba644f6b00 100644 --- a/drivers/char/tpm/Kconfig +++ b/drivers/char/tpm/Kconfig @@ -89,7 +89,6 @@ config TCG_TIS_SYNQUACER config TCG_TIS_I2C_CR50 tristate "TPM Interface Specification 2.0 Interface (I2C - CR50)" depends on I2C - select TCG_CR50 help This is a driver for the Google cr50 I2C TPM interface which is a custom microcontroller and requires a custom i2c protocol interface diff --git a/drivers/char/tpm/tpm_ibmvtpm.c b/drivers/char/tpm/tpm_ibmvtpm.c index 903604769de9..3af4c07a9342 100644 --- a/drivers/char/tpm/tpm_ibmvtpm.c +++ b/drivers/char/tpm/tpm_ibmvtpm.c @@ -106,17 +106,12 @@ static int tpm_ibmvtpm_recv(struct tpm_chip *chip, u8 *buf, size_t count) { struct ibmvtpm_dev *ibmvtpm = dev_get_drvdata(&chip->dev); u16 len; - int sig; if (!ibmvtpm->rtce_buf) { dev_err(ibmvtpm->dev, "ibmvtpm device is not ready\n"); return 0; } - sig = wait_event_interruptible(ibmvtpm->wq, !ibmvtpm->tpm_processing_cmd); - if (sig) - return -EINTR; - len = ibmvtpm->res_len; if (count < len) { @@ -237,7 +232,7 @@ static int tpm_ibmvtpm_send(struct tpm_chip *chip, u8 *buf, size_t count) * set the processing flag before the Hcall, since we may get the * result (interrupt) before even being able to check rc. */ - ibmvtpm->tpm_processing_cmd = true; + ibmvtpm->tpm_processing_cmd = 1; again: rc = ibmvtpm_send_crq(ibmvtpm->vdev, @@ -255,7 +250,7 @@ again: goto again; } dev_err(ibmvtpm->dev, "tpm_ibmvtpm_send failed rc=%d\n", rc); - ibmvtpm->tpm_processing_cmd = false; + ibmvtpm->tpm_processing_cmd = 0; } spin_unlock(&ibmvtpm->rtce_lock); @@ -269,7 +264,9 @@ static void tpm_ibmvtpm_cancel(struct tpm_chip *chip) static u8 tpm_ibmvtpm_status(struct tpm_chip *chip) { - return 0; + struct ibmvtpm_dev *ibmvtpm = dev_get_drvdata(&chip->dev); + + return ibmvtpm->tpm_processing_cmd; } /** @@ -457,7 +454,7 @@ static const struct tpm_class_ops tpm_ibmvtpm = { .send = tpm_ibmvtpm_send, .cancel = tpm_ibmvtpm_cancel, .status = tpm_ibmvtpm_status, - .req_complete_mask = 0, + .req_complete_mask = 1, .req_complete_val = 0, .req_canceled = tpm_ibmvtpm_req_canceled, }; @@ -550,7 +547,7 @@ static void ibmvtpm_crq_process(struct ibmvtpm_crq *crq, case VTPM_TPM_COMMAND_RES: /* len of the data in rtce buffer */ ibmvtpm->res_len = be16_to_cpu(crq->len); - ibmvtpm->tpm_processing_cmd = false; + ibmvtpm->tpm_processing_cmd = 0; wake_up_interruptible(&ibmvtpm->wq); return; default: @@ -688,8 +685,15 @@ static int tpm_ibmvtpm_probe(struct vio_dev *vio_dev, goto init_irq_cleanup; } - if (!strcmp(id->compat, "IBM,vtpm20")) { + + if (!strcmp(id->compat, "IBM,vtpm20")) chip->flags |= TPM_CHIP_FLAG_TPM2; + + rc = tpm_get_timeouts(chip); + if (rc) + goto init_irq_cleanup; + + if (chip->flags & TPM_CHIP_FLAG_TPM2) { rc = tpm2_get_cc_attrs_tbl(chip); if (rc) goto init_irq_cleanup; diff --git a/drivers/char/tpm/tpm_ibmvtpm.h b/drivers/char/tpm/tpm_ibmvtpm.h index b92aa7d3e93e..51198b137461 100644 --- a/drivers/char/tpm/tpm_ibmvtpm.h +++ b/drivers/char/tpm/tpm_ibmvtpm.h @@ -41,7 +41,7 @@ struct ibmvtpm_dev { wait_queue_head_t wq; u16 res_len; u32 vtpm_version; - bool tpm_processing_cmd; + u8 tpm_processing_cmd; }; #define CRQ_RES_BUF_SIZE PAGE_SIZE diff --git a/drivers/char/tpm/tpm_tis_i2c_cr50.c b/drivers/char/tpm/tpm_tis_i2c_cr50.c index 44dde2fbe2fb..c89278103703 100644 --- a/drivers/char/tpm/tpm_tis_i2c_cr50.c +++ b/drivers/char/tpm/tpm_tis_i2c_cr50.c @@ -639,12 +639,6 @@ static const struct tpm_class_ops cr50_i2c = { .req_canceled = &tpm_cr50_i2c_req_canceled, }; -static const struct i2c_device_id cr50_i2c_table[] = { - {"cr50_i2c", 0}, - {} -}; -MODULE_DEVICE_TABLE(i2c, cr50_i2c_table); - #ifdef CONFIG_ACPI static const struct acpi_device_id cr50_i2c_acpi_id[] = { { "GOOG0005", 0 }, @@ -670,8 +664,7 @@ MODULE_DEVICE_TABLE(of, of_cr50_i2c_match); * - 0: Success. * - -errno: A POSIX error code. */ -static int tpm_cr50_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int tpm_cr50_i2c_probe(struct i2c_client *client) { struct tpm_i2c_cr50_priv_data *priv; struct device *dev = &client->dev; @@ -774,8 +767,7 @@ static int tpm_cr50_i2c_remove(struct i2c_client *client) static SIMPLE_DEV_PM_OPS(cr50_i2c_pm, tpm_pm_suspend, tpm_pm_resume); static struct i2c_driver cr50_i2c_driver = { - .id_table = cr50_i2c_table, - .probe = tpm_cr50_i2c_probe, + .probe_new = tpm_cr50_i2c_probe, .remove = tpm_cr50_i2c_remove, .driver = { .name = "cr50_i2c", diff --git a/drivers/clk/imx/clk-imx6q.c b/drivers/clk/imx/clk-imx6q.c index 496900de0b0b..de36f58d551c 100644 --- a/drivers/clk/imx/clk-imx6q.c +++ b/drivers/clk/imx/clk-imx6q.c @@ -974,6 +974,6 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node) hws[IMX6QDL_CLK_PLL3_USB_OTG]->clk); } - imx_register_uart_clocks(1); + imx_register_uart_clocks(2); } CLK_OF_DECLARE(imx6q, "fsl,imx6q-ccm", imx6q_clocks_init); diff --git a/drivers/clk/qcom/gdsc.c b/drivers/clk/qcom/gdsc.c index 51ed640e527b..4ece326ea233 100644 --- a/drivers/clk/qcom/gdsc.c +++ b/drivers/clk/qcom/gdsc.c @@ -357,27 +357,43 @@ static int gdsc_init(struct gdsc *sc) if (on < 0) return on; - /* - * Votable GDSCs can be ON due to Vote from other masters. - * If a Votable GDSC is ON, make sure we have a Vote. - */ - if ((sc->flags & VOTABLE) && on) - gdsc_enable(&sc->pd); + if (on) { + /* The regulator must be on, sync the kernel state */ + if (sc->rsupply) { + ret = regulator_enable(sc->rsupply); + if (ret < 0) + return ret; + } - /* - * Make sure the retain bit is set if the GDSC is already on, otherwise - * we end up turning off the GDSC and destroying all the register - * contents that we thought we were saving. - */ - if ((sc->flags & RETAIN_FF_ENABLE) && on) - gdsc_retain_ff_on(sc); + /* + * Votable GDSCs can be ON due to Vote from other masters. + * If a Votable GDSC is ON, make sure we have a Vote. + */ + if (sc->flags & VOTABLE) { + ret = regmap_update_bits(sc->regmap, sc->gdscr, + SW_COLLAPSE_MASK, val); + if (ret) + return ret; + } + + /* Turn on HW trigger mode if supported */ + if (sc->flags & HW_CTRL) { + ret = gdsc_hwctrl(sc, true); + if (ret < 0) + return ret; + } - /* If ALWAYS_ON GDSCs are not ON, turn them ON */ - if (sc->flags & ALWAYS_ON) { - if (!on) - gdsc_enable(&sc->pd); + /* + * Make sure the retain bit is set if the GDSC is already on, + * otherwise we end up turning off the GDSC and destroying all + * the register contents that we thought we were saving. + */ + if (sc->flags & RETAIN_FF_ENABLE) + gdsc_retain_ff_on(sc); + } else if (sc->flags & ALWAYS_ON) { + /* If ALWAYS_ON GDSCs are not ON, turn them ON */ + gdsc_enable(&sc->pd); on = true; - sc->pd.flags |= GENPD_FLAG_ALWAYS_ON; } if (on || (sc->pwrsts & PWRSTS_RET)) @@ -385,6 +401,8 @@ static int gdsc_init(struct gdsc *sc) else gdsc_clear_mem_on(sc); + if (sc->flags & ALWAYS_ON) + sc->pd.flags |= GENPD_FLAG_ALWAYS_ON; if (!sc->pd.power_off) sc->pd.power_off = gdsc_disable; if (!sc->pd.power_on) diff --git a/drivers/clk/renesas/rcar-usb2-clock-sel.c b/drivers/clk/renesas/rcar-usb2-clock-sel.c index 9fb79bd79435..684d8937965e 100644 --- a/drivers/clk/renesas/rcar-usb2-clock-sel.c +++ b/drivers/clk/renesas/rcar-usb2-clock-sel.c @@ -187,7 +187,7 @@ static int rcar_usb2_clock_sel_probe(struct platform_device *pdev) init.ops = &usb2_clock_sel_clock_ops; priv->hw.init = &init; - ret = devm_clk_hw_register(NULL, &priv->hw); + ret = devm_clk_hw_register(dev, &priv->hw); if (ret) goto pm_put; diff --git a/drivers/cpufreq/armada-37xx-cpufreq.c b/drivers/cpufreq/armada-37xx-cpufreq.c index 3fc98a3ffd91..c10fc33b29b1 100644 --- a/drivers/cpufreq/armada-37xx-cpufreq.c +++ b/drivers/cpufreq/armada-37xx-cpufreq.c @@ -104,7 +104,11 @@ struct armada_37xx_dvfs { }; static struct armada_37xx_dvfs armada_37xx_dvfs[] = { - {.cpu_freq_max = 1200*1000*1000, .divider = {1, 2, 4, 6} }, + /* + * The cpufreq scaling for 1.2 GHz variant of the SOC is currently + * unstable because we do not know how to configure it properly. + */ + /* {.cpu_freq_max = 1200*1000*1000, .divider = {1, 2, 4, 6} }, */ {.cpu_freq_max = 1000*1000*1000, .divider = {1, 2, 4, 5} }, {.cpu_freq_max = 800*1000*1000, .divider = {1, 2, 3, 4} }, {.cpu_freq_max = 600*1000*1000, .divider = {2, 4, 5, 6} }, diff --git a/drivers/cpufreq/cpufreq-dt-platdev.c b/drivers/cpufreq/cpufreq-dt-platdev.c index bef7528aecd3..231e585f6ba2 100644 --- a/drivers/cpufreq/cpufreq-dt-platdev.c +++ b/drivers/cpufreq/cpufreq-dt-platdev.c @@ -139,7 +139,9 @@ static const struct of_device_id blocklist[] __initconst = { { .compatible = "qcom,qcs404", }, { .compatible = "qcom,sc7180", }, { .compatible = "qcom,sc7280", }, + { .compatible = "qcom,sc8180x", }, { .compatible = "qcom,sdm845", }, + { .compatible = "qcom,sm8150", }, { .compatible = "st,stih407", }, { .compatible = "st,stih410", }, diff --git a/drivers/cpufreq/scmi-cpufreq.c b/drivers/cpufreq/scmi-cpufreq.c index ec9a87ca2dbb..75f818d04b48 100644 --- a/drivers/cpufreq/scmi-cpufreq.c +++ b/drivers/cpufreq/scmi-cpufreq.c @@ -134,7 +134,7 @@ static int scmi_cpufreq_init(struct cpufreq_policy *policy) } if (!zalloc_cpumask_var(&opp_shared_cpus, GFP_KERNEL)) - ret = -ENOMEM; + return -ENOMEM; /* Obtain CPUs that share SCMI performance controls */ ret = scmi_get_sharing_cpus(cpu_dev, policy->cpus); diff --git a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-prng.c b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-prng.c index cd1baee424a1..b3a9bbfb8831 100644 --- a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-prng.c +++ b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-prng.c @@ -26,8 +26,7 @@ void sun8i_ce_prng_exit(struct crypto_tfm *tfm) { struct sun8i_ce_rng_tfm_ctx *ctx = crypto_tfm_ctx(tfm); - memzero_explicit(ctx->seed, ctx->slen); - kfree(ctx->seed); + kfree_sensitive(ctx->seed); ctx->seed = NULL; ctx->slen = 0; } @@ -38,8 +37,7 @@ int sun8i_ce_prng_seed(struct crypto_rng *tfm, const u8 *seed, struct sun8i_ce_rng_tfm_ctx *ctx = crypto_rng_ctx(tfm); if (ctx->seed && ctx->slen != slen) { - memzero_explicit(ctx->seed, ctx->slen); - kfree(ctx->seed); + kfree_sensitive(ctx->seed); ctx->slen = 0; ctx->seed = NULL; } @@ -157,9 +155,8 @@ err_dst: memcpy(dst, d, dlen); memcpy(ctx->seed, d + dlen, ctx->slen); } - memzero_explicit(d, todo); err_iv: - kfree(d); + kfree_sensitive(d); err_mem: return err; } diff --git a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-trng.c b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-trng.c index 5b7af4498bd5..19cd2e52f89d 100644 --- a/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-trng.c +++ b/drivers/crypto/allwinner/sun8i-ce/sun8i-ce-trng.c @@ -95,9 +95,8 @@ err_pm: memcpy(data, d, max); err = max; } - memzero_explicit(d, todo); err_dst: - kfree(d); + kfree_sensitive(d); return err; } diff --git a/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-prng.c b/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-prng.c index 3191527928e4..246a6782674c 100644 --- a/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-prng.c +++ b/drivers/crypto/allwinner/sun8i-ss/sun8i-ss-prng.c @@ -20,8 +20,7 @@ int sun8i_ss_prng_seed(struct crypto_rng *tfm, const u8 *seed, struct sun8i_ss_rng_tfm_ctx *ctx = crypto_rng_ctx(tfm); if (ctx->seed && ctx->slen != slen) { - memzero_explicit(ctx->seed, ctx->slen); - kfree(ctx->seed); + kfree_sensitive(ctx->seed); ctx->slen = 0; ctx->seed = NULL; } @@ -48,8 +47,7 @@ void sun8i_ss_prng_exit(struct crypto_tfm *tfm) { struct sun8i_ss_rng_tfm_ctx *ctx = crypto_tfm_ctx(tfm); - memzero_explicit(ctx->seed, ctx->slen); - kfree(ctx->seed); + kfree_sensitive(ctx->seed); ctx->seed = NULL; ctx->slen = 0; } @@ -167,9 +165,8 @@ err_iv: /* Update seed */ memcpy(ctx->seed, d + dlen, ctx->slen); } - memzero_explicit(d, todo); err_free: - kfree(d); + kfree_sensitive(d); return err; } diff --git a/drivers/crypto/atmel-aes.c b/drivers/crypto/atmel-aes.c index b1d286004295..9391ccc03382 100644 --- a/drivers/crypto/atmel-aes.c +++ b/drivers/crypto/atmel-aes.c @@ -143,6 +143,7 @@ struct atmel_aes_xts_ctx { struct atmel_aes_base_ctx base; u32 key2[AES_KEYSIZE_256 / sizeof(u32)]; + struct crypto_skcipher *fallback_tfm; }; #if IS_ENABLED(CONFIG_CRYPTO_DEV_ATMEL_AUTHENC) @@ -155,6 +156,7 @@ struct atmel_aes_authenc_ctx { struct atmel_aes_reqctx { unsigned long mode; u8 lastc[AES_BLOCK_SIZE]; + struct skcipher_request fallback_req; }; #if IS_ENABLED(CONFIG_CRYPTO_DEV_ATMEL_AUTHENC) @@ -418,24 +420,15 @@ static inline size_t atmel_aes_padlen(size_t len, size_t block_size) return len ? block_size - len : 0; } -static struct atmel_aes_dev *atmel_aes_find_dev(struct atmel_aes_base_ctx *ctx) +static struct atmel_aes_dev *atmel_aes_dev_alloc(struct atmel_aes_base_ctx *ctx) { - struct atmel_aes_dev *aes_dd = NULL; - struct atmel_aes_dev *tmp; + struct atmel_aes_dev *aes_dd; spin_lock_bh(&atmel_aes.lock); - if (!ctx->dd) { - list_for_each_entry(tmp, &atmel_aes.dev_list, list) { - aes_dd = tmp; - break; - } - ctx->dd = aes_dd; - } else { - aes_dd = ctx->dd; - } - + /* One AES IP per SoC. */ + aes_dd = list_first_entry_or_null(&atmel_aes.dev_list, + struct atmel_aes_dev, list); spin_unlock_bh(&atmel_aes.lock); - return aes_dd; } @@ -967,7 +960,6 @@ static int atmel_aes_handle_queue(struct atmel_aes_dev *dd, ctx = crypto_tfm_ctx(areq->tfm); dd->areq = areq; - dd->ctx = ctx; start_async = (areq != new_areq); dd->is_async = start_async; @@ -1083,12 +1075,48 @@ static int atmel_aes_ctr_start(struct atmel_aes_dev *dd) return atmel_aes_ctr_transfer(dd); } +static int atmel_aes_xts_fallback(struct skcipher_request *req, bool enc) +{ + struct atmel_aes_reqctx *rctx = skcipher_request_ctx(req); + struct atmel_aes_xts_ctx *ctx = crypto_skcipher_ctx( + crypto_skcipher_reqtfm(req)); + + skcipher_request_set_tfm(&rctx->fallback_req, ctx->fallback_tfm); + skcipher_request_set_callback(&rctx->fallback_req, req->base.flags, + req->base.complete, req->base.data); + skcipher_request_set_crypt(&rctx->fallback_req, req->src, req->dst, + req->cryptlen, req->iv); + + return enc ? crypto_skcipher_encrypt(&rctx->fallback_req) : + crypto_skcipher_decrypt(&rctx->fallback_req); +} + static int atmel_aes_crypt(struct skcipher_request *req, unsigned long mode) { struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req); struct atmel_aes_base_ctx *ctx = crypto_skcipher_ctx(skcipher); struct atmel_aes_reqctx *rctx; - struct atmel_aes_dev *dd; + u32 opmode = mode & AES_FLAGS_OPMODE_MASK; + + if (opmode == AES_FLAGS_XTS) { + if (req->cryptlen < XTS_BLOCK_SIZE) + return -EINVAL; + + if (!IS_ALIGNED(req->cryptlen, XTS_BLOCK_SIZE)) + return atmel_aes_xts_fallback(req, + mode & AES_FLAGS_ENCRYPT); + } + + /* + * ECB, CBC, CFB, OFB or CTR mode require the plaintext and ciphertext + * to have a positve integer length. + */ + if (!req->cryptlen && opmode != AES_FLAGS_XTS) + return 0; + + if ((opmode == AES_FLAGS_ECB || opmode == AES_FLAGS_CBC) && + !IS_ALIGNED(req->cryptlen, crypto_skcipher_blocksize(skcipher))) + return -EINVAL; switch (mode & AES_FLAGS_OPMODE_MASK) { case AES_FLAGS_CFB8: @@ -1113,14 +1141,10 @@ static int atmel_aes_crypt(struct skcipher_request *req, unsigned long mode) } ctx->is_aead = false; - dd = atmel_aes_find_dev(ctx); - if (!dd) - return -ENODEV; - rctx = skcipher_request_ctx(req); rctx->mode = mode; - if ((mode & AES_FLAGS_OPMODE_MASK) != AES_FLAGS_ECB && + if (opmode != AES_FLAGS_ECB && !(mode & AES_FLAGS_ENCRYPT) && req->src == req->dst) { unsigned int ivsize = crypto_skcipher_ivsize(skcipher); @@ -1130,7 +1154,7 @@ static int atmel_aes_crypt(struct skcipher_request *req, unsigned long mode) ivsize, 0); } - return atmel_aes_handle_queue(dd, &req->base); + return atmel_aes_handle_queue(ctx->dd, &req->base); } static int atmel_aes_setkey(struct crypto_skcipher *tfm, const u8 *key, @@ -1242,8 +1266,15 @@ static int atmel_aes_ctr_decrypt(struct skcipher_request *req) static int atmel_aes_init_tfm(struct crypto_skcipher *tfm) { struct atmel_aes_ctx *ctx = crypto_skcipher_ctx(tfm); + struct atmel_aes_dev *dd; + + dd = atmel_aes_dev_alloc(&ctx->base); + if (!dd) + return -ENODEV; crypto_skcipher_set_reqsize(tfm, sizeof(struct atmel_aes_reqctx)); + ctx->base.dd = dd; + ctx->base.dd->ctx = &ctx->base; ctx->base.start = atmel_aes_start; return 0; @@ -1252,8 +1283,15 @@ static int atmel_aes_init_tfm(struct crypto_skcipher *tfm) static int atmel_aes_ctr_init_tfm(struct crypto_skcipher *tfm) { struct atmel_aes_ctx *ctx = crypto_skcipher_ctx(tfm); + struct atmel_aes_dev *dd; + + dd = atmel_aes_dev_alloc(&ctx->base); + if (!dd) + return -ENODEV; crypto_skcipher_set_reqsize(tfm, sizeof(struct atmel_aes_reqctx)); + ctx->base.dd = dd; + ctx->base.dd->ctx = &ctx->base; ctx->base.start = atmel_aes_ctr_start; return 0; @@ -1290,7 +1328,7 @@ static struct skcipher_alg aes_algs[] = { { .base.cra_name = "ofb(aes)", .base.cra_driver_name = "atmel-ofb-aes", - .base.cra_blocksize = AES_BLOCK_SIZE, + .base.cra_blocksize = 1, .base.cra_ctxsize = sizeof(struct atmel_aes_ctx), .init = atmel_aes_init_tfm, @@ -1691,20 +1729,15 @@ static int atmel_aes_gcm_crypt(struct aead_request *req, { struct atmel_aes_base_ctx *ctx; struct atmel_aes_reqctx *rctx; - struct atmel_aes_dev *dd; ctx = crypto_aead_ctx(crypto_aead_reqtfm(req)); ctx->block_size = AES_BLOCK_SIZE; ctx->is_aead = true; - dd = atmel_aes_find_dev(ctx); - if (!dd) - return -ENODEV; - rctx = aead_request_ctx(req); rctx->mode = AES_FLAGS_GCM | mode; - return atmel_aes_handle_queue(dd, &req->base); + return atmel_aes_handle_queue(ctx->dd, &req->base); } static int atmel_aes_gcm_setkey(struct crypto_aead *tfm, const u8 *key, @@ -1742,8 +1775,15 @@ static int atmel_aes_gcm_decrypt(struct aead_request *req) static int atmel_aes_gcm_init(struct crypto_aead *tfm) { struct atmel_aes_gcm_ctx *ctx = crypto_aead_ctx(tfm); + struct atmel_aes_dev *dd; + + dd = atmel_aes_dev_alloc(&ctx->base); + if (!dd) + return -ENODEV; crypto_aead_set_reqsize(tfm, sizeof(struct atmel_aes_reqctx)); + ctx->base.dd = dd; + ctx->base.dd->ctx = &ctx->base; ctx->base.start = atmel_aes_gcm_start; return 0; @@ -1819,12 +1859,8 @@ static int atmel_aes_xts_process_data(struct atmel_aes_dev *dd) * the order of the ciphered tweak bytes need to be reversed before * writing them into the ODATARx registers. */ - for (i = 0; i < AES_BLOCK_SIZE/2; ++i) { - u8 tmp = tweak_bytes[AES_BLOCK_SIZE - 1 - i]; - - tweak_bytes[AES_BLOCK_SIZE - 1 - i] = tweak_bytes[i]; - tweak_bytes[i] = tmp; - } + for (i = 0; i < AES_BLOCK_SIZE/2; ++i) + swap(tweak_bytes[i], tweak_bytes[AES_BLOCK_SIZE - 1 - i]); /* Process the data. */ atmel_aes_write_ctrl(dd, use_dma, NULL); @@ -1849,6 +1885,13 @@ static int atmel_aes_xts_setkey(struct crypto_skcipher *tfm, const u8 *key, if (err) return err; + crypto_skcipher_clear_flags(ctx->fallback_tfm, CRYPTO_TFM_REQ_MASK); + crypto_skcipher_set_flags(ctx->fallback_tfm, tfm->base.crt_flags & + CRYPTO_TFM_REQ_MASK); + err = crypto_skcipher_setkey(ctx->fallback_tfm, key, keylen); + if (err) + return err; + memcpy(ctx->base.key, key, keylen/2); memcpy(ctx->key2, key + keylen/2, keylen/2); ctx->base.keylen = keylen/2; @@ -1869,18 +1912,40 @@ static int atmel_aes_xts_decrypt(struct skcipher_request *req) static int atmel_aes_xts_init_tfm(struct crypto_skcipher *tfm) { struct atmel_aes_xts_ctx *ctx = crypto_skcipher_ctx(tfm); + struct atmel_aes_dev *dd; + const char *tfm_name = crypto_tfm_alg_name(&tfm->base); - crypto_skcipher_set_reqsize(tfm, sizeof(struct atmel_aes_reqctx)); + dd = atmel_aes_dev_alloc(&ctx->base); + if (!dd) + return -ENODEV; + + ctx->fallback_tfm = crypto_alloc_skcipher(tfm_name, 0, + CRYPTO_ALG_NEED_FALLBACK); + if (IS_ERR(ctx->fallback_tfm)) + return PTR_ERR(ctx->fallback_tfm); + + crypto_skcipher_set_reqsize(tfm, sizeof(struct atmel_aes_reqctx) + + crypto_skcipher_reqsize(ctx->fallback_tfm)); + ctx->base.dd = dd; + ctx->base.dd->ctx = &ctx->base; ctx->base.start = atmel_aes_xts_start; return 0; } +static void atmel_aes_xts_exit_tfm(struct crypto_skcipher *tfm) +{ + struct atmel_aes_xts_ctx *ctx = crypto_skcipher_ctx(tfm); + + crypto_free_skcipher(ctx->fallback_tfm); +} + static struct skcipher_alg aes_xts_alg = { .base.cra_name = "xts(aes)", .base.cra_driver_name = "atmel-xts-aes", .base.cra_blocksize = AES_BLOCK_SIZE, .base.cra_ctxsize = sizeof(struct atmel_aes_xts_ctx), + .base.cra_flags = CRYPTO_ALG_NEED_FALLBACK, .min_keysize = 2 * AES_MIN_KEY_SIZE, .max_keysize = 2 * AES_MAX_KEY_SIZE, @@ -1889,6 +1954,7 @@ static struct skcipher_alg aes_xts_alg = { .encrypt = atmel_aes_xts_encrypt, .decrypt = atmel_aes_xts_decrypt, .init = atmel_aes_xts_init_tfm, + .exit = atmel_aes_xts_exit_tfm, }; #if IS_ENABLED(CONFIG_CRYPTO_DEV_ATMEL_AUTHENC) @@ -2075,6 +2141,11 @@ static int atmel_aes_authenc_init_tfm(struct crypto_aead *tfm, { struct atmel_aes_authenc_ctx *ctx = crypto_aead_ctx(tfm); unsigned int auth_reqsize = atmel_sha_authenc_get_reqsize(); + struct atmel_aes_dev *dd; + + dd = atmel_aes_dev_alloc(&ctx->base); + if (!dd) + return -ENODEV; ctx->auth = atmel_sha_authenc_spawn(auth_mode); if (IS_ERR(ctx->auth)) @@ -2082,6 +2153,8 @@ static int atmel_aes_authenc_init_tfm(struct crypto_aead *tfm, crypto_aead_set_reqsize(tfm, (sizeof(struct atmel_aes_authenc_reqctx) + auth_reqsize)); + ctx->base.dd = dd; + ctx->base.dd->ctx = &ctx->base; ctx->base.start = atmel_aes_authenc_start; return 0; @@ -2127,7 +2200,6 @@ static int atmel_aes_authenc_crypt(struct aead_request *req, struct atmel_aes_base_ctx *ctx = crypto_aead_ctx(tfm); u32 authsize = crypto_aead_authsize(tfm); bool enc = (mode & AES_FLAGS_ENCRYPT); - struct atmel_aes_dev *dd; /* Compute text length. */ if (!enc && req->cryptlen < authsize) @@ -2146,11 +2218,7 @@ static int atmel_aes_authenc_crypt(struct aead_request *req, ctx->block_size = AES_BLOCK_SIZE; ctx->is_aead = true; - dd = atmel_aes_find_dev(ctx); - if (!dd) - return -ENODEV; - - return atmel_aes_handle_queue(dd, &req->base); + return atmel_aes_handle_queue(ctx->dd, &req->base); } static int atmel_aes_authenc_cbc_aes_encrypt(struct aead_request *req) @@ -2358,7 +2426,7 @@ static void atmel_aes_unregister_algs(struct atmel_aes_dev *dd) static void atmel_aes_crypto_alg_init(struct crypto_alg *alg) { - alg->cra_flags = CRYPTO_ALG_ASYNC; + alg->cra_flags |= CRYPTO_ALG_ASYNC; alg->cra_alignmask = 0xf; alg->cra_priority = ATMEL_AES_PRIORITY; alg->cra_module = THIS_MODULE; diff --git a/drivers/crypto/atmel-tdes.c b/drivers/crypto/atmel-tdes.c index 6f01c51e3c37..e30786ec9f2d 100644 --- a/drivers/crypto/atmel-tdes.c +++ b/drivers/crypto/atmel-tdes.c @@ -196,23 +196,15 @@ static void atmel_tdes_write_n(struct atmel_tdes_dev *dd, u32 offset, atmel_tdes_write(dd, offset, *value); } -static struct atmel_tdes_dev *atmel_tdes_find_dev(struct atmel_tdes_ctx *ctx) +static struct atmel_tdes_dev *atmel_tdes_dev_alloc(void) { - struct atmel_tdes_dev *tdes_dd = NULL; - struct atmel_tdes_dev *tmp; + struct atmel_tdes_dev *tdes_dd; spin_lock_bh(&atmel_tdes.lock); - if (!ctx->dd) { - list_for_each_entry(tmp, &atmel_tdes.dev_list, list) { - tdes_dd = tmp; - break; - } - ctx->dd = tdes_dd; - } else { - tdes_dd = ctx->dd; - } + /* One TDES IP per SoC. */ + tdes_dd = list_first_entry_or_null(&atmel_tdes.dev_list, + struct atmel_tdes_dev, list); spin_unlock_bh(&atmel_tdes.lock); - return tdes_dd; } @@ -320,7 +312,7 @@ static int atmel_tdes_crypt_pdc_stop(struct atmel_tdes_dev *dd) dd->buf_out, dd->buflen, dd->dma_size, 1); if (count != dd->dma_size) { err = -EINVAL; - pr_err("not all data converted: %zu\n", count); + dev_dbg(dd->dev, "not all data converted: %zu\n", count); } } @@ -337,24 +329,24 @@ static int atmel_tdes_buff_init(struct atmel_tdes_dev *dd) dd->buflen &= ~(DES_BLOCK_SIZE - 1); if (!dd->buf_in || !dd->buf_out) { - dev_err(dd->dev, "unable to alloc pages.\n"); + dev_dbg(dd->dev, "unable to alloc pages.\n"); goto err_alloc; } /* MAP here */ dd->dma_addr_in = dma_map_single(dd->dev, dd->buf_in, dd->buflen, DMA_TO_DEVICE); - if (dma_mapping_error(dd->dev, dd->dma_addr_in)) { - dev_err(dd->dev, "dma %zd bytes error\n", dd->buflen); - err = -EINVAL; + err = dma_mapping_error(dd->dev, dd->dma_addr_in); + if (err) { + dev_dbg(dd->dev, "dma %zd bytes error\n", dd->buflen); goto err_map_in; } dd->dma_addr_out = dma_map_single(dd->dev, dd->buf_out, dd->buflen, DMA_FROM_DEVICE); - if (dma_mapping_error(dd->dev, dd->dma_addr_out)) { - dev_err(dd->dev, "dma %zd bytes error\n", dd->buflen); - err = -EINVAL; + err = dma_mapping_error(dd->dev, dd->dma_addr_out); + if (err) { + dev_dbg(dd->dev, "dma %zd bytes error\n", dd->buflen); goto err_map_out; } @@ -367,8 +359,6 @@ err_map_in: err_alloc: free_page((unsigned long)dd->buf_out); free_page((unsigned long)dd->buf_in); - if (err) - pr_err("error: %d\n", err); return err; } @@ -520,14 +510,14 @@ static int atmel_tdes_crypt_start(struct atmel_tdes_dev *dd) err = dma_map_sg(dd->dev, dd->in_sg, 1, DMA_TO_DEVICE); if (!err) { - dev_err(dd->dev, "dma_map_sg() error\n"); + dev_dbg(dd->dev, "dma_map_sg() error\n"); return -EINVAL; } err = dma_map_sg(dd->dev, dd->out_sg, 1, DMA_FROM_DEVICE); if (!err) { - dev_err(dd->dev, "dma_map_sg() error\n"); + dev_dbg(dd->dev, "dma_map_sg() error\n"); dma_unmap_sg(dd->dev, dd->in_sg, 1, DMA_TO_DEVICE); return -EINVAL; @@ -646,7 +636,6 @@ static int atmel_tdes_handle_queue(struct atmel_tdes_dev *dd, rctx->mode &= TDES_FLAGS_MODE_MASK; dd->flags = (dd->flags & ~TDES_FLAGS_MODE_MASK) | rctx->mode; dd->ctx = ctx; - ctx->dd = dd; err = atmel_tdes_write_ctrl(dd); if (!err) @@ -679,7 +668,7 @@ static int atmel_tdes_crypt_dma_stop(struct atmel_tdes_dev *dd) dd->buf_out, dd->buflen, dd->dma_size, 1); if (count != dd->dma_size) { err = -EINVAL; - pr_err("not all data converted: %zu\n", count); + dev_dbg(dd->dev, "not all data converted: %zu\n", count); } } } @@ -691,11 +680,15 @@ static int atmel_tdes_crypt(struct skcipher_request *req, unsigned long mode) struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req); struct atmel_tdes_ctx *ctx = crypto_skcipher_ctx(skcipher); struct atmel_tdes_reqctx *rctx = skcipher_request_ctx(req); + struct device *dev = ctx->dd->dev; + + if (!req->cryptlen) + return 0; switch (mode & TDES_FLAGS_OPMODE_MASK) { case TDES_FLAGS_CFB8: if (!IS_ALIGNED(req->cryptlen, CFB8_BLOCK_SIZE)) { - pr_err("request size is not exact amount of CFB8 blocks\n"); + dev_dbg(dev, "request size is not exact amount of CFB8 blocks\n"); return -EINVAL; } ctx->block_size = CFB8_BLOCK_SIZE; @@ -703,7 +696,7 @@ static int atmel_tdes_crypt(struct skcipher_request *req, unsigned long mode) case TDES_FLAGS_CFB16: if (!IS_ALIGNED(req->cryptlen, CFB16_BLOCK_SIZE)) { - pr_err("request size is not exact amount of CFB16 blocks\n"); + dev_dbg(dev, "request size is not exact amount of CFB16 blocks\n"); return -EINVAL; } ctx->block_size = CFB16_BLOCK_SIZE; @@ -711,7 +704,7 @@ static int atmel_tdes_crypt(struct skcipher_request *req, unsigned long mode) case TDES_FLAGS_CFB32: if (!IS_ALIGNED(req->cryptlen, CFB32_BLOCK_SIZE)) { - pr_err("request size is not exact amount of CFB32 blocks\n"); + dev_dbg(dev, "request size is not exact amount of CFB32 blocks\n"); return -EINVAL; } ctx->block_size = CFB32_BLOCK_SIZE; @@ -719,7 +712,7 @@ static int atmel_tdes_crypt(struct skcipher_request *req, unsigned long mode) default: if (!IS_ALIGNED(req->cryptlen, DES_BLOCK_SIZE)) { - pr_err("request size is not exact amount of DES blocks\n"); + dev_dbg(dev, "request size is not exact amount of DES blocks\n"); return -EINVAL; } ctx->block_size = DES_BLOCK_SIZE; @@ -897,14 +890,13 @@ static int atmel_tdes_ofb_decrypt(struct skcipher_request *req) static int atmel_tdes_init_tfm(struct crypto_skcipher *tfm) { struct atmel_tdes_ctx *ctx = crypto_skcipher_ctx(tfm); - struct atmel_tdes_dev *dd; - - crypto_skcipher_set_reqsize(tfm, sizeof(struct atmel_tdes_reqctx)); - dd = atmel_tdes_find_dev(ctx); - if (!dd) + ctx->dd = atmel_tdes_dev_alloc(); + if (!ctx->dd) return -ENODEV; + crypto_skcipher_set_reqsize(tfm, sizeof(struct atmel_tdes_reqctx)); + return 0; } @@ -999,7 +991,7 @@ static struct skcipher_alg tdes_algs[] = { { .base.cra_name = "ofb(des)", .base.cra_driver_name = "atmel-ofb-des", - .base.cra_blocksize = DES_BLOCK_SIZE, + .base.cra_blocksize = 1, .base.cra_alignmask = 0x7, .min_keysize = DES_KEY_SIZE, diff --git a/drivers/crypto/ccp/sev-dev.c b/drivers/crypto/ccp/sev-dev.c index 91808402e0bf..2ecb0e1f65d8 100644 --- a/drivers/crypto/ccp/sev-dev.c +++ b/drivers/crypto/ccp/sev-dev.c @@ -300,6 +300,9 @@ static int __sev_platform_shutdown_locked(int *error) struct sev_device *sev = psp_master->sev_data; int ret; + if (sev->state == SEV_STATE_UNINIT) + return 0; + ret = __sev_do_cmd_locked(SEV_CMD_SHUTDOWN, NULL, error); if (ret) return ret; @@ -1019,6 +1022,20 @@ e_err: return ret; } +static void sev_firmware_shutdown(struct sev_device *sev) +{ + sev_platform_shutdown(NULL); + + if (sev_es_tmr) { + /* The TMR area was encrypted, flush it from the cache */ + wbinvd_on_all_cpus(); + + free_pages((unsigned long)sev_es_tmr, + get_order(SEV_ES_TMR_SIZE)); + sev_es_tmr = NULL; + } +} + void sev_dev_destroy(struct psp_device *psp) { struct sev_device *sev = psp->sev_data; @@ -1026,6 +1043,8 @@ void sev_dev_destroy(struct psp_device *psp) if (!sev) return; + sev_firmware_shutdown(sev); + if (sev->misc) kref_put(&misc_dev->refcount, sev_exit); @@ -1056,21 +1075,6 @@ void sev_pci_init(void) if (sev_get_api_version()) goto err; - /* - * If platform is not in UNINIT state then firmware upgrade and/or - * platform INIT command will fail. These command require UNINIT state. - * - * In a normal boot we should never run into case where the firmware - * is not in UNINIT state on boot. But in case of kexec boot, a reboot - * may not go through a typical shutdown sequence and may leave the - * firmware in INIT or WORKING state. - */ - - if (sev->state != SEV_STATE_UNINIT) { - sev_platform_shutdown(NULL); - sev->state = SEV_STATE_UNINIT; - } - if (sev_version_greater_or_equal(0, 15) && sev_update_firmware(sev->dev) == 0) sev_get_api_version(); @@ -1115,17 +1119,10 @@ err: void sev_pci_exit(void) { - if (!psp_master->sev_data) - return; - - sev_platform_shutdown(NULL); + struct sev_device *sev = psp_master->sev_data; - if (sev_es_tmr) { - /* The TMR area was encrypted, flush it from the cache */ - wbinvd_on_all_cpus(); + if (!sev) + return; - free_pages((unsigned long)sev_es_tmr, - get_order(SEV_ES_TMR_SIZE)); - sev_es_tmr = NULL; - } + sev_firmware_shutdown(sev); } diff --git a/drivers/crypto/ccp/sp-pci.c b/drivers/crypto/ccp/sp-pci.c index 6fb6ba35f89d..88c672ad27e4 100644 --- a/drivers/crypto/ccp/sp-pci.c +++ b/drivers/crypto/ccp/sp-pci.c @@ -241,6 +241,17 @@ e_err: return ret; } +static void sp_pci_shutdown(struct pci_dev *pdev) +{ + struct device *dev = &pdev->dev; + struct sp_device *sp = dev_get_drvdata(dev); + + if (!sp) + return; + + sp_destroy(sp); +} + static void sp_pci_remove(struct pci_dev *pdev) { struct device *dev = &pdev->dev; @@ -351,6 +362,12 @@ static const struct sp_dev_vdata dev_vdata[] = { .psp_vdata = &pspv3, #endif }, + { /* 5 */ + .bar = 2, +#ifdef CONFIG_CRYPTO_DEV_SP_PSP + .psp_vdata = &pspv2, +#endif + }, }; static const struct pci_device_id sp_pci_table[] = { { PCI_VDEVICE(AMD, 0x1537), (kernel_ulong_t)&dev_vdata[0] }, @@ -359,6 +376,7 @@ static const struct pci_device_id sp_pci_table[] = { { PCI_VDEVICE(AMD, 0x1486), (kernel_ulong_t)&dev_vdata[3] }, { PCI_VDEVICE(AMD, 0x15DF), (kernel_ulong_t)&dev_vdata[4] }, { PCI_VDEVICE(AMD, 0x1649), (kernel_ulong_t)&dev_vdata[4] }, + { PCI_VDEVICE(AMD, 0x14CA), (kernel_ulong_t)&dev_vdata[5] }, /* Last entry must be zero */ { 0, } }; @@ -371,6 +389,7 @@ static struct pci_driver sp_pci_driver = { .id_table = sp_pci_table, .probe = sp_pci_probe, .remove = sp_pci_remove, + .shutdown = sp_pci_shutdown, .driver.pm = &sp_pci_pm_ops, }; diff --git a/drivers/crypto/hisilicon/hpre/hpre_main.c b/drivers/crypto/hisilicon/hpre/hpre_main.c index 8b0640fb04be..65a641396c07 100644 --- a/drivers/crypto/hisilicon/hpre/hpre_main.c +++ b/drivers/crypto/hisilicon/hpre/hpre_main.c @@ -9,6 +9,7 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/pci.h> +#include <linux/pm_runtime.h> #include <linux/topology.h> #include <linux/uacce.h> #include "hpre.h" @@ -81,6 +82,16 @@ #define HPRE_PREFETCH_DISABLE BIT(30) #define HPRE_SVA_DISABLE_READY (BIT(4) | BIT(8)) +/* clock gate */ +#define HPRE_CLKGATE_CTL 0x301a10 +#define HPRE_PEH_CFG_AUTO_GATE 0x301a2c +#define HPRE_CLUSTER_DYN_CTL 0x302010 +#define HPRE_CORE_SHB_CFG 0x302088 +#define HPRE_CLKGATE_CTL_EN BIT(0) +#define HPRE_PEH_CFG_AUTO_GATE_EN BIT(0) +#define HPRE_CLUSTER_DYN_CTL_EN BIT(0) +#define HPRE_CORE_GATE_EN (BIT(30) | BIT(31)) + #define HPRE_AM_OOO_SHUTDOWN_ENB 0x301044 #define HPRE_AM_OOO_SHUTDOWN_ENABLE BIT(0) #define HPRE_WR_MSI_PORT BIT(2) @@ -417,12 +428,63 @@ static void hpre_close_sva_prefetch(struct hisi_qm *qm) pci_err(qm->pdev, "failed to close sva prefetch\n"); } +static void hpre_enable_clock_gate(struct hisi_qm *qm) +{ + u32 val; + + if (qm->ver < QM_HW_V3) + return; + + val = readl(qm->io_base + HPRE_CLKGATE_CTL); + val |= HPRE_CLKGATE_CTL_EN; + writel(val, qm->io_base + HPRE_CLKGATE_CTL); + + val = readl(qm->io_base + HPRE_PEH_CFG_AUTO_GATE); + val |= HPRE_PEH_CFG_AUTO_GATE_EN; + writel(val, qm->io_base + HPRE_PEH_CFG_AUTO_GATE); + + val = readl(qm->io_base + HPRE_CLUSTER_DYN_CTL); + val |= HPRE_CLUSTER_DYN_CTL_EN; + writel(val, qm->io_base + HPRE_CLUSTER_DYN_CTL); + + val = readl_relaxed(qm->io_base + HPRE_CORE_SHB_CFG); + val |= HPRE_CORE_GATE_EN; + writel(val, qm->io_base + HPRE_CORE_SHB_CFG); +} + +static void hpre_disable_clock_gate(struct hisi_qm *qm) +{ + u32 val; + + if (qm->ver < QM_HW_V3) + return; + + val = readl(qm->io_base + HPRE_CLKGATE_CTL); + val &= ~HPRE_CLKGATE_CTL_EN; + writel(val, qm->io_base + HPRE_CLKGATE_CTL); + + val = readl(qm->io_base + HPRE_PEH_CFG_AUTO_GATE); + val &= ~HPRE_PEH_CFG_AUTO_GATE_EN; + writel(val, qm->io_base + HPRE_PEH_CFG_AUTO_GATE); + + val = readl(qm->io_base + HPRE_CLUSTER_DYN_CTL); + val &= ~HPRE_CLUSTER_DYN_CTL_EN; + writel(val, qm->io_base + HPRE_CLUSTER_DYN_CTL); + + val = readl_relaxed(qm->io_base + HPRE_CORE_SHB_CFG); + val &= ~HPRE_CORE_GATE_EN; + writel(val, qm->io_base + HPRE_CORE_SHB_CFG); +} + static int hpre_set_user_domain_and_cache(struct hisi_qm *qm) { struct device *dev = &qm->pdev->dev; u32 val; int ret; + /* disabel dynamic clock gate before sram init */ + hpre_disable_clock_gate(qm); + writel(HPRE_QM_USR_CFG_MASK, qm->io_base + QM_ARUSER_M_CFG_ENABLE); writel(HPRE_QM_USR_CFG_MASK, qm->io_base + QM_AWUSER_M_CFG_ENABLE); writel_relaxed(HPRE_QM_AXI_CFG_MASK, qm->io_base + QM_AXI_M_CFG); @@ -473,6 +535,8 @@ static int hpre_set_user_domain_and_cache(struct hisi_qm *qm) /* Config data buffer pasid needed by Kunpeng 920 */ hpre_config_pasid(qm); + hpre_enable_clock_gate(qm); + return ret; } @@ -595,10 +659,15 @@ static ssize_t hpre_ctrl_debug_read(struct file *filp, char __user *buf, size_t count, loff_t *pos) { struct hpre_debugfs_file *file = filp->private_data; + struct hisi_qm *qm = hpre_file_to_qm(file); char tbuf[HPRE_DBGFS_VAL_MAX_LEN]; u32 val; int ret; + ret = hisi_qm_get_dfx_access(qm); + if (ret) + return ret; + spin_lock_irq(&file->lock); switch (file->type) { case HPRE_CLEAR_ENABLE: @@ -608,18 +677,25 @@ static ssize_t hpre_ctrl_debug_read(struct file *filp, char __user *buf, val = hpre_cluster_inqry_read(file); break; default: - spin_unlock_irq(&file->lock); - return -EINVAL; + goto err_input; } spin_unlock_irq(&file->lock); + + hisi_qm_put_dfx_access(qm); ret = snprintf(tbuf, HPRE_DBGFS_VAL_MAX_LEN, "%u\n", val); return simple_read_from_buffer(buf, count, pos, tbuf, ret); + +err_input: + spin_unlock_irq(&file->lock); + hisi_qm_put_dfx_access(qm); + return -EINVAL; } static ssize_t hpre_ctrl_debug_write(struct file *filp, const char __user *buf, size_t count, loff_t *pos) { struct hpre_debugfs_file *file = filp->private_data; + struct hisi_qm *qm = hpre_file_to_qm(file); char tbuf[HPRE_DBGFS_VAL_MAX_LEN]; unsigned long val; int len, ret; @@ -639,6 +715,10 @@ static ssize_t hpre_ctrl_debug_write(struct file *filp, const char __user *buf, if (kstrtoul(tbuf, 0, &val)) return -EFAULT; + ret = hisi_qm_get_dfx_access(qm); + if (ret) + return ret; + spin_lock_irq(&file->lock); switch (file->type) { case HPRE_CLEAR_ENABLE: @@ -655,12 +735,12 @@ static ssize_t hpre_ctrl_debug_write(struct file *filp, const char __user *buf, ret = -EINVAL; goto err_input; } - spin_unlock_irq(&file->lock); - return count; + ret = count; err_input: spin_unlock_irq(&file->lock); + hisi_qm_put_dfx_access(qm); return ret; } @@ -700,6 +780,24 @@ static int hpre_debugfs_atomic64_set(void *data, u64 val) DEFINE_DEBUGFS_ATTRIBUTE(hpre_atomic64_ops, hpre_debugfs_atomic64_get, hpre_debugfs_atomic64_set, "%llu\n"); +static int hpre_com_regs_show(struct seq_file *s, void *unused) +{ + hisi_qm_regs_dump(s, s->private); + + return 0; +} + +DEFINE_SHOW_ATTRIBUTE(hpre_com_regs); + +static int hpre_cluster_regs_show(struct seq_file *s, void *unused) +{ + hisi_qm_regs_dump(s, s->private); + + return 0; +} + +DEFINE_SHOW_ATTRIBUTE(hpre_cluster_regs); + static int hpre_create_debugfs_file(struct hisi_qm *qm, struct dentry *dir, enum hpre_ctrl_dbgfs_file type, int indx) { @@ -737,8 +835,11 @@ static int hpre_pf_comm_regs_debugfs_init(struct hisi_qm *qm) regset->regs = hpre_com_dfx_regs; regset->nregs = ARRAY_SIZE(hpre_com_dfx_regs); regset->base = qm->io_base; + regset->dev = dev; + + debugfs_create_file("regs", 0444, qm->debug.debug_root, + regset, &hpre_com_regs_fops); - debugfs_create_regset32("regs", 0444, qm->debug.debug_root, regset); return 0; } @@ -764,8 +865,10 @@ static int hpre_cluster_debugfs_init(struct hisi_qm *qm) regset->regs = hpre_cluster_dfx_regs; regset->nregs = ARRAY_SIZE(hpre_cluster_dfx_regs); regset->base = qm->io_base + hpre_cluster_offsets[i]; + regset->dev = dev; - debugfs_create_regset32("regs", 0444, tmp_d, regset); + debugfs_create_file("regs", 0444, tmp_d, regset, + &hpre_cluster_regs_fops); ret = hpre_create_debugfs_file(qm, tmp_d, HPRE_CLUSTER_CTRL, i + HPRE_CLUSTER_CTRL); if (ret) @@ -1017,6 +1120,8 @@ static int hpre_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto err_with_alg_register; } + hisi_qm_pm_init(qm); + return 0; err_with_alg_register: @@ -1040,6 +1145,7 @@ static void hpre_remove(struct pci_dev *pdev) struct hisi_qm *qm = pci_get_drvdata(pdev); int ret; + hisi_qm_pm_uninit(qm); hisi_qm_wait_task_finish(qm, &hpre_devices); hisi_qm_alg_unregister(qm, &hpre_devices); if (qm->fun_type == QM_HW_PF && qm->vfs_num) { @@ -1062,6 +1168,10 @@ static void hpre_remove(struct pci_dev *pdev) hisi_qm_uninit(qm); } +static const struct dev_pm_ops hpre_pm_ops = { + SET_RUNTIME_PM_OPS(hisi_qm_suspend, hisi_qm_resume, NULL) +}; + static const struct pci_error_handlers hpre_err_handler = { .error_detected = hisi_qm_dev_err_detected, .slot_reset = hisi_qm_dev_slot_reset, @@ -1078,6 +1188,7 @@ static struct pci_driver hpre_pci_driver = { hisi_qm_sriov_configure : NULL, .err_handler = &hpre_err_handler, .shutdown = hisi_qm_dev_shutdown, + .driver.pm = &hpre_pm_ops, }; static void hpre_register_debugfs(void) diff --git a/drivers/crypto/hisilicon/qm.c b/drivers/crypto/hisilicon/qm.c index 1d67f94a1d56..369562d34d66 100644 --- a/drivers/crypto/hisilicon/qm.c +++ b/drivers/crypto/hisilicon/qm.c @@ -4,12 +4,12 @@ #include <linux/acpi.h> #include <linux/aer.h> #include <linux/bitmap.h> -#include <linux/debugfs.h> #include <linux/dma-mapping.h> #include <linux/idr.h> #include <linux/io.h> #include <linux/irqreturn.h> #include <linux/log2.h> +#include <linux/pm_runtime.h> #include <linux/seq_file.h> #include <linux/slab.h> #include <linux/uacce.h> @@ -270,6 +270,8 @@ #define QM_QOS_MAX_CIR_S 11 #define QM_QOS_VAL_MAX_LEN 32 +#define QM_AUTOSUSPEND_DELAY 3000 + #define QM_MK_CQC_DW3_V1(hop_num, pg_sz, buf_sz, cqe_sz) \ (((hop_num) << QM_CQ_HOP_NUM_SHIFT) | \ ((pg_sz) << QM_CQ_PAGE_SIZE_SHIFT) | \ @@ -734,6 +736,34 @@ static u32 qm_get_irq_num_v3(struct hisi_qm *qm) return QM_IRQ_NUM_VF_V3; } +static int qm_pm_get_sync(struct hisi_qm *qm) +{ + struct device *dev = &qm->pdev->dev; + int ret; + + if (qm->fun_type == QM_HW_VF || qm->ver < QM_HW_V3) + return 0; + + ret = pm_runtime_resume_and_get(dev); + if (ret < 0) { + dev_err(dev, "failed to get_sync(%d).\n", ret); + return ret; + } + + return 0; +} + +static void qm_pm_put_sync(struct hisi_qm *qm) +{ + struct device *dev = &qm->pdev->dev; + + if (qm->fun_type == QM_HW_VF || qm->ver < QM_HW_V3) + return; + + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); +} + static struct hisi_qp *qm_to_hisi_qp(struct hisi_qm *qm, struct qm_eqe *eqe) { u16 cqn = le32_to_cpu(eqe->dw0) & QM_EQE_CQN_MASK; @@ -1173,16 +1203,13 @@ static struct hisi_qm *file_to_qm(struct debugfs_file *file) return container_of(debug, struct hisi_qm, debug); } -static u32 current_q_read(struct debugfs_file *file) +static u32 current_q_read(struct hisi_qm *qm) { - struct hisi_qm *qm = file_to_qm(file); - return readl(qm->io_base + QM_DFX_SQE_CNT_VF_SQN) >> QM_DFX_QN_SHIFT; } -static int current_q_write(struct debugfs_file *file, u32 val) +static int current_q_write(struct hisi_qm *qm, u32 val) { - struct hisi_qm *qm = file_to_qm(file); u32 tmp; if (val >= qm->debug.curr_qm_qp_num) @@ -1199,18 +1226,14 @@ static int current_q_write(struct debugfs_file *file, u32 val) return 0; } -static u32 clear_enable_read(struct debugfs_file *file) +static u32 clear_enable_read(struct hisi_qm *qm) { - struct hisi_qm *qm = file_to_qm(file); - return readl(qm->io_base + QM_DFX_CNT_CLR_CE); } /* rd_clr_ctrl 1 enable read clear, otherwise 0 disable it */ -static int clear_enable_write(struct debugfs_file *file, u32 rd_clr_ctrl) +static int clear_enable_write(struct hisi_qm *qm, u32 rd_clr_ctrl) { - struct hisi_qm *qm = file_to_qm(file); - if (rd_clr_ctrl > 1) return -EINVAL; @@ -1219,16 +1242,13 @@ static int clear_enable_write(struct debugfs_file *file, u32 rd_clr_ctrl) return 0; } -static u32 current_qm_read(struct debugfs_file *file) +static u32 current_qm_read(struct hisi_qm *qm) { - struct hisi_qm *qm = file_to_qm(file); - return readl(qm->io_base + QM_DFX_MB_CNT_VF); } -static int current_qm_write(struct debugfs_file *file, u32 val) +static int current_qm_write(struct hisi_qm *qm, u32 val) { - struct hisi_qm *qm = file_to_qm(file); u32 tmp; if (val > qm->vfs_num) @@ -1259,29 +1279,39 @@ static ssize_t qm_debug_read(struct file *filp, char __user *buf, { struct debugfs_file *file = filp->private_data; enum qm_debug_file index = file->index; + struct hisi_qm *qm = file_to_qm(file); char tbuf[QM_DBG_TMP_BUF_LEN]; u32 val; int ret; + ret = hisi_qm_get_dfx_access(qm); + if (ret) + return ret; + mutex_lock(&file->lock); switch (index) { case CURRENT_QM: - val = current_qm_read(file); + val = current_qm_read(qm); break; case CURRENT_Q: - val = current_q_read(file); + val = current_q_read(qm); break; case CLEAR_ENABLE: - val = clear_enable_read(file); + val = clear_enable_read(qm); break; default: - mutex_unlock(&file->lock); - return -EINVAL; + goto err_input; } mutex_unlock(&file->lock); + hisi_qm_put_dfx_access(qm); ret = scnprintf(tbuf, QM_DBG_TMP_BUF_LEN, "%u\n", val); return simple_read_from_buffer(buf, count, pos, tbuf, ret); + +err_input: + mutex_unlock(&file->lock); + hisi_qm_put_dfx_access(qm); + return -EINVAL; } static ssize_t qm_debug_write(struct file *filp, const char __user *buf, @@ -1289,6 +1319,7 @@ static ssize_t qm_debug_write(struct file *filp, const char __user *buf, { struct debugfs_file *file = filp->private_data; enum qm_debug_file index = file->index; + struct hisi_qm *qm = file_to_qm(file); unsigned long val; char tbuf[QM_DBG_TMP_BUF_LEN]; int len, ret; @@ -1308,22 +1339,28 @@ static ssize_t qm_debug_write(struct file *filp, const char __user *buf, if (kstrtoul(tbuf, 0, &val)) return -EFAULT; + ret = hisi_qm_get_dfx_access(qm); + if (ret) + return ret; + mutex_lock(&file->lock); switch (index) { case CURRENT_QM: - ret = current_qm_write(file, val); + ret = current_qm_write(qm, val); break; case CURRENT_Q: - ret = current_q_write(file, val); + ret = current_q_write(qm, val); break; case CLEAR_ENABLE: - ret = clear_enable_write(file, val); + ret = clear_enable_write(qm, val); break; default: ret = -EINVAL; } mutex_unlock(&file->lock); + hisi_qm_put_dfx_access(qm); + if (ret) return ret; @@ -1337,13 +1374,8 @@ static const struct file_operations qm_debug_fops = { .write = qm_debug_write, }; -struct qm_dfx_registers { - char *reg_name; - u64 reg_offset; -}; - #define CNT_CYC_REGS_NUM 10 -static struct qm_dfx_registers qm_dfx_regs[] = { +static const struct debugfs_reg32 qm_dfx_regs[] = { /* XXX_CNT are reading clear register */ {"QM_ECC_1BIT_CNT ", 0x104000ull}, {"QM_ECC_MBIT_CNT ", 0x104008ull}, @@ -1369,31 +1401,59 @@ static struct qm_dfx_registers qm_dfx_regs[] = { {"QM_DFX_FF_ST5 ", 0x1040dcull}, {"QM_DFX_FF_ST6 ", 0x1040e0ull}, {"QM_IN_IDLE_ST ", 0x1040e4ull}, - { NULL, 0} }; -static struct qm_dfx_registers qm_vf_dfx_regs[] = { +static const struct debugfs_reg32 qm_vf_dfx_regs[] = { {"QM_DFX_FUNS_ACTIVE_ST ", 0x200ull}, - { NULL, 0} }; -static int qm_regs_show(struct seq_file *s, void *unused) +/** + * hisi_qm_regs_dump() - Dump registers's value. + * @s: debugfs file handle. + * @regset: accelerator registers information. + * + * Dump accelerator registers. + */ +void hisi_qm_regs_dump(struct seq_file *s, struct debugfs_regset32 *regset) { - struct hisi_qm *qm = s->private; - struct qm_dfx_registers *regs; + struct pci_dev *pdev = to_pci_dev(regset->dev); + struct hisi_qm *qm = pci_get_drvdata(pdev); + const struct debugfs_reg32 *regs = regset->regs; + int regs_len = regset->nregs; + int i, ret; u32 val; - if (qm->fun_type == QM_HW_PF) - regs = qm_dfx_regs; - else - regs = qm_vf_dfx_regs; + ret = hisi_qm_get_dfx_access(qm); + if (ret) + return; - while (regs->reg_name) { - val = readl(qm->io_base + regs->reg_offset); - seq_printf(s, "%s= 0x%08x\n", regs->reg_name, val); - regs++; + for (i = 0; i < regs_len; i++) { + val = readl(regset->base + regs[i].offset); + seq_printf(s, "%s= 0x%08x\n", regs[i].name, val); } + hisi_qm_put_dfx_access(qm); +} +EXPORT_SYMBOL_GPL(hisi_qm_regs_dump); + +static int qm_regs_show(struct seq_file *s, void *unused) +{ + struct hisi_qm *qm = s->private; + struct debugfs_regset32 regset; + + if (qm->fun_type == QM_HW_PF) { + regset.regs = qm_dfx_regs; + regset.nregs = ARRAY_SIZE(qm_dfx_regs); + } else { + regset.regs = qm_vf_dfx_regs; + regset.nregs = ARRAY_SIZE(qm_vf_dfx_regs); + } + + regset.base = qm->io_base; + regset.dev = &qm->pdev->dev; + + hisi_qm_regs_dump(s, ®set); + return 0; } @@ -1823,16 +1883,24 @@ static ssize_t qm_cmd_write(struct file *filp, const char __user *buffer, if (*pos) return 0; + ret = hisi_qm_get_dfx_access(qm); + if (ret) + return ret; + /* Judge if the instance is being reset. */ if (unlikely(atomic_read(&qm->status.flags) == QM_STOP)) return 0; - if (count > QM_DBG_WRITE_LEN) - return -ENOSPC; + if (count > QM_DBG_WRITE_LEN) { + ret = -ENOSPC; + goto put_dfx_access; + } cmd_buf = memdup_user_nul(buffer, count); - if (IS_ERR(cmd_buf)) - return PTR_ERR(cmd_buf); + if (IS_ERR(cmd_buf)) { + ret = PTR_ERR(cmd_buf); + goto put_dfx_access; + } cmd_buf_tmp = strchr(cmd_buf, '\n'); if (cmd_buf_tmp) { @@ -1843,12 +1911,16 @@ static ssize_t qm_cmd_write(struct file *filp, const char __user *buffer, ret = qm_cmd_write_dump(qm, cmd_buf); if (ret) { kfree(cmd_buf); - return ret; + goto put_dfx_access; } kfree(cmd_buf); - return count; + ret = count; + +put_dfx_access: + hisi_qm_put_dfx_access(qm); + return ret; } static const struct file_operations qm_cmd_fops = { @@ -2445,11 +2517,19 @@ static struct hisi_qp *qm_create_qp_nolock(struct hisi_qm *qm, u8 alg_type) struct hisi_qp *hisi_qm_create_qp(struct hisi_qm *qm, u8 alg_type) { struct hisi_qp *qp; + int ret; + + ret = qm_pm_get_sync(qm); + if (ret) + return ERR_PTR(ret); down_write(&qm->qps_lock); qp = qm_create_qp_nolock(qm, alg_type); up_write(&qm->qps_lock); + if (IS_ERR(qp)) + qm_pm_put_sync(qm); + return qp; } EXPORT_SYMBOL_GPL(hisi_qm_create_qp); @@ -2475,6 +2555,8 @@ void hisi_qm_release_qp(struct hisi_qp *qp) idr_remove(&qm->qp_idr, qp->qp_id); up_write(&qm->qps_lock); + + qm_pm_put_sync(qm); } EXPORT_SYMBOL_GPL(hisi_qm_release_qp); @@ -3200,6 +3282,10 @@ static void hisi_qm_pre_init(struct hisi_qm *qm) init_rwsem(&qm->qps_lock); qm->qp_in_used = 0; qm->misc_ctl = false; + if (qm->fun_type == QM_HW_PF && qm->ver > QM_HW_V2) { + if (!acpi_device_power_manageable(ACPI_COMPANION(&pdev->dev))) + dev_info(&pdev->dev, "_PS0 and _PR0 are not defined"); + } } static void qm_cmd_uninit(struct hisi_qm *qm) @@ -4057,10 +4143,15 @@ static ssize_t qm_algqos_read(struct file *filp, char __user *buf, u32 qos_val, ir; int ret; + ret = hisi_qm_get_dfx_access(qm); + if (ret) + return ret; + /* Mailbox and reset cannot be operated at the same time */ if (test_and_set_bit(QM_RESETTING, &qm->misc_ctl)) { pci_err(qm->pdev, "dev resetting, read alg qos failed!\n"); - return -EAGAIN; + ret = -EAGAIN; + goto err_put_dfx_access; } if (qm->fun_type == QM_HW_PF) { @@ -4079,6 +4170,8 @@ static ssize_t qm_algqos_read(struct file *filp, char __user *buf, err_get_status: clear_bit(QM_RESETTING, &qm->misc_ctl); +err_put_dfx_access: + hisi_qm_put_dfx_access(qm); return ret; } @@ -4159,15 +4252,23 @@ static ssize_t qm_algqos_write(struct file *filp, const char __user *buf, fun_index = device * 8 + function; + ret = qm_pm_get_sync(qm); + if (ret) { + ret = -EINVAL; + goto err_get_status; + } + ret = qm_func_shaper_enable(qm, fun_index, val); if (ret) { pci_err(qm->pdev, "failed to enable function shaper!\n"); ret = -EINVAL; - goto err_get_status; + goto err_put_sync; } - ret = count; + ret = count; +err_put_sync: + qm_pm_put_sync(qm); err_get_status: clear_bit(QM_RESETTING, &qm->misc_ctl); return ret; @@ -4245,7 +4346,7 @@ EXPORT_SYMBOL_GPL(hisi_qm_debug_init); */ void hisi_qm_debug_regs_clear(struct hisi_qm *qm) { - struct qm_dfx_registers *regs; + const struct debugfs_reg32 *regs; int i; /* clear current_qm */ @@ -4264,7 +4365,7 @@ void hisi_qm_debug_regs_clear(struct hisi_qm *qm) regs = qm_dfx_regs; for (i = 0; i < CNT_CYC_REGS_NUM; i++) { - readl(qm->io_base + regs->reg_offset); + readl(qm->io_base + regs->offset); regs++; } @@ -4287,19 +4388,23 @@ int hisi_qm_sriov_enable(struct pci_dev *pdev, int max_vfs) struct hisi_qm *qm = pci_get_drvdata(pdev); int pre_existing_vfs, num_vfs, total_vfs, ret; + ret = qm_pm_get_sync(qm); + if (ret) + return ret; + total_vfs = pci_sriov_get_totalvfs(pdev); pre_existing_vfs = pci_num_vf(pdev); if (pre_existing_vfs) { pci_err(pdev, "%d VFs already enabled. Please disable pre-enabled VFs!\n", pre_existing_vfs); - return 0; + goto err_put_sync; } num_vfs = min_t(int, max_vfs, total_vfs); ret = qm_vf_q_assign(qm, num_vfs); if (ret) { pci_err(pdev, "Can't assign queues for VF!\n"); - return ret; + goto err_put_sync; } qm->vfs_num = num_vfs; @@ -4308,12 +4413,16 @@ int hisi_qm_sriov_enable(struct pci_dev *pdev, int max_vfs) if (ret) { pci_err(pdev, "Can't enable VF!\n"); qm_clear_vft_config(qm); - return ret; + goto err_put_sync; } pci_info(pdev, "VF enabled, vfs_num(=%d)!\n", num_vfs); return num_vfs; + +err_put_sync: + qm_pm_put_sync(qm); + return ret; } EXPORT_SYMBOL_GPL(hisi_qm_sriov_enable); @@ -4328,6 +4437,7 @@ int hisi_qm_sriov_disable(struct pci_dev *pdev, bool is_frozen) { struct hisi_qm *qm = pci_get_drvdata(pdev); int total_vfs = pci_sriov_get_totalvfs(qm->pdev); + int ret; if (pci_vfs_assigned(pdev)) { pci_err(pdev, "Failed to disable VFs as VFs are assigned!\n"); @@ -4343,8 +4453,13 @@ int hisi_qm_sriov_disable(struct pci_dev *pdev, bool is_frozen) pci_disable_sriov(pdev); /* clear vf function shaper configure array */ memset(qm->factor + 1, 0, sizeof(struct qm_shaper_factor) * total_vfs); + ret = qm_clear_vft_config(qm); + if (ret) + return ret; - return qm_clear_vft_config(qm); + qm_pm_put_sync(qm); + + return 0; } EXPORT_SYMBOL_GPL(hisi_qm_sriov_disable); @@ -5164,11 +5279,18 @@ static void hisi_qm_controller_reset(struct work_struct *rst_work) struct hisi_qm *qm = container_of(rst_work, struct hisi_qm, rst_work); int ret; + ret = qm_pm_get_sync(qm); + if (ret) { + clear_bit(QM_RST_SCHED, &qm->misc_ctl); + return; + } + /* reset pcie device controller */ ret = qm_controller_reset(qm); if (ret) dev_err(&qm->pdev->dev, "controller reset failed (%d)\n", ret); + qm_pm_put_sync(qm); } static void qm_pf_reset_vf_prepare(struct hisi_qm *qm, @@ -5680,6 +5802,194 @@ err_pci_init: } EXPORT_SYMBOL_GPL(hisi_qm_init); +/** + * hisi_qm_get_dfx_access() - Try to get dfx access. + * @qm: pointer to accelerator device. + * + * Try to get dfx access, then user can get message. + * + * If device is in suspended, return failure, otherwise + * bump up the runtime PM usage counter. + */ +int hisi_qm_get_dfx_access(struct hisi_qm *qm) +{ + struct device *dev = &qm->pdev->dev; + + if (pm_runtime_suspended(dev)) { + dev_info(dev, "can not read/write - device in suspended.\n"); + return -EAGAIN; + } + + return qm_pm_get_sync(qm); +} +EXPORT_SYMBOL_GPL(hisi_qm_get_dfx_access); + +/** + * hisi_qm_put_dfx_access() - Put dfx access. + * @qm: pointer to accelerator device. + * + * Put dfx access, drop runtime PM usage counter. + */ +void hisi_qm_put_dfx_access(struct hisi_qm *qm) +{ + qm_pm_put_sync(qm); +} +EXPORT_SYMBOL_GPL(hisi_qm_put_dfx_access); + +/** + * hisi_qm_pm_init() - Initialize qm runtime PM. + * @qm: pointer to accelerator device. + * + * Function that initialize qm runtime PM. + */ +void hisi_qm_pm_init(struct hisi_qm *qm) +{ + struct device *dev = &qm->pdev->dev; + + if (qm->fun_type == QM_HW_VF || qm->ver < QM_HW_V3) + return; + + pm_runtime_set_autosuspend_delay(dev, QM_AUTOSUSPEND_DELAY); + pm_runtime_use_autosuspend(dev); + pm_runtime_put_noidle(dev); +} +EXPORT_SYMBOL_GPL(hisi_qm_pm_init); + +/** + * hisi_qm_pm_uninit() - Uninitialize qm runtime PM. + * @qm: pointer to accelerator device. + * + * Function that uninitialize qm runtime PM. + */ +void hisi_qm_pm_uninit(struct hisi_qm *qm) +{ + struct device *dev = &qm->pdev->dev; + + if (qm->fun_type == QM_HW_VF || qm->ver < QM_HW_V3) + return; + + pm_runtime_get_noresume(dev); + pm_runtime_dont_use_autosuspend(dev); +} +EXPORT_SYMBOL_GPL(hisi_qm_pm_uninit); + +static int qm_prepare_for_suspend(struct hisi_qm *qm) +{ + struct pci_dev *pdev = qm->pdev; + int ret; + u32 val; + + ret = qm->ops->set_msi(qm, false); + if (ret) { + pci_err(pdev, "failed to disable MSI before suspending!\n"); + return ret; + } + + /* shutdown OOO register */ + writel(ACC_MASTER_GLOBAL_CTRL_SHUTDOWN, + qm->io_base + ACC_MASTER_GLOBAL_CTRL); + + ret = readl_relaxed_poll_timeout(qm->io_base + ACC_MASTER_TRANS_RETURN, + val, + (val == ACC_MASTER_TRANS_RETURN_RW), + POLL_PERIOD, POLL_TIMEOUT); + if (ret) { + pci_emerg(pdev, "Bus lock! Please reset system.\n"); + return ret; + } + + ret = qm_set_pf_mse(qm, false); + if (ret) + pci_err(pdev, "failed to disable MSE before suspending!\n"); + + return ret; +} + +static int qm_rebuild_for_resume(struct hisi_qm *qm) +{ + struct pci_dev *pdev = qm->pdev; + int ret; + + ret = qm_set_pf_mse(qm, true); + if (ret) { + pci_err(pdev, "failed to enable MSE after resuming!\n"); + return ret; + } + + ret = qm->ops->set_msi(qm, true); + if (ret) { + pci_err(pdev, "failed to enable MSI after resuming!\n"); + return ret; + } + + ret = qm_dev_hw_init(qm); + if (ret) { + pci_err(pdev, "failed to init device after resuming\n"); + return ret; + } + + qm_cmd_init(qm); + hisi_qm_dev_err_init(qm); + + return 0; +} + +/** + * hisi_qm_suspend() - Runtime suspend of given device. + * @dev: device to suspend. + * + * Function that suspend the device. + */ +int hisi_qm_suspend(struct device *dev) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct hisi_qm *qm = pci_get_drvdata(pdev); + int ret; + + pci_info(pdev, "entering suspended state\n"); + + ret = hisi_qm_stop(qm, QM_NORMAL); + if (ret) { + pci_err(pdev, "failed to stop qm(%d)\n", ret); + return ret; + } + + ret = qm_prepare_for_suspend(qm); + if (ret) + pci_err(pdev, "failed to prepare suspended(%d)\n", ret); + + return ret; +} +EXPORT_SYMBOL_GPL(hisi_qm_suspend); + +/** + * hisi_qm_resume() - Runtime resume of given device. + * @dev: device to resume. + * + * Function that resume the device. + */ +int hisi_qm_resume(struct device *dev) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct hisi_qm *qm = pci_get_drvdata(pdev); + int ret; + + pci_info(pdev, "resuming from suspend state\n"); + + ret = qm_rebuild_for_resume(qm); + if (ret) { + pci_err(pdev, "failed to rebuild resume(%d)\n", ret); + return ret; + } + + ret = hisi_qm_start(qm); + if (ret) + pci_err(pdev, "failed to start qm(%d)\n", ret); + + return 0; +} +EXPORT_SYMBOL_GPL(hisi_qm_resume); + MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Zhou Wang <wangzhou1@hisilicon.com>"); MODULE_DESCRIPTION("HiSilicon Accelerator queue manager driver"); diff --git a/drivers/crypto/hisilicon/qm.h b/drivers/crypto/hisilicon/qm.h index 035eaf8c442d..3068093229a5 100644 --- a/drivers/crypto/hisilicon/qm.h +++ b/drivers/crypto/hisilicon/qm.h @@ -4,6 +4,7 @@ #define HISI_ACC_QM_H #include <linux/bitfield.h> +#include <linux/debugfs.h> #include <linux/iopoll.h> #include <linux/module.h> #include <linux/pci.h> @@ -430,4 +431,11 @@ void hisi_qm_dev_shutdown(struct pci_dev *pdev); void hisi_qm_wait_task_finish(struct hisi_qm *qm, struct hisi_qm_list *qm_list); int hisi_qm_alg_register(struct hisi_qm *qm, struct hisi_qm_list *qm_list); void hisi_qm_alg_unregister(struct hisi_qm *qm, struct hisi_qm_list *qm_list); +int hisi_qm_resume(struct device *dev); +int hisi_qm_suspend(struct device *dev); +void hisi_qm_pm_uninit(struct hisi_qm *qm); +void hisi_qm_pm_init(struct hisi_qm *qm); +int hisi_qm_get_dfx_access(struct hisi_qm *qm); +void hisi_qm_put_dfx_access(struct hisi_qm *qm); +void hisi_qm_regs_dump(struct seq_file *s, struct debugfs_regset32 *regset); #endif diff --git a/drivers/crypto/hisilicon/sec2/sec.h b/drivers/crypto/hisilicon/sec2/sec.h index 018415b9840a..d97cf02b1df7 100644 --- a/drivers/crypto/hisilicon/sec2/sec.h +++ b/drivers/crypto/hisilicon/sec2/sec.h @@ -157,11 +157,6 @@ struct sec_ctx { struct device *dev; }; -enum sec_endian { - SEC_LE = 0, - SEC_32BE, - SEC_64BE -}; enum sec_debug_file_index { SEC_CLEAR_ENABLE, diff --git a/drivers/crypto/hisilicon/sec2/sec_main.c b/drivers/crypto/hisilicon/sec2/sec_main.c index 490db7bccf61..90551bf38b52 100644 --- a/drivers/crypto/hisilicon/sec2/sec_main.c +++ b/drivers/crypto/hisilicon/sec2/sec_main.c @@ -11,6 +11,7 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/pci.h> +#include <linux/pm_runtime.h> #include <linux/seq_file.h> #include <linux/topology.h> #include <linux/uacce.h> @@ -57,10 +58,16 @@ #define SEC_MEM_START_INIT_REG 0x301100 #define SEC_MEM_INIT_DONE_REG 0x301104 +/* clock gating */ #define SEC_CONTROL_REG 0x301200 -#define SEC_TRNG_EN_SHIFT 8 +#define SEC_DYNAMIC_GATE_REG 0x30121c +#define SEC_CORE_AUTO_GATE 0x30212c +#define SEC_DYNAMIC_GATE_EN 0x7bff +#define SEC_CORE_AUTO_GATE_EN GENMASK(3, 0) #define SEC_CLK_GATE_ENABLE BIT(3) #define SEC_CLK_GATE_DISABLE (~BIT(3)) + +#define SEC_TRNG_EN_SHIFT 8 #define SEC_AXI_SHUTDOWN_ENABLE BIT(12) #define SEC_AXI_SHUTDOWN_DISABLE 0xFFFFEFFF @@ -312,31 +319,20 @@ static const struct pci_device_id sec_dev_ids[] = { }; MODULE_DEVICE_TABLE(pci, sec_dev_ids); -static u8 sec_get_endian(struct hisi_qm *qm) +static void sec_set_endian(struct hisi_qm *qm) { u32 reg; - /* - * As for VF, it is a wrong way to get endian setting by - * reading a register of the engine - */ - if (qm->pdev->is_virtfn) { - dev_err_ratelimited(&qm->pdev->dev, - "cannot access a register in VF!\n"); - return SEC_LE; - } reg = readl_relaxed(qm->io_base + SEC_CONTROL_REG); - /* BD little endian mode */ - if (!(reg & BIT(0))) - return SEC_LE; + reg &= ~(BIT(1) | BIT(0)); + if (!IS_ENABLED(CONFIG_64BIT)) + reg |= BIT(1); - /* BD 32-bits big endian mode */ - else if (!(reg & BIT(1))) - return SEC_32BE; - /* BD 64-bits big endian mode */ - else - return SEC_64BE; + if (!IS_ENABLED(CONFIG_CPU_LITTLE_ENDIAN)) + reg |= BIT(0); + + writel_relaxed(reg, qm->io_base + SEC_CONTROL_REG); } static void sec_open_sva_prefetch(struct hisi_qm *qm) @@ -378,15 +374,43 @@ static void sec_close_sva_prefetch(struct hisi_qm *qm) pci_err(qm->pdev, "failed to close sva prefetch\n"); } +static void sec_enable_clock_gate(struct hisi_qm *qm) +{ + u32 val; + + if (qm->ver < QM_HW_V3) + return; + + val = readl_relaxed(qm->io_base + SEC_CONTROL_REG); + val |= SEC_CLK_GATE_ENABLE; + writel_relaxed(val, qm->io_base + SEC_CONTROL_REG); + + val = readl(qm->io_base + SEC_DYNAMIC_GATE_REG); + val |= SEC_DYNAMIC_GATE_EN; + writel(val, qm->io_base + SEC_DYNAMIC_GATE_REG); + + val = readl(qm->io_base + SEC_CORE_AUTO_GATE); + val |= SEC_CORE_AUTO_GATE_EN; + writel(val, qm->io_base + SEC_CORE_AUTO_GATE); +} + +static void sec_disable_clock_gate(struct hisi_qm *qm) +{ + u32 val; + + /* Kunpeng920 needs to close clock gating */ + val = readl_relaxed(qm->io_base + SEC_CONTROL_REG); + val &= SEC_CLK_GATE_DISABLE; + writel_relaxed(val, qm->io_base + SEC_CONTROL_REG); +} + static int sec_engine_init(struct hisi_qm *qm) { int ret; u32 reg; - /* disable clock gate control */ - reg = readl_relaxed(qm->io_base + SEC_CONTROL_REG); - reg &= SEC_CLK_GATE_DISABLE; - writel_relaxed(reg, qm->io_base + SEC_CONTROL_REG); + /* disable clock gate control before mem init */ + sec_disable_clock_gate(qm); writel_relaxed(0x1, qm->io_base + SEC_MEM_START_INIT_REG); @@ -429,9 +453,9 @@ static int sec_engine_init(struct hisi_qm *qm) qm->io_base + SEC_BD_ERR_CHK_EN_REG3); /* config endian */ - reg = readl_relaxed(qm->io_base + SEC_CONTROL_REG); - reg |= sec_get_endian(qm); - writel_relaxed(reg, qm->io_base + SEC_CONTROL_REG); + sec_set_endian(qm); + + sec_enable_clock_gate(qm); return 0; } @@ -533,17 +557,14 @@ static void sec_hw_error_disable(struct hisi_qm *qm) writel(SEC_RAS_DISABLE, qm->io_base + SEC_RAS_NFE_REG); } -static u32 sec_clear_enable_read(struct sec_debug_file *file) +static u32 sec_clear_enable_read(struct hisi_qm *qm) { - struct hisi_qm *qm = file->qm; - return readl(qm->io_base + SEC_CTRL_CNT_CLR_CE) & SEC_CTRL_CNT_CLR_CE_BIT; } -static int sec_clear_enable_write(struct sec_debug_file *file, u32 val) +static int sec_clear_enable_write(struct hisi_qm *qm, u32 val) { - struct hisi_qm *qm = file->qm; u32 tmp; if (val != 1 && val) @@ -561,24 +582,34 @@ static ssize_t sec_debug_read(struct file *filp, char __user *buf, { struct sec_debug_file *file = filp->private_data; char tbuf[SEC_DBGFS_VAL_MAX_LEN]; + struct hisi_qm *qm = file->qm; u32 val; int ret; + ret = hisi_qm_get_dfx_access(qm); + if (ret) + return ret; + spin_lock_irq(&file->lock); switch (file->index) { case SEC_CLEAR_ENABLE: - val = sec_clear_enable_read(file); + val = sec_clear_enable_read(qm); break; default: - spin_unlock_irq(&file->lock); - return -EINVAL; + goto err_input; } spin_unlock_irq(&file->lock); - ret = snprintf(tbuf, SEC_DBGFS_VAL_MAX_LEN, "%u\n", val); + hisi_qm_put_dfx_access(qm); + ret = snprintf(tbuf, SEC_DBGFS_VAL_MAX_LEN, "%u\n", val); return simple_read_from_buffer(buf, count, pos, tbuf, ret); + +err_input: + spin_unlock_irq(&file->lock); + hisi_qm_put_dfx_access(qm); + return -EINVAL; } static ssize_t sec_debug_write(struct file *filp, const char __user *buf, @@ -586,6 +617,7 @@ static ssize_t sec_debug_write(struct file *filp, const char __user *buf, { struct sec_debug_file *file = filp->private_data; char tbuf[SEC_DBGFS_VAL_MAX_LEN]; + struct hisi_qm *qm = file->qm; unsigned long val; int len, ret; @@ -604,11 +636,15 @@ static ssize_t sec_debug_write(struct file *filp, const char __user *buf, if (kstrtoul(tbuf, 0, &val)) return -EFAULT; + ret = hisi_qm_get_dfx_access(qm); + if (ret) + return ret; + spin_lock_irq(&file->lock); switch (file->index) { case SEC_CLEAR_ENABLE: - ret = sec_clear_enable_write(file, val); + ret = sec_clear_enable_write(qm, val); if (ret) goto err_input; break; @@ -617,12 +653,11 @@ static ssize_t sec_debug_write(struct file *filp, const char __user *buf, goto err_input; } - spin_unlock_irq(&file->lock); - - return count; + ret = count; err_input: spin_unlock_irq(&file->lock); + hisi_qm_put_dfx_access(qm); return ret; } @@ -653,6 +688,15 @@ static int sec_debugfs_atomic64_set(void *data, u64 val) DEFINE_DEBUGFS_ATTRIBUTE(sec_atomic64_ops, sec_debugfs_atomic64_get, sec_debugfs_atomic64_set, "%lld\n"); +static int sec_regs_show(struct seq_file *s, void *unused) +{ + hisi_qm_regs_dump(s, s->private); + + return 0; +} + +DEFINE_SHOW_ATTRIBUTE(sec_regs); + static int sec_core_debug_init(struct hisi_qm *qm) { struct sec_dev *sec = container_of(qm, struct sec_dev, qm); @@ -671,9 +715,10 @@ static int sec_core_debug_init(struct hisi_qm *qm) regset->regs = sec_dfx_regs; regset->nregs = ARRAY_SIZE(sec_dfx_regs); regset->base = qm->io_base; + regset->dev = dev; if (qm->pdev->device == SEC_PF_PCI_DEVICE_ID) - debugfs_create_regset32("regs", 0444, tmp_d, regset); + debugfs_create_file("regs", 0444, tmp_d, regset, &sec_regs_fops); for (i = 0; i < ARRAY_SIZE(sec_dfx_labels); i++) { atomic64_t *data = (atomic64_t *)((uintptr_t)dfx + @@ -981,10 +1026,13 @@ static int sec_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto err_alg_unregister; } + hisi_qm_pm_init(qm); + return 0; err_alg_unregister: - hisi_qm_alg_unregister(qm, &sec_devices); + if (qm->qp_num >= ctx_q_num) + hisi_qm_alg_unregister(qm, &sec_devices); err_qm_stop: sec_debugfs_exit(qm); hisi_qm_stop(qm, QM_NORMAL); @@ -999,6 +1047,7 @@ static void sec_remove(struct pci_dev *pdev) { struct hisi_qm *qm = pci_get_drvdata(pdev); + hisi_qm_pm_uninit(qm); hisi_qm_wait_task_finish(qm, &sec_devices); if (qm->qp_num >= ctx_q_num) hisi_qm_alg_unregister(qm, &sec_devices); @@ -1018,6 +1067,10 @@ static void sec_remove(struct pci_dev *pdev) sec_qm_uninit(qm); } +static const struct dev_pm_ops sec_pm_ops = { + SET_RUNTIME_PM_OPS(hisi_qm_suspend, hisi_qm_resume, NULL) +}; + static const struct pci_error_handlers sec_err_handler = { .error_detected = hisi_qm_dev_err_detected, .slot_reset = hisi_qm_dev_slot_reset, @@ -1033,6 +1086,7 @@ static struct pci_driver sec_pci_driver = { .err_handler = &sec_err_handler, .sriov_configure = hisi_qm_sriov_configure, .shutdown = hisi_qm_dev_shutdown, + .driver.pm = &sec_pm_ops, }; static void sec_register_debugfs(void) diff --git a/drivers/crypto/hisilicon/zip/zip_main.c b/drivers/crypto/hisilicon/zip/zip_main.c index f8482ceebf2a..7148201ce76e 100644 --- a/drivers/crypto/hisilicon/zip/zip_main.c +++ b/drivers/crypto/hisilicon/zip/zip_main.c @@ -9,6 +9,7 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/pci.h> +#include <linux/pm_runtime.h> #include <linux/seq_file.h> #include <linux/topology.h> #include <linux/uacce.h> @@ -107,6 +108,14 @@ #define HZIP_DELAY_1_US 1 #define HZIP_POLL_TIMEOUT_US 1000 +/* clock gating */ +#define HZIP_PEH_CFG_AUTO_GATE 0x3011A8 +#define HZIP_PEH_CFG_AUTO_GATE_EN BIT(0) +#define HZIP_CORE_GATED_EN GENMASK(15, 8) +#define HZIP_CORE_GATED_OOO_EN BIT(29) +#define HZIP_CLOCK_GATED_EN (HZIP_CORE_GATED_EN | \ + HZIP_CORE_GATED_OOO_EN) + static const char hisi_zip_name[] = "hisi_zip"; static struct dentry *hzip_debugfs_root; @@ -312,6 +321,22 @@ static void hisi_zip_close_sva_prefetch(struct hisi_qm *qm) pci_err(qm->pdev, "failed to close sva prefetch\n"); } +static void hisi_zip_enable_clock_gate(struct hisi_qm *qm) +{ + u32 val; + + if (qm->ver < QM_HW_V3) + return; + + val = readl(qm->io_base + HZIP_CLOCK_GATE_CTRL); + val |= HZIP_CLOCK_GATED_EN; + writel(val, qm->io_base + HZIP_CLOCK_GATE_CTRL); + + val = readl(qm->io_base + HZIP_PEH_CFG_AUTO_GATE); + val |= HZIP_PEH_CFG_AUTO_GATE_EN; + writel(val, qm->io_base + HZIP_PEH_CFG_AUTO_GATE); +} + static int hisi_zip_set_user_domain_and_cache(struct hisi_qm *qm) { void __iomem *base = qm->io_base; @@ -359,6 +384,8 @@ static int hisi_zip_set_user_domain_and_cache(struct hisi_qm *qm) CQC_CACHE_WB_ENABLE | FIELD_PREP(SQC_CACHE_WB_THRD, 1) | FIELD_PREP(CQC_CACHE_WB_THRD, 1), base + QM_CACHE_CTL); + hisi_zip_enable_clock_gate(qm); + return 0; } @@ -423,17 +450,14 @@ static inline struct hisi_qm *file_to_qm(struct ctrl_debug_file *file) return &hisi_zip->qm; } -static u32 clear_enable_read(struct ctrl_debug_file *file) +static u32 clear_enable_read(struct hisi_qm *qm) { - struct hisi_qm *qm = file_to_qm(file); - return readl(qm->io_base + HZIP_SOFT_CTRL_CNT_CLR_CE) & HZIP_SOFT_CTRL_CNT_CLR_CE_BIT; } -static int clear_enable_write(struct ctrl_debug_file *file, u32 val) +static int clear_enable_write(struct hisi_qm *qm, u32 val) { - struct hisi_qm *qm = file_to_qm(file); u32 tmp; if (val != 1 && val != 0) @@ -450,22 +474,33 @@ static ssize_t hisi_zip_ctrl_debug_read(struct file *filp, char __user *buf, size_t count, loff_t *pos) { struct ctrl_debug_file *file = filp->private_data; + struct hisi_qm *qm = file_to_qm(file); char tbuf[HZIP_BUF_SIZE]; u32 val; int ret; + ret = hisi_qm_get_dfx_access(qm); + if (ret) + return ret; + spin_lock_irq(&file->lock); switch (file->index) { case HZIP_CLEAR_ENABLE: - val = clear_enable_read(file); + val = clear_enable_read(qm); break; default: - spin_unlock_irq(&file->lock); - return -EINVAL; + goto err_input; } spin_unlock_irq(&file->lock); + + hisi_qm_put_dfx_access(qm); ret = scnprintf(tbuf, sizeof(tbuf), "%u\n", val); return simple_read_from_buffer(buf, count, pos, tbuf, ret); + +err_input: + spin_unlock_irq(&file->lock); + hisi_qm_put_dfx_access(qm); + return -EINVAL; } static ssize_t hisi_zip_ctrl_debug_write(struct file *filp, @@ -473,6 +508,7 @@ static ssize_t hisi_zip_ctrl_debug_write(struct file *filp, size_t count, loff_t *pos) { struct ctrl_debug_file *file = filp->private_data; + struct hisi_qm *qm = file_to_qm(file); char tbuf[HZIP_BUF_SIZE]; unsigned long val; int len, ret; @@ -491,10 +527,14 @@ static ssize_t hisi_zip_ctrl_debug_write(struct file *filp, if (kstrtoul(tbuf, 0, &val)) return -EFAULT; + ret = hisi_qm_get_dfx_access(qm); + if (ret) + return ret; + spin_lock_irq(&file->lock); switch (file->index) { case HZIP_CLEAR_ENABLE: - ret = clear_enable_write(file, val); + ret = clear_enable_write(qm, val); if (ret) goto err_input; break; @@ -502,12 +542,12 @@ static ssize_t hisi_zip_ctrl_debug_write(struct file *filp, ret = -EINVAL; goto err_input; } - spin_unlock_irq(&file->lock); - return count; + ret = count; err_input: spin_unlock_irq(&file->lock); + hisi_qm_put_dfx_access(qm); return ret; } @@ -538,6 +578,15 @@ static int zip_debugfs_atomic64_get(void *data, u64 *val) DEFINE_DEBUGFS_ATTRIBUTE(zip_atomic64_ops, zip_debugfs_atomic64_get, zip_debugfs_atomic64_set, "%llu\n"); +static int hisi_zip_regs_show(struct seq_file *s, void *unused) +{ + hisi_qm_regs_dump(s, s->private); + + return 0; +} + +DEFINE_SHOW_ATTRIBUTE(hisi_zip_regs); + static int hisi_zip_core_debug_init(struct hisi_qm *qm) { struct device *dev = &qm->pdev->dev; @@ -560,9 +609,11 @@ static int hisi_zip_core_debug_init(struct hisi_qm *qm) regset->regs = hzip_dfx_regs; regset->nregs = ARRAY_SIZE(hzip_dfx_regs); regset->base = qm->io_base + core_offsets[i]; + regset->dev = dev; tmp_d = debugfs_create_dir(buf, qm->debug.debug_root); - debugfs_create_regset32("regs", 0444, tmp_d, regset); + debugfs_create_file("regs", 0444, tmp_d, regset, + &hisi_zip_regs_fops); } return 0; @@ -898,6 +949,8 @@ static int hisi_zip_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto err_qm_alg_unregister; } + hisi_qm_pm_init(qm); + return 0; err_qm_alg_unregister: @@ -920,6 +973,7 @@ static void hisi_zip_remove(struct pci_dev *pdev) { struct hisi_qm *qm = pci_get_drvdata(pdev); + hisi_qm_pm_uninit(qm); hisi_qm_wait_task_finish(qm, &zip_devices); hisi_qm_alg_unregister(qm, &zip_devices); @@ -932,6 +986,10 @@ static void hisi_zip_remove(struct pci_dev *pdev) hisi_zip_qm_uninit(qm); } +static const struct dev_pm_ops hisi_zip_pm_ops = { + SET_RUNTIME_PM_OPS(hisi_qm_suspend, hisi_qm_resume, NULL) +}; + static const struct pci_error_handlers hisi_zip_err_handler = { .error_detected = hisi_qm_dev_err_detected, .slot_reset = hisi_qm_dev_slot_reset, @@ -948,6 +1006,7 @@ static struct pci_driver hisi_zip_pci_driver = { hisi_qm_sriov_configure : NULL, .err_handler = &hisi_zip_err_handler, .shutdown = hisi_qm_dev_shutdown, + .driver.pm = &hisi_zip_pm_ops, }; static void hisi_zip_register_debugfs(void) diff --git a/drivers/crypto/mxs-dcp.c b/drivers/crypto/mxs-dcp.c index d6a7784d2988..d19e5ffb5104 100644 --- a/drivers/crypto/mxs-dcp.c +++ b/drivers/crypto/mxs-dcp.c @@ -170,15 +170,19 @@ static struct dcp *global_sdcp; static int mxs_dcp_start_dma(struct dcp_async_ctx *actx) { + int dma_err; struct dcp *sdcp = global_sdcp; const int chan = actx->chan; uint32_t stat; unsigned long ret; struct dcp_dma_desc *desc = &sdcp->coh->desc[actx->chan]; - dma_addr_t desc_phys = dma_map_single(sdcp->dev, desc, sizeof(*desc), DMA_TO_DEVICE); + dma_err = dma_mapping_error(sdcp->dev, desc_phys); + if (dma_err) + return dma_err; + reinit_completion(&sdcp->completion[chan]); /* Clear status register. */ @@ -216,18 +220,29 @@ static int mxs_dcp_start_dma(struct dcp_async_ctx *actx) static int mxs_dcp_run_aes(struct dcp_async_ctx *actx, struct skcipher_request *req, int init) { + dma_addr_t key_phys, src_phys, dst_phys; struct dcp *sdcp = global_sdcp; struct dcp_dma_desc *desc = &sdcp->coh->desc[actx->chan]; struct dcp_aes_req_ctx *rctx = skcipher_request_ctx(req); int ret; - dma_addr_t key_phys = dma_map_single(sdcp->dev, sdcp->coh->aes_key, - 2 * AES_KEYSIZE_128, - DMA_TO_DEVICE); - dma_addr_t src_phys = dma_map_single(sdcp->dev, sdcp->coh->aes_in_buf, - DCP_BUF_SZ, DMA_TO_DEVICE); - dma_addr_t dst_phys = dma_map_single(sdcp->dev, sdcp->coh->aes_out_buf, - DCP_BUF_SZ, DMA_FROM_DEVICE); + key_phys = dma_map_single(sdcp->dev, sdcp->coh->aes_key, + 2 * AES_KEYSIZE_128, DMA_TO_DEVICE); + ret = dma_mapping_error(sdcp->dev, key_phys); + if (ret) + return ret; + + src_phys = dma_map_single(sdcp->dev, sdcp->coh->aes_in_buf, + DCP_BUF_SZ, DMA_TO_DEVICE); + ret = dma_mapping_error(sdcp->dev, src_phys); + if (ret) + goto err_src; + + dst_phys = dma_map_single(sdcp->dev, sdcp->coh->aes_out_buf, + DCP_BUF_SZ, DMA_FROM_DEVICE); + ret = dma_mapping_error(sdcp->dev, dst_phys); + if (ret) + goto err_dst; if (actx->fill % AES_BLOCK_SIZE) { dev_err(sdcp->dev, "Invalid block size!\n"); @@ -265,10 +280,12 @@ static int mxs_dcp_run_aes(struct dcp_async_ctx *actx, ret = mxs_dcp_start_dma(actx); aes_done_run: + dma_unmap_single(sdcp->dev, dst_phys, DCP_BUF_SZ, DMA_FROM_DEVICE); +err_dst: + dma_unmap_single(sdcp->dev, src_phys, DCP_BUF_SZ, DMA_TO_DEVICE); +err_src: dma_unmap_single(sdcp->dev, key_phys, 2 * AES_KEYSIZE_128, DMA_TO_DEVICE); - dma_unmap_single(sdcp->dev, src_phys, DCP_BUF_SZ, DMA_TO_DEVICE); - dma_unmap_single(sdcp->dev, dst_phys, DCP_BUF_SZ, DMA_FROM_DEVICE); return ret; } @@ -283,21 +300,20 @@ static int mxs_dcp_aes_block_crypt(struct crypto_async_request *arq) struct scatterlist *dst = req->dst; struct scatterlist *src = req->src; - const int nents = sg_nents(req->src); + int dst_nents = sg_nents(dst); const int out_off = DCP_BUF_SZ; uint8_t *in_buf = sdcp->coh->aes_in_buf; uint8_t *out_buf = sdcp->coh->aes_out_buf; - uint8_t *out_tmp, *src_buf, *dst_buf = NULL; uint32_t dst_off = 0; + uint8_t *src_buf = NULL; uint32_t last_out_len = 0; uint8_t *key = sdcp->coh->aes_key; int ret = 0; - int split = 0; - unsigned int i, len, clen, rem = 0, tlen = 0; + unsigned int i, len, clen, tlen = 0; int init = 0; bool limit_hit = false; @@ -315,7 +331,7 @@ static int mxs_dcp_aes_block_crypt(struct crypto_async_request *arq) memset(key + AES_KEYSIZE_128, 0, AES_KEYSIZE_128); } - for_each_sg(req->src, src, nents, i) { + for_each_sg(req->src, src, sg_nents(src), i) { src_buf = sg_virt(src); len = sg_dma_len(src); tlen += len; @@ -340,34 +356,17 @@ static int mxs_dcp_aes_block_crypt(struct crypto_async_request *arq) * submit the buffer. */ if (actx->fill == out_off || sg_is_last(src) || - limit_hit) { + limit_hit) { ret = mxs_dcp_run_aes(actx, req, init); if (ret) return ret; init = 0; - out_tmp = out_buf; + sg_pcopy_from_buffer(dst, dst_nents, out_buf, + actx->fill, dst_off); + dst_off += actx->fill; last_out_len = actx->fill; - while (dst && actx->fill) { - if (!split) { - dst_buf = sg_virt(dst); - dst_off = 0; - } - rem = min(sg_dma_len(dst) - dst_off, - actx->fill); - - memcpy(dst_buf + dst_off, out_tmp, rem); - out_tmp += rem; - dst_off += rem; - actx->fill -= rem; - - if (dst_off == sg_dma_len(dst)) { - dst = sg_next(dst); - split = 0; - } else { - split = 1; - } - } + actx->fill = 0; } } while (len); @@ -557,6 +556,10 @@ static int mxs_dcp_run_sha(struct ahash_request *req) dma_addr_t buf_phys = dma_map_single(sdcp->dev, sdcp->coh->sha_in_buf, DCP_BUF_SZ, DMA_TO_DEVICE); + ret = dma_mapping_error(sdcp->dev, buf_phys); + if (ret) + return ret; + /* Fill in the DMA descriptor. */ desc->control0 = MXS_DCP_CONTROL0_DECR_SEMAPHORE | MXS_DCP_CONTROL0_INTERRUPT | @@ -589,6 +592,10 @@ static int mxs_dcp_run_sha(struct ahash_request *req) if (rctx->fini) { digest_phys = dma_map_single(sdcp->dev, sdcp->coh->sha_out_buf, DCP_SHA_PAY_SZ, DMA_FROM_DEVICE); + ret = dma_mapping_error(sdcp->dev, digest_phys); + if (ret) + goto done_run; + desc->control0 |= MXS_DCP_CONTROL0_HASH_TERM; desc->payload = digest_phys; } diff --git a/drivers/crypto/omap-aes.c b/drivers/crypto/omap-aes.c index 0dd4c6b157de..9b968ac4ee7b 100644 --- a/drivers/crypto/omap-aes.c +++ b/drivers/crypto/omap-aes.c @@ -1175,9 +1175,9 @@ static int omap_aes_probe(struct platform_device *pdev) spin_lock_init(&dd->lock); INIT_LIST_HEAD(&dd->list); - spin_lock(&list_lock); + spin_lock_bh(&list_lock); list_add_tail(&dd->list, &dev_list); - spin_unlock(&list_lock); + spin_unlock_bh(&list_lock); /* Initialize crypto engine */ dd->engine = crypto_engine_alloc_init(dev, 1); @@ -1264,9 +1264,9 @@ static int omap_aes_remove(struct platform_device *pdev) if (!dd) return -ENODEV; - spin_lock(&list_lock); + spin_lock_bh(&list_lock); list_del(&dd->list); - spin_unlock(&list_lock); + spin_unlock_bh(&list_lock); for (i = dd->pdata->algs_info_size - 1; i >= 0; i--) for (j = dd->pdata->algs_info[i].registered - 1; j >= 0; j--) { diff --git a/drivers/crypto/omap-crypto.c b/drivers/crypto/omap-crypto.c index 31bdb1d76d11..a4cc6bf146ec 100644 --- a/drivers/crypto/omap-crypto.c +++ b/drivers/crypto/omap-crypto.c @@ -210,7 +210,7 @@ void omap_crypto_cleanup(struct scatterlist *sg, struct scatterlist *orig, buf = sg_virt(sg); pages = get_order(len); - if (orig && (flags & OMAP_CRYPTO_COPY_MASK)) + if (orig && (flags & OMAP_CRYPTO_DATA_COPIED)) omap_crypto_copy_data(sg, orig, offset, len); if (flags & OMAP_CRYPTO_DATA_COPIED) diff --git a/drivers/crypto/omap-des.c b/drivers/crypto/omap-des.c index bc8631363d72..be77656864e3 100644 --- a/drivers/crypto/omap-des.c +++ b/drivers/crypto/omap-des.c @@ -1033,9 +1033,9 @@ static int omap_des_probe(struct platform_device *pdev) INIT_LIST_HEAD(&dd->list); - spin_lock(&list_lock); + spin_lock_bh(&list_lock); list_add_tail(&dd->list, &dev_list); - spin_unlock(&list_lock); + spin_unlock_bh(&list_lock); /* Initialize des crypto engine */ dd->engine = crypto_engine_alloc_init(dev, 1); @@ -1094,9 +1094,9 @@ static int omap_des_remove(struct platform_device *pdev) if (!dd) return -ENODEV; - spin_lock(&list_lock); + spin_lock_bh(&list_lock); list_del(&dd->list); - spin_unlock(&list_lock); + spin_unlock_bh(&list_lock); for (i = dd->pdata->algs_info_size - 1; i >= 0; i--) for (j = dd->pdata->algs_info[i].registered - 1; j >= 0; j--) diff --git a/drivers/crypto/omap-sham.c b/drivers/crypto/omap-sham.c index dd53ad9987b0..f6bf53c00b61 100644 --- a/drivers/crypto/omap-sham.c +++ b/drivers/crypto/omap-sham.c @@ -105,7 +105,6 @@ #define FLAGS_FINAL 1 #define FLAGS_DMA_ACTIVE 2 #define FLAGS_OUTPUT_READY 3 -#define FLAGS_INIT 4 #define FLAGS_CPU 5 #define FLAGS_DMA_READY 6 #define FLAGS_AUTO_XOR 7 @@ -368,24 +367,6 @@ static void omap_sham_copy_ready_hash(struct ahash_request *req) hash[i] = le32_to_cpup((__le32 *)in + i); } -static int omap_sham_hw_init(struct omap_sham_dev *dd) -{ - int err; - - err = pm_runtime_resume_and_get(dd->dev); - if (err < 0) { - dev_err(dd->dev, "failed to get sync: %d\n", err); - return err; - } - - if (!test_bit(FLAGS_INIT, &dd->flags)) { - set_bit(FLAGS_INIT, &dd->flags); - dd->err = 0; - } - - return 0; -} - static void omap_sham_write_ctrl_omap2(struct omap_sham_dev *dd, size_t length, int final, int dma) { @@ -1093,11 +1074,14 @@ static int omap_sham_hash_one_req(struct crypto_engine *engine, void *areq) dev_dbg(dd->dev, "hash-one: op: %u, total: %u, digcnt: %zd, final: %d", ctx->op, ctx->total, ctx->digcnt, final); - dd->req = req; - - err = omap_sham_hw_init(dd); - if (err) + err = pm_runtime_resume_and_get(dd->dev); + if (err < 0) { + dev_err(dd->dev, "failed to get sync: %d\n", err); return err; + } + + dd->err = 0; + dd->req = req; if (ctx->digcnt) dd->pdata->copy_hash(req, 0); @@ -1736,7 +1720,7 @@ static void omap_sham_done_task(unsigned long data) if (test_and_clear_bit(FLAGS_OUTPUT_READY, &dd->flags)) goto finish; } else if (test_bit(FLAGS_DMA_READY, &dd->flags)) { - if (test_and_clear_bit(FLAGS_DMA_ACTIVE, &dd->flags)) { + if (test_bit(FLAGS_DMA_ACTIVE, &dd->flags)) { omap_sham_update_dma_stop(dd); if (dd->err) { err = dd->err; @@ -2129,7 +2113,6 @@ static int omap_sham_probe(struct platform_device *pdev) dd->fallback_sz = OMAP_SHA_DMA_THRESHOLD; pm_runtime_enable(dev); - pm_runtime_irq_safe(dev); err = pm_runtime_get_sync(dev); if (err < 0) { @@ -2144,9 +2127,9 @@ static int omap_sham_probe(struct platform_device *pdev) (rev & dd->pdata->major_mask) >> dd->pdata->major_shift, (rev & dd->pdata->minor_mask) >> dd->pdata->minor_shift); - spin_lock(&sham.lock); + spin_lock_bh(&sham.lock); list_add_tail(&dd->list, &sham.dev_list); - spin_unlock(&sham.lock); + spin_unlock_bh(&sham.lock); dd->engine = crypto_engine_alloc_init(dev, 1); if (!dd->engine) { @@ -2194,10 +2177,11 @@ err_algs: err_engine_start: crypto_engine_exit(dd->engine); err_engine: - spin_lock(&sham.lock); + spin_lock_bh(&sham.lock); list_del(&dd->list); - spin_unlock(&sham.lock); + spin_unlock_bh(&sham.lock); err_pm: + pm_runtime_dont_use_autosuspend(dev); pm_runtime_disable(dev); if (!dd->polling_mode) dma_release_channel(dd->dma_lch); @@ -2215,9 +2199,9 @@ static int omap_sham_remove(struct platform_device *pdev) dd = platform_get_drvdata(pdev); if (!dd) return -ENODEV; - spin_lock(&sham.lock); + spin_lock_bh(&sham.lock); list_del(&dd->list); - spin_unlock(&sham.lock); + spin_unlock_bh(&sham.lock); for (i = dd->pdata->algs_info_size - 1; i >= 0; i--) for (j = dd->pdata->algs_info[i].registered - 1; j >= 0; j--) { crypto_unregister_ahash( @@ -2225,6 +2209,7 @@ static int omap_sham_remove(struct platform_device *pdev) dd->pdata->algs_info[i].registered--; } tasklet_kill(&dd->done_task); + pm_runtime_dont_use_autosuspend(&pdev->dev); pm_runtime_disable(&pdev->dev); if (!dd->polling_mode) @@ -2235,32 +2220,11 @@ static int omap_sham_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM_SLEEP -static int omap_sham_suspend(struct device *dev) -{ - pm_runtime_put_sync(dev); - return 0; -} - -static int omap_sham_resume(struct device *dev) -{ - int err = pm_runtime_resume_and_get(dev); - if (err < 0) { - dev_err(dev, "failed to get sync: %d\n", err); - return err; - } - return 0; -} -#endif - -static SIMPLE_DEV_PM_OPS(omap_sham_pm_ops, omap_sham_suspend, omap_sham_resume); - static struct platform_driver omap_sham_driver = { .probe = omap_sham_probe, .remove = omap_sham_remove, .driver = { .name = "omap-sham", - .pm = &omap_sham_pm_ops, .of_match_table = omap_sham_of_match, }, }; diff --git a/drivers/crypto/qat/qat_4xxx/adf_4xxx_hw_data.c b/drivers/crypto/qat/qat_4xxx/adf_4xxx_hw_data.c index 3524ddd48930..33d8e50dcbda 100644 --- a/drivers/crypto/qat/qat_4xxx/adf_4xxx_hw_data.c +++ b/drivers/crypto/qat/qat_4xxx/adf_4xxx_hw_data.c @@ -161,7 +161,7 @@ static void adf_enable_ints(struct adf_accel_dev *accel_dev) ADF_CSR_WR(addr, ADF_4XXX_SMIAPF_MASK_OFFSET, 0); } -static int adf_pf_enable_vf2pf_comms(struct adf_accel_dev *accel_dev) +static int adf_enable_pf2vf_comms(struct adf_accel_dev *accel_dev) { return 0; } @@ -210,21 +210,21 @@ void adf_init_hw_data_4xxx(struct adf_hw_device_data *hw_data) hw_data->fw_mmp_name = ADF_4XXX_MMP; hw_data->init_admin_comms = adf_init_admin_comms; hw_data->exit_admin_comms = adf_exit_admin_comms; - hw_data->disable_iov = adf_disable_sriov; hw_data->send_admin_init = adf_send_admin_init; hw_data->init_arb = adf_init_arb; hw_data->exit_arb = adf_exit_arb; hw_data->get_arb_mapping = adf_get_arbiter_mapping; hw_data->enable_ints = adf_enable_ints; - hw_data->enable_vf2pf_comms = adf_pf_enable_vf2pf_comms; hw_data->reset_device = adf_reset_flr; - hw_data->min_iov_compat_ver = ADF_PFVF_COMPATIBILITY_VERSION; hw_data->admin_ae_mask = ADF_4XXX_ADMIN_AE_MASK; hw_data->uof_get_num_objs = uof_get_num_objs; hw_data->uof_get_name = uof_get_name; hw_data->uof_get_ae_mask = uof_get_ae_mask; hw_data->set_msix_rttable = set_msix_default_rttable; hw_data->set_ssm_wdtimer = adf_gen4_set_ssm_wdtimer; + hw_data->enable_pfvf_comms = adf_enable_pf2vf_comms; + hw_data->disable_iov = adf_disable_sriov; + hw_data->min_iov_compat_ver = ADF_PFVF_COMPAT_THIS_VERSION; adf_gen4_init_hw_csr_ops(&hw_data->csr_ops); } diff --git a/drivers/crypto/qat/qat_4xxx/adf_drv.c b/drivers/crypto/qat/qat_4xxx/adf_drv.c index a8805c815d16..359fb7989dfb 100644 --- a/drivers/crypto/qat/qat_4xxx/adf_drv.c +++ b/drivers/crypto/qat/qat_4xxx/adf_drv.c @@ -221,16 +221,10 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) } /* Set DMA identifier */ - if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) { - if ((pci_set_dma_mask(pdev, DMA_BIT_MASK(32)))) { - dev_err(&pdev->dev, "No usable DMA configuration.\n"); - ret = -EFAULT; - goto out_err; - } else { - pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); - } - } else { - pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)); + ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); + if (ret) { + dev_err(&pdev->dev, "No usable DMA configuration.\n"); + goto out_err; } /* Get accelerator capabilities mask */ diff --git a/drivers/crypto/qat/qat_c3xxx/adf_c3xxx_hw_data.c b/drivers/crypto/qat/qat_c3xxx/adf_c3xxx_hw_data.c index 1dd64af22bea..3027c01bc89e 100644 --- a/drivers/crypto/qat/qat_c3xxx/adf_c3xxx_hw_data.c +++ b/drivers/crypto/qat/qat_c3xxx/adf_c3xxx_hw_data.c @@ -111,11 +111,6 @@ static u32 get_pf2vf_offset(u32 i) return ADF_C3XXX_PF2VF_OFFSET(i); } -static u32 get_vintmsk_offset(u32 i) -{ - return ADF_C3XXX_VINTMSK_OFFSET(i); -} - static void adf_enable_error_correction(struct adf_accel_dev *accel_dev) { struct adf_hw_device_data *hw_device = accel_dev->hw_device; @@ -159,8 +154,10 @@ static void adf_enable_ints(struct adf_accel_dev *accel_dev) ADF_C3XXX_SMIA1_MASK); } -static int adf_pf_enable_vf2pf_comms(struct adf_accel_dev *accel_dev) +static int adf_enable_pf2vf_comms(struct adf_accel_dev *accel_dev) { + spin_lock_init(&accel_dev->pf.vf2pf_ints_lock); + return 0; } @@ -193,8 +190,6 @@ void adf_init_hw_data_c3xxx(struct adf_hw_device_data *hw_data) hw_data->get_sram_bar_id = get_sram_bar_id; hw_data->get_etr_bar_id = get_etr_bar_id; hw_data->get_misc_bar_id = get_misc_bar_id; - hw_data->get_pf2vf_offset = get_pf2vf_offset; - hw_data->get_vintmsk_offset = get_vintmsk_offset; hw_data->get_admin_info = adf_gen2_get_admin_info; hw_data->get_arb_info = adf_gen2_get_arb_info; hw_data->get_sku = get_sku; @@ -203,16 +198,18 @@ void adf_init_hw_data_c3xxx(struct adf_hw_device_data *hw_data) hw_data->init_admin_comms = adf_init_admin_comms; hw_data->exit_admin_comms = adf_exit_admin_comms; hw_data->configure_iov_threads = configure_iov_threads; - hw_data->disable_iov = adf_disable_sriov; hw_data->send_admin_init = adf_send_admin_init; hw_data->init_arb = adf_init_arb; hw_data->exit_arb = adf_exit_arb; hw_data->get_arb_mapping = adf_get_arbiter_mapping; hw_data->enable_ints = adf_enable_ints; - hw_data->enable_vf2pf_comms = adf_pf_enable_vf2pf_comms; hw_data->reset_device = adf_reset_flr; - hw_data->min_iov_compat_ver = ADF_PFVF_COMPATIBILITY_VERSION; hw_data->set_ssm_wdtimer = adf_gen2_set_ssm_wdtimer; + hw_data->get_pf2vf_offset = get_pf2vf_offset; + hw_data->enable_pfvf_comms = adf_enable_pf2vf_comms; + hw_data->disable_iov = adf_disable_sriov; + hw_data->min_iov_compat_ver = ADF_PFVF_COMPAT_THIS_VERSION; + adf_gen2_init_hw_csr_ops(&hw_data->csr_ops); } diff --git a/drivers/crypto/qat/qat_c3xxx/adf_c3xxx_hw_data.h b/drivers/crypto/qat/qat_c3xxx/adf_c3xxx_hw_data.h index fece8e38025a..86ee02a86789 100644 --- a/drivers/crypto/qat/qat_c3xxx/adf_c3xxx_hw_data.h +++ b/drivers/crypto/qat/qat_c3xxx/adf_c3xxx_hw_data.h @@ -29,7 +29,6 @@ #define ADF_C3XXX_ERRSSMSH_EN BIT(3) #define ADF_C3XXX_PF2VF_OFFSET(i) (0x3A000 + 0x280 + ((i) * 0x04)) -#define ADF_C3XXX_VINTMSK_OFFSET(i) (0x3A000 + 0x200 + ((i) * 0x04)) /* AE to function mapping */ #define ADF_C3XXX_AE2FUNC_MAP_GRP_A_NUM_REGS 48 diff --git a/drivers/crypto/qat/qat_c3xxx/adf_drv.c b/drivers/crypto/qat/qat_c3xxx/adf_drv.c index 7fb3343ae8b0..cc6e75dc60de 100644 --- a/drivers/crypto/qat/qat_c3xxx/adf_drv.c +++ b/drivers/crypto/qat/qat_c3xxx/adf_drv.c @@ -159,17 +159,10 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) } /* set dma identifier */ - if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) { - if ((pci_set_dma_mask(pdev, DMA_BIT_MASK(32)))) { - dev_err(&pdev->dev, "No usable DMA configuration\n"); - ret = -EFAULT; - goto out_err_disable; - } else { - pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); - } - - } else { - pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)); + ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(48)); + if (ret) { + dev_err(&pdev->dev, "No usable DMA configuration\n"); + goto out_err_disable; } if (pci_request_regions(pdev, ADF_C3XXX_DEVICE_NAME)) { @@ -208,12 +201,12 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (pci_save_state(pdev)) { dev_err(&pdev->dev, "Failed to save pci state\n"); ret = -ENOMEM; - goto out_err_free_reg; + goto out_err_disable_aer; } ret = qat_crypto_dev_config(accel_dev); if (ret) - goto out_err_free_reg; + goto out_err_disable_aer; ret = adf_dev_init(accel_dev); if (ret) @@ -229,6 +222,8 @@ out_err_dev_stop: adf_dev_stop(accel_dev); out_err_dev_shutdown: adf_dev_shutdown(accel_dev); +out_err_disable_aer: + adf_disable_aer(accel_dev); out_err_free_reg: pci_release_regions(accel_pci_dev->pci_dev); out_err_disable: diff --git a/drivers/crypto/qat/qat_c3xxxvf/adf_c3xxxvf_hw_data.c b/drivers/crypto/qat/qat_c3xxxvf/adf_c3xxxvf_hw_data.c index 15f6b9bdfb22..3e69b520e82f 100644 --- a/drivers/crypto/qat/qat_c3xxxvf/adf_c3xxxvf_hw_data.c +++ b/drivers/crypto/qat/qat_c3xxxvf/adf_c3xxxvf_hw_data.c @@ -52,11 +52,6 @@ static u32 get_pf2vf_offset(u32 i) return ADF_C3XXXIOV_PF2VF_OFFSET; } -static u32 get_vintmsk_offset(u32 i) -{ - return ADF_C3XXXIOV_VINTMSK_OFFSET; -} - static int adf_vf_int_noop(struct adf_accel_dev *accel_dev) { return 0; @@ -81,10 +76,10 @@ void adf_init_hw_data_c3xxxiov(struct adf_hw_device_data *hw_data) hw_data->enable_error_correction = adf_vf_void_noop; hw_data->init_admin_comms = adf_vf_int_noop; hw_data->exit_admin_comms = adf_vf_void_noop; - hw_data->send_admin_init = adf_vf2pf_init; + hw_data->send_admin_init = adf_vf2pf_notify_init; hw_data->init_arb = adf_vf_int_noop; hw_data->exit_arb = adf_vf_void_noop; - hw_data->disable_iov = adf_vf2pf_shutdown; + hw_data->disable_iov = adf_vf2pf_notify_shutdown; hw_data->get_accel_mask = get_accel_mask; hw_data->get_ae_mask = get_ae_mask; hw_data->get_num_accels = get_num_accels; @@ -92,11 +87,10 @@ void adf_init_hw_data_c3xxxiov(struct adf_hw_device_data *hw_data) hw_data->get_etr_bar_id = get_etr_bar_id; hw_data->get_misc_bar_id = get_misc_bar_id; hw_data->get_pf2vf_offset = get_pf2vf_offset; - hw_data->get_vintmsk_offset = get_vintmsk_offset; hw_data->get_sku = get_sku; hw_data->enable_ints = adf_vf_void_noop; - hw_data->enable_vf2pf_comms = adf_enable_vf2pf_comms; - hw_data->min_iov_compat_ver = ADF_PFVF_COMPATIBILITY_VERSION; + hw_data->enable_pfvf_comms = adf_enable_vf2pf_comms; + hw_data->min_iov_compat_ver = ADF_PFVF_COMPAT_THIS_VERSION; hw_data->dev_class->instances++; adf_devmgr_update_class_index(hw_data); adf_gen2_init_hw_csr_ops(&hw_data->csr_ops); diff --git a/drivers/crypto/qat/qat_c3xxxvf/adf_c3xxxvf_hw_data.h b/drivers/crypto/qat/qat_c3xxxvf/adf_c3xxxvf_hw_data.h index 7945a9cd1c60..f5de4ce66014 100644 --- a/drivers/crypto/qat/qat_c3xxxvf/adf_c3xxxvf_hw_data.h +++ b/drivers/crypto/qat/qat_c3xxxvf/adf_c3xxxvf_hw_data.h @@ -13,7 +13,6 @@ #define ADF_C3XXXIOV_ETR_BAR 0 #define ADF_C3XXXIOV_ETR_MAX_BANKS 1 #define ADF_C3XXXIOV_PF2VF_OFFSET 0x200 -#define ADF_C3XXXIOV_VINTMSK_OFFSET 0x208 void adf_init_hw_data_c3xxxiov(struct adf_hw_device_data *hw_data); void adf_clean_hw_data_c3xxxiov(struct adf_hw_device_data *hw_data); diff --git a/drivers/crypto/qat/qat_c3xxxvf/adf_drv.c b/drivers/crypto/qat/qat_c3xxxvf/adf_drv.c index 067ca5e17d38..1df1b868978d 100644 --- a/drivers/crypto/qat/qat_c3xxxvf/adf_drv.c +++ b/drivers/crypto/qat/qat_c3xxxvf/adf_drv.c @@ -141,17 +141,10 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) } /* set dma identifier */ - if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) { - if ((pci_set_dma_mask(pdev, DMA_BIT_MASK(32)))) { - dev_err(&pdev->dev, "No usable DMA configuration\n"); - ret = -EFAULT; - goto out_err_disable; - } else { - pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); - } - - } else { - pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)); + ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(48)); + if (ret) { + dev_err(&pdev->dev, "No usable DMA configuration\n"); + goto out_err_disable; } if (pci_request_regions(pdev, ADF_C3XXXVF_DEVICE_NAME)) { @@ -218,6 +211,7 @@ static void adf_remove(struct pci_dev *pdev) pr_err("QAT: Driver removal failed\n"); return; } + adf_flush_vf_wq(accel_dev); adf_dev_stop(accel_dev); adf_dev_shutdown(accel_dev); adf_cleanup_accel(accel_dev); diff --git a/drivers/crypto/qat/qat_c62x/adf_c62x_hw_data.c b/drivers/crypto/qat/qat_c62x/adf_c62x_hw_data.c index 30337390513c..b023c80873bb 100644 --- a/drivers/crypto/qat/qat_c62x/adf_c62x_hw_data.c +++ b/drivers/crypto/qat/qat_c62x/adf_c62x_hw_data.c @@ -113,11 +113,6 @@ static u32 get_pf2vf_offset(u32 i) return ADF_C62X_PF2VF_OFFSET(i); } -static u32 get_vintmsk_offset(u32 i) -{ - return ADF_C62X_VINTMSK_OFFSET(i); -} - static void adf_enable_error_correction(struct adf_accel_dev *accel_dev) { struct adf_hw_device_data *hw_device = accel_dev->hw_device; @@ -161,8 +156,10 @@ static void adf_enable_ints(struct adf_accel_dev *accel_dev) ADF_C62X_SMIA1_MASK); } -static int adf_pf_enable_vf2pf_comms(struct adf_accel_dev *accel_dev) +static int adf_enable_pf2vf_comms(struct adf_accel_dev *accel_dev) { + spin_lock_init(&accel_dev->pf.vf2pf_ints_lock); + return 0; } @@ -195,8 +192,6 @@ void adf_init_hw_data_c62x(struct adf_hw_device_data *hw_data) hw_data->get_sram_bar_id = get_sram_bar_id; hw_data->get_etr_bar_id = get_etr_bar_id; hw_data->get_misc_bar_id = get_misc_bar_id; - hw_data->get_pf2vf_offset = get_pf2vf_offset; - hw_data->get_vintmsk_offset = get_vintmsk_offset; hw_data->get_admin_info = adf_gen2_get_admin_info; hw_data->get_arb_info = adf_gen2_get_arb_info; hw_data->get_sku = get_sku; @@ -205,16 +200,18 @@ void adf_init_hw_data_c62x(struct adf_hw_device_data *hw_data) hw_data->init_admin_comms = adf_init_admin_comms; hw_data->exit_admin_comms = adf_exit_admin_comms; hw_data->configure_iov_threads = configure_iov_threads; - hw_data->disable_iov = adf_disable_sriov; hw_data->send_admin_init = adf_send_admin_init; hw_data->init_arb = adf_init_arb; hw_data->exit_arb = adf_exit_arb; hw_data->get_arb_mapping = adf_get_arbiter_mapping; hw_data->enable_ints = adf_enable_ints; - hw_data->enable_vf2pf_comms = adf_pf_enable_vf2pf_comms; hw_data->reset_device = adf_reset_flr; - hw_data->min_iov_compat_ver = ADF_PFVF_COMPATIBILITY_VERSION; hw_data->set_ssm_wdtimer = adf_gen2_set_ssm_wdtimer; + hw_data->get_pf2vf_offset = get_pf2vf_offset; + hw_data->enable_pfvf_comms = adf_enable_pf2vf_comms; + hw_data->disable_iov = adf_disable_sriov; + hw_data->min_iov_compat_ver = ADF_PFVF_COMPAT_THIS_VERSION; + adf_gen2_init_hw_csr_ops(&hw_data->csr_ops); } diff --git a/drivers/crypto/qat/qat_c62x/adf_c62x_hw_data.h b/drivers/crypto/qat/qat_c62x/adf_c62x_hw_data.h index 53d3cb577f5b..e6664bd20c91 100644 --- a/drivers/crypto/qat/qat_c62x/adf_c62x_hw_data.h +++ b/drivers/crypto/qat/qat_c62x/adf_c62x_hw_data.h @@ -30,7 +30,6 @@ #define ADF_C62X_ERRSSMSH_EN BIT(3) #define ADF_C62X_PF2VF_OFFSET(i) (0x3A000 + 0x280 + ((i) * 0x04)) -#define ADF_C62X_VINTMSK_OFFSET(i) (0x3A000 + 0x200 + ((i) * 0x04)) /* AE to function mapping */ #define ADF_C62X_AE2FUNC_MAP_GRP_A_NUM_REGS 80 diff --git a/drivers/crypto/qat/qat_c62x/adf_drv.c b/drivers/crypto/qat/qat_c62x/adf_drv.c index 1f5de442e1e6..bf251dfe74b3 100644 --- a/drivers/crypto/qat/qat_c62x/adf_drv.c +++ b/drivers/crypto/qat/qat_c62x/adf_drv.c @@ -159,17 +159,10 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) } /* set dma identifier */ - if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) { - if ((pci_set_dma_mask(pdev, DMA_BIT_MASK(32)))) { - dev_err(&pdev->dev, "No usable DMA configuration\n"); - ret = -EFAULT; - goto out_err_disable; - } else { - pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); - } - - } else { - pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)); + ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(48)); + if (ret) { + dev_err(&pdev->dev, "No usable DMA configuration\n"); + goto out_err_disable; } if (pci_request_regions(pdev, ADF_C62X_DEVICE_NAME)) { @@ -208,12 +201,12 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (pci_save_state(pdev)) { dev_err(&pdev->dev, "Failed to save pci state\n"); ret = -ENOMEM; - goto out_err_free_reg; + goto out_err_disable_aer; } ret = qat_crypto_dev_config(accel_dev); if (ret) - goto out_err_free_reg; + goto out_err_disable_aer; ret = adf_dev_init(accel_dev); if (ret) @@ -229,6 +222,8 @@ out_err_dev_stop: adf_dev_stop(accel_dev); out_err_dev_shutdown: adf_dev_shutdown(accel_dev); +out_err_disable_aer: + adf_disable_aer(accel_dev); out_err_free_reg: pci_release_regions(accel_pci_dev->pci_dev); out_err_disable: diff --git a/drivers/crypto/qat/qat_c62xvf/adf_c62xvf_hw_data.c b/drivers/crypto/qat/qat_c62xvf/adf_c62xvf_hw_data.c index d231583428c9..3bee3e467363 100644 --- a/drivers/crypto/qat/qat_c62xvf/adf_c62xvf_hw_data.c +++ b/drivers/crypto/qat/qat_c62xvf/adf_c62xvf_hw_data.c @@ -52,11 +52,6 @@ static u32 get_pf2vf_offset(u32 i) return ADF_C62XIOV_PF2VF_OFFSET; } -static u32 get_vintmsk_offset(u32 i) -{ - return ADF_C62XIOV_VINTMSK_OFFSET; -} - static int adf_vf_int_noop(struct adf_accel_dev *accel_dev) { return 0; @@ -81,10 +76,10 @@ void adf_init_hw_data_c62xiov(struct adf_hw_device_data *hw_data) hw_data->enable_error_correction = adf_vf_void_noop; hw_data->init_admin_comms = adf_vf_int_noop; hw_data->exit_admin_comms = adf_vf_void_noop; - hw_data->send_admin_init = adf_vf2pf_init; + hw_data->send_admin_init = adf_vf2pf_notify_init; hw_data->init_arb = adf_vf_int_noop; hw_data->exit_arb = adf_vf_void_noop; - hw_data->disable_iov = adf_vf2pf_shutdown; + hw_data->disable_iov = adf_vf2pf_notify_shutdown; hw_data->get_accel_mask = get_accel_mask; hw_data->get_ae_mask = get_ae_mask; hw_data->get_num_accels = get_num_accels; @@ -92,11 +87,10 @@ void adf_init_hw_data_c62xiov(struct adf_hw_device_data *hw_data) hw_data->get_etr_bar_id = get_etr_bar_id; hw_data->get_misc_bar_id = get_misc_bar_id; hw_data->get_pf2vf_offset = get_pf2vf_offset; - hw_data->get_vintmsk_offset = get_vintmsk_offset; hw_data->get_sku = get_sku; hw_data->enable_ints = adf_vf_void_noop; - hw_data->enable_vf2pf_comms = adf_enable_vf2pf_comms; - hw_data->min_iov_compat_ver = ADF_PFVF_COMPATIBILITY_VERSION; + hw_data->enable_pfvf_comms = adf_enable_vf2pf_comms; + hw_data->min_iov_compat_ver = ADF_PFVF_COMPAT_THIS_VERSION; hw_data->dev_class->instances++; adf_devmgr_update_class_index(hw_data); adf_gen2_init_hw_csr_ops(&hw_data->csr_ops); diff --git a/drivers/crypto/qat/qat_c62xvf/adf_c62xvf_hw_data.h b/drivers/crypto/qat/qat_c62xvf/adf_c62xvf_hw_data.h index a6c04cf7a43c..794778c48678 100644 --- a/drivers/crypto/qat/qat_c62xvf/adf_c62xvf_hw_data.h +++ b/drivers/crypto/qat/qat_c62xvf/adf_c62xvf_hw_data.h @@ -13,7 +13,6 @@ #define ADF_C62XIOV_ETR_BAR 0 #define ADF_C62XIOV_ETR_MAX_BANKS 1 #define ADF_C62XIOV_PF2VF_OFFSET 0x200 -#define ADF_C62XIOV_VINTMSK_OFFSET 0x208 void adf_init_hw_data_c62xiov(struct adf_hw_device_data *hw_data); void adf_clean_hw_data_c62xiov(struct adf_hw_device_data *hw_data); diff --git a/drivers/crypto/qat/qat_c62xvf/adf_drv.c b/drivers/crypto/qat/qat_c62xvf/adf_drv.c index 51ea88c0b17d..8103bd81d617 100644 --- a/drivers/crypto/qat/qat_c62xvf/adf_drv.c +++ b/drivers/crypto/qat/qat_c62xvf/adf_drv.c @@ -141,17 +141,10 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) } /* set dma identifier */ - if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) { - if ((pci_set_dma_mask(pdev, DMA_BIT_MASK(32)))) { - dev_err(&pdev->dev, "No usable DMA configuration\n"); - ret = -EFAULT; - goto out_err_disable; - } else { - pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); - } - - } else { - pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)); + ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(48)); + if (ret) { + dev_err(&pdev->dev, "No usable DMA configuration\n"); + goto out_err_disable; } if (pci_request_regions(pdev, ADF_C62XVF_DEVICE_NAME)) { @@ -218,6 +211,7 @@ static void adf_remove(struct pci_dev *pdev) pr_err("QAT: Driver removal failed\n"); return; } + adf_flush_vf_wq(accel_dev); adf_dev_stop(accel_dev); adf_dev_shutdown(accel_dev); adf_cleanup_accel(accel_dev); diff --git a/drivers/crypto/qat/qat_common/adf_accel_devices.h b/drivers/crypto/qat/qat_common/adf_accel_devices.h index ac435b44f1d2..38c0af6d4e43 100644 --- a/drivers/crypto/qat/qat_common/adf_accel_devices.h +++ b/drivers/crypto/qat/qat_common/adf_accel_devices.h @@ -18,8 +18,6 @@ #define ADF_4XXX_DEVICE_NAME "4xxx" #define ADF_4XXX_PCI_DEVICE_ID 0x4940 #define ADF_4XXXIOV_PCI_DEVICE_ID 0x4941 -#define ADF_ERRSOU3 (0x3A000 + 0x0C) -#define ADF_ERRSOU5 (0x3A000 + 0xD8) #define ADF_DEVICE_FUSECTL_OFFSET 0x40 #define ADF_DEVICE_LEGFUSE_OFFSET 0x4C #define ADF_DEVICE_FUSECTL_MASK 0x80000000 @@ -156,7 +154,6 @@ struct adf_hw_device_data { u32 (*get_num_aes)(struct adf_hw_device_data *self); u32 (*get_num_accels)(struct adf_hw_device_data *self); u32 (*get_pf2vf_offset)(u32 i); - u32 (*get_vintmsk_offset)(u32 i); void (*get_arb_info)(struct arb_info *arb_csrs_info); void (*get_admin_info)(struct admin_info *admin_csrs_info); enum dev_sku_info (*get_sku)(struct adf_hw_device_data *self); @@ -174,7 +171,7 @@ struct adf_hw_device_data { bool enable); void (*enable_ints)(struct adf_accel_dev *accel_dev); void (*set_ssm_wdtimer)(struct adf_accel_dev *accel_dev); - int (*enable_vf2pf_comms)(struct adf_accel_dev *accel_dev); + int (*enable_pfvf_comms)(struct adf_accel_dev *accel_dev); void (*reset_device)(struct adf_accel_dev *accel_dev); void (*set_msix_rttable)(struct adf_accel_dev *accel_dev); char *(*uof_get_name)(u32 obj_num); @@ -227,7 +224,6 @@ struct adf_fw_loader_data { struct adf_accel_vf_info { struct adf_accel_dev *accel_dev; - struct tasklet_struct vf2pf_bh_tasklet; struct mutex pf2vf_lock; /* protect CSR access for PF2VF messages */ struct ratelimit_state vf2pf_ratelimit; u32 vf_nr; @@ -249,6 +245,8 @@ struct adf_accel_dev { struct adf_accel_pci accel_pci_dev; union { struct { + /* protects VF2PF interrupts access */ + spinlock_t vf2pf_ints_lock; /* vf_info is non-zero when SR-IOV is init'ed */ struct adf_accel_vf_info *vf_info; } pf; diff --git a/drivers/crypto/qat/qat_common/adf_aer.c b/drivers/crypto/qat/qat_common/adf_aer.c index d2ae293d0df6..ed3e40bc56eb 100644 --- a/drivers/crypto/qat/qat_common/adf_aer.c +++ b/drivers/crypto/qat/qat_common/adf_aer.c @@ -194,7 +194,7 @@ int adf_enable_aer(struct adf_accel_dev *accel_dev) EXPORT_SYMBOL_GPL(adf_enable_aer); /** - * adf_disable_aer() - Enable Advance Error Reporting for acceleration device + * adf_disable_aer() - Disable Advance Error Reporting for acceleration device * @accel_dev: Pointer to acceleration device. * * Function disables PCI Advance Error Reporting for the diff --git a/drivers/crypto/qat/qat_common/adf_common_drv.h b/drivers/crypto/qat/qat_common/adf_common_drv.h index c61476553728..4261749fae8d 100644 --- a/drivers/crypto/qat/qat_common/adf_common_drv.h +++ b/drivers/crypto/qat/qat_common/adf_common_drv.h @@ -193,22 +193,23 @@ int adf_sriov_configure(struct pci_dev *pdev, int numvfs); void adf_disable_sriov(struct adf_accel_dev *accel_dev); void adf_disable_vf2pf_interrupts(struct adf_accel_dev *accel_dev, u32 vf_mask); +void adf_disable_vf2pf_interrupts_irq(struct adf_accel_dev *accel_dev, + u32 vf_mask); void adf_enable_vf2pf_interrupts(struct adf_accel_dev *accel_dev, u32 vf_mask); void adf_enable_pf2vf_interrupts(struct adf_accel_dev *accel_dev); void adf_disable_pf2vf_interrupts(struct adf_accel_dev *accel_dev); +void adf_schedule_vf2pf_handler(struct adf_accel_vf_info *vf_info); -int adf_vf2pf_init(struct adf_accel_dev *accel_dev); -void adf_vf2pf_shutdown(struct adf_accel_dev *accel_dev); +int adf_vf2pf_notify_init(struct adf_accel_dev *accel_dev); +void adf_vf2pf_notify_shutdown(struct adf_accel_dev *accel_dev); int adf_init_pf_wq(void); void adf_exit_pf_wq(void); int adf_init_vf_wq(void); void adf_exit_vf_wq(void); +void adf_flush_vf_wq(struct adf_accel_dev *accel_dev); #else -static inline int adf_sriov_configure(struct pci_dev *pdev, int numvfs) -{ - return 0; -} +#define adf_sriov_configure NULL static inline void adf_disable_sriov(struct adf_accel_dev *accel_dev) { @@ -222,12 +223,12 @@ static inline void adf_disable_pf2vf_interrupts(struct adf_accel_dev *accel_dev) { } -static inline int adf_vf2pf_init(struct adf_accel_dev *accel_dev) +static inline int adf_vf2pf_notify_init(struct adf_accel_dev *accel_dev) { return 0; } -static inline void adf_vf2pf_shutdown(struct adf_accel_dev *accel_dev) +static inline void adf_vf2pf_notify_shutdown(struct adf_accel_dev *accel_dev) { } @@ -249,5 +250,9 @@ static inline void adf_exit_vf_wq(void) { } +static inline void adf_flush_vf_wq(struct adf_accel_dev *accel_dev) +{ +} + #endif #endif diff --git a/drivers/crypto/qat/qat_common/adf_init.c b/drivers/crypto/qat/qat_common/adf_init.c index 744c40351428..60bc7b991d35 100644 --- a/drivers/crypto/qat/qat_common/adf_init.c +++ b/drivers/crypto/qat/qat_common/adf_init.c @@ -61,6 +61,7 @@ int adf_dev_init(struct adf_accel_dev *accel_dev) struct service_hndl *service; struct list_head *list_itr; struct adf_hw_device_data *hw_data = accel_dev->hw_device; + int ret; if (!hw_data) { dev_err(&GET_DEV(accel_dev), @@ -88,8 +89,6 @@ int adf_dev_init(struct adf_accel_dev *accel_dev) return -EFAULT; } - hw_data->enable_ints(accel_dev); - if (adf_ae_init(accel_dev)) { dev_err(&GET_DEV(accel_dev), "Failed to initialise Acceleration Engine\n"); @@ -110,6 +109,13 @@ int adf_dev_init(struct adf_accel_dev *accel_dev) } set_bit(ADF_STATUS_IRQ_ALLOCATED, &accel_dev->status); + hw_data->enable_ints(accel_dev); + hw_data->enable_error_correction(accel_dev); + + ret = hw_data->enable_pfvf_comms(accel_dev); + if (ret) + return ret; + /* * Subservice initialisation is divided into two stages: init and start. * This is to facilitate any ordering dependencies between services @@ -126,9 +132,6 @@ int adf_dev_init(struct adf_accel_dev *accel_dev) set_bit(accel_dev->accel_id, service->init_status); } - hw_data->enable_error_correction(accel_dev); - hw_data->enable_vf2pf_comms(accel_dev); - return 0; } EXPORT_SYMBOL_GPL(adf_dev_init); diff --git a/drivers/crypto/qat/qat_common/adf_isr.c b/drivers/crypto/qat/qat_common/adf_isr.c index e3ad5587be49..c678d5c531aa 100644 --- a/drivers/crypto/qat/qat_common/adf_isr.c +++ b/drivers/crypto/qat/qat_common/adf_isr.c @@ -15,6 +15,14 @@ #include "adf_transport_access_macros.h" #include "adf_transport_internal.h" +#define ADF_MAX_NUM_VFS 32 +#define ADF_ERRSOU3 (0x3A000 + 0x0C) +#define ADF_ERRSOU5 (0x3A000 + 0xD8) +#define ADF_ERRMSK3 (0x3A000 + 0x1C) +#define ADF_ERRMSK5 (0x3A000 + 0xDC) +#define ADF_ERR_REG_VF2PF_L(vf_src) (((vf_src) & 0x01FFFE00) >> 9) +#define ADF_ERR_REG_VF2PF_U(vf_src) (((vf_src) & 0x0000FFFF) << 16) + static int adf_enable_msix(struct adf_accel_dev *accel_dev) { struct adf_accel_pci *pci_dev_info = &accel_dev->accel_pci_dev; @@ -71,14 +79,23 @@ static irqreturn_t adf_msix_isr_ae(int irq, void *dev_ptr) struct adf_hw_device_data *hw_data = accel_dev->hw_device; struct adf_bar *pmisc = &GET_BARS(accel_dev)[hw_data->get_misc_bar_id(hw_data)]; - void __iomem *pmisc_bar_addr = pmisc->virt_addr; - u32 vf_mask; + void __iomem *pmisc_addr = pmisc->virt_addr; + u32 errsou3, errsou5, errmsk3, errmsk5; + unsigned long vf_mask; /* Get the interrupt sources triggered by VFs */ - vf_mask = ((ADF_CSR_RD(pmisc_bar_addr, ADF_ERRSOU5) & - 0x0000FFFF) << 16) | - ((ADF_CSR_RD(pmisc_bar_addr, ADF_ERRSOU3) & - 0x01FFFE00) >> 9); + errsou3 = ADF_CSR_RD(pmisc_addr, ADF_ERRSOU3); + errsou5 = ADF_CSR_RD(pmisc_addr, ADF_ERRSOU5); + vf_mask = ADF_ERR_REG_VF2PF_L(errsou3); + vf_mask |= ADF_ERR_REG_VF2PF_U(errsou5); + + /* To avoid adding duplicate entries to work queue, clear + * vf_int_mask_sets bits that are already masked in ERRMSK register. + */ + errmsk3 = ADF_CSR_RD(pmisc_addr, ADF_ERRMSK3); + errmsk5 = ADF_CSR_RD(pmisc_addr, ADF_ERRMSK5); + vf_mask &= ~ADF_ERR_REG_VF2PF_L(errmsk3); + vf_mask &= ~ADF_ERR_REG_VF2PF_U(errmsk5); if (vf_mask) { struct adf_accel_vf_info *vf_info; @@ -86,15 +103,13 @@ static irqreturn_t adf_msix_isr_ae(int irq, void *dev_ptr) int i; /* Disable VF2PF interrupts for VFs with pending ints */ - adf_disable_vf2pf_interrupts(accel_dev, vf_mask); + adf_disable_vf2pf_interrupts_irq(accel_dev, vf_mask); /* - * Schedule tasklets to handle VF2PF interrupt BHs - * unless the VF is malicious and is attempting to - * flood the host OS with VF2PF interrupts. + * Handle VF2PF interrupt unless the VF is malicious and + * is attempting to flood the host OS with VF2PF interrupts. */ - for_each_set_bit(i, (const unsigned long *)&vf_mask, - (sizeof(vf_mask) * BITS_PER_BYTE)) { + for_each_set_bit(i, &vf_mask, ADF_MAX_NUM_VFS) { vf_info = accel_dev->pf.vf_info + i; if (!__ratelimit(&vf_info->vf2pf_ratelimit)) { @@ -104,8 +119,7 @@ static irqreturn_t adf_msix_isr_ae(int irq, void *dev_ptr) continue; } - /* Tasklet will re-enable ints from this VF */ - tasklet_hi_schedule(&vf_info->vf2pf_bh_tasklet); + adf_schedule_vf2pf_handler(vf_info); irq_handled = true; } diff --git a/drivers/crypto/qat/qat_common/adf_pf2vf_msg.c b/drivers/crypto/qat/qat_common/adf_pf2vf_msg.c index a1b77bd7a894..976b9ab7617c 100644 --- a/drivers/crypto/qat/qat_common/adf_pf2vf_msg.c +++ b/drivers/crypto/qat/qat_common/adf_pf2vf_msg.c @@ -11,28 +11,8 @@ #define ADF_DH895XCC_ERRMSK5 (ADF_DH895XCC_EP_OFFSET + 0xDC) #define ADF_DH895XCC_ERRMSK5_VF2PF_U_MASK(vf_mask) (vf_mask >> 16) -void adf_enable_pf2vf_interrupts(struct adf_accel_dev *accel_dev) -{ - struct adf_accel_pci *pci_info = &accel_dev->accel_pci_dev; - struct adf_hw_device_data *hw_data = accel_dev->hw_device; - void __iomem *pmisc_bar_addr = - pci_info->pci_bars[hw_data->get_misc_bar_id(hw_data)].virt_addr; - - ADF_CSR_WR(pmisc_bar_addr, hw_data->get_vintmsk_offset(0), 0x0); -} - -void adf_disable_pf2vf_interrupts(struct adf_accel_dev *accel_dev) -{ - struct adf_accel_pci *pci_info = &accel_dev->accel_pci_dev; - struct adf_hw_device_data *hw_data = accel_dev->hw_device; - void __iomem *pmisc_bar_addr = - pci_info->pci_bars[hw_data->get_misc_bar_id(hw_data)].virt_addr; - - ADF_CSR_WR(pmisc_bar_addr, hw_data->get_vintmsk_offset(0), 0x2); -} - -void adf_enable_vf2pf_interrupts(struct adf_accel_dev *accel_dev, - u32 vf_mask) +static void __adf_enable_vf2pf_interrupts(struct adf_accel_dev *accel_dev, + u32 vf_mask) { struct adf_hw_device_data *hw_data = accel_dev->hw_device; struct adf_bar *pmisc = @@ -55,7 +35,17 @@ void adf_enable_vf2pf_interrupts(struct adf_accel_dev *accel_dev, } } -void adf_disable_vf2pf_interrupts(struct adf_accel_dev *accel_dev, u32 vf_mask) +void adf_enable_vf2pf_interrupts(struct adf_accel_dev *accel_dev, u32 vf_mask) +{ + unsigned long flags; + + spin_lock_irqsave(&accel_dev->pf.vf2pf_ints_lock, flags); + __adf_enable_vf2pf_interrupts(accel_dev, vf_mask); + spin_unlock_irqrestore(&accel_dev->pf.vf2pf_ints_lock, flags); +} + +static void __adf_disable_vf2pf_interrupts(struct adf_accel_dev *accel_dev, + u32 vf_mask) { struct adf_hw_device_data *hw_data = accel_dev->hw_device; struct adf_bar *pmisc = @@ -78,6 +68,22 @@ void adf_disable_vf2pf_interrupts(struct adf_accel_dev *accel_dev, u32 vf_mask) } } +void adf_disable_vf2pf_interrupts(struct adf_accel_dev *accel_dev, u32 vf_mask) +{ + unsigned long flags; + + spin_lock_irqsave(&accel_dev->pf.vf2pf_ints_lock, flags); + __adf_disable_vf2pf_interrupts(accel_dev, vf_mask); + spin_unlock_irqrestore(&accel_dev->pf.vf2pf_ints_lock, flags); +} + +void adf_disable_vf2pf_interrupts_irq(struct adf_accel_dev *accel_dev, u32 vf_mask) +{ + spin_lock(&accel_dev->pf.vf2pf_ints_lock); + __adf_disable_vf2pf_interrupts(accel_dev, vf_mask); + spin_unlock(&accel_dev->pf.vf2pf_ints_lock); +} + static int __adf_iov_putmsg(struct adf_accel_dev *accel_dev, u32 msg, u8 vf_nr) { struct adf_accel_pci *pci_info = &accel_dev->accel_pci_dev; @@ -186,7 +192,6 @@ int adf_iov_putmsg(struct adf_accel_dev *accel_dev, u32 msg, u8 vf_nr) return ret; } -EXPORT_SYMBOL_GPL(adf_iov_putmsg); void adf_vf2pf_req_hndl(struct adf_accel_vf_info *vf_info) { @@ -216,7 +221,7 @@ void adf_vf2pf_req_hndl(struct adf_accel_vf_info *vf_info) resp = (ADF_PF2VF_MSGORIGIN_SYSTEM | (ADF_PF2VF_MSGTYPE_VERSION_RESP << ADF_PF2VF_MSGTYPE_SHIFT) | - (ADF_PFVF_COMPATIBILITY_VERSION << + (ADF_PFVF_COMPAT_THIS_VERSION << ADF_PF2VF_VERSION_RESP_VERS_SHIFT)); dev_dbg(&GET_DEV(accel_dev), @@ -226,19 +231,19 @@ void adf_vf2pf_req_hndl(struct adf_accel_vf_info *vf_info) if (vf_compat_ver < hw_data->min_iov_compat_ver) { dev_err(&GET_DEV(accel_dev), "VF (vers %d) incompatible with PF (vers %d)\n", - vf_compat_ver, ADF_PFVF_COMPATIBILITY_VERSION); + vf_compat_ver, ADF_PFVF_COMPAT_THIS_VERSION); resp |= ADF_PF2VF_VF_INCOMPATIBLE << ADF_PF2VF_VERSION_RESP_RESULT_SHIFT; - } else if (vf_compat_ver > ADF_PFVF_COMPATIBILITY_VERSION) { + } else if (vf_compat_ver > ADF_PFVF_COMPAT_THIS_VERSION) { dev_err(&GET_DEV(accel_dev), "VF (vers %d) compat with PF (vers %d) unkn.\n", - vf_compat_ver, ADF_PFVF_COMPATIBILITY_VERSION); + vf_compat_ver, ADF_PFVF_COMPAT_THIS_VERSION); resp |= ADF_PF2VF_VF_COMPAT_UNKNOWN << ADF_PF2VF_VERSION_RESP_RESULT_SHIFT; } else { dev_dbg(&GET_DEV(accel_dev), "VF (vers %d) compatible with PF (vers %d)\n", - vf_compat_ver, ADF_PFVF_COMPATIBILITY_VERSION); + vf_compat_ver, ADF_PFVF_COMPAT_THIS_VERSION); resp |= ADF_PF2VF_VF_COMPATIBLE << ADF_PF2VF_VERSION_RESP_RESULT_SHIFT; } @@ -251,7 +256,7 @@ void adf_vf2pf_req_hndl(struct adf_accel_vf_info *vf_info) resp = (ADF_PF2VF_MSGORIGIN_SYSTEM | (ADF_PF2VF_MSGTYPE_VERSION_RESP << ADF_PF2VF_MSGTYPE_SHIFT) | - (ADF_PFVF_COMPATIBILITY_VERSION << + (ADF_PFVF_COMPAT_THIS_VERSION << ADF_PF2VF_VERSION_RESP_VERS_SHIFT)); resp |= ADF_PF2VF_VF_COMPATIBLE << ADF_PF2VF_VERSION_RESP_RESULT_SHIFT; @@ -284,6 +289,7 @@ void adf_vf2pf_req_hndl(struct adf_accel_vf_info *vf_info) /* re-enable interrupt on PF from this VF */ adf_enable_vf2pf_interrupts(accel_dev, (1 << vf_nr)); + return; err: dev_dbg(&GET_DEV(accel_dev), "Unknown message from VF%d (0x%x);\n", @@ -313,8 +319,10 @@ static int adf_vf2pf_request_version(struct adf_accel_dev *accel_dev) msg = ADF_VF2PF_MSGORIGIN_SYSTEM; msg |= ADF_VF2PF_MSGTYPE_COMPAT_VER_REQ << ADF_VF2PF_MSGTYPE_SHIFT; - msg |= ADF_PFVF_COMPATIBILITY_VERSION << ADF_VF2PF_COMPAT_VER_REQ_SHIFT; - BUILD_BUG_ON(ADF_PFVF_COMPATIBILITY_VERSION > 255); + msg |= ADF_PFVF_COMPAT_THIS_VERSION << ADF_VF2PF_COMPAT_VER_REQ_SHIFT; + BUILD_BUG_ON(ADF_PFVF_COMPAT_THIS_VERSION > 255); + + reinit_completion(&accel_dev->vf.iov_msg_completion); /* Send request from VF to PF */ ret = adf_iov_putmsg(accel_dev, msg, 0); @@ -338,14 +346,16 @@ static int adf_vf2pf_request_version(struct adf_accel_dev *accel_dev) break; case ADF_PF2VF_VF_COMPAT_UNKNOWN: /* VF is newer than PF and decides whether it is compatible */ - if (accel_dev->vf.pf_version >= hw_data->min_iov_compat_ver) + if (accel_dev->vf.pf_version >= hw_data->min_iov_compat_ver) { + accel_dev->vf.compatible = ADF_PF2VF_VF_COMPATIBLE; break; + } fallthrough; case ADF_PF2VF_VF_INCOMPATIBLE: dev_err(&GET_DEV(accel_dev), "PF (vers %d) and VF (vers %d) are not compatible\n", accel_dev->vf.pf_version, - ADF_PFVF_COMPATIBILITY_VERSION); + ADF_PFVF_COMPAT_THIS_VERSION); return -EINVAL; default: dev_err(&GET_DEV(accel_dev), diff --git a/drivers/crypto/qat/qat_common/adf_pf2vf_msg.h b/drivers/crypto/qat/qat_common/adf_pf2vf_msg.h index 0690c031bfce..ffd43aa50b57 100644 --- a/drivers/crypto/qat/qat_common/adf_pf2vf_msg.h +++ b/drivers/crypto/qat/qat_common/adf_pf2vf_msg.h @@ -52,7 +52,7 @@ * IN_USE_BY pattern as part of a collision control scheme (see adf_iov_putmsg). */ -#define ADF_PFVF_COMPATIBILITY_VERSION 0x1 /* PF<->VF compat */ +#define ADF_PFVF_COMPAT_THIS_VERSION 0x1 /* PF<->VF compat */ /* PF->VF messages */ #define ADF_PF2VF_INT BIT(0) diff --git a/drivers/crypto/qat/qat_common/adf_sriov.c b/drivers/crypto/qat/qat_common/adf_sriov.c index 8c822c2861c2..90ec057f9183 100644 --- a/drivers/crypto/qat/qat_common/adf_sriov.c +++ b/drivers/crypto/qat/qat_common/adf_sriov.c @@ -24,9 +24,8 @@ static void adf_iov_send_resp(struct work_struct *work) kfree(pf2vf_resp); } -static void adf_vf2pf_bh_handler(void *data) +void adf_schedule_vf2pf_handler(struct adf_accel_vf_info *vf_info) { - struct adf_accel_vf_info *vf_info = (struct adf_accel_vf_info *)data; struct adf_pf2vf_resp *pf2vf_resp; pf2vf_resp = kzalloc(sizeof(*pf2vf_resp), GFP_ATOMIC); @@ -52,9 +51,6 @@ static int adf_enable_sriov(struct adf_accel_dev *accel_dev) vf_info->accel_dev = accel_dev; vf_info->vf_nr = i; - tasklet_init(&vf_info->vf2pf_bh_tasklet, - (void *)adf_vf2pf_bh_handler, - (unsigned long)vf_info); mutex_init(&vf_info->pf2vf_lock); ratelimit_state_init(&vf_info->vf2pf_ratelimit, DEFAULT_RATELIMIT_INTERVAL, @@ -110,8 +106,6 @@ void adf_disable_sriov(struct adf_accel_dev *accel_dev) hw_data->configure_iov_threads(accel_dev, false); for (i = 0, vf = accel_dev->pf.vf_info; i < totalvfs; i++, vf++) { - tasklet_disable(&vf->vf2pf_bh_tasklet); - tasklet_kill(&vf->vf2pf_bh_tasklet); mutex_destroy(&vf->pf2vf_lock); } diff --git a/drivers/crypto/qat/qat_common/adf_vf2pf_msg.c b/drivers/crypto/qat/qat_common/adf_vf2pf_msg.c index e85bd62d134a..3e25fac051b2 100644 --- a/drivers/crypto/qat/qat_common/adf_vf2pf_msg.c +++ b/drivers/crypto/qat/qat_common/adf_vf2pf_msg.c @@ -5,14 +5,14 @@ #include "adf_pf2vf_msg.h" /** - * adf_vf2pf_init() - send init msg to PF + * adf_vf2pf_notify_init() - send init msg to PF * @accel_dev: Pointer to acceleration VF device. * * Function sends an init message from the VF to a PF * * Return: 0 on success, error code otherwise. */ -int adf_vf2pf_init(struct adf_accel_dev *accel_dev) +int adf_vf2pf_notify_init(struct adf_accel_dev *accel_dev) { u32 msg = (ADF_VF2PF_MSGORIGIN_SYSTEM | (ADF_VF2PF_MSGTYPE_INIT << ADF_VF2PF_MSGTYPE_SHIFT)); @@ -25,17 +25,17 @@ int adf_vf2pf_init(struct adf_accel_dev *accel_dev) set_bit(ADF_STATUS_PF_RUNNING, &accel_dev->status); return 0; } -EXPORT_SYMBOL_GPL(adf_vf2pf_init); +EXPORT_SYMBOL_GPL(adf_vf2pf_notify_init); /** - * adf_vf2pf_shutdown() - send shutdown msg to PF + * adf_vf2pf_notify_shutdown() - send shutdown msg to PF * @accel_dev: Pointer to acceleration VF device. * * Function sends a shutdown message from the VF to a PF * * Return: void */ -void adf_vf2pf_shutdown(struct adf_accel_dev *accel_dev) +void adf_vf2pf_notify_shutdown(struct adf_accel_dev *accel_dev) { u32 msg = (ADF_VF2PF_MSGORIGIN_SYSTEM | (ADF_VF2PF_MSGTYPE_SHUTDOWN << ADF_VF2PF_MSGTYPE_SHIFT)); @@ -45,4 +45,4 @@ void adf_vf2pf_shutdown(struct adf_accel_dev *accel_dev) dev_err(&GET_DEV(accel_dev), "Failed to send Shutdown event to PF\n"); } -EXPORT_SYMBOL_GPL(adf_vf2pf_shutdown); +EXPORT_SYMBOL_GPL(adf_vf2pf_notify_shutdown); diff --git a/drivers/crypto/qat/qat_common/adf_vf_isr.c b/drivers/crypto/qat/qat_common/adf_vf_isr.c index 888388acb6bd..7828a6573f3e 100644 --- a/drivers/crypto/qat/qat_common/adf_vf_isr.c +++ b/drivers/crypto/qat/qat_common/adf_vf_isr.c @@ -18,6 +18,7 @@ #include "adf_pf2vf_msg.h" #define ADF_VINTSOU_OFFSET 0x204 +#define ADF_VINTMSK_OFFSET 0x208 #define ADF_VINTSOU_BUN BIT(0) #define ADF_VINTSOU_PF2VF BIT(1) @@ -28,6 +29,27 @@ struct adf_vf_stop_data { struct work_struct work; }; +void adf_enable_pf2vf_interrupts(struct adf_accel_dev *accel_dev) +{ + struct adf_accel_pci *pci_info = &accel_dev->accel_pci_dev; + struct adf_hw_device_data *hw_data = accel_dev->hw_device; + void __iomem *pmisc_bar_addr = + pci_info->pci_bars[hw_data->get_misc_bar_id(hw_data)].virt_addr; + + ADF_CSR_WR(pmisc_bar_addr, ADF_VINTMSK_OFFSET, 0x0); +} + +void adf_disable_pf2vf_interrupts(struct adf_accel_dev *accel_dev) +{ + struct adf_accel_pci *pci_info = &accel_dev->accel_pci_dev; + struct adf_hw_device_data *hw_data = accel_dev->hw_device; + void __iomem *pmisc_bar_addr = + pci_info->pci_bars[hw_data->get_misc_bar_id(hw_data)].virt_addr; + + ADF_CSR_WR(pmisc_bar_addr, ADF_VINTMSK_OFFSET, 0x2); +} +EXPORT_SYMBOL_GPL(adf_disable_pf2vf_interrupts); + static int adf_enable_msi(struct adf_accel_dev *accel_dev) { struct adf_accel_pci *pci_dev_info = &accel_dev->accel_pci_dev; @@ -160,11 +182,21 @@ static irqreturn_t adf_isr(int irq, void *privdata) struct adf_bar *pmisc = &GET_BARS(accel_dev)[hw_data->get_misc_bar_id(hw_data)]; void __iomem *pmisc_bar_addr = pmisc->virt_addr; - u32 v_int; + bool handled = false; + u32 v_int, v_mask; /* Read VF INT source CSR to determine the source of VF interrupt */ v_int = ADF_CSR_RD(pmisc_bar_addr, ADF_VINTSOU_OFFSET); + /* Read VF INT mask CSR to determine which sources are masked */ + v_mask = ADF_CSR_RD(pmisc_bar_addr, ADF_VINTMSK_OFFSET); + + /* + * Recompute v_int ignoring sources that are masked. This is to + * avoid rescheduling the tasklet for interrupts already handled + */ + v_int &= ~v_mask; + /* Check for PF2VF interrupt */ if (v_int & ADF_VINTSOU_PF2VF) { /* Disable PF to VF interrupt */ @@ -172,7 +204,7 @@ static irqreturn_t adf_isr(int irq, void *privdata) /* Schedule tasklet to handle interrupt BH */ tasklet_hi_schedule(&accel_dev->vf.pf2vf_bh_tasklet); - return IRQ_HANDLED; + handled = true; } /* Check bundle interrupt */ @@ -184,10 +216,10 @@ static irqreturn_t adf_isr(int irq, void *privdata) csr_ops->write_csr_int_flag_and_col(bank->csr_addr, bank->bank_number, 0); tasklet_hi_schedule(&bank->resp_handler); - return IRQ_HANDLED; + handled = true; } - return IRQ_NONE; + return handled ? IRQ_HANDLED : IRQ_NONE; } static int adf_request_msi_irq(struct adf_accel_dev *accel_dev) @@ -285,6 +317,30 @@ err_out: } EXPORT_SYMBOL_GPL(adf_vf_isr_resource_alloc); +/** + * adf_flush_vf_wq() - Flush workqueue for VF + * @accel_dev: Pointer to acceleration device. + * + * Function disables the PF/VF interrupts on the VF so that no new messages + * are received and flushes the workqueue 'adf_vf_stop_wq'. + * + * Return: void. + */ +void adf_flush_vf_wq(struct adf_accel_dev *accel_dev) +{ + adf_disable_pf2vf_interrupts(accel_dev); + + flush_workqueue(adf_vf_stop_wq); +} +EXPORT_SYMBOL_GPL(adf_flush_vf_wq); + +/** + * adf_init_vf_wq() - Init workqueue for VF + * + * Function init workqueue 'adf_vf_stop_wq' for VF. + * + * Return: 0 on success, error code otherwise. + */ int __init adf_init_vf_wq(void) { adf_vf_stop_wq = alloc_workqueue("adf_vf_stop_wq", WQ_MEM_RECLAIM, 0); diff --git a/drivers/crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.c b/drivers/crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.c index 7dd7cd6c3ef8..0a9ce365a544 100644 --- a/drivers/crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.c +++ b/drivers/crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.c @@ -131,11 +131,6 @@ static u32 get_pf2vf_offset(u32 i) return ADF_DH895XCC_PF2VF_OFFSET(i); } -static u32 get_vintmsk_offset(u32 i) -{ - return ADF_DH895XCC_VINTMSK_OFFSET(i); -} - static void adf_enable_error_correction(struct adf_accel_dev *accel_dev) { struct adf_hw_device_data *hw_device = accel_dev->hw_device; @@ -180,8 +175,10 @@ static void adf_enable_ints(struct adf_accel_dev *accel_dev) ADF_DH895XCC_SMIA1_MASK); } -static int adf_pf_enable_vf2pf_comms(struct adf_accel_dev *accel_dev) +static int adf_enable_pf2vf_comms(struct adf_accel_dev *accel_dev) { + spin_lock_init(&accel_dev->pf.vf2pf_ints_lock); + return 0; } @@ -213,8 +210,6 @@ void adf_init_hw_data_dh895xcc(struct adf_hw_device_data *hw_data) hw_data->get_num_aes = get_num_aes; hw_data->get_etr_bar_id = get_etr_bar_id; hw_data->get_misc_bar_id = get_misc_bar_id; - hw_data->get_pf2vf_offset = get_pf2vf_offset; - hw_data->get_vintmsk_offset = get_vintmsk_offset; hw_data->get_admin_info = adf_gen2_get_admin_info; hw_data->get_arb_info = adf_gen2_get_arb_info; hw_data->get_sram_bar_id = get_sram_bar_id; @@ -224,15 +219,17 @@ void adf_init_hw_data_dh895xcc(struct adf_hw_device_data *hw_data) hw_data->init_admin_comms = adf_init_admin_comms; hw_data->exit_admin_comms = adf_exit_admin_comms; hw_data->configure_iov_threads = configure_iov_threads; - hw_data->disable_iov = adf_disable_sriov; hw_data->send_admin_init = adf_send_admin_init; hw_data->init_arb = adf_init_arb; hw_data->exit_arb = adf_exit_arb; hw_data->get_arb_mapping = adf_get_arbiter_mapping; hw_data->enable_ints = adf_enable_ints; - hw_data->enable_vf2pf_comms = adf_pf_enable_vf2pf_comms; hw_data->reset_device = adf_reset_sbr; - hw_data->min_iov_compat_ver = ADF_PFVF_COMPATIBILITY_VERSION; + hw_data->get_pf2vf_offset = get_pf2vf_offset; + hw_data->enable_pfvf_comms = adf_enable_pf2vf_comms; + hw_data->disable_iov = adf_disable_sriov; + hw_data->min_iov_compat_ver = ADF_PFVF_COMPAT_THIS_VERSION; + adf_gen2_init_hw_csr_ops(&hw_data->csr_ops); } diff --git a/drivers/crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.h b/drivers/crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.h index 4d613923d155..f99319cd4543 100644 --- a/drivers/crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.h +++ b/drivers/crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.h @@ -35,7 +35,6 @@ #define ADF_DH895XCC_ERRSSMSH_EN BIT(3) #define ADF_DH895XCC_PF2VF_OFFSET(i) (0x3A000 + 0x280 + ((i) * 0x04)) -#define ADF_DH895XCC_VINTMSK_OFFSET(i) (0x3A000 + 0x200 + ((i) * 0x04)) /* AE to function mapping */ #define ADF_DH895XCC_AE2FUNC_MAP_GRP_A_NUM_REGS 96 diff --git a/drivers/crypto/qat/qat_dh895xcc/adf_drv.c b/drivers/crypto/qat/qat_dh895xcc/adf_drv.c index a9ec4357144c..3976a81bd99b 100644 --- a/drivers/crypto/qat/qat_dh895xcc/adf_drv.c +++ b/drivers/crypto/qat/qat_dh895xcc/adf_drv.c @@ -159,17 +159,10 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) } /* set dma identifier */ - if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) { - if ((pci_set_dma_mask(pdev, DMA_BIT_MASK(32)))) { - dev_err(&pdev->dev, "No usable DMA configuration\n"); - ret = -EFAULT; - goto out_err_disable; - } else { - pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); - } - - } else { - pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)); + ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(48)); + if (ret) { + dev_err(&pdev->dev, "No usable DMA configuration\n"); + goto out_err_disable; } if (pci_request_regions(pdev, ADF_DH895XCC_DEVICE_NAME)) { @@ -208,12 +201,12 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (pci_save_state(pdev)) { dev_err(&pdev->dev, "Failed to save pci state\n"); ret = -ENOMEM; - goto out_err_free_reg; + goto out_err_disable_aer; } ret = qat_crypto_dev_config(accel_dev); if (ret) - goto out_err_free_reg; + goto out_err_disable_aer; ret = adf_dev_init(accel_dev); if (ret) @@ -229,6 +222,8 @@ out_err_dev_stop: adf_dev_stop(accel_dev); out_err_dev_shutdown: adf_dev_shutdown(accel_dev); +out_err_disable_aer: + adf_disable_aer(accel_dev); out_err_free_reg: pci_release_regions(accel_pci_dev->pci_dev); out_err_disable: diff --git a/drivers/crypto/qat/qat_dh895xccvf/adf_dh895xccvf_hw_data.c b/drivers/crypto/qat/qat_dh895xccvf/adf_dh895xccvf_hw_data.c index f14fb82ed6df..7c6ed6bc8abf 100644 --- a/drivers/crypto/qat/qat_dh895xccvf/adf_dh895xccvf_hw_data.c +++ b/drivers/crypto/qat/qat_dh895xccvf/adf_dh895xccvf_hw_data.c @@ -52,11 +52,6 @@ static u32 get_pf2vf_offset(u32 i) return ADF_DH895XCCIOV_PF2VF_OFFSET; } -static u32 get_vintmsk_offset(u32 i) -{ - return ADF_DH895XCCIOV_VINTMSK_OFFSET; -} - static int adf_vf_int_noop(struct adf_accel_dev *accel_dev) { return 0; @@ -81,10 +76,10 @@ void adf_init_hw_data_dh895xcciov(struct adf_hw_device_data *hw_data) hw_data->enable_error_correction = adf_vf_void_noop; hw_data->init_admin_comms = adf_vf_int_noop; hw_data->exit_admin_comms = adf_vf_void_noop; - hw_data->send_admin_init = adf_vf2pf_init; + hw_data->send_admin_init = adf_vf2pf_notify_init; hw_data->init_arb = adf_vf_int_noop; hw_data->exit_arb = adf_vf_void_noop; - hw_data->disable_iov = adf_vf2pf_shutdown; + hw_data->disable_iov = adf_vf2pf_notify_shutdown; hw_data->get_accel_mask = get_accel_mask; hw_data->get_ae_mask = get_ae_mask; hw_data->get_num_accels = get_num_accels; @@ -92,11 +87,10 @@ void adf_init_hw_data_dh895xcciov(struct adf_hw_device_data *hw_data) hw_data->get_etr_bar_id = get_etr_bar_id; hw_data->get_misc_bar_id = get_misc_bar_id; hw_data->get_pf2vf_offset = get_pf2vf_offset; - hw_data->get_vintmsk_offset = get_vintmsk_offset; hw_data->get_sku = get_sku; hw_data->enable_ints = adf_vf_void_noop; - hw_data->enable_vf2pf_comms = adf_enable_vf2pf_comms; - hw_data->min_iov_compat_ver = ADF_PFVF_COMPATIBILITY_VERSION; + hw_data->enable_pfvf_comms = adf_enable_vf2pf_comms; + hw_data->min_iov_compat_ver = ADF_PFVF_COMPAT_THIS_VERSION; hw_data->dev_class->instances++; adf_devmgr_update_class_index(hw_data); adf_gen2_init_hw_csr_ops(&hw_data->csr_ops); diff --git a/drivers/crypto/qat/qat_dh895xccvf/adf_dh895xccvf_hw_data.h b/drivers/crypto/qat/qat_dh895xccvf/adf_dh895xccvf_hw_data.h index 2bfcc67f8f39..306ebb71a408 100644 --- a/drivers/crypto/qat/qat_dh895xccvf/adf_dh895xccvf_hw_data.h +++ b/drivers/crypto/qat/qat_dh895xccvf/adf_dh895xccvf_hw_data.h @@ -13,7 +13,6 @@ #define ADF_DH895XCCIOV_ETR_BAR 0 #define ADF_DH895XCCIOV_ETR_MAX_BANKS 1 #define ADF_DH895XCCIOV_PF2VF_OFFSET 0x200 -#define ADF_DH895XCCIOV_VINTMSK_OFFSET 0x208 void adf_init_hw_data_dh895xcciov(struct adf_hw_device_data *hw_data); void adf_clean_hw_data_dh895xcciov(struct adf_hw_device_data *hw_data); diff --git a/drivers/crypto/qat/qat_dh895xccvf/adf_drv.c b/drivers/crypto/qat/qat_dh895xccvf/adf_drv.c index 29999da716cc..99d90f3ea2b7 100644 --- a/drivers/crypto/qat/qat_dh895xccvf/adf_drv.c +++ b/drivers/crypto/qat/qat_dh895xccvf/adf_drv.c @@ -141,17 +141,10 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) } /* set dma identifier */ - if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) { - if ((pci_set_dma_mask(pdev, DMA_BIT_MASK(32)))) { - dev_err(&pdev->dev, "No usable DMA configuration\n"); - ret = -EFAULT; - goto out_err_disable; - } else { - pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); - } - - } else { - pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)); + ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(48)); + if (ret) { + dev_err(&pdev->dev, "No usable DMA configuration\n"); + goto out_err_disable; } if (pci_request_regions(pdev, ADF_DH895XCCVF_DEVICE_NAME)) { @@ -218,6 +211,7 @@ static void adf_remove(struct pci_dev *pdev) pr_err("QAT: Driver removal failed\n"); return; } + adf_flush_vf_wq(accel_dev); adf_dev_stop(accel_dev); adf_dev_shutdown(accel_dev); adf_cleanup_accel(accel_dev); diff --git a/drivers/crypto/virtio/virtio_crypto_core.c b/drivers/crypto/virtio/virtio_crypto_core.c index 080955a1dd9c..e2375d992308 100644 --- a/drivers/crypto/virtio/virtio_crypto_core.c +++ b/drivers/crypto/virtio/virtio_crypto_core.c @@ -187,9 +187,9 @@ static int virtcrypto_init_vqs(struct virtio_crypto *vi) if (ret) goto err_free; - get_online_cpus(); + cpus_read_lock(); virtcrypto_set_affinity(vi); - put_online_cpus(); + cpus_read_unlock(); return 0; diff --git a/drivers/edac/altera_edac.c b/drivers/edac/altera_edac.c index 61c21bd880a4..2949edb93454 100644 --- a/drivers/edac/altera_edac.c +++ b/drivers/edac/altera_edac.c @@ -539,10 +539,18 @@ module_platform_driver(altr_edac_driver); * trigger testing are different for each memory. */ +#ifdef CONFIG_EDAC_ALTERA_OCRAM static const struct edac_device_prv_data ocramecc_data; +#endif +#ifdef CONFIG_EDAC_ALTERA_L2C static const struct edac_device_prv_data l2ecc_data; +#endif +#ifdef CONFIG_EDAC_ALTERA_OCRAM static const struct edac_device_prv_data a10_ocramecc_data; +#endif +#ifdef CONFIG_EDAC_ALTERA_L2C static const struct edac_device_prv_data a10_l2ecc_data; +#endif static irqreturn_t altr_edac_device_handler(int irq, void *dev_id) { @@ -569,9 +577,9 @@ static irqreturn_t altr_edac_device_handler(int irq, void *dev_id) return ret_value; } -static ssize_t altr_edac_device_trig(struct file *file, - const char __user *user_buf, - size_t count, loff_t *ppos) +static ssize_t __maybe_unused +altr_edac_device_trig(struct file *file, const char __user *user_buf, + size_t count, loff_t *ppos) { u32 *ptemp, i, error_mask; @@ -640,27 +648,27 @@ static ssize_t altr_edac_device_trig(struct file *file, return count; } -static const struct file_operations altr_edac_device_inject_fops = { +static const struct file_operations altr_edac_device_inject_fops __maybe_unused = { .open = simple_open, .write = altr_edac_device_trig, .llseek = generic_file_llseek, }; -static ssize_t altr_edac_a10_device_trig(struct file *file, - const char __user *user_buf, - size_t count, loff_t *ppos); +static ssize_t __maybe_unused +altr_edac_a10_device_trig(struct file *file, const char __user *user_buf, + size_t count, loff_t *ppos); -static const struct file_operations altr_edac_a10_device_inject_fops = { +static const struct file_operations altr_edac_a10_device_inject_fops __maybe_unused = { .open = simple_open, .write = altr_edac_a10_device_trig, .llseek = generic_file_llseek, }; -static ssize_t altr_edac_a10_device_trig2(struct file *file, - const char __user *user_buf, - size_t count, loff_t *ppos); +static ssize_t __maybe_unused +altr_edac_a10_device_trig2(struct file *file, const char __user *user_buf, + size_t count, loff_t *ppos); -static const struct file_operations altr_edac_a10_device_inject2_fops = { +static const struct file_operations altr_edac_a10_device_inject2_fops __maybe_unused = { .open = simple_open, .write = altr_edac_a10_device_trig2, .llseek = generic_file_llseek, @@ -1697,9 +1705,9 @@ MODULE_DEVICE_TABLE(of, altr_edac_a10_device_of_match); * Based on xgene_edac.c peripheral code. */ -static ssize_t altr_edac_a10_device_trig(struct file *file, - const char __user *user_buf, - size_t count, loff_t *ppos) +static ssize_t __maybe_unused +altr_edac_a10_device_trig(struct file *file, const char __user *user_buf, + size_t count, loff_t *ppos) { struct edac_device_ctl_info *edac_dci = file->private_data; struct altr_edac_device_dev *drvdata = edac_dci->pvt_info; @@ -1729,9 +1737,9 @@ static ssize_t altr_edac_a10_device_trig(struct file *file, * slightly. A few Arria10 peripherals can use this injection function. * Inject the error into the memory and then readback to trigger the IRQ. */ -static ssize_t altr_edac_a10_device_trig2(struct file *file, - const char __user *user_buf, - size_t count, loff_t *ppos) +static ssize_t __maybe_unused +altr_edac_a10_device_trig2(struct file *file, const char __user *user_buf, + size_t count, loff_t *ppos) { struct edac_device_ctl_info *edac_dci = file->private_data; struct altr_edac_device_dev *drvdata = edac_dci->pvt_info; diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index f0d8f60acee1..99b06a3e8fb1 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c @@ -571,8 +571,8 @@ EDAC_DCT_ATTR_SHOW(dbam0); EDAC_DCT_ATTR_SHOW(top_mem); EDAC_DCT_ATTR_SHOW(top_mem2); -static ssize_t hole_show(struct device *dev, struct device_attribute *mattr, - char *data) +static ssize_t dram_hole_show(struct device *dev, struct device_attribute *mattr, + char *data) { struct mem_ctl_info *mci = to_mci(dev); @@ -593,7 +593,7 @@ static DEVICE_ATTR(dhar, S_IRUGO, dhar_show, NULL); static DEVICE_ATTR(dbam, S_IRUGO, dbam0_show, NULL); static DEVICE_ATTR(topmem, S_IRUGO, top_mem_show, NULL); static DEVICE_ATTR(topmem2, S_IRUGO, top_mem2_show, NULL); -static DEVICE_ATTR(dram_hole, S_IRUGO, hole_show, NULL); +static DEVICE_ATTR_RO(dram_hole); static struct attribute *dbg_attrs[] = { &dev_attr_dhar.attr, @@ -802,16 +802,11 @@ static ssize_t inject_write_store(struct device *dev, * update NUM_INJ_ATTRS in case you add new members */ -static DEVICE_ATTR(inject_section, S_IRUGO | S_IWUSR, - inject_section_show, inject_section_store); -static DEVICE_ATTR(inject_word, S_IRUGO | S_IWUSR, - inject_word_show, inject_word_store); -static DEVICE_ATTR(inject_ecc_vector, S_IRUGO | S_IWUSR, - inject_ecc_vector_show, inject_ecc_vector_store); -static DEVICE_ATTR(inject_write, S_IWUSR, - NULL, inject_write_store); -static DEVICE_ATTR(inject_read, S_IWUSR, - NULL, inject_read_store); +static DEVICE_ATTR_RW(inject_section); +static DEVICE_ATTR_RW(inject_word); +static DEVICE_ATTR_RW(inject_ecc_vector); +static DEVICE_ATTR_WO(inject_write); +static DEVICE_ATTR_WO(inject_read); static struct attribute *inj_attrs[] = { &dev_attr_inject_section.attr, diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c index f6d462d0be2d..2c5975674723 100644 --- a/drivers/edac/edac_mc.c +++ b/drivers/edac/edac_mc.c @@ -166,6 +166,7 @@ const char * const edac_mem_types[] = { [MEM_DDR5] = "Unbuffered-DDR5", [MEM_NVDIMM] = "Non-volatile-RAM", [MEM_WIO2] = "Wide-IO-2", + [MEM_HBM2] = "High-bandwidth-memory-Gen2", }; EXPORT_SYMBOL_GPL(edac_mem_types); diff --git a/drivers/edac/i10nm_base.c b/drivers/edac/i10nm_base.c index 6ce0ed2ffaaf..83345bfac246 100644 --- a/drivers/edac/i10nm_base.c +++ b/drivers/edac/i10nm_base.c @@ -33,15 +33,21 @@ #define I10NM_GET_DIMMMTR(m, i, j) \ readl((m)->mbase + ((m)->hbm_mc ? 0x80c : 0x2080c) + \ (i) * (m)->chan_mmio_sz + (j) * 4) -#define I10NM_GET_MCDDRTCFG(m, i, j) \ +#define I10NM_GET_MCDDRTCFG(m, i) \ readl((m)->mbase + ((m)->hbm_mc ? 0x970 : 0x20970) + \ - (i) * (m)->chan_mmio_sz + (j) * 4) + (i) * (m)->chan_mmio_sz) #define I10NM_GET_MCMTR(m, i) \ readl((m)->mbase + ((m)->hbm_mc ? 0xef8 : 0x20ef8) + \ (i) * (m)->chan_mmio_sz) #define I10NM_GET_AMAP(m, i) \ readl((m)->mbase + ((m)->hbm_mc ? 0x814 : 0x20814) + \ (i) * (m)->chan_mmio_sz) +#define I10NM_GET_REG32(m, i, offset) \ + readl((m)->mbase + (i) * (m)->chan_mmio_sz + (offset)) +#define I10NM_GET_REG64(m, i, offset) \ + readq((m)->mbase + (i) * (m)->chan_mmio_sz + (offset)) +#define I10NM_SET_REG32(m, i, offset, v) \ + writel(v, (m)->mbase + (i) * (m)->chan_mmio_sz + (offset)) #define I10NM_GET_SCK_MMIO_BASE(reg) (GET_BITFIELD(reg, 0, 28) << 23) #define I10NM_GET_IMC_MMIO_OFFSET(reg) (GET_BITFIELD(reg, 0, 10) << 12) @@ -58,8 +64,125 @@ #define I10NM_SAD_ENABLE(reg) GET_BITFIELD(reg, 0, 0) #define I10NM_SAD_NM_CACHEABLE(reg) GET_BITFIELD(reg, 5, 5) +#define RETRY_RD_ERR_LOG_UC BIT(1) +#define RETRY_RD_ERR_LOG_NOOVER BIT(14) +#define RETRY_RD_ERR_LOG_EN BIT(15) +#define RETRY_RD_ERR_LOG_NOOVER_UC (BIT(14) | BIT(1)) +#define RETRY_RD_ERR_LOG_OVER_UC_V (BIT(2) | BIT(1) | BIT(0)) + static struct list_head *i10nm_edac_list; +static struct res_config *res_cfg; +static int retry_rd_err_log; + +static u32 offsets_scrub_icx[] = {0x22c60, 0x22c54, 0x22c5c, 0x22c58, 0x22c28, 0x20ed8}; +static u32 offsets_scrub_spr[] = {0x22c60, 0x22c54, 0x22f08, 0x22c58, 0x22c28, 0x20ed8}; +static u32 offsets_demand_icx[] = {0x22e54, 0x22e60, 0x22e64, 0x22e58, 0x22e5c, 0x20ee0}; +static u32 offsets_demand_spr[] = {0x22e54, 0x22e60, 0x22f10, 0x22e58, 0x22e5c, 0x20ee0}; + +static void __enable_retry_rd_err_log(struct skx_imc *imc, int chan, bool enable) +{ + u32 s, d; + + if (!imc->mbase) + return; + + s = I10NM_GET_REG32(imc, chan, res_cfg->offsets_scrub[0]); + d = I10NM_GET_REG32(imc, chan, res_cfg->offsets_demand[0]); + + if (enable) { + /* Save default configurations */ + imc->chan[chan].retry_rd_err_log_s = s; + imc->chan[chan].retry_rd_err_log_d = d; + + s &= ~RETRY_RD_ERR_LOG_NOOVER_UC; + s |= RETRY_RD_ERR_LOG_EN; + d &= ~RETRY_RD_ERR_LOG_NOOVER_UC; + d |= RETRY_RD_ERR_LOG_EN; + } else { + /* Restore default configurations */ + if (imc->chan[chan].retry_rd_err_log_s & RETRY_RD_ERR_LOG_UC) + s |= RETRY_RD_ERR_LOG_UC; + if (imc->chan[chan].retry_rd_err_log_s & RETRY_RD_ERR_LOG_NOOVER) + s |= RETRY_RD_ERR_LOG_NOOVER; + if (!(imc->chan[chan].retry_rd_err_log_s & RETRY_RD_ERR_LOG_EN)) + s &= ~RETRY_RD_ERR_LOG_EN; + if (imc->chan[chan].retry_rd_err_log_d & RETRY_RD_ERR_LOG_UC) + d |= RETRY_RD_ERR_LOG_UC; + if (imc->chan[chan].retry_rd_err_log_d & RETRY_RD_ERR_LOG_NOOVER) + d |= RETRY_RD_ERR_LOG_NOOVER; + if (!(imc->chan[chan].retry_rd_err_log_d & RETRY_RD_ERR_LOG_EN)) + d &= ~RETRY_RD_ERR_LOG_EN; + } + + I10NM_SET_REG32(imc, chan, res_cfg->offsets_scrub[0], s); + I10NM_SET_REG32(imc, chan, res_cfg->offsets_demand[0], d); +} + +static void enable_retry_rd_err_log(bool enable) +{ + struct skx_dev *d; + int i, j; + + edac_dbg(2, "\n"); + + list_for_each_entry(d, i10nm_edac_list, list) + for (i = 0; i < I10NM_NUM_IMC; i++) + for (j = 0; j < I10NM_NUM_CHANNELS; j++) + __enable_retry_rd_err_log(&d->imc[i], j, enable); +} + +static void show_retry_rd_err_log(struct decoded_addr *res, char *msg, + int len, bool scrub_err) +{ + struct skx_imc *imc = &res->dev->imc[res->imc]; + u32 log0, log1, log2, log3, log4; + u32 corr0, corr1, corr2, corr3; + u64 log2a, log5; + u32 *offsets; + int n; + + if (!imc->mbase) + return; + + offsets = scrub_err ? res_cfg->offsets_scrub : res_cfg->offsets_demand; + + log0 = I10NM_GET_REG32(imc, res->channel, offsets[0]); + log1 = I10NM_GET_REG32(imc, res->channel, offsets[1]); + log3 = I10NM_GET_REG32(imc, res->channel, offsets[3]); + log4 = I10NM_GET_REG32(imc, res->channel, offsets[4]); + log5 = I10NM_GET_REG64(imc, res->channel, offsets[5]); + + if (res_cfg->type == SPR) { + log2a = I10NM_GET_REG64(imc, res->channel, offsets[2]); + n = snprintf(msg, len, " retry_rd_err_log[%.8x %.8x %.16llx %.8x %.8x %.16llx]", + log0, log1, log2a, log3, log4, log5); + } else { + log2 = I10NM_GET_REG32(imc, res->channel, offsets[2]); + n = snprintf(msg, len, " retry_rd_err_log[%.8x %.8x %.8x %.8x %.8x %.16llx]", + log0, log1, log2, log3, log4, log5); + } + + corr0 = I10NM_GET_REG32(imc, res->channel, 0x22c18); + corr1 = I10NM_GET_REG32(imc, res->channel, 0x22c1c); + corr2 = I10NM_GET_REG32(imc, res->channel, 0x22c20); + corr3 = I10NM_GET_REG32(imc, res->channel, 0x22c24); + + if (len - n > 0) + snprintf(msg + n, len - n, + " correrrcnt[%.4x %.4x %.4x %.4x %.4x %.4x %.4x %.4x]", + corr0 & 0xffff, corr0 >> 16, + corr1 & 0xffff, corr1 >> 16, + corr2 & 0xffff, corr2 >> 16, + corr3 & 0xffff, corr3 >> 16); + + /* Clear status bits */ + if (retry_rd_err_log == 2 && (log0 & RETRY_RD_ERR_LOG_OVER_UC_V)) { + log0 &= ~RETRY_RD_ERR_LOG_OVER_UC_V; + I10NM_SET_REG32(imc, res->channel, offsets[0], log0); + } +} + static struct pci_dev *pci_get_dev_wrapper(int dom, unsigned int bus, unsigned int dev, unsigned int fun) { @@ -263,6 +386,8 @@ static struct res_config i10nm_cfg0 = { .ddr_chan_mmio_sz = 0x4000, .sad_all_devfn = PCI_DEVFN(29, 0), .sad_all_offset = 0x108, + .offsets_scrub = offsets_scrub_icx, + .offsets_demand = offsets_demand_icx, }; static struct res_config i10nm_cfg1 = { @@ -272,6 +397,8 @@ static struct res_config i10nm_cfg1 = { .ddr_chan_mmio_sz = 0x4000, .sad_all_devfn = PCI_DEVFN(29, 0), .sad_all_offset = 0x108, + .offsets_scrub = offsets_scrub_icx, + .offsets_demand = offsets_demand_icx, }; static struct res_config spr_cfg = { @@ -283,6 +410,8 @@ static struct res_config spr_cfg = { .support_ddr5 = true, .sad_all_devfn = PCI_DEVFN(10, 0), .sad_all_offset = 0x300, + .offsets_scrub = offsets_scrub_spr, + .offsets_demand = offsets_demand_spr, }; static const struct x86_cpu_id i10nm_cpuids[] = { @@ -321,10 +450,10 @@ static int i10nm_get_dimm_config(struct mem_ctl_info *mci, ndimms = 0; amap = I10NM_GET_AMAP(imc, i); + mcddrtcfg = I10NM_GET_MCDDRTCFG(imc, i); for (j = 0; j < imc->num_dimms; j++) { dimm = edac_get_dimm(mci, i, j, 0); mtr = I10NM_GET_DIMMMTR(imc, i, j); - mcddrtcfg = I10NM_GET_MCDDRTCFG(imc, i, j); edac_dbg(1, "dimmmtr 0x%x mcddrtcfg 0x%x (mc%d ch%d dimm%d)\n", mtr, mcddrtcfg, imc->mc, i, j); @@ -422,6 +551,7 @@ static int __init i10nm_init(void) return -ENODEV; cfg = (struct res_config *)id->driver_data; + res_cfg = cfg; rc = skx_get_hi_lo(0x09a2, off, &tolm, &tohm); if (rc) @@ -486,6 +616,12 @@ static int __init i10nm_init(void) mce_register_decode_chain(&i10nm_mce_dec); setup_i10nm_debug(); + if (retry_rd_err_log && res_cfg->offsets_scrub && res_cfg->offsets_demand) { + skx_set_decode(NULL, show_retry_rd_err_log); + if (retry_rd_err_log == 2) + enable_retry_rd_err_log(true); + } + i10nm_printk(KERN_INFO, "%s\n", I10NM_REVISION); return 0; @@ -497,6 +633,13 @@ fail: static void __exit i10nm_exit(void) { edac_dbg(2, "\n"); + + if (retry_rd_err_log && res_cfg->offsets_scrub && res_cfg->offsets_demand) { + skx_set_decode(NULL, NULL); + if (retry_rd_err_log == 2) + enable_retry_rd_err_log(false); + } + teardown_i10nm_debug(); mce_unregister_decode_chain(&i10nm_mce_dec); skx_adxl_put(); @@ -506,5 +649,8 @@ static void __exit i10nm_exit(void) module_init(i10nm_init); module_exit(i10nm_exit); +module_param(retry_rd_err_log, int, 0444); +MODULE_PARM_DESC(retry_rd_err_log, "retry_rd_err_log: 0=off(default), 1=bios(Linux doesn't reset any control bits, but just reports values.), 2=linux(Linux tries to take control and resets mode bits, clear valid/UC bits after reading.)"); + MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("MC Driver for Intel 10nm server processors"); diff --git a/drivers/edac/mce_amd.c b/drivers/edac/mce_amd.c index 27d56920b469..67dbf4c31271 100644 --- a/drivers/edac/mce_amd.c +++ b/drivers/edac/mce_amd.c @@ -1246,6 +1246,9 @@ static int __init mce_amd_init(void) c->x86_vendor != X86_VENDOR_HYGON) return -ENODEV; + if (cpu_feature_enabled(X86_FEATURE_HYPERVISOR)) + return -ENODEV; + if (boot_cpu_has(X86_FEATURE_SMCA)) { xec_mask = 0x3f; goto out; diff --git a/drivers/edac/skx_base.c b/drivers/edac/skx_base.c index 4dbd46575bfb..1abc020d49ab 100644 --- a/drivers/edac/skx_base.c +++ b/drivers/edac/skx_base.c @@ -230,7 +230,8 @@ static int skx_get_dimm_config(struct mem_ctl_info *mci, struct res_config *cfg) #define SKX_ILV_TARGET(tgt) ((tgt) & 7) static void skx_show_retry_rd_err_log(struct decoded_addr *res, - char *msg, int len) + char *msg, int len, + bool scrub_err) { u32 log0, log1, log2, log3, log4; u32 corr0, corr1, corr2, corr3; diff --git a/drivers/edac/skx_common.c b/drivers/edac/skx_common.c index 5e83f59bef8a..19c17c5198c5 100644 --- a/drivers/edac/skx_common.c +++ b/drivers/edac/skx_common.c @@ -345,7 +345,10 @@ int skx_get_dimm_info(u32 mtr, u32 mcmtr, u32 amap, struct dimm_info *dimm, rows = numrow(mtr); cols = imc->hbm_mc ? 6 : numcol(mtr); - if (cfg->support_ddr5 && ((amap & 0x8) || imc->hbm_mc)) { + if (imc->hbm_mc) { + banks = 32; + mtype = MEM_HBM2; + } else if (cfg->support_ddr5 && (amap & 0x8)) { banks = 32; mtype = MEM_DDR5; } else { @@ -529,6 +532,7 @@ static void skx_mce_output_error(struct mem_ctl_info *mci, bool ripv = GET_BITFIELD(m->mcgstatus, 0, 0); bool overflow = GET_BITFIELD(m->status, 62, 62); bool uncorrected_error = GET_BITFIELD(m->status, 61, 61); + bool scrub_err = false; bool recoverable; int len; u32 core_err_cnt = GET_BITFIELD(m->status, 38, 52); @@ -580,6 +584,7 @@ static void skx_mce_output_error(struct mem_ctl_info *mci, break; case 4: optype = "memory scrubbing error"; + scrub_err = true; break; default: optype = "reserved"; @@ -602,7 +607,7 @@ static void skx_mce_output_error(struct mem_ctl_info *mci, } if (skx_show_retry_rd_err_log) - skx_show_retry_rd_err_log(res, skx_msg + len, MSG_SIZE - len); + skx_show_retry_rd_err_log(res, skx_msg + len, MSG_SIZE - len, scrub_err); edac_dbg(0, "%s\n", skx_msg); diff --git a/drivers/edac/skx_common.h b/drivers/edac/skx_common.h index 01f67e731766..03ac067a80b9 100644 --- a/drivers/edac/skx_common.h +++ b/drivers/edac/skx_common.h @@ -80,6 +80,8 @@ struct skx_dev { struct skx_channel { struct pci_dev *cdev; struct pci_dev *edev; + u32 retry_rd_err_log_s; + u32 retry_rd_err_log_d; struct skx_dimm { u8 close_pg; u8 bank_xor_enable; @@ -150,12 +152,15 @@ struct res_config { /* SAD device number and function number */ unsigned int sad_all_devfn; int sad_all_offset; + /* Offsets of retry_rd_err_log registers */ + u32 *offsets_scrub; + u32 *offsets_demand; }; typedef int (*get_dimm_config_f)(struct mem_ctl_info *mci, struct res_config *cfg); typedef bool (*skx_decode_f)(struct decoded_addr *res); -typedef void (*skx_show_retry_log_f)(struct decoded_addr *res, char *msg, int len); +typedef void (*skx_show_retry_log_f)(struct decoded_addr *res, char *msg, int len, bool scrub_err); int __init skx_adxl_get(void); void __exit skx_adxl_put(void); diff --git a/drivers/firmware/efi/cper.c b/drivers/firmware/efi/cper.c index ea7ca74fc173..73bdbd207e7a 100644 --- a/drivers/firmware/efi/cper.c +++ b/drivers/firmware/efi/cper.c @@ -221,7 +221,7 @@ static int cper_mem_err_location(struct cper_mem_err_compact *mem, char *msg) return 0; n = 0; - len = CPER_REC_LEN - 1; + len = CPER_REC_LEN; if (mem->validation_bits & CPER_MEM_VALID_NODE) n += scnprintf(msg + n, len - n, "node: %d ", mem->node); if (mem->validation_bits & CPER_MEM_VALID_CARD) @@ -258,13 +258,12 @@ static int cper_mem_err_location(struct cper_mem_err_compact *mem, char *msg) n += scnprintf(msg + n, len - n, "responder_id: 0x%016llx ", mem->responder_id); if (mem->validation_bits & CPER_MEM_VALID_TARGET_ID) - scnprintf(msg + n, len - n, "target_id: 0x%016llx ", - mem->target_id); + n += scnprintf(msg + n, len - n, "target_id: 0x%016llx ", + mem->target_id); if (mem->validation_bits & CPER_MEM_VALID_CHIP_ID) - scnprintf(msg + n, len - n, "chip_id: %d ", - mem->extended >> CPER_MEM_CHIP_ID_SHIFT); + n += scnprintf(msg + n, len - n, "chip_id: %d ", + mem->extended >> CPER_MEM_CHIP_ID_SHIFT); - msg[n] = '\0'; return n; } @@ -633,7 +632,7 @@ int cper_estatus_check(const struct acpi_hest_generic_status *estatus) data_len = estatus->data_length; apei_estatus_for_each_section(estatus, gdata) { - if (sizeof(struct acpi_hest_generic_data) > data_len) + if (acpi_hest_get_size(gdata) > data_len) return -EINVAL; record_size = acpi_hest_get_record_size(gdata); diff --git a/drivers/firmware/smccc/smccc.c b/drivers/firmware/smccc/smccc.c index 9f937b125ab0..60ccf3e90d7d 100644 --- a/drivers/firmware/smccc/smccc.c +++ b/drivers/firmware/smccc/smccc.c @@ -9,6 +9,7 @@ #include <linux/init.h> #include <linux/arm-smccc.h> #include <linux/kernel.h> +#include <linux/platform_device.h> #include <asm/archrandom.h> static u32 smccc_version = ARM_SMCCC_VERSION_1_0; @@ -42,3 +43,19 @@ u32 arm_smccc_get_version(void) return smccc_version; } EXPORT_SYMBOL_GPL(arm_smccc_get_version); + +static int __init smccc_devices_init(void) +{ + struct platform_device *pdev; + + if (smccc_trng_available) { + pdev = platform_device_register_simple("smccc_trng", -1, + NULL, 0); + if (IS_ERR(pdev)) + pr_err("smccc_trng: could not register device: %ld\n", + PTR_ERR(pdev)); + } + + return 0; +} +device_initcall(smccc_devices_init); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c index 4137e848f6a2..a9ce3b20d371 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c @@ -1040,7 +1040,7 @@ void amdgpu_acpi_detect(void) */ bool amdgpu_acpi_is_s0ix_supported(struct amdgpu_device *adev) { -#if IS_ENABLED(CONFIG_AMD_PMC) && IS_ENABLED(CONFIG_PM_SLEEP) +#if IS_ENABLED(CONFIG_AMD_PMC) && IS_ENABLED(CONFIG_SUSPEND) if (acpi_gbl_FADT.flags & ACPI_FADT_LOW_POWER_S0) { if (adev->flags & AMD_IS_APU) return pm_suspend_target_state == PM_SUSPEND_TO_IDLE; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index f3fd5ec710b6..f944ed858f3e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -2777,12 +2777,11 @@ static void amdgpu_device_delay_enable_gfx_off(struct work_struct *work) struct amdgpu_device *adev = container_of(work, struct amdgpu_device, gfx.gfx_off_delay_work.work); - mutex_lock(&adev->gfx.gfx_off_mutex); - if (!adev->gfx.gfx_off_state && !adev->gfx.gfx_off_req_count) { - if (!amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_GFX, true)) - adev->gfx.gfx_off_state = true; - } - mutex_unlock(&adev->gfx.gfx_off_mutex); + WARN_ON_ONCE(adev->gfx.gfx_off_state); + WARN_ON_ONCE(adev->gfx.gfx_off_req_count); + + if (!amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_GFX, true)) + adev->gfx.gfx_off_state = true; } /** diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c index a0be0772c8b3..b4ced45301be 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gfx.c @@ -563,24 +563,38 @@ void amdgpu_gfx_off_ctrl(struct amdgpu_device *adev, bool enable) mutex_lock(&adev->gfx.gfx_off_mutex); - if (!enable) - adev->gfx.gfx_off_req_count++; - else if (adev->gfx.gfx_off_req_count > 0) + if (enable) { + /* If the count is already 0, it means there's an imbalance bug somewhere. + * Note that the bug may be in a different caller than the one which triggers the + * WARN_ON_ONCE. + */ + if (WARN_ON_ONCE(adev->gfx.gfx_off_req_count == 0)) + goto unlock; + adev->gfx.gfx_off_req_count--; - if (enable && !adev->gfx.gfx_off_state && !adev->gfx.gfx_off_req_count) { - schedule_delayed_work(&adev->gfx.gfx_off_delay_work, GFX_OFF_DELAY_ENABLE); - } else if (!enable && adev->gfx.gfx_off_state) { - if (!amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_GFX, false)) { - adev->gfx.gfx_off_state = false; + if (adev->gfx.gfx_off_req_count == 0 && !adev->gfx.gfx_off_state) + schedule_delayed_work(&adev->gfx.gfx_off_delay_work, GFX_OFF_DELAY_ENABLE); + } else { + if (adev->gfx.gfx_off_req_count == 0) { + cancel_delayed_work_sync(&adev->gfx.gfx_off_delay_work); + + if (adev->gfx.gfx_off_state && + !amdgpu_dpm_set_powergating_by_smu(adev, AMD_IP_BLOCK_TYPE_GFX, false)) { + adev->gfx.gfx_off_state = false; - if (adev->gfx.funcs->init_spm_golden) { - dev_dbg(adev->dev, "GFXOFF is disabled, re-init SPM golden settings\n"); - amdgpu_gfx_init_spm_golden(adev); + if (adev->gfx.funcs->init_spm_golden) { + dev_dbg(adev->dev, + "GFXOFF is disabled, re-init SPM golden settings\n"); + amdgpu_gfx_init_spm_golden(adev); + } } } + + adev->gfx.gfx_off_req_count++; } +unlock: mutex_unlock(&adev->gfx.gfx_off_mutex); } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c index 795fa7445abe..92c8e6e7f346 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c @@ -920,11 +920,6 @@ int amdgpu_bo_pin_restricted(struct amdgpu_bo *bo, u32 domain, return -EINVAL; } - /* This assumes only APU display buffers are pinned with (VRAM|GTT). - * See function amdgpu_display_supported_domains() - */ - domain = amdgpu_bo_get_preferred_pin_domain(adev, domain); - if (bo->tbo.pin_count) { uint32_t mem_type = bo->tbo.resource->mem_type; uint32_t mem_flags = bo->tbo.resource->placement; @@ -949,6 +944,11 @@ int amdgpu_bo_pin_restricted(struct amdgpu_bo *bo, u32 domain, return 0; } + /* This assumes only APU display buffers are pinned with (VRAM|GTT). + * See function amdgpu_display_supported_domains() + */ + domain = amdgpu_bo_get_preferred_pin_domain(adev, domain); + if (bo->tbo.base.import_attach) dma_buf_pin(bo->tbo.base.import_attach); diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c index c7b364e4a287..e883731c3f8f 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_svm.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_svm.c @@ -3026,6 +3026,14 @@ svm_range_get_attr(struct kfd_process *p, uint64_t start, uint64_t size, pr_debug("svms 0x%p [0x%llx 0x%llx] nattr 0x%x\n", &p->svms, start, start + size - 1, nattr); + /* Flush pending deferred work to avoid racing with deferred actions from + * previous memory map changes (e.g. munmap). Concurrent memory map changes + * can still race with get_attr because we don't hold the mmap lock. But that + * would be a race condition in the application anyway, and undefined + * behaviour is acceptable in that case. + */ + flush_work(&p->svms.deferred_list_work); + mmap_read_lock(mm); if (!svm_range_is_valid(mm, start, size)) { pr_debug("invalid range\n"); diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c index 605e297b7a59..a30283fa5173 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc.c @@ -1530,6 +1530,12 @@ void dc_z10_restore(struct dc *dc) if (dc->hwss.z10_restore) dc->hwss.z10_restore(dc); } + +void dc_z10_save_init(struct dc *dc) +{ + if (dc->hwss.z10_save_init) + dc->hwss.z10_save_init(dc); +} #endif /* * Applies given context to HW and copy it into current context. diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_vm_helper.c b/drivers/gpu/drm/amd/display/dc/core/dc_vm_helper.c index f2b39ec35c89..cde8ed2560b3 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_vm_helper.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_vm_helper.c @@ -47,6 +47,9 @@ int dc_setup_system_context(struct dc *dc, struct dc_phy_addr_space_config *pa_c */ memcpy(&dc->vm_pa_config, pa_config, sizeof(struct dc_phy_addr_space_config)); dc->vm_pa_config.valid = true; +#if defined(CONFIG_DRM_AMD_DC_DCN) + dc_z10_save_init(dc); +#endif } return num_vmids; diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index af7b60108e9d..21d78289b048 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -1338,6 +1338,7 @@ void dc_hardware_release(struct dc *dc); bool dc_set_psr_allow_active(struct dc *dc, bool enable); #if defined(CONFIG_DRM_AMD_DC_DCN) void dc_z10_restore(struct dc *dc); +void dc_z10_save_init(struct dc *dc); #endif bool dc_enable_dmub_notifications(struct dc *dc); diff --git a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.c b/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.c index 9776d1737818..912285fdce18 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.c +++ b/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.c @@ -1622,106 +1622,12 @@ static void dcn301_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *b dml_init_instance(&dc->dml, &dcn3_01_soc, &dcn3_01_ip, DML_PROJECT_DCN30); } -static void calculate_wm_set_for_vlevel( - int vlevel, - struct wm_range_table_entry *table_entry, - struct dcn_watermarks *wm_set, - struct display_mode_lib *dml, - display_e2e_pipe_params_st *pipes, - int pipe_cnt) -{ - double dram_clock_change_latency_cached = dml->soc.dram_clock_change_latency_us; - - ASSERT(vlevel < dml->soc.num_states); - /* only pipe 0 is read for voltage and dcf/soc clocks */ - pipes[0].clks_cfg.voltage = vlevel; - pipes[0].clks_cfg.dcfclk_mhz = dml->soc.clock_limits[vlevel].dcfclk_mhz; - pipes[0].clks_cfg.socclk_mhz = dml->soc.clock_limits[vlevel].socclk_mhz; - - dml->soc.dram_clock_change_latency_us = table_entry->pstate_latency_us; - dml->soc.sr_exit_time_us = table_entry->sr_exit_time_us; - dml->soc.sr_enter_plus_exit_time_us = table_entry->sr_enter_plus_exit_time_us; - - wm_set->urgent_ns = get_wm_urgent(dml, pipes, pipe_cnt) * 1000; - wm_set->cstate_pstate.cstate_enter_plus_exit_ns = get_wm_stutter_enter_exit(dml, pipes, pipe_cnt) * 1000; - wm_set->cstate_pstate.cstate_exit_ns = get_wm_stutter_exit(dml, pipes, pipe_cnt) * 1000; - wm_set->cstate_pstate.pstate_change_ns = get_wm_dram_clock_change(dml, pipes, pipe_cnt) * 1000; - wm_set->pte_meta_urgent_ns = get_wm_memory_trip(dml, pipes, pipe_cnt) * 1000; - wm_set->frac_urg_bw_nom = get_fraction_of_urgent_bandwidth(dml, pipes, pipe_cnt) * 1000; - wm_set->frac_urg_bw_flip = get_fraction_of_urgent_bandwidth_imm_flip(dml, pipes, pipe_cnt) * 1000; - wm_set->urgent_latency_ns = get_urgent_latency(dml, pipes, pipe_cnt) * 1000; - dml->soc.dram_clock_change_latency_us = dram_clock_change_latency_cached; - -} - -static void dcn301_calculate_wm_and_dlg( - struct dc *dc, struct dc_state *context, - display_e2e_pipe_params_st *pipes, - int pipe_cnt, - int vlevel_req) -{ - int i, pipe_idx; - int vlevel, vlevel_max; - struct wm_range_table_entry *table_entry; - struct clk_bw_params *bw_params = dc->clk_mgr->bw_params; - - ASSERT(bw_params); - - vlevel_max = bw_params->clk_table.num_entries - 1; - - /* WM Set D */ - table_entry = &bw_params->wm_table.entries[WM_D]; - if (table_entry->wm_type == WM_TYPE_RETRAINING) - vlevel = 0; - else - vlevel = vlevel_max; - calculate_wm_set_for_vlevel(vlevel, table_entry, &context->bw_ctx.bw.dcn.watermarks.d, - &context->bw_ctx.dml, pipes, pipe_cnt); - /* WM Set C */ - table_entry = &bw_params->wm_table.entries[WM_C]; - vlevel = min(max(vlevel_req, 2), vlevel_max); - calculate_wm_set_for_vlevel(vlevel, table_entry, &context->bw_ctx.bw.dcn.watermarks.c, - &context->bw_ctx.dml, pipes, pipe_cnt); - /* WM Set B */ - table_entry = &bw_params->wm_table.entries[WM_B]; - vlevel = min(max(vlevel_req, 1), vlevel_max); - calculate_wm_set_for_vlevel(vlevel, table_entry, &context->bw_ctx.bw.dcn.watermarks.b, - &context->bw_ctx.dml, pipes, pipe_cnt); - - /* WM Set A */ - table_entry = &bw_params->wm_table.entries[WM_A]; - vlevel = min(vlevel_req, vlevel_max); - calculate_wm_set_for_vlevel(vlevel, table_entry, &context->bw_ctx.bw.dcn.watermarks.a, - &context->bw_ctx.dml, pipes, pipe_cnt); - - for (i = 0, pipe_idx = 0; i < dc->res_pool->pipe_count; i++) { - if (!context->res_ctx.pipe_ctx[i].stream) - continue; - - pipes[pipe_idx].clks_cfg.dispclk_mhz = get_dispclk_calculated(&context->bw_ctx.dml, pipes, pipe_cnt); - pipes[pipe_idx].clks_cfg.dppclk_mhz = get_dppclk_calculated(&context->bw_ctx.dml, pipes, pipe_cnt, pipe_idx); - - if (dc->config.forced_clocks) { - pipes[pipe_idx].clks_cfg.dispclk_mhz = context->bw_ctx.dml.soc.clock_limits[0].dispclk_mhz; - pipes[pipe_idx].clks_cfg.dppclk_mhz = context->bw_ctx.dml.soc.clock_limits[0].dppclk_mhz; - } - if (dc->debug.min_disp_clk_khz > pipes[pipe_idx].clks_cfg.dispclk_mhz * 1000) - pipes[pipe_idx].clks_cfg.dispclk_mhz = dc->debug.min_disp_clk_khz / 1000.0; - if (dc->debug.min_dpp_clk_khz > pipes[pipe_idx].clks_cfg.dppclk_mhz * 1000) - pipes[pipe_idx].clks_cfg.dppclk_mhz = dc->debug.min_dpp_clk_khz / 1000.0; - - pipe_idx++; - } - - dcn20_calculate_dlg_params(dc, context, pipes, pipe_cnt, vlevel); -} - static struct resource_funcs dcn301_res_pool_funcs = { .destroy = dcn301_destroy_resource_pool, .link_enc_create = dcn301_link_encoder_create, .panel_cntl_create = dcn301_panel_cntl_create, .validate_bandwidth = dcn30_validate_bandwidth, - .calculate_wm_and_dlg = dcn301_calculate_wm_and_dlg, + .calculate_wm_and_dlg = dcn30_calculate_wm_and_dlg, .update_soc_for_wm_a = dcn30_update_soc_for_wm_a, .populate_dml_pipes = dcn30_populate_dml_pipes_from_context, .acquire_idle_pipe_for_layer = dcn20_acquire_idle_pipe_for_layer, diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c index 6ac6faf0c533..8a2119d8ca0d 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c @@ -404,6 +404,18 @@ void dcn31_update_info_frame(struct pipe_ctx *pipe_ctx) &pipe_ctx->stream_res.encoder_info_frame); } } +void dcn31_z10_save_init(struct dc *dc) +{ + union dmub_rb_cmd cmd; + + memset(&cmd, 0, sizeof(cmd)); + cmd.dcn_restore.header.type = DMUB_CMD__IDLE_OPT; + cmd.dcn_restore.header.sub_type = DMUB_CMD__IDLE_OPT_DCN_SAVE_INIT; + + dc_dmub_srv_cmd_queue(dc->ctx->dmub_srv, &cmd); + dc_dmub_srv_cmd_execute(dc->ctx->dmub_srv); + dc_dmub_srv_wait_idle(dc->ctx->dmub_srv); +} void dcn31_z10_restore(struct dc *dc) { diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.h b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.h index 40dfebe78fdd..140435e4f7ff 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.h +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.h @@ -44,6 +44,7 @@ void dcn31_enable_power_gating_plane( void dcn31_update_info_frame(struct pipe_ctx *pipe_ctx); void dcn31_z10_restore(struct dc *dc); +void dcn31_z10_save_init(struct dc *dc); void dcn31_hubp_pg_control(struct dce_hwseq *hws, unsigned int hubp_inst, bool power_on); int dcn31_init_sys_ctx(struct dce_hwseq *hws, struct dc *dc, struct dc_phy_addr_space_config *pa_config); diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_init.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_init.c index aaf2dbd095fe..b30d923471cb 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_init.c +++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_init.c @@ -97,6 +97,7 @@ static const struct hw_sequencer_funcs dcn31_funcs = { .set_abm_immediate_disable = dcn21_set_abm_immediate_disable, .set_pipe = dcn21_set_pipe, .z10_restore = dcn31_z10_restore, + .z10_save_init = dcn31_z10_save_init, .is_abm_supported = dcn31_is_abm_supported, .set_disp_pattern_generator = dcn30_set_disp_pattern_generator, .update_visual_confirm_color = dcn20_update_visual_confirm_color, diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h index 5ab008e62b82..ad5f2adcc40d 100644 --- a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h +++ b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h @@ -237,6 +237,7 @@ struct hw_sequencer_funcs { int width, int height, int offset); void (*z10_restore)(struct dc *dc); + void (*z10_save_init)(struct dc *dc); void (*update_visual_confirm_color)(struct dc *dc, struct pipe_ctx *pipe_ctx, diff --git a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h index 7c4734f905d9..7fafb8d6c1da 100644 --- a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h +++ b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h @@ -856,6 +856,11 @@ enum dmub_cmd_idle_opt_type { * DCN hardware restore. */ DMUB_CMD__IDLE_OPT_DCN_RESTORE = 0, + + /** + * DCN hardware save. + */ + DMUB_CMD__IDLE_OPT_DCN_SAVE_INIT = 1 }; /** diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_hwmgr.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_hwmgr.c index 25979106fd25..02e8c6e5448d 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_hwmgr.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega10_hwmgr.c @@ -5127,6 +5127,13 @@ static int vega10_get_power_profile_mode(struct pp_hwmgr *hwmgr, char *buf) return size; } +static bool vega10_get_power_profile_mode_quirks(struct pp_hwmgr *hwmgr) +{ + struct amdgpu_device *adev = hwmgr->adev; + + return (adev->pdev->device == 0x6860); +} + static int vega10_set_power_profile_mode(struct pp_hwmgr *hwmgr, long *input, uint32_t size) { struct vega10_hwmgr *data = hwmgr->backend; @@ -5163,9 +5170,15 @@ static int vega10_set_power_profile_mode(struct pp_hwmgr *hwmgr, long *input, ui } out: - smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetWorkloadMask, + if (vega10_get_power_profile_mode_quirks(hwmgr)) + smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetWorkloadMask, + 1 << power_profile_mode, + NULL); + else + smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetWorkloadMask, (!power_profile_mode) ? 0 : 1 << (power_profile_mode - 1), NULL); + hwmgr->power_profile_mode = power_profile_mode; return 0; diff --git a/drivers/gpu/drm/drm_ioc32.c b/drivers/gpu/drm/drm_ioc32.c index d29907955ff7..5d82891c3222 100644 --- a/drivers/gpu/drm/drm_ioc32.c +++ b/drivers/gpu/drm/drm_ioc32.c @@ -855,8 +855,6 @@ static int compat_drm_wait_vblank(struct file *file, unsigned int cmd, req.request.sequence = req32.request.sequence; req.request.signal = req32.request.signal; err = drm_ioctl_kernel(file, drm_wait_vblank_ioctl, &req, DRM_UNLOCKED); - if (err) - return err; req32.reply.type = req.reply.type; req32.reply.sequence = req.reply.sequence; @@ -865,7 +863,7 @@ static int compat_drm_wait_vblank(struct file *file, unsigned int cmd, if (copy_to_user(argp, &req32, sizeof(req32))) return -EFAULT; - return 0; + return err; } #if defined(CONFIG_X86) diff --git a/drivers/gpu/drm/i915/display/intel_ddi.c b/drivers/gpu/drm/i915/display/intel_ddi.c index be716b56e8e0..00dade49665b 100644 --- a/drivers/gpu/drm/i915/display/intel_ddi.c +++ b/drivers/gpu/drm/i915/display/intel_ddi.c @@ -2463,6 +2463,15 @@ static void intel_ddi_power_up_lanes(struct intel_encoder *encoder, } } +/* Splitter enable for eDP MSO is limited to certain pipes. */ +static u8 intel_ddi_splitter_pipe_mask(struct drm_i915_private *i915) +{ + if (IS_ALDERLAKE_P(i915)) + return BIT(PIPE_A) | BIT(PIPE_B); + else + return BIT(PIPE_A); +} + static void intel_ddi_mso_get_config(struct intel_encoder *encoder, struct intel_crtc_state *pipe_config) { @@ -2480,8 +2489,7 @@ static void intel_ddi_mso_get_config(struct intel_encoder *encoder, if (!pipe_config->splitter.enable) return; - /* Splitter enable is supported for pipe A only. */ - if (drm_WARN_ON(&i915->drm, pipe != PIPE_A)) { + if (drm_WARN_ON(&i915->drm, !(intel_ddi_splitter_pipe_mask(i915) & BIT(pipe)))) { pipe_config->splitter.enable = false; return; } @@ -2513,10 +2521,6 @@ static void intel_ddi_mso_configure(const struct intel_crtc_state *crtc_state) return; if (crtc_state->splitter.enable) { - /* Splitter enable is supported for pipe A only. */ - if (drm_WARN_ON(&i915->drm, pipe != PIPE_A)) - return; - dss1 |= SPLITTER_ENABLE; dss1 |= OVERLAP_PIXELS(crtc_state->splitter.pixel_overlap); if (crtc_state->splitter.link_count == 2) @@ -4743,12 +4747,8 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port) dig_port->hpd_pulse = intel_dp_hpd_pulse; - /* Splitter enable for eDP MSO is limited to certain pipes. */ - if (dig_port->dp.mso_link_count) { - encoder->pipe_mask = BIT(PIPE_A); - if (IS_ALDERLAKE_P(dev_priv)) - encoder->pipe_mask |= BIT(PIPE_B); - } + if (dig_port->dp.mso_link_count) + encoder->pipe_mask = intel_ddi_splitter_pipe_mask(dev_priv); } /* In theory we don't need the encoder->type check, but leave it just in diff --git a/drivers/gpu/drm/i915/display/intel_display_power.c b/drivers/gpu/drm/i915/display/intel_display_power.c index 4298ae684d7d..86b7ac7b65ec 100644 --- a/drivers/gpu/drm/i915/display/intel_display_power.c +++ b/drivers/gpu/drm/i915/display/intel_display_power.c @@ -6387,13 +6387,13 @@ void intel_display_power_suspend_late(struct drm_i915_private *i915) if (DISPLAY_VER(i915) >= 11 || IS_GEMINILAKE(i915) || IS_BROXTON(i915)) { bxt_enable_dc9(i915); - /* Tweaked Wa_14010685332:icp,jsp,mcc */ - if (INTEL_PCH_TYPE(i915) >= PCH_ICP && INTEL_PCH_TYPE(i915) <= PCH_MCC) - intel_de_rmw(i915, SOUTH_CHICKEN1, - SBCLK_RUN_REFCLK_DIS, SBCLK_RUN_REFCLK_DIS); } else if (IS_HASWELL(i915) || IS_BROADWELL(i915)) { hsw_enable_pc8(i915); } + + /* Tweaked Wa_14010685332:cnp,icp,jsp,mcc,tgp,adp */ + if (INTEL_PCH_TYPE(i915) >= PCH_CNP && INTEL_PCH_TYPE(i915) < PCH_DG1) + intel_de_rmw(i915, SOUTH_CHICKEN1, SBCLK_RUN_REFCLK_DIS, SBCLK_RUN_REFCLK_DIS); } void intel_display_power_resume_early(struct drm_i915_private *i915) @@ -6402,13 +6402,13 @@ void intel_display_power_resume_early(struct drm_i915_private *i915) IS_BROXTON(i915)) { gen9_sanitize_dc_state(i915); bxt_disable_dc9(i915); - /* Tweaked Wa_14010685332:icp,jsp,mcc */ - if (INTEL_PCH_TYPE(i915) >= PCH_ICP && INTEL_PCH_TYPE(i915) <= PCH_MCC) - intel_de_rmw(i915, SOUTH_CHICKEN1, SBCLK_RUN_REFCLK_DIS, 0); - } else if (IS_HASWELL(i915) || IS_BROADWELL(i915)) { hsw_disable_pc8(i915); } + + /* Tweaked Wa_14010685332:cnp,icp,jsp,mcc,tgp,adp */ + if (INTEL_PCH_TYPE(i915) >= PCH_CNP && INTEL_PCH_TYPE(i915) < PCH_DG1) + intel_de_rmw(i915, SOUTH_CHICKEN1, SBCLK_RUN_REFCLK_DIS, 0); } void intel_display_power_suspend(struct drm_i915_private *i915) diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c index 6cc03b9e4321..862c1df69cc2 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -3850,23 +3850,18 @@ static void intel_dp_check_device_service_irq(struct intel_dp *intel_dp) static void intel_dp_check_link_service_irq(struct intel_dp *intel_dp) { - struct drm_i915_private *i915 = dp_to_i915(intel_dp); u8 val; if (intel_dp->dpcd[DP_DPCD_REV] < 0x11) return; if (drm_dp_dpcd_readb(&intel_dp->aux, - DP_LINK_SERVICE_IRQ_VECTOR_ESI0, &val) != 1 || !val) { - drm_dbg_kms(&i915->drm, "Error in reading link service irq vector\n"); + DP_LINK_SERVICE_IRQ_VECTOR_ESI0, &val) != 1 || !val) return; - } if (drm_dp_dpcd_writeb(&intel_dp->aux, - DP_LINK_SERVICE_IRQ_VECTOR_ESI0, val) != 1) { - drm_dbg_kms(&i915->drm, "Error in writing link service irq vector\n"); + DP_LINK_SERVICE_IRQ_VECTOR_ESI0, val) != 1) return; - } if (val & HDMI_LINK_STATUS_CHANGED) intel_dp_handle_hdmi_link_status_change(intel_dp); diff --git a/drivers/gpu/drm/i915/display/intel_dp_link_training.c b/drivers/gpu/drm/i915/display/intel_dp_link_training.c index 08bceae40aa8..053a3c2f7267 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_link_training.c +++ b/drivers/gpu/drm/i915/display/intel_dp_link_training.c @@ -206,7 +206,6 @@ int intel_dp_init_lttpr_and_dprx_caps(struct intel_dp *intel_dp) return lttpr_count; } -EXPORT_SYMBOL(intel_dp_init_lttpr_and_dprx_caps); static u8 dp_voltage_max(u8 preemph) { diff --git a/drivers/gpu/drm/i915/gt/intel_timeline.c b/drivers/gpu/drm/i915/gt/intel_timeline.c index c4a126c8caef..1257f4f11e66 100644 --- a/drivers/gpu/drm/i915/gt/intel_timeline.c +++ b/drivers/gpu/drm/i915/gt/intel_timeline.c @@ -127,6 +127,15 @@ static void intel_timeline_fini(struct rcu_head *rcu) i915_vma_put(timeline->hwsp_ggtt); i915_active_fini(&timeline->active); + + /* + * A small race exists between intel_gt_retire_requests_timeout and + * intel_timeline_exit which could result in the syncmap not getting + * free'd. Rather than work to hard to seal this race, simply cleanup + * the syncmap on fini. + */ + i915_syncmap_free(&timeline->sync); + kfree(timeline); } diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index c03943198089..c3816f5c6900 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -3064,24 +3064,6 @@ static void valleyview_irq_reset(struct drm_i915_private *dev_priv) spin_unlock_irq(&dev_priv->irq_lock); } -static void cnp_display_clock_wa(struct drm_i915_private *dev_priv) -{ - struct intel_uncore *uncore = &dev_priv->uncore; - - /* - * Wa_14010685332:cnp/cmp,tgp,adp - * TODO: Clarify which platforms this applies to - * TODO: Figure out if this workaround can be applied in the s0ix suspend/resume handlers as - * on earlier platforms and whether the workaround is also needed for runtime suspend/resume - */ - if (INTEL_PCH_TYPE(dev_priv) == PCH_CNP || - (INTEL_PCH_TYPE(dev_priv) >= PCH_TGP && INTEL_PCH_TYPE(dev_priv) < PCH_DG1)) { - intel_uncore_rmw(uncore, SOUTH_CHICKEN1, SBCLK_RUN_REFCLK_DIS, - SBCLK_RUN_REFCLK_DIS); - intel_uncore_rmw(uncore, SOUTH_CHICKEN1, SBCLK_RUN_REFCLK_DIS, 0); - } -} - static void gen8_display_irq_reset(struct drm_i915_private *dev_priv) { struct intel_uncore *uncore = &dev_priv->uncore; @@ -3115,7 +3097,6 @@ static void gen8_irq_reset(struct drm_i915_private *dev_priv) if (HAS_PCH_SPLIT(dev_priv)) ibx_irq_reset(dev_priv); - cnp_display_clock_wa(dev_priv); } static void gen11_display_irq_reset(struct drm_i915_private *dev_priv) @@ -3159,8 +3140,6 @@ static void gen11_display_irq_reset(struct drm_i915_private *dev_priv) if (INTEL_PCH_TYPE(dev_priv) >= PCH_ICP) GEN3_IRQ_RESET(uncore, SDE); - - cnp_display_clock_wa(dev_priv); } static void gen11_irq_reset(struct drm_i915_private *dev_priv) diff --git a/drivers/gpu/drm/imx/ipuv3-plane.c b/drivers/gpu/drm/imx/ipuv3-plane.c index 8710f55d2579..bd1f9f0366d3 100644 --- a/drivers/gpu/drm/imx/ipuv3-plane.c +++ b/drivers/gpu/drm/imx/ipuv3-plane.c @@ -683,7 +683,7 @@ static void ipu_plane_atomic_update(struct drm_plane *plane, break; } - ipu_dmfc_config_wait4eot(ipu_plane->dmfc, drm_rect_width(dst)); + ipu_dmfc_config_wait4eot(ipu_plane->dmfc, ALIGN(drm_rect_width(dst), 8)); width = ipu_src_rect_width(new_state); height = drm_rect_height(&new_state->src) >> 16; diff --git a/drivers/gpu/drm/mediatek/mtk_disp_color.c b/drivers/gpu/drm/mediatek/mtk_disp_color.c index 6f4c80bbc0eb..473f5bb5cbad 100644 --- a/drivers/gpu/drm/mediatek/mtk_disp_color.c +++ b/drivers/gpu/drm/mediatek/mtk_disp_color.c @@ -133,6 +133,8 @@ static int mtk_disp_color_probe(struct platform_device *pdev) static int mtk_disp_color_remove(struct platform_device *pdev) { + component_del(&pdev->dev, &mtk_disp_color_component_ops); + return 0; } diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c index fa9d79963cd3..5326989d5206 100644 --- a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c +++ b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c @@ -423,6 +423,8 @@ static int mtk_disp_ovl_probe(struct platform_device *pdev) static int mtk_disp_ovl_remove(struct platform_device *pdev) { + component_del(&pdev->dev, &mtk_disp_ovl_component_ops); + return 0; } diff --git a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c index 75bc00e17fc4..50d20562e612 100644 --- a/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c +++ b/drivers/gpu/drm/mediatek/mtk_drm_ddp_comp.c @@ -34,6 +34,7 @@ #define DISP_AAL_EN 0x0000 #define DISP_AAL_SIZE 0x0030 +#define DISP_AAL_OUTPUT_SIZE 0x04d8 #define DISP_DITHER_EN 0x0000 #define DITHER_EN BIT(0) @@ -197,6 +198,7 @@ static void mtk_aal_config(struct device *dev, unsigned int w, struct mtk_ddp_comp_dev *priv = dev_get_drvdata(dev); mtk_ddp_write(cmdq_pkt, w << 16 | h, &priv->cmdq_reg, priv->regs, DISP_AAL_SIZE); + mtk_ddp_write(cmdq_pkt, w << 16 | h, &priv->cmdq_reg, priv->regs, DISP_AAL_OUTPUT_SIZE); } static void mtk_aal_gamma_set(struct device *dev, struct drm_crtc_state *state) diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c index f949767698fc..bcb0310a41b6 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/disp.c +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c @@ -2237,6 +2237,33 @@ nv50_disp_atomic_commit_tail(struct drm_atomic_state *state) interlock[NV50_DISP_INTERLOCK_CORE] = 0; } + /* Finish updating head(s)... + * + * NVD is rather picky about both where window assignments can change, + * *and* about certain core and window channel states matching. + * + * The EFI GOP driver on newer GPUs configures window channels with a + * different output format to what we do, and the core channel update + * in the assign_windows case above would result in a state mismatch. + * + * Delay some of the head update until after that point to workaround + * the issue. This only affects the initial modeset. + * + * TODO: handle this better when adding flexible window mapping + */ + for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { + struct nv50_head_atom *asyh = nv50_head_atom(new_crtc_state); + struct nv50_head *head = nv50_head(crtc); + + NV_ATOMIC(drm, "%s: set %04x (clr %04x)\n", crtc->name, + asyh->set.mask, asyh->clr.mask); + + if (asyh->set.mask) { + nv50_head_flush_set_wndw(head, asyh); + interlock[NV50_DISP_INTERLOCK_CORE] = 1; + } + } + /* Update plane(s). */ for_each_new_plane_in_state(state, plane, new_plane_state, i) { struct nv50_wndw_atom *asyw = nv50_wndw_atom(new_plane_state); diff --git a/drivers/gpu/drm/nouveau/dispnv50/head.c b/drivers/gpu/drm/nouveau/dispnv50/head.c index ec361d17e900..d66f97280282 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/head.c +++ b/drivers/gpu/drm/nouveau/dispnv50/head.c @@ -50,11 +50,8 @@ nv50_head_flush_clr(struct nv50_head *head, } void -nv50_head_flush_set(struct nv50_head *head, struct nv50_head_atom *asyh) +nv50_head_flush_set_wndw(struct nv50_head *head, struct nv50_head_atom *asyh) { - if (asyh->set.view ) head->func->view (head, asyh); - if (asyh->set.mode ) head->func->mode (head, asyh); - if (asyh->set.core ) head->func->core_set(head, asyh); if (asyh->set.olut ) { asyh->olut.offset = nv50_lut_load(&head->olut, asyh->olut.buffer, @@ -62,6 +59,14 @@ nv50_head_flush_set(struct nv50_head *head, struct nv50_head_atom *asyh) asyh->olut.load); head->func->olut_set(head, asyh); } +} + +void +nv50_head_flush_set(struct nv50_head *head, struct nv50_head_atom *asyh) +{ + if (asyh->set.view ) head->func->view (head, asyh); + if (asyh->set.mode ) head->func->mode (head, asyh); + if (asyh->set.core ) head->func->core_set(head, asyh); if (asyh->set.curs ) head->func->curs_set(head, asyh); if (asyh->set.base ) head->func->base (head, asyh); if (asyh->set.ovly ) head->func->ovly (head, asyh); diff --git a/drivers/gpu/drm/nouveau/dispnv50/head.h b/drivers/gpu/drm/nouveau/dispnv50/head.h index dae841dc05fd..0bac6be9ba34 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/head.h +++ b/drivers/gpu/drm/nouveau/dispnv50/head.h @@ -21,6 +21,7 @@ struct nv50_head { struct nv50_head *nv50_head_create(struct drm_device *, int index); void nv50_head_flush_set(struct nv50_head *head, struct nv50_head_atom *asyh); +void nv50_head_flush_set_wndw(struct nv50_head *head, struct nv50_head_atom *asyh); void nv50_head_flush_clr(struct nv50_head *head, struct nv50_head_atom *asyh, bool flush); diff --git a/drivers/gpu/drm/nouveau/include/nvif/cl0080.h b/drivers/gpu/drm/nouveau/include/nvif/cl0080.h index 0b86c44878e0..59759c4fb62e 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/cl0080.h +++ b/drivers/gpu/drm/nouveau/include/nvif/cl0080.h @@ -4,7 +4,8 @@ struct nv_device_v0 { __u8 version; - __u8 pad01[7]; + __u8 priv; + __u8 pad02[6]; __u64 device; /* device identifier, ~0 for client default */ }; diff --git a/drivers/gpu/drm/nouveau/include/nvif/class.h b/drivers/gpu/drm/nouveau/include/nvif/class.h index ba2c28ea43d2..c68cc957248e 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/class.h +++ b/drivers/gpu/drm/nouveau/include/nvif/class.h @@ -61,8 +61,6 @@ #define NV10_CHANNEL_DMA /* cl506b.h */ 0x0000006e #define NV17_CHANNEL_DMA /* cl506b.h */ 0x0000176e #define NV40_CHANNEL_DMA /* cl506b.h */ 0x0000406e -#define NV50_CHANNEL_DMA /* cl506e.h */ 0x0000506e -#define G82_CHANNEL_DMA /* cl826e.h */ 0x0000826e #define NV50_CHANNEL_GPFIFO /* cl506f.h */ 0x0000506f #define G82_CHANNEL_GPFIFO /* cl826f.h */ 0x0000826f diff --git a/drivers/gpu/drm/nouveau/include/nvif/client.h b/drivers/gpu/drm/nouveau/include/nvif/client.h index 347d2c020bd1..5d9395e651b6 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/client.h +++ b/drivers/gpu/drm/nouveau/include/nvif/client.h @@ -9,7 +9,6 @@ struct nvif_client { const struct nvif_driver *driver; u64 version; u8 route; - bool super; }; int nvif_client_ctor(struct nvif_client *parent, const char *name, u64 device, diff --git a/drivers/gpu/drm/nouveau/include/nvif/driver.h b/drivers/gpu/drm/nouveau/include/nvif/driver.h index 8e85b936eaa0..7a3af05f7f98 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/driver.h +++ b/drivers/gpu/drm/nouveau/include/nvif/driver.h @@ -11,7 +11,7 @@ struct nvif_driver { void (*fini)(void *priv); int (*suspend)(void *priv); int (*resume)(void *priv); - int (*ioctl)(void *priv, bool super, void *data, u32 size, void **hack); + int (*ioctl)(void *priv, void *data, u32 size, void **hack); void __iomem *(*map)(void *priv, u64 handle, u32 size); void (*unmap)(void *priv, void __iomem *ptr, u32 size); bool keep; diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/client.h b/drivers/gpu/drm/nouveau/include/nvkm/core/client.h index 5d7017fe5039..2f86606e708c 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/client.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/client.h @@ -13,7 +13,6 @@ struct nvkm_client { struct nvkm_client_notify *notify[32]; struct rb_root objroot; - bool super; void *data; int (*ntfy)(const void *, u32, const void *, u32); diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/ioctl.h b/drivers/gpu/drm/nouveau/include/nvkm/core/ioctl.h index 71ed147ad077..f52918a43246 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/ioctl.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/ioctl.h @@ -4,5 +4,5 @@ #include <core/os.h> struct nvkm_client; -int nvkm_ioctl(struct nvkm_client *, bool, void *, u32, void **); +int nvkm_ioctl(struct nvkm_client *, void *, u32, void **); #endif diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/mmu.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/mmu.h index 0911e73f7424..70e7887ef4b4 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/mmu.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/mmu.h @@ -15,7 +15,6 @@ struct nvkm_vma { u8 refd:3; /* Current page type (index, or NONE for unreferenced). */ bool used:1; /* Region allocated. */ bool part:1; /* Region was split from an allocated region by map(). */ - bool user:1; /* Region user-allocated. */ bool busy:1; /* Region busy (for temporarily preventing user access). */ bool mapped:1; /* Region contains valid pages. */ struct nvkm_memory *memory; /* Memory currently mapped into VMA. */ diff --git a/drivers/gpu/drm/nouveau/nouveau_abi16.c b/drivers/gpu/drm/nouveau/nouveau_abi16.c index b45ec3086285..4107b7006539 100644 --- a/drivers/gpu/drm/nouveau/nouveau_abi16.c +++ b/drivers/gpu/drm/nouveau/nouveau_abi16.c @@ -570,11 +570,9 @@ nouveau_abi16_ioctl_notifierobj_alloc(ABI16_IOCTL_ARGS) } client->route = NVDRM_OBJECT_ABI16; - client->super = true; ret = nvif_object_ctor(&chan->chan->user, "abi16Ntfy", info->handle, NV_DMA_IN_MEMORY, &args, sizeof(args), &ntfy->object); - client->super = false; client->route = NVDRM_OBJECT_NVIF; if (ret) goto done; diff --git a/drivers/gpu/drm/nouveau/nouveau_chan.c b/drivers/gpu/drm/nouveau/nouveau_chan.c index 40362600eed2..80099ef75702 100644 --- a/drivers/gpu/drm/nouveau/nouveau_chan.c +++ b/drivers/gpu/drm/nouveau/nouveau_chan.c @@ -86,12 +86,6 @@ nouveau_channel_del(struct nouveau_channel **pchan) struct nouveau_channel *chan = *pchan; if (chan) { struct nouveau_cli *cli = (void *)chan->user.client; - bool super; - - if (cli) { - super = cli->base.super; - cli->base.super = true; - } if (chan->fence) nouveau_fence(chan->drm)->context_del(chan); @@ -111,9 +105,6 @@ nouveau_channel_del(struct nouveau_channel **pchan) nouveau_bo_unpin(chan->push.buffer); nouveau_bo_ref(NULL, &chan->push.buffer); kfree(chan); - - if (cli) - cli->base.super = super; } *pchan = NULL; } @@ -512,20 +503,16 @@ nouveau_channel_new(struct nouveau_drm *drm, struct nvif_device *device, struct nouveau_channel **pchan) { struct nouveau_cli *cli = (void *)device->object.client; - bool super; int ret; /* hack until fencenv50 is fixed, and agp access relaxed */ - super = cli->base.super; - cli->base.super = true; - ret = nouveau_channel_ind(drm, device, arg0, priv, pchan); if (ret) { NV_PRINTK(dbg, cli, "ib channel create, %d\n", ret); ret = nouveau_channel_dma(drm, device, pchan); if (ret) { NV_PRINTK(dbg, cli, "dma channel create, %d\n", ret); - goto done; + return ret; } } @@ -533,15 +520,13 @@ nouveau_channel_new(struct nouveau_drm *drm, struct nvif_device *device, if (ret) { NV_PRINTK(err, cli, "channel failed to initialise, %d\n", ret); nouveau_channel_del(pchan); - goto done; + return ret; } ret = nouveau_svmm_join((*pchan)->vmm->svmm, (*pchan)->inst); if (ret) nouveau_channel_del(pchan); -done: - cli->base.super = super; return ret; } diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index a616cf4573b8..ba4cd5f83725 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -244,6 +244,7 @@ nouveau_cli_init(struct nouveau_drm *drm, const char *sname, ret = nvif_device_ctor(&cli->base.object, "drmDevice", 0, NV_DEVICE, &(struct nv_device_v0) { .device = ~0, + .priv = true, }, sizeof(struct nv_device_v0), &cli->device); if (ret) { @@ -1086,8 +1087,6 @@ nouveau_drm_open(struct drm_device *dev, struct drm_file *fpriv) if (ret) goto done; - cli->base.super = false; - fpriv->driver_priv = cli; mutex_lock(&drm->client.mutex); diff --git a/drivers/gpu/drm/nouveau/nouveau_mem.c b/drivers/gpu/drm/nouveau/nouveau_mem.c index 0de6549fb875..2ca3207c13fc 100644 --- a/drivers/gpu/drm/nouveau/nouveau_mem.c +++ b/drivers/gpu/drm/nouveau/nouveau_mem.c @@ -41,8 +41,6 @@ nouveau_mem_map(struct nouveau_mem *mem, struct gf100_vmm_map_v0 gf100; } args; u32 argc = 0; - bool super; - int ret; switch (vmm->object.oclass) { case NVIF_CLASS_VMM_NV04: @@ -73,12 +71,7 @@ nouveau_mem_map(struct nouveau_mem *mem, return -ENOSYS; } - super = vmm->object.client->super; - vmm->object.client->super = true; - ret = nvif_vmm_map(vmm, vma->addr, mem->mem.size, &args, argc, - &mem->mem, 0); - vmm->object.client->super = super; - return ret; + return nvif_vmm_map(vmm, vma->addr, mem->mem.size, &args, argc, &mem->mem, 0); } void @@ -99,7 +92,6 @@ nouveau_mem_host(struct ttm_resource *reg, struct ttm_tt *tt) struct nouveau_drm *drm = cli->drm; struct nvif_mmu *mmu = &cli->mmu; struct nvif_mem_ram_v0 args = {}; - bool super = cli->base.super; u8 type; int ret; @@ -122,11 +114,9 @@ nouveau_mem_host(struct ttm_resource *reg, struct ttm_tt *tt) args.dma = tt->dma_address; mutex_lock(&drm->master.lock); - cli->base.super = true; ret = nvif_mem_ctor_type(mmu, "ttmHostMem", cli->mem->oclass, type, PAGE_SHIFT, reg->num_pages << PAGE_SHIFT, &args, sizeof(args), &mem->mem); - cli->base.super = super; mutex_unlock(&drm->master.lock); return ret; } @@ -138,12 +128,10 @@ nouveau_mem_vram(struct ttm_resource *reg, bool contig, u8 page) struct nouveau_cli *cli = mem->cli; struct nouveau_drm *drm = cli->drm; struct nvif_mmu *mmu = &cli->mmu; - bool super = cli->base.super; u64 size = ALIGN(reg->num_pages << PAGE_SHIFT, 1 << page); int ret; mutex_lock(&drm->master.lock); - cli->base.super = true; switch (cli->mem->oclass) { case NVIF_CLASS_MEM_GF100: ret = nvif_mem_ctor_type(mmu, "ttmVram", cli->mem->oclass, @@ -167,7 +155,6 @@ nouveau_mem_vram(struct ttm_resource *reg, bool contig, u8 page) WARN_ON(1); break; } - cli->base.super = super; mutex_unlock(&drm->master.lock); reg->start = mem->mem.addr >> PAGE_SHIFT; diff --git a/drivers/gpu/drm/nouveau/nouveau_nvif.c b/drivers/gpu/drm/nouveau/nouveau_nvif.c index b3f29b1ce9ea..52f5793b7274 100644 --- a/drivers/gpu/drm/nouveau/nouveau_nvif.c +++ b/drivers/gpu/drm/nouveau/nouveau_nvif.c @@ -52,9 +52,9 @@ nvkm_client_map(void *priv, u64 handle, u32 size) } static int -nvkm_client_ioctl(void *priv, bool super, void *data, u32 size, void **hack) +nvkm_client_ioctl(void *priv, void *data, u32 size, void **hack) { - return nvkm_ioctl(priv, super, data, size, hack); + return nvkm_ioctl(priv, data, size, hack); } static int diff --git a/drivers/gpu/drm/nouveau/nouveau_svm.c b/drivers/gpu/drm/nouveau/nouveau_svm.c index 82b583f5fca8..b0c3422cb01f 100644 --- a/drivers/gpu/drm/nouveau/nouveau_svm.c +++ b/drivers/gpu/drm/nouveau/nouveau_svm.c @@ -237,14 +237,11 @@ void nouveau_svmm_invalidate(struct nouveau_svmm *svmm, u64 start, u64 limit) { if (limit > start) { - bool super = svmm->vmm->vmm.object.client->super; - svmm->vmm->vmm.object.client->super = true; nvif_object_mthd(&svmm->vmm->vmm.object, NVIF_VMM_V0_PFNCLR, &(struct nvif_vmm_pfnclr_v0) { .addr = start, .size = limit - start, }, sizeof(struct nvif_vmm_pfnclr_v0)); - svmm->vmm->vmm.object.client->super = super; } } @@ -634,9 +631,7 @@ static int nouveau_atomic_range_fault(struct nouveau_svmm *svmm, NVIF_VMM_PFNMAP_V0_A | NVIF_VMM_PFNMAP_V0_HOST; - svmm->vmm->vmm.object.client->super = true; ret = nvif_object_ioctl(&svmm->vmm->vmm.object, args, size, NULL); - svmm->vmm->vmm.object.client->super = false; mutex_unlock(&svmm->mutex); unlock_page(page); @@ -702,9 +697,7 @@ static int nouveau_range_fault(struct nouveau_svmm *svmm, nouveau_hmm_convert_pfn(drm, &range, args); - svmm->vmm->vmm.object.client->super = true; ret = nvif_object_ioctl(&svmm->vmm->vmm.object, args, size, NULL); - svmm->vmm->vmm.object.client->super = false; mutex_unlock(&svmm->mutex); out: @@ -928,10 +921,8 @@ nouveau_pfns_map(struct nouveau_svmm *svmm, struct mm_struct *mm, mutex_lock(&svmm->mutex); - svmm->vmm->vmm.object.client->super = true; ret = nvif_object_ioctl(&svmm->vmm->vmm.object, args, sizeof(*args) + npages * sizeof(args->p.phys[0]), NULL); - svmm->vmm->vmm.object.client->super = false; mutex_unlock(&svmm->mutex); } diff --git a/drivers/gpu/drm/nouveau/nouveau_usif.c b/drivers/gpu/drm/nouveau/nouveau_usif.c index 9dc10b17ad34..5da1f4d223d7 100644 --- a/drivers/gpu/drm/nouveau/nouveau_usif.c +++ b/drivers/gpu/drm/nouveau/nouveau_usif.c @@ -32,6 +32,9 @@ #include <nvif/event.h> #include <nvif/ioctl.h> +#include <nvif/class.h> +#include <nvif/cl0080.h> + struct usif_notify_p { struct drm_pending_event base; struct { @@ -261,7 +264,7 @@ usif_object_dtor(struct usif_object *object) } static int -usif_object_new(struct drm_file *f, void *data, u32 size, void *argv, u32 argc) +usif_object_new(struct drm_file *f, void *data, u32 size, void *argv, u32 argc, bool parent_abi16) { struct nouveau_cli *cli = nouveau_cli(f); struct nvif_client *client = &cli->base; @@ -271,23 +274,48 @@ usif_object_new(struct drm_file *f, void *data, u32 size, void *argv, u32 argc) struct usif_object *object; int ret = -ENOSYS; + if ((ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) + return ret; + + switch (args->v0.oclass) { + case NV_DMA_FROM_MEMORY: + case NV_DMA_TO_MEMORY: + case NV_DMA_IN_MEMORY: + return -EINVAL; + case NV_DEVICE: { + union { + struct nv_device_v0 v0; + } *args = data; + + if ((ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) + return ret; + + args->v0.priv = false; + break; + } + default: + if (!parent_abi16) + return -EINVAL; + break; + } + if (!(object = kmalloc(sizeof(*object), GFP_KERNEL))) return -ENOMEM; list_add(&object->head, &cli->objects); - if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) { - object->route = args->v0.route; - object->token = args->v0.token; - args->v0.route = NVDRM_OBJECT_USIF; - args->v0.token = (unsigned long)(void *)object; - ret = nvif_client_ioctl(client, argv, argc); - args->v0.token = object->token; - args->v0.route = object->route; + object->route = args->v0.route; + object->token = args->v0.token; + args->v0.route = NVDRM_OBJECT_USIF; + args->v0.token = (unsigned long)(void *)object; + ret = nvif_client_ioctl(client, argv, argc); + if (ret) { + usif_object_dtor(object); + return ret; } - if (ret) - usif_object_dtor(object); - return ret; + args->v0.token = object->token; + args->v0.route = object->route; + return 0; } int @@ -301,6 +329,7 @@ usif_ioctl(struct drm_file *filp, void __user *user, u32 argc) struct nvif_ioctl_v0 v0; } *argv = data; struct usif_object *object; + bool abi16 = false; u8 owner; int ret; @@ -331,11 +360,13 @@ usif_ioctl(struct drm_file *filp, void __user *user, u32 argc) mutex_unlock(&cli->mutex); goto done; } + + abi16 = true; } switch (argv->v0.type) { case NVIF_IOCTL_V0_NEW: - ret = usif_object_new(filp, data, size, argv, argc); + ret = usif_object_new(filp, data, size, argv, argc, abi16); break; case NVIF_IOCTL_V0_NTFY_NEW: ret = usif_notify_new(filp, data, size, argv, argc); diff --git a/drivers/gpu/drm/nouveau/nvif/client.c b/drivers/gpu/drm/nouveau/nvif/client.c index 12644f811b3e..a3264a0e933a 100644 --- a/drivers/gpu/drm/nouveau/nvif/client.c +++ b/drivers/gpu/drm/nouveau/nvif/client.c @@ -32,7 +32,7 @@ int nvif_client_ioctl(struct nvif_client *client, void *data, u32 size) { - return client->driver->ioctl(client->object.priv, client->super, data, size, NULL); + return client->driver->ioctl(client->object.priv, data, size, NULL); } int @@ -80,7 +80,6 @@ nvif_client_ctor(struct nvif_client *parent, const char *name, u64 device, client->object.client = client; client->object.handle = ~0; client->route = NVIF_IOCTL_V0_ROUTE_NVIF; - client->super = true; client->driver = parent->driver; if (ret == 0) { diff --git a/drivers/gpu/drm/nouveau/nvif/object.c b/drivers/gpu/drm/nouveau/nvif/object.c index 671a5c0199e0..dce1ecee2af5 100644 --- a/drivers/gpu/drm/nouveau/nvif/object.c +++ b/drivers/gpu/drm/nouveau/nvif/object.c @@ -44,8 +44,7 @@ nvif_object_ioctl(struct nvif_object *object, void *data, u32 size, void **hack) } else return -ENOSYS; - return client->driver->ioctl(client->object.priv, client->super, - data, size, hack); + return client->driver->ioctl(client->object.priv, data, size, hack); } void diff --git a/drivers/gpu/drm/nouveau/nvkm/core/ioctl.c b/drivers/gpu/drm/nouveau/nvkm/core/ioctl.c index d777df5a64e6..735cb6816f10 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/ioctl.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/ioctl.c @@ -426,8 +426,7 @@ nvkm_ioctl_path(struct nvkm_client *client, u64 handle, u32 type, } int -nvkm_ioctl(struct nvkm_client *client, bool supervisor, - void *data, u32 size, void **hack) +nvkm_ioctl(struct nvkm_client *client, void *data, u32 size, void **hack) { struct nvkm_object *object = &client->object; union { @@ -435,7 +434,6 @@ nvkm_ioctl(struct nvkm_client *client, bool supervisor, } *args = data; int ret = -ENOSYS; - client->super = supervisor; nvif_ioctl(object, "size %d\n", size); if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, true))) { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index b930f539feec..93ddf63d1114 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -2624,6 +2624,26 @@ nv174_chipset = { .dma = { 0x00000001, gv100_dma_new }, }; +static const struct nvkm_device_chip +nv177_chipset = { + .name = "GA107", + .bar = { 0x00000001, tu102_bar_new }, + .bios = { 0x00000001, nvkm_bios_new }, + .devinit = { 0x00000001, ga100_devinit_new }, + .fb = { 0x00000001, ga102_fb_new }, + .gpio = { 0x00000001, ga102_gpio_new }, + .i2c = { 0x00000001, gm200_i2c_new }, + .imem = { 0x00000001, nv50_instmem_new }, + .mc = { 0x00000001, ga100_mc_new }, + .mmu = { 0x00000001, tu102_mmu_new }, + .pci = { 0x00000001, gp100_pci_new }, + .privring = { 0x00000001, gm200_privring_new }, + .timer = { 0x00000001, gk20a_timer_new }, + .top = { 0x00000001, ga100_top_new }, + .disp = { 0x00000001, ga102_disp_new }, + .dma = { 0x00000001, gv100_dma_new }, +}; + static int nvkm_device_event_ctor(struct nvkm_object *object, void *data, u32 size, struct nvkm_notify *notify) @@ -3049,6 +3069,7 @@ nvkm_device_ctor(const struct nvkm_device_func *func, case 0x168: device->chip = &nv168_chipset; break; case 0x172: device->chip = &nv172_chipset; break; case 0x174: device->chip = &nv174_chipset; break; + case 0x177: device->chip = &nv177_chipset; break; default: if (nvkm_boolopt(device->cfgopt, "NvEnableUnsupportedChipsets", false)) { switch (device->chipset) { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c index fea9d8f2b10c..f28894fdede9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c @@ -397,7 +397,7 @@ nvkm_udevice_new(const struct nvkm_oclass *oclass, void *data, u32 size, return ret; /* give priviledged clients register access */ - if (client->super) + if (args->v0.priv) func = &nvkm_udevice_super; else func = &nvkm_udevice; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c index 55fbfe28c6dc..9669472a2749 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c @@ -440,7 +440,7 @@ nvkm_dp_train(struct nvkm_dp *dp, u32 dataKBps) return ret; } -static void +void nvkm_dp_disable(struct nvkm_outp *outp, struct nvkm_ior *ior) { struct nvkm_dp *dp = nvkm_dp(outp); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h index 428b3f488f03..e484d0c3b0d4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.h @@ -32,6 +32,7 @@ struct nvkm_dp { int nvkm_dp_new(struct nvkm_disp *, int index, struct dcb_output *, struct nvkm_outp **); +void nvkm_dp_disable(struct nvkm_outp *, struct nvkm_ior *); /* DPCD Receiver Capabilities */ #define DPCD_RC00_DPCD_REV 0x00000 diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c index dffcac249211..129982fef7ef 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c @@ -22,6 +22,7 @@ * Authors: Ben Skeggs */ #include "outp.h" +#include "dp.h" #include "ior.h" #include <subdev/bios.h> @@ -257,6 +258,14 @@ nvkm_outp_init_route(struct nvkm_outp *outp) if (!ior->arm.head || ior->arm.proto != proto) { OUTP_DBG(outp, "no heads (%x %d %d)", ior->arm.head, ior->arm.proto, proto); + + /* The EFI GOP driver on Ampere can leave unused DP links routed, + * which we don't expect. The DisableLT IED script *should* get + * us back to where we need to be. + */ + if (ior->func->route.get && !ior->arm.head && outp->info.type == DCB_OUTPUT_DP) + nvkm_dp_disable(outp, ior); + return; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dma/user.c b/drivers/gpu/drm/nouveau/nvkm/engine/dma/user.c index d20cc0681a88..797131ed7d67 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/dma/user.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/dma/user.c @@ -26,7 +26,6 @@ #include <core/client.h> #include <core/gpuobj.h> #include <subdev/fb.h> -#include <subdev/instmem.h> #include <nvif/cl0002.h> #include <nvif/unpack.h> @@ -72,11 +71,7 @@ nvkm_dmaobj_ctor(const struct nvkm_dmaobj_func *func, struct nvkm_dma *dma, union { struct nv_dma_v0 v0; } *args = *pdata; - struct nvkm_device *device = dma->engine.subdev.device; - struct nvkm_client *client = oclass->client; struct nvkm_object *parent = oclass->parent; - struct nvkm_instmem *instmem = device->imem; - struct nvkm_fb *fb = device->fb; void *data = *pdata; u32 size = *psize; int ret = -ENOSYS; @@ -109,23 +104,13 @@ nvkm_dmaobj_ctor(const struct nvkm_dmaobj_func *func, struct nvkm_dma *dma, dmaobj->target = NV_MEM_TARGET_VM; break; case NV_DMA_V0_TARGET_VRAM: - if (!client->super) { - if (dmaobj->limit >= fb->ram->size - instmem->reserved) - return -EACCES; - if (device->card_type >= NV_50) - return -EACCES; - } dmaobj->target = NV_MEM_TARGET_VRAM; break; case NV_DMA_V0_TARGET_PCI: - if (!client->super) - return -EACCES; dmaobj->target = NV_MEM_TARGET_PCI; break; case NV_DMA_V0_TARGET_PCI_US: case NV_DMA_V0_TARGET_AGP: - if (!client->super) - return -EACCES; dmaobj->target = NV_MEM_TARGET_PCI_NOSNOOP; break; default: diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/Kbuild index 90e9a0972a44..3209eb7af65f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/Kbuild @@ -27,8 +27,6 @@ nvkm-y += nvkm/engine/fifo/dmanv04.o nvkm-y += nvkm/engine/fifo/dmanv10.o nvkm-y += nvkm/engine/fifo/dmanv17.o nvkm-y += nvkm/engine/fifo/dmanv40.o -nvkm-y += nvkm/engine/fifo/dmanv50.o -nvkm-y += nvkm/engine/fifo/dmag84.o nvkm-y += nvkm/engine/fifo/gpfifonv50.o nvkm-y += nvkm/engine/fifo/gpfifog84.o diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/channv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/channv50.h index af8bdf275552..3a95730d7ff5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/channv50.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/channv50.h @@ -48,8 +48,6 @@ void nv50_fifo_chan_object_dtor(struct nvkm_fifo_chan *, int); int g84_fifo_chan_ctor(struct nv50_fifo *, u64 vmm, u64 push, const struct nvkm_oclass *, struct nv50_fifo_chan *); -extern const struct nvkm_fifo_chan_oclass nv50_fifo_dma_oclass; extern const struct nvkm_fifo_chan_oclass nv50_fifo_gpfifo_oclass; -extern const struct nvkm_fifo_chan_oclass g84_fifo_dma_oclass; extern const struct nvkm_fifo_chan_oclass g84_fifo_gpfifo_oclass; #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmag84.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmag84.c deleted file mode 100644 index fc34cddcd2f5..000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmag84.c +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright 2012 Red Hat Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: Ben Skeggs - */ -#include "channv50.h" - -#include <core/client.h> -#include <core/ramht.h> - -#include <nvif/class.h> -#include <nvif/cl826e.h> -#include <nvif/unpack.h> - -static int -g84_fifo_dma_new(struct nvkm_fifo *base, const struct nvkm_oclass *oclass, - void *data, u32 size, struct nvkm_object **pobject) -{ - struct nvkm_object *parent = oclass->parent; - union { - struct g82_channel_dma_v0 v0; - } *args = data; - struct nv50_fifo *fifo = nv50_fifo(base); - struct nv50_fifo_chan *chan; - int ret = -ENOSYS; - - nvif_ioctl(parent, "create channel dma size %d\n", size); - if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) { - nvif_ioctl(parent, "create channel dma vers %d vmm %llx " - "pushbuf %llx offset %016llx\n", - args->v0.version, args->v0.vmm, args->v0.pushbuf, - args->v0.offset); - if (!args->v0.pushbuf) - return -EINVAL; - } else - return ret; - - if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) - return -ENOMEM; - *pobject = &chan->base.object; - - ret = g84_fifo_chan_ctor(fifo, args->v0.vmm, args->v0.pushbuf, - oclass, chan); - if (ret) - return ret; - - args->v0.chid = chan->base.chid; - - nvkm_kmap(chan->ramfc); - nvkm_wo32(chan->ramfc, 0x08, lower_32_bits(args->v0.offset)); - nvkm_wo32(chan->ramfc, 0x0c, upper_32_bits(args->v0.offset)); - nvkm_wo32(chan->ramfc, 0x10, lower_32_bits(args->v0.offset)); - nvkm_wo32(chan->ramfc, 0x14, upper_32_bits(args->v0.offset)); - nvkm_wo32(chan->ramfc, 0x3c, 0x003f6078); - nvkm_wo32(chan->ramfc, 0x44, 0x01003fff); - nvkm_wo32(chan->ramfc, 0x48, chan->base.push->node->offset >> 4); - nvkm_wo32(chan->ramfc, 0x4c, 0xffffffff); - nvkm_wo32(chan->ramfc, 0x60, 0x7fffffff); - nvkm_wo32(chan->ramfc, 0x78, 0x00000000); - nvkm_wo32(chan->ramfc, 0x7c, 0x30000001); - nvkm_wo32(chan->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) | - (4 << 24) /* SEARCH_FULL */ | - (chan->ramht->gpuobj->node->offset >> 4)); - nvkm_wo32(chan->ramfc, 0x88, chan->cache->addr >> 10); - nvkm_wo32(chan->ramfc, 0x98, chan->base.inst->addr >> 12); - nvkm_done(chan->ramfc); - return 0; -} - -const struct nvkm_fifo_chan_oclass -g84_fifo_dma_oclass = { - .base.oclass = G82_CHANNEL_DMA, - .base.minver = 0, - .base.maxver = 0, - .ctor = g84_fifo_dma_new, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv50.c deleted file mode 100644 index 8043718ad150..000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv50.c +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright 2012 Red Hat Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - * - * Authors: Ben Skeggs - */ -#include "channv50.h" - -#include <core/client.h> -#include <core/ramht.h> - -#include <nvif/class.h> -#include <nvif/cl506e.h> -#include <nvif/unpack.h> - -static int -nv50_fifo_dma_new(struct nvkm_fifo *base, const struct nvkm_oclass *oclass, - void *data, u32 size, struct nvkm_object **pobject) -{ - struct nvkm_object *parent = oclass->parent; - union { - struct nv50_channel_dma_v0 v0; - } *args = data; - struct nv50_fifo *fifo = nv50_fifo(base); - struct nv50_fifo_chan *chan; - int ret = -ENOSYS; - - nvif_ioctl(parent, "create channel dma size %d\n", size); - if (!(ret = nvif_unpack(ret, &data, &size, args->v0, 0, 0, false))) { - nvif_ioctl(parent, "create channel dma vers %d vmm %llx " - "pushbuf %llx offset %016llx\n", - args->v0.version, args->v0.vmm, args->v0.pushbuf, - args->v0.offset); - if (!args->v0.pushbuf) - return -EINVAL; - } else - return ret; - - if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) - return -ENOMEM; - *pobject = &chan->base.object; - - ret = nv50_fifo_chan_ctor(fifo, args->v0.vmm, args->v0.pushbuf, - oclass, chan); - if (ret) - return ret; - - args->v0.chid = chan->base.chid; - - nvkm_kmap(chan->ramfc); - nvkm_wo32(chan->ramfc, 0x08, lower_32_bits(args->v0.offset)); - nvkm_wo32(chan->ramfc, 0x0c, upper_32_bits(args->v0.offset)); - nvkm_wo32(chan->ramfc, 0x10, lower_32_bits(args->v0.offset)); - nvkm_wo32(chan->ramfc, 0x14, upper_32_bits(args->v0.offset)); - nvkm_wo32(chan->ramfc, 0x3c, 0x003f6078); - nvkm_wo32(chan->ramfc, 0x44, 0x01003fff); - nvkm_wo32(chan->ramfc, 0x48, chan->base.push->node->offset >> 4); - nvkm_wo32(chan->ramfc, 0x4c, 0xffffffff); - nvkm_wo32(chan->ramfc, 0x60, 0x7fffffff); - nvkm_wo32(chan->ramfc, 0x78, 0x00000000); - nvkm_wo32(chan->ramfc, 0x7c, 0x30000001); - nvkm_wo32(chan->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) | - (4 << 24) /* SEARCH_FULL */ | - (chan->ramht->gpuobj->node->offset >> 4)); - nvkm_done(chan->ramfc); - return 0; -} - -const struct nvkm_fifo_chan_oclass -nv50_fifo_dma_oclass = { - .base.oclass = NV50_CHANNEL_DMA, - .base.minver = 0, - .base.maxver = 0, - .ctor = nv50_fifo_dma_new, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c index c0a7d0f21dac..3885c3830b94 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c @@ -119,7 +119,6 @@ g84_fifo = { .uevent_init = g84_fifo_uevent_init, .uevent_fini = g84_fifo_uevent_fini, .chan = { - &g84_fifo_dma_oclass, &g84_fifo_gpfifo_oclass, NULL }, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogk104.c index b6900a52bcce..ae6c4d846eb5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogk104.c @@ -341,8 +341,6 @@ gk104_fifo_gpfifo_new(struct gk104_fifo *fifo, const struct nvkm_oclass *oclass, "runlist %016llx priv %d\n", args->v0.version, args->v0.vmm, args->v0.ioffset, args->v0.ilength, args->v0.runlist, args->v0.priv); - if (args->v0.priv && !oclass->client->super) - return -EINVAL; return gk104_fifo_gpfifo_new_(fifo, &args->v0.runlist, &args->v0.chid, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogv100.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogv100.c index ee4967b706a7..743791c514fe 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogv100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogv100.c @@ -226,8 +226,6 @@ gv100_fifo_gpfifo_new(struct gk104_fifo *fifo, const struct nvkm_oclass *oclass, "runlist %016llx priv %d\n", args->v0.version, args->v0.vmm, args->v0.ioffset, args->v0.ilength, args->v0.runlist, args->v0.priv); - if (args->v0.priv && !oclass->client->super) - return -EINVAL; return gv100_fifo_gpfifo_new_(&gv100_fifo_gpfifo, fifo, &args->v0.runlist, &args->v0.chid, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifotu102.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifotu102.c index abef7fb6e2d3..99aafa103a31 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifotu102.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifotu102.c @@ -65,8 +65,6 @@ tu102_fifo_gpfifo_new(struct gk104_fifo *fifo, const struct nvkm_oclass *oclass, "runlist %016llx priv %d\n", args->v0.version, args->v0.vmm, args->v0.ioffset, args->v0.ilength, args->v0.runlist, args->v0.priv); - if (args->v0.priv && !oclass->client->super) - return -EINVAL; return gv100_fifo_gpfifo_new_(&tu102_fifo_gpfifo, fifo, &args->v0.runlist, &args->v0.chid, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c index be94156ea248..a08742cf425a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c @@ -136,7 +136,6 @@ nv50_fifo = { .pause = nv04_fifo_pause, .start = nv04_fifo_start, .chan = { - &nv50_fifo_dma_oclass, &nv50_fifo_gpfifo_oclass, NULL }, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/umem.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/umem.c index fac2f9a45ea6..e530bb8b3b17 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/umem.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/umem.c @@ -41,7 +41,7 @@ nvkm_umem_search(struct nvkm_client *client, u64 handle) object = nvkm_object_search(client, handle, &nvkm_umem); if (IS_ERR(object)) { - if (client->super && client != master) { + if (client != master) { spin_lock(&master->lock); list_for_each_entry(umem, &master->umem, head) { if (umem->object.object == handle) { @@ -53,8 +53,7 @@ nvkm_umem_search(struct nvkm_client *client, u64 handle) } } else { umem = nvkm_umem(object); - if (!umem->priv || client->super) - memory = nvkm_memory_ref(umem->memory); + memory = nvkm_memory_ref(umem->memory); } return memory ? memory : ERR_PTR(-ENOENT); @@ -167,7 +166,6 @@ nvkm_umem_new(const struct nvkm_oclass *oclass, void *argv, u32 argc, nvkm_object_ctor(&nvkm_umem, oclass, &umem->object); umem->mmu = mmu; umem->type = mmu->type[type].type; - umem->priv = oclass->client->super; INIT_LIST_HEAD(&umem->head); *pobject = &umem->object; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/umem.h b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/umem.h index 85cf692d620a..d56a594016cc 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/umem.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/umem.h @@ -8,7 +8,6 @@ struct nvkm_umem { struct nvkm_object object; struct nvkm_mmu *mmu; u8 type:8; - bool priv:1; bool mappable:1; bool io:1; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/ummu.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/ummu.c index 0e4b8941da37..6870fda4b188 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/ummu.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/ummu.c @@ -34,7 +34,7 @@ nvkm_ummu_sclass(struct nvkm_object *object, int index, { struct nvkm_mmu *mmu = nvkm_ummu(object)->mmu; - if (mmu->func->mem.user.oclass && oclass->client->super) { + if (mmu->func->mem.user.oclass) { if (index-- == 0) { oclass->base = mmu->func->mem.user; oclass->ctor = nvkm_umem_new; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/uvmm.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/uvmm.c index c43b8248c682..d6a1f8d04c09 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/uvmm.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/uvmm.c @@ -45,7 +45,6 @@ nvkm_uvmm_search(struct nvkm_client *client, u64 handle) static int nvkm_uvmm_mthd_pfnclr(struct nvkm_uvmm *uvmm, void *argv, u32 argc) { - struct nvkm_client *client = uvmm->object.client; union { struct nvif_vmm_pfnclr_v0 v0; } *args = argv; @@ -59,9 +58,6 @@ nvkm_uvmm_mthd_pfnclr(struct nvkm_uvmm *uvmm, void *argv, u32 argc) } else return ret; - if (!client->super) - return -ENOENT; - if (size) { mutex_lock(&vmm->mutex); ret = nvkm_vmm_pfn_unmap(vmm, addr, size); @@ -74,7 +70,6 @@ nvkm_uvmm_mthd_pfnclr(struct nvkm_uvmm *uvmm, void *argv, u32 argc) static int nvkm_uvmm_mthd_pfnmap(struct nvkm_uvmm *uvmm, void *argv, u32 argc) { - struct nvkm_client *client = uvmm->object.client; union { struct nvif_vmm_pfnmap_v0 v0; } *args = argv; @@ -93,9 +88,6 @@ nvkm_uvmm_mthd_pfnmap(struct nvkm_uvmm *uvmm, void *argv, u32 argc) } else return ret; - if (!client->super) - return -ENOENT; - if (size) { mutex_lock(&vmm->mutex); ret = nvkm_vmm_pfn_map(vmm, page, addr, size, phys); @@ -108,7 +100,6 @@ nvkm_uvmm_mthd_pfnmap(struct nvkm_uvmm *uvmm, void *argv, u32 argc) static int nvkm_uvmm_mthd_unmap(struct nvkm_uvmm *uvmm, void *argv, u32 argc) { - struct nvkm_client *client = uvmm->object.client; union { struct nvif_vmm_unmap_v0 v0; } *args = argv; @@ -130,9 +121,8 @@ nvkm_uvmm_mthd_unmap(struct nvkm_uvmm *uvmm, void *argv, u32 argc) goto done; } - if (ret = -ENOENT, (!vma->user && !client->super) || vma->busy) { - VMM_DEBUG(vmm, "denied %016llx: %d %d %d", addr, - vma->user, !client->super, vma->busy); + if (ret = -ENOENT, vma->busy) { + VMM_DEBUG(vmm, "denied %016llx: %d", addr, vma->busy); goto done; } @@ -181,9 +171,8 @@ nvkm_uvmm_mthd_map(struct nvkm_uvmm *uvmm, void *argv, u32 argc) goto fail; } - if (ret = -ENOENT, (!vma->user && !client->super) || vma->busy) { - VMM_DEBUG(vmm, "denied %016llx: %d %d %d", addr, - vma->user, !client->super, vma->busy); + if (ret = -ENOENT, vma->busy) { + VMM_DEBUG(vmm, "denied %016llx: %d", addr, vma->busy); goto fail; } @@ -230,7 +219,6 @@ fail: static int nvkm_uvmm_mthd_put(struct nvkm_uvmm *uvmm, void *argv, u32 argc) { - struct nvkm_client *client = uvmm->object.client; union { struct nvif_vmm_put_v0 v0; } *args = argv; @@ -252,9 +240,8 @@ nvkm_uvmm_mthd_put(struct nvkm_uvmm *uvmm, void *argv, u32 argc) goto done; } - if (ret = -ENOENT, (!vma->user && !client->super) || vma->busy) { - VMM_DEBUG(vmm, "denied %016llx: %d %d %d", addr, - vma->user, !client->super, vma->busy); + if (ret = -ENOENT, vma->busy) { + VMM_DEBUG(vmm, "denied %016llx: %d", addr, vma->busy); goto done; } @@ -268,7 +255,6 @@ done: static int nvkm_uvmm_mthd_get(struct nvkm_uvmm *uvmm, void *argv, u32 argc) { - struct nvkm_client *client = uvmm->object.client; union { struct nvif_vmm_get_v0 v0; } *args = argv; @@ -297,7 +283,6 @@ nvkm_uvmm_mthd_get(struct nvkm_uvmm *uvmm, void *argv, u32 argc) return ret; args->v0.addr = vma->addr; - vma->user = !client->super; return ret; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.c index 710f3f8dc7c9..8bf00b396ec1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmm.c @@ -774,7 +774,6 @@ nvkm_vma_tail(struct nvkm_vma *vma, u64 tail) new->refd = vma->refd; new->used = vma->used; new->part = vma->part; - new->user = vma->user; new->busy = vma->busy; new->mapped = vma->mapped; list_add(&new->head, &vma->head); @@ -951,7 +950,7 @@ nvkm_vmm_node_split(struct nvkm_vmm *vmm, static void nvkm_vma_dump(struct nvkm_vma *vma) { - printk(KERN_ERR "%016llx %016llx %c%c%c%c%c%c%c%c%c %p\n", + printk(KERN_ERR "%016llx %016llx %c%c%c%c%c%c%c%c %p\n", vma->addr, (u64)vma->size, vma->used ? '-' : 'F', vma->mapref ? 'R' : '-', @@ -959,7 +958,6 @@ nvkm_vma_dump(struct nvkm_vma *vma) vma->page != NVKM_VMA_PAGE_NONE ? '0' + vma->page : '-', vma->refd != NVKM_VMA_PAGE_NONE ? '0' + vma->refd : '-', vma->part ? 'P' : '-', - vma->user ? 'U' : '-', vma->busy ? 'B' : '-', vma->mapped ? 'M' : '-', vma->memory); @@ -1024,7 +1022,6 @@ nvkm_vmm_ctor_managed(struct nvkm_vmm *vmm, u64 addr, u64 size) vma->mapref = true; vma->sparse = false; vma->used = true; - vma->user = true; nvkm_vmm_node_insert(vmm, vma); list_add_tail(&vma->head, &vmm->list); return 0; @@ -1615,7 +1612,6 @@ nvkm_vmm_put_locked(struct nvkm_vmm *vmm, struct nvkm_vma *vma) vma->page = NVKM_VMA_PAGE_NONE; vma->refd = NVKM_VMA_PAGE_NONE; vma->used = false; - vma->user = false; nvkm_vmm_put_region(vmm, vma); } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgp100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgp100.c index f02abd9cb4dd..b5e733783b5b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgp100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/vmmgp100.c @@ -534,15 +534,13 @@ int gp100_vmm_mthd(struct nvkm_vmm *vmm, struct nvkm_client *client, u32 mthd, void *argv, u32 argc) { - if (client->super) { - switch (mthd) { - case GP100_VMM_VN_FAULT_REPLAY: - return gp100_vmm_fault_replay(vmm, argv, argc); - case GP100_VMM_VN_FAULT_CANCEL: - return gp100_vmm_fault_cancel(vmm, argv, argc); - default: - break; - } + switch (mthd) { + case GP100_VMM_VN_FAULT_REPLAY: + return gp100_vmm_fault_replay(vmm, argv, argc); + case GP100_VMM_VN_FAULT_CANCEL: + return gp100_vmm_fault_cancel(vmm, argv, argc); + default: + break; } return -EINVAL; } diff --git a/drivers/gpu/drm/ttm/ttm_device.c b/drivers/gpu/drm/ttm/ttm_device.c index 74e3b460132b..2df59b3c2ea1 100644 --- a/drivers/gpu/drm/ttm/ttm_device.c +++ b/drivers/gpu/drm/ttm/ttm_device.c @@ -78,9 +78,7 @@ static int ttm_global_init(void) ttm_debugfs_root = debugfs_create_dir("ttm", NULL); if (IS_ERR(ttm_debugfs_root)) { - ret = PTR_ERR(ttm_debugfs_root); ttm_debugfs_root = NULL; - goto out; } /* Limit the number of pages in the pool to about 50% of the total diff --git a/drivers/gpu/ipu-v3/ipu-cpmem.c b/drivers/gpu/ipu-v3/ipu-cpmem.c index a1c85d1521f5..82b244cb313e 100644 --- a/drivers/gpu/ipu-v3/ipu-cpmem.c +++ b/drivers/gpu/ipu-v3/ipu-cpmem.c @@ -585,21 +585,21 @@ static const struct ipu_rgb def_bgra_16 = { .bits_per_pixel = 16, }; -#define Y_OFFSET(pix, x, y) ((x) + pix->width * (y)) -#define U_OFFSET(pix, x, y) ((pix->width * pix->height) + \ - (pix->width * ((y) / 2) / 2) + (x) / 2) -#define V_OFFSET(pix, x, y) ((pix->width * pix->height) + \ - (pix->width * pix->height / 4) + \ - (pix->width * ((y) / 2) / 2) + (x) / 2) -#define U2_OFFSET(pix, x, y) ((pix->width * pix->height) + \ - (pix->width * (y) / 2) + (x) / 2) -#define V2_OFFSET(pix, x, y) ((pix->width * pix->height) + \ - (pix->width * pix->height / 2) + \ - (pix->width * (y) / 2) + (x) / 2) -#define UV_OFFSET(pix, x, y) ((pix->width * pix->height) + \ - (pix->width * ((y) / 2)) + (x)) -#define UV2_OFFSET(pix, x, y) ((pix->width * pix->height) + \ - (pix->width * y) + (x)) +#define Y_OFFSET(pix, x, y) ((x) + pix->bytesperline * (y)) +#define U_OFFSET(pix, x, y) ((pix->bytesperline * pix->height) + \ + (pix->bytesperline * ((y) / 2) / 2) + (x) / 2) +#define V_OFFSET(pix, x, y) ((pix->bytesperline * pix->height) + \ + (pix->bytesperline * pix->height / 4) + \ + (pix->bytesperline * ((y) / 2) / 2) + (x) / 2) +#define U2_OFFSET(pix, x, y) ((pix->bytesperline * pix->height) + \ + (pix->bytesperline * (y) / 2) + (x) / 2) +#define V2_OFFSET(pix, x, y) ((pix->bytesperline * pix->height) + \ + (pix->bytesperline * pix->height / 2) + \ + (pix->bytesperline * (y) / 2) + (x) / 2) +#define UV_OFFSET(pix, x, y) ((pix->bytesperline * pix->height) + \ + (pix->bytesperline * ((y) / 2)) + (x)) +#define UV2_OFFSET(pix, x, y) ((pix->bytesperline * pix->height) + \ + (pix->bytesperline * y) + (x)) #define NUM_ALPHA_CHANNELS 7 diff --git a/drivers/iio/adc/rn5t618-adc.c b/drivers/iio/adc/rn5t618-adc.c index 7010c4276947..c56fccb2c8e1 100644 --- a/drivers/iio/adc/rn5t618-adc.c +++ b/drivers/iio/adc/rn5t618-adc.c @@ -16,6 +16,8 @@ #include <linux/completion.h> #include <linux/regmap.h> #include <linux/iio/iio.h> +#include <linux/iio/driver.h> +#include <linux/iio/machine.h> #include <linux/slab.h> #define RN5T618_ADC_CONVERSION_TIMEOUT (msecs_to_jiffies(500)) @@ -189,6 +191,19 @@ static const struct iio_chan_spec rn5t618_adc_iio_channels[] = { RN5T618_ADC_CHANNEL(AIN0, IIO_VOLTAGE, "AIN0") }; +static struct iio_map rn5t618_maps[] = { + IIO_MAP("VADP", "rn5t618-power", "vadp"), + IIO_MAP("VUSB", "rn5t618-power", "vusb"), + { /* sentinel */ } +}; + +static void unregister_map(void *data) +{ + struct iio_dev *iio_dev = (struct iio_dev *) data; + + iio_map_array_unregister(iio_dev); +} + static int rn5t618_adc_probe(struct platform_device *pdev) { int ret; @@ -239,6 +254,14 @@ static int rn5t618_adc_probe(struct platform_device *pdev) return ret; } + ret = iio_map_array_register(iio_dev, rn5t618_maps); + if (ret < 0) + return ret; + + ret = devm_add_action_or_reset(adc->dev, unregister_map, iio_dev); + if (ret < 0) + return ret; + return devm_iio_device_register(adc->dev, iio_dev); } diff --git a/drivers/infiniband/core/uverbs_std_types_mr.c b/drivers/infiniband/core/uverbs_std_types_mr.c index f782d5e1aa25..03e1db5d1e8c 100644 --- a/drivers/infiniband/core/uverbs_std_types_mr.c +++ b/drivers/infiniband/core/uverbs_std_types_mr.c @@ -249,6 +249,9 @@ static int UVERBS_HANDLER(UVERBS_METHOD_REG_DMABUF_MR)( mr->uobject = uobj; atomic_inc(&pd->usecnt); + rdma_restrack_new(&mr->res, RDMA_RESTRACK_MR); + rdma_restrack_set_name(&mr->res, NULL); + rdma_restrack_add(&mr->res); uobj->object = mr; uverbs_finalize_uobj_create(attrs, UVERBS_ATTR_REG_DMABUF_MR_HANDLE); diff --git a/drivers/infiniband/hw/bnxt_re/ib_verbs.c b/drivers/infiniband/hw/bnxt_re/ib_verbs.c index 283b6b81563c..ea0054c60fbc 100644 --- a/drivers/infiniband/hw/bnxt_re/ib_verbs.c +++ b/drivers/infiniband/hw/bnxt_re/ib_verbs.c @@ -1681,6 +1681,7 @@ int bnxt_re_create_srq(struct ib_srq *ib_srq, if (nq) nq->budget++; atomic_inc(&rdev->srq_count); + spin_lock_init(&srq->lock); return 0; diff --git a/drivers/infiniband/hw/bnxt_re/main.c b/drivers/infiniband/hw/bnxt_re/main.c index a8688a92c760..4678bd6ec7d6 100644 --- a/drivers/infiniband/hw/bnxt_re/main.c +++ b/drivers/infiniband/hw/bnxt_re/main.c @@ -1397,7 +1397,6 @@ static int bnxt_re_dev_init(struct bnxt_re_dev *rdev, u8 wqe_mode) memset(&rattr, 0, sizeof(rattr)); rc = bnxt_re_register_netdev(rdev); if (rc) { - rtnl_unlock(); ibdev_err(&rdev->ibdev, "Failed to register with netedev: %#x\n", rc); return -EINVAL; diff --git a/drivers/infiniband/hw/efa/efa_main.c b/drivers/infiniband/hw/efa/efa_main.c index 203e6ddcacbc..be4a07bd268a 100644 --- a/drivers/infiniband/hw/efa/efa_main.c +++ b/drivers/infiniband/hw/efa/efa_main.c @@ -357,6 +357,7 @@ static int efa_enable_msix(struct efa_dev *dev) } if (irq_num != msix_vecs) { + efa_disable_msix(dev); dev_err(&dev->pdev->dev, "Allocated %d MSI-X (out of %d requested)\n", irq_num, msix_vecs); diff --git a/drivers/infiniband/hw/hfi1/sdma.c b/drivers/infiniband/hw/hfi1/sdma.c index eb15c310d63d..e83dc562629e 100644 --- a/drivers/infiniband/hw/hfi1/sdma.c +++ b/drivers/infiniband/hw/hfi1/sdma.c @@ -3055,6 +3055,7 @@ static void __sdma_process_event(struct sdma_engine *sde, static int _extend_sdma_tx_descs(struct hfi1_devdata *dd, struct sdma_txreq *tx) { int i; + struct sdma_desc *descp; /* Handle last descriptor */ if (unlikely((tx->num_desc == (MAX_DESC - 1)))) { @@ -3075,12 +3076,10 @@ static int _extend_sdma_tx_descs(struct hfi1_devdata *dd, struct sdma_txreq *tx) if (unlikely(tx->num_desc == MAX_DESC)) goto enomem; - tx->descp = kmalloc_array( - MAX_DESC, - sizeof(struct sdma_desc), - GFP_ATOMIC); - if (!tx->descp) + descp = kmalloc_array(MAX_DESC, sizeof(struct sdma_desc), GFP_ATOMIC); + if (!descp) goto enomem; + tx->descp = descp; /* reserve last descriptor for coalescing */ tx->desc_limit = MAX_DESC - 1; diff --git a/drivers/infiniband/hw/irdma/Kconfig b/drivers/infiniband/hw/irdma/Kconfig index dab88286d549..b6f9c41bca51 100644 --- a/drivers/infiniband/hw/irdma/Kconfig +++ b/drivers/infiniband/hw/irdma/Kconfig @@ -6,7 +6,7 @@ config INFINIBAND_IRDMA depends on PCI depends on ICE && I40E select GENERIC_ALLOCATOR - select CONFIG_AUXILIARY_BUS + select AUXILIARY_BUS help This is an Intel(R) Ethernet Protocol Driver for RDMA driver that support E810 (iWARP/RoCE) and X722 (iWARP) network devices. diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index 094c976b1eed..2507051f7b89 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -4454,7 +4454,8 @@ static void mlx5r_mp_remove(struct auxiliary_device *adev) mutex_lock(&mlx5_ib_multiport_mutex); if (mpi->ibdev) mlx5_ib_unbind_slave_port(mpi->ibdev, mpi); - list_del(&mpi->list); + else + list_del(&mpi->list); mutex_unlock(&mlx5_ib_multiport_mutex); kfree(mpi); } diff --git a/drivers/infiniband/sw/rxe/rxe_mcast.c b/drivers/infiniband/sw/rxe/rxe_mcast.c index 0ea9a5aa4ec0..1c1d1b53312d 100644 --- a/drivers/infiniband/sw/rxe/rxe_mcast.c +++ b/drivers/infiniband/sw/rxe/rxe_mcast.c @@ -85,7 +85,7 @@ int rxe_mcast_add_grp_elem(struct rxe_dev *rxe, struct rxe_qp *qp, goto out; } - elem = rxe_alloc(&rxe->mc_elem_pool); + elem = rxe_alloc_locked(&rxe->mc_elem_pool); if (!elem) { err = -ENOMEM; goto out; diff --git a/drivers/infiniband/sw/rxe/rxe_queue.c b/drivers/infiniband/sw/rxe/rxe_queue.c index 85b812586ed4..72d95398e604 100644 --- a/drivers/infiniband/sw/rxe/rxe_queue.c +++ b/drivers/infiniband/sw/rxe/rxe_queue.c @@ -63,7 +63,7 @@ struct rxe_queue *rxe_queue_init(struct rxe_dev *rxe, int *num_elem, if (*num_elem < 0) goto err1; - q = kmalloc(sizeof(*q), GFP_KERNEL); + q = kzalloc(sizeof(*q), GFP_KERNEL); if (!q) goto err1; diff --git a/drivers/interconnect/qcom/icc-rpmh.c b/drivers/interconnect/qcom/icc-rpmh.c index 27cc5f03611c..f6fae64861ce 100644 --- a/drivers/interconnect/qcom/icc-rpmh.c +++ b/drivers/interconnect/qcom/icc-rpmh.c @@ -20,18 +20,13 @@ void qcom_icc_pre_aggregate(struct icc_node *node) { size_t i; struct qcom_icc_node *qn; - struct qcom_icc_provider *qp; qn = node->data; - qp = to_qcom_provider(node->provider); for (i = 0; i < QCOM_ICC_NUM_BUCKETS; i++) { qn->sum_avg[i] = 0; qn->max_peak[i] = 0; } - - for (i = 0; i < qn->num_bcms; i++) - qcom_icc_bcm_voter_add(qp->voter, qn->bcms[i]); } EXPORT_SYMBOL_GPL(qcom_icc_pre_aggregate); @@ -49,8 +44,10 @@ int qcom_icc_aggregate(struct icc_node *node, u32 tag, u32 avg_bw, { size_t i; struct qcom_icc_node *qn; + struct qcom_icc_provider *qp; qn = node->data; + qp = to_qcom_provider(node->provider); if (!tag) tag = QCOM_ICC_TAG_ALWAYS; @@ -70,6 +67,9 @@ int qcom_icc_aggregate(struct icc_node *node, u32 tag, u32 avg_bw, *agg_avg += avg_bw; *agg_peak = max_t(u32, *agg_peak, peak_bw); + for (i = 0; i < qn->num_bcms; i++) + qcom_icc_bcm_voter_add(qp->voter, qn->bcms[i]); + return 0; } EXPORT_SYMBOL_GPL(qcom_icc_aggregate); diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c index 98ba927aee1a..6f0df629353f 100644 --- a/drivers/iommu/dma-iommu.c +++ b/drivers/iommu/dma-iommu.c @@ -768,6 +768,7 @@ static void iommu_dma_free_noncontiguous(struct device *dev, size_t size, __iommu_dma_unmap(dev, sgt->sgl->dma_address, size); __iommu_dma_free_pages(sh->pages, PAGE_ALIGN(size) >> PAGE_SHIFT); sg_free_table(&sh->sgt); + kfree(sh); } #endif /* CONFIG_DMA_REMAP */ diff --git a/drivers/iommu/intel/pasid.c b/drivers/iommu/intel/pasid.c index c6cf44a6c923..9ec374e17469 100644 --- a/drivers/iommu/intel/pasid.c +++ b/drivers/iommu/intel/pasid.c @@ -511,7 +511,7 @@ void intel_pasid_tear_down_entry(struct intel_iommu *iommu, struct device *dev, u32 pasid, bool fault_ignore) { struct pasid_entry *pte; - u16 did; + u16 did, pgtt; pte = intel_pasid_get_entry(dev, pasid); if (WARN_ON(!pte)) @@ -521,13 +521,19 @@ void intel_pasid_tear_down_entry(struct intel_iommu *iommu, struct device *dev, return; did = pasid_get_domain_id(pte); + pgtt = pasid_pte_get_pgtt(pte); + intel_pasid_clear_entry(dev, pasid, fault_ignore); if (!ecap_coherent(iommu->ecap)) clflush_cache_range(pte, sizeof(*pte)); pasid_cache_invalidation_with_pasid(iommu, did, pasid); - qi_flush_piotlb(iommu, did, pasid, 0, -1, 0); + + if (pgtt == PASID_ENTRY_PGTT_PT || pgtt == PASID_ENTRY_PGTT_FL_ONLY) + qi_flush_piotlb(iommu, did, pasid, 0, -1, 0); + else + iommu->flush.flush_iotlb(iommu, did, 0, 0, DMA_TLB_DSI_FLUSH); /* Device IOTLB doesn't need to be flushed in caching mode. */ if (!cap_caching_mode(iommu->cap)) diff --git a/drivers/iommu/intel/pasid.h b/drivers/iommu/intel/pasid.h index 5ff61c3d401f..c11bc8b833b8 100644 --- a/drivers/iommu/intel/pasid.h +++ b/drivers/iommu/intel/pasid.h @@ -99,6 +99,12 @@ static inline bool pasid_pte_is_present(struct pasid_entry *pte) return READ_ONCE(pte->val[0]) & PASID_PTE_PRESENT; } +/* Get PGTT field of a PASID table entry */ +static inline u16 pasid_pte_get_pgtt(struct pasid_entry *pte) +{ + return (u16)((READ_ONCE(pte->val[0]) >> 6) & 0x7); +} + extern unsigned int intel_pasid_max_id; int intel_pasid_alloc_table(struct device *dev); void intel_pasid_free_table(struct device *dev); diff --git a/drivers/iommu/intel/svm.c b/drivers/iommu/intel/svm.c index 9b0f22bc0514..4b9b3f35ba0e 100644 --- a/drivers/iommu/intel/svm.c +++ b/drivers/iommu/intel/svm.c @@ -675,7 +675,6 @@ static int intel_svm_unbind_mm(struct device *dev, u32 pasid) kfree_rcu(sdev, rcu); if (list_empty(&svm->devs)) { - intel_svm_free_pasid(mm); if (svm->notifier.ops) { mmu_notifier_unregister(&svm->notifier, mm); /* Clear mm's pasid. */ @@ -690,6 +689,8 @@ static int intel_svm_unbind_mm(struct device *dev, u32 pasid) kfree(svm); } } + /* Drop a PASID reference and free it if no reference. */ + intel_svm_free_pasid(mm); } out: return ret; diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 5419c4b9f27a..63f0af10c403 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -924,6 +924,9 @@ void iommu_group_remove_device(struct device *dev) struct iommu_group *group = dev->iommu_group; struct group_device *tmp_device, *device = NULL; + if (!group) + return; + dev_info(dev, "Removing from iommu group %d\n", group->id); /* Pre-notify listeners that a device is being removed. */ diff --git a/drivers/iommu/s390-iommu.c b/drivers/iommu/s390-iommu.c index 6019e58ce4fb..83df387e70a3 100644 --- a/drivers/iommu/s390-iommu.c +++ b/drivers/iommu/s390-iommu.c @@ -90,7 +90,7 @@ static int s390_iommu_attach_device(struct iommu_domain *domain, struct zpci_dev *zdev = to_zpci_dev(dev); struct s390_domain_device *domain_device; unsigned long flags; - int rc; + int cc, rc; if (!zdev) return -ENODEV; @@ -99,14 +99,21 @@ static int s390_iommu_attach_device(struct iommu_domain *domain, if (!domain_device) return -ENOMEM; - if (zdev->dma_table) - zpci_dma_exit_device(zdev); + if (zdev->dma_table) { + cc = zpci_dma_exit_device(zdev); + if (cc) { + rc = -EIO; + goto out_free; + } + } zdev->dma_table = s390_domain->dma_table; - rc = zpci_register_ioat(zdev, 0, zdev->start_dma, zdev->end_dma, + cc = zpci_register_ioat(zdev, 0, zdev->start_dma, zdev->end_dma, (u64) zdev->dma_table); - if (rc) + if (cc) { + rc = -EIO; goto out_restore; + } spin_lock_irqsave(&s390_domain->list_lock, flags); /* First device defines the DMA range limits */ @@ -130,6 +137,7 @@ static int s390_iommu_attach_device(struct iommu_domain *domain, out_restore: zpci_dma_init_device(zdev); +out_free: kfree(domain_device); return rc; diff --git a/drivers/ipack/carriers/tpci200.c b/drivers/ipack/carriers/tpci200.c index 3461b0a7dc62..cbfdadecb23b 100644 --- a/drivers/ipack/carriers/tpci200.c +++ b/drivers/ipack/carriers/tpci200.c @@ -89,16 +89,13 @@ static void tpci200_unregister(struct tpci200_board *tpci200) free_irq(tpci200->info->pdev->irq, (void *) tpci200); pci_iounmap(tpci200->info->pdev, tpci200->info->interface_regs); - pci_iounmap(tpci200->info->pdev, tpci200->info->cfg_regs); pci_release_region(tpci200->info->pdev, TPCI200_IP_INTERFACE_BAR); pci_release_region(tpci200->info->pdev, TPCI200_IO_ID_INT_SPACES_BAR); pci_release_region(tpci200->info->pdev, TPCI200_MEM16_SPACE_BAR); pci_release_region(tpci200->info->pdev, TPCI200_MEM8_SPACE_BAR); - pci_release_region(tpci200->info->pdev, TPCI200_CFG_MEM_BAR); pci_disable_device(tpci200->info->pdev); - pci_dev_put(tpci200->info->pdev); } static void tpci200_enable_irq(struct tpci200_board *tpci200, @@ -257,7 +254,7 @@ static int tpci200_register(struct tpci200_board *tpci200) "(bn 0x%X, sn 0x%X) failed to allocate PCI resource for BAR 2 !", tpci200->info->pdev->bus->number, tpci200->info->pdev->devfn); - goto out_disable_pci; + goto err_disable_device; } /* Request IO ID INT space (Bar 3) */ @@ -269,7 +266,7 @@ static int tpci200_register(struct tpci200_board *tpci200) "(bn 0x%X, sn 0x%X) failed to allocate PCI resource for BAR 3 !", tpci200->info->pdev->bus->number, tpci200->info->pdev->devfn); - goto out_release_ip_space; + goto err_ip_interface_bar; } /* Request MEM8 space (Bar 5) */ @@ -280,7 +277,7 @@ static int tpci200_register(struct tpci200_board *tpci200) "(bn 0x%X, sn 0x%X) failed to allocate PCI resource for BAR 5!", tpci200->info->pdev->bus->number, tpci200->info->pdev->devfn); - goto out_release_ioid_int_space; + goto err_io_id_int_spaces_bar; } /* Request MEM16 space (Bar 4) */ @@ -291,7 +288,7 @@ static int tpci200_register(struct tpci200_board *tpci200) "(bn 0x%X, sn 0x%X) failed to allocate PCI resource for BAR 4!", tpci200->info->pdev->bus->number, tpci200->info->pdev->devfn); - goto out_release_mem8_space; + goto err_mem8_space_bar; } /* Map internal tpci200 driver user space */ @@ -305,7 +302,7 @@ static int tpci200_register(struct tpci200_board *tpci200) tpci200->info->pdev->bus->number, tpci200->info->pdev->devfn); res = -ENOMEM; - goto out_release_mem8_space; + goto err_mem16_space_bar; } /* Initialize lock that protects interface_regs */ @@ -344,18 +341,22 @@ static int tpci200_register(struct tpci200_board *tpci200) "(bn 0x%X, sn 0x%X) unable to register IRQ !", tpci200->info->pdev->bus->number, tpci200->info->pdev->devfn); - goto out_release_ioid_int_space; + goto err_interface_regs; } return 0; -out_release_mem8_space: +err_interface_regs: + pci_iounmap(tpci200->info->pdev, tpci200->info->interface_regs); +err_mem16_space_bar: + pci_release_region(tpci200->info->pdev, TPCI200_MEM16_SPACE_BAR); +err_mem8_space_bar: pci_release_region(tpci200->info->pdev, TPCI200_MEM8_SPACE_BAR); -out_release_ioid_int_space: +err_io_id_int_spaces_bar: pci_release_region(tpci200->info->pdev, TPCI200_IO_ID_INT_SPACES_BAR); -out_release_ip_space: +err_ip_interface_bar: pci_release_region(tpci200->info->pdev, TPCI200_IP_INTERFACE_BAR); -out_disable_pci: +err_disable_device: pci_disable_device(tpci200->info->pdev); return res; } @@ -527,7 +528,7 @@ static int tpci200_pci_probe(struct pci_dev *pdev, tpci200->info = kzalloc(sizeof(struct tpci200_infos), GFP_KERNEL); if (!tpci200->info) { ret = -ENOMEM; - goto out_err_info; + goto err_tpci200; } pci_dev_get(pdev); @@ -538,7 +539,7 @@ static int tpci200_pci_probe(struct pci_dev *pdev, if (ret) { dev_err(&pdev->dev, "Failed to allocate PCI Configuration Memory"); ret = -EBUSY; - goto out_err_pci_request; + goto err_tpci200_info; } tpci200->info->cfg_regs = ioremap( pci_resource_start(pdev, TPCI200_CFG_MEM_BAR), @@ -546,7 +547,7 @@ static int tpci200_pci_probe(struct pci_dev *pdev, if (!tpci200->info->cfg_regs) { dev_err(&pdev->dev, "Failed to map PCI Configuration Memory"); ret = -EFAULT; - goto out_err_ioremap; + goto err_request_region; } /* Disable byte swapping for 16 bit IP module access. This will ensure @@ -569,7 +570,7 @@ static int tpci200_pci_probe(struct pci_dev *pdev, if (ret) { dev_err(&pdev->dev, "error during tpci200 install\n"); ret = -ENODEV; - goto out_err_install; + goto err_cfg_regs; } /* Register the carrier in the industry pack bus driver */ @@ -581,7 +582,7 @@ static int tpci200_pci_probe(struct pci_dev *pdev, dev_err(&pdev->dev, "error registering the carrier on ipack driver\n"); ret = -EFAULT; - goto out_err_bus_register; + goto err_tpci200_install; } /* save the bus number given by ipack to logging purpose */ @@ -592,19 +593,16 @@ static int tpci200_pci_probe(struct pci_dev *pdev, tpci200_create_device(tpci200, i); return 0; -out_err_bus_register: +err_tpci200_install: tpci200_uninstall(tpci200); - /* tpci200->info->cfg_regs is unmapped in tpci200_uninstall */ - tpci200->info->cfg_regs = NULL; -out_err_install: - if (tpci200->info->cfg_regs) - iounmap(tpci200->info->cfg_regs); -out_err_ioremap: +err_cfg_regs: + pci_iounmap(tpci200->info->pdev, tpci200->info->cfg_regs); +err_request_region: pci_release_region(pdev, TPCI200_CFG_MEM_BAR); -out_err_pci_request: - pci_dev_put(pdev); +err_tpci200_info: kfree(tpci200->info); -out_err_info: + pci_dev_put(pdev); +err_tpci200: kfree(tpci200); return ret; } @@ -614,6 +612,12 @@ static void __tpci200_pci_remove(struct tpci200_board *tpci200) ipack_bus_unregister(tpci200->info->ipack_bus); tpci200_uninstall(tpci200); + pci_iounmap(tpci200->info->pdev, tpci200->info->cfg_regs); + + pci_release_region(tpci200->info->pdev, TPCI200_CFG_MEM_BAR); + + pci_dev_put(tpci200->info->pdev); + kfree(tpci200->info); kfree(tpci200); } diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index b8436e4930ed..02ed53b20654 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -2437,7 +2437,7 @@ static int resize_chunks(struct r5conf *conf, int new_disks, int new_sectors) conf->scribble_sectors >= new_sectors) return 0; mddev_suspend(conf->mddev); - get_online_cpus(); + cpus_read_lock(); for_each_present_cpu(cpu) { struct raid5_percpu *percpu; @@ -2449,7 +2449,7 @@ static int resize_chunks(struct r5conf *conf, int new_disks, int new_sectors) break; } - put_online_cpus(); + cpus_read_unlock(); mddev_resume(conf->mddev); if (!err) { conf->scribble_disks = new_disks; diff --git a/drivers/media/pci/intel/ipu3/cio2-bridge.c b/drivers/media/pci/intel/ipu3/cio2-bridge.c index 59a36f922675..30d29b96a339 100644 --- a/drivers/media/pci/intel/ipu3/cio2-bridge.c +++ b/drivers/media/pci/intel/ipu3/cio2-bridge.c @@ -226,7 +226,7 @@ static int cio2_bridge_connect_sensor(const struct cio2_sensor_config *cfg, err_free_swnodes: software_node_unregister_nodes(sensor->swnodes); err_put_adev: - acpi_dev_put(sensor->adev); + acpi_dev_put(adev); return ret; } diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c index d333130d1531..c3229d8c7041 100644 --- a/drivers/mmc/host/dw_mmc.c +++ b/drivers/mmc/host/dw_mmc.c @@ -2018,8 +2018,8 @@ static void dw_mci_tasklet_func(struct tasklet_struct *t) continue; } - dw_mci_stop_dma(host); send_stop_abort(host, data); + dw_mci_stop_dma(host); state = STATE_SENDING_STOP; break; } @@ -2043,10 +2043,10 @@ static void dw_mci_tasklet_func(struct tasklet_struct *t) */ if (test_and_clear_bit(EVENT_DATA_ERROR, &host->pending_events)) { - dw_mci_stop_dma(host); if (!(host->data_status & (SDMMC_INT_DRTO | SDMMC_INT_EBE))) send_stop_abort(host, data); + dw_mci_stop_dma(host); state = STATE_DATA_ERROR; break; } @@ -2079,10 +2079,10 @@ static void dw_mci_tasklet_func(struct tasklet_struct *t) */ if (test_and_clear_bit(EVENT_DATA_ERROR, &host->pending_events)) { - dw_mci_stop_dma(host); if (!(host->data_status & (SDMMC_INT_DRTO | SDMMC_INT_EBE))) send_stop_abort(host, data); + dw_mci_stop_dma(host); state = STATE_DATA_ERROR; break; } diff --git a/drivers/mmc/host/mmci_stm32_sdmmc.c b/drivers/mmc/host/mmci_stm32_sdmmc.c index 51db30acf4dc..fdaa11f92fe6 100644 --- a/drivers/mmc/host/mmci_stm32_sdmmc.c +++ b/drivers/mmc/host/mmci_stm32_sdmmc.c @@ -479,8 +479,9 @@ static int sdmmc_post_sig_volt_switch(struct mmci_host *host, u32 status; int ret = 0; - if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_180) { - spin_lock_irqsave(&host->lock, flags); + spin_lock_irqsave(&host->lock, flags); + if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_180 && + host->pwr_reg & MCI_STM32_VSWITCHEN) { mmci_write_pwrreg(host, host->pwr_reg | MCI_STM32_VSWITCH); spin_unlock_irqrestore(&host->lock, flags); @@ -492,9 +493,11 @@ static int sdmmc_post_sig_volt_switch(struct mmci_host *host, writel_relaxed(MCI_STM32_VSWENDC | MCI_STM32_CKSTOPC, host->base + MMCICLEAR); + spin_lock_irqsave(&host->lock, flags); mmci_write_pwrreg(host, host->pwr_reg & ~(MCI_STM32_VSWITCHEN | MCI_STM32_VSWITCH)); } + spin_unlock_irqrestore(&host->lock, flags); return ret; } diff --git a/drivers/mmc/host/sdhci-iproc.c b/drivers/mmc/host/sdhci-iproc.c index cce390fe9cf3..032bf852397f 100644 --- a/drivers/mmc/host/sdhci-iproc.c +++ b/drivers/mmc/host/sdhci-iproc.c @@ -173,6 +173,23 @@ static unsigned int sdhci_iproc_get_max_clock(struct sdhci_host *host) return pltfm_host->clock; } +/* + * There is a known bug on BCM2711's SDHCI core integration where the + * controller will hang when the difference between the core clock and the bus + * clock is too great. Specifically this can be reproduced under the following + * conditions: + * + * - No SD card plugged in, polling thread is running, probing cards at + * 100 kHz. + * - BCM2711's core clock configured at 500MHz or more + * + * So we set 200kHz as the minimum clock frequency available for that SoC. + */ +static unsigned int sdhci_iproc_bcm2711_get_min_clock(struct sdhci_host *host) +{ + return 200000; +} + static const struct sdhci_ops sdhci_iproc_ops = { .set_clock = sdhci_set_clock, .get_max_clock = sdhci_iproc_get_max_clock, @@ -271,6 +288,7 @@ static const struct sdhci_ops sdhci_iproc_bcm2711_ops = { .set_clock = sdhci_set_clock, .set_power = sdhci_set_power_and_bus_voltage, .get_max_clock = sdhci_iproc_get_max_clock, + .get_min_clock = sdhci_iproc_bcm2711_get_min_clock, .set_bus_width = sdhci_set_bus_width, .reset = sdhci_reset, .set_uhs_signaling = sdhci_set_uhs_signaling, diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index e44b7a66b73c..290a14cdc1cf 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -2089,6 +2089,23 @@ static void sdhci_msm_cqe_disable(struct mmc_host *mmc, bool recovery) sdhci_cqe_disable(mmc, recovery); } +static void sdhci_msm_set_timeout(struct sdhci_host *host, struct mmc_command *cmd) +{ + u32 count, start = 15; + + __sdhci_set_timeout(host, cmd); + count = sdhci_readb(host, SDHCI_TIMEOUT_CONTROL); + /* + * Update software timeout value if its value is less than hardware data + * timeout value. Qcom SoC hardware data timeout value was calculated + * using 4 * MCLK * 2^(count + 13). where MCLK = 1 / host->clock. + */ + if (cmd && cmd->data && host->clock > 400000 && + host->clock <= 50000000 && + ((1 << (count + start)) > (10 * host->clock))) + host->data_timeout = 22LL * NSEC_PER_SEC; +} + static const struct cqhci_host_ops sdhci_msm_cqhci_ops = { .enable = sdhci_msm_cqe_enable, .disable = sdhci_msm_cqe_disable, @@ -2438,6 +2455,7 @@ static const struct sdhci_ops sdhci_msm_ops = { .irq = sdhci_msm_cqe_irq, .dump_vendor_regs = sdhci_msm_dump_vendor_regs, .set_power = sdhci_set_power_noreg, + .set_timeout = sdhci_msm_set_timeout, }; static const struct sdhci_pltfm_data sdhci_msm_pdata = { diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index 3097e93787f7..a761134fd3be 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c @@ -119,7 +119,7 @@ static int cfi_use_status_reg(struct cfi_private *cfi) struct cfi_pri_amdstd *extp = cfi->cmdset_priv; u8 poll_mask = CFI_POLL_STATUS_REG | CFI_POLL_DQ; - return extp->MinorVersion >= '5' && + return extp && extp->MinorVersion >= '5' && (extp->SoftwareFeatures & poll_mask) == CFI_POLL_STATUS_REG; } diff --git a/drivers/mtd/devices/mchp48l640.c b/drivers/mtd/devices/mchp48l640.c index efc2003bd13a..99400d0fb8c1 100644 --- a/drivers/mtd/devices/mchp48l640.c +++ b/drivers/mtd/devices/mchp48l640.c @@ -229,7 +229,7 @@ static int mchp48l640_write(struct mtd_info *mtd, loff_t to, size_t len, woff += ws; } - return ret; + return 0; } static int mchp48l640_read_page(struct mtd_info *mtd, loff_t from, size_t len, @@ -255,6 +255,7 @@ static int mchp48l640_read_page(struct mtd_info *mtd, loff_t from, size_t len, if (!ret) *retlen += len; + kfree(cmd); return ret; fail: @@ -286,7 +287,7 @@ static int mchp48l640_read(struct mtd_info *mtd, loff_t from, size_t len, woff += ws; } - return ret; + return 0; }; static const struct mchp48_caps mchp48l640_caps = { diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c index 6ce4bc57f919..44bea3f65060 100644 --- a/drivers/mtd/mtd_blkdevs.c +++ b/drivers/mtd/mtd_blkdevs.c @@ -419,6 +419,7 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new) if (tr->discard) { blk_queue_flag_set(QUEUE_FLAG_DISCARD, new->rq); blk_queue_max_discard_sectors(new->rq, UINT_MAX); + new->rq->limits.discard_granularity = tr->blksize; } gd->queue = new->rq; @@ -525,14 +526,10 @@ int register_mtd_blktrans(struct mtd_blktrans_ops *tr) if (!blktrans_notifier.list.next) register_mtd_user(&blktrans_notifier); - - mutex_lock(&mtd_table_mutex); - ret = register_blkdev(tr->major, tr->name); if (ret < 0) { printk(KERN_WARNING "Unable to register %s block device on major %d: %d\n", tr->name, tr->major, ret); - mutex_unlock(&mtd_table_mutex); return ret; } @@ -542,12 +539,12 @@ int register_mtd_blktrans(struct mtd_blktrans_ops *tr) tr->blkshift = ffs(tr->blksize) - 1; INIT_LIST_HEAD(&tr->devs); - list_add(&tr->list, &blktrans_majors); + mutex_lock(&mtd_table_mutex); + list_add(&tr->list, &blktrans_majors); mtd_for_each_device(mtd) if (mtd->type != MTD_ABSENT) tr->add_mtd(tr, mtd); - mutex_unlock(&mtd_table_mutex); return 0; } @@ -564,8 +561,8 @@ int deregister_mtd_blktrans(struct mtd_blktrans_ops *tr) list_for_each_entry_safe(dev, next, &tr->devs, list) tr->remove_dev(dev); - unregister_blkdev(tr->major, tr->name); mutex_unlock(&mtd_table_mutex); + unregister_blkdev(tr->major, tr->name); BUG_ON(!list_empty(&tr->devs)); return 0; diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index b5ccd3037788..c8fd7f758938 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -806,7 +806,9 @@ static ssize_t mtd_otp_size(struct mtd_info *mtd, bool is_user) err: kfree(info); - return ret; + + /* ENODATA means there is no OTP region. */ + return ret == -ENODATA ? 0 : ret; } static struct nvmem_device *mtd_otp_nvmem_register(struct mtd_info *mtd, diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c index 57a583149cc0..3d6c6e880520 100644 --- a/drivers/mtd/nand/raw/nand_base.c +++ b/drivers/mtd/nand/raw/nand_base.c @@ -5228,12 +5228,18 @@ static bool of_get_nand_on_flash_bbt(struct device_node *np) static int of_get_nand_secure_regions(struct nand_chip *chip) { struct device_node *dn = nand_get_flash_node(chip); + struct property *prop; int nr_elem, i, j; - nr_elem = of_property_count_elems_of_size(dn, "secure-regions", sizeof(u64)); - if (!nr_elem) + /* Only proceed if the "secure-regions" property is present in DT */ + prop = of_find_property(dn, "secure-regions", NULL); + if (!prop) return 0; + nr_elem = of_property_count_elems_of_size(dn, "secure-regions", sizeof(u64)); + if (nr_elem <= 0) + return nr_elem; + chip->nr_secure_regions = nr_elem / 2; chip->secure_regions = kcalloc(chip->nr_secure_regions, sizeof(*chip->secure_regions), GFP_KERNEL); diff --git a/drivers/net/can/usb/esd_usb2.c b/drivers/net/can/usb/esd_usb2.c index 66fa8b07c2e6..95ae740fc311 100644 --- a/drivers/net/can/usb/esd_usb2.c +++ b/drivers/net/can/usb/esd_usb2.c @@ -224,8 +224,8 @@ static void esd_usb2_rx_event(struct esd_usb2_net_priv *priv, if (id == ESD_EV_CAN_ERROR_EXT) { u8 state = msg->msg.rx.data[0]; u8 ecc = msg->msg.rx.data[1]; - u8 txerr = msg->msg.rx.data[2]; - u8 rxerr = msg->msg.rx.data[3]; + u8 rxerr = msg->msg.rx.data[2]; + u8 txerr = msg->msg.rx.data[3]; skb = alloc_can_err_skb(priv->netdev, &cf); if (skb == NULL) { diff --git a/drivers/net/dsa/hirschmann/hellcreek.c b/drivers/net/dsa/hirschmann/hellcreek.c index 5c54ae1be62c..7062db6a083c 100644 --- a/drivers/net/dsa/hirschmann/hellcreek.c +++ b/drivers/net/dsa/hirschmann/hellcreek.c @@ -1472,9 +1472,6 @@ static void hellcreek_setup_gcl(struct hellcreek *hellcreek, int port, u16 data; u8 gates; - cur++; - next++; - if (i == schedule->num_entries) gates = initial->gate_mask ^ cur->gate_mask; @@ -1503,6 +1500,9 @@ static void hellcreek_setup_gcl(struct hellcreek *hellcreek, int port, (initial->gate_mask << TR_GCLCMD_INIT_GATE_STATES_SHIFT); hellcreek_write(hellcreek, data, TR_GCLCMD); + + cur++; + next++; } } @@ -1550,7 +1550,7 @@ static bool hellcreek_schedule_startable(struct hellcreek *hellcreek, int port) /* Calculate difference to admin base time */ base_time_ns = ktime_to_ns(hellcreek_port->current_schedule->base_time); - return base_time_ns - current_ns < (s64)8 * NSEC_PER_SEC; + return base_time_ns - current_ns < (s64)4 * NSEC_PER_SEC; } static void hellcreek_start_schedule(struct hellcreek *hellcreek, int port) diff --git a/drivers/net/dsa/mv88e6xxx/serdes.c b/drivers/net/dsa/mv88e6xxx/serdes.c index b1d46dd8eaab..6ea003678798 100644 --- a/drivers/net/dsa/mv88e6xxx/serdes.c +++ b/drivers/net/dsa/mv88e6xxx/serdes.c @@ -1277,15 +1277,16 @@ static int mv88e6393x_serdes_port_errata(struct mv88e6xxx_chip *chip, int lane) int err; /* mv88e6393x family errata 4.6: - * Cannot clear PwrDn bit on SERDES on port 0 if device is configured - * CPU_MGD mode or P0_mode is configured for [x]MII. - * Workaround: Set Port0 SERDES register 4.F002 bit 5=0 and bit 15=1. + * Cannot clear PwrDn bit on SERDES if device is configured CPU_MGD + * mode or P0_mode is configured for [x]MII. + * Workaround: Set SERDES register 4.F002 bit 5=0 and bit 15=1. * * It seems that after this workaround the SERDES is automatically * powered up (the bit is cleared), so power it down. */ - if (lane == MV88E6393X_PORT0_LANE) { - err = mv88e6390_serdes_read(chip, MV88E6393X_PORT0_LANE, + if (lane == MV88E6393X_PORT0_LANE || lane == MV88E6393X_PORT9_LANE || + lane == MV88E6393X_PORT10_LANE) { + err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS, MV88E6393X_SERDES_POC, ®); if (err) diff --git a/drivers/net/dsa/sja1105/sja1105_mdio.c b/drivers/net/dsa/sja1105/sja1105_mdio.c index 19aea8fb76f6..705d3900e43a 100644 --- a/drivers/net/dsa/sja1105/sja1105_mdio.c +++ b/drivers/net/dsa/sja1105/sja1105_mdio.c @@ -284,8 +284,7 @@ static int sja1105_mdiobus_base_tx_register(struct sja1105_private *priv, struct mii_bus *bus; int rc = 0; - np = of_find_compatible_node(mdio_node, NULL, - "nxp,sja1110-base-tx-mdio"); + np = of_get_compatible_child(mdio_node, "nxp,sja1110-base-tx-mdio"); if (!np) return 0; @@ -339,8 +338,7 @@ static int sja1105_mdiobus_base_t1_register(struct sja1105_private *priv, struct mii_bus *bus; int rc = 0; - np = of_find_compatible_node(mdio_node, NULL, - "nxp,sja1110-base-t1-mdio"); + np = of_get_compatible_child(mdio_node, "nxp,sja1110-base-t1-mdio"); if (!np) return 0; diff --git a/drivers/net/ethernet/apm/xgene-v2/main.c b/drivers/net/ethernet/apm/xgene-v2/main.c index 860c18fb7aae..80399c8980bd 100644 --- a/drivers/net/ethernet/apm/xgene-v2/main.c +++ b/drivers/net/ethernet/apm/xgene-v2/main.c @@ -677,11 +677,13 @@ static int xge_probe(struct platform_device *pdev) ret = register_netdev(ndev); if (ret) { netdev_err(ndev, "Failed to register netdev\n"); - goto err; + goto err_mdio_remove; } return 0; +err_mdio_remove: + xge_mdio_remove(ndev); err: free_netdev(ndev); diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 2fe743503949..8a97640cdfe7 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -72,7 +72,8 @@ #include "bnxt_debugfs.h" #define BNXT_TX_TIMEOUT (5 * HZ) -#define BNXT_DEF_MSG_ENABLE (NETIF_MSG_DRV | NETIF_MSG_HW) +#define BNXT_DEF_MSG_ENABLE (NETIF_MSG_DRV | NETIF_MSG_HW | \ + NETIF_MSG_TX_ERR) MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Broadcom BCM573xx network driver"); @@ -365,6 +366,33 @@ static u16 bnxt_xmit_get_cfa_action(struct sk_buff *skb) return md_dst->u.port_info.port_id; } +static void bnxt_txr_db_kick(struct bnxt *bp, struct bnxt_tx_ring_info *txr, + u16 prod) +{ + bnxt_db_write(bp, &txr->tx_db, prod); + txr->kick_pending = 0; +} + +static bool bnxt_txr_netif_try_stop_queue(struct bnxt *bp, + struct bnxt_tx_ring_info *txr, + struct netdev_queue *txq) +{ + netif_tx_stop_queue(txq); + + /* netif_tx_stop_queue() must be done before checking + * tx index in bnxt_tx_avail() below, because in + * bnxt_tx_int(), we update tx index before checking for + * netif_tx_queue_stopped(). + */ + smp_mb(); + if (bnxt_tx_avail(bp, txr) > bp->tx_wake_thresh) { + netif_tx_wake_queue(txq); + return false; + } + + return true; +} + static netdev_tx_t bnxt_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct bnxt *bp = netdev_priv(dev); @@ -384,6 +412,7 @@ static netdev_tx_t bnxt_start_xmit(struct sk_buff *skb, struct net_device *dev) i = skb_get_queue_mapping(skb); if (unlikely(i >= bp->tx_nr_rings)) { dev_kfree_skb_any(skb); + atomic_long_inc(&dev->tx_dropped); return NETDEV_TX_OK; } @@ -393,8 +422,12 @@ static netdev_tx_t bnxt_start_xmit(struct sk_buff *skb, struct net_device *dev) free_size = bnxt_tx_avail(bp, txr); if (unlikely(free_size < skb_shinfo(skb)->nr_frags + 2)) { - netif_tx_stop_queue(txq); - return NETDEV_TX_BUSY; + /* We must have raced with NAPI cleanup */ + if (net_ratelimit() && txr->kick_pending) + netif_warn(bp, tx_err, dev, + "bnxt: ring busy w/ flush pending!\n"); + if (bnxt_txr_netif_try_stop_queue(bp, txr, txq)) + return NETDEV_TX_BUSY; } length = skb->len; @@ -517,21 +550,16 @@ static netdev_tx_t bnxt_start_xmit(struct sk_buff *skb, struct net_device *dev) normal_tx: if (length < BNXT_MIN_PKT_SIZE) { pad = BNXT_MIN_PKT_SIZE - length; - if (skb_pad(skb, pad)) { + if (skb_pad(skb, pad)) /* SKB already freed. */ - tx_buf->skb = NULL; - return NETDEV_TX_OK; - } + goto tx_kick_pending; length = BNXT_MIN_PKT_SIZE; } mapping = dma_map_single(&pdev->dev, skb->data, len, DMA_TO_DEVICE); - if (unlikely(dma_mapping_error(&pdev->dev, mapping))) { - dev_kfree_skb_any(skb); - tx_buf->skb = NULL; - return NETDEV_TX_OK; - } + if (unlikely(dma_mapping_error(&pdev->dev, mapping))) + goto tx_free; dma_unmap_addr_set(tx_buf, mapping, mapping); flags = (len << TX_BD_LEN_SHIFT) | TX_BD_TYPE_LONG_TX_BD | @@ -618,24 +646,17 @@ normal_tx: txr->tx_prod = prod; if (!netdev_xmit_more() || netif_xmit_stopped(txq)) - bnxt_db_write(bp, &txr->tx_db, prod); + bnxt_txr_db_kick(bp, txr, prod); + else + txr->kick_pending = 1; tx_done: if (unlikely(bnxt_tx_avail(bp, txr) <= MAX_SKB_FRAGS + 1)) { if (netdev_xmit_more() && !tx_buf->is_push) - bnxt_db_write(bp, &txr->tx_db, prod); - - netif_tx_stop_queue(txq); + bnxt_txr_db_kick(bp, txr, prod); - /* netif_tx_stop_queue() must be done before checking - * tx index in bnxt_tx_avail() below, because in - * bnxt_tx_int(), we update tx index before checking for - * netif_tx_queue_stopped(). - */ - smp_mb(); - if (bnxt_tx_avail(bp, txr) > bp->tx_wake_thresh) - netif_tx_wake_queue(txq); + bnxt_txr_netif_try_stop_queue(bp, txr, txq); } return NETDEV_TX_OK; @@ -648,7 +669,6 @@ tx_dma_error: /* start back at beginning and unmap skb */ prod = txr->tx_prod; tx_buf = &txr->tx_buf_ring[prod]; - tx_buf->skb = NULL; dma_unmap_single(&pdev->dev, dma_unmap_addr(tx_buf, mapping), skb_headlen(skb), PCI_DMA_TODEVICE); prod = NEXT_TX(prod); @@ -662,7 +682,13 @@ tx_dma_error: PCI_DMA_TODEVICE); } +tx_free: dev_kfree_skb_any(skb); +tx_kick_pending: + if (txr->kick_pending) + bnxt_txr_db_kick(bp, txr, txr->tx_prod); + txr->tx_buf_ring[txr->tx_prod].skb = NULL; + atomic_long_inc(&dev->tx_dropped); return NETDEV_TX_OK; } @@ -732,14 +758,9 @@ next_tx_int: smp_mb(); if (unlikely(netif_tx_queue_stopped(txq)) && - (bnxt_tx_avail(bp, txr) > bp->tx_wake_thresh)) { - __netif_tx_lock(txq, smp_processor_id()); - if (netif_tx_queue_stopped(txq) && - bnxt_tx_avail(bp, txr) > bp->tx_wake_thresh && - txr->dev_state != BNXT_DEV_STATE_CLOSING) - netif_tx_wake_queue(txq); - __netif_tx_unlock(txq); - } + bnxt_tx_avail(bp, txr) > bp->tx_wake_thresh && + READ_ONCE(txr->dev_state) != BNXT_DEV_STATE_CLOSING) + netif_tx_wake_queue(txq); } static struct page *__bnxt_alloc_rx_page(struct bnxt *bp, dma_addr_t *mapping, @@ -1767,6 +1788,10 @@ static int bnxt_rx_pkt(struct bnxt *bp, struct bnxt_cp_ring_info *cpr, if (!RX_CMP_VALID(rxcmp1, tmp_raw_cons)) return -EBUSY; + /* The valid test of the entry must be done first before + * reading any further. + */ + dma_rmb(); prod = rxr->rx_prod; if (cmp_type == CMP_TYPE_RX_L2_TPA_START_CMP) { @@ -1989,6 +2014,10 @@ static int bnxt_force_rx_discard(struct bnxt *bp, if (!RX_CMP_VALID(rxcmp1, tmp_raw_cons)) return -EBUSY; + /* The valid test of the entry must be done first before + * reading any further. + */ + dma_rmb(); cmp_type = RX_CMP_TYPE(rxcmp); if (cmp_type == CMP_TYPE_RX_L2_CMP) { rxcmp1->rx_cmp_cfa_code_errors_v2 |= @@ -2454,6 +2483,10 @@ static int bnxt_poll_nitroa0(struct napi_struct *napi, int budget) if (!TX_CMP_VALID(txcmp, raw_cons)) break; + /* The valid test of the entry must be done first before + * reading any further. + */ + dma_rmb(); if ((TX_CMP_TYPE(txcmp) & 0x30) == 0x10) { tmp_raw_cons = NEXT_RAW_CMP(raw_cons); cp_cons = RING_CMP(tmp_raw_cons); @@ -9128,10 +9161,9 @@ static void bnxt_disable_napi(struct bnxt *bp) for (i = 0; i < bp->cp_nr_rings; i++) { struct bnxt_cp_ring_info *cpr = &bp->bnapi[i]->cp_ring; + napi_disable(&bp->bnapi[i]->napi); if (bp->bnapi[i]->rx_ring) cancel_work_sync(&cpr->dim.work); - - napi_disable(&bp->bnapi[i]->napi); } } @@ -9165,9 +9197,11 @@ void bnxt_tx_disable(struct bnxt *bp) if (bp->tx_ring) { for (i = 0; i < bp->tx_nr_rings; i++) { txr = &bp->tx_ring[i]; - txr->dev_state = BNXT_DEV_STATE_CLOSING; + WRITE_ONCE(txr->dev_state, BNXT_DEV_STATE_CLOSING); } } + /* Make sure napi polls see @dev_state change */ + synchronize_net(); /* Drop carrier first to prevent TX timeout */ netif_carrier_off(bp->dev); /* Stop all TX queues */ @@ -9181,8 +9215,10 @@ void bnxt_tx_enable(struct bnxt *bp) for (i = 0; i < bp->tx_nr_rings; i++) { txr = &bp->tx_ring[i]; - txr->dev_state = 0; + WRITE_ONCE(txr->dev_state, 0); } + /* Make sure napi polls see @dev_state change */ + synchronize_net(); netif_tx_wake_all_queues(bp->dev); if (bp->link_info.link_up) netif_carrier_on(bp->dev); @@ -10768,6 +10804,9 @@ static bool bnxt_rfs_supported(struct bnxt *bp) return true; return false; } + /* 212 firmware is broken for aRFS */ + if (BNXT_FW_MAJ(bp) == 212) + return false; if (BNXT_PF(bp) && !BNXT_CHIP_TYPE_NITRO_A0(bp)) return true; if (bp->flags & BNXT_FLAG_NEW_RSS_CAP) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h index bcf8d00b8c80..ba4e0fc38520 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h @@ -786,6 +786,7 @@ struct bnxt_tx_ring_info { u16 tx_prod; u16 tx_cons; u16 txq_index; + u8 kick_pending; struct bnxt_db_info tx_db; struct tx_bd *tx_desc_ring[MAX_TX_PAGES]; diff --git a/drivers/net/ethernet/cadence/macb_ptp.c b/drivers/net/ethernet/cadence/macb_ptp.c index 5c368a9cbbbc..c2e1f163bb14 100644 --- a/drivers/net/ethernet/cadence/macb_ptp.c +++ b/drivers/net/ethernet/cadence/macb_ptp.c @@ -275,6 +275,12 @@ void gem_ptp_rxstamp(struct macb *bp, struct sk_buff *skb, if (GEM_BFEXT(DMA_RXVALID, desc->addr)) { desc_ptp = macb_ptp_desc(bp, desc); + /* Unlikely but check */ + if (!desc_ptp) { + dev_warn_ratelimited(&bp->pdev->dev, + "Timestamp not supported in BD\n"); + return; + } gem_hw_timestamp(bp, desc_ptp->ts_1, desc_ptp->ts_2, &ts); memset(shhwtstamps, 0, sizeof(struct skb_shared_hwtstamps)); shhwtstamps->hwtstamp = ktime_set(ts.tv_sec, ts.tv_nsec); @@ -307,8 +313,11 @@ int gem_ptp_txstamp(struct macb_queue *queue, struct sk_buff *skb, if (CIRC_SPACE(head, tail, PTP_TS_BUFFER_SIZE) == 0) return -ENOMEM; - skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; desc_ptp = macb_ptp_desc(queue->bp, desc); + /* Unlikely but check */ + if (!desc_ptp) + return -EINVAL; + skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; tx_timestamp = &queue->tx_timestamps[head]; tx_timestamp->skb = skb; /* ensure ts_1/ts_2 is loaded after ctrl (TX_USED check) */ diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index dbf9a0e6601d..710cb00ce3a3 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -5068,6 +5068,7 @@ static int adap_init0(struct adapter *adap, int vpd_skip) ret = -ENOMEM; goto bye; } + bitmap_zero(adap->sge.blocked_fl, adap->sge.egr_sz); #endif params[0] = FW_PARAM_PFVF(CLIP_START); @@ -6788,13 +6789,11 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent) setup_memwin(adapter); err = adap_init0(adapter, 0); -#ifdef CONFIG_DEBUG_FS - bitmap_zero(adapter->sge.blocked_fl, adapter->sge.egr_sz); -#endif - setup_memwin_rdma(adapter); if (err) goto out_unmap_bar; + setup_memwin_rdma(adapter); + /* configure SGE_STAT_CFG_A to read WC stats */ if (!is_t4(adapter->params.chip)) t4_write_reg(adapter, SGE_STAT_CFG_A, STATSOURCE_T5_V(7) | diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c index 68b78642c045..98cc0133c343 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-switch.c @@ -3038,26 +3038,30 @@ static int dpaa2_switch_port_init(struct ethsw_port_priv *port_priv, u16 port) return err; } -static void dpaa2_switch_takedown(struct fsl_mc_device *sw_dev) +static void dpaa2_switch_ctrl_if_teardown(struct ethsw_core *ethsw) +{ + dpsw_ctrl_if_disable(ethsw->mc_io, 0, ethsw->dpsw_handle); + dpaa2_switch_free_dpio(ethsw); + dpaa2_switch_destroy_rings(ethsw); + dpaa2_switch_drain_bp(ethsw); + dpaa2_switch_free_dpbp(ethsw); +} + +static void dpaa2_switch_teardown(struct fsl_mc_device *sw_dev) { struct device *dev = &sw_dev->dev; struct ethsw_core *ethsw = dev_get_drvdata(dev); int err; + dpaa2_switch_ctrl_if_teardown(ethsw); + + destroy_workqueue(ethsw->workqueue); + err = dpsw_close(ethsw->mc_io, 0, ethsw->dpsw_handle); if (err) dev_warn(dev, "dpsw_close err %d\n", err); } -static void dpaa2_switch_ctrl_if_teardown(struct ethsw_core *ethsw) -{ - dpsw_ctrl_if_disable(ethsw->mc_io, 0, ethsw->dpsw_handle); - dpaa2_switch_free_dpio(ethsw); - dpaa2_switch_destroy_rings(ethsw); - dpaa2_switch_drain_bp(ethsw); - dpaa2_switch_free_dpbp(ethsw); -} - static int dpaa2_switch_remove(struct fsl_mc_device *sw_dev) { struct ethsw_port_priv *port_priv; @@ -3068,8 +3072,6 @@ static int dpaa2_switch_remove(struct fsl_mc_device *sw_dev) dev = &sw_dev->dev; ethsw = dev_get_drvdata(dev); - dpaa2_switch_ctrl_if_teardown(ethsw); - dpaa2_switch_teardown_irqs(sw_dev); dpsw_disable(ethsw->mc_io, 0, ethsw->dpsw_handle); @@ -3084,9 +3086,7 @@ static int dpaa2_switch_remove(struct fsl_mc_device *sw_dev) kfree(ethsw->acls); kfree(ethsw->ports); - dpaa2_switch_takedown(sw_dev); - - destroy_workqueue(ethsw->workqueue); + dpaa2_switch_teardown(sw_dev); fsl_mc_portal_free(ethsw->mc_io); @@ -3199,7 +3199,7 @@ static int dpaa2_switch_probe(struct fsl_mc_device *sw_dev) GFP_KERNEL); if (!(ethsw->ports)) { err = -ENOMEM; - goto err_takedown; + goto err_teardown; } ethsw->fdbs = kcalloc(ethsw->sw_attr.num_ifs, sizeof(*ethsw->fdbs), @@ -3270,8 +3270,8 @@ err_free_fdbs: err_free_ports: kfree(ethsw->ports); -err_takedown: - dpaa2_switch_takedown(sw_dev); +err_teardown: + dpaa2_switch_teardown(sw_dev); err_free_cmdport: fsl_mc_portal_free(ethsw->mc_io); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c b/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c index 532523069d74..80461ab0ce9e 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.c @@ -938,20 +938,19 @@ static int hns3_dbg_dev_info(struct hnae3_handle *h, char *buf, int len) return 0; } -static int hns3_dbg_get_cmd_index(struct hnae3_handle *handle, - const unsigned char *name, u32 *index) +static int hns3_dbg_get_cmd_index(struct hns3_dbg_data *dbg_data, u32 *index) { u32 i; for (i = 0; i < ARRAY_SIZE(hns3_dbg_cmd); i++) { - if (!strncmp(name, hns3_dbg_cmd[i].name, - strlen(hns3_dbg_cmd[i].name))) { + if (hns3_dbg_cmd[i].cmd == dbg_data->cmd) { *index = i; return 0; } } - dev_err(&handle->pdev->dev, "unknown command(%s)\n", name); + dev_err(&dbg_data->handle->pdev->dev, "unknown command(%d)\n", + dbg_data->cmd); return -EINVAL; } @@ -1019,8 +1018,7 @@ static ssize_t hns3_dbg_read(struct file *filp, char __user *buffer, u32 index; int ret; - ret = hns3_dbg_get_cmd_index(handle, filp->f_path.dentry->d_iname, - &index); + ret = hns3_dbg_get_cmd_index(dbg_data, &index); if (ret) return ret; @@ -1090,6 +1088,7 @@ static int hns3_dbg_bd_file_init(struct hnae3_handle *handle, u32 cmd) char name[HNS3_DBG_FILE_NAME_LEN]; data[i].handle = handle; + data[i].cmd = hns3_dbg_cmd[cmd].cmd; data[i].qid = i; sprintf(name, "%s%u", hns3_dbg_cmd[cmd].name, i); debugfs_create_file(name, 0400, entry_dir, &data[i], @@ -1110,6 +1109,7 @@ hns3_dbg_common_file_init(struct hnae3_handle *handle, u32 cmd) return -ENOMEM; data->handle = handle; + data->cmd = hns3_dbg_cmd[cmd].cmd; entry_dir = hns3_dbg_dentry[hns3_dbg_cmd[cmd].dentry].dentry; debugfs_create_file(hns3_dbg_cmd[cmd].name, 0400, entry_dir, data, &hns3_dbg_fops); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.h b/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.h index f3766ff38bb7..bd8801065e02 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_debugfs.h @@ -22,6 +22,7 @@ struct hns3_dbg_item { struct hns3_dbg_data { struct hnae3_handle *handle; + enum hnae3_dbg_cmd cmd; u16 qid; }; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c index 887297e37cf3..eb748aa35952 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.c @@ -573,9 +573,13 @@ static void hclge_cmd_uninit_regs(struct hclge_hw *hw) void hclge_cmd_uninit(struct hclge_dev *hdev) { + set_bit(HCLGE_STATE_CMD_DISABLE, &hdev->state); + /* wait to ensure that the firmware completes the possible left + * over commands. + */ + msleep(HCLGE_CMDQ_CLEAR_WAIT_TIME); spin_lock_bh(&hdev->hw.cmq.csq.lock); spin_lock(&hdev->hw.cmq.crq.lock); - set_bit(HCLGE_STATE_CMD_DISABLE, &hdev->state); hclge_cmd_uninit_regs(&hdev->hw); spin_unlock(&hdev->hw.cmq.crq.lock); spin_unlock_bh(&hdev->hw.cmq.csq.lock); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h index 18bde77ef944..ac70d49e205d 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_cmd.h @@ -9,6 +9,7 @@ #include "hnae3.h" #define HCLGE_CMDQ_TX_TIMEOUT 30000 +#define HCLGE_CMDQ_CLEAR_WAIT_TIME 200 #define HCLGE_DESC_DATA_LEN 6 struct hclge_dev; @@ -270,6 +271,9 @@ enum hclge_opcode_type { /* Led command */ HCLGE_OPC_LED_STATUS_CFG = 0xB000, + /* clear hardware resource command */ + HCLGE_OPC_CLEAR_HW_RESOURCE = 0x700B, + /* NCL config command */ HCLGE_OPC_QUERY_NCL_CONFIG = 0x7011, diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c index 5bf5db91d16c..39f56f245d84 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_dcb.c @@ -255,21 +255,12 @@ static int hclge_ieee_getpfc(struct hnae3_handle *h, struct ieee_pfc *pfc) u64 requests[HNAE3_MAX_TC], indications[HNAE3_MAX_TC]; struct hclge_vport *vport = hclge_get_vport(h); struct hclge_dev *hdev = vport->back; - u8 i, j, pfc_map, *prio_tc; int ret; + u8 i; memset(pfc, 0, sizeof(*pfc)); pfc->pfc_cap = hdev->pfc_max; - prio_tc = hdev->tm_info.prio_tc; - pfc_map = hdev->tm_info.hw_pfc_map; - - /* Pfc setting is based on TC */ - for (i = 0; i < hdev->tm_info.num_tc; i++) { - for (j = 0; j < HNAE3_MAX_USER_PRIO; j++) { - if ((prio_tc[j] == i) && (pfc_map & BIT(i))) - pfc->pfc_en |= BIT(j); - } - } + pfc->pfc_en = hdev->tm_info.pfc_en; ret = hclge_pfc_tx_stats_get(hdev, requests); if (ret) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index ebeaf12e409b..03ae122f1c9a 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -1550,6 +1550,7 @@ static int hclge_configure(struct hclge_dev *hdev) hdev->tm_info.hw_pfc_map = 0; hdev->wanted_umv_size = cfg.umv_space; hdev->tx_spare_buf_size = cfg.tx_spare_buf_size; + hdev->gro_en = true; if (cfg.vlan_fliter_cap == HCLGE_VLAN_FLTR_CAN_MDF) set_bit(HNAE3_DEV_SUPPORT_VLAN_FLTR_MDF_B, ae_dev->caps); @@ -1618,7 +1619,7 @@ static int hclge_config_tso(struct hclge_dev *hdev, u16 tso_mss_min, return hclge_cmd_send(&hdev->hw, &desc, 1); } -static int hclge_config_gro(struct hclge_dev *hdev, bool en) +static int hclge_config_gro(struct hclge_dev *hdev) { struct hclge_cfg_gro_status_cmd *req; struct hclge_desc desc; @@ -1630,7 +1631,7 @@ static int hclge_config_gro(struct hclge_dev *hdev, bool en) hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_GRO_GENERIC_CONFIG, false); req = (struct hclge_cfg_gro_status_cmd *)desc.data; - req->gro_en = en ? 1 : 0; + req->gro_en = hdev->gro_en ? 1 : 0; ret = hclge_cmd_send(&hdev->hw, &desc, 1); if (ret) @@ -2952,12 +2953,12 @@ static void hclge_update_link_status(struct hclge_dev *hdev) } if (state != hdev->hw.mac.link) { + hdev->hw.mac.link = state; client->ops->link_status_change(handle, state); hclge_config_mac_tnl_int(hdev, state); if (rclient && rclient->ops->link_status_change) rclient->ops->link_status_change(rhandle, state); - hdev->hw.mac.link = state; hclge_push_link_status(hdev); } @@ -10073,7 +10074,11 @@ static int hclge_init_vlan_config(struct hclge_dev *hdev) static void hclge_add_vport_vlan_table(struct hclge_vport *vport, u16 vlan_id, bool writen_to_tbl) { - struct hclge_vport_vlan_cfg *vlan; + struct hclge_vport_vlan_cfg *vlan, *tmp; + + list_for_each_entry_safe(vlan, tmp, &vport->vlan_list, node) + if (vlan->vlan_id == vlan_id) + return; vlan = kzalloc(sizeof(*vlan), GFP_KERNEL); if (!vlan) @@ -11443,6 +11448,28 @@ static void hclge_clear_resetting_state(struct hclge_dev *hdev) } } +static int hclge_clear_hw_resource(struct hclge_dev *hdev) +{ + struct hclge_desc desc; + int ret; + + hclge_cmd_setup_basic_desc(&desc, HCLGE_OPC_CLEAR_HW_RESOURCE, false); + + ret = hclge_cmd_send(&hdev->hw, &desc, 1); + /* This new command is only supported by new firmware, it will + * fail with older firmware. Error value -EOPNOSUPP can only be + * returned by older firmware running this command, to keep code + * backward compatible we will override this value and return + * success. + */ + if (ret && ret != -EOPNOTSUPP) { + dev_err(&hdev->pdev->dev, + "failed to clear hw resource, ret = %d\n", ret); + return ret; + } + return 0; +} + static void hclge_init_rxd_adv_layout(struct hclge_dev *hdev) { if (hnae3_ae_dev_rxd_adv_layout_supported(hdev->ae_dev)) @@ -11492,6 +11519,10 @@ static int hclge_init_ae_dev(struct hnae3_ae_dev *ae_dev) if (ret) goto err_cmd_uninit; + ret = hclge_clear_hw_resource(hdev); + if (ret) + goto err_cmd_uninit; + ret = hclge_get_cap(hdev); if (ret) goto err_cmd_uninit; @@ -11556,7 +11587,7 @@ static int hclge_init_ae_dev(struct hnae3_ae_dev *ae_dev) goto err_mdiobus_unreg; } - ret = hclge_config_gro(hdev, true); + ret = hclge_config_gro(hdev); if (ret) goto err_mdiobus_unreg; @@ -11937,7 +11968,7 @@ static int hclge_reset_ae_dev(struct hnae3_ae_dev *ae_dev) return ret; } - ret = hclge_config_gro(hdev, true); + ret = hclge_config_gro(hdev); if (ret) return ret; @@ -12671,8 +12702,15 @@ static int hclge_gro_en(struct hnae3_handle *handle, bool enable) { struct hclge_vport *vport = hclge_get_vport(handle); struct hclge_dev *hdev = vport->back; + bool gro_en_old = hdev->gro_en; + int ret; - return hclge_config_gro(hdev, enable); + hdev->gro_en = enable; + ret = hclge_config_gro(hdev); + if (ret) + hdev->gro_en = gro_en_old; + + return ret; } static void hclge_sync_promisc_mode(struct hclge_dev *hdev) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h index 3d3352491dba..e446b839a371 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h @@ -927,6 +927,7 @@ struct hclge_dev { unsigned long fd_bmap[BITS_TO_LONGS(MAX_FD_FILTER_NUM)]; enum HCLGE_FD_ACTIVE_RULE_TYPE fd_active_type; u8 fd_en; + bool gro_en; u16 wanted_umv_size; /* max available unicast mac vlan space */ diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.c index bd19a2d89f6c..d9ddb0a243d4 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.c @@ -507,12 +507,17 @@ static void hclgevf_cmd_uninit_regs(struct hclgevf_hw *hw) void hclgevf_cmd_uninit(struct hclgevf_dev *hdev) { + set_bit(HCLGEVF_STATE_CMD_DISABLE, &hdev->state); + /* wait to ensure that the firmware completes the possible left + * over commands. + */ + msleep(HCLGEVF_CMDQ_CLEAR_WAIT_TIME); spin_lock_bh(&hdev->hw.cmq.csq.lock); spin_lock(&hdev->hw.cmq.crq.lock); - set_bit(HCLGEVF_STATE_CMD_DISABLE, &hdev->state); hclgevf_cmd_uninit_regs(&hdev->hw); spin_unlock(&hdev->hw.cmq.crq.lock); spin_unlock_bh(&hdev->hw.cmq.csq.lock); + hclgevf_free_cmd_desc(&hdev->hw.cmq.csq); hclgevf_free_cmd_desc(&hdev->hw.cmq.crq); } diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.h b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.h index 202feb70dba5..5b82177f98b4 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_cmd.h @@ -8,6 +8,7 @@ #include "hnae3.h" #define HCLGEVF_CMDQ_TX_TIMEOUT 30000 +#define HCLGEVF_CMDQ_CLEAR_WAIT_TIME 200 #define HCLGEVF_CMDQ_RX_INVLD_B 0 #define HCLGEVF_CMDQ_RX_OUTVLD_B 1 diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c index 8784d61e833f..938654778979 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.c @@ -506,10 +506,10 @@ void hclgevf_update_link_status(struct hclgevf_dev *hdev, int link_state) link_state = test_bit(HCLGEVF_STATE_DOWN, &hdev->state) ? 0 : link_state; if (link_state != hdev->hw.mac.link) { + hdev->hw.mac.link = link_state; client->ops->link_status_change(handle, !!link_state); if (rclient && rclient->ops->link_status_change) rclient->ops->link_status_change(rhandle, !!link_state); - hdev->hw.mac.link = link_state; } clear_bit(HCLGEVF_STATE_LINK_UPDATING, &hdev->state); @@ -2487,6 +2487,8 @@ static int hclgevf_configure(struct hclgevf_dev *hdev) { int ret; + hdev->gro_en = true; + ret = hclgevf_get_basic_info(hdev); if (ret) return ret; @@ -2549,7 +2551,7 @@ static int hclgevf_init_roce_base_info(struct hclgevf_dev *hdev) return 0; } -static int hclgevf_config_gro(struct hclgevf_dev *hdev, bool en) +static int hclgevf_config_gro(struct hclgevf_dev *hdev) { struct hclgevf_cfg_gro_status_cmd *req; struct hclgevf_desc desc; @@ -2562,7 +2564,7 @@ static int hclgevf_config_gro(struct hclgevf_dev *hdev, bool en) false); req = (struct hclgevf_cfg_gro_status_cmd *)desc.data; - req->gro_en = en ? 1 : 0; + req->gro_en = hdev->gro_en ? 1 : 0; ret = hclgevf_cmd_send(&hdev->hw, &desc, 1); if (ret) @@ -3308,7 +3310,7 @@ static int hclgevf_reset_hdev(struct hclgevf_dev *hdev) return ret; } - ret = hclgevf_config_gro(hdev, true); + ret = hclgevf_config_gro(hdev); if (ret) return ret; @@ -3389,7 +3391,7 @@ static int hclgevf_init_hdev(struct hclgevf_dev *hdev) if (ret) goto err_config; - ret = hclgevf_config_gro(hdev, true); + ret = hclgevf_config_gro(hdev); if (ret) goto err_config; @@ -3638,8 +3640,15 @@ void hclgevf_update_speed_duplex(struct hclgevf_dev *hdev, u32 speed, static int hclgevf_gro_en(struct hnae3_handle *handle, bool enable) { struct hclgevf_dev *hdev = hclgevf_ae_get_hdev(handle); + bool gro_en_old = hdev->gro_en; + int ret; - return hclgevf_config_gro(hdev, enable); + hdev->gro_en = enable; + ret = hclgevf_config_gro(hdev); + if (ret) + hdev->gro_en = gro_en_old; + + return ret; } static void hclgevf_get_media_type(struct hnae3_handle *handle, u8 *media_type, diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h index d7d02848d674..e8013be055f8 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_main.h @@ -310,6 +310,8 @@ struct hclgevf_dev { u16 *vector_status; int *vector_irq; + bool gro_en; + unsigned long vlan_del_fail_bmap[BITS_TO_LONGS(VLAN_N_VID)]; struct hclgevf_mac_table_cfg mac_table; diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_mbx.c b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_mbx.c index 772b2f8acd2e..b339b9bc0625 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_mbx.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3vf/hclgevf_mbx.c @@ -323,8 +323,8 @@ void hclgevf_mbx_async_handler(struct hclgevf_dev *hdev) flag = (u8)msg_q[5]; /* update upper layer with new link link status */ - hclgevf_update_link_status(hdev, link_status); hclgevf_update_speed_duplex(hdev, speed, duplex); + hclgevf_update_link_status(hdev, link_status); if (flag & HCLGE_MBX_PUSH_LINK_STATUS_EN) set_bit(HCLGEVF_STATE_PF_PUSH_LINK_STATUS, diff --git a/drivers/net/ethernet/intel/e1000e/ich8lan.c b/drivers/net/ethernet/intel/e1000e/ich8lan.c index cf7b3887da1d..a80336c4319b 100644 --- a/drivers/net/ethernet/intel/e1000e/ich8lan.c +++ b/drivers/net/ethernet/intel/e1000e/ich8lan.c @@ -1006,6 +1006,8 @@ static s32 e1000_platform_pm_pch_lpt(struct e1000_hw *hw, bool link) { u32 reg = link << (E1000_LTRV_REQ_SHIFT + E1000_LTRV_NOSNOOP_SHIFT) | link << E1000_LTRV_REQ_SHIFT | E1000_LTRV_SEND; + u16 max_ltr_enc_d = 0; /* maximum LTR decoded by platform */ + u16 lat_enc_d = 0; /* latency decoded */ u16 lat_enc = 0; /* latency encoded */ if (link) { @@ -1059,7 +1061,17 @@ static s32 e1000_platform_pm_pch_lpt(struct e1000_hw *hw, bool link) E1000_PCI_LTR_CAP_LPT + 2, &max_nosnoop); max_ltr_enc = max_t(u16, max_snoop, max_nosnoop); - if (lat_enc > max_ltr_enc) + lat_enc_d = (lat_enc & E1000_LTRV_VALUE_MASK) * + (1U << (E1000_LTRV_SCALE_FACTOR * + ((lat_enc & E1000_LTRV_SCALE_MASK) + >> E1000_LTRV_SCALE_SHIFT))); + + max_ltr_enc_d = (max_ltr_enc & E1000_LTRV_VALUE_MASK) * + (1U << (E1000_LTRV_SCALE_FACTOR * + ((max_ltr_enc & E1000_LTRV_SCALE_MASK) + >> E1000_LTRV_SCALE_SHIFT))); + + if (lat_enc_d > max_ltr_enc_d) lat_enc = max_ltr_enc; } @@ -4115,13 +4127,17 @@ static s32 e1000_validate_nvm_checksum_ich8lan(struct e1000_hw *hw) return ret_val; if (!(data & valid_csum_mask)) { - data |= valid_csum_mask; - ret_val = e1000_write_nvm(hw, word, 1, &data); - if (ret_val) - return ret_val; - ret_val = e1000e_update_nvm_checksum(hw); - if (ret_val) - return ret_val; + e_dbg("NVM Checksum Invalid\n"); + + if (hw->mac.type < e1000_pch_cnp) { + data |= valid_csum_mask; + ret_val = e1000_write_nvm(hw, word, 1, &data); + if (ret_val) + return ret_val; + ret_val = e1000e_update_nvm_checksum(hw); + if (ret_val) + return ret_val; + } } return e1000e_validate_nvm_checksum_generic(hw); diff --git a/drivers/net/ethernet/intel/e1000e/ich8lan.h b/drivers/net/ethernet/intel/e1000e/ich8lan.h index 1502895eb45d..e757896287eb 100644 --- a/drivers/net/ethernet/intel/e1000e/ich8lan.h +++ b/drivers/net/ethernet/intel/e1000e/ich8lan.h @@ -274,8 +274,11 @@ /* Latency Tolerance Reporting */ #define E1000_LTRV 0x000F8 +#define E1000_LTRV_VALUE_MASK 0x000003FF #define E1000_LTRV_SCALE_MAX 5 #define E1000_LTRV_SCALE_FACTOR 5 +#define E1000_LTRV_SCALE_SHIFT 10 +#define E1000_LTRV_SCALE_MASK 0x00001C00 #define E1000_LTRV_REQ_SHIFT 15 #define E1000_LTRV_NOSNOOP_SHIFT 16 #define E1000_LTRV_SEND (1 << 30) diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c index 3f25bd8c4924..10a83e5385c7 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c @@ -3663,8 +3663,7 @@ u16 i40e_lan_select_queue(struct net_device *netdev, /* is DCB enabled at all? */ if (vsi->tc_config.numtc == 1) - return i40e_swdcb_skb_tx_hash(netdev, skb, - netdev->real_num_tx_queues); + return netdev_pick_tx(netdev, skb, sb_dev); prio = skb->priority; hw = &vsi->back->hw; diff --git a/drivers/net/ethernet/intel/iavf/iavf.h b/drivers/net/ethernet/intel/iavf/iavf.h index e8bd04100ecd..90793b36126e 100644 --- a/drivers/net/ethernet/intel/iavf/iavf.h +++ b/drivers/net/ethernet/intel/iavf/iavf.h @@ -136,6 +136,7 @@ struct iavf_q_vector { struct iavf_mac_filter { struct list_head list; u8 macaddr[ETH_ALEN]; + bool is_new_mac; /* filter is new, wait for PF decision */ bool remove; /* filter needs to be removed */ bool add; /* filter needs to be added */ }; diff --git a/drivers/net/ethernet/intel/iavf/iavf_main.c b/drivers/net/ethernet/intel/iavf/iavf_main.c index 244ec74ceca7..606a01ce4073 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_main.c +++ b/drivers/net/ethernet/intel/iavf/iavf_main.c @@ -751,6 +751,7 @@ struct iavf_mac_filter *iavf_add_filter(struct iavf_adapter *adapter, list_add_tail(&f->list, &adapter->mac_filter_list); f->add = true; + f->is_new_mac = true; adapter->aq_required |= IAVF_FLAG_AQ_ADD_MAC_FILTER; } else { f->remove = false; diff --git a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c index 0eab3c43bdc5..3c735968e1b8 100644 --- a/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c +++ b/drivers/net/ethernet/intel/iavf/iavf_virtchnl.c @@ -541,6 +541,47 @@ void iavf_del_ether_addrs(struct iavf_adapter *adapter) } /** + * iavf_mac_add_ok + * @adapter: adapter structure + * + * Submit list of filters based on PF response. + **/ +static void iavf_mac_add_ok(struct iavf_adapter *adapter) +{ + struct iavf_mac_filter *f, *ftmp; + + spin_lock_bh(&adapter->mac_vlan_list_lock); + list_for_each_entry_safe(f, ftmp, &adapter->mac_filter_list, list) { + f->is_new_mac = false; + } + spin_unlock_bh(&adapter->mac_vlan_list_lock); +} + +/** + * iavf_mac_add_reject + * @adapter: adapter structure + * + * Remove filters from list based on PF response. + **/ +static void iavf_mac_add_reject(struct iavf_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + struct iavf_mac_filter *f, *ftmp; + + spin_lock_bh(&adapter->mac_vlan_list_lock); + list_for_each_entry_safe(f, ftmp, &adapter->mac_filter_list, list) { + if (f->remove && ether_addr_equal(f->macaddr, netdev->dev_addr)) + f->remove = false; + + if (f->is_new_mac) { + list_del(&f->list); + kfree(f); + } + } + spin_unlock_bh(&adapter->mac_vlan_list_lock); +} + +/** * iavf_add_vlans * @adapter: adapter structure * @@ -1492,6 +1533,7 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter, case VIRTCHNL_OP_ADD_ETH_ADDR: dev_err(&adapter->pdev->dev, "Failed to add MAC filter, error %s\n", iavf_stat_str(&adapter->hw, v_retval)); + iavf_mac_add_reject(adapter); /* restore administratively set MAC address */ ether_addr_copy(adapter->hw.mac.addr, netdev->dev_addr); break; @@ -1639,10 +1681,11 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter, } } switch (v_opcode) { - case VIRTCHNL_OP_ADD_ETH_ADDR: { + case VIRTCHNL_OP_ADD_ETH_ADDR: + if (!v_retval) + iavf_mac_add_ok(adapter); if (!ether_addr_equal(netdev->dev_addr, adapter->hw.mac.addr)) ether_addr_copy(netdev->dev_addr, adapter->hw.mac.addr); - } break; case VIRTCHNL_OP_GET_STATS: { struct iavf_eth_stats *stats = diff --git a/drivers/net/ethernet/intel/ice/ice_devlink.c b/drivers/net/ethernet/intel/ice/ice_devlink.c index 91b545ab8b8f..7fe6e8ea39f0 100644 --- a/drivers/net/ethernet/intel/ice/ice_devlink.c +++ b/drivers/net/ethernet/intel/ice/ice_devlink.c @@ -42,7 +42,9 @@ static int ice_info_pba(struct ice_pf *pf, struct ice_info_ctx *ctx) status = ice_read_pba_string(hw, (u8 *)ctx->buf, sizeof(ctx->buf)); if (status) - return -EIO; + /* We failed to locate the PBA, so just skip this entry */ + dev_dbg(ice_pf_to_dev(pf), "Failed to read Product Board Assembly string, status %s\n", + ice_stat_str(status)); return 0; } diff --git a/drivers/net/ethernet/intel/ice/ice_ptp.c b/drivers/net/ethernet/intel/ice/ice_ptp.c index 5d5207b56ca9..9e3ddb9b8b51 100644 --- a/drivers/net/ethernet/intel/ice/ice_ptp.c +++ b/drivers/net/ethernet/intel/ice/ice_ptp.c @@ -656,7 +656,7 @@ static int ice_ptp_cfg_clkout(struct ice_pf *pf, unsigned int chan, * maintaining phase */ if (start_time < current_time) - start_time = div64_u64(current_time + NSEC_PER_MSEC - 1, + start_time = div64_u64(current_time + NSEC_PER_SEC - 1, NSEC_PER_SEC) * NSEC_PER_SEC + phase; start_time -= E810_OUT_PROP_DELAY_NS; diff --git a/drivers/net/ethernet/intel/igc/igc_main.c b/drivers/net/ethernet/intel/igc/igc_main.c index e29aadbc6744..ed2d66bc2d6c 100644 --- a/drivers/net/ethernet/intel/igc/igc_main.c +++ b/drivers/net/ethernet/intel/igc/igc_main.c @@ -149,6 +149,9 @@ static void igc_release_hw_control(struct igc_adapter *adapter) struct igc_hw *hw = &adapter->hw; u32 ctrl_ext; + if (!pci_device_is_present(adapter->pdev)) + return; + /* Let firmware take over control of h/w */ ctrl_ext = rd32(IGC_CTRL_EXT); wr32(IGC_CTRL_EXT, @@ -4449,26 +4452,29 @@ void igc_down(struct igc_adapter *adapter) igc_ptp_suspend(adapter); - /* disable receives in the hardware */ - rctl = rd32(IGC_RCTL); - wr32(IGC_RCTL, rctl & ~IGC_RCTL_EN); - /* flush and sleep below */ - + if (pci_device_is_present(adapter->pdev)) { + /* disable receives in the hardware */ + rctl = rd32(IGC_RCTL); + wr32(IGC_RCTL, rctl & ~IGC_RCTL_EN); + /* flush and sleep below */ + } /* set trans_start so we don't get spurious watchdogs during reset */ netif_trans_update(netdev); netif_carrier_off(netdev); netif_tx_stop_all_queues(netdev); - /* disable transmits in the hardware */ - tctl = rd32(IGC_TCTL); - tctl &= ~IGC_TCTL_EN; - wr32(IGC_TCTL, tctl); - /* flush both disables and wait for them to finish */ - wrfl(); - usleep_range(10000, 20000); + if (pci_device_is_present(adapter->pdev)) { + /* disable transmits in the hardware */ + tctl = rd32(IGC_TCTL); + tctl &= ~IGC_TCTL_EN; + wr32(IGC_TCTL, tctl); + /* flush both disables and wait for them to finish */ + wrfl(); + usleep_range(10000, 20000); - igc_irq_disable(adapter); + igc_irq_disable(adapter); + } adapter->flags &= ~IGC_FLAG_NEED_LINK_UPDATE; @@ -5489,7 +5495,7 @@ static bool validate_schedule(struct igc_adapter *adapter, if (e->command != TC_TAPRIO_CMD_SET_GATES) return false; - for (i = 0; i < IGC_MAX_TX_QUEUES; i++) { + for (i = 0; i < adapter->num_tx_queues; i++) { if (e->gate_mask & BIT(i)) queue_uses[i]++; @@ -5546,7 +5552,7 @@ static int igc_save_qbv_schedule(struct igc_adapter *adapter, end_time += e->interval; - for (i = 0; i < IGC_MAX_TX_QUEUES; i++) { + for (i = 0; i < adapter->num_tx_queues; i++) { struct igc_ring *ring = adapter->tx_ring[i]; if (!(e->gate_mask & BIT(i))) diff --git a/drivers/net/ethernet/intel/igc/igc_ptp.c b/drivers/net/ethernet/intel/igc/igc_ptp.c index 69617d2c1be2..4ae19c6a3247 100644 --- a/drivers/net/ethernet/intel/igc/igc_ptp.c +++ b/drivers/net/ethernet/intel/igc/igc_ptp.c @@ -849,7 +849,8 @@ void igc_ptp_suspend(struct igc_adapter *adapter) adapter->ptp_tx_skb = NULL; clear_bit_unlock(__IGC_PTP_TX_IN_PROGRESS, &adapter->state); - igc_ptp_time_save(adapter); + if (pci_device_is_present(adapter->pdev)) + igc_ptp_time_save(adapter); } /** diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_xsk.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_xsk.c index 96dd1a4f956a..b1d22e4d5ec9 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_xsk.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_xsk.c @@ -52,8 +52,11 @@ static int ixgbe_xsk_pool_enable(struct ixgbe_adapter *adapter, /* Kick start the NAPI context so that receiving will start */ err = ixgbe_xsk_wakeup(adapter->netdev, qid, XDP_WAKEUP_RX); - if (err) + if (err) { + clear_bit(qid, adapter->af_xdp_zc_qps); + xsk_pool_dma_unmap(pool, IXGBE_RX_DMA_ATTR); return err; + } } return 0; diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index 76a7777c746d..de32e5b49053 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -105,7 +105,7 @@ #define MVNETA_VLAN_PRIO_TO_RXQ 0x2440 #define MVNETA_VLAN_PRIO_RXQ_MAP(prio, rxq) ((rxq) << ((prio) * 3)) #define MVNETA_PORT_STATUS 0x2444 -#define MVNETA_TX_IN_PRGRS BIT(1) +#define MVNETA_TX_IN_PRGRS BIT(0) #define MVNETA_TX_FIFO_EMPTY BIT(8) #define MVNETA_RX_MIN_FRAME_SIZE 0x247c /* Only exists on Armada XP and Armada 370 */ diff --git a/drivers/net/ethernet/mscc/ocelot.c b/drivers/net/ethernet/mscc/ocelot.c index adfb9781799e..2948d731a1c1 100644 --- a/drivers/net/ethernet/mscc/ocelot.c +++ b/drivers/net/ethernet/mscc/ocelot.c @@ -1334,6 +1334,7 @@ void ocelot_apply_bridge_fwd_mask(struct ocelot *ocelot) struct net_device *bond = ocelot_port->bond; mask = ocelot_get_bridge_fwd_mask(ocelot, bridge); + mask |= cpu_fwd_mask; mask &= ~BIT(port); if (bond) { mask &= ~ocelot_get_bond_mask(ocelot, bond, diff --git a/drivers/net/ethernet/qlogic/qed/qed_ll2.c b/drivers/net/ethernet/qlogic/qed/qed_ll2.c index 02a4610d9330..c46a7f756ed5 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_ll2.c +++ b/drivers/net/ethernet/qlogic/qed/qed_ll2.c @@ -327,6 +327,9 @@ static int qed_ll2_txq_completion(struct qed_hwfn *p_hwfn, void *p_cookie) unsigned long flags; int rc = -EINVAL; + if (!p_ll2_conn) + return rc; + spin_lock_irqsave(&p_tx->lock, flags); if (p_tx->b_completing_packet) { rc = -EBUSY; @@ -500,7 +503,16 @@ static int qed_ll2_rxq_completion(struct qed_hwfn *p_hwfn, void *cookie) unsigned long flags = 0; int rc = 0; + if (!p_ll2_conn) + return rc; + spin_lock_irqsave(&p_rx->lock, flags); + + if (!QED_LL2_RX_REGISTERED(p_ll2_conn)) { + spin_unlock_irqrestore(&p_rx->lock, flags); + return 0; + } + cq_new_idx = le16_to_cpu(*p_rx->p_fw_cons); cq_old_idx = qed_chain_get_cons_idx(&p_rx->rcq_chain); @@ -821,6 +833,9 @@ static int qed_ll2_lb_rxq_completion(struct qed_hwfn *p_hwfn, void *p_cookie) struct qed_ll2_info *p_ll2_conn = (struct qed_ll2_info *)p_cookie; int rc; + if (!p_ll2_conn) + return 0; + if (!QED_LL2_RX_REGISTERED(p_ll2_conn)) return 0; @@ -844,6 +859,9 @@ static int qed_ll2_lb_txq_completion(struct qed_hwfn *p_hwfn, void *p_cookie) u16 new_idx = 0, num_bds = 0; int rc; + if (!p_ll2_conn) + return 0; + if (!QED_LL2_TX_REGISTERED(p_ll2_conn)) return 0; @@ -1728,6 +1746,8 @@ int qed_ll2_post_rx_buffer(void *cxt, if (!p_ll2_conn) return -EINVAL; p_rx = &p_ll2_conn->rx_queue; + if (!p_rx->set_prod_addr) + return -EIO; spin_lock_irqsave(&p_rx->lock, flags); if (!list_empty(&p_rx->free_descq)) diff --git a/drivers/net/ethernet/qlogic/qed/qed_main.c b/drivers/net/ethernet/qlogic/qed/qed_main.c index 5bd58c65e163..6bb9ec98a12b 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_main.c +++ b/drivers/net/ethernet/qlogic/qed/qed_main.c @@ -616,7 +616,12 @@ static int qed_enable_msix(struct qed_dev *cdev, rc = cnt; } - if (rc > 0) { + /* For VFs, we should return with an error in case we didn't get the + * exact number of msix vectors as we requested. + * Not doing that will lead to a crash when starting queues for + * this VF. + */ + if ((IS_PF(cdev) && rc > 0) || (IS_VF(cdev) && rc == cnt)) { /* MSI-x configuration was achieved */ int_params->out.int_mode = QED_INT_MODE_MSIX; int_params->out.num_vectors = rc; diff --git a/drivers/net/ethernet/qlogic/qed/qed_rdma.c b/drivers/net/ethernet/qlogic/qed/qed_rdma.c index da864d12916b..4f4b79250a2b 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_rdma.c +++ b/drivers/net/ethernet/qlogic/qed/qed_rdma.c @@ -1285,8 +1285,7 @@ qed_rdma_create_qp(void *rdma_cxt, if (!rdma_cxt || !in_params || !out_params || !p_hwfn->p_rdma_info->active) { - DP_ERR(p_hwfn->cdev, - "qed roce create qp failed due to NULL entry (rdma_cxt=%p, in=%p, out=%p, roce_info=?\n", + pr_err("qed roce create qp failed due to NULL entry (rdma_cxt=%p, in=%p, out=%p, roce_info=?\n", rdma_cxt, in_params, out_params); return NULL; } diff --git a/drivers/net/ethernet/qlogic/qede/qede_main.c b/drivers/net/ethernet/qlogic/qede/qede_main.c index 7c6064baeba2..1c7f9ed6f1c1 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_main.c +++ b/drivers/net/ethernet/qlogic/qede/qede_main.c @@ -1874,6 +1874,7 @@ static void qede_sync_free_irqs(struct qede_dev *edev) } edev->int_info.used_cnt = 0; + edev->int_info.msix_cnt = 0; } static int qede_req_msix_irqs(struct qede_dev *edev) @@ -2427,7 +2428,6 @@ static int qede_load(struct qede_dev *edev, enum qede_load_mode mode, goto out; err4: qede_sync_free_irqs(edev); - memset(&edev->int_info.msix_cnt, 0, sizeof(struct qed_int_info)); err3: qede_napi_disable_remove(edev); err2: diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c index d8882d0b6b49..d51bac7ba5af 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c @@ -3156,8 +3156,10 @@ int qlcnic_83xx_flash_read32(struct qlcnic_adapter *adapter, u32 flash_addr, indirect_addr = QLC_83XX_FLASH_DIRECT_DATA(addr); ret = QLCRD32(adapter, indirect_addr, &err); - if (err == -EIO) + if (err == -EIO) { + qlcnic_83xx_unlock_flash(adapter); return err; + } word = ret; *(u32 *)p_data = word; diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c index 280ac0129572..ed817011a94a 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c @@ -21,7 +21,6 @@ #include <linux/delay.h> #include <linux/mfd/syscon.h> #include <linux/regmap.h> -#include <linux/pm_runtime.h> #include "stmmac_platform.h" @@ -1529,9 +1528,6 @@ static int rk_gmac_powerup(struct rk_priv_data *bsp_priv) return ret; } - pm_runtime_enable(dev); - pm_runtime_get_sync(dev); - if (bsp_priv->integrated_phy) rk_gmac_integrated_phy_powerup(bsp_priv); @@ -1540,14 +1536,9 @@ static int rk_gmac_powerup(struct rk_priv_data *bsp_priv) static void rk_gmac_powerdown(struct rk_priv_data *gmac) { - struct device *dev = &gmac->pdev->dev; - if (gmac->integrated_phy) rk_gmac_integrated_phy_powerdown(gmac); - pm_runtime_put_sync(dev); - pm_runtime_disable(dev); - phy_power_on(gmac, false); gmac_clk_enable(gmac, false); } diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h index fcdb1d20389b..43eead726886 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h @@ -339,9 +339,9 @@ static inline bool stmmac_xdp_is_enabled(struct stmmac_priv *priv) static inline unsigned int stmmac_rx_offset(struct stmmac_priv *priv) { if (stmmac_xdp_is_enabled(priv)) - return XDP_PACKET_HEADROOM + NET_IP_ALIGN; + return XDP_PACKET_HEADROOM; - return NET_SKB_PAD + NET_IP_ALIGN; + return 0; } void stmmac_disable_rx_queue(struct stmmac_priv *priv, u32 queue); diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 7b8404a21544..fa90bcdf4e45 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -4914,6 +4914,10 @@ read_again: prefetch(np); + /* Ensure a valid XSK buffer before proceed */ + if (!buf->xdp) + break; + if (priv->extend_desc) stmmac_rx_extended_status(priv, &priv->dev->stats, &priv->xstats, @@ -4934,10 +4938,6 @@ read_again: continue; } - /* Ensure a valid XSK buffer before proceed */ - if (!buf->xdp) - break; - /* XSK pool expects RX frame 1:1 mapped to XSK buffer */ if (likely(status & rx_not_ls)) { xsk_buff_free(buf->xdp); diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c index 4f3b6437b114..8160087ee92f 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_tc.c @@ -884,11 +884,13 @@ static int tc_setup_taprio(struct stmmac_priv *priv, return 0; disable: - mutex_lock(&priv->plat->est->lock); - priv->plat->est->enable = false; - stmmac_est_configure(priv, priv->ioaddr, priv->plat->est, - priv->plat->clk_ptp_rate); - mutex_unlock(&priv->plat->est->lock); + if (priv->plat->est) { + mutex_lock(&priv->plat->est->lock); + priv->plat->est->enable = false; + stmmac_est_configure(priv, priv->ioaddr, priv->plat->est, + priv->plat->clk_ptp_rate); + mutex_unlock(&priv->plat->est->lock); + } priv->plat->fpe_cfg->enable = false; stmmac_fpe_configure(priv, priv->ioaddr, diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_xdp.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_xdp.c index 105821b53020..2a616c6f7cd0 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_xdp.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_xdp.c @@ -34,18 +34,18 @@ static int stmmac_xdp_enable_pool(struct stmmac_priv *priv, need_update = netif_running(priv->dev) && stmmac_xdp_is_enabled(priv); if (need_update) { - stmmac_disable_rx_queue(priv, queue); - stmmac_disable_tx_queue(priv, queue); napi_disable(&ch->rx_napi); napi_disable(&ch->tx_napi); + stmmac_disable_rx_queue(priv, queue); + stmmac_disable_tx_queue(priv, queue); } set_bit(queue, priv->af_xdp_zc_qps); if (need_update) { - napi_enable(&ch->rxtx_napi); stmmac_enable_rx_queue(priv, queue); stmmac_enable_tx_queue(priv, queue); + napi_enable(&ch->rxtx_napi); err = stmmac_xsk_wakeup(priv->dev, queue, XDP_WAKEUP_RX); if (err) @@ -72,10 +72,10 @@ static int stmmac_xdp_disable_pool(struct stmmac_priv *priv, u16 queue) need_update = netif_running(priv->dev) && stmmac_xdp_is_enabled(priv); if (need_update) { + napi_disable(&ch->rxtx_napi); stmmac_disable_rx_queue(priv, queue); stmmac_disable_tx_queue(priv, queue); synchronize_rcu(); - napi_disable(&ch->rxtx_napi); } xsk_pool_dma_unmap(pool, STMMAC_RX_DMA_ATTR); @@ -83,10 +83,10 @@ static int stmmac_xdp_disable_pool(struct stmmac_priv *priv, u16 queue) clear_bit(queue, priv->af_xdp_zc_qps); if (need_update) { - napi_enable(&ch->rx_napi); - napi_enable(&ch->tx_napi); stmmac_enable_rx_queue(priv, queue); stmmac_enable_tx_queue(priv, queue); + napi_enable(&ch->rx_napi); + napi_enable(&ch->tx_napi); } return 0; diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c index fcf3af76b6d7..8fe8887d506a 100644 --- a/drivers/net/hamradio/6pack.c +++ b/drivers/net/hamradio/6pack.c @@ -827,6 +827,12 @@ static void decode_data(struct sixpack *sp, unsigned char inbyte) return; } + if (sp->rx_count_cooked + 2 >= sizeof(sp->cooked_buf)) { + pr_err("6pack: cooked buffer overrun, data loss\n"); + sp->rx_count = 0; + return; + } + buf = sp->raw_buf; sp->cooked_buf[sp->rx_count_cooked++] = buf[0] | ((buf[1] << 2) & 0xc0); diff --git a/drivers/net/mdio/mdio-mux.c b/drivers/net/mdio/mdio-mux.c index 110e4ee85785..ebd001f0eece 100644 --- a/drivers/net/mdio/mdio-mux.c +++ b/drivers/net/mdio/mdio-mux.c @@ -82,6 +82,17 @@ out: static int parent_count; +static void mdio_mux_uninit_children(struct mdio_mux_parent_bus *pb) +{ + struct mdio_mux_child_bus *cb = pb->children; + + while (cb) { + mdiobus_unregister(cb->mii_bus); + mdiobus_free(cb->mii_bus); + cb = cb->next; + } +} + int mdio_mux_init(struct device *dev, struct device_node *mux_node, int (*switch_fn)(int cur, int desired, void *data), @@ -144,7 +155,7 @@ int mdio_mux_init(struct device *dev, cb = devm_kzalloc(dev, sizeof(*cb), GFP_KERNEL); if (!cb) { ret_val = -ENOMEM; - continue; + goto err_loop; } cb->bus_number = v; cb->parent = pb; @@ -152,8 +163,7 @@ int mdio_mux_init(struct device *dev, cb->mii_bus = mdiobus_alloc(); if (!cb->mii_bus) { ret_val = -ENOMEM; - devm_kfree(dev, cb); - continue; + goto err_loop; } cb->mii_bus->priv = cb; @@ -165,11 +175,15 @@ int mdio_mux_init(struct device *dev, cb->mii_bus->write = mdio_mux_write; r = of_mdiobus_register(cb->mii_bus, child_bus_node); if (r) { + mdiobus_free(cb->mii_bus); + if (r == -EPROBE_DEFER) { + ret_val = r; + goto err_loop; + } + devm_kfree(dev, cb); dev_err(dev, "Error: Failed to register MDIO bus for child %pOF\n", child_bus_node); - mdiobus_free(cb->mii_bus); - devm_kfree(dev, cb); } else { cb->next = pb->children; pb->children = cb; @@ -181,7 +195,10 @@ int mdio_mux_init(struct device *dev, } dev_err(dev, "Error: No acceptable child buses found\n"); - devm_kfree(dev, pb); + +err_loop: + mdio_mux_uninit_children(pb); + of_node_put(child_bus_node); err_pb_kz: put_device(&parent_bus->dev); err_parent_bus: @@ -193,14 +210,8 @@ EXPORT_SYMBOL_GPL(mdio_mux_init); void mdio_mux_uninit(void *mux_handle) { struct mdio_mux_parent_bus *pb = mux_handle; - struct mdio_mux_child_bus *cb = pb->children; - - while (cb) { - mdiobus_unregister(cb->mii_bus); - mdiobus_free(cb->mii_bus); - cb = cb->next; - } + mdio_mux_uninit_children(pb); put_device(&pb->mii_bus->dev); } EXPORT_SYMBOL_GPL(mdio_mux_uninit); diff --git a/drivers/net/mhi/net.c b/drivers/net/mhi/net.c index 11be6bcdd551..e60e38c1f09d 100644 --- a/drivers/net/mhi/net.c +++ b/drivers/net/mhi/net.c @@ -335,7 +335,7 @@ static int mhi_net_newlink(void *ctxt, struct net_device *ndev, u32 if_id, u64_stats_init(&mhi_netdev->stats.tx_syncp); /* Start MHI channels */ - err = mhi_prepare_for_transfer(mhi_dev, 0); + err = mhi_prepare_for_transfer(mhi_dev); if (err) goto out_err; diff --git a/drivers/net/phy/mediatek-ge.c b/drivers/net/phy/mediatek-ge.c index 11ff335d6228..b7a5ae20edd5 100644 --- a/drivers/net/phy/mediatek-ge.c +++ b/drivers/net/phy/mediatek-ge.c @@ -81,6 +81,8 @@ static struct phy_driver mtk_gephy_driver[] = { */ .config_intr = genphy_no_config_intr, .handle_interrupt = genphy_handle_interrupt_no_ack, + .suspend = genphy_suspend, + .resume = genphy_resume, .read_page = mtk_gephy_read_page, .write_page = mtk_gephy_write_page, }, @@ -93,6 +95,8 @@ static struct phy_driver mtk_gephy_driver[] = { */ .config_intr = genphy_no_config_intr, .handle_interrupt = genphy_handle_interrupt_no_ack, + .suspend = genphy_suspend, + .resume = genphy_resume, .read_page = mtk_gephy_read_page, .write_page = mtk_gephy_write_page, }, diff --git a/drivers/net/usb/asix.h b/drivers/net/usb/asix.h index e1994a246122..2a1e31defe71 100644 --- a/drivers/net/usb/asix.h +++ b/drivers/net/usb/asix.h @@ -184,6 +184,7 @@ struct asix_common_private { struct phy_device *phydev; u16 phy_addr; char phy_name[20]; + bool embd_phy; }; extern const struct driver_info ax88172a_info; diff --git a/drivers/net/usb/asix_common.c b/drivers/net/usb/asix_common.c index ac92bc52a85e..38cda590895c 100644 --- a/drivers/net/usb/asix_common.c +++ b/drivers/net/usb/asix_common.c @@ -63,6 +63,29 @@ void asix_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index, value, index, data, size); } +static int asix_check_host_enable(struct usbnet *dev, int in_pm) +{ + int i, ret; + u8 smsr; + + for (i = 0; i < 30; ++i) { + ret = asix_set_sw_mii(dev, in_pm); + if (ret == -ENODEV || ret == -ETIMEDOUT) + break; + usleep_range(1000, 1100); + ret = asix_read_cmd(dev, AX_CMD_STATMNGSTS_REG, + 0, 0, 1, &smsr, in_pm); + if (ret == -ENODEV) + break; + else if (ret < 0) + continue; + else if (smsr & AX_HOST_EN) + break; + } + + return ret; +} + static void reset_asix_rx_fixup_info(struct asix_rx_fixup_info *rx) { /* Reset the variables that have a lifetime outside of @@ -467,19 +490,11 @@ int asix_mdio_read(struct net_device *netdev, int phy_id, int loc) { struct usbnet *dev = netdev_priv(netdev); __le16 res; - u8 smsr; - int i = 0; int ret; mutex_lock(&dev->phy_mutex); - do { - ret = asix_set_sw_mii(dev, 0); - if (ret == -ENODEV || ret == -ETIMEDOUT) - break; - usleep_range(1000, 1100); - ret = asix_read_cmd(dev, AX_CMD_STATMNGSTS_REG, - 0, 0, 1, &smsr, 0); - } while (!(smsr & AX_HOST_EN) && (i++ < 30) && (ret != -ENODEV)); + + ret = asix_check_host_enable(dev, 0); if (ret == -ENODEV || ret == -ETIMEDOUT) { mutex_unlock(&dev->phy_mutex); return ret; @@ -505,23 +520,14 @@ static int __asix_mdio_write(struct net_device *netdev, int phy_id, int loc, { struct usbnet *dev = netdev_priv(netdev); __le16 res = cpu_to_le16(val); - u8 smsr; - int i = 0; int ret; netdev_dbg(dev->net, "asix_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x\n", phy_id, loc, val); mutex_lock(&dev->phy_mutex); - do { - ret = asix_set_sw_mii(dev, 0); - if (ret == -ENODEV) - break; - usleep_range(1000, 1100); - ret = asix_read_cmd(dev, AX_CMD_STATMNGSTS_REG, - 0, 0, 1, &smsr, 0); - } while (!(smsr & AX_HOST_EN) && (i++ < 30) && (ret != -ENODEV)); + ret = asix_check_host_enable(dev, 0); if (ret == -ENODEV) goto out; @@ -561,19 +567,11 @@ int asix_mdio_read_nopm(struct net_device *netdev, int phy_id, int loc) { struct usbnet *dev = netdev_priv(netdev); __le16 res; - u8 smsr; - int i = 0; int ret; mutex_lock(&dev->phy_mutex); - do { - ret = asix_set_sw_mii(dev, 1); - if (ret == -ENODEV || ret == -ETIMEDOUT) - break; - usleep_range(1000, 1100); - ret = asix_read_cmd(dev, AX_CMD_STATMNGSTS_REG, - 0, 0, 1, &smsr, 1); - } while (!(smsr & AX_HOST_EN) && (i++ < 30) && (ret != -ENODEV)); + + ret = asix_check_host_enable(dev, 1); if (ret == -ENODEV || ret == -ETIMEDOUT) { mutex_unlock(&dev->phy_mutex); return ret; @@ -595,22 +593,14 @@ asix_mdio_write_nopm(struct net_device *netdev, int phy_id, int loc, int val) { struct usbnet *dev = netdev_priv(netdev); __le16 res = cpu_to_le16(val); - u8 smsr; - int i = 0; int ret; netdev_dbg(dev->net, "asix_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x\n", phy_id, loc, val); mutex_lock(&dev->phy_mutex); - do { - ret = asix_set_sw_mii(dev, 1); - if (ret == -ENODEV) - break; - usleep_range(1000, 1100); - ret = asix_read_cmd(dev, AX_CMD_STATMNGSTS_REG, - 0, 0, 1, &smsr, 1); - } while (!(smsr & AX_HOST_EN) && (i++ < 30) && (ret != -ENODEV)); + + ret = asix_check_host_enable(dev, 1); if (ret == -ENODEV) { mutex_unlock(&dev->phy_mutex); return; diff --git a/drivers/net/usb/asix_devices.c b/drivers/net/usb/asix_devices.c index 2c115216420a..dc87e8caf954 100644 --- a/drivers/net/usb/asix_devices.c +++ b/drivers/net/usb/asix_devices.c @@ -354,24 +354,23 @@ out: static int ax88772_hw_reset(struct usbnet *dev, int in_pm) { struct asix_data *data = (struct asix_data *)&dev->data; - int ret, embd_phy; + struct asix_common_private *priv = dev->driver_priv; u16 rx_ctl; + int ret; ret = asix_write_gpio(dev, AX_GPIO_RSE | AX_GPIO_GPO_2 | AX_GPIO_GPO2EN, 5, in_pm); if (ret < 0) goto out; - embd_phy = ((dev->mii.phy_id & 0x1f) == 0x10 ? 1 : 0); - - ret = asix_write_cmd(dev, AX_CMD_SW_PHY_SELECT, embd_phy, + ret = asix_write_cmd(dev, AX_CMD_SW_PHY_SELECT, priv->embd_phy, 0, 0, NULL, in_pm); if (ret < 0) { netdev_dbg(dev->net, "Select PHY #1 failed: %d\n", ret); goto out; } - if (embd_phy) { + if (priv->embd_phy) { ret = asix_sw_reset(dev, AX_SWRESET_IPPD, in_pm); if (ret < 0) goto out; @@ -449,17 +448,16 @@ out: static int ax88772a_hw_reset(struct usbnet *dev, int in_pm) { struct asix_data *data = (struct asix_data *)&dev->data; - int ret, embd_phy; + struct asix_common_private *priv = dev->driver_priv; u16 rx_ctl, phy14h, phy15h, phy16h; u8 chipcode = 0; + int ret; ret = asix_write_gpio(dev, AX_GPIO_RSE, 5, in_pm); if (ret < 0) goto out; - embd_phy = ((dev->mii.phy_id & 0x1f) == 0x10 ? 1 : 0); - - ret = asix_write_cmd(dev, AX_CMD_SW_PHY_SELECT, embd_phy | + ret = asix_write_cmd(dev, AX_CMD_SW_PHY_SELECT, priv->embd_phy | AX_PHYSEL_SSEN, 0, 0, NULL, in_pm); if (ret < 0) { netdev_dbg(dev->net, "Select PHY #1 failed: %d\n", ret); @@ -683,12 +681,6 @@ static int ax88772_init_phy(struct usbnet *dev) struct asix_common_private *priv = dev->driver_priv; int ret; - ret = asix_read_phy_addr(dev, true); - if (ret < 0) - return ret; - - priv->phy_addr = ret; - snprintf(priv->phy_name, sizeof(priv->phy_name), PHY_ID_FMT, priv->mdio->id, priv->phy_addr); @@ -716,6 +708,12 @@ static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf) int ret, i; u32 phyid; + priv = devm_kzalloc(&dev->udev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + dev->driver_priv = priv; + usbnet_get_endpoints(dev, intf); /* Maybe the boot loader passed the MAC address via device tree */ @@ -751,6 +749,13 @@ static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf) dev->net->needed_headroom = 4; /* cf asix_tx_fixup() */ dev->net->needed_tailroom = 4; /* cf asix_tx_fixup() */ + ret = asix_read_phy_addr(dev, true); + if (ret < 0) + return ret; + + priv->phy_addr = ret; + priv->embd_phy = ((priv->phy_addr & 0x1f) == 0x10); + asix_read_cmd(dev, AX_CMD_STATMNGSTS_REG, 0, 0, 1, &chipcode, 0); chipcode &= AX_CHIPCODE_MASK; @@ -773,12 +778,6 @@ static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf) dev->rx_urb_size = 2048; } - priv = devm_kzalloc(&dev->udev->dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - dev->driver_priv = priv; - priv->presvd_phy_bmcr = 0; priv->presvd_phy_advertise = 0; if (chipcode == AX_AX88772_CHIPCODE) { @@ -817,6 +816,12 @@ static void ax88772_unbind(struct usbnet *dev, struct usb_interface *intf) asix_rx_fixup_common_free(dev->driver_priv); } +static void ax88178_unbind(struct usbnet *dev, struct usb_interface *intf) +{ + asix_rx_fixup_common_free(dev->driver_priv); + kfree(dev->driver_priv); +} + static const struct ethtool_ops ax88178_ethtool_ops = { .get_drvinfo = asix_get_drvinfo, .get_link = asix_get_link, @@ -1225,7 +1230,7 @@ static const struct driver_info ax88772b_info = { static const struct driver_info ax88178_info = { .description = "ASIX AX88178 USB 2.0 Ethernet", .bind = ax88178_bind, - .unbind = ax88772_unbind, + .unbind = ax88178_unbind, .status = asix_status, .link_reset = ax88178_link_reset, .reset = ax88178_reset, diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c index 652e9fcf0b77..9f9dd0de33cb 100644 --- a/drivers/net/usb/pegasus.c +++ b/drivers/net/usb/pegasus.c @@ -446,7 +446,7 @@ static int enable_net_traffic(struct net_device *dev, struct usb_device *usb) write_mii_word(pegasus, 0, 0x1b, &auxmode); } - return 0; + return ret; fail: netif_dbg(pegasus, drv, pegasus->net, "%s failed\n", __func__); return ret; @@ -835,7 +835,7 @@ static int pegasus_open(struct net_device *net) if (!pegasus->rx_skb) goto exit; - res = set_registers(pegasus, EthID, 6, net->dev_addr); + set_registers(pegasus, EthID, 6, net->dev_addr); usb_fill_bulk_urb(pegasus->rx_urb, pegasus->usb, usb_rcvbulkpipe(pegasus->usb, 1), diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index e09b107b5c99..79832374f78d 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -3955,17 +3955,28 @@ static void rtl_clear_bp(struct r8152 *tp, u16 type) case RTL_VER_06: ocp_write_byte(tp, type, PLA_BP_EN, 0); break; + case RTL_VER_14: + ocp_write_word(tp, type, USB_BP2_EN, 0); + + ocp_write_word(tp, type, USB_BP_8, 0); + ocp_write_word(tp, type, USB_BP_9, 0); + ocp_write_word(tp, type, USB_BP_10, 0); + ocp_write_word(tp, type, USB_BP_11, 0); + ocp_write_word(tp, type, USB_BP_12, 0); + ocp_write_word(tp, type, USB_BP_13, 0); + ocp_write_word(tp, type, USB_BP_14, 0); + ocp_write_word(tp, type, USB_BP_15, 0); + break; case RTL_VER_08: case RTL_VER_09: case RTL_VER_10: case RTL_VER_11: case RTL_VER_12: case RTL_VER_13: - case RTL_VER_14: case RTL_VER_15: default: if (type == MCU_TYPE_USB) { - ocp_write_byte(tp, MCU_TYPE_USB, USB_BP2_EN, 0); + ocp_write_word(tp, MCU_TYPE_USB, USB_BP2_EN, 0); ocp_write_word(tp, MCU_TYPE_USB, USB_BP_8, 0); ocp_write_word(tp, MCU_TYPE_USB, USB_BP_9, 0); @@ -4331,7 +4342,6 @@ static bool rtl8152_is_fw_mac_ok(struct r8152 *tp, struct fw_mac *mac) case RTL_VER_11: case RTL_VER_12: case RTL_VER_13: - case RTL_VER_14: case RTL_VER_15: fw_reg = 0xf800; bp_ba_addr = PLA_BP_BA; @@ -4339,6 +4349,13 @@ static bool rtl8152_is_fw_mac_ok(struct r8152 *tp, struct fw_mac *mac) bp_start = PLA_BP_0; max_bp = 8; break; + case RTL_VER_14: + fw_reg = 0xf800; + bp_ba_addr = PLA_BP_BA; + bp_en_addr = USB_BP2_EN; + bp_start = PLA_BP_0; + max_bp = 16; + break; default: goto out; } diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 56c3f8519093..eee493685aad 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -63,7 +63,7 @@ static const unsigned long guest_offloads[] = { VIRTIO_NET_F_GUEST_CSUM }; -#define GUEST_OFFLOAD_LRO_MASK ((1ULL << VIRTIO_NET_F_GUEST_TSO4) | \ +#define GUEST_OFFLOAD_GRO_HW_MASK ((1ULL << VIRTIO_NET_F_GUEST_TSO4) | \ (1ULL << VIRTIO_NET_F_GUEST_TSO6) | \ (1ULL << VIRTIO_NET_F_GUEST_ECN) | \ (1ULL << VIRTIO_NET_F_GUEST_UFO)) @@ -2515,7 +2515,7 @@ static int virtnet_xdp_set(struct net_device *dev, struct bpf_prog *prog, virtio_has_feature(vi->vdev, VIRTIO_NET_F_GUEST_ECN) || virtio_has_feature(vi->vdev, VIRTIO_NET_F_GUEST_UFO) || virtio_has_feature(vi->vdev, VIRTIO_NET_F_GUEST_CSUM))) { - NL_SET_ERR_MSG_MOD(extack, "Can't set XDP while host is implementing LRO/CSUM, disable LRO/CSUM first"); + NL_SET_ERR_MSG_MOD(extack, "Can't set XDP while host is implementing GRO_HW/CSUM, disable GRO_HW/CSUM first"); return -EOPNOTSUPP; } @@ -2646,15 +2646,15 @@ static int virtnet_set_features(struct net_device *dev, u64 offloads; int err; - if ((dev->features ^ features) & NETIF_F_LRO) { + if ((dev->features ^ features) & NETIF_F_GRO_HW) { if (vi->xdp_enabled) return -EBUSY; - if (features & NETIF_F_LRO) + if (features & NETIF_F_GRO_HW) offloads = vi->guest_offloads_capable; else offloads = vi->guest_offloads_capable & - ~GUEST_OFFLOAD_LRO_MASK; + ~GUEST_OFFLOAD_GRO_HW_MASK; err = virtnet_set_guest_offloads(vi, offloads); if (err) @@ -3134,9 +3134,9 @@ static int virtnet_probe(struct virtio_device *vdev) dev->features |= NETIF_F_RXCSUM; if (virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_TSO4) || virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_TSO6)) - dev->features |= NETIF_F_LRO; + dev->features |= NETIF_F_GRO_HW; if (virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_GUEST_OFFLOADS)) - dev->hw_features |= NETIF_F_LRO; + dev->hw_features |= NETIF_F_GRO_HW; dev->vlan_features = dev->features; diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c index 2b1b944d4b28..8bbe2a7bb141 100644 --- a/drivers/net/vrf.c +++ b/drivers/net/vrf.c @@ -1367,6 +1367,8 @@ static struct sk_buff *vrf_ip6_rcv(struct net_device *vrf_dev, bool need_strict = rt6_need_strict(&ipv6_hdr(skb)->daddr); bool is_ndisc = ipv6_ndisc_frame(skb); + nf_reset_ct(skb); + /* loopback, multicast & non-ND link-local traffic; do not push through * packet taps again. Reset pkt_type for upper layers to process skb. * For strict packets with a source LLA, determine the dst using the @@ -1429,6 +1431,8 @@ static struct sk_buff *vrf_ip_rcv(struct net_device *vrf_dev, skb->skb_iif = vrf_dev->ifindex; IPCB(skb)->flags |= IPSKB_L3SLAVE; + nf_reset_ct(skb); + if (ipv4_is_multicast(ip_hdr(skb)->daddr)) goto out; diff --git a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c index 2403490cbc26..b4b1f75b9c2a 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c @@ -37,6 +37,7 @@ static int iwl_pnvm_handle_section(struct iwl_trans *trans, const u8 *data, u32 sha1 = 0; u16 mac_type = 0, rf_id = 0; u8 *pnvm_data = NULL, *tmp; + bool hw_match = false; u32 size = 0; int ret; @@ -83,6 +84,9 @@ static int iwl_pnvm_handle_section(struct iwl_trans *trans, const u8 *data, break; } + if (hw_match) + break; + mac_type = le16_to_cpup((__le16 *)data); rf_id = le16_to_cpup((__le16 *)(data + sizeof(__le16))); @@ -90,15 +94,9 @@ static int iwl_pnvm_handle_section(struct iwl_trans *trans, const u8 *data, "Got IWL_UCODE_TLV_HW_TYPE mac_type 0x%0x rf_id 0x%0x\n", mac_type, rf_id); - if (mac_type != CSR_HW_REV_TYPE(trans->hw_rev) || - rf_id != CSR_HW_RFID_TYPE(trans->hw_rf_id)) { - IWL_DEBUG_FW(trans, - "HW mismatch, skipping PNVM section, mac_type 0x%0x, rf_id 0x%0x.\n", - CSR_HW_REV_TYPE(trans->hw_rev), trans->hw_rf_id); - ret = -ENOENT; - goto out; - } - + if (mac_type == CSR_HW_REV_TYPE(trans->hw_rev) && + rf_id == CSR_HW_RFID_TYPE(trans->hw_rf_id)) + hw_match = true; break; case IWL_UCODE_TLV_SEC_RT: { struct iwl_pnvm_section *section = (void *)data; @@ -149,6 +147,15 @@ static int iwl_pnvm_handle_section(struct iwl_trans *trans, const u8 *data, } done: + if (!hw_match) { + IWL_DEBUG_FW(trans, + "HW mismatch, skipping PNVM section (need mac_type 0x%x rf_id 0x%x)\n", + CSR_HW_REV_TYPE(trans->hw_rev), + CSR_HW_RFID_TYPE(trans->hw_rf_id)); + ret = -ENOENT; + goto out; + } + if (!size) { IWL_DEBUG_FW(trans, "Empty PNVM, skipping.\n"); ret = -ENOENT; diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index 16baee3d52ae..0b8a0cd3b652 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -1110,12 +1110,80 @@ static const struct iwl_dev_info iwl_dev_info_table[] = { IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_NO_CDB, iwl_cfg_bz_a0_mr_a0, iwl_ax211_name), +/* SoF with JF2 */ + _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, + IWL_CFG_MAC_TYPE_SOF, IWL_CFG_ANY, + IWL_CFG_RF_TYPE_JF2, IWL_CFG_RF_ID_JF, + IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, + iwlax210_2ax_cfg_so_jf_b0, iwl9560_160_name), + _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, + IWL_CFG_MAC_TYPE_SOF, IWL_CFG_ANY, + IWL_CFG_RF_TYPE_JF2, IWL_CFG_RF_ID_JF, + IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, + iwlax210_2ax_cfg_so_jf_b0, iwl9560_name), + +/* SoF with JF */ + _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, + IWL_CFG_MAC_TYPE_SOF, IWL_CFG_ANY, + IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1, + IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, + iwlax210_2ax_cfg_so_jf_b0, iwl9461_160_name), + _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, + IWL_CFG_MAC_TYPE_SOF, IWL_CFG_ANY, + IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1_DIV, + IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, + iwlax210_2ax_cfg_so_jf_b0, iwl9462_160_name), + _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, + IWL_CFG_MAC_TYPE_SOF, IWL_CFG_ANY, + IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1, + IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, + iwlax210_2ax_cfg_so_jf_b0, iwl9461_name), + _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, + IWL_CFG_MAC_TYPE_SOF, IWL_CFG_ANY, + IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1_DIV, + IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, + iwlax210_2ax_cfg_so_jf_b0, iwl9462_name), + /* So with GF */ _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, IWL_CFG_MAC_TYPE_SO, IWL_CFG_ANY, IWL_CFG_RF_TYPE_GF, IWL_CFG_ANY, IWL_CFG_160, IWL_CFG_ANY, IWL_CFG_NO_CDB, - iwlax211_2ax_cfg_so_gf_a0, iwl_ax211_name) + iwlax211_2ax_cfg_so_gf_a0, iwl_ax211_name), + +/* So with JF2 */ + _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, + IWL_CFG_MAC_TYPE_SO, IWL_CFG_ANY, + IWL_CFG_RF_TYPE_JF2, IWL_CFG_RF_ID_JF, + IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, + iwlax210_2ax_cfg_so_jf_b0, iwl9560_160_name), + _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, + IWL_CFG_MAC_TYPE_SO, IWL_CFG_ANY, + IWL_CFG_RF_TYPE_JF2, IWL_CFG_RF_ID_JF, + IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, + iwlax210_2ax_cfg_so_jf_b0, iwl9560_name), + +/* So with JF */ + _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, + IWL_CFG_MAC_TYPE_SO, IWL_CFG_ANY, + IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1, + IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, + iwlax210_2ax_cfg_so_jf_b0, iwl9461_160_name), + _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, + IWL_CFG_MAC_TYPE_SO, IWL_CFG_ANY, + IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1_DIV, + IWL_CFG_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, + iwlax210_2ax_cfg_so_jf_b0, iwl9462_160_name), + _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, + IWL_CFG_MAC_TYPE_SO, IWL_CFG_ANY, + IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1, + IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, + iwlax210_2ax_cfg_so_jf_b0, iwl9461_name), + _IWL_DEV_INFO(IWL_CFG_ANY, IWL_CFG_ANY, + IWL_CFG_MAC_TYPE_SO, IWL_CFG_ANY, + IWL_CFG_RF_TYPE_JF1, IWL_CFG_RF_ID_JF1_DIV, + IWL_CFG_NO_160, IWL_CFG_CORES_BT, IWL_CFG_NO_CDB, + iwlax210_2ax_cfg_so_jf_b0, iwl9462_name) #endif /* CONFIG_IWLMVM */ }; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index 863aa18b3024..43960770a9af 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -111,7 +111,7 @@ mt7915_mcu_get_cipher(int cipher) case WLAN_CIPHER_SUITE_SMS4: return MCU_CIPHER_WAPI; default: - return MT_CIPHER_NONE; + return MCU_CIPHER_NONE; } } diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h index edd3ba3a0c2d..e68a562cc5b4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h @@ -1073,7 +1073,8 @@ enum { }; enum mcu_cipher_type { - MCU_CIPHER_WEP40 = 1, + MCU_CIPHER_NONE = 0, + MCU_CIPHER_WEP40, MCU_CIPHER_WEP104, MCU_CIPHER_WEP128, MCU_CIPHER_TKIP, diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c index cd690c64f65b..9fbaacc67cfa 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c @@ -111,7 +111,7 @@ mt7921_mcu_get_cipher(int cipher) case WLAN_CIPHER_SUITE_SMS4: return MCU_CIPHER_WAPI; default: - return MT_CIPHER_NONE; + return MCU_CIPHER_NONE; } } diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.h index d76cf8f8dfdf..de3c091f6736 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.h @@ -199,7 +199,8 @@ struct sta_rec_sec { } __packed; enum mcu_cipher_type { - MCU_CIPHER_WEP40 = 1, + MCU_CIPHER_NONE = 0, + MCU_CIPHER_WEP40, MCU_CIPHER_WEP104, MCU_CIPHER_WEP128, MCU_CIPHER_TKIP, diff --git a/drivers/net/wwan/iosm/iosm_ipc_chnl_cfg.c b/drivers/net/wwan/iosm/iosm_ipc_chnl_cfg.c index 804e6c4f2c78..519361ec40df 100644 --- a/drivers/net/wwan/iosm/iosm_ipc_chnl_cfg.c +++ b/drivers/net/wwan/iosm/iosm_ipc_chnl_cfg.c @@ -64,10 +64,9 @@ static struct ipc_chnl_cfg modem_cfg[] = { int ipc_chnl_cfg_get(struct ipc_chnl_cfg *chnl_cfg, int index) { - int array_size = ARRAY_SIZE(modem_cfg); - - if (index >= array_size) { - pr_err("index: %d and array_size %d", index, array_size); + if (index >= ARRAY_SIZE(modem_cfg)) { + pr_err("index: %d and array size %zu", index, + ARRAY_SIZE(modem_cfg)); return -ECHRNG; } diff --git a/drivers/net/wwan/mhi_wwan_ctrl.c b/drivers/net/wwan/mhi_wwan_ctrl.c index d0a98f34c54d..e4d0f696687f 100644 --- a/drivers/net/wwan/mhi_wwan_ctrl.c +++ b/drivers/net/wwan/mhi_wwan_ctrl.c @@ -110,7 +110,7 @@ static int mhi_wwan_ctrl_start(struct wwan_port *port) int ret; /* Start mhi device's channel(s) */ - ret = mhi_prepare_for_transfer(mhiwwan->mhi_dev, 0); + ret = mhi_prepare_for_transfer(mhiwwan->mhi_dev); if (ret) return ret; diff --git a/drivers/opp/core.c b/drivers/opp/core.c index b335c077f215..04b4691a8aac 100644 --- a/drivers/opp/core.c +++ b/drivers/opp/core.c @@ -893,6 +893,10 @@ static int _set_required_opps(struct device *dev, if (!required_opp_tables) return 0; + /* required-opps not fully initialized yet */ + if (lazy_linking_pending(opp_table)) + return -EBUSY; + /* * We only support genpd's OPPs in the "required-opps" for now, as we * don't know much about other use cases. Error out if the required OPP @@ -903,10 +907,6 @@ static int _set_required_opps(struct device *dev, return -ENOENT; } - /* required-opps not fully initialized yet */ - if (lazy_linking_pending(opp_table)) - return -EBUSY; - /* Single genpd case */ if (!genpd_virt_devs) return _set_required_opp(dev, dev, opp, 0); @@ -1856,9 +1856,6 @@ void dev_pm_opp_put_supported_hw(struct opp_table *opp_table) if (unlikely(!opp_table)) return; - /* Make sure there are no concurrent readers while updating opp_table */ - WARN_ON(!list_empty(&opp_table->opp_list)); - kfree(opp_table->supported_hw); opp_table->supported_hw = NULL; opp_table->supported_hw_count = 0; @@ -1944,9 +1941,6 @@ void dev_pm_opp_put_prop_name(struct opp_table *opp_table) if (unlikely(!opp_table)) return; - /* Make sure there are no concurrent readers while updating opp_table */ - WARN_ON(!list_empty(&opp_table->opp_list)); - kfree(opp_table->prop_name); opp_table->prop_name = NULL; @@ -2056,9 +2050,6 @@ void dev_pm_opp_put_regulators(struct opp_table *opp_table) if (!opp_table->regulators) goto put_opp_table; - /* Make sure there are no concurrent readers while updating opp_table */ - WARN_ON(!list_empty(&opp_table->opp_list)); - if (opp_table->enabled) { for (i = opp_table->regulator_count - 1; i >= 0; i--) regulator_disable(opp_table->regulators[i]); @@ -2178,9 +2169,6 @@ void dev_pm_opp_put_clkname(struct opp_table *opp_table) if (unlikely(!opp_table)) return; - /* Make sure there are no concurrent readers while updating opp_table */ - WARN_ON(!list_empty(&opp_table->opp_list)); - clk_put(opp_table->clk); opp_table->clk = ERR_PTR(-EINVAL); @@ -2279,9 +2267,6 @@ void dev_pm_opp_unregister_set_opp_helper(struct opp_table *opp_table) if (unlikely(!opp_table)) return; - /* Make sure there are no concurrent readers while updating opp_table */ - WARN_ON(!list_empty(&opp_table->opp_list)); - opp_table->set_opp = NULL; mutex_lock(&opp_table->lock); diff --git a/drivers/opp/of.c b/drivers/opp/of.c index d298e38aaf7e..67f2e0710e79 100644 --- a/drivers/opp/of.c +++ b/drivers/opp/of.c @@ -964,8 +964,9 @@ static int _of_add_opp_table_v2(struct device *dev, struct opp_table *opp_table) } } - /* There should be one of more OPP defined */ - if (WARN_ON(!count)) { + /* There should be one or more OPPs defined */ + if (!count) { + dev_err(dev, "%s: no supported OPPs", __func__); ret = -ENOENT; goto remove_static_opp; } diff --git a/drivers/pci/controller/pci-ixp4xx.c b/drivers/pci/controller/pci-ixp4xx.c index 896a45b24236..654ac4a82beb 100644 --- a/drivers/pci/controller/pci-ixp4xx.c +++ b/drivers/pci/controller/pci-ixp4xx.c @@ -145,7 +145,7 @@ static int ixp4xx_pci_check_master_abort(struct ixp4xx_pci *p) return 0; } -static int ixp4xx_pci_read(struct ixp4xx_pci *p, u32 addr, u32 cmd, u32 *data) +static int ixp4xx_pci_read_indirect(struct ixp4xx_pci *p, u32 addr, u32 cmd, u32 *data) { ixp4xx_writel(p, IXP4XX_PCI_NP_AD, addr); @@ -170,7 +170,7 @@ static int ixp4xx_pci_read(struct ixp4xx_pci *p, u32 addr, u32 cmd, u32 *data) return ixp4xx_pci_check_master_abort(p); } -static int ixp4xx_pci_write(struct ixp4xx_pci *p, u32 addr, u32 cmd, u32 data) +static int ixp4xx_pci_write_indirect(struct ixp4xx_pci *p, u32 addr, u32 cmd, u32 data) { ixp4xx_writel(p, IXP4XX_PCI_NP_AD, addr); @@ -308,7 +308,7 @@ static int ixp4xx_pci_read_config(struct pci_bus *bus, unsigned int devfn, dev_dbg(p->dev, "read_config from %d size %d dev %d:%d:%d address: %08x cmd: %08x\n", where, size, bus_num, PCI_SLOT(devfn), PCI_FUNC(devfn), addr, cmd); - ret = ixp4xx_pci_read(p, addr, cmd, &val); + ret = ixp4xx_pci_read_indirect(p, addr, cmd, &val); if (ret) return PCIBIOS_DEVICE_NOT_FOUND; @@ -356,7 +356,7 @@ static int ixp4xx_pci_write_config(struct pci_bus *bus, unsigned int devfn, dev_dbg(p->dev, "write_config_byte %#x to %d size %d dev %d:%d:%d addr: %08x cmd %08x\n", value, where, size, bus_num, PCI_SLOT(devfn), PCI_FUNC(devfn), addr, cmd); - ret = ixp4xx_pci_write(p, addr, cmd, val); + ret = ixp4xx_pci_write_indirect(p, addr, cmd, val); if (ret) return PCIBIOS_DEVICE_NOT_FOUND; diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index e5e75331b415..3a9f4f8ad8f9 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -776,6 +776,9 @@ static void msix_mask_all(void __iomem *base, int tsize) u32 ctrl = PCI_MSIX_ENTRY_CTRL_MASKBIT; int i; + if (pci_msi_ignore_mask) + return; + for (i = 0; i < tsize; i++, base += PCI_MSIX_ENTRY_SIZE) writel(ctrl, base + PCI_MSIX_ENTRY_VECTOR_CTRL); } diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 5d63df7c1820..7bbf2673c7f2 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -978,7 +978,7 @@ void pci_create_legacy_files(struct pci_bus *b) b->legacy_mem->size = 1024*1024; b->legacy_mem->attr.mode = 0600; b->legacy_mem->mmap = pci_mmap_legacy_mem; - b->legacy_io->mapping = iomem_get_mapping(); + b->legacy_mem->mapping = iomem_get_mapping(); pci_adjust_legacy_attr(b, pci_mmap_mem); error = device_create_bin_file(&b->dev, b->legacy_mem); if (error) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 6d74386eadc2..ab3de1551b50 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -1900,6 +1900,7 @@ static void quirk_ryzen_xhci_d3hot(struct pci_dev *dev) } DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, 0x15e0, quirk_ryzen_xhci_d3hot); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, 0x15e1, quirk_ryzen_xhci_d3hot); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, 0x1639, quirk_ryzen_xhci_d3hot); #ifdef CONFIG_X86_IO_APIC static int dmi_disable_ioapicreroute(const struct dmi_system_id *d) diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c index 0cb927f0f301..a81dc4b191b7 100644 --- a/drivers/platform/x86/asus-nb-wmi.c +++ b/drivers/platform/x86/asus-nb-wmi.c @@ -41,6 +41,10 @@ static int wapf = -1; module_param(wapf, uint, 0444); MODULE_PARM_DESC(wapf, "WAPF value"); +static int tablet_mode_sw = -1; +module_param(tablet_mode_sw, uint, 0444); +MODULE_PARM_DESC(tablet_mode_sw, "Tablet mode detect: -1:auto 0:disable 1:kbd-dock 2:lid-flip"); + static struct quirk_entry *quirks; static bool asus_q500a_i8042_filter(unsigned char data, unsigned char str, @@ -458,6 +462,15 @@ static const struct dmi_system_id asus_quirks[] = { }, .driver_data = &quirk_asus_use_lid_flip_devid, }, + { + .callback = dmi_matched, + .ident = "ASUS TP200s / E205SA", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "E205SA"), + }, + .driver_data = &quirk_asus_use_lid_flip_devid, + }, {}, }; @@ -477,6 +490,21 @@ static void asus_nb_wmi_quirks(struct asus_wmi_driver *driver) else wapf = quirks->wapf; + switch (tablet_mode_sw) { + case 0: + quirks->use_kbd_dock_devid = false; + quirks->use_lid_flip_devid = false; + break; + case 1: + quirks->use_kbd_dock_devid = true; + quirks->use_lid_flip_devid = false; + break; + case 2: + quirks->use_kbd_dock_devid = false; + quirks->use_lid_flip_devid = true; + break; + } + if (quirks->i8042_filter) { ret = i8042_install_filter(quirks->i8042_filter); if (ret) { diff --git a/drivers/platform/x86/gigabyte-wmi.c b/drivers/platform/x86/gigabyte-wmi.c index fbb224a82e34..7f3a03f937f6 100644 --- a/drivers/platform/x86/gigabyte-wmi.c +++ b/drivers/platform/x86/gigabyte-wmi.c @@ -140,6 +140,7 @@ static u8 gigabyte_wmi_detect_sensor_usability(struct wmi_device *wdev) }} static const struct dmi_system_id gigabyte_wmi_known_working_platforms[] = { + DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("B450M S2H V2"), DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("B550 AORUS ELITE"), DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("B550 AORUS ELITE V2"), DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("B550 GAMING X V2"), @@ -147,6 +148,7 @@ static const struct dmi_system_id gigabyte_wmi_known_working_platforms[] = { DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("B550M DS3H"), DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("Z390 I AORUS PRO WIFI-CF"), DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("X570 AORUS ELITE"), + DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("X570 GAMING X"), DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("X570 I AORUS PRO WIFI"), DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("X570 UD"), { } diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig index 4d1192062508..4b563db3ab3e 100644 --- a/drivers/power/reset/Kconfig +++ b/drivers/power/reset/Kconfig @@ -204,6 +204,12 @@ config POWER_RESET_ST help Reset support for STMicroelectronics boards. +config POWER_RESET_TPS65086 + bool "TPS65086 restart driver" + depends on MFD_TPS65086 + help + This driver adds support for resetting the TPS65086 PMIC on restart. + config POWER_RESET_VERSATILE bool "ARM Versatile family reboot driver" depends on ARM diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile index cf3f4d02d8a5..f606a2f60539 100644 --- a/drivers/power/reset/Makefile +++ b/drivers/power/reset/Makefile @@ -23,6 +23,7 @@ obj-$(CONFIG_POWER_RESET_QNAP) += qnap-poweroff.o obj-$(CONFIG_POWER_RESET_REGULATOR) += regulator-poweroff.o obj-$(CONFIG_POWER_RESET_RESTART) += restart-poweroff.o obj-$(CONFIG_POWER_RESET_ST) += st-poweroff.o +obj-$(CONFIG_POWER_RESET_TPS65086) += tps65086-restart.o obj-$(CONFIG_POWER_RESET_VERSATILE) += arm-versatile-reboot.o obj-$(CONFIG_POWER_RESET_VEXPRESS) += vexpress-poweroff.o obj-$(CONFIG_POWER_RESET_XGENE) += xgene-reboot.o diff --git a/drivers/power/reset/linkstation-poweroff.c b/drivers/power/reset/linkstation-poweroff.c index f1e843df0e16..02f5fdb8ffc4 100644 --- a/drivers/power/reset/linkstation-poweroff.c +++ b/drivers/power/reset/linkstation-poweroff.c @@ -19,6 +19,7 @@ #define MII_MARVELL_PHY_PAGE 22 #define MII_PHY_LED_CTRL 16 +#define MII_PHY_LED_POL_CTRL 17 #define MII_88E1318S_PHY_LED_TCR 18 #define MII_88E1318S_PHY_WOL_CTRL 16 #define MII_M1011_IEVENT 19 @@ -29,11 +30,23 @@ #define LED2_FORCE_ON (0x8 << 8) #define LEDMASK GENMASK(11,8) +#define MII_88E1318S_PHY_LED_POL_LED2 BIT(4) + +struct power_off_cfg { + char *mdio_node_name; + void (*phy_set_reg)(bool restart); +}; + static struct phy_device *phydev; +static const struct power_off_cfg *cfg; -static void mvphy_reg_intn(u16 data) +static void linkstation_mvphy_reg_intn(bool restart) { int rc = 0, saved_page; + u16 data = 0; + + if (restart) + data = MII_88E1318S_PHY_LED_TCR_FORCE_INT; saved_page = phy_select_page(phydev, MII_MARVELL_LED_PAGE); if (saved_page < 0) @@ -66,11 +79,52 @@ err: dev_err(&phydev->mdio.dev, "Write register failed, %d\n", rc); } +static void readynas_mvphy_set_reg(bool restart) +{ + int rc = 0, saved_page; + u16 data = 0; + + if (restart) + data = MII_88E1318S_PHY_LED_POL_LED2; + + saved_page = phy_select_page(phydev, MII_MARVELL_LED_PAGE); + if (saved_page < 0) + goto err; + + /* Set the LED[2].0 Polarity bit to the required state */ + __phy_modify(phydev, MII_PHY_LED_POL_CTRL, + MII_88E1318S_PHY_LED_POL_LED2, data); + + if (!data) { + /* If WOL was enabled and a magic packet was received before powering + * off, we won't be able to wake up by sending another magic packet. + * Clear WOL status. + */ + __phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_MARVELL_WOL_PAGE); + __phy_set_bits(phydev, MII_88E1318S_PHY_WOL_CTRL, + MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS); + } +err: + rc = phy_restore_page(phydev, saved_page, rc); + if (rc < 0) + dev_err(&phydev->mdio.dev, "Write register failed, %d\n", rc); +} + +static const struct power_off_cfg linkstation_power_off_cfg = { + .mdio_node_name = "mdio", + .phy_set_reg = linkstation_mvphy_reg_intn, +}; + +static const struct power_off_cfg readynas_power_off_cfg = { + .mdio_node_name = "mdio-bus", + .phy_set_reg = readynas_mvphy_set_reg, +}; + static int linkstation_reboot_notifier(struct notifier_block *nb, unsigned long action, void *unused) { if (action == SYS_RESTART) - mvphy_reg_intn(MII_88E1318S_PHY_LED_TCR_FORCE_INT); + cfg->phy_set_reg(true); return NOTIFY_DONE; } @@ -82,14 +136,21 @@ static struct notifier_block linkstation_reboot_nb = { static void linkstation_poweroff(void) { unregister_reboot_notifier(&linkstation_reboot_nb); - mvphy_reg_intn(0); + cfg->phy_set_reg(false); kernel_restart("Power off"); } static const struct of_device_id ls_poweroff_of_match[] = { - { .compatible = "buffalo,ls421d" }, - { .compatible = "buffalo,ls421de" }, + { .compatible = "buffalo,ls421d", + .data = &linkstation_power_off_cfg, + }, + { .compatible = "buffalo,ls421de", + .data = &linkstation_power_off_cfg, + }, + { .compatible = "netgear,readynas-duo-v2", + .data = &readynas_power_off_cfg, + }, { }, }; @@ -97,13 +158,17 @@ static int __init linkstation_poweroff_init(void) { struct mii_bus *bus; struct device_node *dn; + const struct of_device_id *match; dn = of_find_matching_node(NULL, ls_poweroff_of_match); if (!dn) return -ENODEV; of_node_put(dn); - dn = of_find_node_by_name(NULL, "mdio"); + match = of_match_node(ls_poweroff_of_match, dn); + cfg = match->data; + + dn = of_find_node_by_name(NULL, cfg->mdio_node_name); if (!dn) return -ENODEV; diff --git a/drivers/power/reset/tps65086-restart.c b/drivers/power/reset/tps65086-restart.c new file mode 100644 index 000000000000..78b89f745a3d --- /dev/null +++ b/drivers/power/reset/tps65086-restart.c @@ -0,0 +1,98 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2021 Emil Renner Berthing + */ + +#include <linux/mfd/tps65086.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/reboot.h> + +struct tps65086_restart { + struct notifier_block handler; + struct device *dev; +}; + +static int tps65086_restart_notify(struct notifier_block *this, + unsigned long mode, void *cmd) +{ + struct tps65086_restart *tps65086_restart = + container_of(this, struct tps65086_restart, handler); + struct tps65086 *tps65086 = dev_get_drvdata(tps65086_restart->dev->parent); + int ret; + + ret = regmap_write(tps65086->regmap, TPS65086_FORCESHUTDN, 1); + if (ret) { + dev_err(tps65086_restart->dev, "%s: error writing to tps65086 pmic: %d\n", + __func__, ret); + return NOTIFY_DONE; + } + + /* give it a little time */ + mdelay(200); + + WARN_ON(1); + + return NOTIFY_DONE; +} + +static int tps65086_restart_probe(struct platform_device *pdev) +{ + struct tps65086_restart *tps65086_restart; + int ret; + + tps65086_restart = devm_kzalloc(&pdev->dev, sizeof(*tps65086_restart), GFP_KERNEL); + if (!tps65086_restart) + return -ENOMEM; + + platform_set_drvdata(pdev, tps65086_restart); + + tps65086_restart->handler.notifier_call = tps65086_restart_notify; + tps65086_restart->handler.priority = 192; + tps65086_restart->dev = &pdev->dev; + + ret = register_restart_handler(&tps65086_restart->handler); + if (ret) { + dev_err(&pdev->dev, "%s: cannot register restart handler: %d\n", + __func__, ret); + return -ENODEV; + } + + return 0; +} + +static int tps65086_restart_remove(struct platform_device *pdev) +{ + struct tps65086_restart *tps65086_restart = platform_get_drvdata(pdev); + int ret; + + ret = unregister_restart_handler(&tps65086_restart->handler); + if (ret) { + dev_err(&pdev->dev, "%s: cannot unregister restart handler: %d\n", + __func__, ret); + return -ENODEV; + } + + return 0; +} + +static const struct platform_device_id tps65086_restart_id_table[] = { + { "tps65086-reset", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(platform, tps65086_restart_id_table); + +static struct platform_driver tps65086_restart_driver = { + .driver = { + .name = "tps65086-restart", + }, + .probe = tps65086_restart_probe, + .remove = tps65086_restart_remove, + .id_table = tps65086_restart_id_table, +}; +module_platform_driver(tps65086_restart_driver); + +MODULE_AUTHOR("Emil Renner Berthing <kernel@esmil.dk>"); +MODULE_DESCRIPTION("TPS65086 restart driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/power/supply/Kconfig b/drivers/power/supply/Kconfig index 11f5368e810e..fcc7534edcb2 100644 --- a/drivers/power/supply/Kconfig +++ b/drivers/power/supply/Kconfig @@ -358,7 +358,7 @@ config AXP288_CHARGER config AXP288_FUEL_GAUGE tristate "X-Powers AXP288 Fuel Gauge" - depends on MFD_AXP20X && IIO + depends on MFD_AXP20X && IIO && IOSF_MBI help Say yes here to have support for X-Power power management IC (PMIC) Fuel Gauge. The device provides battery statistics and status @@ -577,6 +577,17 @@ config CHARGER_MP2629 Battery charger. This driver provides Battery charger power management functions on the systems. +config CHARGER_MT6360 + tristate "Mediatek MT6360 Charger Driver" + depends on MFD_MT6360 + depends on REGULATOR + select LINEAR_RANGES + help + Say Y here to enable MT6360 Charger Part. + The device supports High-Accuracy Voltage/Current Regulation, + Average Input Current Regulation, Battery Temperature Sensing, + Over-Temperature Protection, DPDM Detection for BC1.2. + config CHARGER_QCOM_SMBB tristate "Qualcomm Switch-Mode Battery Charger and Boost" depends on MFD_SPMI_PMIC || COMPILE_TEST @@ -669,6 +680,7 @@ config CHARGER_BQ256XX config CHARGER_SMB347 tristate "Summit Microelectronics SMB3XX Battery Charger" depends on I2C + depends on REGULATOR select REGMAP_I2C help Say Y to include support for Summit Microelectronics SMB345, @@ -736,6 +748,16 @@ config CHARGER_CROS_USBPD what is connected to USB PD ports from the EC and converts that into power_supply properties. +config CHARGER_CROS_PCHG + tristate "ChromeOS EC based peripheral charger" + depends on MFD_CROS_EC_DEV + default MFD_CROS_EC_DEV + help + Say Y here to enable ChromeOS EC based peripheral charge driver. + This driver gets various information about the devices connected to + the peripheral charge ports from the EC and converts that into + power_supply properties. + config CHARGER_SC2731 tristate "Spreadtrum SC2731 charger driver" depends on MFD_SC27XX_PMIC || COMPILE_TEST @@ -782,6 +804,8 @@ config CHARGER_WILCO config RN5T618_POWER tristate "RN5T618 charger/fuel gauge support" depends on MFD_RN5T618 + depends on RN5T618_ADC + depends on IIO help Say Y here to have support for RN5T618 PMIC family fuel gauge and charger. This driver can also be built as a module. If so, the module will be diff --git a/drivers/power/supply/Makefile b/drivers/power/supply/Makefile index 33059a91f60c..4e55a11aab79 100644 --- a/drivers/power/supply/Makefile +++ b/drivers/power/supply/Makefile @@ -60,7 +60,7 @@ obj-$(CONFIG_BATTERY_TWL4030_MADC) += twl4030_madc_battery.o obj-$(CONFIG_CHARGER_88PM860X) += 88pm860x_charger.o obj-$(CONFIG_CHARGER_PCF50633) += pcf50633-charger.o obj-$(CONFIG_BATTERY_RX51) += rx51_battery.o -obj-$(CONFIG_AB8500_BM) += ab8500_bmdata.o ab8500_charger.o ab8500_fg.o ab8500_btemp.o abx500_chargalg.o +obj-$(CONFIG_AB8500_BM) += ab8500_bmdata.o ab8500_charger.o ab8500_fg.o ab8500_btemp.o ab8500_chargalg.o obj-$(CONFIG_CHARGER_CPCAP) += cpcap-charger.o obj-$(CONFIG_CHARGER_ISP1704) += isp1704_charger.o obj-$(CONFIG_CHARGER_MAX8903) += max8903_charger.o @@ -78,6 +78,7 @@ obj-$(CONFIG_CHARGER_MAX77693) += max77693_charger.o obj-$(CONFIG_CHARGER_MAX8997) += max8997_charger.o obj-$(CONFIG_CHARGER_MAX8998) += max8998_charger.o obj-$(CONFIG_CHARGER_MP2629) += mp2629_charger.o +obj-$(CONFIG_CHARGER_MT6360) += mt6360_charger.o obj-$(CONFIG_CHARGER_QCOM_SMBB) += qcom_smbb.o obj-$(CONFIG_CHARGER_BQ2415X) += bq2415x_charger.o obj-$(CONFIG_CHARGER_BQ24190) += bq24190_charger.o @@ -93,6 +94,7 @@ obj-$(CONFIG_CHARGER_TPS65217) += tps65217_charger.o obj-$(CONFIG_AXP288_FUEL_GAUGE) += axp288_fuel_gauge.o obj-$(CONFIG_AXP288_CHARGER) += axp288_charger.o obj-$(CONFIG_CHARGER_CROS_USBPD) += cros_usbpd-charger.o +obj-$(CONFIG_CHARGER_CROS_PCHG) += cros_peripheral_charger.o obj-$(CONFIG_CHARGER_SC2731) += sc2731_charger.o obj-$(CONFIG_FUEL_GAUGE_SC27XX) += sc27xx_fuel_gauge.o obj-$(CONFIG_CHARGER_UCS1002) += ucs1002_power.o diff --git a/drivers/power/supply/ab8500-bm.h b/drivers/power/supply/ab8500-bm.h index 0c940571e5b0..d11405b7ee1a 100644 --- a/drivers/power/supply/ab8500-bm.h +++ b/drivers/power/supply/ab8500-bm.h @@ -269,43 +269,43 @@ enum bup_vch_sel { /* * ADC for the battery thermistor. - * When using the ABx500_ADC_THERM_BATCTRL the battery ID resistor is combined + * When using the AB8500_ADC_THERM_BATCTRL the battery ID resistor is combined * with a NTC resistor to both identify the battery and to measure its * temperature. Different phone manufactures uses different techniques to both * identify the battery and to read its temperature. */ -enum abx500_adc_therm { - ABx500_ADC_THERM_BATCTRL, - ABx500_ADC_THERM_BATTEMP, +enum ab8500_adc_therm { + AB8500_ADC_THERM_BATCTRL, + AB8500_ADC_THERM_BATTEMP, }; /** - * struct abx500_res_to_temp - defines one point in a temp to res curve. To + * struct ab8500_res_to_temp - defines one point in a temp to res curve. To * be used in battery packs that combines the identification resistor with a * NTC resistor. * @temp: battery pack temperature in Celsius * @resist: NTC resistor net total resistance */ -struct abx500_res_to_temp { +struct ab8500_res_to_temp { int temp; int resist; }; /** - * struct abx500_v_to_cap - Table for translating voltage to capacity + * struct ab8500_v_to_cap - Table for translating voltage to capacity * @voltage: Voltage in mV * @capacity: Capacity in percent */ -struct abx500_v_to_cap { +struct ab8500_v_to_cap { int voltage; int capacity; }; /* Forward declaration */ -struct abx500_fg; +struct ab8500_fg; /** - * struct abx500_fg_parameters - Fuel gauge algorithm parameters, in seconds + * struct ab8500_fg_parameters - Fuel gauge algorithm parameters, in seconds * if not specified * @recovery_sleep_timer: Time between measurements while recovering * @recovery_total_time: Total recovery time @@ -333,7 +333,7 @@ struct abx500_fg; * @pcut_max_restart: Max number of restarts * @pcut_debounce_time: Sets battery debounce time */ -struct abx500_fg_parameters { +struct ab8500_fg_parameters { int recovery_sleep_timer; int recovery_total_time; int init_timer; @@ -357,13 +357,13 @@ struct abx500_fg_parameters { }; /** - * struct abx500_charger_maximization - struct used by the board config. + * struct ab8500_charger_maximization - struct used by the board config. * @use_maxi: Enable maximization for this battery type * @maxi_chg_curr: Maximum charger current allowed * @maxi_wait_cycles: cycles to wait before setting charger current * @charger_curr_step delta between two charger current settings (mA) */ -struct abx500_maxim_parameters { +struct ab8500_maxim_parameters { bool ena_maxi; int chg_curr; int wait_cycles; @@ -371,7 +371,7 @@ struct abx500_maxim_parameters { }; /** - * struct abx500_battery_type - different batteries supported + * struct ab8500_battery_type - different batteries supported * @name: battery technology * @resis_high: battery upper resistance limit * @resis_low: battery lower resistance limit @@ -400,7 +400,7 @@ struct abx500_maxim_parameters { * @n_batres_tbl_elements number of elements in the batres_tbl * @batres_tbl battery internal resistance vs temperature table */ -struct abx500_battery_type { +struct ab8500_battery_type { int name; int resis_high; int resis_low; @@ -421,22 +421,22 @@ struct abx500_battery_type { int low_high_vol_lvl; int battery_resistance; int n_temp_tbl_elements; - const struct abx500_res_to_temp *r_to_t_tbl; + const struct ab8500_res_to_temp *r_to_t_tbl; int n_v_cap_tbl_elements; - const struct abx500_v_to_cap *v_to_cap_tbl; + const struct ab8500_v_to_cap *v_to_cap_tbl; int n_batres_tbl_elements; const struct batres_vs_temp *batres_tbl; }; /** - * struct abx500_bm_capacity_levels - abx500 capacity level data + * struct ab8500_bm_capacity_levels - ab8500 capacity level data * @critical: critical capacity level in percent * @low: low capacity level in percent * @normal: normal capacity level in percent * @high: high capacity level in percent * @full: full capacity level in percent */ -struct abx500_bm_capacity_levels { +struct ab8500_bm_capacity_levels { int critical; int low; int normal; @@ -445,13 +445,13 @@ struct abx500_bm_capacity_levels { }; /** - * struct abx500_bm_charger_parameters - Charger specific parameters + * struct ab8500_bm_charger_parameters - Charger specific parameters * @usb_volt_max: maximum allowed USB charger voltage in mV * @usb_curr_max: maximum allowed USB charger current in mA * @ac_volt_max: maximum allowed AC charger voltage in mV * @ac_curr_max: maximum allowed AC charger current in mA */ -struct abx500_bm_charger_parameters { +struct ab8500_bm_charger_parameters { int usb_volt_max; int usb_curr_max; int ac_volt_max; @@ -459,7 +459,7 @@ struct abx500_bm_charger_parameters { }; /** - * struct abx500_bm_data - abx500 battery management data + * struct ab8500_bm_data - ab8500 battery management data * @temp_under under this temp, charging is stopped * @temp_low between this temp and temp_under charging is reduced * @temp_high between this temp and temp_over charging is reduced @@ -473,7 +473,7 @@ struct abx500_bm_charger_parameters { * @bkup_bat_i current which we charge the backup battery with * @no_maintenance indicates that maintenance charging is disabled * @capacity_scaling indicates whether capacity scaling is to be used - * @abx500_adc_therm placement of thermistor, batctrl or battemp adc + * @ab8500_adc_therm placement of thermistor, batctrl or battemp adc * @chg_unknown_bat flag to enable charging of unknown batteries * @enable_overshoot flag to enable VBAT overshoot control * @auto_trig flag to enable auto adc trigger @@ -494,7 +494,7 @@ struct abx500_bm_charger_parameters { * @chg_params charger parameters * @fg_params fuel gauge parameters */ -struct abx500_bm_data { +struct ab8500_bm_data { int temp_under; int temp_low; int temp_high; @@ -511,7 +511,7 @@ struct abx500_bm_data { bool chg_unknown_bat; bool enable_overshoot; bool auto_trig; - enum abx500_adc_therm adc_therm; + enum ab8500_adc_therm adc_therm; int fg_res; int n_btypes; int batt_id; @@ -523,11 +523,11 @@ struct abx500_bm_data { int n_chg_in_curr; int *chg_output_curr; int *chg_input_curr; - const struct abx500_maxim_parameters *maxi; - const struct abx500_bm_capacity_levels *cap_levels; - struct abx500_battery_type *bat_type; - const struct abx500_bm_charger_parameters *chg_params; - const struct abx500_fg_parameters *fg_params; + const struct ab8500_maxim_parameters *maxi; + const struct ab8500_bm_capacity_levels *cap_levels; + struct ab8500_battery_type *bat_type; + const struct ab8500_bm_charger_parameters *chg_params; + const struct ab8500_fg_parameters *fg_params; }; enum { @@ -561,160 +561,7 @@ struct batres_vs_temp { /* Forward declaration */ struct ab8500_fg; -/** - * struct ab8500_fg_parameters - Fuel gauge algorithm parameters, in seconds - * if not specified - * @recovery_sleep_timer: Time between measurements while recovering - * @recovery_total_time: Total recovery time - * @init_timer: Measurement interval during startup - * @init_discard_time: Time we discard voltage measurement at startup - * @init_total_time: Total init time during startup - * @high_curr_time: Time current has to be high to go to recovery - * @accu_charging: FG accumulation time while charging - * @accu_high_curr: FG accumulation time in high current mode - * @high_curr_threshold: High current threshold, in mA - * @lowbat_threshold: Low battery threshold, in mV - * @battok_falling_th_sel0 Threshold in mV for battOk signal sel0 - * Resolution in 50 mV step. - * @battok_raising_th_sel1 Threshold in mV for battOk signal sel1 - * Resolution in 50 mV step. - * @user_cap_limit Capacity reported from user must be within this - * limit to be considered as sane, in percentage - * points. - * @maint_thres This is the threshold where we stop reporting - * battery full while in maintenance, in per cent - * @pcut_enable: Enable power cut feature in ab8505 - * @pcut_max_time: Max time threshold - * @pcut_flag_time: Flagtime threshold - * @pcut_max_restart: Max number of restarts - * @pcut_debunce_time: Sets battery debounce time - */ -struct ab8500_fg_parameters { - int recovery_sleep_timer; - int recovery_total_time; - int init_timer; - int init_discard_time; - int init_total_time; - int high_curr_time; - int accu_charging; - int accu_high_curr; - int high_curr_threshold; - int lowbat_threshold; - int battok_falling_th_sel0; - int battok_raising_th_sel1; - int user_cap_limit; - int maint_thres; - bool pcut_enable; - u8 pcut_max_time; - u8 pcut_flag_time; - u8 pcut_max_restart; - u8 pcut_debunce_time; -}; - -/** - * struct ab8500_charger_maximization - struct used by the board config. - * @use_maxi: Enable maximization for this battery type - * @maxi_chg_curr: Maximum charger current allowed - * @maxi_wait_cycles: cycles to wait before setting charger current - * @charger_curr_step delta between two charger current settings (mA) - */ -struct ab8500_maxim_parameters { - bool ena_maxi; - int chg_curr; - int wait_cycles; - int charger_curr_step; -}; - -/** - * struct ab8500_bm_capacity_levels - ab8500 capacity level data - * @critical: critical capacity level in percent - * @low: low capacity level in percent - * @normal: normal capacity level in percent - * @high: high capacity level in percent - * @full: full capacity level in percent - */ -struct ab8500_bm_capacity_levels { - int critical; - int low; - int normal; - int high; - int full; -}; - -/** - * struct ab8500_bm_charger_parameters - Charger specific parameters - * @usb_volt_max: maximum allowed USB charger voltage in mV - * @usb_curr_max: maximum allowed USB charger current in mA - * @ac_volt_max: maximum allowed AC charger voltage in mV - * @ac_curr_max: maximum allowed AC charger current in mA - */ -struct ab8500_bm_charger_parameters { - int usb_volt_max; - int usb_curr_max; - int ac_volt_max; - int ac_curr_max; -}; - -/** - * struct ab8500_bm_data - ab8500 battery management data - * @temp_under under this temp, charging is stopped - * @temp_low between this temp and temp_under charging is reduced - * @temp_high between this temp and temp_over charging is reduced - * @temp_over over this temp, charging is stopped - * @temp_interval_chg temperature measurement interval in s when charging - * @temp_interval_nochg temperature measurement interval in s when not charging - * @main_safety_tmr_h safety timer for main charger - * @usb_safety_tmr_h safety timer for usb charger - * @bkup_bat_v voltage which we charge the backup battery with - * @bkup_bat_i current which we charge the backup battery with - * @no_maintenance indicates that maintenance charging is disabled - * @capacity_scaling indicates whether capacity scaling is to be used - * @adc_therm placement of thermistor, batctrl or battemp adc - * @chg_unknown_bat flag to enable charging of unknown batteries - * @enable_overshoot flag to enable VBAT overshoot control - * @fg_res resistance of FG resistor in 0.1mOhm - * @n_btypes number of elements in array bat_type - * @batt_id index of the identified battery in array bat_type - * @interval_charging charge alg cycle period time when charging (sec) - * @interval_not_charging charge alg cycle period time when not charging (sec) - * @temp_hysteresis temperature hysteresis - * @gnd_lift_resistance Battery ground to phone ground resistance (mOhm) - * @maxi: maximization parameters - * @cap_levels capacity in percent for the different capacity levels - * @bat_type table of supported battery types - * @chg_params charger parameters - * @fg_params fuel gauge parameters - */ -struct ab8500_bm_data { - int temp_under; - int temp_low; - int temp_high; - int temp_over; - int temp_interval_chg; - int temp_interval_nochg; - int main_safety_tmr_h; - int usb_safety_tmr_h; - int bkup_bat_v; - int bkup_bat_i; - bool no_maintenance; - bool capacity_scaling; - bool chg_unknown_bat; - bool enable_overshoot; - enum abx500_adc_therm adc_therm; - int fg_res; - int n_btypes; - int batt_id; - int interval_charging; - int interval_not_charging; - int temp_hysteresis; - int gnd_lift_resistance; - const struct ab8500_maxim_parameters *maxi; - const struct ab8500_bm_capacity_levels *cap_levels; - const struct ab8500_bm_charger_parameters *chg_params; - const struct ab8500_fg_parameters *fg_params; -}; - -extern struct abx500_bm_data ab8500_bm_data; +extern struct ab8500_bm_data ab8500_bm_data; void ab8500_charger_usb_state_changed(u8 bm_usb_state, u16 mA); struct ab8500_fg *ab8500_fg_get(void); @@ -725,10 +572,10 @@ int ab8500_fg_inst_curr_started(struct ab8500_fg *di); int ab8500_fg_inst_curr_done(struct ab8500_fg *di); int ab8500_bm_of_probe(struct device *dev, struct device_node *np, - struct abx500_bm_data *bm); + struct ab8500_bm_data *bm); extern struct platform_driver ab8500_fg_driver; extern struct platform_driver ab8500_btemp_driver; -extern struct platform_driver abx500_chargalg_driver; +extern struct platform_driver ab8500_chargalg_driver; #endif /* _AB8500_CHARGER_H_ */ diff --git a/drivers/power/supply/ab8500_bmdata.c b/drivers/power/supply/ab8500_bmdata.c index c2b8c0bb77e2..6f5fb794042c 100644 --- a/drivers/power/supply/ab8500_bmdata.c +++ b/drivers/power/supply/ab8500_bmdata.c @@ -2,8 +2,6 @@ #include <linux/export.h> #include <linux/power_supply.h> #include <linux/of.h> -#include <linux/mfd/abx500.h> -#include <linux/mfd/abx500/ab8500.h> #include "ab8500-bm.h" @@ -13,7 +11,7 @@ * Note that the res_to_temp table must be strictly sorted by falling resistance * values to work. */ -const struct abx500_res_to_temp ab8500_temp_tbl_a_thermistor[] = { +const struct ab8500_res_to_temp ab8500_temp_tbl_a_thermistor[] = { {-5, 53407}, { 0, 48594}, { 5, 43804}, @@ -35,7 +33,7 @@ EXPORT_SYMBOL(ab8500_temp_tbl_a_thermistor); const int ab8500_temp_tbl_a_size = ARRAY_SIZE(ab8500_temp_tbl_a_thermistor); EXPORT_SYMBOL(ab8500_temp_tbl_a_size); -const struct abx500_res_to_temp ab8500_temp_tbl_b_thermistor[] = { +const struct ab8500_res_to_temp ab8500_temp_tbl_b_thermistor[] = { {-5, 200000}, { 0, 159024}, { 5, 151921}, @@ -57,7 +55,7 @@ EXPORT_SYMBOL(ab8500_temp_tbl_b_thermistor); const int ab8500_temp_tbl_b_size = ARRAY_SIZE(ab8500_temp_tbl_b_thermistor); EXPORT_SYMBOL(ab8500_temp_tbl_b_size); -static const struct abx500_v_to_cap cap_tbl_a_thermistor[] = { +static const struct ab8500_v_to_cap cap_tbl_a_thermistor[] = { {4171, 100}, {4114, 95}, {4009, 83}, @@ -80,7 +78,7 @@ static const struct abx500_v_to_cap cap_tbl_a_thermistor[] = { {3247, 0}, }; -static const struct abx500_v_to_cap cap_tbl_b_thermistor[] = { +static const struct ab8500_v_to_cap cap_tbl_b_thermistor[] = { {4161, 100}, {4124, 98}, {4044, 90}, @@ -103,7 +101,7 @@ static const struct abx500_v_to_cap cap_tbl_b_thermistor[] = { {3250, 0}, }; -static const struct abx500_v_to_cap cap_tbl[] = { +static const struct ab8500_v_to_cap cap_tbl[] = { {4186, 100}, {4163, 99}, {4114, 95}, @@ -134,7 +132,7 @@ static const struct abx500_v_to_cap cap_tbl[] = { * Note that the res_to_temp table must be strictly sorted by falling * resistance values to work. */ -static const struct abx500_res_to_temp temp_tbl[] = { +static const struct ab8500_res_to_temp temp_tbl[] = { {-5, 214834}, { 0, 162943}, { 5, 124820}, @@ -191,7 +189,7 @@ static const struct batres_vs_temp temp_to_batres_tbl_9100[] = { {-20, 180}, }; -static struct abx500_battery_type bat_type_thermistor[] = { +static struct ab8500_battery_type bat_type_thermistor[] = { [BATTERY_UNKNOWN] = { /* First element always represent the UNKNOWN battery */ .name = POWER_SUPPLY_TECHNOLOGY_UNKNOWN, @@ -277,7 +275,7 @@ static struct abx500_battery_type bat_type_thermistor[] = { }, }; -static struct abx500_battery_type bat_type_ext_thermistor[] = { +static struct ab8500_battery_type bat_type_ext_thermistor[] = { [BATTERY_UNKNOWN] = { /* First element always represent the UNKNOWN battery */ .name = POWER_SUPPLY_TECHNOLOGY_UNKNOWN, @@ -394,7 +392,7 @@ static struct abx500_battery_type bat_type_ext_thermistor[] = { }, }; -static const struct abx500_bm_capacity_levels cap_levels = { +static const struct ab8500_bm_capacity_levels cap_levels = { .critical = 2, .low = 10, .normal = 70, @@ -402,7 +400,7 @@ static const struct abx500_bm_capacity_levels cap_levels = { .full = 100, }; -static const struct abx500_fg_parameters fg = { +static const struct ab8500_fg_parameters fg = { .recovery_sleep_timer = 10, .recovery_total_time = 100, .init_timer = 1, @@ -424,14 +422,14 @@ static const struct abx500_fg_parameters fg = { .pcut_debounce_time = 2, }; -static const struct abx500_maxim_parameters ab8500_maxi_params = { +static const struct ab8500_maxim_parameters ab8500_maxi_params = { .ena_maxi = true, .chg_curr = 910, .wait_cycles = 10, .charger_curr_step = 100, }; -static const struct abx500_bm_charger_parameters chg = { +static const struct ab8500_bm_charger_parameters chg = { .usb_volt_max = 5500, .usb_curr_max = 1500, .ac_volt_max = 7500, @@ -456,7 +454,7 @@ static int ab8500_charge_input_curr_map[] = { 700, 800, 900, 1000, 1100, 1300, 1400, 1500, }; -struct abx500_bm_data ab8500_bm_data = { +struct ab8500_bm_data ab8500_bm_data = { .temp_under = 3, .temp_low = 8, .temp_high = 43, @@ -469,7 +467,7 @@ struct abx500_bm_data ab8500_bm_data = { .bkup_bat_i = BUP_ICH_SEL_150UA, .no_maintenance = false, .capacity_scaling = false, - .adc_therm = ABx500_ADC_THERM_BATCTRL, + .adc_therm = AB8500_ADC_THERM_BATCTRL, .chg_unknown_bat = false, .enable_overshoot = false, .fg_res = 100, @@ -492,7 +490,7 @@ struct abx500_bm_data ab8500_bm_data = { int ab8500_bm_of_probe(struct device *dev, struct device_node *np, - struct abx500_bm_data *bm) + struct ab8500_bm_data *bm) { const struct batres_vs_temp *tmp_batres_tbl; struct device_node *battery_node; @@ -531,7 +529,7 @@ int ab8500_bm_of_probe(struct device *dev, } else { bm->n_btypes = 4; bm->bat_type = bat_type_ext_thermistor; - bm->adc_therm = ABx500_ADC_THERM_BATTEMP; + bm->adc_therm = AB8500_ADC_THERM_BATTEMP; tmp_batres_tbl = temp_to_batres_tbl_ext_thermistor; } diff --git a/drivers/power/supply/ab8500_btemp.c b/drivers/power/supply/ab8500_btemp.c index dbdcff32f353..b6c9111d77d7 100644 --- a/drivers/power/supply/ab8500_btemp.c +++ b/drivers/power/supply/ab8500_btemp.c @@ -27,6 +27,7 @@ #include <linux/mfd/abx500.h> #include <linux/mfd/abx500/ab8500.h> #include <linux/iio/consumer.h> +#include <linux/fixp-arith.h> #include "ab8500-bm.h" @@ -102,7 +103,7 @@ struct ab8500_btemp { struct iio_channel *btemp_ball; struct iio_channel *bat_ctrl; struct ab8500_fg *fg; - struct abx500_bm_data *bm; + struct ab8500_bm_data *bm; struct power_supply *btemp_psy; struct ab8500_btemp_events events; struct ab8500_btemp_ranges btemp_ranges; @@ -144,7 +145,7 @@ static int ab8500_btemp_batctrl_volt_to_res(struct ab8500_btemp *di, return (450000 * (v_batctrl)) / (1800 - v_batctrl); } - if (di->bm->adc_therm == ABx500_ADC_THERM_BATCTRL) { + if (di->bm->adc_therm == AB8500_ADC_THERM_BATCTRL) { /* * If the battery has internal NTC, we use the current * source to calculate the resistance. @@ -206,7 +207,7 @@ static int ab8500_btemp_curr_source_enable(struct ab8500_btemp *di, return 0; /* Only do this for batteries with internal NTC */ - if (di->bm->adc_therm == ABx500_ADC_THERM_BATCTRL && enable) { + if (di->bm->adc_therm == AB8500_ADC_THERM_BATCTRL && enable) { if (di->curr_source == BTEMP_BATCTRL_CURR_SRC_7UA) curr = BAT_CTRL_7U_ENA; @@ -239,7 +240,7 @@ static int ab8500_btemp_curr_source_enable(struct ab8500_btemp *di, __func__); goto disable_curr_source; } - } else if (di->bm->adc_therm == ABx500_ADC_THERM_BATCTRL && !enable) { + } else if (di->bm->adc_therm == AB8500_ADC_THERM_BATCTRL && !enable) { dev_dbg(di->dev, "Disable BATCTRL curr source\n"); /* Write 0 to the curr bits */ @@ -417,7 +418,7 @@ static int ab8500_btemp_get_batctrl_res(struct ab8500_btemp *di) * based on the NTC resistance. */ static int ab8500_btemp_res_to_temp(struct ab8500_btemp *di, - const struct abx500_res_to_temp *tbl, int tbl_size, int res) + const struct ab8500_res_to_temp *tbl, int tbl_size, int res) { int i; /* @@ -437,8 +438,9 @@ static int ab8500_btemp_res_to_temp(struct ab8500_btemp *di, i++; } - return tbl[i].temp + ((tbl[i + 1].temp - tbl[i].temp) * - (res - tbl[i].resist)) / (tbl[i + 1].resist - tbl[i].resist); + return fixp_linear_interpolate(tbl[i].resist, tbl[i].temp, + tbl[i + 1].resist, tbl[i + 1].temp, + res); } /** @@ -456,7 +458,7 @@ static int ab8500_btemp_measure_temp(struct ab8500_btemp *di) id = di->bm->batt_id; - if (di->bm->adc_therm == ABx500_ADC_THERM_BATCTRL && + if (di->bm->adc_therm == AB8500_ADC_THERM_BATCTRL && id != BATTERY_UNKNOWN) { rbat = ab8500_btemp_get_batctrl_res(di); @@ -525,7 +527,7 @@ static int ab8500_btemp_id(struct ab8500_btemp *di) dev_dbg(di->dev, "Battery detected on %s" " low %d < res %d < high: %d" " index: %d\n", - di->bm->adc_therm == ABx500_ADC_THERM_BATCTRL ? + di->bm->adc_therm == AB8500_ADC_THERM_BATCTRL ? "BATCTRL" : "BATTEMP", di->bm->bat_type[i].resis_low, res, di->bm->bat_type[i].resis_high, i); @@ -545,7 +547,7 @@ static int ab8500_btemp_id(struct ab8500_btemp *di) * We only have to change current source if the * detected type is Type 1. */ - if (di->bm->adc_therm == ABx500_ADC_THERM_BATCTRL && + if (di->bm->adc_therm == AB8500_ADC_THERM_BATCTRL && di->bm->batt_id == 1) { dev_dbg(di->dev, "Set BATCTRL current source to 20uA\n"); di->curr_source = BTEMP_BATCTRL_CURR_SRC_20UA; diff --git a/drivers/power/supply/abx500_chargalg.c b/drivers/power/supply/ab8500_chargalg.c index b72826cf6794..ff4b26b1ceca 100644 --- a/drivers/power/supply/abx500_chargalg.c +++ b/drivers/power/supply/ab8500_chargalg.c @@ -3,7 +3,7 @@ * Copyright (C) ST-Ericsson SA 2012 * Copyright (c) 2012 Sony Mobile Communications AB * - * Charging algorithm driver for abx500 variants + * Charging algorithm driver for AB8500 * * Authors: * Johan Palsson <johan.palsson@stericsson.com> @@ -49,18 +49,18 @@ #define CHARGALG_CURR_STEP_LOW 0 #define CHARGALG_CURR_STEP_HIGH 100 -enum abx500_chargers { +enum ab8500_chargers { NO_CHG, AC_CHG, USB_CHG, }; -struct abx500_chargalg_charger_info { - enum abx500_chargers conn_chg; - enum abx500_chargers prev_conn_chg; - enum abx500_chargers online_chg; - enum abx500_chargers prev_online_chg; - enum abx500_chargers charger_type; +struct ab8500_chargalg_charger_info { + enum ab8500_chargers conn_chg; + enum ab8500_chargers prev_conn_chg; + enum ab8500_chargers online_chg; + enum ab8500_chargers prev_online_chg; + enum ab8500_chargers charger_type; bool usb_chg_ok; bool ac_chg_ok; int usb_volt; @@ -73,18 +73,18 @@ struct abx500_chargalg_charger_info { int ac_iset; }; -struct abx500_chargalg_suspension_status { +struct ab8500_chargalg_suspension_status { bool suspended_change; bool ac_suspended; bool usb_suspended; }; -struct abx500_chargalg_current_step_status { +struct ab8500_chargalg_current_step_status { bool curr_step_change; int curr_step; }; -struct abx500_chargalg_battery_data { +struct ab8500_chargalg_battery_data { int temp; int volt; int avg_curr; @@ -92,7 +92,7 @@ struct abx500_chargalg_battery_data { int percent; }; -enum abx500_chargalg_states { +enum ab8500_chargalg_states { STATE_HANDHELD_INIT, STATE_HANDHELD, STATE_CHG_NOT_OK_INIT, @@ -123,7 +123,7 @@ enum abx500_chargalg_states { STATE_WD_EXPIRED, }; -static const char *states[] = { +static const char * const states[] = { "HANDHELD_INIT", "HANDHELD", "CHG_NOT_OK_INIT", @@ -154,7 +154,7 @@ static const char *states[] = { "WD_EXPIRED", }; -struct abx500_chargalg_events { +struct ab8500_chargalg_events { bool batt_unknown; bool mainextchnotok; bool batt_ovv; @@ -176,7 +176,7 @@ struct abx500_chargalg_events { }; /** - * struct abx500_charge_curr_maximization - Charger maximization parameters + * struct ab8500_charge_curr_maximization - Charger maximization parameters * @original_iset: the non optimized/maximised charger current * @current_iset: the charging current used at this moment * @test_delta_i: the delta between the current we want to charge and the @@ -190,7 +190,7 @@ struct abx500_chargalg_events { * @level: tells in how many steps the charging current has been increased */ -struct abx500_charge_curr_maximization { +struct ab8500_charge_curr_maximization { int original_iset; int current_iset; int test_delta_i; @@ -207,7 +207,7 @@ enum maxim_ret { }; /** - * struct abx500_chargalg - abx500 Charging algorithm device information + * struct ab8500_chargalg - ab8500 Charging algorithm device information * @dev: pointer to the structure device * @charge_status: battery operating status * @eoc_cnt: counter used to determine end-of_charge @@ -223,7 +223,7 @@ enum maxim_ret { * @susp_status: current charger suspension status * @bm: Platform specific battery management information * @curr_status: Current step status for over-current protection - * @parent: pointer to the struct abx500 + * @parent: pointer to the struct ab8500 * @chargalg_psy: structure that holds the battery properties exposed by * the charging algorithm * @events: structure for information about events triggered @@ -235,25 +235,25 @@ enum maxim_ret { * @maintenance_timer: maintenance charging timer * @chargalg_kobject: structure of type kobject */ -struct abx500_chargalg { +struct ab8500_chargalg { struct device *dev; int charge_status; int eoc_cnt; bool maintenance_chg; int t_hyst_norm; int t_hyst_lowhigh; - enum abx500_chargalg_states charge_state; - struct abx500_charge_curr_maximization ccm; - struct abx500_chargalg_charger_info chg_info; - struct abx500_chargalg_battery_data batt_data; - struct abx500_chargalg_suspension_status susp_status; + enum ab8500_chargalg_states charge_state; + struct ab8500_charge_curr_maximization ccm; + struct ab8500_chargalg_charger_info chg_info; + struct ab8500_chargalg_battery_data batt_data; + struct ab8500_chargalg_suspension_status susp_status; struct ab8500 *parent; - struct abx500_chargalg_current_step_status curr_status; - struct abx500_bm_data *bm; + struct ab8500_chargalg_current_step_status curr_status; + struct ab8500_bm_data *bm; struct power_supply *chargalg_psy; struct ux500_charger *ac_chg; struct ux500_charger *usb_chg; - struct abx500_chargalg_events events; + struct ab8500_chargalg_events events; struct workqueue_struct *chargalg_wq; struct delayed_work chargalg_periodic_work; struct delayed_work chargalg_wd_work; @@ -267,28 +267,28 @@ struct abx500_chargalg { BLOCKING_NOTIFIER_HEAD(charger_notifier_list); /* Main battery properties */ -static enum power_supply_property abx500_chargalg_props[] = { +static enum power_supply_property ab8500_chargalg_props[] = { POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_PROP_HEALTH, }; -struct abx500_chargalg_sysfs_entry { +struct ab8500_chargalg_sysfs_entry { struct attribute attr; - ssize_t (*show)(struct abx500_chargalg *, char *); - ssize_t (*store)(struct abx500_chargalg *, const char *, size_t); + ssize_t (*show)(struct ab8500_chargalg *di, char *buf); + ssize_t (*store)(struct ab8500_chargalg *di, const char *buf, size_t length); }; /** - * abx500_chargalg_safety_timer_expired() - Expiration of the safety timer + * ab8500_chargalg_safety_timer_expired() - Expiration of the safety timer * @timer: pointer to the hrtimer structure * * This function gets called when the safety timer for the charger * expires */ static enum hrtimer_restart -abx500_chargalg_safety_timer_expired(struct hrtimer *timer) +ab8500_chargalg_safety_timer_expired(struct hrtimer *timer) { - struct abx500_chargalg *di = container_of(timer, struct abx500_chargalg, + struct ab8500_chargalg *di = container_of(timer, struct ab8500_chargalg, safety_timer); dev_err(di->dev, "Safety timer expired\n"); di->events.safety_timer_expired = true; @@ -300,7 +300,7 @@ abx500_chargalg_safety_timer_expired(struct hrtimer *timer) } /** - * abx500_chargalg_maintenance_timer_expired() - Expiration of + * ab8500_chargalg_maintenance_timer_expired() - Expiration of * the maintenance timer * @timer: pointer to the timer structure * @@ -308,10 +308,10 @@ abx500_chargalg_safety_timer_expired(struct hrtimer *timer) * expires */ static enum hrtimer_restart -abx500_chargalg_maintenance_timer_expired(struct hrtimer *timer) +ab8500_chargalg_maintenance_timer_expired(struct hrtimer *timer) { - struct abx500_chargalg *di = container_of(timer, struct abx500_chargalg, + struct ab8500_chargalg *di = container_of(timer, struct ab8500_chargalg, maintenance_timer); dev_dbg(di->dev, "Maintenance timer expired\n"); @@ -324,13 +324,13 @@ abx500_chargalg_maintenance_timer_expired(struct hrtimer *timer) } /** - * abx500_chargalg_state_to() - Change charge state - * @di: pointer to the abx500_chargalg structure + * ab8500_chargalg_state_to() - Change charge state + * @di: pointer to the ab8500_chargalg structure * * This function gets called when a charge state change should occur */ -static void abx500_chargalg_state_to(struct abx500_chargalg *di, - enum abx500_chargalg_states state) +static void ab8500_chargalg_state_to(struct ab8500_chargalg *di, + enum ab8500_chargalg_states state) { dev_dbg(di->dev, "State changed: %s (From state: [%d] %s =to=> [%d] %s )\n", @@ -343,7 +343,7 @@ static void abx500_chargalg_state_to(struct abx500_chargalg *di, di->charge_state = state; } -static int abx500_chargalg_check_charger_enable(struct abx500_chargalg *di) +static int ab8500_chargalg_check_charger_enable(struct ab8500_chargalg *di) { switch (di->charge_state) { case STATE_NORMAL: @@ -368,13 +368,13 @@ static int abx500_chargalg_check_charger_enable(struct abx500_chargalg *di) } /** - * abx500_chargalg_check_charger_connection() - Check charger connection change - * @di: pointer to the abx500_chargalg structure + * ab8500_chargalg_check_charger_connection() - Check charger connection change + * @di: pointer to the ab8500_chargalg structure * * This function will check if there is a change in the charger connection * and change charge state accordingly. AC has precedence over USB. */ -static int abx500_chargalg_check_charger_connection(struct abx500_chargalg *di) +static int ab8500_chargalg_check_charger_connection(struct ab8500_chargalg *di) { if (di->chg_info.conn_chg != di->chg_info.prev_conn_chg || di->susp_status.suspended_change) { @@ -387,23 +387,23 @@ static int abx500_chargalg_check_charger_connection(struct abx500_chargalg *di) dev_dbg(di->dev, "Charging source is AC\n"); if (di->chg_info.charger_type != AC_CHG) { di->chg_info.charger_type = AC_CHG; - abx500_chargalg_state_to(di, STATE_NORMAL_INIT); + ab8500_chargalg_state_to(di, STATE_NORMAL_INIT); } } else if ((di->chg_info.conn_chg & USB_CHG) && !di->susp_status.usb_suspended) { dev_dbg(di->dev, "Charging source is USB\n"); di->chg_info.charger_type = USB_CHG; - abx500_chargalg_state_to(di, STATE_NORMAL_INIT); + ab8500_chargalg_state_to(di, STATE_NORMAL_INIT); } else if (di->chg_info.conn_chg && (di->susp_status.ac_suspended || di->susp_status.usb_suspended)) { dev_dbg(di->dev, "Charging is suspended\n"); di->chg_info.charger_type = NO_CHG; - abx500_chargalg_state_to(di, STATE_SUSPENDED_INIT); + ab8500_chargalg_state_to(di, STATE_SUSPENDED_INIT); } else { dev_dbg(di->dev, "Charging source is OFF\n"); di->chg_info.charger_type = NO_CHG; - abx500_chargalg_state_to(di, STATE_HANDHELD_INIT); + ab8500_chargalg_state_to(di, STATE_HANDHELD_INIT); } di->chg_info.prev_conn_chg = di->chg_info.conn_chg; di->susp_status.suspended_change = false; @@ -412,29 +412,29 @@ static int abx500_chargalg_check_charger_connection(struct abx500_chargalg *di) } /** - * abx500_chargalg_check_current_step_status() - Check charging current + * ab8500_chargalg_check_current_step_status() - Check charging current * step status. - * @di: pointer to the abx500_chargalg structure + * @di: pointer to the ab8500_chargalg structure * * This function will check if there is a change in the charging current step * and change charge state accordingly. */ -static void abx500_chargalg_check_current_step_status - (struct abx500_chargalg *di) +static void ab8500_chargalg_check_current_step_status + (struct ab8500_chargalg *di) { if (di->curr_status.curr_step_change) - abx500_chargalg_state_to(di, STATE_NORMAL_INIT); + ab8500_chargalg_state_to(di, STATE_NORMAL_INIT); di->curr_status.curr_step_change = false; } /** - * abx500_chargalg_start_safety_timer() - Start charging safety timer - * @di: pointer to the abx500_chargalg structure + * ab8500_chargalg_start_safety_timer() - Start charging safety timer + * @di: pointer to the ab8500_chargalg structure * * The safety timer is used to avoid overcharging of old or bad batteries. * There are different timers for AC and USB */ -static void abx500_chargalg_start_safety_timer(struct abx500_chargalg *di) +static void ab8500_chargalg_start_safety_timer(struct ab8500_chargalg *di) { /* Charger-dependent expiration time in hours*/ int timer_expiration = 0; @@ -461,27 +461,27 @@ static void abx500_chargalg_start_safety_timer(struct abx500_chargalg *di) } /** - * abx500_chargalg_stop_safety_timer() - Stop charging safety timer - * @di: pointer to the abx500_chargalg structure + * ab8500_chargalg_stop_safety_timer() - Stop charging safety timer + * @di: pointer to the ab8500_chargalg structure * * The safety timer is stopped whenever the NORMAL state is exited */ -static void abx500_chargalg_stop_safety_timer(struct abx500_chargalg *di) +static void ab8500_chargalg_stop_safety_timer(struct ab8500_chargalg *di) { if (hrtimer_try_to_cancel(&di->safety_timer) >= 0) di->events.safety_timer_expired = false; } /** - * abx500_chargalg_start_maintenance_timer() - Start charging maintenance timer - * @di: pointer to the abx500_chargalg structure + * ab8500_chargalg_start_maintenance_timer() - Start charging maintenance timer + * @di: pointer to the ab8500_chargalg structure * @duration: duration of ther maintenance timer in hours * * The maintenance timer is used to maintain the charge in the battery once * the battery is considered full. These timers are chosen to match the * discharge curve of the battery */ -static void abx500_chargalg_start_maintenance_timer(struct abx500_chargalg *di, +static void ab8500_chargalg_start_maintenance_timer(struct ab8500_chargalg *di, int duration) { hrtimer_set_expires_range(&di->maintenance_timer, @@ -492,26 +492,26 @@ static void abx500_chargalg_start_maintenance_timer(struct abx500_chargalg *di, } /** - * abx500_chargalg_stop_maintenance_timer() - Stop maintenance timer - * @di: pointer to the abx500_chargalg structure + * ab8500_chargalg_stop_maintenance_timer() - Stop maintenance timer + * @di: pointer to the ab8500_chargalg structure * * The maintenance timer is stopped whenever maintenance ends or when another * state is entered */ -static void abx500_chargalg_stop_maintenance_timer(struct abx500_chargalg *di) +static void ab8500_chargalg_stop_maintenance_timer(struct ab8500_chargalg *di) { if (hrtimer_try_to_cancel(&di->maintenance_timer) >= 0) di->events.maintenance_timer_expired = false; } /** - * abx500_chargalg_kick_watchdog() - Kick charger watchdog - * @di: pointer to the abx500_chargalg structure + * ab8500_chargalg_kick_watchdog() - Kick charger watchdog + * @di: pointer to the ab8500_chargalg structure * * The charger watchdog have to be kicked periodically whenever the charger is * on, else the ABB will reset the system */ -static int abx500_chargalg_kick_watchdog(struct abx500_chargalg *di) +static int ab8500_chargalg_kick_watchdog(struct ab8500_chargalg *di) { /* Check if charger exists and kick watchdog if charging */ if (di->ac_chg && di->ac_chg->ops.kick_wd && @@ -526,8 +526,7 @@ static int abx500_chargalg_kick_watchdog(struct abx500_chargalg *di) di->usb_chg->ops.kick_wd(di->usb_chg); return di->ac_chg->ops.kick_wd(di->ac_chg); - } - else if (di->usb_chg && di->usb_chg->ops.kick_wd && + } else if (di->usb_chg && di->usb_chg->ops.kick_wd && di->chg_info.online_chg & USB_CHG) return di->usb_chg->ops.kick_wd(di->usb_chg); @@ -535,8 +534,8 @@ static int abx500_chargalg_kick_watchdog(struct abx500_chargalg *di) } /** - * abx500_chargalg_ac_en() - Turn on/off the AC charger - * @di: pointer to the abx500_chargalg structure + * ab8500_chargalg_ac_en() - Turn on/off the AC charger + * @di: pointer to the ab8500_chargalg structure * @enable: charger on/off * @vset: requested charger output voltage * @iset: requested charger output current @@ -544,10 +543,10 @@ static int abx500_chargalg_kick_watchdog(struct abx500_chargalg *di) * The AC charger will be turned on/off with the requested charge voltage and * current */ -static int abx500_chargalg_ac_en(struct abx500_chargalg *di, int enable, +static int ab8500_chargalg_ac_en(struct ab8500_chargalg *di, int enable, int vset, int iset) { - static int abx500_chargalg_ex_ac_enable_toggle; + static int ab8500_chargalg_ex_ac_enable_toggle; if (!di->ac_chg || !di->ac_chg->ops.enable) return -ENXIO; @@ -563,18 +562,18 @@ static int abx500_chargalg_ac_en(struct abx500_chargalg *di, int enable, /* Enable external charger */ if (enable && di->ac_chg->external && - !abx500_chargalg_ex_ac_enable_toggle) { + !ab8500_chargalg_ex_ac_enable_toggle) { blocking_notifier_call_chain(&charger_notifier_list, 0, di->dev); - abx500_chargalg_ex_ac_enable_toggle++; + ab8500_chargalg_ex_ac_enable_toggle++; } return di->ac_chg->ops.enable(di->ac_chg, enable, vset, iset); } /** - * abx500_chargalg_usb_en() - Turn on/off the USB charger - * @di: pointer to the abx500_chargalg structure + * ab8500_chargalg_usb_en() - Turn on/off the USB charger + * @di: pointer to the ab8500_chargalg structure * @enable: charger on/off * @vset: requested charger output voltage * @iset: requested charger output current @@ -582,7 +581,7 @@ static int abx500_chargalg_ac_en(struct abx500_chargalg *di, int enable, * The USB charger will be turned on/off with the requested charge voltage and * current */ -static int abx500_chargalg_usb_en(struct abx500_chargalg *di, int enable, +static int ab8500_chargalg_usb_en(struct ab8500_chargalg *di, int enable, int vset, int iset) { if (!di->usb_chg || !di->usb_chg->ops.enable) @@ -601,14 +600,14 @@ static int abx500_chargalg_usb_en(struct abx500_chargalg *di, int enable, } /** - * abx500_chargalg_update_chg_curr() - Update charger current - * @di: pointer to the abx500_chargalg structure + * ab8500_chargalg_update_chg_curr() - Update charger current + * @di: pointer to the ab8500_chargalg structure * @iset: requested charger output current * * The charger output current will be updated for the charger * that is currently in use */ -static int abx500_chargalg_update_chg_curr(struct abx500_chargalg *di, +static int ab8500_chargalg_update_chg_curr(struct ab8500_chargalg *di, int iset) { /* Check if charger exists and update current if charging */ @@ -642,19 +641,19 @@ static int abx500_chargalg_update_chg_curr(struct abx500_chargalg *di, } /** - * abx500_chargalg_stop_charging() - Stop charging - * @di: pointer to the abx500_chargalg structure + * ab8500_chargalg_stop_charging() - Stop charging + * @di: pointer to the ab8500_chargalg structure * * This function is called from any state where charging should be stopped. * All charging is disabled and all status parameters and timers are changed * accordingly */ -static void abx500_chargalg_stop_charging(struct abx500_chargalg *di) +static void ab8500_chargalg_stop_charging(struct ab8500_chargalg *di) { - abx500_chargalg_ac_en(di, false, 0, 0); - abx500_chargalg_usb_en(di, false, 0, 0); - abx500_chargalg_stop_safety_timer(di); - abx500_chargalg_stop_maintenance_timer(di); + ab8500_chargalg_ac_en(di, false, 0, 0); + ab8500_chargalg_usb_en(di, false, 0, 0); + ab8500_chargalg_stop_safety_timer(di); + ab8500_chargalg_stop_maintenance_timer(di); di->charge_status = POWER_SUPPLY_STATUS_NOT_CHARGING; di->maintenance_chg = false; cancel_delayed_work(&di->chargalg_wd_work); @@ -662,19 +661,19 @@ static void abx500_chargalg_stop_charging(struct abx500_chargalg *di) } /** - * abx500_chargalg_hold_charging() - Pauses charging - * @di: pointer to the abx500_chargalg structure + * ab8500_chargalg_hold_charging() - Pauses charging + * @di: pointer to the ab8500_chargalg structure * * This function is called in the case where maintenance charging has been * disabled and instead a battery voltage mode is entered to check when the * battery voltage has reached a certain recharge voltage */ -static void abx500_chargalg_hold_charging(struct abx500_chargalg *di) +static void ab8500_chargalg_hold_charging(struct ab8500_chargalg *di) { - abx500_chargalg_ac_en(di, false, 0, 0); - abx500_chargalg_usb_en(di, false, 0, 0); - abx500_chargalg_stop_safety_timer(di); - abx500_chargalg_stop_maintenance_timer(di); + ab8500_chargalg_ac_en(di, false, 0, 0); + ab8500_chargalg_usb_en(di, false, 0, 0); + ab8500_chargalg_stop_safety_timer(di); + ab8500_chargalg_stop_maintenance_timer(di); di->charge_status = POWER_SUPPLY_STATUS_CHARGING; di->maintenance_chg = false; cancel_delayed_work(&di->chargalg_wd_work); @@ -682,30 +681,30 @@ static void abx500_chargalg_hold_charging(struct abx500_chargalg *di) } /** - * abx500_chargalg_start_charging() - Start the charger - * @di: pointer to the abx500_chargalg structure + * ab8500_chargalg_start_charging() - Start the charger + * @di: pointer to the ab8500_chargalg structure * @vset: requested charger output voltage * @iset: requested charger output current * * A charger will be enabled depending on the requested charger type that was * detected previously. */ -static void abx500_chargalg_start_charging(struct abx500_chargalg *di, +static void ab8500_chargalg_start_charging(struct ab8500_chargalg *di, int vset, int iset) { switch (di->chg_info.charger_type) { case AC_CHG: dev_dbg(di->dev, "AC parameters: Vset %d, Ich %d\n", vset, iset); - abx500_chargalg_usb_en(di, false, 0, 0); - abx500_chargalg_ac_en(di, true, vset, iset); + ab8500_chargalg_usb_en(di, false, 0, 0); + ab8500_chargalg_ac_en(di, true, vset, iset); break; case USB_CHG: dev_dbg(di->dev, "USB parameters: Vset %d, Ich %d\n", vset, iset); - abx500_chargalg_ac_en(di, false, 0, 0); - abx500_chargalg_usb_en(di, true, vset, iset); + ab8500_chargalg_ac_en(di, false, 0, 0); + ab8500_chargalg_usb_en(di, true, vset, iset); break; default: @@ -715,13 +714,13 @@ static void abx500_chargalg_start_charging(struct abx500_chargalg *di, } /** - * abx500_chargalg_check_temp() - Check battery temperature ranges - * @di: pointer to the abx500_chargalg structure + * ab8500_chargalg_check_temp() - Check battery temperature ranges + * @di: pointer to the ab8500_chargalg structure * * The battery temperature is checked against the predefined limits and the * charge state is changed accordingly */ -static void abx500_chargalg_check_temp(struct abx500_chargalg *di) +static void ab8500_chargalg_check_temp(struct ab8500_chargalg *di) { if (di->batt_data.temp > (di->bm->temp_low + di->t_hyst_norm) && di->batt_data.temp < (di->bm->temp_high - di->t_hyst_norm)) { @@ -750,8 +749,8 @@ static void abx500_chargalg_check_temp(struct abx500_chargalg *di) di->t_hyst_norm = 0; di->t_hyst_lowhigh = di->bm->temp_hysteresis; } else { - /* Within hysteresis */ - dev_dbg(di->dev, "Within hysteresis limit temp: %d " + /* Within hysteresis */ + dev_dbg(di->dev, "Within hysteresis limit temp: %d " "hyst_lowhigh %d, hyst normal %d\n", di->batt_data.temp, di->t_hyst_lowhigh, di->t_hyst_norm); @@ -760,12 +759,12 @@ static void abx500_chargalg_check_temp(struct abx500_chargalg *di) } /** - * abx500_chargalg_check_charger_voltage() - Check charger voltage - * @di: pointer to the abx500_chargalg structure + * ab8500_chargalg_check_charger_voltage() - Check charger voltage + * @di: pointer to the ab8500_chargalg structure * * Charger voltage is checked against maximum limit */ -static void abx500_chargalg_check_charger_voltage(struct abx500_chargalg *di) +static void ab8500_chargalg_check_charger_voltage(struct ab8500_chargalg *di) { if (di->chg_info.usb_volt > di->bm->chg_params->usb_volt_max) di->chg_info.usb_chg_ok = false; @@ -780,14 +779,14 @@ static void abx500_chargalg_check_charger_voltage(struct abx500_chargalg *di) } /** - * abx500_chargalg_end_of_charge() - Check if end-of-charge criteria is fulfilled - * @di: pointer to the abx500_chargalg structure + * ab8500_chargalg_end_of_charge() - Check if end-of-charge criteria is fulfilled + * @di: pointer to the ab8500_chargalg structure * * End-of-charge criteria is fulfilled when the battery voltage is above a * certain limit and the battery current is below a certain limit for a * predefined number of consecutive seconds. If true, the battery is full */ -static void abx500_chargalg_end_of_charge(struct abx500_chargalg *di) +static void ab8500_chargalg_end_of_charge(struct ab8500_chargalg *di) { if (di->charge_status == POWER_SUPPLY_STATUS_CHARGING && di->charge_state == STATE_NORMAL && @@ -815,7 +814,7 @@ static void abx500_chargalg_end_of_charge(struct abx500_chargalg *di) } } -static void init_maxim_chg_curr(struct abx500_chargalg *di) +static void init_maxim_chg_curr(struct ab8500_chargalg *di) { di->ccm.original_iset = di->bm->bat_type[di->bm->batt_id].normal_cur_lvl; @@ -828,15 +827,15 @@ static void init_maxim_chg_curr(struct abx500_chargalg *di) } /** - * abx500_chargalg_chg_curr_maxim - increases the charger current to + * ab8500_chargalg_chg_curr_maxim - increases the charger current to * compensate for the system load - * @di pointer to the abx500_chargalg structure + * @di pointer to the ab8500_chargalg structure * * This maximization function is used to raise the charger current to get the * battery current as close to the optimal value as possible. The battery * current during charging is affected by the system load */ -static enum maxim_ret abx500_chargalg_chg_curr_maxim(struct abx500_chargalg *di) +static enum maxim_ret ab8500_chargalg_chg_curr_maxim(struct ab8500_chargalg *di) { int delta_i; @@ -867,7 +866,7 @@ static enum maxim_ret abx500_chargalg_chg_curr_maxim(struct abx500_chargalg *di) di->ccm.wait_cnt = 0; - if ((di->batt_data.inst_curr > di->ccm.original_iset)) { + if (di->batt_data.inst_curr > di->ccm.original_iset) { dev_dbg(di->dev, " Maximization Ibat (%dmA) too high" " (limit %dmA) (current iset: %dmA)!\n", di->batt_data.inst_curr, di->ccm.original_iset, @@ -908,21 +907,21 @@ static enum maxim_ret abx500_chargalg_chg_curr_maxim(struct abx500_chargalg *di) } } -static void handle_maxim_chg_curr(struct abx500_chargalg *di) +static void handle_maxim_chg_curr(struct ab8500_chargalg *di) { enum maxim_ret ret; int result; - ret = abx500_chargalg_chg_curr_maxim(di); + ret = ab8500_chargalg_chg_curr_maxim(di); switch (ret) { case MAXIM_RET_CHANGE: - result = abx500_chargalg_update_chg_curr(di, + result = ab8500_chargalg_update_chg_curr(di, di->ccm.current_iset); if (result) dev_err(di->dev, "failed to set chg curr\n"); break; case MAXIM_RET_IBAT_TOO_HIGH: - result = abx500_chargalg_update_chg_curr(di, + result = ab8500_chargalg_update_chg_curr(di, di->bm->bat_type[di->bm->batt_id].normal_cur_lvl); if (result) dev_err(di->dev, "failed to set chg curr\n"); @@ -935,12 +934,12 @@ static void handle_maxim_chg_curr(struct abx500_chargalg *di) } } -static int abx500_chargalg_get_ext_psy_data(struct device *dev, void *data) +static int ab8500_chargalg_get_ext_psy_data(struct device *dev, void *data) { struct power_supply *psy; struct power_supply *ext = dev_get_drvdata(dev); const char **supplicants = (const char **)ext->supplied_to; - struct abx500_chargalg *di; + struct ab8500_chargalg *di; union power_supply_propval ret; int j; bool capacity_updated = false; @@ -1260,7 +1259,7 @@ static int abx500_chargalg_get_ext_psy_data(struct device *dev, void *data) } /** - * abx500_chargalg_external_power_changed() - callback for power supply changes + * ab8500_chargalg_external_power_changed() - callback for power supply changes * @psy: pointer to the structure power_supply * * This function is the entry point of the pointer external_power_changed @@ -1268,26 +1267,27 @@ static int abx500_chargalg_get_ext_psy_data(struct device *dev, void *data) * This function gets executed when there is a change in any external power * supply that this driver needs to be notified of. */ -static void abx500_chargalg_external_power_changed(struct power_supply *psy) +static void ab8500_chargalg_external_power_changed(struct power_supply *psy) { - struct abx500_chargalg *di = power_supply_get_drvdata(psy); + struct ab8500_chargalg *di = power_supply_get_drvdata(psy); /* * Trigger execution of the algorithm instantly and read * all power_supply properties there instead */ - queue_work(di->chargalg_wq, &di->chargalg_work); + if (di->chargalg_wq) + queue_work(di->chargalg_wq, &di->chargalg_work); } /** - * abx500_chargalg_algorithm() - Main function for the algorithm - * @di: pointer to the abx500_chargalg structure + * ab8500_chargalg_algorithm() - Main function for the algorithm + * @di: pointer to the ab8500_chargalg structure * * This is the main control function for the charging algorithm. * It is called periodically or when something happens that will * trigger a state change */ -static void abx500_chargalg_algorithm(struct abx500_chargalg *di) +static void ab8500_chargalg_algorithm(struct ab8500_chargalg *di) { int charger_status; int ret; @@ -1295,17 +1295,17 @@ static void abx500_chargalg_algorithm(struct abx500_chargalg *di) /* Collect data from all power_supply class devices */ class_for_each_device(power_supply_class, NULL, - di->chargalg_psy, abx500_chargalg_get_ext_psy_data); + di->chargalg_psy, ab8500_chargalg_get_ext_psy_data); - abx500_chargalg_end_of_charge(di); - abx500_chargalg_check_temp(di); - abx500_chargalg_check_charger_voltage(di); + ab8500_chargalg_end_of_charge(di); + ab8500_chargalg_check_temp(di); + ab8500_chargalg_check_charger_voltage(di); - charger_status = abx500_chargalg_check_charger_connection(di); - abx500_chargalg_check_current_step_status(di); + charger_status = ab8500_chargalg_check_charger_connection(di); + ab8500_chargalg_check_current_step_status(di); if (is_ab8500(di->parent)) { - ret = abx500_chargalg_check_charger_enable(di); + ret = ab8500_chargalg_check_charger_enable(di); if (ret < 0) dev_err(di->dev, "Checking charger is enabled error" ": Returned Value %d\n", ret); @@ -1320,7 +1320,7 @@ static void abx500_chargalg_algorithm(struct abx500_chargalg *di) (di->events.batt_unknown && !di->bm->chg_unknown_bat)) { if (di->charge_state != STATE_HANDHELD) { di->events.safety_timer_expired = false; - abx500_chargalg_state_to(di, STATE_HANDHELD_INIT); + ab8500_chargalg_state_to(di, STATE_HANDHELD_INIT); } } @@ -1333,7 +1333,7 @@ static void abx500_chargalg_algorithm(struct abx500_chargalg *di) /* Safety timer expiration */ else if (di->events.safety_timer_expired) { if (di->charge_state != STATE_SAFETY_TIMER_EXPIRED) - abx500_chargalg_state_to(di, + ab8500_chargalg_state_to(di, STATE_SAFETY_TIMER_EXPIRED_INIT); } /* @@ -1344,7 +1344,7 @@ static void abx500_chargalg_algorithm(struct abx500_chargalg *di) /* Battery removed */ else if (di->events.batt_rem) { if (di->charge_state != STATE_BATT_REMOVED) - abx500_chargalg_state_to(di, STATE_BATT_REMOVED_INIT); + ab8500_chargalg_state_to(di, STATE_BATT_REMOVED_INIT); } /* Main or USB charger not ok. */ else if (di->events.mainextchnotok || di->events.usbchargernotok) { @@ -1354,7 +1354,7 @@ static void abx500_chargalg_algorithm(struct abx500_chargalg *di) */ if (di->charge_state != STATE_CHG_NOT_OK && !di->events.vbus_collapsed) - abx500_chargalg_state_to(di, STATE_CHG_NOT_OK_INIT); + ab8500_chargalg_state_to(di, STATE_CHG_NOT_OK_INIT); } /* VBUS, Main or VBAT OVV. */ else if (di->events.vbus_ovv || @@ -1363,31 +1363,31 @@ static void abx500_chargalg_algorithm(struct abx500_chargalg *di) !di->chg_info.usb_chg_ok || !di->chg_info.ac_chg_ok) { if (di->charge_state != STATE_OVV_PROTECT) - abx500_chargalg_state_to(di, STATE_OVV_PROTECT_INIT); + ab8500_chargalg_state_to(di, STATE_OVV_PROTECT_INIT); } /* USB Thermal, stop charging */ else if (di->events.main_thermal_prot || di->events.usb_thermal_prot) { if (di->charge_state != STATE_HW_TEMP_PROTECT) - abx500_chargalg_state_to(di, + ab8500_chargalg_state_to(di, STATE_HW_TEMP_PROTECT_INIT); } /* Battery temp over/under */ else if (di->events.btemp_underover) { if (di->charge_state != STATE_TEMP_UNDEROVER) - abx500_chargalg_state_to(di, + ab8500_chargalg_state_to(di, STATE_TEMP_UNDEROVER_INIT); } /* Watchdog expired */ else if (di->events.ac_wd_expired || di->events.usb_wd_expired) { if (di->charge_state != STATE_WD_EXPIRED) - abx500_chargalg_state_to(di, STATE_WD_EXPIRED_INIT); + ab8500_chargalg_state_to(di, STATE_WD_EXPIRED_INIT); } /* Battery temp high/low */ else if (di->events.btemp_lowhigh) { if (di->charge_state != STATE_TEMP_LOWHIGH) - abx500_chargalg_state_to(di, STATE_TEMP_LOWHIGH_INIT); + ab8500_chargalg_state_to(di, STATE_TEMP_LOWHIGH_INIT); } dev_dbg(di->dev, @@ -1419,9 +1419,9 @@ static void abx500_chargalg_algorithm(struct abx500_chargalg *di) switch (di->charge_state) { case STATE_HANDHELD_INIT: - abx500_chargalg_stop_charging(di); + ab8500_chargalg_stop_charging(di); di->charge_status = POWER_SUPPLY_STATUS_DISCHARGING; - abx500_chargalg_state_to(di, STATE_HANDHELD); + ab8500_chargalg_state_to(di, STATE_HANDHELD); fallthrough; case STATE_HANDHELD: @@ -1429,14 +1429,14 @@ static void abx500_chargalg_algorithm(struct abx500_chargalg *di) case STATE_SUSPENDED_INIT: if (di->susp_status.ac_suspended) - abx500_chargalg_ac_en(di, false, 0, 0); + ab8500_chargalg_ac_en(di, false, 0, 0); if (di->susp_status.usb_suspended) - abx500_chargalg_usb_en(di, false, 0, 0); - abx500_chargalg_stop_safety_timer(di); - abx500_chargalg_stop_maintenance_timer(di); + ab8500_chargalg_usb_en(di, false, 0, 0); + ab8500_chargalg_stop_safety_timer(di); + ab8500_chargalg_stop_maintenance_timer(di); di->charge_status = POWER_SUPPLY_STATUS_NOT_CHARGING; di->maintenance_chg = false; - abx500_chargalg_state_to(di, STATE_SUSPENDED); + ab8500_chargalg_state_to(di, STATE_SUSPENDED); power_supply_changed(di->chargalg_psy); fallthrough; @@ -1445,29 +1445,29 @@ static void abx500_chargalg_algorithm(struct abx500_chargalg *di) break; case STATE_BATT_REMOVED_INIT: - abx500_chargalg_stop_charging(di); - abx500_chargalg_state_to(di, STATE_BATT_REMOVED); + ab8500_chargalg_stop_charging(di); + ab8500_chargalg_state_to(di, STATE_BATT_REMOVED); fallthrough; case STATE_BATT_REMOVED: if (!di->events.batt_rem) - abx500_chargalg_state_to(di, STATE_NORMAL_INIT); + ab8500_chargalg_state_to(di, STATE_NORMAL_INIT); break; case STATE_HW_TEMP_PROTECT_INIT: - abx500_chargalg_stop_charging(di); - abx500_chargalg_state_to(di, STATE_HW_TEMP_PROTECT); + ab8500_chargalg_stop_charging(di); + ab8500_chargalg_state_to(di, STATE_HW_TEMP_PROTECT); fallthrough; case STATE_HW_TEMP_PROTECT: if (!di->events.main_thermal_prot && !di->events.usb_thermal_prot) - abx500_chargalg_state_to(di, STATE_NORMAL_INIT); + ab8500_chargalg_state_to(di, STATE_NORMAL_INIT); break; case STATE_OVV_PROTECT_INIT: - abx500_chargalg_stop_charging(di); - abx500_chargalg_state_to(di, STATE_OVV_PROTECT); + ab8500_chargalg_stop_charging(di); + ab8500_chargalg_state_to(di, STATE_OVV_PROTECT); fallthrough; case STATE_OVV_PROTECT: @@ -1476,23 +1476,23 @@ static void abx500_chargalg_algorithm(struct abx500_chargalg *di) !di->events.batt_ovv && di->chg_info.usb_chg_ok && di->chg_info.ac_chg_ok) - abx500_chargalg_state_to(di, STATE_NORMAL_INIT); + ab8500_chargalg_state_to(di, STATE_NORMAL_INIT); break; case STATE_CHG_NOT_OK_INIT: - abx500_chargalg_stop_charging(di); - abx500_chargalg_state_to(di, STATE_CHG_NOT_OK); + ab8500_chargalg_stop_charging(di); + ab8500_chargalg_state_to(di, STATE_CHG_NOT_OK); fallthrough; case STATE_CHG_NOT_OK: if (!di->events.mainextchnotok && !di->events.usbchargernotok) - abx500_chargalg_state_to(di, STATE_NORMAL_INIT); + ab8500_chargalg_state_to(di, STATE_NORMAL_INIT); break; case STATE_SAFETY_TIMER_EXPIRED_INIT: - abx500_chargalg_stop_charging(di); - abx500_chargalg_state_to(di, STATE_SAFETY_TIMER_EXPIRED); + ab8500_chargalg_stop_charging(di); + ab8500_chargalg_state_to(di, STATE_SAFETY_TIMER_EXPIRED); fallthrough; case STATE_SAFETY_TIMER_EXPIRED: @@ -1501,20 +1501,20 @@ static void abx500_chargalg_algorithm(struct abx500_chargalg *di) case STATE_NORMAL_INIT: if (di->curr_status.curr_step == CHARGALG_CURR_STEP_LOW) - abx500_chargalg_stop_charging(di); + ab8500_chargalg_stop_charging(di); else { curr_step_lvl = di->bm->bat_type[ di->bm->batt_id].normal_cur_lvl * di->curr_status.curr_step / CHARGALG_CURR_STEP_HIGH; - abx500_chargalg_start_charging(di, + ab8500_chargalg_start_charging(di, di->bm->bat_type[di->bm->batt_id] .normal_vol_lvl, curr_step_lvl); } - abx500_chargalg_state_to(di, STATE_NORMAL); - abx500_chargalg_start_safety_timer(di); - abx500_chargalg_stop_maintenance_timer(di); + ab8500_chargalg_state_to(di, STATE_NORMAL); + ab8500_chargalg_start_safety_timer(di); + ab8500_chargalg_stop_maintenance_timer(di); init_maxim_chg_curr(di); di->charge_status = POWER_SUPPLY_STATUS_CHARGING; di->eoc_cnt = 0; @@ -1528,104 +1528,103 @@ static void abx500_chargalg_algorithm(struct abx500_chargalg *di) if (di->charge_status == POWER_SUPPLY_STATUS_FULL && di->maintenance_chg) { if (di->bm->no_maintenance) - abx500_chargalg_state_to(di, + ab8500_chargalg_state_to(di, STATE_WAIT_FOR_RECHARGE_INIT); else - abx500_chargalg_state_to(di, + ab8500_chargalg_state_to(di, STATE_MAINTENANCE_A_INIT); } break; /* This state will be used when the maintenance state is disabled */ case STATE_WAIT_FOR_RECHARGE_INIT: - abx500_chargalg_hold_charging(di); - abx500_chargalg_state_to(di, STATE_WAIT_FOR_RECHARGE); + ab8500_chargalg_hold_charging(di); + ab8500_chargalg_state_to(di, STATE_WAIT_FOR_RECHARGE); fallthrough; case STATE_WAIT_FOR_RECHARGE: if (di->batt_data.percent <= - di->bm->bat_type[di->bm->batt_id]. - recharge_cap) - abx500_chargalg_state_to(di, STATE_NORMAL_INIT); + di->bm->bat_type[di->bm->batt_id].recharge_cap) + ab8500_chargalg_state_to(di, STATE_NORMAL_INIT); break; case STATE_MAINTENANCE_A_INIT: - abx500_chargalg_stop_safety_timer(di); - abx500_chargalg_start_maintenance_timer(di, + ab8500_chargalg_stop_safety_timer(di); + ab8500_chargalg_start_maintenance_timer(di, di->bm->bat_type[ di->bm->batt_id].maint_a_chg_timer_h); - abx500_chargalg_start_charging(di, + ab8500_chargalg_start_charging(di, di->bm->bat_type[ di->bm->batt_id].maint_a_vol_lvl, di->bm->bat_type[ di->bm->batt_id].maint_a_cur_lvl); - abx500_chargalg_state_to(di, STATE_MAINTENANCE_A); + ab8500_chargalg_state_to(di, STATE_MAINTENANCE_A); power_supply_changed(di->chargalg_psy); fallthrough; case STATE_MAINTENANCE_A: if (di->events.maintenance_timer_expired) { - abx500_chargalg_stop_maintenance_timer(di); - abx500_chargalg_state_to(di, STATE_MAINTENANCE_B_INIT); + ab8500_chargalg_stop_maintenance_timer(di); + ab8500_chargalg_state_to(di, STATE_MAINTENANCE_B_INIT); } break; case STATE_MAINTENANCE_B_INIT: - abx500_chargalg_start_maintenance_timer(di, + ab8500_chargalg_start_maintenance_timer(di, di->bm->bat_type[ di->bm->batt_id].maint_b_chg_timer_h); - abx500_chargalg_start_charging(di, + ab8500_chargalg_start_charging(di, di->bm->bat_type[ di->bm->batt_id].maint_b_vol_lvl, di->bm->bat_type[ di->bm->batt_id].maint_b_cur_lvl); - abx500_chargalg_state_to(di, STATE_MAINTENANCE_B); + ab8500_chargalg_state_to(di, STATE_MAINTENANCE_B); power_supply_changed(di->chargalg_psy); fallthrough; case STATE_MAINTENANCE_B: if (di->events.maintenance_timer_expired) { - abx500_chargalg_stop_maintenance_timer(di); - abx500_chargalg_state_to(di, STATE_NORMAL_INIT); + ab8500_chargalg_stop_maintenance_timer(di); + ab8500_chargalg_state_to(di, STATE_NORMAL_INIT); } break; case STATE_TEMP_LOWHIGH_INIT: - abx500_chargalg_start_charging(di, + ab8500_chargalg_start_charging(di, di->bm->bat_type[ di->bm->batt_id].low_high_vol_lvl, di->bm->bat_type[ di->bm->batt_id].low_high_cur_lvl); - abx500_chargalg_stop_maintenance_timer(di); + ab8500_chargalg_stop_maintenance_timer(di); di->charge_status = POWER_SUPPLY_STATUS_CHARGING; - abx500_chargalg_state_to(di, STATE_TEMP_LOWHIGH); + ab8500_chargalg_state_to(di, STATE_TEMP_LOWHIGH); power_supply_changed(di->chargalg_psy); fallthrough; case STATE_TEMP_LOWHIGH: if (!di->events.btemp_lowhigh) - abx500_chargalg_state_to(di, STATE_NORMAL_INIT); + ab8500_chargalg_state_to(di, STATE_NORMAL_INIT); break; case STATE_WD_EXPIRED_INIT: - abx500_chargalg_stop_charging(di); - abx500_chargalg_state_to(di, STATE_WD_EXPIRED); + ab8500_chargalg_stop_charging(di); + ab8500_chargalg_state_to(di, STATE_WD_EXPIRED); fallthrough; case STATE_WD_EXPIRED: if (!di->events.ac_wd_expired && !di->events.usb_wd_expired) - abx500_chargalg_state_to(di, STATE_NORMAL_INIT); + ab8500_chargalg_state_to(di, STATE_NORMAL_INIT); break; case STATE_TEMP_UNDEROVER_INIT: - abx500_chargalg_stop_charging(di); - abx500_chargalg_state_to(di, STATE_TEMP_UNDEROVER); + ab8500_chargalg_stop_charging(di); + ab8500_chargalg_state_to(di, STATE_TEMP_UNDEROVER); fallthrough; case STATE_TEMP_UNDEROVER: if (!di->events.btemp_underover) - abx500_chargalg_state_to(di, STATE_NORMAL_INIT); + ab8500_chargalg_state_to(di, STATE_NORMAL_INIT); break; } @@ -1637,17 +1636,17 @@ static void abx500_chargalg_algorithm(struct abx500_chargalg *di) } /** - * abx500_chargalg_periodic_work() - Periodic work for the algorithm + * ab8500_chargalg_periodic_work() - Periodic work for the algorithm * @work: pointer to the work_struct structure * * Work queue function for the charging algorithm */ -static void abx500_chargalg_periodic_work(struct work_struct *work) +static void ab8500_chargalg_periodic_work(struct work_struct *work) { - struct abx500_chargalg *di = container_of(work, - struct abx500_chargalg, chargalg_periodic_work.work); + struct ab8500_chargalg *di = container_of(work, + struct ab8500_chargalg, chargalg_periodic_work.work); - abx500_chargalg_algorithm(di); + ab8500_chargalg_algorithm(di); /* * If a charger is connected then the battery has to be monitored @@ -1664,20 +1663,18 @@ static void abx500_chargalg_periodic_work(struct work_struct *work) } /** - * abx500_chargalg_wd_work() - periodic work to kick the charger watchdog + * ab8500_chargalg_wd_work() - periodic work to kick the charger watchdog * @work: pointer to the work_struct structure * * Work queue function for kicking the charger watchdog */ -static void abx500_chargalg_wd_work(struct work_struct *work) +static void ab8500_chargalg_wd_work(struct work_struct *work) { int ret; - struct abx500_chargalg *di = container_of(work, - struct abx500_chargalg, chargalg_wd_work.work); - - dev_dbg(di->dev, "abx500_chargalg_wd_work\n"); + struct ab8500_chargalg *di = container_of(work, + struct ab8500_chargalg, chargalg_wd_work.work); - ret = abx500_chargalg_kick_watchdog(di); + ret = ab8500_chargalg_kick_watchdog(di); if (ret < 0) dev_err(di->dev, "failed to kick watchdog\n"); @@ -1686,21 +1683,21 @@ static void abx500_chargalg_wd_work(struct work_struct *work) } /** - * abx500_chargalg_work() - Work to run the charging algorithm instantly + * ab8500_chargalg_work() - Work to run the charging algorithm instantly * @work: pointer to the work_struct structure * * Work queue function for calling the charging algorithm */ -static void abx500_chargalg_work(struct work_struct *work) +static void ab8500_chargalg_work(struct work_struct *work) { - struct abx500_chargalg *di = container_of(work, - struct abx500_chargalg, chargalg_work); + struct ab8500_chargalg *di = container_of(work, + struct ab8500_chargalg, chargalg_work); - abx500_chargalg_algorithm(di); + ab8500_chargalg_algorithm(di); } /** - * abx500_chargalg_get_property() - get the chargalg properties + * ab8500_chargalg_get_property() - get the chargalg properties * @psy: pointer to the power_supply structure * @psp: pointer to the power_supply_property structure * @val: pointer to the power_supply_propval union @@ -1711,11 +1708,11 @@ static void abx500_chargalg_work(struct work_struct *work) * health: health of the battery * Returns error code in case of failure else 0 on success */ -static int abx500_chargalg_get_property(struct power_supply *psy, +static int ab8500_chargalg_get_property(struct power_supply *psy, enum power_supply_property psp, union power_supply_propval *val) { - struct abx500_chargalg *di = power_supply_get_drvdata(psy); + struct ab8500_chargalg *di = power_supply_get_drvdata(psy); switch (psp) { case POWER_SUPPLY_PROP_STATUS: @@ -1744,16 +1741,16 @@ static int abx500_chargalg_get_property(struct power_supply *psy, /* Exposure to the sysfs interface */ -static ssize_t abx500_chargalg_curr_step_show(struct abx500_chargalg *di, +static ssize_t ab8500_chargalg_curr_step_show(struct ab8500_chargalg *di, char *buf) { return sprintf(buf, "%d\n", di->curr_status.curr_step); } -static ssize_t abx500_chargalg_curr_step_store(struct abx500_chargalg *di, +static ssize_t ab8500_chargalg_curr_step_store(struct ab8500_chargalg *di, const char *buf, size_t length) { - long int param; + long param; int ret; ret = kstrtol(buf, 10, ¶m); @@ -1775,7 +1772,7 @@ static ssize_t abx500_chargalg_curr_step_store(struct abx500_chargalg *di, } -static ssize_t abx500_chargalg_en_show(struct abx500_chargalg *di, +static ssize_t ab8500_chargalg_en_show(struct ab8500_chargalg *di, char *buf) { return sprintf(buf, "%d\n", @@ -1783,10 +1780,10 @@ static ssize_t abx500_chargalg_en_show(struct abx500_chargalg *di, di->susp_status.usb_suspended); } -static ssize_t abx500_chargalg_en_store(struct abx500_chargalg *di, +static ssize_t ab8500_chargalg_en_store(struct ab8500_chargalg *di, const char *buf, size_t length) { - long int param; + long param; int ac_usb; int ret; @@ -1830,22 +1827,22 @@ static ssize_t abx500_chargalg_en_store(struct abx500_chargalg *di, return strlen(buf); } -static struct abx500_chargalg_sysfs_entry abx500_chargalg_en_charger = - __ATTR(chargalg, 0644, abx500_chargalg_en_show, - abx500_chargalg_en_store); +static struct ab8500_chargalg_sysfs_entry ab8500_chargalg_en_charger = + __ATTR(chargalg, 0644, ab8500_chargalg_en_show, + ab8500_chargalg_en_store); -static struct abx500_chargalg_sysfs_entry abx500_chargalg_curr_step = - __ATTR(chargalg_curr_step, 0644, abx500_chargalg_curr_step_show, - abx500_chargalg_curr_step_store); +static struct ab8500_chargalg_sysfs_entry ab8500_chargalg_curr_step = + __ATTR(chargalg_curr_step, 0644, ab8500_chargalg_curr_step_show, + ab8500_chargalg_curr_step_store); -static ssize_t abx500_chargalg_sysfs_show(struct kobject *kobj, +static ssize_t ab8500_chargalg_sysfs_show(struct kobject *kobj, struct attribute *attr, char *buf) { - struct abx500_chargalg_sysfs_entry *entry = container_of(attr, - struct abx500_chargalg_sysfs_entry, attr); + struct ab8500_chargalg_sysfs_entry *entry = container_of(attr, + struct ab8500_chargalg_sysfs_entry, attr); - struct abx500_chargalg *di = container_of(kobj, - struct abx500_chargalg, chargalg_kobject); + struct ab8500_chargalg *di = container_of(kobj, + struct ab8500_chargalg, chargalg_kobject); if (!entry->show) return -EIO; @@ -1853,14 +1850,14 @@ static ssize_t abx500_chargalg_sysfs_show(struct kobject *kobj, return entry->show(di, buf); } -static ssize_t abx500_chargalg_sysfs_charger(struct kobject *kobj, +static ssize_t ab8500_chargalg_sysfs_charger(struct kobject *kobj, struct attribute *attr, const char *buf, size_t length) { - struct abx500_chargalg_sysfs_entry *entry = container_of(attr, - struct abx500_chargalg_sysfs_entry, attr); + struct ab8500_chargalg_sysfs_entry *entry = container_of(attr, + struct ab8500_chargalg_sysfs_entry, attr); - struct abx500_chargalg *di = container_of(kobj, - struct abx500_chargalg, chargalg_kobject); + struct ab8500_chargalg *di = container_of(kobj, + struct ab8500_chargalg, chargalg_kobject); if (!entry->store) return -EIO; @@ -1868,47 +1865,47 @@ static ssize_t abx500_chargalg_sysfs_charger(struct kobject *kobj, return entry->store(di, buf, length); } -static struct attribute *abx500_chargalg_chg[] = { - &abx500_chargalg_en_charger.attr, - &abx500_chargalg_curr_step.attr, +static struct attribute *ab8500_chargalg_chg[] = { + &ab8500_chargalg_en_charger.attr, + &ab8500_chargalg_curr_step.attr, NULL, }; -static const struct sysfs_ops abx500_chargalg_sysfs_ops = { - .show = abx500_chargalg_sysfs_show, - .store = abx500_chargalg_sysfs_charger, +static const struct sysfs_ops ab8500_chargalg_sysfs_ops = { + .show = ab8500_chargalg_sysfs_show, + .store = ab8500_chargalg_sysfs_charger, }; -static struct kobj_type abx500_chargalg_ktype = { - .sysfs_ops = &abx500_chargalg_sysfs_ops, - .default_attrs = abx500_chargalg_chg, +static struct kobj_type ab8500_chargalg_ktype = { + .sysfs_ops = &ab8500_chargalg_sysfs_ops, + .default_attrs = ab8500_chargalg_chg, }; /** - * abx500_chargalg_sysfs_exit() - de-init of sysfs entry - * @di: pointer to the struct abx500_chargalg + * ab8500_chargalg_sysfs_exit() - de-init of sysfs entry + * @di: pointer to the struct ab8500_chargalg * * This function removes the entry in sysfs. */ -static void abx500_chargalg_sysfs_exit(struct abx500_chargalg *di) +static void ab8500_chargalg_sysfs_exit(struct ab8500_chargalg *di) { kobject_del(&di->chargalg_kobject); } /** - * abx500_chargalg_sysfs_init() - init of sysfs entry - * @di: pointer to the struct abx500_chargalg + * ab8500_chargalg_sysfs_init() - init of sysfs entry + * @di: pointer to the struct ab8500_chargalg * * This function adds an entry in sysfs. * Returns error code in case of failure else 0(on success) */ -static int abx500_chargalg_sysfs_init(struct abx500_chargalg *di) +static int ab8500_chargalg_sysfs_init(struct ab8500_chargalg *di) { int ret = 0; ret = kobject_init_and_add(&di->chargalg_kobject, - &abx500_chargalg_ktype, - NULL, "abx500_chargalg"); + &ab8500_chargalg_ktype, + NULL, "ab8500_chargalg"); if (ret < 0) dev_err(di->dev, "failed to create sysfs entry\n"); @@ -1916,9 +1913,9 @@ static int abx500_chargalg_sysfs_init(struct abx500_chargalg *di) } /* Exposure to the sysfs interface <<END>> */ -static int __maybe_unused abx500_chargalg_resume(struct device *dev) +static int __maybe_unused ab8500_chargalg_resume(struct device *dev) { - struct abx500_chargalg *di = dev_get_drvdata(dev); + struct ab8500_chargalg *di = dev_get_drvdata(dev); /* Kick charger watchdog if charging (any charger online) */ if (di->chg_info.online_chg) @@ -1933,9 +1930,9 @@ static int __maybe_unused abx500_chargalg_resume(struct device *dev) return 0; } -static int __maybe_unused abx500_chargalg_suspend(struct device *dev) +static int __maybe_unused ab8500_chargalg_suspend(struct device *dev) { - struct abx500_chargalg *di = dev_get_drvdata(dev); + struct ab8500_chargalg *di = dev_get_drvdata(dev); if (di->chg_info.online_chg) cancel_delayed_work_sync(&di->chargalg_wd_work); @@ -1949,22 +1946,22 @@ static char *supply_interface[] = { "ab8500_fg", }; -static const struct power_supply_desc abx500_chargalg_desc = { - .name = "abx500_chargalg", +static const struct power_supply_desc ab8500_chargalg_desc = { + .name = "ab8500_chargalg", .type = POWER_SUPPLY_TYPE_BATTERY, - .properties = abx500_chargalg_props, - .num_properties = ARRAY_SIZE(abx500_chargalg_props), - .get_property = abx500_chargalg_get_property, - .external_power_changed = abx500_chargalg_external_power_changed, + .properties = ab8500_chargalg_props, + .num_properties = ARRAY_SIZE(ab8500_chargalg_props), + .get_property = ab8500_chargalg_get_property, + .external_power_changed = ab8500_chargalg_external_power_changed, }; -static int abx500_chargalg_bind(struct device *dev, struct device *master, +static int ab8500_chargalg_bind(struct device *dev, struct device *master, void *data) { - struct abx500_chargalg *di = dev_get_drvdata(dev); + struct ab8500_chargalg *di = dev_get_drvdata(dev); /* Create a work queue for the chargalg */ - di->chargalg_wq = alloc_ordered_workqueue("abx500_chargalg_wq", + di->chargalg_wq = alloc_ordered_workqueue("ab8500_chargalg_wq", WQ_MEM_RECLAIM); if (di->chargalg_wq == NULL) { dev_err(di->dev, "failed to create work queue\n"); @@ -1977,10 +1974,10 @@ static int abx500_chargalg_bind(struct device *dev, struct device *master, return 0; } -static void abx500_chargalg_unbind(struct device *dev, struct device *master, +static void ab8500_chargalg_unbind(struct device *dev, struct device *master, void *data) { - struct abx500_chargalg *di = dev_get_drvdata(dev); + struct ab8500_chargalg *di = dev_get_drvdata(dev); /* Stop all timers and work */ hrtimer_cancel(&di->safety_timer); @@ -1995,16 +1992,16 @@ static void abx500_chargalg_unbind(struct device *dev, struct device *master, flush_scheduled_work(); } -static const struct component_ops abx500_chargalg_component_ops = { - .bind = abx500_chargalg_bind, - .unbind = abx500_chargalg_unbind, +static const struct component_ops ab8500_chargalg_component_ops = { + .bind = ab8500_chargalg_bind, + .unbind = ab8500_chargalg_unbind, }; -static int abx500_chargalg_probe(struct platform_device *pdev) +static int ab8500_chargalg_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct power_supply_config psy_cfg = {}; - struct abx500_chargalg *di; + struct ab8500_chargalg *di; int ret = 0; di = devm_kzalloc(dev, sizeof(*di), GFP_KERNEL); @@ -2023,28 +2020,28 @@ static int abx500_chargalg_probe(struct platform_device *pdev) /* Initilialize safety timer */ hrtimer_init(&di->safety_timer, CLOCK_REALTIME, HRTIMER_MODE_ABS); - di->safety_timer.function = abx500_chargalg_safety_timer_expired; + di->safety_timer.function = ab8500_chargalg_safety_timer_expired; /* Initilialize maintenance timer */ hrtimer_init(&di->maintenance_timer, CLOCK_REALTIME, HRTIMER_MODE_ABS); di->maintenance_timer.function = - abx500_chargalg_maintenance_timer_expired; + ab8500_chargalg_maintenance_timer_expired; /* Init work for chargalg */ INIT_DEFERRABLE_WORK(&di->chargalg_periodic_work, - abx500_chargalg_periodic_work); + ab8500_chargalg_periodic_work); INIT_DEFERRABLE_WORK(&di->chargalg_wd_work, - abx500_chargalg_wd_work); + ab8500_chargalg_wd_work); /* Init work for chargalg */ - INIT_WORK(&di->chargalg_work, abx500_chargalg_work); + INIT_WORK(&di->chargalg_work, ab8500_chargalg_work); /* To detect charger at startup */ di->chg_info.prev_conn_chg = -1; /* Register chargalg power supply class */ di->chargalg_psy = devm_power_supply_register(di->dev, - &abx500_chargalg_desc, + &ab8500_chargalg_desc, &psy_cfg); if (IS_ERR(di->chargalg_psy)) { dev_err(di->dev, "failed to register chargalg psy\n"); @@ -2054,7 +2051,7 @@ static int abx500_chargalg_probe(struct platform_device *pdev) platform_set_drvdata(pdev, di); /* sysfs interface to enable/disable charging from user space */ - ret = abx500_chargalg_sysfs_init(di); + ret = ab8500_chargalg_sysfs_init(di); if (ret) { dev_err(di->dev, "failed to create sysfs entry\n"); return ret; @@ -2062,38 +2059,38 @@ static int abx500_chargalg_probe(struct platform_device *pdev) di->curr_status.curr_step = CHARGALG_CURR_STEP_HIGH; dev_info(di->dev, "probe success\n"); - return component_add(dev, &abx500_chargalg_component_ops); + return component_add(dev, &ab8500_chargalg_component_ops); } -static int abx500_chargalg_remove(struct platform_device *pdev) +static int ab8500_chargalg_remove(struct platform_device *pdev) { - struct abx500_chargalg *di = platform_get_drvdata(pdev); + struct ab8500_chargalg *di = platform_get_drvdata(pdev); - component_del(&pdev->dev, &abx500_chargalg_component_ops); + component_del(&pdev->dev, &ab8500_chargalg_component_ops); /* sysfs interface to enable/disable charging from user space */ - abx500_chargalg_sysfs_exit(di); + ab8500_chargalg_sysfs_exit(di); return 0; } -static SIMPLE_DEV_PM_OPS(abx500_chargalg_pm_ops, abx500_chargalg_suspend, abx500_chargalg_resume); +static SIMPLE_DEV_PM_OPS(ab8500_chargalg_pm_ops, ab8500_chargalg_suspend, ab8500_chargalg_resume); static const struct of_device_id ab8500_chargalg_match[] = { { .compatible = "stericsson,ab8500-chargalg", }, { }, }; -struct platform_driver abx500_chargalg_driver = { - .probe = abx500_chargalg_probe, - .remove = abx500_chargalg_remove, +struct platform_driver ab8500_chargalg_driver = { + .probe = ab8500_chargalg_probe, + .remove = ab8500_chargalg_remove, .driver = { - .name = "ab8500-chargalg", + .name = "ab8500_chargalg", .of_match_table = ab8500_chargalg_match, - .pm = &abx500_chargalg_pm_ops, + .pm = &ab8500_chargalg_pm_ops, }, }; MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Johan Palsson, Karl Komierowski"); -MODULE_ALIAS("platform:abx500-chargalg"); -MODULE_DESCRIPTION("abx500 battery charging algorithm"); +MODULE_ALIAS("platform:ab8500-chargalg"); +MODULE_DESCRIPTION("ab8500 battery charging algorithm"); diff --git a/drivers/power/supply/ab8500_charger.c b/drivers/power/supply/ab8500_charger.c index fa49e12e5a60..15eadaf46f14 100644 --- a/drivers/power/supply/ab8500_charger.c +++ b/drivers/power/supply/ab8500_charger.c @@ -292,7 +292,7 @@ struct ab8500_charger { struct iio_channel *adc_main_charger_c; struct iio_channel *adc_vbus_v; struct iio_channel *adc_usb_charger_c; - struct abx500_bm_data *bm; + struct ab8500_bm_data *bm; struct ab8500_charger_event_flags flags; struct ab8500_charger_usb_state usb_state; struct ab8500_charger_max_usb_in_curr max_usb_in_curr; @@ -3388,7 +3388,7 @@ static const struct component_master_ops ab8500_charger_comp_ops = { static struct platform_driver *const ab8500_charger_component_drivers[] = { &ab8500_fg_driver, &ab8500_btemp_driver, - &abx500_chargalg_driver, + &ab8500_chargalg_driver, }; static int ab8500_charger_compare_dev(struct device *dev, void *data) diff --git a/drivers/power/supply/ab8500_fg.c b/drivers/power/supply/ab8500_fg.c index a6ebdb269fdd..05fe9724ba50 100644 --- a/drivers/power/supply/ab8500_fg.c +++ b/drivers/power/supply/ab8500_fg.c @@ -34,6 +34,7 @@ #include <linux/mfd/abx500/ab8500.h> #include <linux/iio/consumer.h> #include <linux/kernel.h> +#include <linux/fixp-arith.h> #include "ab8500-bm.h" @@ -56,9 +57,6 @@ /* FG constants */ #define BATT_OVV 0x01 -#define interpolate(x, x1, y1, x2, y2) \ - ((y1) + ((((y2) - (y1)) * ((x) - (x1))) / ((x2) - (x1)))); - /** * struct ab8500_fg_interrupts - ab8500 fg interrupts * @name: name of the interrupt @@ -227,7 +225,7 @@ struct ab8500_fg { struct ab8500_fg_avg_cap avg_cap; struct ab8500 *parent; struct iio_channel *main_bat_v; - struct abx500_bm_data *bm; + struct ab8500_bm_data *bm; struct power_supply *fg_psy; struct workqueue_struct *fg_wq; struct delayed_work fg_periodic_work; @@ -856,7 +854,7 @@ static int ab8500_fg_bat_voltage(struct ab8500_fg *di) static int ab8500_fg_volt_to_capacity(struct ab8500_fg *di, int voltage) { int i, tbl_size; - const struct abx500_v_to_cap *tbl; + const struct ab8500_v_to_cap *tbl; int cap = 0; tbl = di->bm->bat_type[di->bm->batt_id].v_to_cap_tbl; @@ -868,11 +866,12 @@ static int ab8500_fg_volt_to_capacity(struct ab8500_fg *di, int voltage) } if ((i > 0) && (i < tbl_size)) { - cap = interpolate(voltage, + cap = fixp_linear_interpolate( tbl[i].voltage, tbl[i].capacity * 10, tbl[i-1].voltage, - tbl[i-1].capacity * 10); + tbl[i-1].capacity * 10, + voltage); } else if (i == 0) { cap = 1000; } else { @@ -920,11 +919,12 @@ static int ab8500_fg_battery_resistance(struct ab8500_fg *di) } if ((i > 0) && (i < tbl_size)) { - resist = interpolate(di->bat_temp / 10, + resist = fixp_linear_interpolate( tbl[i].temp, tbl[i].resist, tbl[i-1].temp, - tbl[i-1].resist); + tbl[i-1].resist, + di->bat_temp / 10); } else if (i == 0) { resist = tbl[0].resist; } else { @@ -2235,7 +2235,7 @@ static int ab8500_fg_get_ext_psy_data(struct device *dev, void *data) case POWER_SUPPLY_TYPE_BATTERY: if (!di->flags.batt_id_received && di->bm->batt_id != BATTERY_UNKNOWN) { - const struct abx500_battery_type *b; + const struct ab8500_battery_type *b; b = &(di->bm->bat_type[di->bm->batt_id]); diff --git a/drivers/power/supply/axp288_charger.c b/drivers/power/supply/axp288_charger.c index a4df1ea92386..b9553be9bed5 100644 --- a/drivers/power/supply/axp288_charger.c +++ b/drivers/power/supply/axp288_charger.c @@ -813,7 +813,7 @@ static int axp288_charger_probe(struct platform_device *pdev) if (val == 0) return -ENODEV; - info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); + info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL); if (!info) return -ENOMEM; @@ -823,7 +823,7 @@ static int axp288_charger_probe(struct platform_device *pdev) info->cable.edev = extcon_get_extcon_dev(AXP288_EXTCON_DEV_NAME); if (info->cable.edev == NULL) { - dev_dbg(&pdev->dev, "%s is not ready, probe deferred\n", + dev_dbg(dev, "%s is not ready, probe deferred\n", AXP288_EXTCON_DEV_NAME); return -EPROBE_DEFER; } @@ -834,8 +834,7 @@ static int axp288_charger_probe(struct platform_device *pdev) dev_dbg(dev, "EXTCON_USB_HOST is not ready, probe deferred\n"); return -EPROBE_DEFER; } - dev_info(&pdev->dev, - "Using " USB_HOST_EXTCON_HID " extcon for usb-id\n"); + dev_info(dev, "Using " USB_HOST_EXTCON_HID " extcon for usb-id\n"); } platform_set_drvdata(pdev, info); @@ -874,7 +873,7 @@ static int axp288_charger_probe(struct platform_device *pdev) INIT_WORK(&info->otg.work, axp288_charger_otg_evt_worker); info->otg.id_nb.notifier_call = axp288_charger_handle_otg_evt; if (info->otg.cable) { - ret = devm_extcon_register_notifier(&pdev->dev, info->otg.cable, + ret = devm_extcon_register_notifier(dev, info->otg.cable, EXTCON_USB_HOST, &info->otg.id_nb); if (ret) { dev_err(dev, "failed to register EXTCON_USB_HOST notifier\n"); @@ -899,7 +898,7 @@ static int axp288_charger_probe(struct platform_device *pdev) NULL, axp288_charger_irq_thread_handler, IRQF_ONESHOT, info->pdev->name, info); if (ret) { - dev_err(&pdev->dev, "failed to request interrupt=%d\n", + dev_err(dev, "failed to request interrupt=%d\n", info->irq[i]); return ret; } diff --git a/drivers/power/supply/axp288_fuel_gauge.c b/drivers/power/supply/axp288_fuel_gauge.c index 2ba2d8d6b8e6..c1da217fdb0e 100644 --- a/drivers/power/supply/axp288_fuel_gauge.c +++ b/drivers/power/supply/axp288_fuel_gauge.c @@ -2,7 +2,8 @@ /* * axp288_fuel_gauge.c - Xpower AXP288 PMIC Fuel Gauge Driver * - * Copyright (C) 2016-2017 Hans de Goede <hdegoede@redhat.com> + * Copyright (C) 2020-2021 Andrejus Basovas <xxx@yyy.tld> + * Copyright (C) 2016-2021 Hans de Goede <hdegoede@redhat.com> * Copyright (C) 2014 Intel Corporation * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -19,38 +20,37 @@ #include <linux/platform_device.h> #include <linux/power_supply.h> #include <linux/iio/consumer.h> -#include <linux/debugfs.h> -#include <linux/seq_file.h> #include <asm/unaligned.h> +#include <asm/iosf_mbi.h> -#define PS_STAT_VBUS_TRIGGER (1 << 0) -#define PS_STAT_BAT_CHRG_DIR (1 << 2) -#define PS_STAT_VBAT_ABOVE_VHOLD (1 << 3) -#define PS_STAT_VBUS_VALID (1 << 4) -#define PS_STAT_VBUS_PRESENT (1 << 5) +#define PS_STAT_VBUS_TRIGGER (1 << 0) +#define PS_STAT_BAT_CHRG_DIR (1 << 2) +#define PS_STAT_VBAT_ABOVE_VHOLD (1 << 3) +#define PS_STAT_VBUS_VALID (1 << 4) +#define PS_STAT_VBUS_PRESENT (1 << 5) -#define CHRG_STAT_BAT_SAFE_MODE (1 << 3) +#define CHRG_STAT_BAT_SAFE_MODE (1 << 3) #define CHRG_STAT_BAT_VALID (1 << 4) -#define CHRG_STAT_BAT_PRESENT (1 << 5) +#define CHRG_STAT_BAT_PRESENT (1 << 5) #define CHRG_STAT_CHARGING (1 << 6) #define CHRG_STAT_PMIC_OTP (1 << 7) #define CHRG_CCCV_CC_MASK 0xf /* 4 bits */ -#define CHRG_CCCV_CC_BIT_POS 0 +#define CHRG_CCCV_CC_BIT_POS 0 #define CHRG_CCCV_CC_OFFSET 200 /* 200mA */ -#define CHRG_CCCV_CC_LSB_RES 200 /* 200mA */ +#define CHRG_CCCV_CC_LSB_RES 200 /* 200mA */ #define CHRG_CCCV_ITERM_20P (1 << 4) /* 20% of CC */ #define CHRG_CCCV_CV_MASK 0x60 /* 2 bits */ -#define CHRG_CCCV_CV_BIT_POS 5 +#define CHRG_CCCV_CV_BIT_POS 5 #define CHRG_CCCV_CV_4100MV 0x0 /* 4.10V */ #define CHRG_CCCV_CV_4150MV 0x1 /* 4.15V */ #define CHRG_CCCV_CV_4200MV 0x2 /* 4.20V */ #define CHRG_CCCV_CV_4350MV 0x3 /* 4.35V */ #define CHRG_CCCV_CHG_EN (1 << 7) -#define FG_CNTL_OCV_ADJ_STAT (1 << 2) +#define FG_CNTL_OCV_ADJ_STAT (1 << 2) #define FG_CNTL_OCV_ADJ_EN (1 << 3) -#define FG_CNTL_CAP_ADJ_STAT (1 << 4) +#define FG_CNTL_CAP_ADJ_STAT (1 << 4) #define FG_CNTL_CAP_ADJ_EN (1 << 5) #define FG_CNTL_CC_EN (1 << 6) #define FG_CNTL_GAUGE_EN (1 << 7) @@ -71,23 +71,23 @@ #define FG_CC_CAP_VALID (1 << 7) #define FG_CC_CAP_VAL_MASK 0x7F -#define FG_LOW_CAP_THR1_MASK 0xf0 /* 5% tp 20% */ +#define FG_LOW_CAP_THR1_MASK 0xf0 /* 5% tp 20% */ #define FG_LOW_CAP_THR1_VAL 0xa0 /* 15 perc */ -#define FG_LOW_CAP_THR2_MASK 0x0f /* 0% to 15% */ +#define FG_LOW_CAP_THR2_MASK 0x0f /* 0% to 15% */ #define FG_LOW_CAP_WARN_THR 14 /* 14 perc */ #define FG_LOW_CAP_CRIT_THR 4 /* 4 perc */ #define FG_LOW_CAP_SHDN_THR 0 /* 0 perc */ -#define NR_RETRY_CNT 3 -#define DEV_NAME "axp288_fuel_gauge" +#define DEV_NAME "axp288_fuel_gauge" /* 1.1mV per LSB expressed in uV */ #define VOLTAGE_FROM_ADC(a) ((a * 11) / 10) /* properties converted to uV, uA */ -#define PROP_VOLT(a) ((a) * 1000) -#define PROP_CURR(a) ((a) * 1000) +#define PROP_VOLT(a) ((a) * 1000) +#define PROP_CURR(a) ((a) * 1000) -#define AXP288_FG_INTR_NUM 6 +#define AXP288_REG_UPDATE_INTERVAL (60 * HZ) +#define AXP288_FG_INTR_NUM 6 enum { QWBTU_IRQ = 0, WBTU_IRQ, @@ -98,9 +98,6 @@ enum { }; enum { - BAT_TEMP = 0, - PMIC_TEMP, - SYSTEM_TEMP, BAT_CHRG_CURR, BAT_D_CURR, BAT_VOLT, @@ -108,7 +105,7 @@ enum { }; struct axp288_fg_info { - struct platform_device *pdev; + struct device *dev; struct regmap *regmap; struct regmap_irq_chip_data *regmap_irqc; int irq[AXP288_FG_INTR_NUM]; @@ -117,7 +114,21 @@ struct axp288_fg_info { struct mutex lock; int status; int max_volt; + int pwr_op; + int low_cap; struct dentry *debug_file; + + char valid; /* zero until following fields are valid */ + unsigned long last_updated; /* in jiffies */ + + int pwr_stat; + int fg_res; + int bat_volt; + int d_curr; + int c_curr; + int ocv; + int fg_cc_mtr1; + int fg_des_cap1; }; static enum power_supply_property fuel_gauge_props[] = { @@ -137,17 +148,12 @@ static enum power_supply_property fuel_gauge_props[] = { static int fuel_gauge_reg_readb(struct axp288_fg_info *info, int reg) { - int ret, i; unsigned int val; + int ret; - for (i = 0; i < NR_RETRY_CNT; i++) { - ret = regmap_read(info->regmap, reg, &val); - if (ret != -EBUSY) - break; - } - + ret = regmap_read(info->regmap, reg, &val); if (ret < 0) { - dev_err(&info->pdev->dev, "axp288 reg read err:%d\n", ret); + dev_err(info->dev, "Error reading reg 0x%02x err: %d\n", reg, ret); return ret; } @@ -161,7 +167,7 @@ static int fuel_gauge_reg_writeb(struct axp288_fg_info *info, int reg, u8 val) ret = regmap_write(info->regmap, reg, (unsigned int)val); if (ret < 0) - dev_err(&info->pdev->dev, "axp288 reg write err:%d\n", ret); + dev_err(info->dev, "Error writing reg 0x%02x err: %d\n", reg, ret); return ret; } @@ -173,15 +179,13 @@ static int fuel_gauge_read_15bit_word(struct axp288_fg_info *info, int reg) ret = regmap_bulk_read(info->regmap, reg, buf, 2); if (ret < 0) { - dev_err(&info->pdev->dev, "Error reading reg 0x%02x err: %d\n", - reg, ret); + dev_err(info->dev, "Error reading reg 0x%02x err: %d\n", reg, ret); return ret; } ret = get_unaligned_be16(buf); if (!(ret & FG_15BIT_WORD_VALID)) { - dev_err(&info->pdev->dev, "Error reg 0x%02x contents not valid\n", - reg); + dev_err(info->dev, "Error reg 0x%02x contents not valid\n", reg); return -ENXIO; } @@ -195,8 +199,7 @@ static int fuel_gauge_read_12bit_word(struct axp288_fg_info *info, int reg) ret = regmap_bulk_read(info->regmap, reg, buf, 2); if (ret < 0) { - dev_err(&info->pdev->dev, "Error reading reg 0x%02x err: %d\n", - reg, ret); + dev_err(info->dev, "Error reading reg 0x%02x err: %d\n", reg, ret); return ret; } @@ -204,139 +207,78 @@ static int fuel_gauge_read_12bit_word(struct axp288_fg_info *info, int reg) return (buf[0] << 4) | ((buf[1] >> 4) & 0x0f); } -#ifdef CONFIG_DEBUG_FS -static int fuel_gauge_debug_show(struct seq_file *s, void *data) +static int fuel_gauge_update_registers(struct axp288_fg_info *info) { - struct axp288_fg_info *info = s->private; - int raw_val, ret; - - seq_printf(s, " PWR_STATUS[%02x] : %02x\n", - AXP20X_PWR_INPUT_STATUS, - fuel_gauge_reg_readb(info, AXP20X_PWR_INPUT_STATUS)); - seq_printf(s, "PWR_OP_MODE[%02x] : %02x\n", - AXP20X_PWR_OP_MODE, - fuel_gauge_reg_readb(info, AXP20X_PWR_OP_MODE)); - seq_printf(s, " CHRG_CTRL1[%02x] : %02x\n", - AXP20X_CHRG_CTRL1, - fuel_gauge_reg_readb(info, AXP20X_CHRG_CTRL1)); - seq_printf(s, " VLTF[%02x] : %02x\n", - AXP20X_V_LTF_DISCHRG, - fuel_gauge_reg_readb(info, AXP20X_V_LTF_DISCHRG)); - seq_printf(s, " VHTF[%02x] : %02x\n", - AXP20X_V_HTF_DISCHRG, - fuel_gauge_reg_readb(info, AXP20X_V_HTF_DISCHRG)); - seq_printf(s, " CC_CTRL[%02x] : %02x\n", - AXP20X_CC_CTRL, - fuel_gauge_reg_readb(info, AXP20X_CC_CTRL)); - seq_printf(s, "BATTERY CAP[%02x] : %02x\n", - AXP20X_FG_RES, - fuel_gauge_reg_readb(info, AXP20X_FG_RES)); - seq_printf(s, " FG_RDC1[%02x] : %02x\n", - AXP288_FG_RDC1_REG, - fuel_gauge_reg_readb(info, AXP288_FG_RDC1_REG)); - seq_printf(s, " FG_RDC0[%02x] : %02x\n", - AXP288_FG_RDC0_REG, - fuel_gauge_reg_readb(info, AXP288_FG_RDC0_REG)); - seq_printf(s, " FG_OCV[%02x] : %04x\n", - AXP288_FG_OCVH_REG, - fuel_gauge_read_12bit_word(info, AXP288_FG_OCVH_REG)); - seq_printf(s, " FG_DES_CAP[%02x] : %04x\n", - AXP288_FG_DES_CAP1_REG, - fuel_gauge_read_15bit_word(info, AXP288_FG_DES_CAP1_REG)); - seq_printf(s, " FG_CC_MTR[%02x] : %04x\n", - AXP288_FG_CC_MTR1_REG, - fuel_gauge_read_15bit_word(info, AXP288_FG_CC_MTR1_REG)); - seq_printf(s, " FG_OCV_CAP[%02x] : %02x\n", - AXP288_FG_OCV_CAP_REG, - fuel_gauge_reg_readb(info, AXP288_FG_OCV_CAP_REG)); - seq_printf(s, " FG_CC_CAP[%02x] : %02x\n", - AXP288_FG_CC_CAP_REG, - fuel_gauge_reg_readb(info, AXP288_FG_CC_CAP_REG)); - seq_printf(s, " FG_LOW_CAP[%02x] : %02x\n", - AXP288_FG_LOW_CAP_REG, - fuel_gauge_reg_readb(info, AXP288_FG_LOW_CAP_REG)); - seq_printf(s, "TUNING_CTL0[%02x] : %02x\n", - AXP288_FG_TUNE0, - fuel_gauge_reg_readb(info, AXP288_FG_TUNE0)); - seq_printf(s, "TUNING_CTL1[%02x] : %02x\n", - AXP288_FG_TUNE1, - fuel_gauge_reg_readb(info, AXP288_FG_TUNE1)); - seq_printf(s, "TUNING_CTL2[%02x] : %02x\n", - AXP288_FG_TUNE2, - fuel_gauge_reg_readb(info, AXP288_FG_TUNE2)); - seq_printf(s, "TUNING_CTL3[%02x] : %02x\n", - AXP288_FG_TUNE3, - fuel_gauge_reg_readb(info, AXP288_FG_TUNE3)); - seq_printf(s, "TUNING_CTL4[%02x] : %02x\n", - AXP288_FG_TUNE4, - fuel_gauge_reg_readb(info, AXP288_FG_TUNE4)); - seq_printf(s, "TUNING_CTL5[%02x] : %02x\n", - AXP288_FG_TUNE5, - fuel_gauge_reg_readb(info, AXP288_FG_TUNE5)); - - ret = iio_read_channel_raw(info->iio_channel[BAT_TEMP], &raw_val); - if (ret >= 0) - seq_printf(s, "axp288-batttemp : %d\n", raw_val); - ret = iio_read_channel_raw(info->iio_channel[PMIC_TEMP], &raw_val); - if (ret >= 0) - seq_printf(s, "axp288-pmictemp : %d\n", raw_val); - ret = iio_read_channel_raw(info->iio_channel[SYSTEM_TEMP], &raw_val); - if (ret >= 0) - seq_printf(s, "axp288-systtemp : %d\n", raw_val); - ret = iio_read_channel_raw(info->iio_channel[BAT_CHRG_CURR], &raw_val); - if (ret >= 0) - seq_printf(s, "axp288-chrgcurr : %d\n", raw_val); - ret = iio_read_channel_raw(info->iio_channel[BAT_D_CURR], &raw_val); - if (ret >= 0) - seq_printf(s, "axp288-dchrgcur : %d\n", raw_val); - ret = iio_read_channel_raw(info->iio_channel[BAT_VOLT], &raw_val); - if (ret >= 0) - seq_printf(s, "axp288-battvolt : %d\n", raw_val); + int ret; - return 0; -} + if (info->valid && time_before(jiffies, info->last_updated + AXP288_REG_UPDATE_INTERVAL)) + return 0; -DEFINE_SHOW_ATTRIBUTE(fuel_gauge_debug); + dev_dbg(info->dev, "Fuel Gauge updating register values...\n"); -static void fuel_gauge_create_debugfs(struct axp288_fg_info *info) -{ - info->debug_file = debugfs_create_file("fuelgauge", 0666, NULL, - info, &fuel_gauge_debug_fops); -} + ret = iosf_mbi_block_punit_i2c_access(); + if (ret < 0) + return ret; -static void fuel_gauge_remove_debugfs(struct axp288_fg_info *info) -{ - debugfs_remove(info->debug_file); -} -#else -static inline void fuel_gauge_create_debugfs(struct axp288_fg_info *info) -{ -} -static inline void fuel_gauge_remove_debugfs(struct axp288_fg_info *info) -{ + ret = fuel_gauge_reg_readb(info, AXP20X_PWR_INPUT_STATUS); + if (ret < 0) + goto out; + info->pwr_stat = ret; + + ret = fuel_gauge_reg_readb(info, AXP20X_FG_RES); + if (ret < 0) + goto out; + info->fg_res = ret; + + ret = iio_read_channel_raw(info->iio_channel[BAT_VOLT], &info->bat_volt); + if (ret < 0) + goto out; + + if (info->pwr_stat & PS_STAT_BAT_CHRG_DIR) { + info->d_curr = 0; + ret = iio_read_channel_raw(info->iio_channel[BAT_CHRG_CURR], &info->c_curr); + if (ret < 0) + goto out; + } else { + info->c_curr = 0; + ret = iio_read_channel_raw(info->iio_channel[BAT_D_CURR], &info->d_curr); + if (ret < 0) + goto out; + } + + ret = fuel_gauge_read_12bit_word(info, AXP288_FG_OCVH_REG); + if (ret < 0) + goto out; + info->ocv = ret; + + ret = fuel_gauge_read_15bit_word(info, AXP288_FG_CC_MTR1_REG); + if (ret < 0) + goto out; + info->fg_cc_mtr1 = ret; + + ret = fuel_gauge_read_15bit_word(info, AXP288_FG_DES_CAP1_REG); + if (ret < 0) + goto out; + info->fg_des_cap1 = ret; + + info->last_updated = jiffies; + info->valid = 1; + ret = 0; +out: + iosf_mbi_unblock_punit_i2c_access(); + return ret; } -#endif static void fuel_gauge_get_status(struct axp288_fg_info *info) { - int pwr_stat, fg_res, curr, ret; - - pwr_stat = fuel_gauge_reg_readb(info, AXP20X_PWR_INPUT_STATUS); - if (pwr_stat < 0) { - dev_err(&info->pdev->dev, - "PWR STAT read failed:%d\n", pwr_stat); - return; - } + int pwr_stat = info->pwr_stat; + int fg_res = info->fg_res; + int curr = info->d_curr; /* Report full if Vbus is valid and the reported capacity is 100% */ if (!(pwr_stat & PS_STAT_VBUS_VALID)) goto not_full; - fg_res = fuel_gauge_reg_readb(info, AXP20X_FG_RES); - if (fg_res < 0) { - dev_err(&info->pdev->dev, "FG RES read failed: %d\n", fg_res); - return; - } if (!(fg_res & FG_REP_CAP_VALID)) goto not_full; @@ -354,11 +296,6 @@ static void fuel_gauge_get_status(struct axp288_fg_info *info) if (fg_res < 90 || (pwr_stat & PS_STAT_BAT_CHRG_DIR)) goto not_full; - ret = iio_read_channel_raw(info->iio_channel[BAT_D_CURR], &curr); - if (ret < 0) { - dev_err(&info->pdev->dev, "FG get current failed: %d\n", ret); - return; - } if (curr == 0) { info->status = POWER_SUPPLY_STATUS_FULL; return; @@ -371,61 +308,16 @@ not_full: info->status = POWER_SUPPLY_STATUS_DISCHARGING; } -static int fuel_gauge_get_vbatt(struct axp288_fg_info *info, int *vbatt) -{ - int ret = 0, raw_val; - - ret = iio_read_channel_raw(info->iio_channel[BAT_VOLT], &raw_val); - if (ret < 0) - goto vbatt_read_fail; - - *vbatt = VOLTAGE_FROM_ADC(raw_val); -vbatt_read_fail: - return ret; -} - -static int fuel_gauge_get_current(struct axp288_fg_info *info, int *cur) -{ - int ret, discharge; - - /* First check discharge current, so that we do only 1 read on bat. */ - ret = iio_read_channel_raw(info->iio_channel[BAT_D_CURR], &discharge); - if (ret < 0) - return ret; - - if (discharge > 0) { - *cur = -1 * discharge; - return 0; - } - - return iio_read_channel_raw(info->iio_channel[BAT_CHRG_CURR], cur); -} - -static int fuel_gauge_get_vocv(struct axp288_fg_info *info, int *vocv) -{ - int ret; - - ret = fuel_gauge_read_12bit_word(info, AXP288_FG_OCVH_REG); - if (ret >= 0) - *vocv = VOLTAGE_FROM_ADC(ret); - - return ret; -} - static int fuel_gauge_battery_health(struct axp288_fg_info *info) { - int ret, vocv, health = POWER_SUPPLY_HEALTH_UNKNOWN; - - ret = fuel_gauge_get_vocv(info, &vocv); - if (ret < 0) - goto health_read_fail; + int vocv = VOLTAGE_FROM_ADC(info->ocv); + int health = POWER_SUPPLY_HEALTH_UNKNOWN; if (vocv > info->max_volt) health = POWER_SUPPLY_HEALTH_OVERVOLTAGE; else health = POWER_SUPPLY_HEALTH_GOOD; -health_read_fail: return health; } @@ -434,9 +326,14 @@ static int fuel_gauge_get_property(struct power_supply *ps, union power_supply_propval *val) { struct axp288_fg_info *info = power_supply_get_drvdata(ps); - int ret = 0, value; + int ret, value; mutex_lock(&info->lock); + + ret = fuel_gauge_update_registers(info); + if (ret < 0) + goto out; + switch (prop) { case POWER_SUPPLY_PROP_STATUS: fuel_gauge_get_status(info); @@ -446,78 +343,52 @@ static int fuel_gauge_get_property(struct power_supply *ps, val->intval = fuel_gauge_battery_health(info); break; case POWER_SUPPLY_PROP_VOLTAGE_NOW: - ret = fuel_gauge_get_vbatt(info, &value); - if (ret < 0) - goto fuel_gauge_read_err; + value = VOLTAGE_FROM_ADC(info->bat_volt); val->intval = PROP_VOLT(value); break; case POWER_SUPPLY_PROP_VOLTAGE_OCV: - ret = fuel_gauge_get_vocv(info, &value); - if (ret < 0) - goto fuel_gauge_read_err; + value = VOLTAGE_FROM_ADC(info->ocv); val->intval = PROP_VOLT(value); break; case POWER_SUPPLY_PROP_CURRENT_NOW: - ret = fuel_gauge_get_current(info, &value); - if (ret < 0) - goto fuel_gauge_read_err; + if (info->d_curr > 0) + value = -1 * info->d_curr; + else + value = info->c_curr; + val->intval = PROP_CURR(value); break; case POWER_SUPPLY_PROP_PRESENT: - ret = fuel_gauge_reg_readb(info, AXP20X_PWR_OP_MODE); - if (ret < 0) - goto fuel_gauge_read_err; - - if (ret & CHRG_STAT_BAT_PRESENT) + if (info->pwr_op & CHRG_STAT_BAT_PRESENT) val->intval = 1; else val->intval = 0; break; case POWER_SUPPLY_PROP_CAPACITY: - ret = fuel_gauge_reg_readb(info, AXP20X_FG_RES); - if (ret < 0) - goto fuel_gauge_read_err; - - if (!(ret & FG_REP_CAP_VALID)) - dev_err(&info->pdev->dev, - "capacity measurement not valid\n"); - val->intval = (ret & FG_REP_CAP_VAL_MASK); + if (!(info->fg_res & FG_REP_CAP_VALID)) + dev_err(info->dev, "capacity measurement not valid\n"); + val->intval = (info->fg_res & FG_REP_CAP_VAL_MASK); break; case POWER_SUPPLY_PROP_CAPACITY_ALERT_MIN: - ret = fuel_gauge_reg_readb(info, AXP288_FG_LOW_CAP_REG); - if (ret < 0) - goto fuel_gauge_read_err; - val->intval = (ret & 0x0f); + val->intval = (info->low_cap & 0x0f); break; case POWER_SUPPLY_PROP_TECHNOLOGY: val->intval = POWER_SUPPLY_TECHNOLOGY_LION; break; case POWER_SUPPLY_PROP_CHARGE_NOW: - ret = fuel_gauge_read_15bit_word(info, AXP288_FG_CC_MTR1_REG); - if (ret < 0) - goto fuel_gauge_read_err; - - val->intval = ret * FG_DES_CAP_RES_LSB; + val->intval = info->fg_cc_mtr1 * FG_DES_CAP_RES_LSB; break; case POWER_SUPPLY_PROP_CHARGE_FULL: - ret = fuel_gauge_read_15bit_word(info, AXP288_FG_DES_CAP1_REG); - if (ret < 0) - goto fuel_gauge_read_err; - - val->intval = ret * FG_DES_CAP_RES_LSB; + val->intval = info->fg_des_cap1 * FG_DES_CAP_RES_LSB; break; case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: val->intval = PROP_VOLT(info->max_volt); break; default: - mutex_unlock(&info->lock); - return -EINVAL; + ret = -EINVAL; } - mutex_unlock(&info->lock); - return 0; - -fuel_gauge_read_err: +out: mutex_unlock(&info->lock); return ret; } @@ -527,7 +398,7 @@ static int fuel_gauge_set_property(struct power_supply *ps, const union power_supply_propval *val) { struct axp288_fg_info *info = power_supply_get_drvdata(ps); - int ret = 0; + int new_low_cap, ret = 0; mutex_lock(&info->lock); switch (prop) { @@ -536,12 +407,12 @@ static int fuel_gauge_set_property(struct power_supply *ps, ret = -EINVAL; break; } - ret = fuel_gauge_reg_readb(info, AXP288_FG_LOW_CAP_REG); - if (ret < 0) - break; - ret &= 0xf0; - ret |= (val->intval & 0xf); - ret = fuel_gauge_reg_writeb(info, AXP288_FG_LOW_CAP_REG, ret); + new_low_cap = info->low_cap; + new_low_cap &= 0xf0; + new_low_cap |= (val->intval & 0xf); + ret = fuel_gauge_reg_writeb(info, AXP288_FG_LOW_CAP_REG, new_low_cap); + if (ret == 0) + info->low_cap = new_low_cap; break; default: ret = -EINVAL; @@ -579,37 +450,35 @@ static irqreturn_t fuel_gauge_thread_handler(int irq, void *dev) } if (i >= AXP288_FG_INTR_NUM) { - dev_warn(&info->pdev->dev, "spurious interrupt!!\n"); + dev_warn(info->dev, "spurious interrupt!!\n"); return IRQ_NONE; } switch (i) { case QWBTU_IRQ: - dev_info(&info->pdev->dev, - "Quit Battery under temperature in work mode IRQ (QWBTU)\n"); + dev_info(info->dev, "Quit Battery under temperature in work mode IRQ (QWBTU)\n"); break; case WBTU_IRQ: - dev_info(&info->pdev->dev, - "Battery under temperature in work mode IRQ (WBTU)\n"); + dev_info(info->dev, "Battery under temperature in work mode IRQ (WBTU)\n"); break; case QWBTO_IRQ: - dev_info(&info->pdev->dev, - "Quit Battery over temperature in work mode IRQ (QWBTO)\n"); + dev_info(info->dev, "Quit Battery over temperature in work mode IRQ (QWBTO)\n"); break; case WBTO_IRQ: - dev_info(&info->pdev->dev, - "Battery over temperature in work mode IRQ (WBTO)\n"); + dev_info(info->dev, "Battery over temperature in work mode IRQ (WBTO)\n"); break; case WL2_IRQ: - dev_info(&info->pdev->dev, "Low Batt Warning(2) INTR\n"); + dev_info(info->dev, "Low Batt Warning(2) INTR\n"); break; case WL1_IRQ: - dev_info(&info->pdev->dev, "Low Batt Warning(1) INTR\n"); + dev_info(info->dev, "Low Batt Warning(1) INTR\n"); break; default: - dev_warn(&info->pdev->dev, "Spurious Interrupt!!!\n"); + dev_warn(info->dev, "Spurious Interrupt!!!\n"); } + info->valid = 0; /* Force updating of the cached registers */ + power_supply_changed(info->bat); return IRQ_HANDLED; } @@ -618,6 +487,7 @@ static void fuel_gauge_external_power_changed(struct power_supply *psy) { struct axp288_fg_info *info = power_supply_get_drvdata(psy); + info->valid = 0; /* Force updating of the cached registers */ power_supply_changed(info->bat); } @@ -632,16 +502,15 @@ static const struct power_supply_desc fuel_gauge_desc = { .external_power_changed = fuel_gauge_external_power_changed, }; -static void fuel_gauge_init_irq(struct axp288_fg_info *info) +static void fuel_gauge_init_irq(struct axp288_fg_info *info, struct platform_device *pdev) { int ret, i, pirq; for (i = 0; i < AXP288_FG_INTR_NUM; i++) { - pirq = platform_get_irq(info->pdev, i); + pirq = platform_get_irq(pdev, i); info->irq[i] = regmap_irq_get_virq(info->regmap_irqc, pirq); if (info->irq[i] < 0) { - dev_warn(&info->pdev->dev, - "regmap_irq get virq failed for IRQ %d: %d\n", + dev_warn(info->dev, "regmap_irq get virq failed for IRQ %d: %d\n", pirq, info->irq[i]); info->irq[i] = -1; goto intr_failed; @@ -650,14 +519,10 @@ static void fuel_gauge_init_irq(struct axp288_fg_info *info) NULL, fuel_gauge_thread_handler, IRQF_ONESHOT, DEV_NAME, info); if (ret) { - dev_warn(&info->pdev->dev, - "request irq failed for IRQ %d: %d\n", + dev_warn(info->dev, "request irq failed for IRQ %d: %d\n", pirq, info->irq[i]); info->irq[i] = -1; goto intr_failed; - } else { - dev_info(&info->pdev->dev, "HW IRQ %d -> VIRQ %d\n", - pirq, info->irq[i]); } } return; @@ -753,9 +618,6 @@ static int axp288_fuel_gauge_probe(struct platform_device *pdev) struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent); struct power_supply_config psy_cfg = {}; static const char * const iio_chan_name[] = { - [BAT_TEMP] = "axp288-batt-temp", - [PMIC_TEMP] = "axp288-pmic-temp", - [SYSTEM_TEMP] = "axp288-system-temp", [BAT_CHRG_CURR] = "axp288-chrg-curr", [BAT_D_CURR] = "axp288-chrg-d-curr", [BAT_VOLT] = "axp288-batt-volt", @@ -765,24 +627,15 @@ static int axp288_fuel_gauge_probe(struct platform_device *pdev) if (dmi_check_system(axp288_no_battery_list)) return -ENODEV; - /* - * On some devices the fuelgauge and charger parts of the axp288 are - * not used, check that the fuelgauge is enabled (CC_CTRL != 0). - */ - ret = regmap_read(axp20x->regmap, AXP20X_CC_CTRL, &val); - if (ret < 0) - return ret; - if (val == 0) - return -ENODEV; - info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); if (!info) return -ENOMEM; - info->pdev = pdev; + info->dev = &pdev->dev; info->regmap = axp20x->regmap; info->regmap_irqc = axp20x->regmap_irqc; info->status = POWER_SUPPLY_STATUS_UNKNOWN; + info->valid = 0; platform_set_drvdata(pdev, info); @@ -808,19 +661,35 @@ static int axp288_fuel_gauge_probe(struct platform_device *pdev) } } - ret = fuel_gauge_reg_readb(info, AXP288_FG_DES_CAP1_REG); + ret = iosf_mbi_block_punit_i2c_access(); if (ret < 0) goto out_free_iio_chan; + /* + * On some devices the fuelgauge and charger parts of the axp288 are + * not used, check that the fuelgauge is enabled (CC_CTRL != 0). + */ + ret = regmap_read(axp20x->regmap, AXP20X_CC_CTRL, &val); + if (ret < 0) + goto unblock_punit_i2c_access; + if (val == 0) { + ret = -ENODEV; + goto unblock_punit_i2c_access; + } + + ret = fuel_gauge_reg_readb(info, AXP288_FG_DES_CAP1_REG); + if (ret < 0) + goto unblock_punit_i2c_access; + if (!(ret & FG_DES_CAP1_VALID)) { dev_err(&pdev->dev, "axp288 not configured by firmware\n"); ret = -ENODEV; - goto out_free_iio_chan; + goto unblock_punit_i2c_access; } ret = fuel_gauge_reg_readb(info, AXP20X_CHRG_CTRL1); if (ret < 0) - goto out_free_iio_chan; + goto unblock_punit_i2c_access; switch ((ret & CHRG_CCCV_CV_MASK) >> CHRG_CCCV_CV_BIT_POS) { case CHRG_CCCV_CV_4100MV: info->max_volt = 4100; @@ -836,6 +705,22 @@ static int axp288_fuel_gauge_probe(struct platform_device *pdev) break; } + ret = fuel_gauge_reg_readb(info, AXP20X_PWR_OP_MODE); + if (ret < 0) + goto unblock_punit_i2c_access; + info->pwr_op = ret; + + ret = fuel_gauge_reg_readb(info, AXP288_FG_LOW_CAP_REG); + if (ret < 0) + goto unblock_punit_i2c_access; + info->low_cap = ret; + +unblock_punit_i2c_access: + iosf_mbi_unblock_punit_i2c_access(); + /* In case we arrive here by goto because of a register access error */ + if (ret < 0) + goto out_free_iio_chan; + psy_cfg.drv_data = info; info->bat = power_supply_register(&pdev->dev, &fuel_gauge_desc, &psy_cfg); if (IS_ERR(info->bat)) { @@ -844,8 +729,7 @@ static int axp288_fuel_gauge_probe(struct platform_device *pdev) goto out_free_iio_chan; } - fuel_gauge_create_debugfs(info); - fuel_gauge_init_irq(info); + fuel_gauge_init_irq(info, pdev); return 0; @@ -869,7 +753,6 @@ static int axp288_fuel_gauge_remove(struct platform_device *pdev) int i; power_supply_unregister(info->bat); - fuel_gauge_remove_debugfs(info); for (i = 0; i < AXP288_FG_INTR_NUM; i++) if (info->irq[i] >= 0) diff --git a/drivers/power/supply/bq24735-charger.c b/drivers/power/supply/bq24735-charger.c index b5d619db79f6..3ce36d09c017 100644 --- a/drivers/power/supply/bq24735-charger.c +++ b/drivers/power/supply/bq24735-charger.c @@ -31,9 +31,8 @@ #include <linux/power/bq24735-charger.h> -#define BQ24735_CHG_OPT 0x12 -#define BQ24735_CHG_OPT_CHARGE_DISABLE (1 << 0) -#define BQ24735_CHG_OPT_AC_PRESENT (1 << 4) +/* BQ24735 available commands and their respective masks */ +#define BQ24735_CHARGE_OPT 0x12 #define BQ24735_CHARGE_CURRENT 0x14 #define BQ24735_CHARGE_CURRENT_MASK 0x1fc0 #define BQ24735_CHARGE_VOLTAGE 0x15 @@ -43,6 +42,10 @@ #define BQ24735_MANUFACTURER_ID 0xfe #define BQ24735_DEVICE_ID 0xff +/* ChargeOptions bits of interest */ +#define BQ24735_CHARGE_OPT_CHG_DISABLE (1 << 0) +#define BQ24735_CHARGE_OPT_AC_PRESENT (1 << 4) + struct bq24735 { struct power_supply *charger; struct power_supply_desc charger_desc; @@ -167,8 +170,8 @@ static inline int bq24735_enable_charging(struct bq24735 *charger) if (ret) return ret; - return bq24735_update_word(charger->client, BQ24735_CHG_OPT, - BQ24735_CHG_OPT_CHARGE_DISABLE, 0); + return bq24735_update_word(charger->client, BQ24735_CHARGE_OPT, + BQ24735_CHARGE_OPT_CHG_DISABLE, 0); } static inline int bq24735_disable_charging(struct bq24735 *charger) @@ -176,9 +179,9 @@ static inline int bq24735_disable_charging(struct bq24735 *charger) if (charger->pdata->ext_control) return 0; - return bq24735_update_word(charger->client, BQ24735_CHG_OPT, - BQ24735_CHG_OPT_CHARGE_DISABLE, - BQ24735_CHG_OPT_CHARGE_DISABLE); + return bq24735_update_word(charger->client, BQ24735_CHARGE_OPT, + BQ24735_CHARGE_OPT_CHG_DISABLE, + BQ24735_CHARGE_OPT_CHG_DISABLE); } static bool bq24735_charger_is_present(struct bq24735 *charger) @@ -188,14 +191,14 @@ static bool bq24735_charger_is_present(struct bq24735 *charger) } else { int ac = 0; - ac = bq24735_read_word(charger->client, BQ24735_CHG_OPT); + ac = bq24735_read_word(charger->client, BQ24735_CHARGE_OPT); if (ac < 0) { dev_dbg(&charger->client->dev, "Failed to read charger options : %d\n", ac); return false; } - return (ac & BQ24735_CHG_OPT_AC_PRESENT) ? true : false; + return (ac & BQ24735_CHARGE_OPT_AC_PRESENT) ? true : false; } return false; @@ -208,11 +211,11 @@ static int bq24735_charger_is_charging(struct bq24735 *charger) if (!bq24735_charger_is_present(charger)) return 0; - ret = bq24735_read_word(charger->client, BQ24735_CHG_OPT); + ret = bq24735_read_word(charger->client, BQ24735_CHARGE_OPT); if (ret < 0) return ret; - return !(ret & BQ24735_CHG_OPT_CHARGE_DISABLE); + return !(ret & BQ24735_CHARGE_OPT_CHG_DISABLE); } static void bq24735_update(struct bq24735 *charger) diff --git a/drivers/power/supply/cros_peripheral_charger.c b/drivers/power/supply/cros_peripheral_charger.c new file mode 100644 index 000000000000..305f10dfc06d --- /dev/null +++ b/drivers/power/supply/cros_peripheral_charger.c @@ -0,0 +1,386 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Power supply driver for ChromeOS EC based Peripheral Device Charger. + * + * Copyright 2020 Google LLC. + */ + +#include <linux/module.h> +#include <linux/notifier.h> +#include <linux/platform_data/cros_ec_commands.h> +#include <linux/platform_data/cros_ec_proto.h> +#include <linux/platform_device.h> +#include <linux/power_supply.h> +#include <linux/slab.h> +#include <linux/stringify.h> +#include <linux/types.h> + +#define DRV_NAME "cros-ec-pchg" +#define PCHG_DIR_PREFIX "peripheral" +#define PCHG_DIR_NAME PCHG_DIR_PREFIX "%d" +#define PCHG_DIR_NAME_LENGTH \ + sizeof(PCHG_DIR_PREFIX __stringify(EC_PCHG_MAX_PORTS)) +#define PCHG_CACHE_UPDATE_DELAY msecs_to_jiffies(500) + +struct port_data { + int port_number; + char name[PCHG_DIR_NAME_LENGTH]; + struct power_supply *psy; + struct power_supply_desc psy_desc; + int psy_status; + int battery_percentage; + int charge_type; + struct charger_data *charger; + unsigned long last_update; +}; + +struct charger_data { + struct device *dev; + struct cros_ec_dev *ec_dev; + struct cros_ec_device *ec_device; + int num_registered_psy; + struct port_data *ports[EC_PCHG_MAX_PORTS]; + struct notifier_block notifier; +}; + +static enum power_supply_property cros_pchg_props[] = { + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_CHARGE_TYPE, + POWER_SUPPLY_PROP_CAPACITY, + POWER_SUPPLY_PROP_SCOPE, +}; + +static int cros_pchg_ec_command(const struct charger_data *charger, + unsigned int version, + unsigned int command, + const void *outdata, + unsigned int outsize, + void *indata, + unsigned int insize) +{ + struct cros_ec_dev *ec_dev = charger->ec_dev; + struct cros_ec_command *msg; + int ret; + + msg = kzalloc(sizeof(*msg) + max(outsize, insize), GFP_KERNEL); + if (!msg) + return -ENOMEM; + + msg->version = version; + msg->command = ec_dev->cmd_offset + command; + msg->outsize = outsize; + msg->insize = insize; + + if (outsize) + memcpy(msg->data, outdata, outsize); + + ret = cros_ec_cmd_xfer_status(charger->ec_device, msg); + if (ret >= 0 && insize) + memcpy(indata, msg->data, insize); + + kfree(msg); + return ret; +} + +static const unsigned int pchg_cmd_version = 1; + +static bool cros_pchg_cmd_ver_check(const struct charger_data *charger) +{ + struct ec_params_get_cmd_versions_v1 req; + struct ec_response_get_cmd_versions rsp; + int ret; + + req.cmd = EC_CMD_PCHG; + ret = cros_pchg_ec_command(charger, 1, EC_CMD_GET_CMD_VERSIONS, + &req, sizeof(req), &rsp, sizeof(rsp)); + if (ret < 0) { + dev_warn(charger->dev, + "Unable to get versions of EC_CMD_PCHG (err:%d)\n", + ret); + return false; + } + + return !!(rsp.version_mask & BIT(pchg_cmd_version)); +} + +static int cros_pchg_port_count(const struct charger_data *charger) +{ + struct ec_response_pchg_count rsp; + int ret; + + ret = cros_pchg_ec_command(charger, 0, EC_CMD_PCHG_COUNT, + NULL, 0, &rsp, sizeof(rsp)); + if (ret < 0) { + dev_warn(charger->dev, + "Unable to get number or ports (err:%d)\n", ret); + return ret; + } + + return rsp.port_count; +} + +static int cros_pchg_get_status(struct port_data *port) +{ + struct charger_data *charger = port->charger; + struct ec_params_pchg req; + struct ec_response_pchg rsp; + struct device *dev = charger->dev; + int old_status = port->psy_status; + int old_percentage = port->battery_percentage; + int ret; + + req.port = port->port_number; + ret = cros_pchg_ec_command(charger, pchg_cmd_version, EC_CMD_PCHG, + &req, sizeof(req), &rsp, sizeof(rsp)); + if (ret < 0) { + dev_err(dev, "Unable to get port.%d status (err:%d)\n", + port->port_number, ret); + return ret; + } + + switch (rsp.state) { + case PCHG_STATE_RESET: + case PCHG_STATE_INITIALIZED: + case PCHG_STATE_ENABLED: + default: + port->psy_status = POWER_SUPPLY_STATUS_UNKNOWN; + port->charge_type = POWER_SUPPLY_CHARGE_TYPE_NONE; + break; + case PCHG_STATE_DETECTED: + port->psy_status = POWER_SUPPLY_STATUS_CHARGING; + port->charge_type = POWER_SUPPLY_CHARGE_TYPE_TRICKLE; + break; + case PCHG_STATE_CHARGING: + port->psy_status = POWER_SUPPLY_STATUS_CHARGING; + port->charge_type = POWER_SUPPLY_CHARGE_TYPE_STANDARD; + break; + case PCHG_STATE_FULL: + port->psy_status = POWER_SUPPLY_STATUS_FULL; + port->charge_type = POWER_SUPPLY_CHARGE_TYPE_NONE; + break; + } + + port->battery_percentage = rsp.battery_percentage; + + if (port->psy_status != old_status || + port->battery_percentage != old_percentage) + power_supply_changed(port->psy); + + dev_dbg(dev, + "Port %d: state=%d battery=%d%%\n", + port->port_number, rsp.state, rsp.battery_percentage); + + return 0; +} + +static int cros_pchg_get_port_status(struct port_data *port, bool ratelimit) +{ + int ret; + + if (ratelimit && + time_is_after_jiffies(port->last_update + PCHG_CACHE_UPDATE_DELAY)) + return 0; + + ret = cros_pchg_get_status(port); + if (ret < 0) + return ret; + + port->last_update = jiffies; + + return ret; +} + +static int cros_pchg_get_prop(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct port_data *port = power_supply_get_drvdata(psy); + + switch (psp) { + case POWER_SUPPLY_PROP_STATUS: + case POWER_SUPPLY_PROP_CAPACITY: + case POWER_SUPPLY_PROP_CHARGE_TYPE: + cros_pchg_get_port_status(port, true); + break; + default: + break; + } + + switch (psp) { + case POWER_SUPPLY_PROP_STATUS: + val->intval = port->psy_status; + break; + case POWER_SUPPLY_PROP_CAPACITY: + val->intval = port->battery_percentage; + break; + case POWER_SUPPLY_PROP_CHARGE_TYPE: + val->intval = port->charge_type; + break; + case POWER_SUPPLY_PROP_SCOPE: + val->intval = POWER_SUPPLY_SCOPE_DEVICE; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int cros_pchg_event(const struct charger_data *charger, + unsigned long host_event) +{ + int i; + + for (i = 0; i < charger->num_registered_psy; i++) + cros_pchg_get_port_status(charger->ports[i], false); + + return NOTIFY_OK; +} + +static u32 cros_get_device_event(const struct charger_data *charger) +{ + struct ec_params_device_event req; + struct ec_response_device_event rsp; + struct device *dev = charger->dev; + int ret; + + req.param = EC_DEVICE_EVENT_PARAM_GET_CURRENT_EVENTS; + ret = cros_pchg_ec_command(charger, 0, EC_CMD_DEVICE_EVENT, + &req, sizeof(req), &rsp, sizeof(rsp)); + if (ret < 0) { + dev_warn(dev, "Unable to get device events (err:%d)\n", ret); + return 0; + } + + return rsp.event_mask; +} + +static int cros_ec_notify(struct notifier_block *nb, + unsigned long queued_during_suspend, + void *data) +{ + struct cros_ec_device *ec_dev = (struct cros_ec_device *)data; + u32 host_event = cros_ec_get_host_event(ec_dev); + struct charger_data *charger = + container_of(nb, struct charger_data, notifier); + u32 device_event_mask; + + if (!host_event) + return NOTIFY_DONE; + + if (!(host_event & EC_HOST_EVENT_MASK(EC_HOST_EVENT_DEVICE))) + return NOTIFY_DONE; + + /* + * todo: Retrieve device event mask in common place + * (e.g. cros_ec_proto.c). + */ + device_event_mask = cros_get_device_event(charger); + if (!(device_event_mask & EC_DEVICE_EVENT_MASK(EC_DEVICE_EVENT_WLC))) + return NOTIFY_DONE; + + return cros_pchg_event(charger, host_event); +} + +static int cros_pchg_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct cros_ec_dev *ec_dev = dev_get_drvdata(dev->parent); + struct cros_ec_device *ec_device = ec_dev->ec_dev; + struct power_supply_desc *psy_desc; + struct charger_data *charger; + struct power_supply *psy; + struct port_data *port; + struct notifier_block *nb; + int num_ports; + int ret; + int i; + + charger = devm_kzalloc(dev, sizeof(*charger), GFP_KERNEL); + if (!charger) + return -ENOMEM; + + charger->dev = dev; + charger->ec_dev = ec_dev; + charger->ec_device = ec_device; + + ret = cros_pchg_port_count(charger); + if (ret <= 0) { + /* + * This feature is enabled by the EC and the kernel driver is + * included by default for CrOS devices. Don't need to be loud + * since this error can be normal. + */ + dev_info(dev, "No peripheral charge ports (err:%d)\n", ret); + return -ENODEV; + } + + if (!cros_pchg_cmd_ver_check(charger)) { + dev_err(dev, "EC_CMD_PCHG version %d isn't available.\n", + pchg_cmd_version); + return -EOPNOTSUPP; + } + + num_ports = ret; + if (num_ports > EC_PCHG_MAX_PORTS) { + dev_err(dev, "Too many peripheral charge ports (%d)\n", + num_ports); + return -ENOBUFS; + } + + dev_info(dev, "%d peripheral charge ports found\n", num_ports); + + for (i = 0; i < num_ports; i++) { + struct power_supply_config psy_cfg = {}; + + port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL); + if (!port) + return -ENOMEM; + + port->charger = charger; + port->port_number = i; + snprintf(port->name, sizeof(port->name), PCHG_DIR_NAME, i); + + psy_desc = &port->psy_desc; + psy_desc->name = port->name; + psy_desc->type = POWER_SUPPLY_TYPE_BATTERY; + psy_desc->get_property = cros_pchg_get_prop; + psy_desc->external_power_changed = NULL; + psy_desc->properties = cros_pchg_props; + psy_desc->num_properties = ARRAY_SIZE(cros_pchg_props); + psy_cfg.drv_data = port; + + psy = devm_power_supply_register(dev, psy_desc, &psy_cfg); + if (IS_ERR(psy)) + return dev_err_probe(dev, PTR_ERR(psy), + "Failed to register power supply\n"); + port->psy = psy; + + charger->ports[charger->num_registered_psy++] = port; + } + + if (!charger->num_registered_psy) + return -ENODEV; + + nb = &charger->notifier; + nb->notifier_call = cros_ec_notify; + ret = blocking_notifier_chain_register(&ec_dev->ec_dev->event_notifier, + nb); + if (ret < 0) + dev_err(dev, "Failed to register notifier (err:%d)\n", ret); + + return 0; +} + +static struct platform_driver cros_pchg_driver = { + .driver = { + .name = DRV_NAME, + }, + .probe = cros_pchg_probe +}; + +module_platform_driver(cros_pchg_driver); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("ChromeOS EC peripheral device charger"); +MODULE_ALIAS("platform:" DRV_NAME); diff --git a/drivers/power/supply/cw2015_battery.c b/drivers/power/supply/cw2015_battery.c index d110597746b0..091868e9e9e8 100644 --- a/drivers/power/supply/cw2015_battery.c +++ b/drivers/power/supply/cw2015_battery.c @@ -679,7 +679,9 @@ static int cw_bat_probe(struct i2c_client *client) &cw2015_bat_desc, &psy_cfg); if (IS_ERR(cw_bat->rk_bat)) { - dev_err(cw_bat->dev, "Failed to register power supply\n"); + /* try again if this happens */ + dev_err_probe(&client->dev, PTR_ERR(cw_bat->rk_bat), + "Failed to register power supply\n"); return PTR_ERR(cw_bat->rk_bat); } diff --git a/drivers/power/supply/max17042_battery.c b/drivers/power/supply/max17042_battery.c index ce2041b30a06..8dffae76b6a3 100644 --- a/drivers/power/supply/max17042_battery.c +++ b/drivers/power/supply/max17042_battery.c @@ -36,8 +36,6 @@ /* Interrupt mask bits */ #define CONFIG_ALRT_BIT_ENBL (1 << 2) -#define STATUS_INTR_SOCMIN_BIT (1 << 10) -#define STATUS_INTR_SOCMAX_BIT (1 << 14) #define VFSOC0_LOCK 0x0000 #define VFSOC0_UNLOCK 0x0080 @@ -285,8 +283,6 @@ static int max17042_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: if (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17042) ret = regmap_read(map, MAX17042_V_empty, &data); - else if (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17055) - ret = regmap_read(map, MAX17055_V_empty, &data); else ret = regmap_read(map, MAX17047_V_empty, &data); if (ret < 0) @@ -748,7 +744,7 @@ static inline void max17042_override_por_values(struct max17042_chip *chip) struct max17042_config_data *config = chip->pdata->config_data; max17042_override_por(map, MAX17042_TGAIN, config->tgain); - max17042_override_por(map, MAx17042_TOFF, config->toff); + max17042_override_por(map, MAX17042_TOFF, config->toff); max17042_override_por(map, MAX17042_CGAIN, config->cgain); max17042_override_por(map, MAX17042_COFF, config->coff); @@ -767,36 +763,36 @@ static inline void max17042_override_por_values(struct max17042_chip *chip) max17042_override_por(map, MAX17042_FilterCFG, config->filter_cfg); max17042_override_por(map, MAX17042_RelaxCFG, config->relax_cfg); max17042_override_por(map, MAX17042_MiscCFG, config->misc_cfg); - max17042_override_por(map, MAX17042_MaskSOC, config->masksoc); max17042_override_por(map, MAX17042_FullCAP, config->fullcap); max17042_override_por(map, MAX17042_FullCAPNom, config->fullcapnom); - if (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17042) - max17042_override_por(map, MAX17042_SOC_empty, - config->socempty); - max17042_override_por(map, MAX17042_LAvg_empty, config->lavg_empty); max17042_override_por(map, MAX17042_dQacc, config->dqacc); max17042_override_por(map, MAX17042_dPacc, config->dpacc); - if (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17042) - max17042_override_por(map, MAX17042_V_empty, config->vempty); - if (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17055) - max17042_override_por(map, MAX17055_V_empty, config->vempty); - else - max17042_override_por(map, MAX17047_V_empty, config->vempty); - max17042_override_por(map, MAX17042_TempNom, config->temp_nom); - max17042_override_por(map, MAX17042_TempLim, config->temp_lim); - max17042_override_por(map, MAX17042_FCTC, config->fctc); max17042_override_por(map, MAX17042_RCOMP0, config->rcomp0); max17042_override_por(map, MAX17042_TempCo, config->tcompc0); - if (chip->chip_type && - ((chip->chip_type == MAXIM_DEVICE_TYPE_MAX17042) || + + if (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17042) { + max17042_override_por(map, MAX17042_MaskSOC, config->masksoc); + max17042_override_por(map, MAX17042_SOC_empty, config->socempty); + max17042_override_por(map, MAX17042_V_empty, config->vempty); + max17042_override_por(map, MAX17042_EmptyTempCo, config->empty_tempco); + max17042_override_por(map, MAX17042_K_empty0, config->kempty0); + } + + if ((chip->chip_type == MAXIM_DEVICE_TYPE_MAX17042) || (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17047) || - (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17050))) { - max17042_override_por(map, MAX17042_EmptyTempCo, - config->empty_tempco); - max17042_override_por(map, MAX17042_K_empty0, - config->kempty0); + (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17050)) { + max17042_override_por(map, MAX17042_LAvg_empty, config->lavg_empty); + max17042_override_por(map, MAX17042_TempNom, config->temp_nom); + max17042_override_por(map, MAX17042_TempLim, config->temp_lim); + max17042_override_por(map, MAX17042_FCTC, config->fctc); + } + + if ((chip->chip_type == MAXIM_DEVICE_TYPE_MAX17047) || + (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17050) || + (chip->chip_type == MAXIM_DEVICE_TYPE_MAX17055)) { + max17042_override_por(map, MAX17047_V_empty, config->vempty); } } @@ -869,11 +865,14 @@ static irqreturn_t max17042_thread_handler(int id, void *dev) { struct max17042_chip *chip = dev; u32 val; + int ret; - regmap_read(chip->regmap, MAX17042_STATUS, &val); - if ((val & STATUS_INTR_SOCMIN_BIT) || - (val & STATUS_INTR_SOCMAX_BIT)) { - dev_info(&chip->client->dev, "SOC threshold INTR\n"); + ret = regmap_read(chip->regmap, MAX17042_STATUS, &val); + if (ret) + return IRQ_HANDLED; + + if ((val & STATUS_SMN_BIT) || (val & STATUS_SMX_BIT)) { + dev_dbg(&chip->client->dev, "SOC threshold INTR\n"); max17042_set_soc_threshold(chip, 1); } @@ -1196,6 +1195,7 @@ static const struct of_device_id max17042_dt_match[] = { { .compatible = "maxim,max17047" }, { .compatible = "maxim,max17050" }, { .compatible = "maxim,max17055" }, + { .compatible = "maxim,max77849-battery" }, { }, }; MODULE_DEVICE_TABLE(of, max17042_dt_match); @@ -1206,6 +1206,7 @@ static const struct i2c_device_id max17042_id[] = { { "max17047", MAXIM_DEVICE_TYPE_MAX17047 }, { "max17050", MAXIM_DEVICE_TYPE_MAX17050 }, { "max17055", MAXIM_DEVICE_TYPE_MAX17055 }, + { "max77849-battery", MAXIM_DEVICE_TYPE_MAX17047 }, { } }; MODULE_DEVICE_TABLE(i2c, max17042_id); diff --git a/drivers/power/supply/mt6360_charger.c b/drivers/power/supply/mt6360_charger.c new file mode 100644 index 000000000000..3abaa72e0668 --- /dev/null +++ b/drivers/power/supply/mt6360_charger.c @@ -0,0 +1,867 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2021 MediaTek Inc. + */ + +#include <linux/devm-helpers.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <linux/linear_range.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/power_supply.h> +#include <linux/property.h> +#include <linux/regmap.h> +#include <linux/regulator/driver.h> + +#define MT6360_PMU_CHG_CTRL1 0x311 +#define MT6360_PMU_CHG_CTRL2 0x312 +#define MT6360_PMU_CHG_CTRL3 0x313 +#define MT6360_PMU_CHG_CTRL4 0x314 +#define MT6360_PMU_CHG_CTRL5 0x315 +#define MT6360_PMU_CHG_CTRL6 0x316 +#define MT6360_PMU_CHG_CTRL7 0x317 +#define MT6360_PMU_CHG_CTRL8 0x318 +#define MT6360_PMU_CHG_CTRL9 0x319 +#define MT6360_PMU_CHG_CTRL10 0x31A +#define MT6360_PMU_DEVICE_TYPE 0x322 +#define MT6360_PMU_USB_STATUS1 0x327 +#define MT6360_PMU_CHG_STAT 0x34A +#define MT6360_PMU_CHG_CTRL19 0x361 +#define MT6360_PMU_FOD_STAT 0x3E7 + +/* MT6360_PMU_CHG_CTRL1 */ +#define MT6360_FSLP_SHFT (3) +#define MT6360_FSLP_MASK BIT(MT6360_FSLP_SHFT) +#define MT6360_OPA_MODE_SHFT (0) +#define MT6360_OPA_MODE_MASK BIT(MT6360_OPA_MODE_SHFT) +/* MT6360_PMU_CHG_CTRL2 */ +#define MT6360_IINLMTSEL_SHFT (2) +#define MT6360_IINLMTSEL_MASK GENMASK(3, 2) +/* MT6360_PMU_CHG_CTRL3 */ +#define MT6360_IAICR_SHFT (2) +#define MT6360_IAICR_MASK GENMASK(7, 2) +#define MT6360_ILIM_EN_MASK BIT(0) +/* MT6360_PMU_CHG_CTRL4 */ +#define MT6360_VOREG_SHFT (1) +#define MT6360_VOREG_MASK GENMASK(7, 1) +/* MT6360_PMU_CHG_CTRL5 */ +#define MT6360_VOBST_MASK GENMASK(7, 2) +/* MT6360_PMU_CHG_CTRL6 */ +#define MT6360_VMIVR_SHFT (1) +#define MT6360_VMIVR_MASK GENMASK(7, 1) +/* MT6360_PMU_CHG_CTRL7 */ +#define MT6360_ICHG_SHFT (2) +#define MT6360_ICHG_MASK GENMASK(7, 2) +/* MT6360_PMU_CHG_CTRL8 */ +#define MT6360_IPREC_SHFT (0) +#define MT6360_IPREC_MASK GENMASK(3, 0) +/* MT6360_PMU_CHG_CTRL9 */ +#define MT6360_IEOC_SHFT (4) +#define MT6360_IEOC_MASK GENMASK(7, 4) +/* MT6360_PMU_CHG_CTRL10 */ +#define MT6360_OTG_OC_MASK GENMASK(3, 0) +/* MT6360_PMU_DEVICE_TYPE */ +#define MT6360_USBCHGEN_MASK BIT(7) +/* MT6360_PMU_USB_STATUS1 */ +#define MT6360_USB_STATUS_SHFT (4) +#define MT6360_USB_STATUS_MASK GENMASK(6, 4) +/* MT6360_PMU_CHG_STAT */ +#define MT6360_CHG_STAT_SHFT (6) +#define MT6360_CHG_STAT_MASK GENMASK(7, 6) +#define MT6360_VBAT_LVL_MASK BIT(5) +/* MT6360_PMU_CHG_CTRL19 */ +#define MT6360_VINOVP_SHFT (5) +#define MT6360_VINOVP_MASK GENMASK(6, 5) +/* MT6360_PMU_FOD_STAT */ +#define MT6360_CHRDET_EXT_MASK BIT(4) + +/* uV */ +#define MT6360_VMIVR_MIN 3900000 +#define MT6360_VMIVR_MAX 13400000 +#define MT6360_VMIVR_STEP 100000 +/* uA */ +#define MT6360_ICHG_MIN 100000 +#define MT6360_ICHG_MAX 5000000 +#define MT6360_ICHG_STEP 100000 +/* uV */ +#define MT6360_VOREG_MIN 3900000 +#define MT6360_VOREG_MAX 4710000 +#define MT6360_VOREG_STEP 10000 +/* uA */ +#define MT6360_AICR_MIN 100000 +#define MT6360_AICR_MAX 3250000 +#define MT6360_AICR_STEP 50000 +/* uA */ +#define MT6360_IPREC_MIN 100000 +#define MT6360_IPREC_MAX 850000 +#define MT6360_IPREC_STEP 50000 +/* uA */ +#define MT6360_IEOC_MIN 100000 +#define MT6360_IEOC_MAX 850000 +#define MT6360_IEOC_STEP 50000 + +enum { + MT6360_RANGE_VMIVR, + MT6360_RANGE_ICHG, + MT6360_RANGE_VOREG, + MT6360_RANGE_AICR, + MT6360_RANGE_IPREC, + MT6360_RANGE_IEOC, + MT6360_RANGE_MAX, +}; + +#define MT6360_LINEAR_RANGE(idx, _min, _min_sel, _max_sel, _step) \ + [idx] = REGULATOR_LINEAR_RANGE(_min, _min_sel, _max_sel, _step) + +static const struct linear_range mt6360_chg_range[MT6360_RANGE_MAX] = { + MT6360_LINEAR_RANGE(MT6360_RANGE_VMIVR, 3900000, 0, 0x5F, 100000), + MT6360_LINEAR_RANGE(MT6360_RANGE_ICHG, 100000, 0, 0x31, 100000), + MT6360_LINEAR_RANGE(MT6360_RANGE_VOREG, 3900000, 0, 0x51, 10000), + MT6360_LINEAR_RANGE(MT6360_RANGE_AICR, 100000, 0, 0x3F, 50000), + MT6360_LINEAR_RANGE(MT6360_RANGE_IPREC, 100000, 0, 0x0F, 50000), + MT6360_LINEAR_RANGE(MT6360_RANGE_IEOC, 100000, 0, 0x0F, 50000), +}; + +struct mt6360_chg_info { + struct device *dev; + struct regmap *regmap; + struct power_supply_desc psy_desc; + struct power_supply *psy; + struct regulator_dev *otg_rdev; + struct mutex chgdet_lock; + u32 vinovp; + bool pwr_rdy; + bool bc12_en; + int psy_usb_type; + struct work_struct chrdet_work; +}; + +enum mt6360_iinlmtsel { + MT6360_IINLMTSEL_AICR_3250 = 0, + MT6360_IINLMTSEL_CHG_TYPE, + MT6360_IINLMTSEL_AICR, + MT6360_IINLMTSEL_LOWER_LEVEL, +}; + +enum mt6360_pmu_chg_type { + MT6360_CHG_TYPE_NOVBUS = 0, + MT6360_CHG_TYPE_UNDER_GOING, + MT6360_CHG_TYPE_SDP, + MT6360_CHG_TYPE_SDPNSTD, + MT6360_CHG_TYPE_DCP, + MT6360_CHG_TYPE_CDP, + MT6360_CHG_TYPE_DISABLE_BC12, + MT6360_CHG_TYPE_MAX, +}; + +static enum power_supply_usb_type mt6360_charger_usb_types[] = { + POWER_SUPPLY_USB_TYPE_UNKNOWN, + POWER_SUPPLY_USB_TYPE_SDP, + POWER_SUPPLY_USB_TYPE_DCP, + POWER_SUPPLY_USB_TYPE_CDP, +}; + +static int mt6360_get_chrdet_ext_stat(struct mt6360_chg_info *mci, + bool *pwr_rdy) +{ + int ret; + unsigned int regval; + + ret = regmap_read(mci->regmap, MT6360_PMU_FOD_STAT, ®val); + if (ret < 0) + return ret; + *pwr_rdy = (regval & MT6360_CHRDET_EXT_MASK) ? true : false; + return 0; +} + +static int mt6360_charger_get_online(struct mt6360_chg_info *mci, + union power_supply_propval *val) +{ + int ret; + bool pwr_rdy; + + ret = mt6360_get_chrdet_ext_stat(mci, &pwr_rdy); + if (ret < 0) + return ret; + val->intval = pwr_rdy ? true : false; + return 0; +} + +static int mt6360_charger_get_status(struct mt6360_chg_info *mci, + union power_supply_propval *val) +{ + int status, ret; + unsigned int regval; + bool pwr_rdy; + + ret = mt6360_get_chrdet_ext_stat(mci, &pwr_rdy); + if (ret < 0) + return ret; + if (!pwr_rdy) { + status = POWER_SUPPLY_STATUS_DISCHARGING; + goto out; + } + + ret = regmap_read(mci->regmap, MT6360_PMU_CHG_STAT, ®val); + if (ret < 0) + return ret; + regval &= MT6360_CHG_STAT_MASK; + regval >>= MT6360_CHG_STAT_SHFT; + switch (regval) { + case 0x0: + status = POWER_SUPPLY_STATUS_NOT_CHARGING; + break; + case 0x1: + status = POWER_SUPPLY_STATUS_CHARGING; + break; + case 0x2: + status = POWER_SUPPLY_STATUS_FULL; + break; + default: + ret = -EIO; + } +out: + if (!ret) + val->intval = status; + return ret; +} + +static int mt6360_charger_get_charge_type(struct mt6360_chg_info *mci, + union power_supply_propval *val) +{ + int type, ret; + unsigned int regval; + u8 chg_stat; + + ret = regmap_read(mci->regmap, MT6360_PMU_CHG_STAT, ®val); + if (ret < 0) + return ret; + + chg_stat = (regval & MT6360_CHG_STAT_MASK) >> MT6360_CHG_STAT_SHFT; + switch (chg_stat) { + case 0x01: /* Charge in Progress */ + if (regval & MT6360_VBAT_LVL_MASK) + type = POWER_SUPPLY_CHARGE_TYPE_FAST; + else + type = POWER_SUPPLY_CHARGE_TYPE_TRICKLE; + break; + case 0x00: /* Not Charging */ + case 0x02: /* Charge Done */ + case 0x03: /* Charge Fault */ + default: + type = POWER_SUPPLY_CHARGE_TYPE_NONE; + break; + } + + val->intval = type; + return 0; +} + +static int mt6360_charger_get_ichg(struct mt6360_chg_info *mci, + union power_supply_propval *val) +{ + int ret; + u32 sel, value; + + ret = regmap_read(mci->regmap, MT6360_PMU_CHG_CTRL7, &sel); + if (ret < 0) + return ret; + sel = (sel & MT6360_ICHG_MASK) >> MT6360_ICHG_SHFT; + ret = linear_range_get_value(&mt6360_chg_range[MT6360_RANGE_ICHG], sel, &value); + if (!ret) + val->intval = value; + return ret; +} + +static int mt6360_charger_get_max_ichg(struct mt6360_chg_info *mci, + union power_supply_propval *val) +{ + val->intval = MT6360_ICHG_MAX; + return 0; +} + +static int mt6360_charger_get_cv(struct mt6360_chg_info *mci, + union power_supply_propval *val) +{ + int ret; + u32 sel, value; + + ret = regmap_read(mci->regmap, MT6360_PMU_CHG_CTRL4, &sel); + if (ret < 0) + return ret; + sel = (sel & MT6360_VOREG_MASK) >> MT6360_VOREG_SHFT; + ret = linear_range_get_value(&mt6360_chg_range[MT6360_RANGE_VOREG], sel, &value); + if (!ret) + val->intval = value; + return ret; +} + +static int mt6360_charger_get_max_cv(struct mt6360_chg_info *mci, + union power_supply_propval *val) +{ + val->intval = MT6360_VOREG_MAX; + return 0; +} + +static int mt6360_charger_get_aicr(struct mt6360_chg_info *mci, + union power_supply_propval *val) +{ + int ret; + u32 sel, value; + + ret = regmap_read(mci->regmap, MT6360_PMU_CHG_CTRL3, &sel); + if (ret < 0) + return ret; + sel = (sel & MT6360_IAICR_MASK) >> MT6360_IAICR_SHFT; + ret = linear_range_get_value(&mt6360_chg_range[MT6360_RANGE_AICR], sel, &value); + if (!ret) + val->intval = value; + return ret; +} + +static int mt6360_charger_get_mivr(struct mt6360_chg_info *mci, + union power_supply_propval *val) +{ + int ret; + u32 sel, value; + + ret = regmap_read(mci->regmap, MT6360_PMU_CHG_CTRL6, &sel); + if (ret < 0) + return ret; + sel = (sel & MT6360_VMIVR_MASK) >> MT6360_VMIVR_SHFT; + ret = linear_range_get_value(&mt6360_chg_range[MT6360_RANGE_VMIVR], sel, &value); + if (!ret) + val->intval = value; + return ret; +} + +static int mt6360_charger_get_iprechg(struct mt6360_chg_info *mci, + union power_supply_propval *val) +{ + int ret; + u32 sel, value; + + ret = regmap_read(mci->regmap, MT6360_PMU_CHG_CTRL8, &sel); + if (ret < 0) + return ret; + sel = (sel & MT6360_IPREC_MASK) >> MT6360_IPREC_SHFT; + ret = linear_range_get_value(&mt6360_chg_range[MT6360_RANGE_IPREC], sel, &value); + if (!ret) + val->intval = value; + return ret; +} + +static int mt6360_charger_get_ieoc(struct mt6360_chg_info *mci, + union power_supply_propval *val) +{ + int ret; + u32 sel, value; + + ret = regmap_read(mci->regmap, MT6360_PMU_CHG_CTRL9, &sel); + if (ret < 0) + return ret; + sel = (sel & MT6360_IEOC_MASK) >> MT6360_IEOC_SHFT; + ret = linear_range_get_value(&mt6360_chg_range[MT6360_RANGE_IEOC], sel, &value); + if (!ret) + val->intval = value; + return ret; +} + +static int mt6360_charger_set_online(struct mt6360_chg_info *mci, + const union power_supply_propval *val) +{ + u8 force_sleep = val->intval ? 0 : 1; + + return regmap_update_bits(mci->regmap, + MT6360_PMU_CHG_CTRL1, + MT6360_FSLP_MASK, + force_sleep << MT6360_FSLP_SHFT); +} + +static int mt6360_charger_set_ichg(struct mt6360_chg_info *mci, + const union power_supply_propval *val) +{ + u32 sel; + + linear_range_get_selector_within(&mt6360_chg_range[MT6360_RANGE_ICHG], val->intval, &sel); + return regmap_update_bits(mci->regmap, + MT6360_PMU_CHG_CTRL7, + MT6360_ICHG_MASK, + sel << MT6360_ICHG_SHFT); +} + +static int mt6360_charger_set_cv(struct mt6360_chg_info *mci, + const union power_supply_propval *val) +{ + u32 sel; + + linear_range_get_selector_within(&mt6360_chg_range[MT6360_RANGE_VOREG], val->intval, &sel); + return regmap_update_bits(mci->regmap, + MT6360_PMU_CHG_CTRL4, + MT6360_VOREG_MASK, + sel << MT6360_VOREG_SHFT); +} + +static int mt6360_charger_set_aicr(struct mt6360_chg_info *mci, + const union power_supply_propval *val) +{ + u32 sel; + + linear_range_get_selector_within(&mt6360_chg_range[MT6360_RANGE_AICR], val->intval, &sel); + return regmap_update_bits(mci->regmap, + MT6360_PMU_CHG_CTRL3, + MT6360_IAICR_MASK, + sel << MT6360_IAICR_SHFT); +} + +static int mt6360_charger_set_mivr(struct mt6360_chg_info *mci, + const union power_supply_propval *val) +{ + u32 sel; + + linear_range_get_selector_within(&mt6360_chg_range[MT6360_RANGE_VMIVR], val->intval, &sel); + return regmap_update_bits(mci->regmap, + MT6360_PMU_CHG_CTRL3, + MT6360_VMIVR_MASK, + sel << MT6360_VMIVR_SHFT); +} + +static int mt6360_charger_set_iprechg(struct mt6360_chg_info *mci, + const union power_supply_propval *val) +{ + u32 sel; + + linear_range_get_selector_within(&mt6360_chg_range[MT6360_RANGE_IPREC], val->intval, &sel); + return regmap_update_bits(mci->regmap, + MT6360_PMU_CHG_CTRL8, + MT6360_IPREC_MASK, + sel << MT6360_IPREC_SHFT); +} + +static int mt6360_charger_set_ieoc(struct mt6360_chg_info *mci, + const union power_supply_propval *val) +{ + u32 sel; + + linear_range_get_selector_within(&mt6360_chg_range[MT6360_RANGE_IEOC], val->intval, &sel); + return regmap_update_bits(mci->regmap, + MT6360_PMU_CHG_CTRL9, + MT6360_IEOC_MASK, + sel << MT6360_IEOC_SHFT); +} + +static int mt6360_charger_get_property(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct mt6360_chg_info *mci = power_supply_get_drvdata(psy); + int ret = 0; + + switch (psp) { + case POWER_SUPPLY_PROP_ONLINE: + ret = mt6360_charger_get_online(mci, val); + break; + case POWER_SUPPLY_PROP_STATUS: + ret = mt6360_charger_get_status(mci, val); + break; + case POWER_SUPPLY_PROP_CHARGE_TYPE: + ret = mt6360_charger_get_charge_type(mci, val); + break; + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: + ret = mt6360_charger_get_ichg(mci, val); + break; + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: + ret = mt6360_charger_get_max_ichg(mci, val); + break; + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: + ret = mt6360_charger_get_cv(mci, val); + break; + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX: + ret = mt6360_charger_get_max_cv(mci, val); + break; + case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: + ret = mt6360_charger_get_aicr(mci, val); + break; + case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT: + ret = mt6360_charger_get_mivr(mci, val); + break; + case POWER_SUPPLY_PROP_PRECHARGE_CURRENT: + ret = mt6360_charger_get_iprechg(mci, val); + break; + case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT: + ret = mt6360_charger_get_ieoc(mci, val); + break; + case POWER_SUPPLY_PROP_USB_TYPE: + val->intval = mci->psy_usb_type; + break; + default: + ret = -ENODATA; + } + return ret; +} + +static int mt6360_charger_set_property(struct power_supply *psy, + enum power_supply_property psp, + const union power_supply_propval *val) +{ + struct mt6360_chg_info *mci = power_supply_get_drvdata(psy); + int ret; + + switch (psp) { + case POWER_SUPPLY_PROP_ONLINE: + ret = mt6360_charger_set_online(mci, val); + break; + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: + ret = mt6360_charger_set_ichg(mci, val); + break; + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: + ret = mt6360_charger_set_cv(mci, val); + break; + case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: + ret = mt6360_charger_set_aicr(mci, val); + break; + case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT: + ret = mt6360_charger_set_mivr(mci, val); + break; + case POWER_SUPPLY_PROP_PRECHARGE_CURRENT: + ret = mt6360_charger_set_iprechg(mci, val); + break; + case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT: + ret = mt6360_charger_set_ieoc(mci, val); + break; + default: + ret = -EINVAL; + } + return ret; +} + +static int mt6360_charger_property_is_writeable(struct power_supply *psy, + enum power_supply_property psp) +{ + switch (psp) { + case POWER_SUPPLY_PROP_ONLINE: + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: + case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT: + case POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT: + case POWER_SUPPLY_PROP_PRECHARGE_CURRENT: + case POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT: + return 1; + default: + return 0; + } +} + +static enum power_supply_property mt6360_charger_properties[] = { + POWER_SUPPLY_PROP_ONLINE, + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_CHARGE_TYPE, + POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT, + POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, + POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE, + POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX, + POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, + POWER_SUPPLY_PROP_INPUT_VOLTAGE_LIMIT, + POWER_SUPPLY_PROP_PRECHARGE_CURRENT, + POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT, + POWER_SUPPLY_PROP_USB_TYPE, +}; + +static const struct power_supply_desc mt6360_charger_desc = { + .type = POWER_SUPPLY_TYPE_USB, + .properties = mt6360_charger_properties, + .num_properties = ARRAY_SIZE(mt6360_charger_properties), + .get_property = mt6360_charger_get_property, + .set_property = mt6360_charger_set_property, + .property_is_writeable = mt6360_charger_property_is_writeable, + .usb_types = mt6360_charger_usb_types, + .num_usb_types = ARRAY_SIZE(mt6360_charger_usb_types), +}; + +static const struct regulator_ops mt6360_chg_otg_ops = { + .list_voltage = regulator_list_voltage_linear, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, +}; + +static const struct regulator_desc mt6360_otg_rdesc = { + .of_match = "usb-otg-vbus", + .name = "usb-otg-vbus", + .ops = &mt6360_chg_otg_ops, + .owner = THIS_MODULE, + .type = REGULATOR_VOLTAGE, + .min_uV = 4425000, + .uV_step = 25000, + .n_voltages = 57, + .vsel_reg = MT6360_PMU_CHG_CTRL5, + .vsel_mask = MT6360_VOBST_MASK, + .enable_reg = MT6360_PMU_CHG_CTRL1, + .enable_mask = MT6360_OPA_MODE_MASK, +}; + +static irqreturn_t mt6360_pmu_attach_i_handler(int irq, void *data) +{ + struct mt6360_chg_info *mci = data; + int ret; + unsigned int usb_status; + int last_usb_type; + + mutex_lock(&mci->chgdet_lock); + if (!mci->bc12_en) { + dev_warn(mci->dev, "Received attach interrupt, bc12 disabled, ignore irq\n"); + goto out; + } + last_usb_type = mci->psy_usb_type; + /* Plug in */ + ret = regmap_read(mci->regmap, MT6360_PMU_USB_STATUS1, &usb_status); + if (ret < 0) + goto out; + usb_status &= MT6360_USB_STATUS_MASK; + usb_status >>= MT6360_USB_STATUS_SHFT; + switch (usb_status) { + case MT6360_CHG_TYPE_NOVBUS: + dev_dbg(mci->dev, "Received attach interrupt, no vbus\n"); + goto out; + case MT6360_CHG_TYPE_UNDER_GOING: + dev_dbg(mci->dev, "Received attach interrupt, under going...\n"); + goto out; + case MT6360_CHG_TYPE_SDP: + mci->psy_usb_type = POWER_SUPPLY_USB_TYPE_SDP; + break; + case MT6360_CHG_TYPE_SDPNSTD: + mci->psy_usb_type = POWER_SUPPLY_USB_TYPE_SDP; + break; + case MT6360_CHG_TYPE_CDP: + mci->psy_usb_type = POWER_SUPPLY_USB_TYPE_CDP; + break; + case MT6360_CHG_TYPE_DCP: + mci->psy_usb_type = POWER_SUPPLY_USB_TYPE_DCP; + break; + case MT6360_CHG_TYPE_DISABLE_BC12: + dev_dbg(mci->dev, "Received attach interrupt, bc12 detect not enable\n"); + goto out; + default: + mci->psy_usb_type = POWER_SUPPLY_USB_TYPE_UNKNOWN; + dev_dbg(mci->dev, "Received attach interrupt, reserved address\n"); + goto out; + } + + dev_dbg(mci->dev, "Received attach interrupt, chg_type = %d\n", mci->psy_usb_type); + if (last_usb_type != mci->psy_usb_type) + power_supply_changed(mci->psy); +out: + mutex_unlock(&mci->chgdet_lock); + return IRQ_HANDLED; +} + +static void mt6360_handle_chrdet_ext_evt(struct mt6360_chg_info *mci) +{ + int ret; + bool pwr_rdy; + + mutex_lock(&mci->chgdet_lock); + ret = mt6360_get_chrdet_ext_stat(mci, &pwr_rdy); + if (ret < 0) + goto out; + if (mci->pwr_rdy == pwr_rdy) { + dev_dbg(mci->dev, "Received vbus interrupt, pwr_rdy is same(%d)\n", pwr_rdy); + goto out; + } + mci->pwr_rdy = pwr_rdy; + dev_dbg(mci->dev, "Received vbus interrupt, pwr_rdy = %d\n", pwr_rdy); + if (!pwr_rdy) { + mci->psy_usb_type = POWER_SUPPLY_USB_TYPE_UNKNOWN; + power_supply_changed(mci->psy); + + } + ret = regmap_update_bits(mci->regmap, + MT6360_PMU_DEVICE_TYPE, + MT6360_USBCHGEN_MASK, + pwr_rdy ? MT6360_USBCHGEN_MASK : 0); + if (ret < 0) + goto out; + mci->bc12_en = pwr_rdy; +out: + mutex_unlock(&mci->chgdet_lock); +} + +static void mt6360_chrdet_work(struct work_struct *work) +{ + struct mt6360_chg_info *mci = (struct mt6360_chg_info *)container_of( + work, struct mt6360_chg_info, chrdet_work); + + mt6360_handle_chrdet_ext_evt(mci); +} + +static irqreturn_t mt6360_pmu_chrdet_ext_evt_handler(int irq, void *data) +{ + struct mt6360_chg_info *mci = data; + + mt6360_handle_chrdet_ext_evt(mci); + return IRQ_HANDLED; +} + +static int mt6360_chg_irq_register(struct platform_device *pdev) +{ + const struct { + const char *name; + irq_handler_t handler; + } irq_descs[] = { + { "attach_i", mt6360_pmu_attach_i_handler }, + { "chrdet_ext_evt", mt6360_pmu_chrdet_ext_evt_handler } + }; + int i, ret; + + for (i = 0; i < ARRAY_SIZE(irq_descs); i++) { + ret = platform_get_irq_byname(pdev, irq_descs[i].name); + if (ret < 0) + return ret; + + ret = devm_request_threaded_irq(&pdev->dev, ret, NULL, + irq_descs[i].handler, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + irq_descs[i].name, + platform_get_drvdata(pdev)); + if (ret < 0) + return dev_err_probe(&pdev->dev, ret, "Failed to request %s irq\n", + irq_descs[i].name); + } + + return 0; +} + +static u32 mt6360_vinovp_trans_to_sel(u32 val) +{ + u32 vinovp_tbl[] = { 5500000, 6500000, 11000000, 14500000 }; + int i; + + /* Select the smaller and equal supported value */ + for (i = 0; i < ARRAY_SIZE(vinovp_tbl)-1; i++) { + if (val < vinovp_tbl[i+1]) + break; + } + return i; +} + +static int mt6360_chg_init_setting(struct mt6360_chg_info *mci) +{ + int ret; + u32 sel; + + sel = mt6360_vinovp_trans_to_sel(mci->vinovp); + ret = regmap_update_bits(mci->regmap, MT6360_PMU_CHG_CTRL19, + MT6360_VINOVP_MASK, sel << MT6360_VINOVP_SHFT); + if (ret) + return dev_err_probe(mci->dev, ret, "%s: Failed to apply vinovp\n", __func__); + ret = regmap_update_bits(mci->regmap, MT6360_PMU_DEVICE_TYPE, + MT6360_USBCHGEN_MASK, 0); + if (ret) + return dev_err_probe(mci->dev, ret, "%s: Failed to disable bc12\n", __func__); + ret = regmap_update_bits(mci->regmap, MT6360_PMU_CHG_CTRL2, + MT6360_IINLMTSEL_MASK, + MT6360_IINLMTSEL_AICR << + MT6360_IINLMTSEL_SHFT); + if (ret) + return dev_err_probe(mci->dev, ret, + "%s: Failed to switch iinlmtsel to aicr\n", __func__); + usleep_range(5000, 6000); + ret = regmap_update_bits(mci->regmap, MT6360_PMU_CHG_CTRL3, + MT6360_ILIM_EN_MASK, 0); + if (ret) + return dev_err_probe(mci->dev, ret, + "%s: Failed to disable ilim\n", __func__); + ret = regmap_update_bits(mci->regmap, MT6360_PMU_CHG_CTRL10, + MT6360_OTG_OC_MASK, MT6360_OTG_OC_MASK); + if (ret) + return dev_err_probe(mci->dev, ret, + "%s: Failed to config otg oc to 3A\n", __func__); + return 0; +} + +static int mt6360_charger_probe(struct platform_device *pdev) +{ + struct mt6360_chg_info *mci; + struct power_supply_config charger_cfg = {}; + struct regulator_config config = { }; + int ret; + + mci = devm_kzalloc(&pdev->dev, sizeof(*mci), GFP_KERNEL); + if (!mci) + return -ENOMEM; + + mci->dev = &pdev->dev; + mci->vinovp = 6500000; + mutex_init(&mci->chgdet_lock); + platform_set_drvdata(pdev, mci); + devm_work_autocancel(&pdev->dev, &mci->chrdet_work, mt6360_chrdet_work); + + ret = device_property_read_u32(&pdev->dev, "richtek,vinovp-microvolt", &mci->vinovp); + if (ret) + dev_warn(&pdev->dev, "Failed to parse vinovp in DT, keep default 6.5v\n"); + + mci->regmap = dev_get_regmap(pdev->dev.parent, NULL); + if (!mci->regmap) + return dev_err_probe(&pdev->dev, -ENODEV, "Failed to get parent regmap\n"); + + ret = mt6360_chg_init_setting(mci); + if (ret) + return dev_err_probe(&pdev->dev, ret, "Failed to initial setting\n"); + + memcpy(&mci->psy_desc, &mt6360_charger_desc, sizeof(mci->psy_desc)); + mci->psy_desc.name = dev_name(&pdev->dev); + charger_cfg.drv_data = mci; + charger_cfg.of_node = pdev->dev.of_node; + mci->psy = devm_power_supply_register(&pdev->dev, + &mci->psy_desc, &charger_cfg); + if (IS_ERR(mci->psy)) + return dev_err_probe(&pdev->dev, PTR_ERR(mci->psy), + "Failed to register power supply dev\n"); + + + ret = mt6360_chg_irq_register(pdev); + if (ret) + return dev_err_probe(&pdev->dev, ret, "Failed to register irqs\n"); + + config.dev = &pdev->dev; + config.regmap = mci->regmap; + mci->otg_rdev = devm_regulator_register(&pdev->dev, &mt6360_otg_rdesc, + &config); + if (IS_ERR(mci->otg_rdev)) + return PTR_ERR(mci->otg_rdev); + + schedule_work(&mci->chrdet_work); + + return 0; +} + +static const struct of_device_id __maybe_unused mt6360_charger_of_id[] = { + { .compatible = "mediatek,mt6360-chg", }, + {}, +}; +MODULE_DEVICE_TABLE(of, mt6360_charger_of_id); + +static const struct platform_device_id mt6360_charger_id[] = { + { "mt6360-chg", 0 }, + {}, +}; +MODULE_DEVICE_TABLE(platform, mt6360_charger_id); + +static struct platform_driver mt6360_charger_driver = { + .driver = { + .name = "mt6360-chg", + .of_match_table = of_match_ptr(mt6360_charger_of_id), + }, + .probe = mt6360_charger_probe, + .id_table = mt6360_charger_id, +}; +module_platform_driver(mt6360_charger_driver); + +MODULE_AUTHOR("Gene Chen <gene_chen@richtek.com>"); +MODULE_DESCRIPTION("MT6360 Charger Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/power/supply/power_supply_core.c b/drivers/power/supply/power_supply_core.c index d99e2f11c183..0c2132c7f5d4 100644 --- a/drivers/power/supply/power_supply_core.c +++ b/drivers/power/supply/power_supply_core.c @@ -571,6 +571,7 @@ int power_supply_get_battery_info(struct power_supply *psy, int err, len, index; const __be32 *list; + info->technology = POWER_SUPPLY_TECHNOLOGY_UNKNOWN; info->energy_full_design_uwh = -EINVAL; info->charge_full_design_uah = -EINVAL; info->voltage_min_design_uv = -EINVAL; @@ -618,6 +619,24 @@ int power_supply_get_battery_info(struct power_supply *psy, * Documentation/power/power_supply_class.rst. */ + if (!of_property_read_string(battery_np, "device-chemistry", &value)) { + if (!strcmp("nickel-cadmium", value)) + info->technology = POWER_SUPPLY_TECHNOLOGY_NiCd; + else if (!strcmp("nickel-metal-hydride", value)) + info->technology = POWER_SUPPLY_TECHNOLOGY_NiMH; + else if (!strcmp("lithium-ion", value)) + /* Imprecise lithium-ion type */ + info->technology = POWER_SUPPLY_TECHNOLOGY_LION; + else if (!strcmp("lithium-ion-polymer", value)) + info->technology = POWER_SUPPLY_TECHNOLOGY_LIPO; + else if (!strcmp("lithium-ion-iron-phosphate", value)) + info->technology = POWER_SUPPLY_TECHNOLOGY_LiFe; + else if (!strcmp("lithium-ion-manganese-oxide", value)) + info->technology = POWER_SUPPLY_TECHNOLOGY_LiMn; + else + dev_warn(&psy->dev, "%s unknown battery type\n", value); + } + of_property_read_u32(battery_np, "energy-full-design-microwatt-hours", &info->energy_full_design_uwh); of_property_read_u32(battery_np, "charge-full-design-microamp-hours", diff --git a/drivers/power/supply/qcom_smbb.c b/drivers/power/supply/qcom_smbb.c index c890e1cec720..84cc9fba029d 100644 --- a/drivers/power/supply/qcom_smbb.c +++ b/drivers/power/supply/qcom_smbb.c @@ -929,11 +929,8 @@ static int smbb_charger_probe(struct platform_device *pdev) int irq; irq = platform_get_irq_byname(pdev, smbb_charger_irqs[i].name); - if (irq < 0) { - dev_err(&pdev->dev, "failed to get irq '%s'\n", - smbb_charger_irqs[i].name); + if (irq < 0) return irq; - } smbb_charger_irqs[i].handler(irq, chg); diff --git a/drivers/power/supply/rn5t618_power.c b/drivers/power/supply/rn5t618_power.c index 819061918b2a..a5e09ac78a50 100644 --- a/drivers/power/supply/rn5t618_power.c +++ b/drivers/power/supply/rn5t618_power.c @@ -9,10 +9,12 @@ #include <linux/device.h> #include <linux/bitops.h> #include <linux/errno.h> +#include <linux/iio/consumer.h> #include <linux/init.h> #include <linux/interrupt.h> #include <linux/module.h> #include <linux/mfd/rn5t618.h> +#include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/power_supply.h> #include <linux/regmap.h> @@ -64,6 +66,8 @@ struct rn5t618_power_info { struct power_supply *battery; struct power_supply *usb; struct power_supply *adp; + struct iio_channel *channel_vusb; + struct iio_channel *channel_vadp; int irq; }; @@ -77,6 +81,7 @@ static enum power_supply_usb_type rn5t618_usb_types[] = { static enum power_supply_property rn5t618_usb_props[] = { /* input current limit is not very accurate */ POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, + POWER_SUPPLY_PROP_VOLTAGE_NOW, POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_PROP_USB_TYPE, POWER_SUPPLY_PROP_ONLINE, @@ -85,6 +90,7 @@ static enum power_supply_property rn5t618_usb_props[] = { static enum power_supply_property rn5t618_adp_props[] = { /* input current limit is not very accurate */ POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, + POWER_SUPPLY_PROP_VOLTAGE_NOW, POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_PROP_ONLINE, }; @@ -464,6 +470,15 @@ static int rn5t618_adp_get_property(struct power_supply *psy, val->intval = FROM_CUR_REG(regval); break; + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + if (!info->channel_vadp) + return -ENODATA; + + ret = iio_read_channel_processed_scale(info->channel_vadp, &val->intval, 1000); + if (ret < 0) + return ret; + + break; default: return -EINVAL; } @@ -589,6 +604,15 @@ static int rn5t618_usb_get_property(struct power_supply *psy, val->intval = FROM_CUR_REG(regval); } break; + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + if (!info->channel_vusb) + return -ENODATA; + + ret = iio_read_channel_processed_scale(info->channel_vusb, &val->intval, 1000); + if (ret < 0) + return ret; + + break; default: return -EINVAL; } @@ -711,6 +735,20 @@ static int rn5t618_power_probe(struct platform_device *pdev) platform_set_drvdata(pdev, info); + info->channel_vusb = devm_iio_channel_get(&pdev->dev, "vusb"); + if (IS_ERR(info->channel_vusb)) { + if (PTR_ERR(info->channel_vusb) == -ENODEV) + return -EPROBE_DEFER; + return PTR_ERR(info->channel_vusb); + } + + info->channel_vadp = devm_iio_channel_get(&pdev->dev, "vadp"); + if (IS_ERR(info->channel_vadp)) { + if (PTR_ERR(info->channel_vadp) == -ENODEV) + return -EPROBE_DEFER; + return PTR_ERR(info->channel_vadp); + } + ret = regmap_read(info->rn5t618->regmap, RN5T618_CONTROL, &v); if (ret) return ret; diff --git a/drivers/power/supply/sbs-battery.c b/drivers/power/supply/sbs-battery.c index f84dbaab283a..c4a95b01463a 100644 --- a/drivers/power/supply/sbs-battery.c +++ b/drivers/power/supply/sbs-battery.c @@ -31,8 +31,9 @@ enum { REG_CURRENT_AVG, REG_MAX_ERR, REG_CAPACITY, - REG_TIME_TO_EMPTY, - REG_TIME_TO_FULL, + REG_TIME_TO_EMPTY_NOW, + REG_TIME_TO_EMPTY_AVG, + REG_TIME_TO_FULL_AVG, REG_STATUS, REG_CAPACITY_LEVEL, REG_CYCLE_COUNT, @@ -102,7 +103,7 @@ static const struct chip_data { [REG_TEMPERATURE] = SBS_DATA(POWER_SUPPLY_PROP_TEMP, 0x08, 0, 65535), [REG_VOLTAGE] = - SBS_DATA(POWER_SUPPLY_PROP_VOLTAGE_NOW, 0x09, 0, 20000), + SBS_DATA(POWER_SUPPLY_PROP_VOLTAGE_NOW, 0x09, 0, 65535), [REG_CURRENT_NOW] = SBS_DATA(POWER_SUPPLY_PROP_CURRENT_NOW, 0x0A, -32768, 32767), [REG_CURRENT_AVG] = @@ -119,9 +120,11 @@ static const struct chip_data { SBS_DATA(POWER_SUPPLY_PROP_ENERGY_FULL, 0x10, 0, 65535), [REG_FULL_CHARGE_CAPACITY_CHARGE] = SBS_DATA(POWER_SUPPLY_PROP_CHARGE_FULL, 0x10, 0, 65535), - [REG_TIME_TO_EMPTY] = + [REG_TIME_TO_EMPTY_NOW] = + SBS_DATA(POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, 0x11, 0, 65535), + [REG_TIME_TO_EMPTY_AVG] = SBS_DATA(POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG, 0x12, 0, 65535), - [REG_TIME_TO_FULL] = + [REG_TIME_TO_FULL_AVG] = SBS_DATA(POWER_SUPPLY_PROP_TIME_TO_FULL_AVG, 0x13, 0, 65535), [REG_CHARGE_CURRENT] = SBS_DATA(POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, 0x14, 0, 65535), @@ -165,6 +168,7 @@ static const enum power_supply_property sbs_properties[] = { POWER_SUPPLY_PROP_CAPACITY, POWER_SUPPLY_PROP_CAPACITY_ERROR_MARGIN, POWER_SUPPLY_PROP_TEMP, + POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG, POWER_SUPPLY_PROP_TIME_TO_FULL_AVG, POWER_SUPPLY_PROP_SERIAL_NUMBER, @@ -748,6 +752,7 @@ static void sbs_unit_adjustment(struct i2c_client *client, val->intval -= TEMP_KELVIN_TO_CELSIUS; break; + case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW: case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG: case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG: /* sbs provides time to empty and time to full in minutes. @@ -966,6 +971,7 @@ static int sbs_get_property(struct power_supply *psy, case POWER_SUPPLY_PROP_CURRENT_NOW: case POWER_SUPPLY_PROP_CURRENT_AVG: case POWER_SUPPLY_PROP_TEMP: + case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW: case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG: case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG: case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: diff --git a/drivers/power/supply/sc27xx_fuel_gauge.c b/drivers/power/supply/sc27xx_fuel_gauge.c index 1ae8374e1ceb..ae45069bd5e1 100644 --- a/drivers/power/supply/sc27xx_fuel_gauge.c +++ b/drivers/power/supply/sc27xx_fuel_gauge.c @@ -1229,10 +1229,8 @@ static int sc27xx_fgu_probe(struct platform_device *pdev) } irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(dev, "no irq resource specified\n"); + if (irq < 0) return irq; - } ret = devm_request_threaded_irq(data->dev, irq, NULL, sc27xx_fgu_interrupt, diff --git a/drivers/power/supply/smb347-charger.c b/drivers/power/supply/smb347-charger.c index df240420f2de..753944e774c4 100644 --- a/drivers/power/supply/smb347-charger.c +++ b/drivers/power/supply/smb347-charger.c @@ -18,6 +18,7 @@ #include <linux/power_supply.h> #include <linux/property.h> #include <linux/regmap.h> +#include <linux/regulator/driver.h> #include <dt-bindings/power/summit,smb347-charger.h> @@ -55,6 +56,7 @@ #define CFG_PIN_EN_CTRL_ACTIVE_LOW 0x60 #define CFG_PIN_EN_APSD_IRQ BIT(1) #define CFG_PIN_EN_CHARGER_ERROR BIT(2) +#define CFG_PIN_EN_CTRL BIT(4) #define CFG_THERM 0x07 #define CFG_THERM_SOFT_HOT_COMPENSATION_MASK 0x03 #define CFG_THERM_SOFT_HOT_COMPENSATION_SHIFT 0 @@ -62,12 +64,15 @@ #define CFG_THERM_SOFT_COLD_COMPENSATION_SHIFT 2 #define CFG_THERM_MONITOR_DISABLED BIT(4) #define CFG_SYSOK 0x08 +#define CFG_SYSOK_INOK_ACTIVE_HIGH BIT(0) #define CFG_SYSOK_SUSPEND_HARD_LIMIT_DISABLED BIT(2) #define CFG_OTHER 0x09 #define CFG_OTHER_RID_MASK 0xc0 #define CFG_OTHER_RID_ENABLED_AUTO_OTG 0xc0 #define CFG_OTG 0x0a #define CFG_OTG_TEMP_THRESHOLD_MASK 0x30 +#define CFG_OTG_CURRENT_LIMIT_250mA BIT(2) +#define CFG_OTG_CURRENT_LIMIT_750mA BIT(3) #define CFG_OTG_TEMP_THRESHOLD_SHIFT 4 #define CFG_OTG_CC_COMPENSATION_MASK 0xc0 #define CFG_OTG_CC_COMPENSATION_SHIFT 6 @@ -91,6 +96,7 @@ #define CMD_A 0x30 #define CMD_A_CHG_ENABLED BIT(1) #define CMD_A_SUSPEND_ENABLED BIT(2) +#define CMD_A_OTG_ENABLED BIT(4) #define CMD_A_ALLOW_WRITE BIT(7) #define CMD_B 0x31 #define CMD_C 0x33 @@ -132,11 +138,12 @@ * @regmap: pointer to driver regmap * @mains: power_supply instance for AC/DC power * @usb: power_supply instance for USB power + * @usb_rdev: USB VBUS regulator device * @id: SMB charger ID * @mains_online: is AC/DC input connected * @usb_online: is USB input connected - * @charging_enabled: is charging enabled * @irq_unsupported: is interrupt unsupported by SMB hardware + * @usb_vbus_enabled: is USB VBUS powered by SMB charger * @max_charge_current: maximum current (in uA) the battery can be charged * @max_charge_voltage: maximum voltage (in uV) the battery can be charged * @pre_charge_current: current (in uA) to use in pre-charging phase @@ -167,6 +174,8 @@ * @use_usb_otg: USB OTG output can be used (not implemented yet) * @enable_control: how charging enable/disable is controlled * (driver/pin controls) + * @inok_polarity: polarity of INOK signal which denotes presence of external + * power supply * * @use_main, @use_usb, and @use_usb_otg are means to enable/disable * hardware support for these. This is useful when we want to have for @@ -189,11 +198,12 @@ struct smb347_charger { struct regmap *regmap; struct power_supply *mains; struct power_supply *usb; + struct regulator_dev *usb_rdev; unsigned int id; bool mains_online; bool usb_online; - bool charging_enabled; bool irq_unsupported; + bool usb_vbus_enabled; unsigned int max_charge_current; unsigned int max_charge_voltage; @@ -214,6 +224,7 @@ struct smb347_charger { bool use_usb; bool use_usb_otg; unsigned int enable_control; + unsigned int inok_polarity; }; enum smb_charger_chipid { @@ -358,21 +369,18 @@ static int smb347_charging_status(struct smb347_charger *smb) static int smb347_charging_set(struct smb347_charger *smb, bool enable) { - int ret = 0; - if (smb->enable_control != SMB3XX_CHG_ENABLE_SW) { dev_dbg(smb->dev, "charging enable/disable in SW disabled\n"); return 0; } - if (smb->charging_enabled != enable) { - ret = regmap_update_bits(smb->regmap, CMD_A, CMD_A_CHG_ENABLED, - enable ? CMD_A_CHG_ENABLED : 0); - if (!ret) - smb->charging_enabled = enable; + if (enable && smb->usb_vbus_enabled) { + dev_dbg(smb->dev, "charging not enabled because USB is in host mode\n"); + return 0; } - return ret; + return regmap_update_bits(smb->regmap, CMD_A, CMD_A_CHG_ENABLED, + enable ? CMD_A_CHG_ENABLED : 0); } static inline int smb347_charging_enable(struct smb347_charger *smb) @@ -671,10 +679,22 @@ static int smb347_set_temp_limits(struct smb347_charger *smb) * * Returns %0 on success and negative errno in case of failure. */ -static int smb347_set_writable(struct smb347_charger *smb, bool writable) +static int smb347_set_writable(struct smb347_charger *smb, bool writable, + bool irq_toggle) { - return regmap_update_bits(smb->regmap, CMD_A, CMD_A_ALLOW_WRITE, - writable ? CMD_A_ALLOW_WRITE : 0); + struct i2c_client *client = to_i2c_client(smb->dev); + int ret; + + if (writable && irq_toggle && !smb->irq_unsupported) + disable_irq(client->irq); + + ret = regmap_update_bits(smb->regmap, CMD_A, CMD_A_ALLOW_WRITE, + writable ? CMD_A_ALLOW_WRITE : 0); + + if ((!writable || ret) && irq_toggle && !smb->irq_unsupported) + enable_irq(client->irq); + + return ret; } static int smb347_hw_init(struct smb347_charger *smb) @@ -682,7 +702,7 @@ static int smb347_hw_init(struct smb347_charger *smb) unsigned int val; int ret; - ret = smb347_set_writable(smb, true); + ret = smb347_set_writable(smb, true, false); if (ret < 0) return ret; @@ -724,6 +744,15 @@ static int smb347_hw_init(struct smb347_charger *smb) if (ret < 0) goto fail; + /* Activate pin control, making it writable. */ + switch (smb->enable_control) { + case SMB3XX_CHG_ENABLE_PIN_ACTIVE_LOW: + case SMB3XX_CHG_ENABLE_PIN_ACTIVE_HIGH: + ret = regmap_set_bits(smb->regmap, CFG_PIN, CFG_PIN_EN_CTRL); + if (ret < 0) + goto fail; + } + /* * Make the charging functionality controllable by a write to the * command register unless pin control is specified in the platform @@ -758,7 +787,7 @@ static int smb347_hw_init(struct smb347_charger *smb) ret = smb347_start_stop_charging(smb); fail: - smb347_set_writable(smb, false); + smb347_set_writable(smb, false, false); return ret; } @@ -866,7 +895,7 @@ static int smb347_irq_set(struct smb347_charger *smb, bool enable) if (smb->irq_unsupported) return 0; - ret = smb347_set_writable(smb, true); + ret = smb347_set_writable(smb, true, true); if (ret < 0) return ret; @@ -891,7 +920,7 @@ static int smb347_irq_set(struct smb347_charger *smb, bool enable) ret = regmap_update_bits(smb->regmap, CFG_PIN, CFG_PIN_EN_CHARGER_ERROR, enable ? CFG_PIN_EN_CHARGER_ERROR : 0); fail: - smb347_set_writable(smb, false); + smb347_set_writable(smb, false, true); return ret; } @@ -919,7 +948,7 @@ static int smb347_irq_init(struct smb347_charger *smb, if (!client->irq) return 0; - ret = smb347_set_writable(smb, true); + ret = smb347_set_writable(smb, true, false); if (ret < 0) return ret; @@ -931,7 +960,7 @@ static int smb347_irq_init(struct smb347_charger *smb, CFG_STAT_ACTIVE_HIGH | CFG_STAT_DISABLED, CFG_STAT_DISABLED); - smb347_set_writable(smb, false); + smb347_set_writable(smb, false, false); if (ret < 0) { dev_warn(smb->dev, "failed to initialize IRQ: %d\n", ret); @@ -1241,6 +1270,13 @@ static void smb347_dt_parse_dev_info(struct smb347_charger *smb) /* Select charging control */ device_property_read_u32(dev, "summit,enable-charge-control", &smb->enable_control); + + /* + * Polarity of INOK signal indicating presence of external power + * supply connected to the charger. + */ + device_property_read_u32(dev, "summit,inok-polarity", + &smb->inok_polarity); } static int smb347_get_battery_info(struct smb347_charger *smb) @@ -1292,12 +1328,176 @@ static int smb347_get_battery_info(struct smb347_charger *smb) return 0; } +static int smb347_usb_vbus_get_current_limit(struct regulator_dev *rdev) +{ + struct smb347_charger *smb = rdev_get_drvdata(rdev); + unsigned int val; + int ret; + + ret = regmap_read(smb->regmap, CFG_OTG, &val); + if (ret < 0) + return ret; + + /* + * It's unknown what happens if this bit is unset due to lack of + * access to the datasheet, assume it's limit-enable. + */ + if (!(val & CFG_OTG_CURRENT_LIMIT_250mA)) + return 0; + + return val & CFG_OTG_CURRENT_LIMIT_750mA ? 750000 : 250000; +} + +static int smb347_usb_vbus_set_new_current_limit(struct smb347_charger *smb, + int max_uA) +{ + const unsigned int mask = CFG_OTG_CURRENT_LIMIT_750mA | + CFG_OTG_CURRENT_LIMIT_250mA; + unsigned int val = CFG_OTG_CURRENT_LIMIT_250mA; + int ret; + + if (max_uA >= 750000) + val |= CFG_OTG_CURRENT_LIMIT_750mA; + + ret = regmap_update_bits(smb->regmap, CFG_OTG, mask, val); + if (ret < 0) + dev_err(smb->dev, "failed to change USB current limit\n"); + + return ret; +} + +static int smb347_usb_vbus_set_current_limit(struct regulator_dev *rdev, + int min_uA, int max_uA) +{ + struct smb347_charger *smb = rdev_get_drvdata(rdev); + int ret; + + ret = smb347_set_writable(smb, true, true); + if (ret < 0) + return ret; + + ret = smb347_usb_vbus_set_new_current_limit(smb, max_uA); + smb347_set_writable(smb, false, true); + + return ret; +} + +static int smb347_usb_vbus_regulator_enable(struct regulator_dev *rdev) +{ + struct smb347_charger *smb = rdev_get_drvdata(rdev); + int ret, max_uA; + + ret = smb347_set_writable(smb, true, true); + if (ret < 0) + return ret; + + smb347_charging_disable(smb); + + if (device_property_read_bool(&rdev->dev, "summit,needs-inok-toggle")) { + unsigned int sysok = 0; + + if (smb->inok_polarity == SMB3XX_SYSOK_INOK_ACTIVE_LOW) + sysok = CFG_SYSOK_INOK_ACTIVE_HIGH; + + /* + * VBUS won't be powered if INOK is active, so we need to + * manually disable INOK on some platforms. + */ + ret = regmap_update_bits(smb->regmap, CFG_SYSOK, + CFG_SYSOK_INOK_ACTIVE_HIGH, sysok); + if (ret < 0) { + dev_err(smb->dev, "failed to disable INOK\n"); + goto done; + } + } + + ret = smb347_usb_vbus_get_current_limit(rdev); + if (ret < 0) { + dev_err(smb->dev, "failed to get USB VBUS current limit\n"); + goto done; + } + + max_uA = ret; + + ret = smb347_usb_vbus_set_new_current_limit(smb, 250000); + if (ret < 0) { + dev_err(smb->dev, "failed to preset USB VBUS current limit\n"); + goto done; + } + + ret = regmap_set_bits(smb->regmap, CMD_A, CMD_A_OTG_ENABLED); + if (ret < 0) { + dev_err(smb->dev, "failed to enable USB VBUS\n"); + goto done; + } + + smb->usb_vbus_enabled = true; + + ret = smb347_usb_vbus_set_new_current_limit(smb, max_uA); + if (ret < 0) { + dev_err(smb->dev, "failed to restore USB VBUS current limit\n"); + goto done; + } +done: + smb347_set_writable(smb, false, true); + + return ret; +} + +static int smb347_usb_vbus_regulator_disable(struct regulator_dev *rdev) +{ + struct smb347_charger *smb = rdev_get_drvdata(rdev); + int ret; + + ret = smb347_set_writable(smb, true, true); + if (ret < 0) + return ret; + + ret = regmap_clear_bits(smb->regmap, CMD_A, CMD_A_OTG_ENABLED); + if (ret < 0) { + dev_err(smb->dev, "failed to disable USB VBUS\n"); + goto done; + } + + smb->usb_vbus_enabled = false; + + if (device_property_read_bool(&rdev->dev, "summit,needs-inok-toggle")) { + unsigned int sysok = 0; + + if (smb->inok_polarity == SMB3XX_SYSOK_INOK_ACTIVE_HIGH) + sysok = CFG_SYSOK_INOK_ACTIVE_HIGH; + + ret = regmap_update_bits(smb->regmap, CFG_SYSOK, + CFG_SYSOK_INOK_ACTIVE_HIGH, sysok); + if (ret < 0) { + dev_err(smb->dev, "failed to enable INOK\n"); + goto done; + } + } + + smb347_start_stop_charging(smb); +done: + smb347_set_writable(smb, false, true); + + return ret; +} + static const struct regmap_config smb347_regmap = { .reg_bits = 8, .val_bits = 8, .max_register = SMB347_MAX_REGISTER, .volatile_reg = smb347_volatile_reg, .readable_reg = smb347_readable_reg, + .cache_type = REGCACHE_FLAT, + .num_reg_defaults_raw = SMB347_MAX_REGISTER, +}; + +static const struct regulator_ops smb347_usb_vbus_regulator_ops = { + .is_enabled = regulator_is_enabled_regmap, + .enable = smb347_usb_vbus_regulator_enable, + .disable = smb347_usb_vbus_regulator_disable, + .get_current_limit = smb347_usb_vbus_get_current_limit, + .set_current_limit = smb347_usb_vbus_set_current_limit, }; static const struct power_supply_desc smb347_mains_desc = { @@ -1316,10 +1516,24 @@ static const struct power_supply_desc smb347_usb_desc = { .num_properties = ARRAY_SIZE(smb347_properties), }; +static const struct regulator_desc smb347_usb_vbus_regulator_desc = { + .name = "smb347-usb-vbus", + .of_match = of_match_ptr("usb-vbus"), + .ops = &smb347_usb_vbus_regulator_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE, + .enable_reg = CMD_A, + .enable_mask = CMD_A_OTG_ENABLED, + .enable_val = CMD_A_OTG_ENABLED, + .fixed_uV = 5000000, + .n_voltages = 1, +}; + static int smb347_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct power_supply_config mains_usb_cfg = {}; + struct regulator_config usb_rdev_cfg = {}; struct device *dev = &client->dev; struct smb347_charger *smb; int ret; @@ -1367,6 +1581,18 @@ static int smb347_probe(struct i2c_client *client, if (ret) return ret; + usb_rdev_cfg.dev = dev; + usb_rdev_cfg.driver_data = smb; + usb_rdev_cfg.regmap = smb->regmap; + + smb->usb_rdev = devm_regulator_register(dev, + &smb347_usb_vbus_regulator_desc, + &usb_rdev_cfg); + if (IS_ERR(smb->usb_rdev)) { + smb347_irq_disable(smb); + return PTR_ERR(smb->usb_rdev); + } + return 0; } @@ -1374,11 +1600,17 @@ static int smb347_remove(struct i2c_client *client) { struct smb347_charger *smb = i2c_get_clientdata(client); + smb347_usb_vbus_regulator_disable(smb->usb_rdev); smb347_irq_disable(smb); return 0; } +static void smb347_shutdown(struct i2c_client *client) +{ + smb347_remove(client); +} + static const struct i2c_device_id smb347_id[] = { { "smb345", SMB345 }, { "smb347", SMB347 }, @@ -1402,6 +1634,7 @@ static struct i2c_driver smb347_driver = { }, .probe = smb347_probe, .remove = smb347_remove, + .shutdown = smb347_shutdown, .id_table = smb347_id, }; module_i2c_driver(smb347_driver); diff --git a/drivers/ptp/Kconfig b/drivers/ptp/Kconfig index 8c20e524e9ad..e085c255da0c 100644 --- a/drivers/ptp/Kconfig +++ b/drivers/ptp/Kconfig @@ -90,7 +90,8 @@ config PTP_1588_CLOCK_INES config PTP_1588_CLOCK_PCH tristate "Intel PCH EG20T as PTP clock" depends on X86_32 || COMPILE_TEST - depends on HAS_IOMEM && NET + depends on HAS_IOMEM && PCI + depends on NET imply PTP_1588_CLOCK help This driver adds support for using the PCH EG20T as a PTP diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index 24ce9a17ab4f..4fd13b06231f 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -1044,7 +1044,7 @@ config REGULATOR_RT6160 help This adds support for voltage regulator in Richtek RT6160. This device automatically change voltage output mode from - Buck or Boost. The mode transistion depend on the input source voltage. + Buck or Boost. The mode transition depend on the input source voltage. The wide output range is from 2025mV to 5200mV and can be used on most common application scenario. @@ -1053,10 +1053,21 @@ config REGULATOR_RT6245 depends on I2C select REGMAP_I2C help - This adds supprot for Richtek RT6245 voltage regulator. + This adds support for Richtek RT6245 voltage regulator. It can support up to 14A output current and adjustable output voltage from 0.4375V to 1.3875V, per step 12.5mV. +config REGULATOR_RTQ2134 + tristate "Richtek RTQ2134 SubPMIC Regulator" + depends on I2C + select REGMAP_I2C + help + This driver adds support for RTQ2134 SubPMIC regulators. + The RTQ2134 is a multi-phase, programmable power management IC that + integrate with four high efficient, synchronous step-down converter + cores. It features wide output voltage range and the capability to + configure the corresponding power stages. + config REGULATOR_RTMV20 tristate "Richtek RTMV20 Laser Diode Regulator" depends on I2C @@ -1066,6 +1077,15 @@ config REGULATOR_RTMV20 the Richtek RTMV20. It can support the load current up to 6A and integrate strobe/vsync/fsin signal to synchronize the IR camera. +config REGULATOR_RTQ6752 + tristate "Richtek RTQ6752 TFT LCD voltage regulator" + depends on I2C + select REGMAP_I2C + help + This driver adds support for Richtek RTQ6752. RTQ6752 includes two + synchronous boost converters for PAVDD, and one synchronous NAVDD + buck-boost. This device is suitable for automotive TFT-LCD panel. + config REGULATOR_S2MPA01 tristate "Samsung S2MPA01 voltage regulator" depends on MFD_SEC_CORE || COMPILE_TEST diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 8c2f82206b94..9e382b50a5ef 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -128,6 +128,8 @@ obj-$(CONFIG_REGULATOR_RT5033) += rt5033-regulator.o obj-$(CONFIG_REGULATOR_RT6160) += rt6160-regulator.o obj-$(CONFIG_REGULATOR_RT6245) += rt6245-regulator.o obj-$(CONFIG_REGULATOR_RTMV20) += rtmv20-regulator.o +obj-$(CONFIG_REGULATOR_RTQ2134) += rtq2134-regulator.o +obj-$(CONFIG_REGULATOR_RTQ6752) += rtq6752-regulator.o obj-$(CONFIG_REGULATOR_S2MPA01) += s2mpa01.o obj-$(CONFIG_REGULATOR_S2MPS11) += s2mps11.o obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o diff --git a/drivers/regulator/bd718x7-regulator.c b/drivers/regulator/bd718x7-regulator.c index b1eb46961993..d60fccedb250 100644 --- a/drivers/regulator/bd718x7-regulator.c +++ b/drivers/regulator/bd718x7-regulator.c @@ -55,7 +55,8 @@ #define BD718XX_HWOPNAME(swopname) swopname##_hwcontrol #define BD718XX_OPS(name, _list_voltage, _map_voltage, _set_voltage_sel, \ - _get_voltage_sel, _set_voltage_time_sel, _set_ramp_delay) \ + _get_voltage_sel, _set_voltage_time_sel, _set_ramp_delay, \ + _set_uvp, _set_ovp) \ static const struct regulator_ops name = { \ .enable = regulator_enable_regmap, \ .disable = regulator_disable_regmap, \ @@ -66,6 +67,8 @@ static const struct regulator_ops name = { \ .get_voltage_sel = (_get_voltage_sel), \ .set_voltage_time_sel = (_set_voltage_time_sel), \ .set_ramp_delay = (_set_ramp_delay), \ + .set_under_voltage_protection = (_set_uvp), \ + .set_over_voltage_protection = (_set_ovp), \ }; \ \ static const struct regulator_ops BD718XX_HWOPNAME(name) = { \ @@ -76,6 +79,8 @@ static const struct regulator_ops BD718XX_HWOPNAME(name) = { \ .get_voltage_sel = (_get_voltage_sel), \ .set_voltage_time_sel = (_set_voltage_time_sel), \ .set_ramp_delay = (_set_ramp_delay), \ + .set_under_voltage_protection = (_set_uvp), \ + .set_over_voltage_protection = (_set_ovp), \ } \ /* @@ -154,17 +159,9 @@ static void voltage_change_done(struct regulator_dev *rdev, unsigned int sel, * exceed it due to the scheduling. */ msleep(1); - /* - * Note for next hacker. The PWRGOOD should not be masked on - * BD71847 so we will just unconditionally enable detection - * when voltage is set. - * If someone want's to disable PWRGOOD he must implement - * caching and restoring the old value here. I am not - * aware of such use-cases so for the sake of the simplicity - * we just always enable PWRGOOD here. - */ - ret = regmap_update_bits(rdev->regmap, BD718XX_REG_MVRFLTMASK2, - *mask, 0); + + ret = regmap_clear_bits(rdev->regmap, BD718XX_REG_MVRFLTMASK2, + *mask); if (ret) dev_err(&rdev->dev, "Failed to re-enable voltage monitoring (%d)\n", @@ -208,12 +205,27 @@ static int voltage_change_prepare(struct regulator_dev *rdev, unsigned int sel, * time configurable. */ if (new > now) { + int tmp; + int prot_bit; int ldo_offset = rdev->desc->id - BD718XX_LDO1; - *mask = BD718XX_LDO1_VRMON80 << ldo_offset; - ret = regmap_update_bits(rdev->regmap, - BD718XX_REG_MVRFLTMASK2, - *mask, *mask); + prot_bit = BD718XX_LDO1_VRMON80 << ldo_offset; + ret = regmap_read(rdev->regmap, BD718XX_REG_MVRFLTMASK2, + &tmp); + if (ret) { + dev_err(&rdev->dev, + "Failed to read voltage monitoring state\n"); + return ret; + } + + if (!(tmp & prot_bit)) { + /* We disable protection if it was enabled... */ + ret = regmap_set_bits(rdev->regmap, + BD718XX_REG_MVRFLTMASK2, + prot_bit); + /* ...and we also want to re-enable it */ + *mask = prot_bit; + } if (ret) { dev_err(&rdev->dev, "Failed to stop voltage monitoring\n"); @@ -267,99 +279,6 @@ static int bd71837_set_voltage_sel_pickable_restricted( } /* - * OPS common for BD71847 and BD71850 - */ -BD718XX_OPS(bd718xx_pickable_range_ldo_ops, - regulator_list_voltage_pickable_linear_range, NULL, - bd718xx_set_voltage_sel_pickable_restricted, - regulator_get_voltage_sel_pickable_regmap, NULL, NULL); - -/* BD71847 and BD71850 LDO 5 is by default OFF at RUN state */ -static const struct regulator_ops bd718xx_ldo5_ops_hwstate = { - .is_enabled = never_enabled_by_hwstate, - .list_voltage = regulator_list_voltage_pickable_linear_range, - .set_voltage_sel = bd718xx_set_voltage_sel_pickable_restricted, - .get_voltage_sel = regulator_get_voltage_sel_pickable_regmap, -}; - -BD718XX_OPS(bd718xx_pickable_range_buck_ops, - regulator_list_voltage_pickable_linear_range, NULL, - regulator_set_voltage_sel_pickable_regmap, - regulator_get_voltage_sel_pickable_regmap, - regulator_set_voltage_time_sel, NULL); - -BD718XX_OPS(bd718xx_ldo_regulator_ops, regulator_list_voltage_linear_range, - NULL, bd718xx_set_voltage_sel_restricted, - regulator_get_voltage_sel_regmap, NULL, NULL); - -BD718XX_OPS(bd718xx_ldo_regulator_nolinear_ops, regulator_list_voltage_table, - NULL, bd718xx_set_voltage_sel_restricted, - regulator_get_voltage_sel_regmap, NULL, NULL); - -BD718XX_OPS(bd718xx_buck_regulator_ops, regulator_list_voltage_linear_range, - NULL, regulator_set_voltage_sel_regmap, - regulator_get_voltage_sel_regmap, regulator_set_voltage_time_sel, - NULL); - -BD718XX_OPS(bd718xx_buck_regulator_nolinear_ops, regulator_list_voltage_table, - regulator_map_voltage_ascend, regulator_set_voltage_sel_regmap, - regulator_get_voltage_sel_regmap, regulator_set_voltage_time_sel, - NULL); - -/* - * OPS for BD71837 - */ -BD718XX_OPS(bd71837_pickable_range_ldo_ops, - regulator_list_voltage_pickable_linear_range, NULL, - bd71837_set_voltage_sel_pickable_restricted, - regulator_get_voltage_sel_pickable_regmap, NULL, NULL); - -BD718XX_OPS(bd71837_pickable_range_buck_ops, - regulator_list_voltage_pickable_linear_range, NULL, - bd71837_set_voltage_sel_pickable_restricted, - regulator_get_voltage_sel_pickable_regmap, - regulator_set_voltage_time_sel, NULL); - -BD718XX_OPS(bd71837_ldo_regulator_ops, regulator_list_voltage_linear_range, - NULL, bd71837_set_voltage_sel_restricted, - regulator_get_voltage_sel_regmap, NULL, NULL); - -BD718XX_OPS(bd71837_ldo_regulator_nolinear_ops, regulator_list_voltage_table, - NULL, bd71837_set_voltage_sel_restricted, - regulator_get_voltage_sel_regmap, NULL, NULL); - -BD718XX_OPS(bd71837_buck_regulator_ops, regulator_list_voltage_linear_range, - NULL, bd71837_set_voltage_sel_restricted, - regulator_get_voltage_sel_regmap, regulator_set_voltage_time_sel, - NULL); - -BD718XX_OPS(bd71837_buck_regulator_nolinear_ops, regulator_list_voltage_table, - regulator_map_voltage_ascend, bd71837_set_voltage_sel_restricted, - regulator_get_voltage_sel_regmap, regulator_set_voltage_time_sel, - NULL); -/* - * BD71837 bucks 3 and 4 support defining their enable/disable state also - * when buck enable state is under HW state machine control. In that case the - * bit [2] in CTRL register is used to indicate if regulator should be ON. - */ -static const struct regulator_ops bd71837_buck34_ops_hwctrl = { - .is_enabled = bd71837_get_buck34_enable_hwctrl, - .list_voltage = regulator_list_voltage_linear_range, - .set_voltage_sel = regulator_set_voltage_sel_regmap, - .get_voltage_sel = regulator_get_voltage_sel_regmap, - .set_voltage_time_sel = regulator_set_voltage_time_sel, - .set_ramp_delay = regulator_set_ramp_delay_regmap, -}; - -/* - * OPS for all of the ICs - BD718(37/47/50) - */ -BD718XX_OPS(bd718xx_dvs_buck_regulator_ops, regulator_list_voltage_linear_range, - NULL, regulator_set_voltage_sel_regmap, - regulator_get_voltage_sel_regmap, regulator_set_voltage_time_sel, - /* bd718xx_buck1234_set_ramp_delay */ regulator_set_ramp_delay_regmap); - -/* * BD71837 BUCK1/2/3/4 * BD71847 BUCK1/2 * 0.70 to 1.30V (10mV step) @@ -536,6 +455,238 @@ struct bd718xx_regulator_data { int additional_init_amnt; }; +static int bd718x7_xvp_sanity_check(struct regulator_dev *rdev, int lim_uV, + int severity) +{ + /* + * BD71837/47/50 ... (ICs supported by this driver) do not provide + * warnings, only protection + */ + if (severity != REGULATOR_SEVERITY_PROT) { + dev_err(&rdev->dev, + "Unsupported Under Voltage protection level\n"); + return -EINVAL; + } + + /* + * And protection limit is not changeable. It can only be enabled + * or disabled + */ + if (lim_uV) + return -EINVAL; + + return 0; +} + +static int bd718x7_set_ldo_uvp(struct regulator_dev *rdev, int lim_uV, + int severity, bool enable) +{ + int ldo_offset = rdev->desc->id - BD718XX_LDO1; + int prot_bit, ret; + + ret = bd718x7_xvp_sanity_check(rdev, lim_uV, severity); + if (ret) + return ret; + + prot_bit = BD718XX_LDO1_VRMON80 << ldo_offset; + + if (enable) + return regmap_clear_bits(rdev->regmap, BD718XX_REG_MVRFLTMASK2, + prot_bit); + + return regmap_set_bits(rdev->regmap, BD718XX_REG_MVRFLTMASK2, + prot_bit); +} + +static int bd718x7_get_buck_prot_reg(int id, int *reg) +{ + + if (id > BD718XX_BUCK8) { + WARN_ON(id > BD718XX_BUCK8); + return -EINVAL; + } + + if (id > BD718XX_BUCK4) + *reg = BD718XX_REG_MVRFLTMASK0; + else + *reg = BD718XX_REG_MVRFLTMASK1; + + return 0; +} + +static int bd718x7_get_buck_ovp_info(int id, int *reg, int *bit) +{ + int ret; + + ret = bd718x7_get_buck_prot_reg(id, reg); + if (ret) + return ret; + + *bit = BIT((id % 4) * 2 + 1); + + return 0; +} + +static int bd718x7_get_buck_uvp_info(int id, int *reg, int *bit) +{ + int ret; + + ret = bd718x7_get_buck_prot_reg(id, reg); + if (ret) + return ret; + + *bit = BIT((id % 4) * 2); + + return 0; +} + +static int bd718x7_set_buck_uvp(struct regulator_dev *rdev, int lim_uV, + int severity, bool enable) +{ + int bit, reg, ret; + + ret = bd718x7_xvp_sanity_check(rdev, lim_uV, severity); + if (ret) + return ret; + + ret = bd718x7_get_buck_uvp_info(rdev->desc->id, ®, &bit); + if (ret) + return ret; + + if (enable) + return regmap_clear_bits(rdev->regmap, reg, bit); + + return regmap_set_bits(rdev->regmap, reg, bit); + +} + +static int bd718x7_set_buck_ovp(struct regulator_dev *rdev, int lim_uV, + int severity, + bool enable) +{ + int bit, reg, ret; + + ret = bd718x7_xvp_sanity_check(rdev, lim_uV, severity); + if (ret) + return ret; + + ret = bd718x7_get_buck_ovp_info(rdev->desc->id, ®, &bit); + if (ret) + return ret; + + if (enable) + return regmap_clear_bits(rdev->regmap, reg, bit); + + return regmap_set_bits(rdev->regmap, reg, bit); +} + +/* + * OPS common for BD71847 and BD71850 + */ +BD718XX_OPS(bd718xx_pickable_range_ldo_ops, + regulator_list_voltage_pickable_linear_range, NULL, + bd718xx_set_voltage_sel_pickable_restricted, + regulator_get_voltage_sel_pickable_regmap, NULL, NULL, + bd718x7_set_ldo_uvp, NULL); + +/* BD71847 and BD71850 LDO 5 is by default OFF at RUN state */ +static const struct regulator_ops bd718xx_ldo5_ops_hwstate = { + .is_enabled = never_enabled_by_hwstate, + .list_voltage = regulator_list_voltage_pickable_linear_range, + .set_voltage_sel = bd718xx_set_voltage_sel_pickable_restricted, + .get_voltage_sel = regulator_get_voltage_sel_pickable_regmap, + .set_under_voltage_protection = bd718x7_set_ldo_uvp, +}; + +BD718XX_OPS(bd718xx_pickable_range_buck_ops, + regulator_list_voltage_pickable_linear_range, NULL, + regulator_set_voltage_sel_pickable_regmap, + regulator_get_voltage_sel_pickable_regmap, + regulator_set_voltage_time_sel, NULL, bd718x7_set_buck_uvp, + bd718x7_set_buck_ovp); + +BD718XX_OPS(bd718xx_ldo_regulator_ops, regulator_list_voltage_linear_range, + NULL, bd718xx_set_voltage_sel_restricted, + regulator_get_voltage_sel_regmap, NULL, NULL, bd718x7_set_ldo_uvp, + NULL); + +BD718XX_OPS(bd718xx_ldo_regulator_nolinear_ops, regulator_list_voltage_table, + NULL, bd718xx_set_voltage_sel_restricted, + regulator_get_voltage_sel_regmap, NULL, NULL, bd718x7_set_ldo_uvp, + NULL); + +BD718XX_OPS(bd718xx_buck_regulator_ops, regulator_list_voltage_linear_range, + NULL, regulator_set_voltage_sel_regmap, + regulator_get_voltage_sel_regmap, regulator_set_voltage_time_sel, + NULL, bd718x7_set_buck_uvp, bd718x7_set_buck_ovp); + +BD718XX_OPS(bd718xx_buck_regulator_nolinear_ops, regulator_list_voltage_table, + regulator_map_voltage_ascend, regulator_set_voltage_sel_regmap, + regulator_get_voltage_sel_regmap, regulator_set_voltage_time_sel, + NULL, bd718x7_set_buck_uvp, bd718x7_set_buck_ovp); + +/* + * OPS for BD71837 + */ +BD718XX_OPS(bd71837_pickable_range_ldo_ops, + regulator_list_voltage_pickable_linear_range, NULL, + bd71837_set_voltage_sel_pickable_restricted, + regulator_get_voltage_sel_pickable_regmap, NULL, NULL, + bd718x7_set_ldo_uvp, NULL); + +BD718XX_OPS(bd71837_pickable_range_buck_ops, + regulator_list_voltage_pickable_linear_range, NULL, + bd71837_set_voltage_sel_pickable_restricted, + regulator_get_voltage_sel_pickable_regmap, + regulator_set_voltage_time_sel, NULL, bd718x7_set_buck_uvp, + bd718x7_set_buck_ovp); + +BD718XX_OPS(bd71837_ldo_regulator_ops, regulator_list_voltage_linear_range, + NULL, bd71837_set_voltage_sel_restricted, + regulator_get_voltage_sel_regmap, NULL, NULL, bd718x7_set_ldo_uvp, + NULL); + +BD718XX_OPS(bd71837_ldo_regulator_nolinear_ops, regulator_list_voltage_table, + NULL, bd71837_set_voltage_sel_restricted, + regulator_get_voltage_sel_regmap, NULL, NULL, bd718x7_set_ldo_uvp, + NULL); + +BD718XX_OPS(bd71837_buck_regulator_ops, regulator_list_voltage_linear_range, + NULL, bd71837_set_voltage_sel_restricted, + regulator_get_voltage_sel_regmap, regulator_set_voltage_time_sel, + NULL, bd718x7_set_buck_uvp, bd718x7_set_buck_ovp); + +BD718XX_OPS(bd71837_buck_regulator_nolinear_ops, regulator_list_voltage_table, + regulator_map_voltage_ascend, bd71837_set_voltage_sel_restricted, + regulator_get_voltage_sel_regmap, regulator_set_voltage_time_sel, + NULL, bd718x7_set_buck_uvp, bd718x7_set_buck_ovp); +/* + * BD71837 bucks 3 and 4 support defining their enable/disable state also + * when buck enable state is under HW state machine control. In that case the + * bit [2] in CTRL register is used to indicate if regulator should be ON. + */ +static const struct regulator_ops bd71837_buck34_ops_hwctrl = { + .is_enabled = bd71837_get_buck34_enable_hwctrl, + .list_voltage = regulator_list_voltage_linear_range, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_time_sel = regulator_set_voltage_time_sel, + .set_ramp_delay = regulator_set_ramp_delay_regmap, + .set_under_voltage_protection = bd718x7_set_buck_uvp, + .set_over_voltage_protection = bd718x7_set_buck_ovp, +}; + +/* + * OPS for all of the ICs - BD718(37/47/50) + */ +BD718XX_OPS(bd718xx_dvs_buck_regulator_ops, regulator_list_voltage_linear_range, + NULL, regulator_set_voltage_sel_regmap, + regulator_get_voltage_sel_regmap, regulator_set_voltage_time_sel, + regulator_set_ramp_delay_regmap, bd718x7_set_buck_uvp, + bd718x7_set_buck_ovp); + + + /* * There is a HW quirk in BD71837. The shutdown sequence timings for * bucks/LDOs which are controlled via register interface are changed. diff --git a/drivers/regulator/da9063-regulator.c b/drivers/regulator/da9063-regulator.c index cf7d5341750e..82f52a2a031a 100644 --- a/drivers/regulator/da9063-regulator.c +++ b/drivers/regulator/da9063-regulator.c @@ -412,6 +412,134 @@ static int da9063_ldo_set_suspend_mode(struct regulator_dev *rdev, return regmap_field_write(regl->suspend_sleep, val); } +static unsigned int da9063_get_overdrive_mask(const struct regulator_desc *desc) +{ + switch (desc->id) { + case DA9063_ID_BCORES_MERGED: + case DA9063_ID_BCORE1: + return DA9063_BCORE1_OD; + case DA9063_ID_BCORE2: + return DA9063_BCORE2_OD; + case DA9063_ID_BPRO: + return DA9063_BPRO_OD; + default: + return 0; + } +} + +static int da9063_buck_set_limit_set_overdrive(struct regulator_dev *rdev, + int min_uA, int max_uA, + unsigned int overdrive_mask) +{ + /* + * When enabling overdrive, do it before changing the current limit to + * ensure sufficient supply throughout the switch. + */ + struct da9063_regulator *regl = rdev_get_drvdata(rdev); + int ret; + unsigned int orig_overdrive; + + ret = regmap_read(regl->hw->regmap, DA9063_REG_CONFIG_H, + &orig_overdrive); + if (ret < 0) + return ret; + orig_overdrive &= overdrive_mask; + + if (orig_overdrive == 0) { + ret = regmap_set_bits(regl->hw->regmap, DA9063_REG_CONFIG_H, + overdrive_mask); + if (ret < 0) + return ret; + } + + ret = regulator_set_current_limit_regmap(rdev, min_uA / 2, max_uA / 2); + if (ret < 0 && orig_overdrive == 0) + /* + * regulator_set_current_limit_regmap may have rejected the + * change because of unusable min_uA and/or max_uA inputs. + * Attempt to restore original overdrive state, ignore failure- + * on-failure. + */ + regmap_clear_bits(regl->hw->regmap, DA9063_REG_CONFIG_H, + overdrive_mask); + + return ret; +} + +static int da9063_buck_set_limit_clear_overdrive(struct regulator_dev *rdev, + int min_uA, int max_uA, + unsigned int overdrive_mask) +{ + /* + * When disabling overdrive, do it after changing the current limit to + * ensure sufficient supply throughout the switch. + */ + struct da9063_regulator *regl = rdev_get_drvdata(rdev); + int ret, orig_limit; + + ret = regmap_read(rdev->regmap, rdev->desc->csel_reg, &orig_limit); + if (ret < 0) + return ret; + + ret = regulator_set_current_limit_regmap(rdev, min_uA, max_uA); + if (ret < 0) + return ret; + + ret = regmap_clear_bits(regl->hw->regmap, DA9063_REG_CONFIG_H, + overdrive_mask); + if (ret < 0) + /* + * Attempt to restore original current limit, ignore failure- + * on-failure. + */ + regmap_write(rdev->regmap, rdev->desc->csel_reg, orig_limit); + + return ret; +} + +static int da9063_buck_set_current_limit(struct regulator_dev *rdev, + int min_uA, int max_uA) +{ + unsigned int overdrive_mask, n_currents; + + overdrive_mask = da9063_get_overdrive_mask(rdev->desc); + if (overdrive_mask) { + n_currents = rdev->desc->n_current_limits; + if (n_currents == 0) + return -EINVAL; + + if (max_uA > rdev->desc->curr_table[n_currents - 1]) + return da9063_buck_set_limit_set_overdrive(rdev, min_uA, + max_uA, + overdrive_mask); + + return da9063_buck_set_limit_clear_overdrive(rdev, min_uA, + max_uA, + overdrive_mask); + } + return regulator_set_current_limit_regmap(rdev, min_uA, max_uA); +} + +static int da9063_buck_get_current_limit(struct regulator_dev *rdev) +{ + struct da9063_regulator *regl = rdev_get_drvdata(rdev); + int val, ret, limit; + unsigned int mask; + + limit = regulator_get_current_limit_regmap(rdev); + if (limit < 0) + return limit; + mask = da9063_get_overdrive_mask(rdev->desc); + if (mask) { + ret = regmap_read(regl->hw->regmap, DA9063_REG_CONFIG_H, &val); + if (ret < 0) + return ret; + if (val & mask) + limit *= 2; + } + return limit; +} + static const struct regulator_ops da9063_buck_ops = { .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, @@ -419,8 +547,8 @@ static const struct regulator_ops da9063_buck_ops = { .get_voltage_sel = regulator_get_voltage_sel_regmap, .set_voltage_sel = regulator_set_voltage_sel_regmap, .list_voltage = regulator_list_voltage_linear, - .set_current_limit = regulator_set_current_limit_regmap, - .get_current_limit = regulator_get_current_limit_regmap, + .set_current_limit = da9063_buck_set_current_limit, + .get_current_limit = da9063_buck_get_current_limit, .set_mode = da9063_buck_set_mode, .get_mode = da9063_buck_get_mode, .get_status = da9063_buck_get_status, diff --git a/drivers/regulator/dbx500-prcmu.c b/drivers/regulator/dbx500-prcmu.c index 8b70bfe88019..a45c1e1ac7ef 100644 --- a/drivers/regulator/dbx500-prcmu.c +++ b/drivers/regulator/dbx500-prcmu.c @@ -117,11 +117,11 @@ ux500_regulator_debug_init(struct platform_device *pdev, rdebug.dir = debugfs_create_dir("ux500-regulator", NULL); /* create "status" file */ - debugfs_create_file("status", S_IRUGO, rdebug.dir, &pdev->dev, + debugfs_create_file("status", 0444, rdebug.dir, &pdev->dev, &ux500_regulator_status_fops); /* create "power-state-count" file */ - debugfs_create_file("power-state-count", S_IRUGO, rdebug.dir, + debugfs_create_file("power-state-count", 0444, rdebug.dir, &pdev->dev, &ux500_regulator_power_state_cnt_fops); rdebug.regulator_array = regulator_info; diff --git a/drivers/regulator/devres.c b/drivers/regulator/devres.c index a8de0aa88bad..9113233f41cd 100644 --- a/drivers/regulator/devres.c +++ b/drivers/regulator/devres.c @@ -205,35 +205,6 @@ struct regulator_dev *devm_regulator_register(struct device *dev, } EXPORT_SYMBOL_GPL(devm_regulator_register); -static int devm_rdev_match(struct device *dev, void *res, void *data) -{ - struct regulator_dev **r = res; - if (!r || !*r) { - WARN_ON(!r || !*r); - return 0; - } - return *r == data; -} - -/** - * devm_regulator_unregister - Resource managed regulator_unregister() - * @dev: device to supply - * @rdev: regulator to free - * - * Unregister a regulator registered with devm_regulator_register(). - * Normally this function will not need to be called and the resource - * management code will ensure that the resource is freed. - */ -void devm_regulator_unregister(struct device *dev, struct regulator_dev *rdev) -{ - int rc; - - rc = devres_release(dev, devm_rdev_release, devm_rdev_match, rdev); - if (rc != 0) - WARN_ON(rc); -} -EXPORT_SYMBOL_GPL(devm_regulator_unregister); - struct regulator_supply_alias_match { struct device *dev; const char *id; @@ -296,19 +267,8 @@ int devm_regulator_register_supply_alias(struct device *dev, const char *id, } EXPORT_SYMBOL_GPL(devm_regulator_register_supply_alias); -/** - * devm_regulator_unregister_supply_alias - Resource managed - * regulator_unregister_supply_alias() - * - * @dev: device to supply - * @id: supply name or regulator ID - * - * Unregister an alias registered with - * devm_regulator_register_supply_alias(). Normally this function - * will not need to be called and the resource management code - * will ensure that the resource is freed. - */ -void devm_regulator_unregister_supply_alias(struct device *dev, const char *id) +static void devm_regulator_unregister_supply_alias(struct device *dev, + const char *id) { struct regulator_supply_alias_match match; int rc; @@ -321,7 +281,6 @@ void devm_regulator_unregister_supply_alias(struct device *dev, const char *id) if (rc != 0) WARN_ON(rc); } -EXPORT_SYMBOL_GPL(devm_regulator_unregister_supply_alias); /** * devm_regulator_bulk_register_supply_alias - Managed register @@ -373,30 +332,6 @@ err: } EXPORT_SYMBOL_GPL(devm_regulator_bulk_register_supply_alias); -/** - * devm_regulator_bulk_unregister_supply_alias - Managed unregister - * multiple aliases - * - * @dev: device to supply - * @id: list of supply names or regulator IDs - * @num_id: number of aliases to unregister - * - * Unregister aliases registered with - * devm_regulator_bulk_register_supply_alias(). Normally this function - * will not need to be called and the resource management code - * will ensure that the resource is freed. - */ -void devm_regulator_bulk_unregister_supply_alias(struct device *dev, - const char *const *id, - int num_id) -{ - int i; - - for (i = 0; i < num_id; ++i) - devm_regulator_unregister_supply_alias(dev, id[i]); -} -EXPORT_SYMBOL_GPL(devm_regulator_bulk_unregister_supply_alias); - struct regulator_notifier_match { struct regulator *regulator; struct notifier_block *nb; diff --git a/drivers/regulator/fixed.c b/drivers/regulator/fixed.c index 39284610a536..599ad201dca7 100644 --- a/drivers/regulator/fixed.c +++ b/drivers/regulator/fixed.c @@ -287,8 +287,9 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev) drvdata->dev = devm_regulator_register(&pdev->dev, &drvdata->desc, &cfg); if (IS_ERR(drvdata->dev)) { - ret = PTR_ERR(drvdata->dev); - dev_err(&pdev->dev, "Failed to register regulator: %d\n", ret); + ret = dev_err_probe(&pdev->dev, PTR_ERR(drvdata->dev), + "Failed to register regulator: %ld\n", + PTR_ERR(drvdata->dev)); return ret; } diff --git a/drivers/regulator/hi6421v600-regulator.c b/drivers/regulator/hi6421v600-regulator.c index 845bc3b4026d..662d87ae61cb 100644 --- a/drivers/regulator/hi6421v600-regulator.c +++ b/drivers/regulator/hi6421v600-regulator.c @@ -4,7 +4,7 @@ // // Copyright (c) 2013 Linaro Ltd. // Copyright (c) 2011 HiSilicon Ltd. -// Copyright (c) 2020-2021 Huawei Technologies Co., Ltd +// Copyright (c) 2020-2021 Huawei Technologies Co., Ltd. // // Guodong Xu <guodong.xu@linaro.org> @@ -27,34 +27,34 @@ struct hi6421_spmi_reg_info { u32 eco_uA; }; -static const unsigned int ldo3_voltages[] = { +static const unsigned int range_1v5_to_2v0[] = { 1500000, 1550000, 1600000, 1650000, 1700000, 1725000, 1750000, 1775000, 1800000, 1825000, 1850000, 1875000, 1900000, 1925000, 1950000, 2000000 }; -static const unsigned int ldo4_voltages[] = { +static const unsigned int range_1v725_to_1v9[] = { 1725000, 1750000, 1775000, 1800000, 1825000, 1850000, 1875000, 1900000 }; -static const unsigned int ldo9_voltages[] = { +static const unsigned int range_1v75_to_3v3[] = { 1750000, 1800000, 1825000, 2800000, 2850000, 2950000, 3000000, 3300000 }; -static const unsigned int ldo15_voltages[] = { +static const unsigned int range_1v8_to_3v0[] = { 1800000, 1850000, 2400000, 2600000, 2700000, 2850000, 2950000, 3000000 }; -static const unsigned int ldo17_voltages[] = { +static const unsigned int range_2v5_to_3v3[] = { 2500000, 2600000, 2700000, 2800000, 3000000, 3100000, 3200000, 3300000 }; -static const unsigned int ldo34_voltages[] = { +static const unsigned int range_2v6_to_3v3[] = { 2600000, 2700000, 2800000, 2900000, 3000000, 3100000, 3200000, 3300000 }; @@ -73,14 +73,14 @@ static const unsigned int ldo34_voltages[] = { */ #define HI6421V600_LDO(_id, vtable, ereg, emask, vreg, \ odelay, etime, ecomask, ecoamp) \ - [HI6421V600_##_id] = { \ + [hi6421v600_##_id] = { \ .desc = { \ .name = #_id, \ .of_match = of_match_ptr(#_id), \ .regulators_node = of_match_ptr("regulators"), \ .ops = &hi6421_spmi_ldo_rops, \ .type = REGULATOR_VOLTAGE, \ - .id = HI6421V600_##_id, \ + .id = hi6421v600_##_id, \ .owner = THIS_MODULE, \ .volt_table = vtable, \ .n_voltages = ARRAY_SIZE(vtable), \ @@ -185,46 +185,46 @@ static const struct regulator_ops hi6421_spmi_ldo_rops = { /* HI6421v600 regulators with known registers */ enum hi6421_spmi_regulator_id { - HI6421V600_LDO3, - HI6421V600_LDO4, - HI6421V600_LDO9, - HI6421V600_LDO15, - HI6421V600_LDO16, - HI6421V600_LDO17, - HI6421V600_LDO33, - HI6421V600_LDO34, + hi6421v600_ldo3, + hi6421v600_ldo4, + hi6421v600_ldo9, + hi6421v600_ldo15, + hi6421v600_ldo16, + hi6421v600_ldo17, + hi6421v600_ldo33, + hi6421v600_ldo34, }; static struct hi6421_spmi_reg_info regulator_info[] = { - HI6421V600_LDO(LDO3, ldo3_voltages, + HI6421V600_LDO(ldo3, range_1v5_to_2v0, 0x16, 0x01, 0x51, 20000, 120, 0, 0), - HI6421V600_LDO(LDO4, ldo4_voltages, + HI6421V600_LDO(ldo4, range_1v725_to_1v9, 0x17, 0x01, 0x52, 20000, 120, 0x10, 10000), - HI6421V600_LDO(LDO9, ldo9_voltages, + HI6421V600_LDO(ldo9, range_1v75_to_3v3, 0x1c, 0x01, 0x57, 20000, 360, 0x10, 10000), - HI6421V600_LDO(LDO15, ldo15_voltages, + HI6421V600_LDO(ldo15, range_1v8_to_3v0, 0x21, 0x01, 0x5c, 20000, 360, 0x10, 10000), - HI6421V600_LDO(LDO16, ldo15_voltages, + HI6421V600_LDO(ldo16, range_1v8_to_3v0, 0x22, 0x01, 0x5d, 20000, 360, 0x10, 10000), - HI6421V600_LDO(LDO17, ldo17_voltages, + HI6421V600_LDO(ldo17, range_2v5_to_3v3, 0x23, 0x01, 0x5e, 20000, 120, 0x10, 10000), - HI6421V600_LDO(LDO33, ldo17_voltages, + HI6421V600_LDO(ldo33, range_2v5_to_3v3, 0x32, 0x01, 0x6d, 20000, 120, 0, 0), - HI6421V600_LDO(LDO34, ldo34_voltages, + HI6421V600_LDO(ldo34, range_2v6_to_3v3, 0x33, 0x01, 0x6e, 20000, 120, 0, 0), diff --git a/drivers/regulator/irq_helpers.c b/drivers/regulator/irq_helpers.c index fabe2e53093e..522764435575 100644 --- a/drivers/regulator/irq_helpers.c +++ b/drivers/regulator/irq_helpers.c @@ -184,7 +184,7 @@ static irqreturn_t regulator_notifier_isr(int irq, void *data) * If retry_count exceeds the given safety limit we call IC specific die * handler which can try disabling regulator(s). * - * If no die handler is given we will just bug() as a last resort. + * If no die handler is given we will just power-off as a last resort. * * We could try disabling all associated rdevs - but we might shoot * ourselves in the head and leave the problematic regulator enabled. So diff --git a/drivers/regulator/mt6358-regulator.c b/drivers/regulator/mt6358-regulator.c index 0d35be4e0e5a..eb8027813b99 100644 --- a/drivers/regulator/mt6358-regulator.c +++ b/drivers/regulator/mt6358-regulator.c @@ -28,18 +28,15 @@ struct mt6358_regulator_info { u32 qi; const u32 *index_table; unsigned int n_table; - u32 vsel_shift; u32 da_vsel_reg; u32 da_vsel_mask; - u32 da_vsel_shift; u32 modeset_reg; u32 modeset_mask; - u32 modeset_shift; }; #define MT6358_BUCK(match, vreg, min, max, step, \ volt_ranges, vosel_mask, _da_vsel_reg, _da_vsel_mask, \ - _da_vsel_shift, _modeset_reg, _modeset_shift) \ + _modeset_reg, _modeset_shift) \ [MT6358_ID_##vreg] = { \ .desc = { \ .name = #vreg, \ @@ -61,15 +58,13 @@ struct mt6358_regulator_info { .qi = BIT(0), \ .da_vsel_reg = _da_vsel_reg, \ .da_vsel_mask = _da_vsel_mask, \ - .da_vsel_shift = _da_vsel_shift, \ .modeset_reg = _modeset_reg, \ .modeset_mask = BIT(_modeset_shift), \ - .modeset_shift = _modeset_shift \ } #define MT6358_LDO(match, vreg, ldo_volt_table, \ ldo_index_table, enreg, enbit, vosel, \ - vosel_mask, vosel_shift) \ + vosel_mask) \ [MT6358_ID_##vreg] = { \ .desc = { \ .name = #vreg, \ @@ -89,12 +84,11 @@ struct mt6358_regulator_info { .qi = BIT(15), \ .index_table = ldo_index_table, \ .n_table = ARRAY_SIZE(ldo_index_table), \ - .vsel_shift = vosel_shift, \ } #define MT6358_LDO1(match, vreg, min, max, step, \ volt_ranges, _da_vsel_reg, _da_vsel_mask, \ - _da_vsel_shift, vosel, vosel_mask) \ + vosel, vosel_mask) \ [MT6358_ID_##vreg] = { \ .desc = { \ .name = #vreg, \ @@ -113,7 +107,6 @@ struct mt6358_regulator_info { }, \ .da_vsel_reg = _da_vsel_reg, \ .da_vsel_mask = _da_vsel_mask, \ - .da_vsel_shift = _da_vsel_shift, \ .status_reg = MT6358_LDO_##vreg##_DBG1, \ .qi = BIT(0), \ } @@ -260,9 +253,9 @@ static int mt6358_set_voltage_sel(struct regulator_dev *rdev, pvol = info->index_table; idx = pvol[selector]; + idx <<= ffs(info->desc.vsel_mask) - 1; ret = regmap_update_bits(rdev->regmap, info->desc.vsel_reg, - info->desc.vsel_mask, - idx << info->vsel_shift); + info->desc.vsel_mask, idx); return ret; } @@ -282,7 +275,8 @@ static int mt6358_get_voltage_sel(struct regulator_dev *rdev) return ret; } - selector = (selector & info->desc.vsel_mask) >> info->vsel_shift; + selector = (selector & info->desc.vsel_mask) >> + (ffs(info->desc.vsel_mask) - 1); pvol = info->index_table; for (idx = 0; idx < info->desc.n_voltages; idx++) { if (pvol[idx] == selector) @@ -305,7 +299,7 @@ static int mt6358_get_buck_voltage_sel(struct regulator_dev *rdev) return ret; } - ret = (regval >> info->da_vsel_shift) & info->da_vsel_mask; + ret = (regval & info->da_vsel_mask) >> (ffs(info->da_vsel_mask) - 1); return ret; } @@ -342,11 +336,10 @@ static int mt6358_regulator_set_mode(struct regulator_dev *rdev, return -EINVAL; } - dev_dbg(&rdev->dev, "mt6358 buck set_mode %#x, %#x, %#x, %#x\n", - info->modeset_reg, info->modeset_mask, - info->modeset_shift, val); + dev_dbg(&rdev->dev, "mt6358 buck set_mode %#x, %#x, %#x\n", + info->modeset_reg, info->modeset_mask, val); - val <<= info->modeset_shift; + val <<= ffs(info->modeset_mask) - 1; return regmap_update_bits(rdev->regmap, info->modeset_reg, info->modeset_mask, val); @@ -364,7 +357,7 @@ static unsigned int mt6358_regulator_get_mode(struct regulator_dev *rdev) return ret; } - switch ((regval & info->modeset_mask) >> info->modeset_shift) { + switch ((regval & info->modeset_mask) >> (ffs(info->modeset_mask) - 1)) { case MT6358_BUCK_MODE_AUTO: return REGULATOR_MODE_NORMAL; case MT6358_BUCK_MODE_FORCE_PWM: @@ -412,30 +405,30 @@ static const struct regulator_ops mt6358_volt_fixed_ops = { static struct mt6358_regulator_info mt6358_regulators[] = { MT6358_BUCK("buck_vdram1", VDRAM1, 500000, 2087500, 12500, buck_volt_range2, 0x7f, MT6358_BUCK_VDRAM1_DBG0, 0x7f, - 0, MT6358_VDRAM1_ANA_CON0, 8), + MT6358_VDRAM1_ANA_CON0, 8), MT6358_BUCK("buck_vcore", VCORE, 500000, 1293750, 6250, buck_volt_range1, 0x7f, MT6358_BUCK_VCORE_DBG0, 0x7f, - 0, MT6358_VCORE_VGPU_ANA_CON0, 1), + MT6358_VCORE_VGPU_ANA_CON0, 1), MT6358_BUCK("buck_vpa", VPA, 500000, 3650000, 50000, - buck_volt_range3, 0x3f, MT6358_BUCK_VPA_DBG0, 0x3f, 0, + buck_volt_range3, 0x3f, MT6358_BUCK_VPA_DBG0, 0x3f, MT6358_VPA_ANA_CON0, 3), MT6358_BUCK("buck_vproc11", VPROC11, 500000, 1293750, 6250, buck_volt_range1, 0x7f, MT6358_BUCK_VPROC11_DBG0, 0x7f, - 0, MT6358_VPROC_ANA_CON0, 1), + MT6358_VPROC_ANA_CON0, 1), MT6358_BUCK("buck_vproc12", VPROC12, 500000, 1293750, 6250, buck_volt_range1, 0x7f, MT6358_BUCK_VPROC12_DBG0, 0x7f, - 0, MT6358_VPROC_ANA_CON0, 2), + MT6358_VPROC_ANA_CON0, 2), MT6358_BUCK("buck_vgpu", VGPU, 500000, 1293750, 6250, - buck_volt_range1, 0x7f, MT6358_BUCK_VGPU_ELR0, 0x7f, 0, + buck_volt_range1, 0x7f, MT6358_BUCK_VGPU_ELR0, 0x7f, MT6358_VCORE_VGPU_ANA_CON0, 2), MT6358_BUCK("buck_vs2", VS2, 500000, 2087500, 12500, - buck_volt_range2, 0x7f, MT6358_BUCK_VS2_DBG0, 0x7f, 0, + buck_volt_range2, 0x7f, MT6358_BUCK_VS2_DBG0, 0x7f, MT6358_VS2_ANA_CON0, 8), MT6358_BUCK("buck_vmodem", VMODEM, 500000, 1293750, 6250, buck_volt_range1, 0x7f, MT6358_BUCK_VMODEM_DBG0, 0x7f, - 0, MT6358_VMODEM_ANA_CON0, 8), + MT6358_VMODEM_ANA_CON0, 8), MT6358_BUCK("buck_vs1", VS1, 1000000, 2587500, 12500, - buck_volt_range4, 0x7f, MT6358_BUCK_VS1_DBG0, 0x7f, 0, + buck_volt_range4, 0x7f, MT6358_BUCK_VS1_DBG0, 0x7f, MT6358_VS1_ANA_CON0, 8), MT6358_REG_FIXED("ldo_vrf12", VRF12, MT6358_LDO_VRF12_CON0, 0, 1200000), @@ -457,49 +450,49 @@ static struct mt6358_regulator_info mt6358_regulators[] = { MT6358_REG_FIXED("ldo_vaud28", VAUD28, MT6358_LDO_VAUD28_CON0, 0, 2800000), MT6358_LDO("ldo_vdram2", VDRAM2, vdram2_voltages, vdram2_idx, - MT6358_LDO_VDRAM2_CON0, 0, MT6358_LDO_VDRAM2_ELR0, 0xf, 0), + MT6358_LDO_VDRAM2_CON0, 0, MT6358_LDO_VDRAM2_ELR0, 0xf), MT6358_LDO("ldo_vsim1", VSIM1, vsim_voltages, vsim_idx, - MT6358_LDO_VSIM1_CON0, 0, MT6358_VSIM1_ANA_CON0, 0xf00, 8), + MT6358_LDO_VSIM1_CON0, 0, MT6358_VSIM1_ANA_CON0, 0xf00), MT6358_LDO("ldo_vibr", VIBR, vibr_voltages, vibr_idx, - MT6358_LDO_VIBR_CON0, 0, MT6358_VIBR_ANA_CON0, 0xf00, 8), + MT6358_LDO_VIBR_CON0, 0, MT6358_VIBR_ANA_CON0, 0xf00), MT6358_LDO("ldo_vusb", VUSB, vusb_voltages, vusb_idx, - MT6358_LDO_VUSB_CON0_0, 0, MT6358_VUSB_ANA_CON0, 0x700, 8), + MT6358_LDO_VUSB_CON0_0, 0, MT6358_VUSB_ANA_CON0, 0x700), MT6358_LDO("ldo_vcamd", VCAMD, vcamd_voltages, vcamd_idx, - MT6358_LDO_VCAMD_CON0, 0, MT6358_VCAMD_ANA_CON0, 0xf00, 8), + MT6358_LDO_VCAMD_CON0, 0, MT6358_VCAMD_ANA_CON0, 0xf00), MT6358_LDO("ldo_vefuse", VEFUSE, vefuse_voltages, vefuse_idx, - MT6358_LDO_VEFUSE_CON0, 0, MT6358_VEFUSE_ANA_CON0, 0xf00, 8), + MT6358_LDO_VEFUSE_CON0, 0, MT6358_VEFUSE_ANA_CON0, 0xf00), MT6358_LDO("ldo_vmch", VMCH, vmch_vemc_voltages, vmch_vemc_idx, - MT6358_LDO_VMCH_CON0, 0, MT6358_VMCH_ANA_CON0, 0x700, 8), + MT6358_LDO_VMCH_CON0, 0, MT6358_VMCH_ANA_CON0, 0x700), MT6358_LDO("ldo_vcama1", VCAMA1, vcama_voltages, vcama_idx, - MT6358_LDO_VCAMA1_CON0, 0, MT6358_VCAMA1_ANA_CON0, 0xf00, 8), + MT6358_LDO_VCAMA1_CON0, 0, MT6358_VCAMA1_ANA_CON0, 0xf00), MT6358_LDO("ldo_vemc", VEMC, vmch_vemc_voltages, vmch_vemc_idx, - MT6358_LDO_VEMC_CON0, 0, MT6358_VEMC_ANA_CON0, 0x700, 8), + MT6358_LDO_VEMC_CON0, 0, MT6358_VEMC_ANA_CON0, 0x700), MT6358_LDO("ldo_vcn33_bt", VCN33_BT, vcn33_bt_wifi_voltages, vcn33_bt_wifi_idx, MT6358_LDO_VCN33_CON0_0, - 0, MT6358_VCN33_ANA_CON0, 0x300, 8), + 0, MT6358_VCN33_ANA_CON0, 0x300), MT6358_LDO("ldo_vcn33_wifi", VCN33_WIFI, vcn33_bt_wifi_voltages, vcn33_bt_wifi_idx, MT6358_LDO_VCN33_CON0_1, - 0, MT6358_VCN33_ANA_CON0, 0x300, 8), + 0, MT6358_VCN33_ANA_CON0, 0x300), MT6358_LDO("ldo_vcama2", VCAMA2, vcama_voltages, vcama_idx, - MT6358_LDO_VCAMA2_CON0, 0, MT6358_VCAMA2_ANA_CON0, 0xf00, 8), + MT6358_LDO_VCAMA2_CON0, 0, MT6358_VCAMA2_ANA_CON0, 0xf00), MT6358_LDO("ldo_vmc", VMC, vmc_voltages, vmc_idx, - MT6358_LDO_VMC_CON0, 0, MT6358_VMC_ANA_CON0, 0xf00, 8), + MT6358_LDO_VMC_CON0, 0, MT6358_VMC_ANA_CON0, 0xf00), MT6358_LDO("ldo_vldo28", VLDO28, vldo28_voltages, vldo28_idx, MT6358_LDO_VLDO28_CON0_0, 0, - MT6358_VLDO28_ANA_CON0, 0x300, 8), + MT6358_VLDO28_ANA_CON0, 0x300), MT6358_LDO("ldo_vsim2", VSIM2, vsim_voltages, vsim_idx, - MT6358_LDO_VSIM2_CON0, 0, MT6358_VSIM2_ANA_CON0, 0xf00, 8), + MT6358_LDO_VSIM2_CON0, 0, MT6358_VSIM2_ANA_CON0, 0xf00), MT6358_LDO1("ldo_vsram_proc11", VSRAM_PROC11, 500000, 1293750, 6250, - buck_volt_range1, MT6358_LDO_VSRAM_PROC11_DBG0, 0x7f, 8, + buck_volt_range1, MT6358_LDO_VSRAM_PROC11_DBG0, 0x7f00, MT6358_LDO_VSRAM_CON0, 0x7f), MT6358_LDO1("ldo_vsram_others", VSRAM_OTHERS, 500000, 1293750, 6250, - buck_volt_range1, MT6358_LDO_VSRAM_OTHERS_DBG0, 0x7f, 8, + buck_volt_range1, MT6358_LDO_VSRAM_OTHERS_DBG0, 0x7f00, MT6358_LDO_VSRAM_CON2, 0x7f), MT6358_LDO1("ldo_vsram_gpu", VSRAM_GPU, 500000, 1293750, 6250, - buck_volt_range1, MT6358_LDO_VSRAM_GPU_DBG0, 0x7f, 8, + buck_volt_range1, MT6358_LDO_VSRAM_GPU_DBG0, 0x7f00, MT6358_LDO_VSRAM_CON3, 0x7f), MT6358_LDO1("ldo_vsram_proc12", VSRAM_PROC12, 500000, 1293750, 6250, - buck_volt_range1, MT6358_LDO_VSRAM_PROC12_DBG0, 0x7f, 8, + buck_volt_range1, MT6358_LDO_VSRAM_PROC12_DBG0, 0x7f00, MT6358_LDO_VSRAM_CON1, 0x7f), }; diff --git a/drivers/regulator/mt6359-regulator.c b/drivers/regulator/mt6359-regulator.c index 7ce0bd377a08..de3b0462832c 100644 --- a/drivers/regulator/mt6359-regulator.c +++ b/drivers/regulator/mt6359-regulator.c @@ -27,7 +27,6 @@ * @qi: Mask for query enable signal status of regulators. * @modeset_reg: for operating AUTO/PWM mode register. * @modeset_mask: MASK for operating modeset register. - * @modeset_shift: SHIFT for operating modeset register. */ struct mt6359_regulator_info { struct regulator_desc desc; @@ -35,10 +34,8 @@ struct mt6359_regulator_info { u32 qi; u32 modeset_reg; u32 modeset_mask; - u32 modeset_shift; u32 lp_mode_reg; u32 lp_mode_mask; - u32 lp_mode_shift; }; #define MT6359_BUCK(match, _name, min, max, step, \ @@ -68,10 +65,8 @@ struct mt6359_regulator_info { .qi = BIT(0), \ .lp_mode_reg = _lp_mode_reg, \ .lp_mode_mask = BIT(_lp_mode_shift), \ - .lp_mode_shift = _lp_mode_shift, \ .modeset_reg = _modeset_reg, \ .modeset_mask = BIT(_modeset_shift), \ - .modeset_shift = _modeset_shift \ } #define MT6359_LDO_LINEAR(match, _name, min, max, step, \ @@ -282,8 +277,10 @@ static unsigned int mt6359_regulator_get_mode(struct regulator_dev *rdev) return ret; } - if ((regval & info->modeset_mask) >> info->modeset_shift == - MT6359_BUCK_MODE_FORCE_PWM) + regval &= info->modeset_mask; + regval >>= ffs(info->modeset_mask) - 1; + + if (regval == MT6359_BUCK_MODE_FORCE_PWM) return REGULATOR_MODE_FAST; ret = regmap_read(rdev->regmap, info->lp_mode_reg, ®val); @@ -310,7 +307,7 @@ static int mt6359_regulator_set_mode(struct regulator_dev *rdev, switch (mode) { case REGULATOR_MODE_FAST: val = MT6359_BUCK_MODE_FORCE_PWM; - val <<= info->modeset_shift; + val <<= ffs(info->modeset_mask) - 1; ret = regmap_update_bits(rdev->regmap, info->modeset_reg, info->modeset_mask, @@ -319,14 +316,14 @@ static int mt6359_regulator_set_mode(struct regulator_dev *rdev, case REGULATOR_MODE_NORMAL: if (curr_mode == REGULATOR_MODE_FAST) { val = MT6359_BUCK_MODE_AUTO; - val <<= info->modeset_shift; + val <<= ffs(info->modeset_mask) - 1; ret = regmap_update_bits(rdev->regmap, info->modeset_reg, info->modeset_mask, val); } else if (curr_mode == REGULATOR_MODE_IDLE) { val = MT6359_BUCK_MODE_NORMAL; - val <<= info->lp_mode_shift; + val <<= ffs(info->lp_mode_mask) - 1; ret = regmap_update_bits(rdev->regmap, info->lp_mode_reg, info->lp_mode_mask, @@ -336,7 +333,7 @@ static int mt6359_regulator_set_mode(struct regulator_dev *rdev, break; case REGULATOR_MODE_IDLE: val = MT6359_BUCK_MODE_LP >> 1; - val <<= info->lp_mode_shift; + val <<= ffs(info->lp_mode_mask) - 1; ret = regmap_update_bits(rdev->regmap, info->lp_mode_reg, info->lp_mode_mask, diff --git a/drivers/regulator/mt6397-regulator.c b/drivers/regulator/mt6397-regulator.c index 0a30df5e414f..b9bf7ade1f8a 100644 --- a/drivers/regulator/mt6397-regulator.c +++ b/drivers/regulator/mt6397-regulator.c @@ -32,7 +32,6 @@ struct mt6397_regulator_info { u32 vselctrl_mask; u32 modeset_reg; u32 modeset_mask; - u32 modeset_shift; }; #define MT6397_BUCK(match, vreg, min, max, step, volt_ranges, enreg, \ @@ -61,7 +60,6 @@ struct mt6397_regulator_info { .vselctrl_mask = BIT(1), \ .modeset_reg = _modeset_reg, \ .modeset_mask = BIT(_modeset_shift), \ - .modeset_shift = _modeset_shift \ } #define MT6397_LDO(match, vreg, ldo_volt_table, enreg, enbit, vosel, \ @@ -175,11 +173,11 @@ static int mt6397_regulator_set_mode(struct regulator_dev *rdev, goto err_mode; } - dev_dbg(&rdev->dev, "mt6397 buck set_mode %#x, %#x, %#x, %#x\n", - info->modeset_reg, info->modeset_mask, - info->modeset_shift, val); + dev_dbg(&rdev->dev, "mt6397 buck set_mode %#x, %#x, %#x\n", + info->modeset_reg, info->modeset_mask, val); + + val <<= ffs(info->modeset_mask) - 1; - val <<= info->modeset_shift; ret = regmap_update_bits(rdev->regmap, info->modeset_reg, info->modeset_mask, val); err_mode: @@ -204,7 +202,10 @@ static unsigned int mt6397_regulator_get_mode(struct regulator_dev *rdev) return ret; } - switch ((regval & info->modeset_mask) >> info->modeset_shift) { + regval &= info->modeset_mask; + regval >>= ffs(info->modeset_mask) - 1; + + switch (regval) { case MT6397_BUCK_MODE_AUTO: return REGULATOR_MODE_NORMAL; case MT6397_BUCK_MODE_FORCE_PWM: diff --git a/drivers/regulator/rt5033-regulator.c b/drivers/regulator/rt5033-regulator.c index 0e7311629165..da4cf5a6acc2 100644 --- a/drivers/regulator/rt5033-regulator.c +++ b/drivers/regulator/rt5033-regulator.c @@ -13,6 +13,16 @@ #include <linux/mfd/rt5033-private.h> #include <linux/regulator/of_regulator.h> +static const struct linear_range rt5033_buck_ranges[] = { + REGULATOR_LINEAR_RANGE(1000000, 0, 20, 100000), + REGULATOR_LINEAR_RANGE(3000000, 21, 31, 0), +}; + +static const struct linear_range rt5033_ldo_ranges[] = { + REGULATOR_LINEAR_RANGE(1200000, 0, 18, 100000), + REGULATOR_LINEAR_RANGE(3000000, 19, 31, 0), +}; + static const struct regulator_ops rt5033_safe_ldo_ops = { .is_enabled = regulator_is_enabled_regmap, .enable = regulator_enable_regmap, @@ -24,8 +34,7 @@ static const struct regulator_ops rt5033_buck_ops = { .is_enabled = regulator_is_enabled_regmap, .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, - .list_voltage = regulator_list_voltage_linear, - .map_voltage = regulator_map_voltage_linear, + .list_voltage = regulator_list_voltage_linear_range, .get_voltage_sel = regulator_get_voltage_sel_regmap, .set_voltage_sel = regulator_set_voltage_sel_regmap, }; @@ -40,8 +49,8 @@ static const struct regulator_desc rt5033_supported_regulators[] = { .type = REGULATOR_VOLTAGE, .owner = THIS_MODULE, .n_voltages = RT5033_REGULATOR_BUCK_VOLTAGE_STEP_NUM, - .min_uV = RT5033_REGULATOR_BUCK_VOLTAGE_MIN, - .uV_step = RT5033_REGULATOR_BUCK_VOLTAGE_STEP, + .linear_ranges = rt5033_buck_ranges, + .n_linear_ranges = ARRAY_SIZE(rt5033_buck_ranges), .enable_reg = RT5033_REG_CTRL, .enable_mask = RT5033_CTRL_EN_BUCK_MASK, .vsel_reg = RT5033_REG_BUCK_CTRL, @@ -56,8 +65,8 @@ static const struct regulator_desc rt5033_supported_regulators[] = { .type = REGULATOR_VOLTAGE, .owner = THIS_MODULE, .n_voltages = RT5033_REGULATOR_LDO_VOLTAGE_STEP_NUM, - .min_uV = RT5033_REGULATOR_LDO_VOLTAGE_MIN, - .uV_step = RT5033_REGULATOR_LDO_VOLTAGE_STEP, + .linear_ranges = rt5033_ldo_ranges, + .n_linear_ranges = ARRAY_SIZE(rt5033_ldo_ranges), .enable_reg = RT5033_REG_CTRL, .enable_mask = RT5033_CTRL_EN_LDO_MASK, .vsel_reg = RT5033_REG_LDO_CTRL, diff --git a/drivers/regulator/rt6245-regulator.c b/drivers/regulator/rt6245-regulator.c index d3299a72fd10..cb22a207e9ff 100644 --- a/drivers/regulator/rt6245-regulator.c +++ b/drivers/regulator/rt6245-regulator.c @@ -144,7 +144,7 @@ static int rt6245_init_device_properties(struct device *dev) static int rt6245_reg_write(void *context, unsigned int reg, unsigned int val) { struct i2c_client *i2c = context; - const u8 func_base[] = { 0x6F, 0x73, 0x78, 0x61, 0x7C, 0 }; + static const u8 func_base[] = { 0x6F, 0x73, 0x78, 0x61, 0x7C, 0 }; unsigned int code, bit_count; code = func_base[reg]; diff --git a/drivers/regulator/rtq2134-regulator.c b/drivers/regulator/rtq2134-regulator.c new file mode 100644 index 000000000000..f21e3f8b21f2 --- /dev/null +++ b/drivers/regulator/rtq2134-regulator.c @@ -0,0 +1,373 @@ +// SPDX-License-Identifier: GPL-2.0+ + +#include <linux/bitops.h> +#include <linux/i2c.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/regmap.h> +#include <linux/regulator/driver.h> + +enum { + RTQ2134_IDX_BUCK1 = 0, + RTQ2134_IDX_BUCK2, + RTQ2134_IDX_BUCK3, + RTQ2134_IDX_MAX +}; + +#define RTQ2134_AUTO_MODE 0 +#define RTQ2134_FCCM_MODE 1 + +#define RTQ2134_BUCK_DVS0_CTRL 0 +#define RTQ2134_BUCK_VSEL_CTRL 2 + +#define RTQ2134_REG_IO_CHIPNAME 0x01 +#define RTQ2134_REG_FLT_RECORDTEMP 0x13 +#define RTQ2134_REG_FLT_RECORDBUCK(_id) (0x14 + (_id)) +#define RTQ2134_REG_FLT_BUCKCTRL(_id) (0x37 + (_id)) +#define RTQ2134_REG_BUCK1_CFG0 0x42 +#define RTQ2134_REG_BUCK1_DVS0CFG1 0x48 +#define RTQ2134_REG_BUCK1_DVS0CFG0 0x49 +#define RTQ2134_REG_BUCK1_DVS1CFG1 0x4A +#define RTQ2134_REG_BUCK1_DVS1CFG0 0x4B +#define RTQ2134_REG_BUCK1_DVSCFG 0x52 +#define RTQ2134_REG_BUCK1_RSPCFG 0x54 +#define RTQ2134_REG_BUCK2_CFG0 0x5F +#define RTQ2134_REG_BUCK2_DVS0CFG1 0x62 +#define RTQ2134_REG_BUCK2_DVS0CFG0 0x63 +#define RTQ2134_REG_BUCK2_DVS1CFG1 0x64 +#define RTQ2134_REG_BUCK2_DVS1CFG0 0x65 +#define RTQ2134_REG_BUCK2_DVSCFG 0x6C +#define RTQ2134_REG_BUCK2_RSPCFG 0x6E +#define RTQ2134_REG_BUCK3_CFG0 0x79 +#define RTQ2134_REG_BUCK3_DVS0CFG1 0x7C +#define RTQ2134_REG_BUCK3_DVS0CFG0 0x7D +#define RTQ2134_REG_BUCK3_DVS1CFG1 0x7E +#define RTQ2134_REG_BUCK3_DVS1CFG0 0x7F +#define RTQ2134_REG_BUCK3_DVSCFG 0x86 +#define RTQ2134_REG_BUCK3_RSPCFG 0x88 +#define RTQ2134_REG_BUCK3_SLEWCTRL 0x89 + +#define RTQ2134_VOUT_MAXNUM 256 +#define RTQ2134_VOUT_MASK 0xFF +#define RTQ2134_VOUTEN_MASK BIT(0) +#define RTQ2134_ACTDISCHG_MASK BIT(0) +#define RTQ2134_RSPUP_MASK GENMASK(6, 4) +#define RTQ2134_FCCM_MASK BIT(5) +#define RTQ2134_UVHICCUP_MASK BIT(3) +#define RTQ2134_BUCKDVS_CTRL_MASK GENMASK(1, 0) +#define RTQ2134_CHIPOT_MASK BIT(2) +#define RTQ2134_BUCKOV_MASK BIT(5) +#define RTQ2134_BUCKUV_MASK BIT(4) + +struct rtq2134_regulator_desc { + struct regulator_desc desc; + /* Extension for proprietary register and mask */ + unsigned int mode_reg; + unsigned int mode_mask; + unsigned int suspend_enable_reg; + unsigned int suspend_enable_mask; + unsigned int suspend_vsel_reg; + unsigned int suspend_vsel_mask; + unsigned int suspend_mode_reg; + unsigned int suspend_mode_mask; + unsigned int dvs_ctrl_reg; +}; + +static int rtq2134_buck_set_mode(struct regulator_dev *rdev, unsigned int mode) +{ + struct rtq2134_regulator_desc *desc = + (struct rtq2134_regulator_desc *)rdev->desc; + unsigned int val; + + if (mode == REGULATOR_MODE_NORMAL) + val = RTQ2134_AUTO_MODE; + else if (mode == REGULATOR_MODE_FAST) + val = RTQ2134_FCCM_MODE; + else + return -EINVAL; + + val <<= ffs(desc->mode_mask) - 1; + return regmap_update_bits(rdev->regmap, desc->mode_reg, desc->mode_mask, + val); +} + +static unsigned int rtq2134_buck_get_mode(struct regulator_dev *rdev) +{ + struct rtq2134_regulator_desc *desc = + (struct rtq2134_regulator_desc *)rdev->desc; + unsigned int mode; + int ret; + + ret = regmap_read(rdev->regmap, desc->mode_reg, &mode); + if (ret) + return ret; + + if (mode & desc->mode_mask) + return REGULATOR_MODE_FAST; + return REGULATOR_MODE_NORMAL; +} + +static int rtq2134_buck_set_suspend_voltage(struct regulator_dev *rdev, int uV) +{ + struct rtq2134_regulator_desc *desc = + (struct rtq2134_regulator_desc *)rdev->desc; + int sel; + + sel = regulator_map_voltage_linear_range(rdev, uV, uV); + if (sel < 0) + return sel; + + sel <<= ffs(desc->suspend_vsel_mask) - 1; + + return regmap_update_bits(rdev->regmap, desc->suspend_vsel_reg, + desc->suspend_vsel_mask, sel); +} + +static int rtq2134_buck_set_suspend_enable(struct regulator_dev *rdev) +{ + struct rtq2134_regulator_desc *desc = + (struct rtq2134_regulator_desc *)rdev->desc; + unsigned int val = desc->suspend_enable_mask; + + return regmap_update_bits(rdev->regmap, desc->suspend_enable_reg, + desc->suspend_enable_mask, val); +} + +static int rtq2134_buck_set_suspend_disable(struct regulator_dev *rdev) +{ + struct rtq2134_regulator_desc *desc = + (struct rtq2134_regulator_desc *)rdev->desc; + + return regmap_update_bits(rdev->regmap, desc->suspend_enable_reg, + desc->suspend_enable_mask, 0); +} + +static int rtq2134_buck_set_suspend_mode(struct regulator_dev *rdev, + unsigned int mode) +{ + struct rtq2134_regulator_desc *desc = + (struct rtq2134_regulator_desc *)rdev->desc; + unsigned int val; + + if (mode == REGULATOR_MODE_NORMAL) + val = RTQ2134_AUTO_MODE; + else if (mode == REGULATOR_MODE_FAST) + val = RTQ2134_FCCM_MODE; + else + return -EINVAL; + + val <<= ffs(desc->suspend_mode_mask) - 1; + return regmap_update_bits(rdev->regmap, desc->suspend_mode_reg, + desc->suspend_mode_mask, val); +} + +static int rtq2134_buck_get_error_flags(struct regulator_dev *rdev, + unsigned int *flags) +{ + int rid = rdev_get_id(rdev); + unsigned int chip_error, buck_error, events = 0; + int ret; + + ret = regmap_read(rdev->regmap, RTQ2134_REG_FLT_RECORDTEMP, + &chip_error); + if (ret) { + dev_err(&rdev->dev, "Failed to get chip error flag\n"); + return ret; + } + + ret = regmap_read(rdev->regmap, RTQ2134_REG_FLT_RECORDBUCK(rid), + &buck_error); + if (ret) { + dev_err(&rdev->dev, "Failed to get buck error flag\n"); + return ret; + } + + if (chip_error & RTQ2134_CHIPOT_MASK) + events |= REGULATOR_ERROR_OVER_TEMP; + + if (buck_error & RTQ2134_BUCKUV_MASK) + events |= REGULATOR_ERROR_UNDER_VOLTAGE; + + if (buck_error & RTQ2134_BUCKOV_MASK) + events |= REGULATOR_ERROR_REGULATION_OUT; + + *flags = events; + return 0; +} + +static const struct regulator_ops rtq2134_buck_ops = { + .list_voltage = regulator_list_voltage_linear_range, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .set_active_discharge = regulator_set_active_discharge_regmap, + .set_ramp_delay = regulator_set_ramp_delay_regmap, + .set_mode = rtq2134_buck_set_mode, + .get_mode = rtq2134_buck_get_mode, + .set_suspend_voltage = rtq2134_buck_set_suspend_voltage, + .set_suspend_enable = rtq2134_buck_set_suspend_enable, + .set_suspend_disable = rtq2134_buck_set_suspend_disable, + .set_suspend_mode = rtq2134_buck_set_suspend_mode, + .get_error_flags = rtq2134_buck_get_error_flags, +}; + +static const struct linear_range rtq2134_buck_vout_ranges[] = { + REGULATOR_LINEAR_RANGE(300000, 0, 200, 5000), + REGULATOR_LINEAR_RANGE(1310000, 201, 255, 10000) +}; + +static unsigned int rtq2134_buck_of_map_mode(unsigned int mode) +{ + switch (mode) { + case RTQ2134_AUTO_MODE: + return REGULATOR_MODE_NORMAL; + case RTQ2134_FCCM_MODE: + return REGULATOR_MODE_FAST; + } + + return REGULATOR_MODE_INVALID; +} + +static int rtq2134_buck_of_parse_cb(struct device_node *np, + const struct regulator_desc *desc, + struct regulator_config *cfg) +{ + struct rtq2134_regulator_desc *rdesc = + (struct rtq2134_regulator_desc *)desc; + int rid = desc->id; + bool uv_shutdown, vsel_dvs; + unsigned int val; + int ret; + + vsel_dvs = of_property_read_bool(np, "richtek,use-vsel-dvs"); + if (vsel_dvs) + val = RTQ2134_BUCK_VSEL_CTRL; + else + val = RTQ2134_BUCK_DVS0_CTRL; + + ret = regmap_update_bits(cfg->regmap, rdesc->dvs_ctrl_reg, + RTQ2134_BUCKDVS_CTRL_MASK, val); + if (ret) + return ret; + + uv_shutdown = of_property_read_bool(np, "richtek,uv-shutdown"); + if (uv_shutdown) + val = 0; + else + val = RTQ2134_UVHICCUP_MASK; + + return regmap_update_bits(cfg->regmap, RTQ2134_REG_FLT_BUCKCTRL(rid), + RTQ2134_UVHICCUP_MASK, val); +} + +static const unsigned int rtq2134_buck_ramp_delay_table[] = { + 0, 16000, 0, 8000, 4000, 2000, 1000, 500 +}; + +#define RTQ2134_BUCK_DESC(_id) { \ + .desc = { \ + .name = "rtq2134_buck" #_id, \ + .of_match = of_match_ptr("buck" #_id), \ + .regulators_node = of_match_ptr("regulators"), \ + .id = RTQ2134_IDX_BUCK##_id, \ + .type = REGULATOR_VOLTAGE, \ + .owner = THIS_MODULE, \ + .ops = &rtq2134_buck_ops, \ + .n_voltages = RTQ2134_VOUT_MAXNUM, \ + .linear_ranges = rtq2134_buck_vout_ranges, \ + .n_linear_ranges = ARRAY_SIZE(rtq2134_buck_vout_ranges), \ + .vsel_reg = RTQ2134_REG_BUCK##_id##_DVS0CFG1, \ + .vsel_mask = RTQ2134_VOUT_MASK, \ + .enable_reg = RTQ2134_REG_BUCK##_id##_DVS0CFG0, \ + .enable_mask = RTQ2134_VOUTEN_MASK, \ + .active_discharge_reg = RTQ2134_REG_BUCK##_id##_CFG0, \ + .active_discharge_mask = RTQ2134_ACTDISCHG_MASK, \ + .ramp_reg = RTQ2134_REG_BUCK##_id##_RSPCFG, \ + .ramp_mask = RTQ2134_RSPUP_MASK, \ + .ramp_delay_table = rtq2134_buck_ramp_delay_table, \ + .n_ramp_values = ARRAY_SIZE(rtq2134_buck_ramp_delay_table), \ + .of_map_mode = rtq2134_buck_of_map_mode, \ + .of_parse_cb = rtq2134_buck_of_parse_cb, \ + }, \ + .mode_reg = RTQ2134_REG_BUCK##_id##_DVS0CFG0, \ + .mode_mask = RTQ2134_FCCM_MASK, \ + .suspend_mode_reg = RTQ2134_REG_BUCK##_id##_DVS1CFG0, \ + .suspend_mode_mask = RTQ2134_FCCM_MASK, \ + .suspend_enable_reg = RTQ2134_REG_BUCK##_id##_DVS1CFG0, \ + .suspend_enable_mask = RTQ2134_VOUTEN_MASK, \ + .suspend_vsel_reg = RTQ2134_REG_BUCK##_id##_DVS1CFG1, \ + .suspend_vsel_mask = RTQ2134_VOUT_MASK, \ + .dvs_ctrl_reg = RTQ2134_REG_BUCK##_id##_DVSCFG, \ +} + +static const struct rtq2134_regulator_desc rtq2134_regulator_descs[] = { + RTQ2134_BUCK_DESC(1), + RTQ2134_BUCK_DESC(2), + RTQ2134_BUCK_DESC(3) +}; + +static bool rtq2134_is_accissible_reg(struct device *dev, unsigned int reg) +{ + if (reg >= RTQ2134_REG_IO_CHIPNAME && reg <= RTQ2134_REG_BUCK3_SLEWCTRL) + return true; + return false; +} + +static const struct regmap_config rtq2134_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = RTQ2134_REG_BUCK3_SLEWCTRL, + + .readable_reg = rtq2134_is_accissible_reg, + .writeable_reg = rtq2134_is_accissible_reg, +}; + +static int rtq2134_probe(struct i2c_client *i2c) +{ + struct regmap *regmap; + struct regulator_dev *rdev; + struct regulator_config regulator_cfg = {}; + int i; + + regmap = devm_regmap_init_i2c(i2c, &rtq2134_regmap_config); + if (IS_ERR(regmap)) { + dev_err(&i2c->dev, "Failed to allocate regmap\n"); + return PTR_ERR(regmap); + } + + regulator_cfg.dev = &i2c->dev; + regulator_cfg.regmap = regmap; + for (i = 0; i < ARRAY_SIZE(rtq2134_regulator_descs); i++) { + rdev = devm_regulator_register(&i2c->dev, + &rtq2134_regulator_descs[i].desc, + ®ulator_cfg); + if (IS_ERR(rdev)) { + dev_err(&i2c->dev, "Failed to init %d regulator\n", i); + return PTR_ERR(rdev); + } + } + + return 0; +} + +static const struct of_device_id __maybe_unused rtq2134_device_tables[] = { + { .compatible = "richtek,rtq2134", }, + {} +}; +MODULE_DEVICE_TABLE(of, rtq2134_device_tables); + +static struct i2c_driver rtq2134_driver = { + .driver = { + .name = "rtq2134", + .of_match_table = rtq2134_device_tables, + }, + .probe_new = rtq2134_probe, +}; +module_i2c_driver(rtq2134_driver); + +MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>"); +MODULE_DESCRIPTION("Richtek RTQ2134 Regulator Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/regulator/rtq6752-regulator.c b/drivers/regulator/rtq6752-regulator.c new file mode 100644 index 000000000000..609d3fcf4923 --- /dev/null +++ b/drivers/regulator/rtq6752-regulator.c @@ -0,0 +1,289 @@ +// SPDX-License-Identifier: GPL-2.0+ + +#include <linux/bitops.h> +#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/i2c.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/regmap.h> +#include <linux/regulator/driver.h> + +enum { + RTQ6752_IDX_PAVDD = 0, + RTQ6752_IDX_NAVDD = 1, + RTQ6752_IDX_MAX +}; + +#define RTQ6752_REG_PAVDD 0x00 +#define RTQ6752_REG_NAVDD 0x01 +#define RTQ6752_REG_PAVDDONDLY 0x07 +#define RTQ6752_REG_PAVDDSSTIME 0x08 +#define RTQ6752_REG_NAVDDONDLY 0x0D +#define RTQ6752_REG_NAVDDSSTIME 0x0E +#define RTQ6752_REG_OPTION1 0x12 +#define RTQ6752_REG_CHSWITCH 0x16 +#define RTQ6752_REG_FAULT 0x1D + +#define RTQ6752_VOUT_MASK GENMASK(5, 0) +#define RTQ6752_NAVDDEN_MASK BIT(3) +#define RTQ6752_PAVDDEN_MASK BIT(0) +#define RTQ6752_PAVDDAD_MASK BIT(4) +#define RTQ6752_NAVDDAD_MASK BIT(3) +#define RTQ6752_PAVDDF_MASK BIT(3) +#define RTQ6752_NAVDDF_MASK BIT(0) +#define RTQ6752_ENABLE_MASK (BIT(RTQ6752_IDX_MAX) - 1) + +#define RTQ6752_VOUT_MINUV 5000000 +#define RTQ6752_VOUT_STEPUV 50000 +#define RTQ6752_VOUT_NUM 47 +#define RTQ6752_I2CRDY_TIMEUS 1000 +#define RTQ6752_MINSS_TIMEUS 5000 + +struct rtq6752_priv { + struct regmap *regmap; + struct gpio_desc *enable_gpio; + struct mutex lock; + unsigned char enable_flag; +}; + +static int rtq6752_set_vdd_enable(struct regulator_dev *rdev) +{ + struct rtq6752_priv *priv = rdev_get_drvdata(rdev); + int rid = rdev_get_id(rdev), ret; + + mutex_lock(&priv->lock); + if (priv->enable_gpio) { + gpiod_set_value(priv->enable_gpio, 1); + + usleep_range(RTQ6752_I2CRDY_TIMEUS, + RTQ6752_I2CRDY_TIMEUS + 100); + } + + if (!priv->enable_flag) { + regcache_cache_only(priv->regmap, false); + ret = regcache_sync(priv->regmap); + if (ret) { + mutex_unlock(&priv->lock); + return ret; + } + } + + priv->enable_flag |= BIT(rid); + mutex_unlock(&priv->lock); + + return regulator_enable_regmap(rdev); +} + +static int rtq6752_set_vdd_disable(struct regulator_dev *rdev) +{ + struct rtq6752_priv *priv = rdev_get_drvdata(rdev); + int rid = rdev_get_id(rdev), ret; + + ret = regulator_disable_regmap(rdev); + if (ret) + return ret; + + mutex_lock(&priv->lock); + priv->enable_flag &= ~BIT(rid); + + if (!priv->enable_flag) { + regcache_cache_only(priv->regmap, true); + regcache_mark_dirty(priv->regmap); + } + + if (priv->enable_gpio) + gpiod_set_value(priv->enable_gpio, 0); + + mutex_unlock(&priv->lock); + + return 0; +} + +static int rtq6752_get_error_flags(struct regulator_dev *rdev, + unsigned int *flags) +{ + unsigned int val, events = 0; + const unsigned int fault_mask[] = { + RTQ6752_PAVDDF_MASK, RTQ6752_NAVDDF_MASK }; + int rid = rdev_get_id(rdev), ret; + + ret = regmap_read(rdev->regmap, RTQ6752_REG_FAULT, &val); + if (ret) + return ret; + + if (val & fault_mask[rid]) + events = REGULATOR_ERROR_REGULATION_OUT; + + *flags = events; + return 0; +} + +static const struct regulator_ops rtq6752_regulator_ops = { + .list_voltage = regulator_list_voltage_linear, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .enable = rtq6752_set_vdd_enable, + .disable = rtq6752_set_vdd_disable, + .is_enabled = regulator_is_enabled_regmap, + .set_active_discharge = regulator_set_active_discharge_regmap, + .get_error_flags = rtq6752_get_error_flags, +}; + +static const struct regulator_desc rtq6752_regulator_descs[] = { + { + .name = "rtq6752-pavdd", + .of_match = of_match_ptr("pavdd"), + .regulators_node = of_match_ptr("regulators"), + .id = RTQ6752_IDX_PAVDD, + .n_voltages = RTQ6752_VOUT_NUM, + .ops = &rtq6752_regulator_ops, + .owner = THIS_MODULE, + .min_uV = RTQ6752_VOUT_MINUV, + .uV_step = RTQ6752_VOUT_STEPUV, + .enable_time = RTQ6752_MINSS_TIMEUS, + .vsel_reg = RTQ6752_REG_PAVDD, + .vsel_mask = RTQ6752_VOUT_MASK, + .enable_reg = RTQ6752_REG_CHSWITCH, + .enable_mask = RTQ6752_PAVDDEN_MASK, + .active_discharge_reg = RTQ6752_REG_OPTION1, + .active_discharge_mask = RTQ6752_PAVDDAD_MASK, + .active_discharge_off = RTQ6752_PAVDDAD_MASK, + }, + { + .name = "rtq6752-navdd", + .of_match = of_match_ptr("navdd"), + .regulators_node = of_match_ptr("regulators"), + .id = RTQ6752_IDX_NAVDD, + .n_voltages = RTQ6752_VOUT_NUM, + .ops = &rtq6752_regulator_ops, + .owner = THIS_MODULE, + .min_uV = RTQ6752_VOUT_MINUV, + .uV_step = RTQ6752_VOUT_STEPUV, + .enable_time = RTQ6752_MINSS_TIMEUS, + .vsel_reg = RTQ6752_REG_NAVDD, + .vsel_mask = RTQ6752_VOUT_MASK, + .enable_reg = RTQ6752_REG_CHSWITCH, + .enable_mask = RTQ6752_NAVDDEN_MASK, + .active_discharge_reg = RTQ6752_REG_OPTION1, + .active_discharge_mask = RTQ6752_NAVDDAD_MASK, + .active_discharge_off = RTQ6752_NAVDDAD_MASK, + } +}; + +static int rtq6752_init_device_properties(struct rtq6752_priv *priv) +{ + u8 raw_vals[] = { 0, 0 }; + int ret; + + /* Configure PAVDD on and softstart delay time to the minimum */ + ret = regmap_raw_write(priv->regmap, RTQ6752_REG_PAVDDONDLY, raw_vals, + ARRAY_SIZE(raw_vals)); + if (ret) + return ret; + + /* Configure NAVDD on and softstart delay time to the minimum */ + return regmap_raw_write(priv->regmap, RTQ6752_REG_NAVDDONDLY, raw_vals, + ARRAY_SIZE(raw_vals)); +} + +static bool rtq6752_is_volatile_reg(struct device *dev, unsigned int reg) +{ + if (reg == RTQ6752_REG_FAULT) + return true; + return false; +} + +static const struct reg_default rtq6752_reg_defaults[] = { + { RTQ6752_REG_PAVDD, 0x14 }, + { RTQ6752_REG_NAVDD, 0x14 }, + { RTQ6752_REG_PAVDDONDLY, 0x01 }, + { RTQ6752_REG_PAVDDSSTIME, 0x01 }, + { RTQ6752_REG_NAVDDONDLY, 0x01 }, + { RTQ6752_REG_NAVDDSSTIME, 0x01 }, + { RTQ6752_REG_OPTION1, 0x07 }, + { RTQ6752_REG_CHSWITCH, 0x29 }, +}; + +static const struct regmap_config rtq6752_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .cache_type = REGCACHE_RBTREE, + .max_register = RTQ6752_REG_FAULT, + .reg_defaults = rtq6752_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(rtq6752_reg_defaults), + .volatile_reg = rtq6752_is_volatile_reg, +}; + +static int rtq6752_probe(struct i2c_client *i2c) +{ + struct rtq6752_priv *priv; + struct regulator_config reg_cfg = {}; + struct regulator_dev *rdev; + int i, ret; + + priv = devm_kzalloc(&i2c->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + mutex_init(&priv->lock); + + priv->enable_gpio = devm_gpiod_get_optional(&i2c->dev, "enable", + GPIOD_OUT_HIGH); + if (IS_ERR(priv->enable_gpio)) { + dev_err(&i2c->dev, "Failed to get 'enable' gpio\n"); + return PTR_ERR(priv->enable_gpio); + } + + usleep_range(RTQ6752_I2CRDY_TIMEUS, RTQ6752_I2CRDY_TIMEUS + 100); + /* Default EN pin to high, PAVDD and NAVDD will be on */ + priv->enable_flag = RTQ6752_ENABLE_MASK; + + priv->regmap = devm_regmap_init_i2c(i2c, &rtq6752_regmap_config); + if (IS_ERR(priv->regmap)) { + dev_err(&i2c->dev, "Failed to init regmap\n"); + return PTR_ERR(priv->regmap); + } + + ret = rtq6752_init_device_properties(priv); + if (ret) { + dev_err(&i2c->dev, "Failed to init device properties\n"); + return ret; + } + + reg_cfg.dev = &i2c->dev; + reg_cfg.regmap = priv->regmap; + reg_cfg.driver_data = priv; + + for (i = 0; i < ARRAY_SIZE(rtq6752_regulator_descs); i++) { + rdev = devm_regulator_register(&i2c->dev, + rtq6752_regulator_descs + i, + ®_cfg); + if (IS_ERR(rdev)) { + dev_err(&i2c->dev, "Failed to init %d regulator\n", i); + return PTR_ERR(rdev); + } + } + + return 0; +} + +static const struct of_device_id __maybe_unused rtq6752_device_table[] = { + { .compatible = "richtek,rtq6752", }, + {} +}; +MODULE_DEVICE_TABLE(of, rtq6752_device_table); + +static struct i2c_driver rtq6752_driver = { + .driver = { + .name = "rtq6752", + .of_match_table = rtq6752_device_table, + }, + .probe_new = rtq6752_probe, +}; +module_i2c_driver(rtq6752_driver); + +MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>"); +MODULE_DESCRIPTION("Richtek RTQ6752 Regulator Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/regulator/sy7636a-regulator.c b/drivers/regulator/sy7636a-regulator.c index e021ae08cbaa..8360b3947ead 100644 --- a/drivers/regulator/sy7636a-regulator.c +++ b/drivers/regulator/sy7636a-regulator.c @@ -13,7 +13,10 @@ #include <linux/gpio/consumer.h> #include <linux/mfd/sy7636a.h> -#define SY7636A_POLL_ENABLED_TIME 500 +struct sy7636a_data { + struct regmap *regmap; + struct gpio_desc *pgood_gpio; +}; static int sy7636a_get_vcom_voltage_op(struct regulator_dev *rdev) { @@ -35,10 +38,10 @@ static int sy7636a_get_vcom_voltage_op(struct regulator_dev *rdev) static int sy7636a_get_status(struct regulator_dev *rdev) { - struct sy7636a *sy7636a = rdev_get_drvdata(rdev); + struct sy7636a_data *data = dev_get_drvdata(rdev->dev.parent); int ret = 0; - ret = gpiod_get_value_cansleep(sy7636a->pgood_gpio); + ret = gpiod_get_value_cansleep(data->pgood_gpio); if (ret < 0) dev_err(&rdev->dev, "Failed to read pgood gpio: %d\n", ret); @@ -61,46 +64,50 @@ static const struct regulator_desc desc = { .owner = THIS_MODULE, .enable_reg = SY7636A_REG_OPERATION_MODE_CRL, .enable_mask = SY7636A_OPERATION_MODE_CRL_ONOFF, - .poll_enabled_time = SY7636A_POLL_ENABLED_TIME, .regulators_node = of_match_ptr("regulators"), .of_match = of_match_ptr("vcom"), }; static int sy7636a_regulator_probe(struct platform_device *pdev) { - struct sy7636a *sy7636a = dev_get_drvdata(pdev->dev.parent); + struct regmap *regmap = dev_get_drvdata(pdev->dev.parent); struct regulator_config config = { }; struct regulator_dev *rdev; struct gpio_desc *gdp; + struct sy7636a_data *data; int ret; - if (!sy7636a) + if (!regmap) return -EPROBE_DEFER; - platform_set_drvdata(pdev, sy7636a); - - gdp = devm_gpiod_get(sy7636a->dev, "epd-pwr-good", GPIOD_IN); + gdp = devm_gpiod_get(pdev->dev.parent, "epd-pwr-good", GPIOD_IN); if (IS_ERR(gdp)) { - dev_err(sy7636a->dev, "Power good GPIO fault %ld\n", PTR_ERR(gdp)); + dev_err(pdev->dev.parent, "Power good GPIO fault %ld\n", PTR_ERR(gdp)); return PTR_ERR(gdp); } - sy7636a->pgood_gpio = gdp; + data = devm_kzalloc(&pdev->dev, sizeof(struct sy7636a_data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->regmap = regmap; + data->pgood_gpio = gdp; + + platform_set_drvdata(pdev, data); - ret = regmap_write(sy7636a->regmap, SY7636A_REG_POWER_ON_DELAY_TIME, 0x0); + ret = regmap_write(regmap, SY7636A_REG_POWER_ON_DELAY_TIME, 0x0); if (ret) { - dev_err(sy7636a->dev, "Failed to initialize regulator: %d\n", ret); + dev_err(pdev->dev.parent, "Failed to initialize regulator: %d\n", ret); return ret; } config.dev = &pdev->dev; - config.dev->of_node = sy7636a->dev->of_node; - config.driver_data = sy7636a; - config.regmap = sy7636a->regmap; + config.dev->of_node = pdev->dev.parent->of_node; + config.regmap = regmap; rdev = devm_regulator_register(&pdev->dev, &desc, &config); if (IS_ERR(rdev)) { - dev_err(sy7636a->dev, "Failed to register %s regulator\n", + dev_err(pdev->dev.parent, "Failed to register %s regulator\n", pdev->name); return PTR_ERR(rdev); } diff --git a/drivers/regulator/sy8824x.c b/drivers/regulator/sy8824x.c index 62d243f3b904..5e915cf307b3 100644 --- a/drivers/regulator/sy8824x.c +++ b/drivers/regulator/sy8824x.c @@ -25,6 +25,7 @@ struct sy8824_config { unsigned int vsel_min; unsigned int vsel_step; unsigned int vsel_count; + const struct regmap_config *config; }; struct sy8824_device_info { @@ -110,6 +111,15 @@ static int sy8824_regulator_register(struct sy8824_device_info *di, static const struct regmap_config sy8824_regmap_config = { .reg_bits = 8, .val_bits = 8, + .num_reg_defaults_raw = 1, + .cache_type = REGCACHE_FLAT, +}; + +static const struct regmap_config sy20276_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .num_reg_defaults_raw = 2, + .cache_type = REGCACHE_FLAT, }; static int sy8824_i2c_probe(struct i2c_client *client) @@ -134,7 +144,7 @@ static int sy8824_i2c_probe(struct i2c_client *client) di->dev = dev; di->cfg = of_device_get_match_data(dev); - regmap = devm_regmap_init_i2c(client, &sy8824_regmap_config); + regmap = devm_regmap_init_i2c(client, di->cfg->config); if (IS_ERR(regmap)) { dev_err(dev, "Failed to allocate regmap!\n"); return PTR_ERR(regmap); @@ -160,6 +170,7 @@ static const struct sy8824_config sy8824c_cfg = { .vsel_min = 762500, .vsel_step = 12500, .vsel_count = 64, + .config = &sy8824_regmap_config, }; static const struct sy8824_config sy8824e_cfg = { @@ -169,6 +180,7 @@ static const struct sy8824_config sy8824e_cfg = { .vsel_min = 700000, .vsel_step = 12500, .vsel_count = 64, + .config = &sy8824_regmap_config, }; static const struct sy8824_config sy20276_cfg = { @@ -178,6 +190,7 @@ static const struct sy8824_config sy20276_cfg = { .vsel_min = 600000, .vsel_step = 10000, .vsel_count = 128, + .config = &sy20276_regmap_config, }; static const struct sy8824_config sy20278_cfg = { @@ -187,6 +200,7 @@ static const struct sy8824_config sy20278_cfg = { .vsel_min = 762500, .vsel_step = 12500, .vsel_count = 64, + .config = &sy20276_regmap_config, }; static const struct of_device_id sy8824_dt_ids[] = { diff --git a/drivers/regulator/sy8827n.c b/drivers/regulator/sy8827n.c index 52e8c17afe24..7d5d9f879ce3 100644 --- a/drivers/regulator/sy8827n.c +++ b/drivers/regulator/sy8827n.c @@ -19,6 +19,10 @@ #define SY8827N_MODE (1 << 6) #define SY8827N_VSEL1 1 #define SY8827N_CTRL 2 +#define SY8827N_ID1 3 +#define SY8827N_ID2 4 +#define SY8827N_PGOOD 5 +#define SY8827N_MAX (SY8827N_PGOOD + 1) #define SY8827N_NVOLTAGES 64 #define SY8827N_VSELMIN 600000 @@ -102,9 +106,19 @@ static int sy8827n_regulator_register(struct sy8827n_device_info *di, return PTR_ERR_OR_ZERO(rdev); } +static bool sy8827n_volatile_reg(struct device *dev, unsigned int reg) +{ + if (reg == SY8827N_PGOOD) + return true; + return false; +} + static const struct regmap_config sy8827n_regmap_config = { .reg_bits = 8, .val_bits = 8, + .volatile_reg = sy8827n_volatile_reg, + .num_reg_defaults_raw = SY8827N_MAX, + .cache_type = REGCACHE_FLAT, }; static int sy8827n_i2c_probe(struct i2c_client *client) diff --git a/drivers/regulator/tps65910-regulator.c b/drivers/regulator/tps65910-regulator.c index 1d5b0a1b86f7..06cbe60c990f 100644 --- a/drivers/regulator/tps65910-regulator.c +++ b/drivers/regulator/tps65910-regulator.c @@ -1211,12 +1211,10 @@ static int tps65910_probe(struct platform_device *pdev) rdev = devm_regulator_register(&pdev->dev, &pmic->desc[i], &config); - if (IS_ERR(rdev)) { - dev_err(tps65910->dev, - "failed to register %s regulator\n", - pdev->name); - return PTR_ERR(rdev); - } + if (IS_ERR(rdev)) + return dev_err_probe(tps65910->dev, PTR_ERR(rdev), + "failed to register %s regulator\n", + pdev->name); /* Save regulator for cleanup */ pmic->rdev[i] = rdev; diff --git a/drivers/regulator/vctrl-regulator.c b/drivers/regulator/vctrl-regulator.c index cbadb1c99679..d2a37978fc3a 100644 --- a/drivers/regulator/vctrl-regulator.c +++ b/drivers/regulator/vctrl-regulator.c @@ -37,7 +37,6 @@ struct vctrl_voltage_table { struct vctrl_data { struct regulator_dev *rdev; struct regulator_desc desc; - struct regulator *ctrl_reg; bool enabled; unsigned int min_slew_down_rate; unsigned int ovp_threshold; @@ -82,7 +81,12 @@ static int vctrl_calc_output_voltage(struct vctrl_data *vctrl, int ctrl_uV) static int vctrl_get_voltage(struct regulator_dev *rdev) { struct vctrl_data *vctrl = rdev_get_drvdata(rdev); - int ctrl_uV = regulator_get_voltage_rdev(vctrl->ctrl_reg->rdev); + int ctrl_uV; + + if (!rdev->supply) + return -EPROBE_DEFER; + + ctrl_uV = regulator_get_voltage_rdev(rdev->supply->rdev); return vctrl_calc_output_voltage(vctrl, ctrl_uV); } @@ -92,14 +96,19 @@ static int vctrl_set_voltage(struct regulator_dev *rdev, unsigned int *selector) { struct vctrl_data *vctrl = rdev_get_drvdata(rdev); - struct regulator *ctrl_reg = vctrl->ctrl_reg; - int orig_ctrl_uV = regulator_get_voltage_rdev(ctrl_reg->rdev); - int uV = vctrl_calc_output_voltage(vctrl, orig_ctrl_uV); + int orig_ctrl_uV; + int uV; int ret; + if (!rdev->supply) + return -EPROBE_DEFER; + + orig_ctrl_uV = regulator_get_voltage_rdev(rdev->supply->rdev); + uV = vctrl_calc_output_voltage(vctrl, orig_ctrl_uV); + if (req_min_uV >= uV || !vctrl->ovp_threshold) /* voltage rising or no OVP */ - return regulator_set_voltage_rdev(ctrl_reg->rdev, + return regulator_set_voltage_rdev(rdev->supply->rdev, vctrl_calc_ctrl_voltage(vctrl, req_min_uV), vctrl_calc_ctrl_voltage(vctrl, req_max_uV), PM_SUSPEND_ON); @@ -117,7 +126,7 @@ static int vctrl_set_voltage(struct regulator_dev *rdev, next_uV = max_t(int, req_min_uV, uV - max_drop_uV); next_ctrl_uV = vctrl_calc_ctrl_voltage(vctrl, next_uV); - ret = regulator_set_voltage_rdev(ctrl_reg->rdev, + ret = regulator_set_voltage_rdev(rdev->supply->rdev, next_ctrl_uV, next_ctrl_uV, PM_SUSPEND_ON); @@ -134,7 +143,7 @@ static int vctrl_set_voltage(struct regulator_dev *rdev, err: /* Try to go back to original voltage */ - regulator_set_voltage_rdev(ctrl_reg->rdev, orig_ctrl_uV, orig_ctrl_uV, + regulator_set_voltage_rdev(rdev->supply->rdev, orig_ctrl_uV, orig_ctrl_uV, PM_SUSPEND_ON); return ret; @@ -151,16 +160,18 @@ static int vctrl_set_voltage_sel(struct regulator_dev *rdev, unsigned int selector) { struct vctrl_data *vctrl = rdev_get_drvdata(rdev); - struct regulator *ctrl_reg = vctrl->ctrl_reg; unsigned int orig_sel = vctrl->sel; int ret; + if (!rdev->supply) + return -EPROBE_DEFER; + if (selector >= rdev->desc->n_voltages) return -EINVAL; if (selector >= vctrl->sel || !vctrl->ovp_threshold) { /* voltage rising or no OVP */ - ret = regulator_set_voltage_rdev(ctrl_reg->rdev, + ret = regulator_set_voltage_rdev(rdev->supply->rdev, vctrl->vtable[selector].ctrl, vctrl->vtable[selector].ctrl, PM_SUSPEND_ON); @@ -179,7 +190,7 @@ static int vctrl_set_voltage_sel(struct regulator_dev *rdev, else next_sel = vctrl->vtable[vctrl->sel].ovp_min_sel; - ret = regulator_set_voltage_rdev(ctrl_reg->rdev, + ret = regulator_set_voltage_rdev(rdev->supply->rdev, vctrl->vtable[next_sel].ctrl, vctrl->vtable[next_sel].ctrl, PM_SUSPEND_ON); @@ -202,7 +213,7 @@ static int vctrl_set_voltage_sel(struct regulator_dev *rdev, err: if (vctrl->sel != orig_sel) { /* Try to go back to original voltage */ - if (!regulator_set_voltage_rdev(ctrl_reg->rdev, + if (!regulator_set_voltage_rdev(rdev->supply->rdev, vctrl->vtable[orig_sel].ctrl, vctrl->vtable[orig_sel].ctrl, PM_SUSPEND_ON)) @@ -234,10 +245,6 @@ static int vctrl_parse_dt(struct platform_device *pdev, u32 pval; u32 vrange_ctrl[2]; - vctrl->ctrl_reg = devm_regulator_get(&pdev->dev, "ctrl"); - if (IS_ERR(vctrl->ctrl_reg)) - return PTR_ERR(vctrl->ctrl_reg); - ret = of_property_read_u32(np, "ovp-threshold-percent", &pval); if (!ret) { vctrl->ovp_threshold = pval; @@ -315,11 +322,11 @@ static int vctrl_cmp_ctrl_uV(const void *a, const void *b) return at->ctrl - bt->ctrl; } -static int vctrl_init_vtable(struct platform_device *pdev) +static int vctrl_init_vtable(struct platform_device *pdev, + struct regulator *ctrl_reg) { struct vctrl_data *vctrl = platform_get_drvdata(pdev); struct regulator_desc *rdesc = &vctrl->desc; - struct regulator *ctrl_reg = vctrl->ctrl_reg; struct vctrl_voltage_range *vrange_ctrl = &vctrl->vrange.ctrl; int n_voltages; int ctrl_uV; @@ -395,23 +402,19 @@ static int vctrl_init_vtable(struct platform_device *pdev) static int vctrl_enable(struct regulator_dev *rdev) { struct vctrl_data *vctrl = rdev_get_drvdata(rdev); - int ret = regulator_enable(vctrl->ctrl_reg); - if (!ret) - vctrl->enabled = true; + vctrl->enabled = true; - return ret; + return 0; } static int vctrl_disable(struct regulator_dev *rdev) { struct vctrl_data *vctrl = rdev_get_drvdata(rdev); - int ret = regulator_disable(vctrl->ctrl_reg); - if (!ret) - vctrl->enabled = false; + vctrl->enabled = false; - return ret; + return 0; } static int vctrl_is_enabled(struct regulator_dev *rdev) @@ -447,6 +450,7 @@ static int vctrl_probe(struct platform_device *pdev) struct regulator_desc *rdesc; struct regulator_config cfg = { }; struct vctrl_voltage_range *vrange_ctrl; + struct regulator *ctrl_reg; int ctrl_uV; int ret; @@ -461,15 +465,20 @@ static int vctrl_probe(struct platform_device *pdev) if (ret) return ret; + ctrl_reg = devm_regulator_get(&pdev->dev, "ctrl"); + if (IS_ERR(ctrl_reg)) + return PTR_ERR(ctrl_reg); + vrange_ctrl = &vctrl->vrange.ctrl; rdesc = &vctrl->desc; rdesc->name = "vctrl"; rdesc->type = REGULATOR_VOLTAGE; rdesc->owner = THIS_MODULE; + rdesc->supply_name = "ctrl"; - if ((regulator_get_linear_step(vctrl->ctrl_reg) == 1) || - (regulator_count_voltages(vctrl->ctrl_reg) == -EINVAL)) { + if ((regulator_get_linear_step(ctrl_reg) == 1) || + (regulator_count_voltages(ctrl_reg) == -EINVAL)) { rdesc->continuous_voltage_range = true; rdesc->ops = &vctrl_ops_cont; } else { @@ -486,11 +495,12 @@ static int vctrl_probe(struct platform_device *pdev) cfg.init_data = init_data; if (!rdesc->continuous_voltage_range) { - ret = vctrl_init_vtable(pdev); + ret = vctrl_init_vtable(pdev, ctrl_reg); if (ret) return ret; - ctrl_uV = regulator_get_voltage_rdev(vctrl->ctrl_reg->rdev); + /* Use locked consumer API when not in regulator framework */ + ctrl_uV = regulator_get_voltage(ctrl_reg); if (ctrl_uV < 0) { dev_err(&pdev->dev, "failed to get control voltage\n"); return ctrl_uV; @@ -513,6 +523,9 @@ static int vctrl_probe(struct platform_device *pdev) } } + /* Drop ctrl-supply here in favor of regulator core managed supply */ + devm_regulator_put(ctrl_reg); + vctrl->rdev = devm_regulator_register(&pdev->dev, rdesc, &cfg); if (IS_ERR(vctrl->rdev)) { ret = PTR_ERR(vctrl->rdev); diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index 328f70f633eb..5656cac04b4c 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -116,7 +116,7 @@ config RESET_LPC18XX config RESET_MCHP_SPARX5 bool "Microchip Sparx5 reset driver" - depends on HAS_IOMEM || COMPILE_TEST + depends on ARCH_SPARX5 || COMPILE_TEST default y if SPARX5_SWITCH select MFD_SYSCON help diff --git a/drivers/reset/reset-zynqmp.c b/drivers/reset/reset-zynqmp.c index daa425e74c96..59dc0ff9af9e 100644 --- a/drivers/reset/reset-zynqmp.c +++ b/drivers/reset/reset-zynqmp.c @@ -53,7 +53,8 @@ static int zynqmp_reset_status(struct reset_controller_dev *rcdev, unsigned long id) { struct zynqmp_reset_data *priv = to_zynqmp_reset_data(rcdev); - int val, err; + int err; + u32 val; err = zynqmp_pm_reset_get_status(priv->data->reset_id + id, &val); if (err) diff --git a/drivers/s390/block/dasd_ioctl.c b/drivers/s390/block/dasd_ioctl.c index 9f6424408946..468cbeb539ff 100644 --- a/drivers/s390/block/dasd_ioctl.c +++ b/drivers/s390/block/dasd_ioctl.c @@ -575,10 +575,8 @@ int dasd_ioctl(struct block_device *bdev, fmode_t mode, else argp = (void __user *)arg; - if ((_IOC_DIR(cmd) != _IOC_NONE) && !arg) { - PRINT_DEBUG("empty data ptr"); + if ((_IOC_DIR(cmd) != _IOC_NONE) && !arg) return -EINVAL; - } base = dasd_device_from_gendisk(bdev->bd_disk); if (!base) diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c index 792b4bfa6d9a..b4b84e3e0949 100644 --- a/drivers/s390/char/sclp.c +++ b/drivers/s390/char/sclp.c @@ -21,11 +21,30 @@ #include <linux/platform_device.h> #include <asm/types.h> #include <asm/irq.h> +#include <asm/debug.h> #include "sclp.h" #define SCLP_HEADER "sclp: " +struct sclp_trace_entry { + char id[4]; + u32 a; + u64 b; +}; + +#define SCLP_TRACE_ENTRY_SIZE sizeof(struct sclp_trace_entry) +#define SCLP_TRACE_MAX_SIZE 128 +#define SCLP_TRACE_EVENT_MAX_SIZE 64 + +/* Debug trace area intended for all entries in abbreviated form. */ +DEFINE_STATIC_DEBUG_INFO(sclp_debug, "sclp", 8, 1, SCLP_TRACE_ENTRY_SIZE, + &debug_hex_ascii_view); + +/* Error trace area intended for full entries relating to failed requests. */ +DEFINE_STATIC_DEBUG_INFO(sclp_debug_err, "sclp_err", 4, 1, + SCLP_TRACE_ENTRY_SIZE, &debug_hex_ascii_view); + /* Lock to protect internal data consistency. */ static DEFINE_SPINLOCK(sclp_lock); @@ -54,6 +73,114 @@ int sclp_console_drop = 1; /* Number of times the console dropped buffer pages */ unsigned long sclp_console_full; +/* The currently active SCLP command word. */ +static sclp_cmdw_t active_cmd; + +static inline void sclp_trace(int prio, char *id, u32 a, u64 b, bool err) +{ + struct sclp_trace_entry e; + + memset(&e, 0, sizeof(e)); + strncpy(e.id, id, sizeof(e.id)); + e.a = a; + e.b = b; + debug_event(&sclp_debug, prio, &e, sizeof(e)); + if (err) + debug_event(&sclp_debug_err, 0, &e, sizeof(e)); +} + +static inline int no_zeroes_len(void *data, int len) +{ + char *d = data; + + /* Minimize trace area usage by not tracing trailing zeroes. */ + while (len > SCLP_TRACE_ENTRY_SIZE && d[len - 1] == 0) + len--; + + return len; +} + +static inline void sclp_trace_bin(int prio, void *d, int len, int errlen) +{ + debug_event(&sclp_debug, prio, d, no_zeroes_len(d, len)); + if (errlen) + debug_event(&sclp_debug_err, 0, d, no_zeroes_len(d, errlen)); +} + +static inline int abbrev_len(sclp_cmdw_t cmd, struct sccb_header *sccb) +{ + struct evbuf_header *evbuf = (struct evbuf_header *)(sccb + 1); + int len = sccb->length, limit = SCLP_TRACE_MAX_SIZE; + + /* Full SCCB tracing if debug level is set to max. */ + if (sclp_debug.level == DEBUG_MAX_LEVEL) + return len; + + /* Minimal tracing for console writes. */ + if (cmd == SCLP_CMDW_WRITE_EVENT_DATA && + (evbuf->type == EVTYP_MSG || evbuf->type == EVTYP_VT220MSG)) + limit = SCLP_TRACE_ENTRY_SIZE; + + return min(len, limit); +} + +static inline void sclp_trace_sccb(int prio, char *id, u32 a, u64 b, + sclp_cmdw_t cmd, struct sccb_header *sccb, + bool err) +{ + sclp_trace(prio, id, a, b, err); + if (sccb) { + sclp_trace_bin(prio + 1, sccb, abbrev_len(cmd, sccb), + err ? sccb->length : 0); + } +} + +static inline void sclp_trace_evbuf(int prio, char *id, u32 a, u64 b, + struct evbuf_header *evbuf, bool err) +{ + sclp_trace(prio, id, a, b, err); + sclp_trace_bin(prio + 1, evbuf, + min((int)evbuf->length, (int)SCLP_TRACE_EVENT_MAX_SIZE), + err ? evbuf->length : 0); +} + +static inline void sclp_trace_req(int prio, char *id, struct sclp_req *req, + bool err) +{ + struct sccb_header *sccb = req->sccb; + union { + struct { + u16 status; + u16 response; + u16 timeout; + u16 start_count; + }; + u64 b; + } summary; + + summary.status = req->status; + summary.response = sccb ? sccb->response_code : 0; + summary.timeout = (u16)req->queue_timeout; + summary.start_count = (u16)req->start_count; + + sclp_trace(prio, id, (u32)(addr_t)sccb, summary.b, err); +} + +static inline void sclp_trace_register(int prio, char *id, u32 a, u64 b, + struct sclp_register *reg) +{ + struct { + u64 receive; + u64 send; + } d; + + d.receive = reg->receive_mask; + d.send = reg->send_mask; + + sclp_trace(prio, id, a, b, false); + sclp_trace_bin(prio, &d, sizeof(d), 0); +} + static int __init sclp_setup_console_pages(char *str) { int pages, rc; @@ -162,6 +289,9 @@ static void sclp_request_timeout(bool force_restart) { unsigned long flags; + /* TMO: A timeout occurred (a=force_restart) */ + sclp_trace(2, "TMO", force_restart, 0, true); + spin_lock_irqsave(&sclp_lock, flags); if (force_restart) { if (sclp_running_state == sclp_running_state_running) { @@ -237,6 +367,12 @@ static void sclp_req_queue_timeout(struct timer_list *unused) do { req = __sclp_req_queue_remove_expired_req(); + + if (req) { + /* RQTM: Request timed out (a=sccb, b=summary) */ + sclp_trace_req(2, "RQTM", req, true); + } + if (req && req->callback) req->callback(req, req->callback_data); } while (req); @@ -248,6 +384,25 @@ static void sclp_req_queue_timeout(struct timer_list *unused) spin_unlock_irqrestore(&sclp_lock, flags); } +static int sclp_service_call_trace(sclp_cmdw_t command, void *sccb) +{ + static u64 srvc_count; + int rc; + + /* SRV1: Service call about to be issued (a=command, b=sccb address) */ + sclp_trace_sccb(0, "SRV1", command, (u64)sccb, command, sccb, false); + + rc = sclp_service_call(command, sccb); + + /* SRV2: Service call was issued (a=rc, b=SRVC sequence number) */ + sclp_trace(0, "SRV2", -rc, ++srvc_count, rc != 0); + + if (rc == 0) + active_cmd = command; + + return rc; +} + /* Try to start a request. Return zero if the request was successfully * started or if it will be started at a later time. Return non-zero otherwise. * Called while sclp_lock is locked. */ @@ -259,7 +414,7 @@ __sclp_start_request(struct sclp_req *req) if (sclp_running_state != sclp_running_state_idle) return 0; del_timer(&sclp_request_timer); - rc = sclp_service_call(req->command, req->sccb); + rc = sclp_service_call_trace(req->command, req->sccb); req->start_count++; if (rc == 0) { @@ -309,6 +464,10 @@ sclp_process_queue(void) } /* Post-processing for aborted request */ list_del(&req->list); + + /* RQAB: Request aborted (a=sccb, b=summary) */ + sclp_trace_req(2, "RQAB", req, true); + if (req->callback) { spin_unlock_irqrestore(&sclp_lock, flags); req->callback(req, req->callback_data); @@ -341,6 +500,10 @@ sclp_add_request(struct sclp_req *req) spin_unlock_irqrestore(&sclp_lock, flags); return -EIO; } + + /* RQAD: Request was added (a=sccb, b=caller) */ + sclp_trace(2, "RQAD", (u32)(addr_t)req->sccb, _RET_IP_, false); + req->status = SCLP_REQ_QUEUED; req->start_count = 0; list_add_tail(&req->list, &sclp_req_queue); @@ -394,6 +557,11 @@ sclp_dispatch_evbufs(struct sccb_header *sccb) else reg = NULL; } + + /* EVNT: Event callback (b=receiver) */ + sclp_trace_evbuf(2, "EVNT", 0, reg ? (u64)reg->receiver_fn : 0, + evbuf, !reg); + if (reg && reg->receiver_fn) { spin_unlock_irqrestore(&sclp_lock, flags); reg->receiver_fn(evbuf); @@ -455,6 +623,30 @@ __sclp_find_req(u32 sccb) return NULL; } +static bool ok_response(u32 sccb_int, sclp_cmdw_t cmd) +{ + struct sccb_header *sccb = (struct sccb_header *)(addr_t)sccb_int; + struct evbuf_header *evbuf; + u16 response; + + if (!sccb) + return true; + + /* Check SCCB response. */ + response = sccb->response_code & 0xff; + if (response != 0x10 && response != 0x20) + return false; + + /* Check event-processed flag on outgoing events. */ + if (cmd == SCLP_CMDW_WRITE_EVENT_DATA) { + evbuf = (struct evbuf_header *)(sccb + 1); + if (!(evbuf->flags & 0x80)) + return false; + } + + return true; +} + /* Handler for external interruption. Perform request post-processing. * Prepare read event data request if necessary. Start processing of next * request on queue. */ @@ -469,6 +661,12 @@ static void sclp_interrupt_handler(struct ext_code ext_code, spin_lock(&sclp_lock); finished_sccb = param32 & 0xfffffff8; evbuf_pending = param32 & 0x3; + + /* INT: Interrupt received (a=intparm, b=cmd) */ + sclp_trace_sccb(0, "INT", param32, active_cmd, active_cmd, + (struct sccb_header *)(addr_t)finished_sccb, + !ok_response(finished_sccb, active_cmd)); + if (finished_sccb) { del_timer(&sclp_request_timer); sclp_running_state = sclp_running_state_reset_pending; @@ -477,13 +675,21 @@ static void sclp_interrupt_handler(struct ext_code ext_code, /* Request post-processing */ list_del(&req->list); req->status = SCLP_REQ_DONE; + + /* RQOK: Request success (a=sccb, b=summary) */ + sclp_trace_req(2, "RQOK", req, false); + if (req->callback) { spin_unlock(&sclp_lock); req->callback(req, req->callback_data); spin_lock(&sclp_lock); } + } else { + /* UNEX: Unexpected SCCB completion (a=sccb address) */ + sclp_trace(0, "UNEX", finished_sccb, 0, true); } sclp_running_state = sclp_running_state_idle; + active_cmd = 0; } if (evbuf_pending && sclp_activation_state == sclp_activation_state_active) @@ -507,9 +713,13 @@ sclp_sync_wait(void) unsigned long long old_tick; unsigned long flags; unsigned long cr0, cr0_sync; + static u64 sync_count; u64 timeout; int irq_context; + /* SYN1: Synchronous wait start (a=runstate, b=sync count) */ + sclp_trace(4, "SYN1", sclp_running_state, ++sync_count, false); + /* We'll be disabling timer interrupts, so we need a custom timeout * mechanism */ timeout = 0; @@ -547,6 +757,9 @@ sclp_sync_wait(void) _local_bh_enable(); local_tick_enable(old_tick); local_irq_restore(flags); + + /* SYN2: Synchronous wait end (a=runstate, b=sync_count) */ + sclp_trace(4, "SYN2", sclp_running_state, sync_count, false); } EXPORT_SYMBOL(sclp_sync_wait); @@ -576,8 +789,13 @@ sclp_dispatch_state_change(void) reg = NULL; } spin_unlock_irqrestore(&sclp_lock, flags); - if (reg && reg->state_change_fn) + if (reg && reg->state_change_fn) { + /* STCG: State-change callback (b=callback) */ + sclp_trace(2, "STCG", 0, (u64)reg->state_change_fn, + false); + reg->state_change_fn(reg); + } } while (reg); } @@ -651,6 +869,9 @@ sclp_register(struct sclp_register *reg) sccb_mask_t send_mask; int rc; + /* REG: Event listener registered (b=caller) */ + sclp_trace_register(2, "REG", 0, _RET_IP_, reg); + rc = sclp_init(); if (rc) return rc; @@ -683,6 +904,9 @@ sclp_unregister(struct sclp_register *reg) { unsigned long flags; + /* UREG: Event listener unregistered (b=caller) */ + sclp_trace_register(2, "UREG", 0, _RET_IP_, reg); + spin_lock_irqsave(&sclp_lock, flags); list_del(®->list); spin_unlock_irqrestore(&sclp_lock, flags); @@ -932,7 +1156,7 @@ sclp_check_interface(void) for (retry = 0; retry <= SCLP_INIT_RETRY; retry++) { __sclp_make_init_req(0, 0); sccb = (struct init_sccb *) sclp_init_req.sccb; - rc = sclp_service_call(sclp_init_req.command, sccb); + rc = sclp_service_call_trace(sclp_init_req.command, sccb); if (rc == -EIO) break; sclp_init_req.status = SCLP_REQ_RUNNING; diff --git a/drivers/s390/char/sclp.h b/drivers/s390/char/sclp.h index 8dd8ad83b78b..5e434108aae6 100644 --- a/drivers/s390/char/sclp.h +++ b/drivers/s390/char/sclp.h @@ -310,8 +310,6 @@ extern int sclp_console_drop; extern unsigned long sclp_console_full; extern bool sclp_mask_compat_mode; -extern char *sclp_early_sccb; - void sclp_early_wait_irq(void); int sclp_early_cmd(sclp_cmdw_t cmd, void *sccb); unsigned int sclp_early_con_check_linemode(struct init_sccb *sccb); diff --git a/drivers/s390/char/sclp_cmd.c b/drivers/s390/char/sclp_cmd.c index ab0518cfdcfe..998933e83610 100644 --- a/drivers/s390/char/sclp_cmd.c +++ b/drivers/s390/char/sclp_cmd.c @@ -457,7 +457,7 @@ static int __init sclp_detect_standby_memory(void) struct read_storage_sccb *sccb; int i, id, assigned, rc; - if (OLDMEM_BASE) /* No standby memory in kdump mode */ + if (oldmem_data.start) /* No standby memory in kdump mode */ return 0; if ((sclp.facilities & 0xe00000000000ULL) != 0xe00000000000ULL) return 0; diff --git a/drivers/s390/char/sclp_config.c b/drivers/s390/char/sclp_config.c index 039b2074db7e..c365110f2dae 100644 --- a/drivers/s390/char/sclp_config.c +++ b/drivers/s390/char/sclp_config.c @@ -50,12 +50,12 @@ static void sclp_cpu_capability_notify(struct work_struct *work) s390_update_cpu_mhz(); pr_info("CPU capability may have changed\n"); - get_online_cpus(); + cpus_read_lock(); for_each_online_cpu(cpu) { dev = get_cpu_device(cpu); kobject_uevent(&dev->kobj, KOBJ_CHANGE); } - put_online_cpus(); + cpus_read_unlock(); } static void __ref sclp_cpu_change_notify(struct work_struct *work) diff --git a/drivers/s390/char/sclp_early_core.c b/drivers/s390/char/sclp_early_core.c index b7329af076a0..676634de65a8 100644 --- a/drivers/s390/char/sclp_early_core.c +++ b/drivers/s390/char/sclp_early_core.c @@ -17,7 +17,7 @@ static struct read_info_sccb __bootdata(sclp_info_sccb); static int __bootdata(sclp_info_sccb_valid); -char *sclp_early_sccb = (char *) EARLY_SCCB_OFFSET; +char *__bootdata(sclp_early_sccb); int sclp_init_state = sclp_init_state_uninitialized; /* * Used to keep track of the size of the event masks. Qemu until version 2.11 @@ -211,6 +211,11 @@ static int sclp_early_setup(int disable, int *have_linemode, int *have_vt220) return rc; } +void sclp_early_set_buffer(void *sccb) +{ + sclp_early_sccb = sccb; +} + /* * Output one or more lines of text on the SCLP console (VT220 and / * or line-mode). @@ -235,11 +240,20 @@ void sclp_early_printk(const char *str) __sclp_early_printk(str, strlen(str)); } +/* + * We can't pass sclp_info_sccb to sclp_early_cmd() here directly, + * because it might not fulfil the requiremets for a SCLP communication buffer: + * - lie below 2G in memory + * - be page-aligned + * Therefore, we use the buffer sclp_early_sccb (which fulfils all those + * requirements) temporarily for communication and copy a received response + * back into the buffer sclp_info_sccb upon successful completion. + */ int __init sclp_early_read_info(void) { int i; int length = test_facility(140) ? EXT_SCCB_READ_SCP : PAGE_SIZE; - struct read_info_sccb *sccb = &sclp_info_sccb; + struct read_info_sccb *sccb = (struct read_info_sccb *)sclp_early_sccb; sclp_cmdw_t commands[] = {SCLP_CMDW_READ_SCP_INFO_FORCED, SCLP_CMDW_READ_SCP_INFO}; @@ -251,6 +265,7 @@ int __init sclp_early_read_info(void) if (sclp_early_cmd(commands[i], sccb)) break; if (sccb->header.response_code == 0x10) { + memcpy(&sclp_info_sccb, sccb, length); sclp_info_sccb_valid = 1; return 0; } diff --git a/drivers/s390/char/zcore.c b/drivers/s390/char/zcore.c index b5b0848da93b..3ba2d934a3e8 100644 --- a/drivers/s390/char/zcore.c +++ b/drivers/s390/char/zcore.c @@ -269,7 +269,7 @@ static int __init zcore_init(void) if (!is_ipl_type_dump()) return -ENODATA; - if (OLDMEM_BASE) + if (oldmem_data.start) return -ENODATA; zcore_dbf = debug_register("zcore", 4, 1, 4 * sizeof(long)); diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index a974943c27da..0ce48a354e04 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c @@ -430,9 +430,26 @@ static ssize_t pimpampom_show(struct device *dev, } static DEVICE_ATTR_RO(pimpampom); +static ssize_t dev_busid_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct subchannel *sch = to_subchannel(dev); + struct pmcw *pmcw = &sch->schib.pmcw; + + if ((pmcw->st == SUBCHANNEL_TYPE_IO || + pmcw->st == SUBCHANNEL_TYPE_MSG) && pmcw->dnv) + return sysfs_emit(buf, "0.%x.%04x\n", sch->schid.ssid, + pmcw->dev); + else + return sysfs_emit(buf, "none\n"); +} +static DEVICE_ATTR_RO(dev_busid); + static struct attribute *io_subchannel_type_attrs[] = { &dev_attr_chpids.attr, &dev_attr_pimpampom.attr, + &dev_attr_dev_busid.attr, NULL, }; ATTRIBUTE_GROUPS(io_subchannel_type); @@ -886,6 +903,18 @@ static ssize_t real_cssid_show(struct device *dev, struct device_attribute *a, } static DEVICE_ATTR_RO(real_cssid); +static ssize_t rescan_store(struct device *dev, struct device_attribute *a, + const char *buf, size_t count) +{ + CIO_TRACE_EVENT(4, "usr-rescan"); + + css_schedule_eval_all(); + css_complete_work(); + + return count; +} +static DEVICE_ATTR_WO(rescan); + static ssize_t cm_enable_show(struct device *dev, struct device_attribute *a, char *buf) { @@ -932,6 +961,7 @@ static umode_t cm_enable_mode(struct kobject *kobj, struct attribute *attr, static struct attribute *cssdev_attrs[] = { &dev_attr_real_cssid.attr, + &dev_attr_rescan.attr, NULL, }; diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h index f69ffbb8edc9..99c2212dc6a6 100644 --- a/drivers/s390/cio/qdio.h +++ b/drivers/s390/cio/qdio.h @@ -126,21 +126,9 @@ static inline int do_eqbs(u64 token, unsigned char *state, int queue, struct qdio_irq; -struct siga_flag { - u8 input:1; - u8 output:1; - u8 sync:1; - u8 sync_after_ai:1; - u8 sync_out_after_pci:1; - u8:3; -} __attribute__ ((packed)); - struct qdio_dev_perf_stat { unsigned int adapter_int; unsigned int qdio_int; - unsigned int pci_request_int; - - unsigned int tasklet_outbound; unsigned int siga_read; unsigned int siga_write; @@ -150,7 +138,6 @@ struct qdio_dev_perf_stat { unsigned int stop_polling; unsigned int inbound_queue_full; unsigned int outbound_call; - unsigned int outbound_handler; unsigned int outbound_queue_full; unsigned int fast_requeue; unsigned int target_full; @@ -180,12 +167,6 @@ struct qdio_input_q { }; struct qdio_output_q { - /* PCIs are enabled for the queue */ - int pci_out_enabled; - /* timer to check for more outbound work */ - struct timer_list timer; - /* tasklet to check for completions */ - struct tasklet_struct tasklet; }; /* @@ -250,8 +231,7 @@ struct qdio_irq { unsigned long sch_token; /* QEBSM facility */ enum qdio_irq_states state; - - struct siga_flag siga_flag; /* siga sync information from qdioac */ + u8 qdioac1; int nr_input_qs; int nr_output_qs; @@ -263,7 +243,6 @@ struct qdio_irq { struct qdio_ssqd_desc ssqd_desc; void (*orig_handler) (struct ccw_device *, unsigned long, struct irb *); - unsigned int scan_threshold; /* used SBALs before tasklet schedule */ int perf_stat_enabled; struct qdr *qdr; @@ -325,13 +304,9 @@ static inline void qdio_deliver_irq(struct qdio_irq *irq) #define pci_out_supported(irq) ((irq)->qib.ac & QIB_AC_OUTBOUND_PCI_SUPPORTED) #define is_qebsm(q) (q->irq_ptr->sch_token != 0) -#define need_siga_in(q) (q->irq_ptr->siga_flag.input) -#define need_siga_out(q) (q->irq_ptr->siga_flag.output) -#define need_siga_sync(q) (unlikely(q->irq_ptr->siga_flag.sync)) -#define need_siga_sync_after_ai(q) \ - (unlikely(q->irq_ptr->siga_flag.sync_after_ai)) -#define need_siga_sync_out_after_pci(q) \ - (unlikely(q->irq_ptr->siga_flag.sync_out_after_pci)) +#define qdio_need_siga_in(irq) ((irq)->qdioac1 & AC1_SIGA_INPUT_NEEDED) +#define qdio_need_siga_out(irq) ((irq)->qdioac1 & AC1_SIGA_OUTPUT_NEEDED) +#define qdio_need_siga_sync(irq) (unlikely((irq)->qdioac1 & AC1_SIGA_SYNC_NEEDED)) #define for_each_input_queue(irq_ptr, q, i) \ for (i = 0; i < irq_ptr->nr_input_qs && \ @@ -345,11 +320,6 @@ static inline void qdio_deliver_irq(struct qdio_irq *irq) #define sub_buf(bufnr, dec) QDIO_BUFNR((bufnr) - (dec)) #define prev_buf(bufnr) sub_buf(bufnr, 1) -#define queue_irqs_enabled(q) \ - (test_bit(QDIO_QUEUE_IRQS_DISABLED, &q->u.in.queue_irq_state) == 0) -#define queue_irqs_disabled(q) \ - (test_bit(QDIO_QUEUE_IRQS_DISABLED, &q->u.in.queue_irq_state) != 0) - extern u64 last_ai_time; /* prototypes for thin interrupt */ @@ -360,8 +330,6 @@ void qdio_thinint_exit(void); int test_nonshared_ind(struct qdio_irq *); /* prototypes for setup */ -void qdio_outbound_tasklet(struct tasklet_struct *t); -void qdio_outbound_timer(struct timer_list *t); void qdio_int_handler(struct ccw_device *cdev, unsigned long intparm, struct irb *irb); int qdio_allocate_qs(struct qdio_irq *irq_ptr, int nr_input_qs, diff --git a/drivers/s390/cio/qdio_debug.c b/drivers/s390/cio/qdio_debug.c index 00384f58f218..4bb7965daa0f 100644 --- a/drivers/s390/cio/qdio_debug.c +++ b/drivers/s390/cio/qdio_debug.c @@ -197,8 +197,6 @@ DEFINE_SHOW_ATTRIBUTE(ssqd); static char *qperf_names[] = { "Assumed adapter interrupts", "QDIO interrupts", - "Requested PCIs", - "Outbound tasklet runs", "SIGA read", "SIGA write", "SIGA sync", @@ -206,7 +204,6 @@ static char *qperf_names[] = { "Inbound stop_polling", "Inbound queue full", "Outbound calls", - "Outbound handler", "Outbound queue full", "Outbound fast_requeue", "Outbound target_full", diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index 3052fab00597..45e810c6ea3b 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c @@ -10,7 +10,6 @@ #include <linux/module.h> #include <linux/init.h> #include <linux/kernel.h> -#include <linux/timer.h> #include <linux/delay.h> #include <linux/gfp.h> #include <linux/io.h> @@ -304,12 +303,22 @@ static inline int qdio_siga_sync(struct qdio_q *q, unsigned int output, return (cc) ? -EIO : 0; } +static inline int qdio_sync_input_queue(struct qdio_q *q) +{ + return qdio_siga_sync(q, 0, q->mask); +} + +static inline int qdio_sync_output_queue(struct qdio_q *q) +{ + return qdio_siga_sync(q, q->mask, 0); +} + static inline int qdio_siga_sync_q(struct qdio_q *q) { if (q->is_input_q) - return qdio_siga_sync(q, 0, q->mask); + return qdio_sync_input_queue(q); else - return qdio_siga_sync(q, q->mask, 0); + return qdio_sync_output_queue(q); } static int qdio_siga_output(struct qdio_q *q, unsigned int count, @@ -373,22 +382,10 @@ static inline int qdio_siga_input(struct qdio_q *q) return (cc) ? -EIO : 0; } -#define qdio_siga_sync_out(q) qdio_siga_sync(q, ~0U, 0) -#define qdio_siga_sync_all(q) qdio_siga_sync(q, ~0U, ~0U) - -static inline void qdio_sync_queues(struct qdio_q *q) -{ - /* PCI capable outbound queues will also be scanned so sync them too */ - if (pci_out_supported(q->irq_ptr)) - qdio_siga_sync_all(q); - else - qdio_siga_sync_q(q); -} - int debug_get_buf_state(struct qdio_q *q, unsigned int bufnr, unsigned char *state) { - if (need_siga_sync(q)) + if (qdio_need_siga_sync(q->irq_ptr)) qdio_siga_sync_q(q); return get_buf_state(q, bufnr, state, 0); } @@ -455,10 +452,9 @@ static int get_inbound_buffer_frontier(struct qdio_q *q, unsigned int start, if (!count) return 0; - /* - * No siga sync here, as a PCI or we after a thin interrupt - * already sync'ed the queues. - */ + if (qdio_need_siga_sync(q->irq_ptr)) + qdio_sync_input_queue(q); + count = get_buf_states(q, start, &state, count, 1); if (!count) return 0; @@ -510,8 +506,8 @@ static inline int qdio_inbound_q_done(struct qdio_q *q, unsigned int start) if (!atomic_read(&q->nr_buf_used)) return 1; - if (need_siga_sync(q)) - qdio_siga_sync_q(q); + if (qdio_need_siga_sync(q->irq_ptr)) + qdio_sync_input_queue(q); get_buf_state(q, start, &state, 0); if (state == SLSB_P_INPUT_PRIMED || state == SLSB_P_INPUT_ERROR) @@ -521,15 +517,6 @@ static inline int qdio_inbound_q_done(struct qdio_q *q, unsigned int start) return 1; } -static inline int qdio_tasklet_schedule(struct qdio_q *q) -{ - if (likely(q->irq_ptr->state == QDIO_IRQ_STATE_ACTIVE)) { - tasklet_schedule(&q->u.out.tasklet); - return 0; - } - return -EPERM; -} - static int get_outbound_buffer_frontier(struct qdio_q *q, unsigned int start, unsigned int *error) { @@ -538,17 +525,13 @@ static int get_outbound_buffer_frontier(struct qdio_q *q, unsigned int start, q->timestamp = get_tod_clock_fast(); - if (need_siga_sync(q)) - if (((queue_type(q) != QDIO_IQDIO_QFMT) && - !pci_out_supported(q->irq_ptr)) || - (queue_type(q) == QDIO_IQDIO_QFMT && - multicast_outbound(q))) - qdio_siga_sync_q(q); - count = atomic_read(&q->nr_buf_used); if (!count) return 0; + if (qdio_need_siga_sync(q->irq_ptr)) + qdio_sync_output_queue(q); + count = get_buf_states(q, start, &state, count, 0); if (!count) return 0; @@ -595,19 +578,13 @@ static int get_outbound_buffer_frontier(struct qdio_q *q, unsigned int start, } } -/* all buffers processed? */ -static inline int qdio_outbound_q_done(struct qdio_q *q) -{ - return atomic_read(&q->nr_buf_used) == 0; -} - static int qdio_kick_outbound_q(struct qdio_q *q, unsigned int count, unsigned long aob) { int retries = 0, cc; unsigned int busy_bit; - if (!need_siga_out(q)) + if (!qdio_need_siga_out(q->irq_ptr)) return 0; DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "siga-w:%1d", q->nr); @@ -644,75 +621,6 @@ retry: return cc; } -void qdio_outbound_tasklet(struct tasklet_struct *t) -{ - struct qdio_output_q *out_q = from_tasklet(out_q, t, tasklet); - struct qdio_q *q = container_of(out_q, struct qdio_q, u.out); - unsigned int start = q->first_to_check; - unsigned int error = 0; - int count; - - qperf_inc(q, tasklet_outbound); - WARN_ON_ONCE(atomic_read(&q->nr_buf_used) < 0); - - count = get_outbound_buffer_frontier(q, start, &error); - if (count) { - q->first_to_check = add_buf(start, count); - - if (q->irq_ptr->state == QDIO_IRQ_STATE_ACTIVE) { - qperf_inc(q, outbound_handler); - DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "koh: s:%02x c:%02x", - start, count); - - q->handler(q->irq_ptr->cdev, error, q->nr, start, - count, q->irq_ptr->int_parm); - } - } - - if (queue_type(q) == QDIO_ZFCP_QFMT && !pci_out_supported(q->irq_ptr) && - !qdio_outbound_q_done(q)) - goto sched; - - if (q->u.out.pci_out_enabled) - return; - - /* - * Now we know that queue type is either qeth without pci enabled - * or HiperSockets. Make sure buffer switch from PRIMED to EMPTY - * is noticed and outbound_handler is called after some time. - */ - if (qdio_outbound_q_done(q)) - del_timer_sync(&q->u.out.timer); - else - if (!timer_pending(&q->u.out.timer) && - likely(q->irq_ptr->state == QDIO_IRQ_STATE_ACTIVE)) - mod_timer(&q->u.out.timer, jiffies + 10 * HZ); - return; - -sched: - qdio_tasklet_schedule(q); -} - -void qdio_outbound_timer(struct timer_list *t) -{ - struct qdio_q *q = from_timer(q, t, u.out.timer); - - qdio_tasklet_schedule(q); -} - -static inline void qdio_check_outbound_pci_queues(struct qdio_irq *irq) -{ - struct qdio_q *out; - int i; - - if (!pci_out_supported(irq) || !irq->scan_threshold) - return; - - for_each_output_queue(irq, out, i) - if (!qdio_outbound_q_done(out)) - qdio_tasklet_schedule(out); -} - static inline void qdio_set_state(struct qdio_irq *irq_ptr, enum qdio_irq_states state) { @@ -734,25 +642,11 @@ static void qdio_irq_check_sense(struct qdio_irq *irq_ptr, struct irb *irb) /* PCI interrupt handler */ static void qdio_int_handler_pci(struct qdio_irq *irq_ptr) { - int i; - struct qdio_q *q; - if (unlikely(irq_ptr->state != QDIO_IRQ_STATE_ACTIVE)) return; qdio_deliver_irq(irq_ptr); irq_ptr->last_data_irq_time = S390_lowcore.int_clock; - - if (!pci_out_supported(irq_ptr) || !irq_ptr->scan_threshold) - return; - - for_each_output_queue(irq_ptr, q, i) { - if (qdio_outbound_q_done(q)) - continue; - if (need_siga_sync(q) && need_siga_sync_out_after_pci(q)) - qdio_siga_sync_q(q); - qdio_tasklet_schedule(q); - } } static void qdio_handle_activate_check(struct qdio_irq *irq_ptr, @@ -879,15 +773,34 @@ int qdio_get_ssqd_desc(struct ccw_device *cdev, } EXPORT_SYMBOL_GPL(qdio_get_ssqd_desc); -static void qdio_shutdown_queues(struct qdio_irq *irq_ptr) +static int qdio_cancel_ccw(struct qdio_irq *irq, int how) { - struct qdio_q *q; - int i; + struct ccw_device *cdev = irq->cdev; + long timeout; + int rc; - for_each_output_queue(irq_ptr, q, i) { - del_timer_sync(&q->u.out.timer); - tasklet_kill(&q->u.out.tasklet); + spin_lock_irq(get_ccwdev_lock(cdev)); + qdio_set_state(irq, QDIO_IRQ_STATE_CLEANUP); + if (how & QDIO_FLAG_CLEANUP_USING_CLEAR) + rc = ccw_device_clear(cdev, QDIO_DOING_CLEANUP); + else + /* default behaviour is halt */ + rc = ccw_device_halt(cdev, QDIO_DOING_CLEANUP); + spin_unlock_irq(get_ccwdev_lock(cdev)); + if (rc) { + DBF_ERROR("%4x SHUTD ERR", irq->schid.sch_no); + DBF_ERROR("rc:%4d", rc); + return rc; } + + timeout = wait_event_interruptible_timeout(cdev->private->wait_q, + irq->state == QDIO_IRQ_STATE_INACTIVE || + irq->state == QDIO_IRQ_STATE_ERR, + 10 * HZ); + if (timeout <= 0) + rc = (timeout == -ERESTARTSYS) ? -EINTR : -ETIME; + + return rc; } /** @@ -919,35 +832,13 @@ int qdio_shutdown(struct ccw_device *cdev, int how) } /* - * Indicate that the device is going down. Scheduling the queue - * tasklets is forbidden from here on. + * Indicate that the device is going down. */ qdio_set_state(irq_ptr, QDIO_IRQ_STATE_STOPPED); - qdio_shutdown_queues(irq_ptr); qdio_shutdown_debug_entries(irq_ptr); - /* cleanup subchannel */ - spin_lock_irq(get_ccwdev_lock(cdev)); - qdio_set_state(irq_ptr, QDIO_IRQ_STATE_CLEANUP); - if (how & QDIO_FLAG_CLEANUP_USING_CLEAR) - rc = ccw_device_clear(cdev, QDIO_DOING_CLEANUP); - else - /* default behaviour is halt */ - rc = ccw_device_halt(cdev, QDIO_DOING_CLEANUP); - spin_unlock_irq(get_ccwdev_lock(cdev)); - if (rc) { - DBF_ERROR("%4x SHUTD ERR", irq_ptr->schid.sch_no); - DBF_ERROR("rc:%4d", rc); - goto no_cleanup; - } - - wait_event_interruptible_timeout(cdev->private->wait_q, - irq_ptr->state == QDIO_IRQ_STATE_INACTIVE || - irq_ptr->state == QDIO_IRQ_STATE_ERR, - 10 * HZ); - -no_cleanup: + rc = qdio_cancel_ccw(irq_ptr, how); qdio_shutdown_thinint(irq_ptr); qdio_shutdown_irq(irq_ptr); @@ -1061,8 +952,6 @@ static void qdio_trace_init_data(struct qdio_irq *irq, DBF_DEV_EVENT(DBF_ERR, irq, "qfmt:%1u", data->q_format); DBF_DEV_EVENT(DBF_ERR, irq, "qpff%4x", data->qib_param_field_format); DBF_DEV_HEX(irq, &data->qib_param_field, sizeof(void *), DBF_ERR); - DBF_DEV_HEX(irq, &data->input_slib_elements, sizeof(void *), DBF_ERR); - DBF_DEV_HEX(irq, &data->output_slib_elements, sizeof(void *), DBF_ERR); DBF_DEV_EVENT(DBF_ERR, irq, "niq:%1u noq:%1u", data->no_input_qs, data->no_output_qs); DBF_DEV_HEX(irq, &data->input_handler, sizeof(void *), DBF_ERR); @@ -1083,6 +972,7 @@ int qdio_establish(struct ccw_device *cdev, { struct qdio_irq *irq_ptr = cdev->private->qdio_data; struct subchannel_id schid; + long timeout; int rc; ccw_device_get_schid(cdev, &schid); @@ -1111,17 +1001,14 @@ int qdio_establish(struct ccw_device *cdev, qdio_setup_irq(irq_ptr, init_data); rc = qdio_establish_thinint(irq_ptr); - if (rc) { - qdio_shutdown_irq(irq_ptr); - mutex_unlock(&irq_ptr->setup_mutex); - return rc; - } + if (rc) + goto err_thinint; /* establish q */ irq_ptr->ccw.cmd_code = irq_ptr->equeue.cmd; irq_ptr->ccw.flags = CCW_FLAG_SLI; irq_ptr->ccw.count = irq_ptr->equeue.count; - irq_ptr->ccw.cda = (u32)((addr_t)irq_ptr->qdr); + irq_ptr->ccw.cda = (u32) virt_to_phys(irq_ptr->qdr); spin_lock_irq(get_ccwdev_lock(cdev)); ccw_device_set_options_mask(cdev, 0); @@ -1131,20 +1018,20 @@ int qdio_establish(struct ccw_device *cdev, if (rc) { DBF_ERROR("%4x est IO ERR", irq_ptr->schid.sch_no); DBF_ERROR("rc:%4x", rc); - qdio_shutdown_thinint(irq_ptr); - qdio_shutdown_irq(irq_ptr); - mutex_unlock(&irq_ptr->setup_mutex); - return rc; + goto err_ccw_start; } - wait_event_interruptible_timeout(cdev->private->wait_q, - irq_ptr->state == QDIO_IRQ_STATE_ESTABLISHED || - irq_ptr->state == QDIO_IRQ_STATE_ERR, HZ); + timeout = wait_event_interruptible_timeout(cdev->private->wait_q, + irq_ptr->state == QDIO_IRQ_STATE_ESTABLISHED || + irq_ptr->state == QDIO_IRQ_STATE_ERR, HZ); + if (timeout <= 0) { + rc = (timeout == -ERESTARTSYS) ? -EINTR : -ETIME; + goto err_ccw_timeout; + } if (irq_ptr->state != QDIO_IRQ_STATE_ESTABLISHED) { - mutex_unlock(&irq_ptr->setup_mutex); - qdio_shutdown(cdev, QDIO_FLAG_CLEANUP_USING_CLEAR); - return -EIO; + rc = -EIO; + goto err_ccw_error; } qdio_setup_ssqd_info(irq_ptr); @@ -1156,6 +1043,17 @@ int qdio_establish(struct ccw_device *cdev, qdio_print_subchannel_info(irq_ptr); qdio_setup_debug_entries(irq_ptr); return 0; + +err_ccw_timeout: + qdio_cancel_ccw(irq_ptr, QDIO_FLAG_CLEANUP_USING_CLEAR); +err_ccw_error: +err_ccw_start: + qdio_shutdown_thinint(irq_ptr); +err_thinint: + qdio_shutdown_irq(irq_ptr); + qdio_set_state(irq_ptr, QDIO_IRQ_STATE_INACTIVE); + mutex_unlock(&irq_ptr->setup_mutex); + return rc; } EXPORT_SYMBOL_GPL(qdio_establish); @@ -1219,12 +1117,10 @@ EXPORT_SYMBOL_GPL(qdio_activate); /** * handle_inbound - reset processed input buffers * @q: queue containing the buffers - * @callflags: flags * @bufnr: first buffer to process * @count: how many buffers are emptied */ -static int handle_inbound(struct qdio_q *q, unsigned int callflags, - int bufnr, int count) +static int handle_inbound(struct qdio_q *q, int bufnr, int count) { int overlap; @@ -1241,7 +1137,7 @@ static int handle_inbound(struct qdio_q *q, unsigned int callflags, count = set_buf_states(q, bufnr, SLSB_CU_INPUT_EMPTY, count); atomic_add(count, &q->nr_buf_used); - if (need_siga_in(q)) + if (qdio_need_siga_in(q->irq_ptr)) return qdio_siga_input(q); return 0; @@ -1250,16 +1146,13 @@ static int handle_inbound(struct qdio_q *q, unsigned int callflags, /** * handle_outbound - process filled outbound buffers * @q: queue containing the buffers - * @callflags: flags * @bufnr: first buffer to process * @count: how many buffers are filled * @aob: asynchronous operation block */ -static int handle_outbound(struct qdio_q *q, unsigned int callflags, - unsigned int bufnr, unsigned int count, +static int handle_outbound(struct qdio_q *q, unsigned int bufnr, unsigned int count, struct qaob *aob) { - const unsigned int scan_threshold = q->irq_ptr->scan_threshold; unsigned char state = 0; int used, rc = 0; @@ -1271,19 +1164,13 @@ static int handle_outbound(struct qdio_q *q, unsigned int callflags, if (used == QDIO_MAX_BUFFERS_PER_Q) qperf_inc(q, outbound_queue_full); - if (callflags & QDIO_FLAG_PCI_OUT) { - q->u.out.pci_out_enabled = 1; - qperf_inc(q, pci_request_int); - } else - q->u.out.pci_out_enabled = 0; - if (queue_type(q) == QDIO_IQDIO_QFMT) { unsigned long phys_aob = aob ? virt_to_phys(aob) : 0; WARN_ON_ONCE(!IS_ALIGNED(phys_aob, 256)); rc = qdio_kick_outbound_q(q, count, phys_aob); - } else if (need_siga_sync(q)) { - rc = qdio_siga_sync_q(q); + } else if (qdio_need_siga_sync(q->irq_ptr)) { + rc = qdio_sync_output_queue(q); } else if (count < QDIO_MAX_BUFFERS_PER_Q && get_buf_state(q, prev_buf(bufnr), &state, 0) > 0 && state == SLSB_CU_OUTPUT_PRIMED) { @@ -1293,18 +1180,6 @@ static int handle_outbound(struct qdio_q *q, unsigned int callflags, rc = qdio_kick_outbound_q(q, count, 0); } - /* Let drivers implement their own completion scanning: */ - if (!scan_threshold) - return rc; - - /* in case of SIGA errors we must process the error immediately */ - if (used >= scan_threshold || rc) - qdio_tasklet_schedule(q); - else - /* free the SBALs in case of no further traffic */ - if (!timer_pending(&q->u.out.timer) && - likely(q->irq_ptr->state == QDIO_IRQ_STATE_ACTIVE)) - mod_timer(&q->u.out.timer, jiffies + HZ); return rc; } @@ -1336,11 +1211,9 @@ int do_QDIO(struct ccw_device *cdev, unsigned int callflags, if (!count) return 0; if (callflags & QDIO_FLAG_SYNC_INPUT) - return handle_inbound(irq_ptr->input_qs[q_nr], - callflags, bufnr, count); + return handle_inbound(irq_ptr->input_qs[q_nr], bufnr, count); else if (callflags & QDIO_FLAG_SYNC_OUTPUT) - return handle_outbound(irq_ptr->output_qs[q_nr], - callflags, bufnr, count, aob); + return handle_outbound(irq_ptr->output_qs[q_nr], bufnr, count, aob); return -EINVAL; } EXPORT_SYMBOL_GPL(do_QDIO); @@ -1420,53 +1293,11 @@ int qdio_inspect_queue(struct ccw_device *cdev, unsigned int nr, bool is_input, return -ENODEV; q = is_input ? irq_ptr->input_qs[nr] : irq_ptr->output_qs[nr]; - if (need_siga_sync(q)) - qdio_siga_sync_q(q); - return __qdio_inspect_queue(q, bufnr, error); } EXPORT_SYMBOL_GPL(qdio_inspect_queue); /** - * qdio_get_next_buffers - process input buffers - * @cdev: associated ccw_device for the qdio subchannel - * @nr: input queue number - * @bufnr: first filled buffer number - * @error: buffers are in error state - * - * Return codes - * < 0 - error - * = 0 - no new buffers found - * > 0 - number of processed buffers - */ -int qdio_get_next_buffers(struct ccw_device *cdev, int nr, int *bufnr, - int *error) -{ - struct qdio_q *q; - struct qdio_irq *irq_ptr = cdev->private->qdio_data; - - if (!irq_ptr) - return -ENODEV; - q = irq_ptr->input_qs[nr]; - - /* - * Cannot rely on automatic sync after interrupt since queues may - * also be examined without interrupt. - */ - if (need_siga_sync(q)) - qdio_sync_queues(q); - - qdio_check_outbound_pci_queues(irq_ptr); - - /* Note: upper-layer MUST stop processing immediately here ... */ - if (unlikely(q->irq_ptr->state != QDIO_IRQ_STATE_ACTIVE)) - return -EIO; - - return __qdio_inspect_queue(q, bufnr, error); -} -EXPORT_SYMBOL(qdio_get_next_buffers); - -/** * qdio_stop_irq - disable interrupt processing for the device * @cdev: associated ccw_device for the qdio subchannel * diff --git a/drivers/s390/cio/qdio_setup.c b/drivers/s390/cio/qdio_setup.c index da67e4979402..20efafe47897 100644 --- a/drivers/s390/cio/qdio_setup.c +++ b/drivers/s390/cio/qdio_setup.c @@ -89,55 +89,6 @@ void qdio_reset_buffers(struct qdio_buffer **buf, unsigned int count) } EXPORT_SYMBOL_GPL(qdio_reset_buffers); -/* - * qebsm is only available under 64bit but the adapter sets the feature - * flag anyway, so we manually override it. - */ -static inline int qebsm_possible(void) -{ - return css_general_characteristics.qebsm; -} - -/* - * qib_param_field: pointer to 128 bytes or NULL, if no param field - * nr_input_qs: pointer to nr_queues*128 words of data or NULL - */ -static void set_impl_params(struct qdio_irq *irq_ptr, - unsigned int qib_param_field_format, - unsigned char *qib_param_field, - unsigned long *input_slib_elements, - unsigned long *output_slib_elements) -{ - struct qdio_q *q; - int i, j; - - if (!irq_ptr) - return; - - irq_ptr->qib.pfmt = qib_param_field_format; - if (qib_param_field) - memcpy(irq_ptr->qib.parm, qib_param_field, - sizeof(irq_ptr->qib.parm)); - - if (!input_slib_elements) - goto output; - - for_each_input_queue(irq_ptr, q, i) { - for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; j++) - q->slib->slibe[j].parms = - input_slib_elements[i * QDIO_MAX_BUFFERS_PER_Q + j]; - } -output: - if (!output_slib_elements) - return; - - for_each_output_queue(irq_ptr, q, i) { - for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; j++) - q->slib->slibe[j].parms = - output_slib_elements[i * QDIO_MAX_BUFFERS_PER_Q + j]; - } -} - static void __qdio_free_queues(struct qdio_q **queues, unsigned int count) { struct qdio_q *q; @@ -267,26 +218,9 @@ static void setup_queues(struct qdio_irq *irq_ptr, q->is_input_q = 0; setup_storage_lists(q, irq_ptr, qdio_init->output_sbal_addr_array[i], i); - - tasklet_setup(&q->u.out.tasklet, qdio_outbound_tasklet); - timer_setup(&q->u.out.timer, qdio_outbound_timer, 0); } } -static void process_ac_flags(struct qdio_irq *irq_ptr, unsigned char qdioac) -{ - if (qdioac & AC1_SIGA_INPUT_NEEDED) - irq_ptr->siga_flag.input = 1; - if (qdioac & AC1_SIGA_OUTPUT_NEEDED) - irq_ptr->siga_flag.output = 1; - if (qdioac & AC1_SIGA_SYNC_NEEDED) - irq_ptr->siga_flag.sync = 1; - if (!(qdioac & AC1_AUTOMATIC_SYNC_ON_THININT)) - irq_ptr->siga_flag.sync_after_ai = 1; - if (!(qdioac & AC1_AUTOMATIC_SYNC_ON_OUT_PCI)) - irq_ptr->siga_flag.sync_out_after_pci = 1; -} - static void check_and_setup_qebsm(struct qdio_irq *irq_ptr, unsigned char qdioac, unsigned long token) { @@ -363,7 +297,7 @@ void qdio_setup_ssqd_info(struct qdio_irq *irq_ptr) qdioac = irq_ptr->ssqd_desc.qdioac1; check_and_setup_qebsm(irq_ptr, qdioac, irq_ptr->ssqd_desc.sch_token); - process_ac_flags(irq_ptr, qdioac); + irq_ptr->qdioac1 = qdioac; DBF_EVENT("ac 1:%2x 2:%4x", qdioac, irq_ptr->ssqd_desc.qdioac2); DBF_EVENT("3:%4x qib:%4x", irq_ptr->ssqd_desc.qdioac3, irq_ptr->qib.ac); } @@ -386,6 +320,8 @@ static void setup_qdr(struct qdio_irq *irq_ptr, struct qdesfmt0 *desc = &irq_ptr->qdr->qdf0[0]; int i; + memset(irq_ptr->qdr, 0, sizeof(struct qdr)); + irq_ptr->qdr->qfmt = qdio_init->q_format; irq_ptr->qdr->ac = qdio_init->qdr_ac; irq_ptr->qdr->iqdcnt = qdio_init->no_input_qs; @@ -405,12 +341,15 @@ static void setup_qdr(struct qdio_irq *irq_ptr, static void setup_qib(struct qdio_irq *irq_ptr, struct qdio_initialize *init_data) { - if (qebsm_possible()) - irq_ptr->qib.rflags |= QIB_RFLAGS_ENABLE_QEBSM; - - irq_ptr->qib.rflags |= init_data->qib_rflags; + memset(&irq_ptr->qib, 0, sizeof(irq_ptr->qib)); irq_ptr->qib.qfmt = init_data->q_format; + irq_ptr->qib.pfmt = init_data->qib_param_field_format; + + irq_ptr->qib.rflags = init_data->qib_rflags; + if (css_general_characteristics.qebsm) + irq_ptr->qib.rflags |= QIB_RFLAGS_ENABLE_QEBSM; + if (init_data->no_input_qs) irq_ptr->qib.isliba = (unsigned long)(irq_ptr->input_qs[0]->slib); @@ -419,6 +358,10 @@ static void setup_qib(struct qdio_irq *irq_ptr, (unsigned long)(irq_ptr->output_qs[0]->slib); memcpy(irq_ptr->qib.ebcnam, dev_name(&irq_ptr->cdev->dev), 8); ASCEBC(irq_ptr->qib.ebcnam, 8); + + if (init_data->qib_param_field) + memcpy(irq_ptr->qib.parm, init_data->qib_param_field, + sizeof(irq_ptr->qib.parm)); } int qdio_setup_irq(struct qdio_irq *irq_ptr, struct qdio_initialize *init_data) @@ -426,8 +369,7 @@ int qdio_setup_irq(struct qdio_irq *irq_ptr, struct qdio_initialize *init_data) struct ccw_device *cdev = irq_ptr->cdev; struct ciw *ciw; - memset(&irq_ptr->qib, 0, sizeof(irq_ptr->qib)); - memset(&irq_ptr->siga_flag, 0, sizeof(irq_ptr->siga_flag)); + irq_ptr->qdioac1 = 0; memset(&irq_ptr->ccw, 0, sizeof(irq_ptr->ccw)); memset(&irq_ptr->ssqd_desc, 0, sizeof(irq_ptr->ssqd_desc)); memset(&irq_ptr->perf_stat, 0, sizeof(irq_ptr->perf_stat)); @@ -436,13 +378,9 @@ int qdio_setup_irq(struct qdio_irq *irq_ptr, struct qdio_initialize *init_data) irq_ptr->sch_token = irq_ptr->perf_stat_enabled = 0; irq_ptr->state = QDIO_IRQ_STATE_INACTIVE; - /* wipes qib.ac, required by ar7063 */ - memset(irq_ptr->qdr, 0, sizeof(struct qdr)); - irq_ptr->int_parm = init_data->int_parm; irq_ptr->nr_input_qs = init_data->no_input_qs; irq_ptr->nr_output_qs = init_data->no_output_qs; - irq_ptr->scan_threshold = init_data->scan_threshold; ccw_device_get_schid(cdev, &irq_ptr->schid); setup_queues(irq_ptr, init_data); @@ -450,10 +388,6 @@ int qdio_setup_irq(struct qdio_irq *irq_ptr, struct qdio_initialize *init_data) set_bit(QDIO_IRQ_DISABLED, &irq_ptr->poll_state); setup_qib(irq_ptr, init_data); - set_impl_params(irq_ptr, init_data->qib_param_field_format, - init_data->qib_param_field, - init_data->input_slib_elements, - init_data->output_slib_elements); /* fill input and output descriptors */ setup_qdr(irq_ptr, init_data); @@ -497,11 +431,8 @@ void qdio_shutdown_irq(struct qdio_irq *irq) void qdio_print_subchannel_info(struct qdio_irq *irq_ptr) { - char s[80]; - - snprintf(s, 80, "qdio: %s %s on SC %x using " - "AI:%d QEBSM:%d PRI:%d TDD:%d SIGA:%s%s%s%s%s\n", - dev_name(&irq_ptr->cdev->dev), + dev_info(&irq_ptr->cdev->dev, + "qdio: %s on SC %x using AI:%d QEBSM:%d PRI:%d TDD:%d SIGA:%s%s%s\n", (irq_ptr->qib.qfmt == QDIO_QETH_QFMT) ? "OSA" : ((irq_ptr->qib.qfmt == QDIO_ZFCP_QFMT) ? "ZFCP" : "HS"), irq_ptr->schid.sch_no, @@ -509,12 +440,9 @@ void qdio_print_subchannel_info(struct qdio_irq *irq_ptr) (irq_ptr->sch_token) ? 1 : 0, pci_out_supported(irq_ptr) ? 1 : 0, css_general_characteristics.aif_tdd, - (irq_ptr->siga_flag.input) ? "R" : " ", - (irq_ptr->siga_flag.output) ? "W" : " ", - (irq_ptr->siga_flag.sync) ? "S" : " ", - (irq_ptr->siga_flag.sync_after_ai) ? "A" : " ", - (irq_ptr->siga_flag.sync_out_after_pci) ? "P" : " "); - printk(KERN_INFO "%s", s); + qdio_need_siga_in(irq_ptr) ? "R" : " ", + qdio_need_siga_out(irq_ptr) ? "W" : " ", + qdio_need_siga_sync(irq_ptr) ? "S" : " "); } int __init qdio_setup_init(void) @@ -541,7 +469,7 @@ int __init qdio_setup_init(void) (css_general_characteristics.aif_osa) ? 1 : 0); /* Check for QEBSM support in general (bit 58). */ - DBF_EVENT("cssQEBSM:%1d", (qebsm_possible()) ? 1 : 0); + DBF_EVENT("cssQEBSM:%1d", css_general_characteristics.qebsm); rc = 0; out: return rc; diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index 8d3a1d84a757..439c1f6d2866 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -127,7 +127,7 @@ static struct bus_type ap_bus_type; /* Adapter interrupt definitions */ static void ap_interrupt_handler(struct airq_struct *airq, bool floating); -static int ap_airq_flag; +static bool ap_irq_flag; static struct airq_struct ap_airq = { .handler = ap_interrupt_handler, @@ -135,15 +135,6 @@ static struct airq_struct ap_airq = { }; /** - * ap_using_interrupts() - Returns non-zero if interrupt support is - * available. - */ -static inline int ap_using_interrupts(void) -{ - return ap_airq_flag; -} - -/** * ap_airq_ptr() - Get the address of the adapter interrupt indicator * * Returns the address of the local-summary-indicator of the adapter @@ -152,7 +143,7 @@ static inline int ap_using_interrupts(void) */ void *ap_airq_ptr(void) { - if (ap_using_interrupts()) + if (ap_irq_flag) return ap_airq.lsi_ptr; return NULL; } @@ -396,7 +387,7 @@ void ap_wait(enum ap_sm_wait wait) switch (wait) { case AP_SM_WAIT_AGAIN: case AP_SM_WAIT_INTERRUPT: - if (ap_using_interrupts()) + if (ap_irq_flag) break; if (ap_poll_kthread) { wake_up(&ap_poll_wait); @@ -471,7 +462,7 @@ static void ap_tasklet_fn(unsigned long dummy) * be received. Doing it in the beginning of the tasklet is therefor * important that no requests on any AP get lost. */ - if (ap_using_interrupts()) + if (ap_irq_flag) xchg(ap_airq.lsi_ptr, 0); spin_lock_bh(&ap_queues_lock); @@ -541,7 +532,7 @@ static int ap_poll_thread_start(void) { int rc; - if (ap_using_interrupts() || ap_poll_kthread) + if (ap_irq_flag || ap_poll_kthread) return 0; mutex_lock(&ap_poll_thread_mutex); ap_poll_kthread = kthread_run(ap_poll_thread, NULL, "appoll"); @@ -703,7 +694,7 @@ static int __ap_calc_helper(struct device *dev, void *arg) if (is_queue_dev(dev)) { pctrs->apqns++; - if ((to_ap_dev(dev))->drv) + if (dev->driver) pctrs->bound++; } @@ -883,7 +874,6 @@ static int ap_device_probe(struct device *dev) to_ap_queue(dev)->qid); spin_unlock_bh(&ap_queues_lock); - ap_dev->drv = ap_drv; rc = ap_drv->probe ? ap_drv->probe(ap_dev) : -ENODEV; if (rc) { @@ -891,7 +881,6 @@ static int ap_device_probe(struct device *dev) if (is_queue_dev(dev)) hash_del(&to_ap_queue(dev)->hnode); spin_unlock_bh(&ap_queues_lock); - ap_dev->drv = NULL; } else ap_check_bindings_complete(); @@ -904,7 +893,7 @@ out: static int ap_device_remove(struct device *dev) { struct ap_device *ap_dev = to_ap_dev(dev); - struct ap_driver *ap_drv = ap_dev->drv; + struct ap_driver *ap_drv = to_ap_drv(dev->driver); /* prepare ap queue device removal */ if (is_queue_dev(dev)) @@ -923,7 +912,6 @@ static int ap_device_remove(struct device *dev) if (is_queue_dev(dev)) hash_del(&to_ap_queue(dev)->hnode); spin_unlock_bh(&ap_queues_lock); - ap_dev->drv = NULL; put_device(dev); @@ -1187,7 +1175,7 @@ static BUS_ATTR_RO(ap_adapter_mask); static ssize_t ap_interrupts_show(struct bus_type *bus, char *buf) { return scnprintf(buf, PAGE_SIZE, "%d\n", - ap_using_interrupts() ? 1 : 0); + ap_irq_flag ? 1 : 0); } static BUS_ATTR_RO(ap_interrupts); @@ -1912,7 +1900,7 @@ static int __init ap_module_init(void) /* enable interrupts if available */ if (ap_interrupts_available()) { rc = register_adapter_interrupt(&ap_airq); - ap_airq_flag = (rc == 0); + ap_irq_flag = (rc == 0); } /* Create /sys/bus/ap. */ @@ -1956,7 +1944,7 @@ out_work: out_bus: bus_unregister(&ap_bus_type); out: - if (ap_using_interrupts()) + if (ap_irq_flag) unregister_adapter_interrupt(&ap_airq); kfree(ap_qci_info); return rc; diff --git a/drivers/s390/crypto/ap_bus.h b/drivers/s390/crypto/ap_bus.h index 8f18abdbbc2b..95b577754b35 100644 --- a/drivers/s390/crypto/ap_bus.h +++ b/drivers/s390/crypto/ap_bus.h @@ -81,12 +81,6 @@ static inline int ap_test_bit(unsigned int *ptr, unsigned int nr) #define AP_FUNC_APXA 6 /* - * AP interrupt states - */ -#define AP_INTR_DISABLED 0 /* AP interrupt disabled */ -#define AP_INTR_ENABLED 1 /* AP interrupt enabled */ - -/* * AP queue state machine states */ enum ap_sm_state { @@ -112,7 +106,7 @@ enum ap_sm_event { * AP queue state wait behaviour */ enum ap_sm_wait { - AP_SM_WAIT_AGAIN, /* retry immediately */ + AP_SM_WAIT_AGAIN = 0, /* retry immediately */ AP_SM_WAIT_TIMEOUT, /* wait for timeout */ AP_SM_WAIT_INTERRUPT, /* wait for thin interrupt (if available) */ AP_SM_WAIT_NONE, /* no wait */ @@ -157,7 +151,6 @@ void ap_driver_unregister(struct ap_driver *); struct ap_device { struct device device; - struct ap_driver *drv; /* Pointer to AP device driver. */ int device_type; /* AP device type. */ }; @@ -165,7 +158,6 @@ struct ap_device { struct ap_card { struct ap_device ap_dev; - void *private; /* ap driver private pointer. */ int raw_hwtype; /* AP raw hardware type. */ unsigned int functions; /* AP device function bitfield. */ int queue_depth; /* AP queue depth.*/ @@ -182,11 +174,10 @@ struct ap_queue { struct hlist_node hnode; /* Node for the ap_queues hashtable */ struct ap_card *card; /* Ptr to assoc. AP card. */ spinlock_t lock; /* Per device lock. */ - void *private; /* ap driver private pointer. */ enum ap_dev_state dev_state; /* queue device state */ bool config; /* configured state */ ap_qid_t qid; /* AP queue id. */ - int interrupt; /* indicate if interrupts are enabled */ + bool interrupt; /* indicate if interrupts are enabled */ int queue_count; /* # messages currently on AP queue. */ int pendingq_count; /* # requests on pendingq list. */ int requestq_count; /* # requests on requestq list. */ diff --git a/drivers/s390/crypto/ap_queue.c b/drivers/s390/crypto/ap_queue.c index 669f96fddad6..d70c4d3d0907 100644 --- a/drivers/s390/crypto/ap_queue.c +++ b/drivers/s390/crypto/ap_queue.c @@ -19,7 +19,7 @@ static void __ap_flush_queue(struct ap_queue *aq); /** - * ap_queue_enable_interruption(): Enable interruption on an AP queue. + * ap_queue_enable_irq(): Enable interrupt support on this AP queue. * @qid: The AP queue number * @ind: the notification indicator byte * @@ -27,7 +27,7 @@ static void __ap_flush_queue(struct ap_queue *aq); * value it waits a while and tests the AP queue if interrupts * have been switched on using ap_test_queue(). */ -static int ap_queue_enable_interruption(struct ap_queue *aq, void *ind) +static int ap_queue_enable_irq(struct ap_queue *aq, void *ind) { struct ap_queue_status status; struct ap_qirq_ctrl qirqctrl = { 0 }; @@ -218,7 +218,8 @@ static enum ap_sm_wait ap_sm_read(struct ap_queue *aq) return AP_SM_WAIT_NONE; case AP_RESPONSE_NO_PENDING_REPLY: if (aq->queue_count > 0) - return AP_SM_WAIT_INTERRUPT; + return aq->interrupt ? + AP_SM_WAIT_INTERRUPT : AP_SM_WAIT_TIMEOUT; aq->sm_state = AP_SM_STATE_IDLE; return AP_SM_WAIT_NONE; default: @@ -272,7 +273,8 @@ static enum ap_sm_wait ap_sm_write(struct ap_queue *aq) fallthrough; case AP_RESPONSE_Q_FULL: aq->sm_state = AP_SM_STATE_QUEUE_FULL; - return AP_SM_WAIT_INTERRUPT; + return aq->interrupt ? + AP_SM_WAIT_INTERRUPT : AP_SM_WAIT_TIMEOUT; case AP_RESPONSE_RESET_IN_PROGRESS: aq->sm_state = AP_SM_STATE_RESET_WAIT; return AP_SM_WAIT_TIMEOUT; @@ -322,7 +324,7 @@ static enum ap_sm_wait ap_sm_reset(struct ap_queue *aq) case AP_RESPONSE_NORMAL: case AP_RESPONSE_RESET_IN_PROGRESS: aq->sm_state = AP_SM_STATE_RESET_WAIT; - aq->interrupt = AP_INTR_DISABLED; + aq->interrupt = false; return AP_SM_WAIT_TIMEOUT; default: aq->dev_state = AP_DEV_STATE_ERROR; @@ -355,7 +357,7 @@ static enum ap_sm_wait ap_sm_reset_wait(struct ap_queue *aq) switch (status.response_code) { case AP_RESPONSE_NORMAL: lsi_ptr = ap_airq_ptr(); - if (lsi_ptr && ap_queue_enable_interruption(aq, lsi_ptr) == 0) + if (lsi_ptr && ap_queue_enable_irq(aq, lsi_ptr) == 0) aq->sm_state = AP_SM_STATE_SETIRQ_WAIT; else aq->sm_state = (aq->queue_count > 0) ? @@ -396,7 +398,7 @@ static enum ap_sm_wait ap_sm_setirq_wait(struct ap_queue *aq) if (status.irq_enabled == 1) { /* Irqs are now enabled */ - aq->interrupt = AP_INTR_ENABLED; + aq->interrupt = true; aq->sm_state = (aq->queue_count > 0) ? AP_SM_STATE_WORKING : AP_SM_STATE_IDLE; } @@ -586,7 +588,7 @@ static ssize_t interrupt_show(struct device *dev, spin_lock_bh(&aq->lock); if (aq->sm_state == AP_SM_STATE_SETIRQ_WAIT) rc = scnprintf(buf, PAGE_SIZE, "Enable Interrupt pending.\n"); - else if (aq->interrupt == AP_INTR_ENABLED) + else if (aq->interrupt) rc = scnprintf(buf, PAGE_SIZE, "Interrupts enabled.\n"); else rc = scnprintf(buf, PAGE_SIZE, "Interrupts disabled.\n"); @@ -767,7 +769,7 @@ struct ap_queue *ap_queue_create(ap_qid_t qid, int device_type) aq->ap_dev.device.type = &ap_queue_type; aq->ap_dev.device_type = device_type; aq->qid = qid; - aq->interrupt = AP_INTR_DISABLED; + aq->interrupt = false; spin_lock_init(&aq->lock); INIT_LIST_HEAD(&aq->pendingq); INIT_LIST_HEAD(&aq->requestq); diff --git a/drivers/s390/crypto/vfio_ap_ops.c b/drivers/s390/crypto/vfio_ap_ops.c index 122c85c22469..67f145589f58 100644 --- a/drivers/s390/crypto/vfio_ap_ops.c +++ b/drivers/s390/crypto/vfio_ap_ops.c @@ -35,7 +35,7 @@ static int match_apqn(struct device *dev, const void *data) } /** - * vfio_ap_get_queue: Retrieve a queue with a specific APQN from a list + * vfio_ap_get_queue - retrieve a queue with a specific APQN from a list * @matrix_mdev: the associated mediated matrix * @apqn: The queue APQN * @@ -43,7 +43,7 @@ static int match_apqn(struct device *dev, const void *data) * devices of the vfio_ap_drv. * Verify that the APID and the APQI are set in the matrix. * - * Returns the pointer to the associated vfio_ap_queue + * Return: the pointer to the associated vfio_ap_queue */ static struct vfio_ap_queue *vfio_ap_get_queue( struct ap_matrix_mdev *matrix_mdev, @@ -64,7 +64,7 @@ static struct vfio_ap_queue *vfio_ap_get_queue( } /** - * vfio_ap_wait_for_irqclear + * vfio_ap_wait_for_irqclear - clears the IR bit or gives up after 5 tries * @apqn: The AP Queue number * * Checks the IRQ bit for the status of this APQN using ap_tapq. @@ -72,7 +72,6 @@ static struct vfio_ap_queue *vfio_ap_get_queue( * Returns if ap_tapq function failed with invalid, deconfigured or * checkstopped AP. * Otherwise retries up to 5 times after waiting 20ms. - * */ static void vfio_ap_wait_for_irqclear(int apqn) { @@ -105,13 +104,12 @@ static void vfio_ap_wait_for_irqclear(int apqn) } /** - * vfio_ap_free_aqic_resources + * vfio_ap_free_aqic_resources - free vfio_ap_queue resources * @q: The vfio_ap_queue * * Unregisters the ISC in the GIB when the saved ISC not invalid. - * Unpin the guest's page holding the NIB when it exist. - * Reset the saved_pfn and saved_isc to invalid values. - * + * Unpins the guest's page holding the NIB when it exists. + * Resets the saved_pfn and saved_isc to invalid values. */ static void vfio_ap_free_aqic_resources(struct vfio_ap_queue *q) { @@ -130,7 +128,7 @@ static void vfio_ap_free_aqic_resources(struct vfio_ap_queue *q) } /** - * vfio_ap_irq_disable + * vfio_ap_irq_disable - disables and clears an ap_queue interrupt * @q: The vfio_ap_queue * * Uses ap_aqic to disable the interruption and in case of success, reset @@ -144,6 +142,8 @@ static void vfio_ap_free_aqic_resources(struct vfio_ap_queue *q) * * Returns if ap_aqic function failed with invalid, deconfigured or * checkstopped AP. + * + * Return: &struct ap_queue_status */ static struct ap_queue_status vfio_ap_irq_disable(struct vfio_ap_queue *q) { @@ -183,9 +183,8 @@ end_free: } /** - * vfio_ap_setirq: Enable Interruption for a APQN + * vfio_ap_irq_enable - Enable Interruption for a APQN * - * @dev: the device associated with the ap_queue * @q: the vfio_ap_queue holding AQIC parameters * * Pin the NIB saved in *q @@ -197,6 +196,8 @@ end_free: * * Otherwise return the ap_queue_status returned by the ap_aqic(), * all retry handling will be done by the guest. + * + * Return: &struct ap_queue_status */ static struct ap_queue_status vfio_ap_irq_enable(struct vfio_ap_queue *q, int isc, @@ -253,7 +254,7 @@ static struct ap_queue_status vfio_ap_irq_enable(struct vfio_ap_queue *q, } /** - * handle_pqap: PQAP instruction callback + * handle_pqap - PQAP instruction callback * * @vcpu: The vcpu on which we received the PQAP instruction * @@ -270,8 +271,8 @@ static struct ap_queue_status vfio_ap_irq_enable(struct vfio_ap_queue *q, * We take the matrix_dev lock to ensure serialization on queues and * mediated device access. * - * Return 0 if we could handle the request inside KVM. - * otherwise, returns -EOPNOTSUPP to let QEMU handle the fault. + * Return: 0 if we could handle the request inside KVM. + * Otherwise, returns -EOPNOTSUPP to let QEMU handle the fault. */ static int handle_pqap(struct kvm_vcpu *vcpu) { @@ -426,7 +427,7 @@ struct vfio_ap_queue_reserved { }; /** - * vfio_ap_has_queue + * vfio_ap_has_queue - determines if the AP queue containing the target in @data * * @dev: an AP queue device * @data: a struct vfio_ap_queue_reserved reference @@ -443,7 +444,7 @@ struct vfio_ap_queue_reserved { * - If @data contains only an apqi value, @data will be flagged as * reserved if the APQI field in the AP queue device matches * - * Returns 0 to indicate the input to function succeeded. Returns -EINVAL if + * Return: 0 to indicate the input to function succeeded. Returns -EINVAL if * @data does not contain either an apid or apqi. */ static int vfio_ap_has_queue(struct device *dev, void *data) @@ -473,9 +474,9 @@ static int vfio_ap_has_queue(struct device *dev, void *data) } /** - * vfio_ap_verify_queue_reserved + * vfio_ap_verify_queue_reserved - verifies that the AP queue containing + * @apid or @aqpi is reserved * - * @matrix_dev: a mediated matrix device * @apid: an AP adapter ID * @apqi: an AP queue index * @@ -492,7 +493,7 @@ static int vfio_ap_has_queue(struct device *dev, void *data) * - If only @apqi is not NULL, then there must be an AP queue device bound * to the vfio_ap driver with an APQN containing @apqi * - * Returns 0 if the AP queue is reserved; otherwise, returns -EADDRNOTAVAIL. + * Return: 0 if the AP queue is reserved; otherwise, returns -EADDRNOTAVAIL. */ static int vfio_ap_verify_queue_reserved(unsigned long *apid, unsigned long *apqi) @@ -536,15 +537,15 @@ vfio_ap_mdev_verify_queues_reserved_for_apid(struct ap_matrix_mdev *matrix_mdev, } /** - * vfio_ap_mdev_verify_no_sharing + * vfio_ap_mdev_verify_no_sharing - verifies that the AP matrix is not configured + * + * @matrix_mdev: the mediated matrix device * * Verifies that the APQNs derived from the cross product of the AP adapter IDs * and AP queue indexes comprising the AP matrix are not configured for another * mediated device. AP queue sharing is not allowed. * - * @matrix_mdev: the mediated matrix device - * - * Returns 0 if the APQNs are not shared, otherwise; returns -EADDRINUSE. + * Return: 0 if the APQNs are not shared; otherwise returns -EADDRINUSE. */ static int vfio_ap_mdev_verify_no_sharing(struct ap_matrix_mdev *matrix_mdev) { @@ -578,7 +579,8 @@ static int vfio_ap_mdev_verify_no_sharing(struct ap_matrix_mdev *matrix_mdev) } /** - * assign_adapter_store + * assign_adapter_store - parses the APID from @buf and sets the + * corresponding bit in the mediated matrix device's APM * * @dev: the matrix device * @attr: the mediated matrix device's assign_adapter attribute @@ -586,10 +588,7 @@ static int vfio_ap_mdev_verify_no_sharing(struct ap_matrix_mdev *matrix_mdev) * be assigned * @count: the number of bytes in @buf * - * Parses the APID from @buf and sets the corresponding bit in the mediated - * matrix device's APM. - * - * Returns the number of bytes processed if the APID is valid; otherwise, + * Return: the number of bytes processed if the APID is valid; otherwise, * returns one of the following errors: * * 1. -EINVAL @@ -666,17 +665,15 @@ done: static DEVICE_ATTR_WO(assign_adapter); /** - * unassign_adapter_store + * unassign_adapter_store - parses the APID from @buf and clears the + * corresponding bit in the mediated matrix device's APM * * @dev: the matrix device * @attr: the mediated matrix device's unassign_adapter attribute * @buf: a buffer containing the adapter number (APID) to be unassigned * @count: the number of bytes in @buf * - * Parses the APID from @buf and clears the corresponding bit in the mediated - * matrix device's APM. - * - * Returns the number of bytes processed if the APID is valid; otherwise, + * Return: the number of bytes processed if the APID is valid; otherwise, * returns one of the following errors: * -EINVAL if the APID is not a number * -ENODEV if the APID it exceeds the maximum value configured for the @@ -740,7 +737,9 @@ vfio_ap_mdev_verify_queues_reserved_for_apqi(struct ap_matrix_mdev *matrix_mdev, } /** - * assign_domain_store + * assign_domain_store - parses the APQI from @buf and sets the + * corresponding bit in the mediated matrix device's AQM + * * * @dev: the matrix device * @attr: the mediated matrix device's assign_domain attribute @@ -748,10 +747,7 @@ vfio_ap_mdev_verify_queues_reserved_for_apqi(struct ap_matrix_mdev *matrix_mdev, * be assigned * @count: the number of bytes in @buf * - * Parses the APQI from @buf and sets the corresponding bit in the mediated - * matrix device's AQM. - * - * Returns the number of bytes processed if the APQI is valid; otherwise returns + * Return: the number of bytes processed if the APQI is valid; otherwise returns * one of the following errors: * * 1. -EINVAL @@ -824,7 +820,8 @@ static DEVICE_ATTR_WO(assign_domain); /** - * unassign_domain_store + * unassign_domain_store - parses the APQI from @buf and clears the + * corresponding bit in the mediated matrix device's AQM * * @dev: the matrix device * @attr: the mediated matrix device's unassign_domain attribute @@ -832,10 +829,7 @@ static DEVICE_ATTR_WO(assign_domain); * be unassigned * @count: the number of bytes in @buf * - * Parses the APQI from @buf and clears the corresponding bit in the - * mediated matrix device's AQM. - * - * Returns the number of bytes processed if the APQI is valid; otherwise, + * Return: the number of bytes processed if the APQI is valid; otherwise, * returns one of the following errors: * -EINVAL if the APQI is not a number * -ENODEV if the APQI exceeds the maximum value configured for the system @@ -879,17 +873,16 @@ done: static DEVICE_ATTR_WO(unassign_domain); /** - * assign_control_domain_store + * assign_control_domain_store - parses the domain ID from @buf and sets + * the corresponding bit in the mediated matrix device's ADM + * * * @dev: the matrix device * @attr: the mediated matrix device's assign_control_domain attribute * @buf: a buffer containing the domain ID to be assigned * @count: the number of bytes in @buf * - * Parses the domain ID from @buf and sets the corresponding bit in the mediated - * matrix device's ADM. - * - * Returns the number of bytes processed if the domain ID is valid; otherwise, + * Return: the number of bytes processed if the domain ID is valid; otherwise, * returns one of the following errors: * -EINVAL if the ID is not a number * -ENODEV if the ID exceeds the maximum value configured for the system @@ -937,17 +930,15 @@ done: static DEVICE_ATTR_WO(assign_control_domain); /** - * unassign_control_domain_store + * unassign_control_domain_store - parses the domain ID from @buf and + * clears the corresponding bit in the mediated matrix device's ADM * * @dev: the matrix device * @attr: the mediated matrix device's unassign_control_domain attribute * @buf: a buffer containing the domain ID to be unassigned * @count: the number of bytes in @buf * - * Parses the domain ID from @buf and clears the corresponding bit in the - * mediated matrix device's ADM. - * - * Returns the number of bytes processed if the domain ID is valid; otherwise, + * Return: the number of bytes processed if the domain ID is valid; otherwise, * returns one of the following errors: * -EINVAL if the ID is not a number * -ENODEV if the ID exceeds the maximum value configured for the system @@ -1085,14 +1076,12 @@ static const struct attribute_group *vfio_ap_mdev_attr_groups[] = { }; /** - * vfio_ap_mdev_set_kvm + * vfio_ap_mdev_set_kvm - sets all data for @matrix_mdev that are needed + * to manage AP resources for the guest whose state is represented by @kvm * * @matrix_mdev: a mediated matrix device * @kvm: reference to KVM instance * - * Sets all data for @matrix_mdev that are needed to manage AP resources - * for the guest whose state is represented by @kvm. - * * Note: The matrix_dev->lock must be taken prior to calling * this function; however, the lock will be temporarily released while the * guest's AP configuration is set to avoid a potential lockdep splat. @@ -1100,7 +1089,7 @@ static const struct attribute_group *vfio_ap_mdev_attr_groups[] = { * certain circumstances, will result in a circular lock dependency if this is * done under the @matrix_mdev->lock. * - * Return 0 if no other mediated matrix device has a reference to @kvm; + * Return: 0 if no other mediated matrix device has a reference to @kvm; * otherwise, returns an -EPERM. */ static int vfio_ap_mdev_set_kvm(struct ap_matrix_mdev *matrix_mdev, @@ -1131,8 +1120,8 @@ static int vfio_ap_mdev_set_kvm(struct ap_matrix_mdev *matrix_mdev, return 0; } -/* - * vfio_ap_mdev_iommu_notifier: IOMMU notifier callback +/** + * vfio_ap_mdev_iommu_notifier - IOMMU notifier callback * * @nb: The notifier block * @action: Action to be taken @@ -1141,6 +1130,7 @@ static int vfio_ap_mdev_set_kvm(struct ap_matrix_mdev *matrix_mdev, * For an UNMAP request, unpin the guest IOVA (the NIB guest address we * pinned before). Other requests are ignored. * + * Return: for an UNMAP request, NOFITY_OK; otherwise NOTIFY_DONE. */ static int vfio_ap_mdev_iommu_notifier(struct notifier_block *nb, unsigned long action, void *data) @@ -1161,19 +1151,17 @@ static int vfio_ap_mdev_iommu_notifier(struct notifier_block *nb, } /** - * vfio_ap_mdev_unset_kvm + * vfio_ap_mdev_unset_kvm - performs clean-up of resources no longer needed + * by @matrix_mdev. * * @matrix_mdev: a matrix mediated device * - * Performs clean-up of resources no longer needed by @matrix_mdev. - * * Note: The matrix_dev->lock must be taken prior to calling * this function; however, the lock will be temporarily released while the * guest's AP configuration is cleared to avoid a potential lockdep splat. * The kvm->lock is taken to clear the guest's AP configuration which, under * certain circumstances, will result in a circular lock dependency if this is * done under the @matrix_mdev->lock. - * */ static void vfio_ap_mdev_unset_kvm(struct ap_matrix_mdev *matrix_mdev) { diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c index 529ffe26ea9d..fa0cb8633040 100644 --- a/drivers/s390/crypto/zcrypt_api.c +++ b/drivers/s390/crypto/zcrypt_api.c @@ -572,14 +572,14 @@ static inline struct zcrypt_queue *zcrypt_pick_queue(struct zcrypt_card *zc, struct module **pmod, unsigned int weight) { - if (!zq || !try_module_get(zq->queue->ap_dev.drv->driver.owner)) + if (!zq || !try_module_get(zq->queue->ap_dev.device.driver->owner)) return NULL; zcrypt_queue_get(zq); get_device(&zq->queue->ap_dev.device); atomic_add(weight, &zc->load); atomic_add(weight, &zq->load); zq->request_count++; - *pmod = zq->queue->ap_dev.drv->driver.owner; + *pmod = zq->queue->ap_dev.device.driver->owner; return zq; } diff --git a/drivers/s390/crypto/zcrypt_card.c b/drivers/s390/crypto/zcrypt_card.c index 40fd5d37d26a..ef11d2a0ca6c 100644 --- a/drivers/s390/crypto/zcrypt_card.c +++ b/drivers/s390/crypto/zcrypt_card.c @@ -39,7 +39,7 @@ static ssize_t type_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct zcrypt_card *zc = to_ap_card(dev)->private; + struct zcrypt_card *zc = dev_get_drvdata(dev); return scnprintf(buf, PAGE_SIZE, "%s\n", zc->type_string); } @@ -50,8 +50,8 @@ static ssize_t online_show(struct device *dev, struct device_attribute *attr, char *buf) { + struct zcrypt_card *zc = dev_get_drvdata(dev); struct ap_card *ac = to_ap_card(dev); - struct zcrypt_card *zc = ac->private; int online = ac->config && zc->online ? 1 : 0; return scnprintf(buf, PAGE_SIZE, "%d\n", online); @@ -61,8 +61,8 @@ static ssize_t online_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { + struct zcrypt_card *zc = dev_get_drvdata(dev); struct ap_card *ac = to_ap_card(dev); - struct zcrypt_card *zc = ac->private; struct zcrypt_queue *zq; int online, id, i = 0, maxzqs = 0; struct zcrypt_queue **zq_uelist = NULL; @@ -116,7 +116,7 @@ static ssize_t load_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct zcrypt_card *zc = to_ap_card(dev)->private; + struct zcrypt_card *zc = dev_get_drvdata(dev); return scnprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&zc->load)); } diff --git a/drivers/s390/crypto/zcrypt_ccamisc.c b/drivers/s390/crypto/zcrypt_ccamisc.c index bc34bedf9db8..6a3c2b460965 100644 --- a/drivers/s390/crypto/zcrypt_ccamisc.c +++ b/drivers/s390/crypto/zcrypt_ccamisc.c @@ -1724,10 +1724,10 @@ static int fetch_cca_info(u16 cardnr, u16 domain, struct cca_info *ci) rlen = vlen = PAGE_SIZE/2; rc = cca_query_crypto_facility(cardnr, domain, "STATICSB", rarray, &rlen, varray, &vlen); - if (rc == 0 && rlen >= 10*8 && vlen >= 240) { - ci->new_apka_mk_state = (char) rarray[7*8]; - ci->cur_apka_mk_state = (char) rarray[8*8]; - ci->old_apka_mk_state = (char) rarray[9*8]; + if (rc == 0 && rlen >= 13*8 && vlen >= 240) { + ci->new_apka_mk_state = (char) rarray[10*8]; + ci->cur_apka_mk_state = (char) rarray[11*8]; + ci->old_apka_mk_state = (char) rarray[12*8]; if (ci->old_apka_mk_state == '2') memcpy(&ci->old_apka_mkvp, varray + 208, 8); if (ci->cur_apka_mk_state == '2') diff --git a/drivers/s390/crypto/zcrypt_cex2a.c b/drivers/s390/crypto/zcrypt_cex2a.c index 62ceeb7fc125..fa8293d37006 100644 --- a/drivers/s390/crypto/zcrypt_cex2a.c +++ b/drivers/s390/crypto/zcrypt_cex2a.c @@ -89,7 +89,7 @@ static int zcrypt_cex2a_card_probe(struct ap_device *ap_dev) if (!zc) return -ENOMEM; zc->card = ac; - ac->private = zc; + dev_set_drvdata(&ap_dev->device, zc); if (ac->ap_dev.device_type == AP_DEVICE_TYPE_CEX2A) { zc->min_mod_size = CEX2A_MIN_MOD_SIZE; @@ -118,7 +118,6 @@ static int zcrypt_cex2a_card_probe(struct ap_device *ap_dev) rc = zcrypt_card_register(zc); if (rc) { - ac->private = NULL; zcrypt_card_free(zc); } @@ -131,10 +130,9 @@ static int zcrypt_cex2a_card_probe(struct ap_device *ap_dev) */ static void zcrypt_cex2a_card_remove(struct ap_device *ap_dev) { - struct zcrypt_card *zc = to_ap_card(&ap_dev->device)->private; + struct zcrypt_card *zc = dev_get_drvdata(&ap_dev->device); - if (zc) - zcrypt_card_unregister(zc); + zcrypt_card_unregister(zc); } static struct ap_driver zcrypt_cex2a_card_driver = { @@ -176,10 +174,9 @@ static int zcrypt_cex2a_queue_probe(struct ap_device *ap_dev) ap_queue_init_state(aq); ap_queue_init_reply(aq, &zq->reply); aq->request_timeout = CEX2A_CLEANUP_TIME; - aq->private = zq; + dev_set_drvdata(&ap_dev->device, zq); rc = zcrypt_queue_register(zq); if (rc) { - aq->private = NULL; zcrypt_queue_free(zq); } @@ -192,11 +189,9 @@ static int zcrypt_cex2a_queue_probe(struct ap_device *ap_dev) */ static void zcrypt_cex2a_queue_remove(struct ap_device *ap_dev) { - struct ap_queue *aq = to_ap_queue(&ap_dev->device); - struct zcrypt_queue *zq = aq->private; + struct zcrypt_queue *zq = dev_get_drvdata(&ap_dev->device); - if (zq) - zcrypt_queue_unregister(zq); + zcrypt_queue_unregister(zq); } static struct ap_driver zcrypt_cex2a_queue_driver = { diff --git a/drivers/s390/crypto/zcrypt_cex2c.c b/drivers/s390/crypto/zcrypt_cex2c.c index 7a8cbdbe4408..a0b9f1153e12 100644 --- a/drivers/s390/crypto/zcrypt_cex2c.c +++ b/drivers/s390/crypto/zcrypt_cex2c.c @@ -66,9 +66,9 @@ static ssize_t cca_serialnr_show(struct device *dev, struct device_attribute *attr, char *buf) { + struct zcrypt_card *zc = dev_get_drvdata(dev); struct cca_info ci; struct ap_card *ac = to_ap_card(dev); - struct zcrypt_card *zc = ac->private; memset(&ci, 0, sizeof(ci)); @@ -97,9 +97,9 @@ static ssize_t cca_mkvps_show(struct device *dev, struct device_attribute *attr, char *buf) { + struct zcrypt_queue *zq = dev_get_drvdata(dev); int n = 0; struct cca_info ci; - struct zcrypt_queue *zq = to_ap_queue(dev)->private; static const char * const cao_state[] = { "invalid", "valid" }; static const char * const new_state[] = { "empty", "partial", "full" }; @@ -261,7 +261,7 @@ static int zcrypt_cex2c_card_probe(struct ap_device *ap_dev) if (!zc) return -ENOMEM; zc->card = ac; - ac->private = zc; + dev_set_drvdata(&ap_dev->device, zc); switch (ac->ap_dev.device_type) { case AP_DEVICE_TYPE_CEX2C: zc->user_space_type = ZCRYPT_CEX2C; @@ -287,7 +287,6 @@ static int zcrypt_cex2c_card_probe(struct ap_device *ap_dev) rc = zcrypt_card_register(zc); if (rc) { - ac->private = NULL; zcrypt_card_free(zc); return rc; } @@ -297,7 +296,6 @@ static int zcrypt_cex2c_card_probe(struct ap_device *ap_dev) &cca_card_attr_grp); if (rc) { zcrypt_card_unregister(zc); - ac->private = NULL; zcrypt_card_free(zc); } } @@ -311,13 +309,13 @@ static int zcrypt_cex2c_card_probe(struct ap_device *ap_dev) */ static void zcrypt_cex2c_card_remove(struct ap_device *ap_dev) { + struct zcrypt_card *zc = dev_get_drvdata(&ap_dev->device); struct ap_card *ac = to_ap_card(&ap_dev->device); - struct zcrypt_card *zc = to_ap_card(&ap_dev->device)->private; if (ap_test_bit(&ac->functions, AP_FUNC_COPRO)) sysfs_remove_group(&ap_dev->device.kobj, &cca_card_attr_grp); - if (zc) - zcrypt_card_unregister(zc); + + zcrypt_card_unregister(zc); } static struct ap_driver zcrypt_cex2c_card_driver = { @@ -359,10 +357,9 @@ static int zcrypt_cex2c_queue_probe(struct ap_device *ap_dev) ap_queue_init_state(aq); ap_queue_init_reply(aq, &zq->reply); aq->request_timeout = CEX2C_CLEANUP_TIME; - aq->private = zq; + dev_set_drvdata(&ap_dev->device, zq); rc = zcrypt_queue_register(zq); if (rc) { - aq->private = NULL; zcrypt_queue_free(zq); return rc; } @@ -372,7 +369,6 @@ static int zcrypt_cex2c_queue_probe(struct ap_device *ap_dev) &cca_queue_attr_grp); if (rc) { zcrypt_queue_unregister(zq); - aq->private = NULL; zcrypt_queue_free(zq); } } @@ -386,13 +382,13 @@ static int zcrypt_cex2c_queue_probe(struct ap_device *ap_dev) */ static void zcrypt_cex2c_queue_remove(struct ap_device *ap_dev) { + struct zcrypt_queue *zq = dev_get_drvdata(&ap_dev->device); struct ap_queue *aq = to_ap_queue(&ap_dev->device); - struct zcrypt_queue *zq = aq->private; if (ap_test_bit(&aq->card->functions, AP_FUNC_COPRO)) sysfs_remove_group(&ap_dev->device.kobj, &cca_queue_attr_grp); - if (zq) - zcrypt_queue_unregister(zq); + + zcrypt_queue_unregister(zq); } static struct ap_driver zcrypt_cex2c_queue_driver = { diff --git a/drivers/s390/crypto/zcrypt_cex4.c b/drivers/s390/crypto/zcrypt_cex4.c index f518b5fc7e5d..1f7ec54142e1 100644 --- a/drivers/s390/crypto/zcrypt_cex4.c +++ b/drivers/s390/crypto/zcrypt_cex4.c @@ -75,9 +75,9 @@ static ssize_t cca_serialnr_show(struct device *dev, struct device_attribute *attr, char *buf) { + struct zcrypt_card *zc = dev_get_drvdata(dev); struct cca_info ci; struct ap_card *ac = to_ap_card(dev); - struct zcrypt_card *zc = ac->private; memset(&ci, 0, sizeof(ci)); @@ -106,9 +106,9 @@ static ssize_t cca_mkvps_show(struct device *dev, struct device_attribute *attr, char *buf) { + struct zcrypt_queue *zq = dev_get_drvdata(dev); int n = 0; struct cca_info ci; - struct zcrypt_queue *zq = to_ap_queue(dev)->private; static const char * const cao_state[] = { "invalid", "valid" }; static const char * const new_state[] = { "empty", "partial", "full" }; @@ -187,9 +187,9 @@ static ssize_t ep11_api_ordinalnr_show(struct device *dev, struct device_attribute *attr, char *buf) { + struct zcrypt_card *zc = dev_get_drvdata(dev); struct ep11_card_info ci; struct ap_card *ac = to_ap_card(dev); - struct zcrypt_card *zc = ac->private; memset(&ci, 0, sizeof(ci)); @@ -208,9 +208,9 @@ static ssize_t ep11_fw_version_show(struct device *dev, struct device_attribute *attr, char *buf) { + struct zcrypt_card *zc = dev_get_drvdata(dev); struct ep11_card_info ci; struct ap_card *ac = to_ap_card(dev); - struct zcrypt_card *zc = ac->private; memset(&ci, 0, sizeof(ci)); @@ -231,9 +231,9 @@ static ssize_t ep11_serialnr_show(struct device *dev, struct device_attribute *attr, char *buf) { + struct zcrypt_card *zc = dev_get_drvdata(dev); struct ep11_card_info ci; struct ap_card *ac = to_ap_card(dev); - struct zcrypt_card *zc = ac->private; memset(&ci, 0, sizeof(ci)); @@ -264,10 +264,10 @@ static ssize_t ep11_card_op_modes_show(struct device *dev, struct device_attribute *attr, char *buf) { + struct zcrypt_card *zc = dev_get_drvdata(dev); int i, n = 0; struct ep11_card_info ci; struct ap_card *ac = to_ap_card(dev); - struct zcrypt_card *zc = ac->private; memset(&ci, 0, sizeof(ci)); @@ -309,9 +309,9 @@ static ssize_t ep11_mkvps_show(struct device *dev, struct device_attribute *attr, char *buf) { + struct zcrypt_queue *zq = dev_get_drvdata(dev); int n = 0; struct ep11_domain_info di; - struct zcrypt_queue *zq = to_ap_queue(dev)->private; static const char * const cwk_state[] = { "invalid", "valid" }; static const char * const nwk_state[] = { "empty", "uncommitted", "committed" }; @@ -357,9 +357,9 @@ static ssize_t ep11_queue_op_modes_show(struct device *dev, struct device_attribute *attr, char *buf) { + struct zcrypt_queue *zq = dev_get_drvdata(dev); int i, n = 0; struct ep11_domain_info di; - struct zcrypt_queue *zq = to_ap_queue(dev)->private; memset(&di, 0, sizeof(di)); @@ -441,7 +441,7 @@ static int zcrypt_cex4_card_probe(struct ap_device *ap_dev) if (!zc) return -ENOMEM; zc->card = ac; - ac->private = zc; + dev_set_drvdata(&ap_dev->device, zc); if (ap_test_bit(&ac->functions, AP_FUNC_ACCEL)) { if (ac->ap_dev.device_type == AP_DEVICE_TYPE_CEX4) { zc->type_string = "CEX4A"; @@ -539,7 +539,6 @@ static int zcrypt_cex4_card_probe(struct ap_device *ap_dev) rc = zcrypt_card_register(zc); if (rc) { - ac->private = NULL; zcrypt_card_free(zc); return rc; } @@ -549,7 +548,6 @@ static int zcrypt_cex4_card_probe(struct ap_device *ap_dev) &cca_card_attr_grp); if (rc) { zcrypt_card_unregister(zc); - ac->private = NULL; zcrypt_card_free(zc); } } else if (ap_test_bit(&ac->functions, AP_FUNC_EP11)) { @@ -557,7 +555,6 @@ static int zcrypt_cex4_card_probe(struct ap_device *ap_dev) &ep11_card_attr_grp); if (rc) { zcrypt_card_unregister(zc); - ac->private = NULL; zcrypt_card_free(zc); } } @@ -571,15 +568,15 @@ static int zcrypt_cex4_card_probe(struct ap_device *ap_dev) */ static void zcrypt_cex4_card_remove(struct ap_device *ap_dev) { + struct zcrypt_card *zc = dev_get_drvdata(&ap_dev->device); struct ap_card *ac = to_ap_card(&ap_dev->device); - struct zcrypt_card *zc = ac->private; if (ap_test_bit(&ac->functions, AP_FUNC_COPRO)) sysfs_remove_group(&ap_dev->device.kobj, &cca_card_attr_grp); else if (ap_test_bit(&ac->functions, AP_FUNC_EP11)) sysfs_remove_group(&ap_dev->device.kobj, &ep11_card_attr_grp); - if (zc) - zcrypt_card_unregister(zc); + + zcrypt_card_unregister(zc); } static struct ap_driver zcrypt_cex4_card_driver = { @@ -629,10 +626,9 @@ static int zcrypt_cex4_queue_probe(struct ap_device *ap_dev) ap_queue_init_state(aq); ap_queue_init_reply(aq, &zq->reply); aq->request_timeout = CEX4_CLEANUP_TIME; - aq->private = zq; + dev_set_drvdata(&ap_dev->device, zq); rc = zcrypt_queue_register(zq); if (rc) { - aq->private = NULL; zcrypt_queue_free(zq); return rc; } @@ -642,7 +638,6 @@ static int zcrypt_cex4_queue_probe(struct ap_device *ap_dev) &cca_queue_attr_grp); if (rc) { zcrypt_queue_unregister(zq); - aq->private = NULL; zcrypt_queue_free(zq); } } else if (ap_test_bit(&aq->card->functions, AP_FUNC_EP11)) { @@ -650,7 +645,6 @@ static int zcrypt_cex4_queue_probe(struct ap_device *ap_dev) &ep11_queue_attr_grp); if (rc) { zcrypt_queue_unregister(zq); - aq->private = NULL; zcrypt_queue_free(zq); } } @@ -664,15 +658,15 @@ static int zcrypt_cex4_queue_probe(struct ap_device *ap_dev) */ static void zcrypt_cex4_queue_remove(struct ap_device *ap_dev) { + struct zcrypt_queue *zq = dev_get_drvdata(&ap_dev->device); struct ap_queue *aq = to_ap_queue(&ap_dev->device); - struct zcrypt_queue *zq = aq->private; if (ap_test_bit(&aq->card->functions, AP_FUNC_COPRO)) sysfs_remove_group(&ap_dev->device.kobj, &cca_queue_attr_grp); else if (ap_test_bit(&aq->card->functions, AP_FUNC_EP11)) sysfs_remove_group(&ap_dev->device.kobj, &ep11_queue_attr_grp); - if (zq) - zcrypt_queue_unregister(zq); + + zcrypt_queue_unregister(zq); } static struct ap_driver zcrypt_cex4_queue_driver = { diff --git a/drivers/s390/crypto/zcrypt_queue.c b/drivers/s390/crypto/zcrypt_queue.c index 20f12288a8c1..398bde237e37 100644 --- a/drivers/s390/crypto/zcrypt_queue.c +++ b/drivers/s390/crypto/zcrypt_queue.c @@ -40,8 +40,8 @@ static ssize_t online_show(struct device *dev, struct device_attribute *attr, char *buf) { + struct zcrypt_queue *zq = dev_get_drvdata(dev); struct ap_queue *aq = to_ap_queue(dev); - struct zcrypt_queue *zq = aq->private; int online = aq->config && zq->online ? 1 : 0; return scnprintf(buf, PAGE_SIZE, "%d\n", online); @@ -51,8 +51,8 @@ static ssize_t online_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { + struct zcrypt_queue *zq = dev_get_drvdata(dev); struct ap_queue *aq = to_ap_queue(dev); - struct zcrypt_queue *zq = aq->private; struct zcrypt_card *zc = zq->zcard; int online; @@ -83,7 +83,7 @@ static ssize_t load_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct zcrypt_queue *zq = to_ap_queue(dev)->private; + struct zcrypt_queue *zq = dev_get_drvdata(dev); return scnprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&zq->load)); } @@ -170,7 +170,7 @@ int zcrypt_queue_register(struct zcrypt_queue *zq) int rc; spin_lock(&zcrypt_list_lock); - zc = zq->queue->card->private; + zc = dev_get_drvdata(&zq->queue->card->ap_dev.device); zcrypt_card_get(zc); zq->zcard = zc; zq->online = 1; /* New devices are online by default. */ diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 62f88ccbd03f..f96755a0a261 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -3804,14 +3804,10 @@ static void qeth_qdio_output_handler(struct ccw_device *ccwdev, unsigned long card_ptr) { struct qeth_card *card = (struct qeth_card *) card_ptr; - struct net_device *dev = card->dev; - QETH_CARD_TEXT(card, 6, "qdouhdl"); - if (qdio_error & QDIO_ERROR_FATAL) { - QETH_CARD_TEXT(card, 2, "achkcond"); - netif_tx_stop_all_queues(dev); - qeth_schedule_recovery(card); - } + QETH_CARD_TEXT(card, 2, "achkcond"); + netif_tx_stop_all_queues(card->dev); + qeth_schedule_recovery(card); } /** diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c index 6671d9563f6c..8f19bed6384e 100644 --- a/drivers/s390/scsi/zfcp_qdio.c +++ b/drivers/s390/scsi/zfcp_qdio.c @@ -69,10 +69,7 @@ static void zfcp_qdio_int_req(struct ccw_device *cdev, unsigned int qdio_err, { struct zfcp_qdio *qdio = (struct zfcp_qdio *) parm; - if (unlikely(qdio_err)) { - zfcp_qdio_handler_error(qdio, "qdireq1", qdio_err); - return; - } + zfcp_qdio_handler_error(qdio, "qdireq1", qdio_err); } static void zfcp_qdio_request_tasklet(struct tasklet_struct *tasklet) diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index ae9bfc658203..c0d31119d6d7 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -808,12 +808,15 @@ store_state_field(struct device *dev, struct device_attribute *attr, ret = scsi_device_set_state(sdev, state); /* * If the device state changes to SDEV_RUNNING, we need to - * rescan the device to revalidate it, and run the queue to - * avoid I/O hang. + * run the queue to avoid I/O hang, and rescan the device + * to revalidate it. Running the queue first is necessary + * because another thread may be waiting inside + * blk_mq_freeze_queue_wait() and because that call may be + * waiting for pending I/O to finish. */ if (ret == 0 && state == SDEV_RUNNING) { - scsi_rescan_device(dev); blk_mq_run_hw_queues(sdev->request_queue, true); + scsi_rescan_device(dev); } mutex_unlock(&sdev->state_mutex); diff --git a/drivers/slimbus/messaging.c b/drivers/slimbus/messaging.c index f2b5d347d227..e5ae26227bdb 100644 --- a/drivers/slimbus/messaging.c +++ b/drivers/slimbus/messaging.c @@ -66,7 +66,7 @@ int slim_alloc_txn_tid(struct slim_controller *ctrl, struct slim_msg_txn *txn) int ret = 0; spin_lock_irqsave(&ctrl->txn_lock, flags); - ret = idr_alloc_cyclic(&ctrl->tid_idr, txn, 0, + ret = idr_alloc_cyclic(&ctrl->tid_idr, txn, 1, SLIM_MAX_TIDS, GFP_ATOMIC); if (ret < 0) { spin_unlock_irqrestore(&ctrl->txn_lock, flags); @@ -131,7 +131,8 @@ int slim_do_transfer(struct slim_controller *ctrl, struct slim_msg_txn *txn) goto slim_xfer_err; } } - + /* Initialize tid to invalid value */ + txn->tid = 0; need_tid = slim_tid_txn(txn->mt, txn->mc); if (need_tid) { @@ -163,7 +164,7 @@ int slim_do_transfer(struct slim_controller *ctrl, struct slim_msg_txn *txn) txn->mt, txn->mc, txn->la, ret); slim_xfer_err: - if (!clk_pause_msg && (!need_tid || ret == -ETIMEDOUT)) { + if (!clk_pause_msg && (txn->tid == 0 || ret == -ETIMEDOUT)) { /* * remove runtime-pm vote if this was TX only, or * if there was error during this transaction diff --git a/drivers/slimbus/qcom-ngd-ctrl.c b/drivers/slimbus/qcom-ngd-ctrl.c index c054e83ab636..7040293c2ee8 100644 --- a/drivers/slimbus/qcom-ngd-ctrl.c +++ b/drivers/slimbus/qcom-ngd-ctrl.c @@ -618,7 +618,7 @@ static void qcom_slim_ngd_rx(struct qcom_slim_ngd_ctrl *ctrl, u8 *buf) (mc == SLIM_USR_MC_GENERIC_ACK && mt == SLIM_MSG_MT_SRC_REFERRED_USER)) { slim_msg_response(&ctrl->ctrl, &buf[4], buf[3], len - 4); - pm_runtime_mark_last_busy(ctrl->dev); + pm_runtime_mark_last_busy(ctrl->ctrl.dev); } } @@ -1080,7 +1080,8 @@ static void qcom_slim_ngd_setup(struct qcom_slim_ngd_ctrl *ctrl) { u32 cfg = readl_relaxed(ctrl->ngd->base); - if (ctrl->state == QCOM_SLIM_NGD_CTRL_DOWN) + if (ctrl->state == QCOM_SLIM_NGD_CTRL_DOWN || + ctrl->state == QCOM_SLIM_NGD_CTRL_ASLEEP) qcom_slim_ngd_init_dma(ctrl); /* By default enable message queues */ @@ -1131,6 +1132,7 @@ static int qcom_slim_ngd_power_up(struct qcom_slim_ngd_ctrl *ctrl) dev_info(ctrl->dev, "Subsys restart: ADSP active framer\n"); return 0; } + qcom_slim_ngd_setup(ctrl); return 0; } @@ -1257,13 +1259,14 @@ static int qcom_slim_ngd_enable(struct qcom_slim_ngd_ctrl *ctrl, bool enable) } /* controller state should be in sync with framework state */ complete(&ctrl->qmi.qmi_comp); - if (!pm_runtime_enabled(ctrl->dev) || - !pm_runtime_suspended(ctrl->dev)) - qcom_slim_ngd_runtime_resume(ctrl->dev); + if (!pm_runtime_enabled(ctrl->ctrl.dev) || + !pm_runtime_suspended(ctrl->ctrl.dev)) + qcom_slim_ngd_runtime_resume(ctrl->ctrl.dev); else - pm_runtime_resume(ctrl->dev); - pm_runtime_mark_last_busy(ctrl->dev); - pm_runtime_put(ctrl->dev); + pm_runtime_resume(ctrl->ctrl.dev); + + pm_runtime_mark_last_busy(ctrl->ctrl.dev); + pm_runtime_put(ctrl->ctrl.dev); ret = slim_register_controller(&ctrl->ctrl); if (ret) { @@ -1389,7 +1392,7 @@ static int qcom_slim_ngd_ssr_pdr_notify(struct qcom_slim_ngd_ctrl *ctrl, /* Make sure the last dma xfer is finished */ mutex_lock(&ctrl->tx_lock); if (ctrl->state != QCOM_SLIM_NGD_CTRL_DOWN) { - pm_runtime_get_noresume(ctrl->dev); + pm_runtime_get_noresume(ctrl->ctrl.dev); ctrl->state = QCOM_SLIM_NGD_CTRL_DOWN; qcom_slim_ngd_down(ctrl); qcom_slim_ngd_exit_dma(ctrl); @@ -1617,6 +1620,7 @@ static int __maybe_unused qcom_slim_ngd_runtime_suspend(struct device *dev) struct qcom_slim_ngd_ctrl *ctrl = dev_get_drvdata(dev); int ret = 0; + qcom_slim_ngd_exit_dma(ctrl); if (!ctrl->qmi.handle) return 0; diff --git a/drivers/soc/fsl/qe/qe_ic.c b/drivers/soc/fsl/qe/qe_ic.c index 3f711c1a0996..bbae3d39c7be 100644 --- a/drivers/soc/fsl/qe/qe_ic.c +++ b/drivers/soc/fsl/qe/qe_ic.c @@ -23,6 +23,7 @@ #include <linux/signal.h> #include <linux/device.h> #include <linux/spinlock.h> +#include <linux/platform_device.h> #include <asm/irq.h> #include <asm/io.h> #include <soc/fsl/qe/qe.h> @@ -53,8 +54,8 @@ struct qe_ic { struct irq_chip hc_irq; /* VIRQ numbers of QE high/low irqs */ - unsigned int virq_high; - unsigned int virq_low; + int virq_high; + int virq_low; }; /* @@ -404,42 +405,40 @@ static void qe_ic_cascade_muxed_mpic(struct irq_desc *desc) chip->irq_eoi(&desc->irq_data); } -static void __init qe_ic_init(struct device_node *node) +static int qe_ic_init(struct platform_device *pdev) { + struct device *dev = &pdev->dev; void (*low_handler)(struct irq_desc *desc); void (*high_handler)(struct irq_desc *desc); struct qe_ic *qe_ic; - struct resource res; - u32 ret; + struct resource *res; + struct device_node *node = pdev->dev.of_node; - ret = of_address_to_resource(node, 0, &res); - if (ret) - return; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res == NULL) { + dev_err(dev, "no memory resource defined\n"); + return -ENODEV; + } - qe_ic = kzalloc(sizeof(*qe_ic), GFP_KERNEL); + qe_ic = devm_kzalloc(dev, sizeof(*qe_ic), GFP_KERNEL); if (qe_ic == NULL) - return; + return -ENOMEM; - qe_ic->irqhost = irq_domain_add_linear(node, NR_QE_IC_INTS, - &qe_ic_host_ops, qe_ic); - if (qe_ic->irqhost == NULL) { - kfree(qe_ic); - return; + qe_ic->regs = devm_ioremap(dev, res->start, resource_size(res)); + if (qe_ic->regs == NULL) { + dev_err(dev, "failed to ioremap() registers\n"); + return -ENODEV; } - qe_ic->regs = ioremap(res.start, resource_size(&res)); - qe_ic->hc_irq = qe_ic_irq_chip; - qe_ic->virq_high = irq_of_parse_and_map(node, 0); - qe_ic->virq_low = irq_of_parse_and_map(node, 1); + qe_ic->virq_high = platform_get_irq(pdev, 0); + qe_ic->virq_low = platform_get_irq(pdev, 1); - if (!qe_ic->virq_low) { - printk(KERN_ERR "Failed to map QE_IC low IRQ\n"); - kfree(qe_ic); - return; - } - if (qe_ic->virq_high != qe_ic->virq_low) { + if (qe_ic->virq_low <= 0) + return -ENODEV; + + if (qe_ic->virq_high > 0 && qe_ic->virq_high != qe_ic->virq_low) { low_handler = qe_ic_cascade_low; high_handler = qe_ic_cascade_high; } else { @@ -447,29 +446,42 @@ static void __init qe_ic_init(struct device_node *node) high_handler = NULL; } + qe_ic->irqhost = irq_domain_add_linear(node, NR_QE_IC_INTS, + &qe_ic_host_ops, qe_ic); + if (qe_ic->irqhost == NULL) { + dev_err(dev, "failed to add irq domain\n"); + return -ENODEV; + } + qe_ic_write(qe_ic->regs, QEIC_CICR, 0); irq_set_handler_data(qe_ic->virq_low, qe_ic); irq_set_chained_handler(qe_ic->virq_low, low_handler); - if (qe_ic->virq_high && qe_ic->virq_high != qe_ic->virq_low) { + if (high_handler) { irq_set_handler_data(qe_ic->virq_high, qe_ic); irq_set_chained_handler(qe_ic->virq_high, high_handler); } + return 0; } +static const struct of_device_id qe_ic_ids[] = { + { .compatible = "fsl,qe-ic"}, + { .type = "qeic"}, + {}, +}; -static int __init qe_ic_of_init(void) +static struct platform_driver qe_ic_driver = { - struct device_node *np; + .driver = { + .name = "qe-ic", + .of_match_table = qe_ic_ids, + }, + .probe = qe_ic_init, +}; - np = of_find_compatible_node(NULL, NULL, "fsl,qe-ic"); - if (!np) { - np = of_find_node_by_type(NULL, "qeic"); - if (!np) - return -ENODEV; - } - qe_ic_init(np); - of_node_put(np); +static int __init qe_ic_of_init(void) +{ + platform_driver_register(&qe_ic_driver); return 0; } subsys_initcall(qe_ic_of_init); diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index e71a4c514f7b..83e352b0c8f9 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -658,6 +658,18 @@ config SPI_ROCKCHIP The main usecase of this controller is to use spi flash as boot device. +config SPI_ROCKCHIP_SFC + tristate "Rockchip Serial Flash Controller (SFC)" + depends on ARCH_ROCKCHIP || COMPILE_TEST + depends on HAS_IOMEM && HAS_DMA + help + This enables support for Rockchip serial flash controller. This + is a specialized controller used to access SPI flash on some + Rockchip SOCs. + + ROCKCHIP SFC supports DMA and PIO modes. When DMA is not available, + the driver automatically falls back to PIO mode. + config SPI_RB4XX tristate "Mikrotik RB4XX SPI master" depends on SPI_MASTER && ATH79 diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 13e54c45e9df..699db95c8441 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -95,6 +95,7 @@ obj-$(CONFIG_SPI_QCOM_GENI) += spi-geni-qcom.o obj-$(CONFIG_SPI_QCOM_QSPI) += spi-qcom-qspi.o obj-$(CONFIG_SPI_QUP) += spi-qup.o obj-$(CONFIG_SPI_ROCKCHIP) += spi-rockchip.o +obj-$(CONFIG_SPI_ROCKCHIP_SFC) += spi-rockchip-sfc.o obj-$(CONFIG_SPI_RB4XX) += spi-rb4xx.o obj-$(CONFIG_MACH_REALTEK_RTL) += spi-realtek-rtl.o obj-$(CONFIG_SPI_RPCIF) += spi-rpc-if.o diff --git a/drivers/spi/spi-bcm2835aux.c b/drivers/spi/spi-bcm2835aux.c index 37eab100a7d8..7d709a8c833b 100644 --- a/drivers/spi/spi-bcm2835aux.c +++ b/drivers/spi/spi-bcm2835aux.c @@ -143,12 +143,12 @@ static void bcm2835aux_debugfs_remove(struct bcm2835aux_spi *bs) } #endif /* CONFIG_DEBUG_FS */ -static inline u32 bcm2835aux_rd(struct bcm2835aux_spi *bs, unsigned reg) +static inline u32 bcm2835aux_rd(struct bcm2835aux_spi *bs, unsigned int reg) { return readl(bs->regs + reg); } -static inline void bcm2835aux_wr(struct bcm2835aux_spi *bs, unsigned reg, +static inline void bcm2835aux_wr(struct bcm2835aux_spi *bs, unsigned int reg, u32 val) { writel(val, bs->regs + reg); diff --git a/drivers/spi/spi-coldfire-qspi.c b/drivers/spi/spi-coldfire-qspi.c index 8996115ce736..263ce9047327 100644 --- a/drivers/spi/spi-coldfire-qspi.c +++ b/drivers/spi/spi-coldfire-qspi.c @@ -444,7 +444,7 @@ static int mcfqspi_remove(struct platform_device *pdev) mcfqspi_wr_qmr(mcfqspi, MCFQSPI_QMR_MSTR); mcfqspi_cs_teardown(mcfqspi); - clk_disable(mcfqspi->clk); + clk_disable_unprepare(mcfqspi->clk); return 0; } diff --git a/drivers/spi/spi-davinci.c b/drivers/spi/spi-davinci.c index e114e6fe5ea5..d112c2cac042 100644 --- a/drivers/spi/spi-davinci.c +++ b/drivers/spi/spi-davinci.c @@ -213,12 +213,6 @@ static void davinci_spi_chipselect(struct spi_device *spi, int value) * line for the controller */ if (spi->cs_gpiod) { - /* - * FIXME: is this code ever executed? This host does not - * set SPI_MASTER_GPIO_SS so this chipselect callback should - * not get called from the SPI core when we are using - * GPIOs for chip select. - */ if (value == BITBANG_CS_ACTIVE) gpiod_set_value(spi->cs_gpiod, 1); else @@ -945,7 +939,7 @@ static int davinci_spi_probe(struct platform_device *pdev) master->bus_num = pdev->id; master->num_chipselect = pdata->num_chipselect; master->bits_per_word_mask = SPI_BPW_RANGE_MASK(2, 16); - master->flags = SPI_MASTER_MUST_RX; + master->flags = SPI_MASTER_MUST_RX | SPI_MASTER_GPIO_SS; master->setup = davinci_spi_setup; master->cleanup = davinci_spi_cleanup; master->can_dma = davinci_spi_can_dma; diff --git a/drivers/spi/spi-ep93xx.c b/drivers/spi/spi-ep93xx.c index aa676559d273..5896a7b2fade 100644 --- a/drivers/spi/spi-ep93xx.c +++ b/drivers/spi/spi-ep93xx.c @@ -550,7 +550,7 @@ static int ep93xx_spi_prepare_hardware(struct spi_master *master) u32 val; int ret; - ret = clk_enable(espi->clk); + ret = clk_prepare_enable(espi->clk); if (ret) return ret; @@ -570,7 +570,7 @@ static int ep93xx_spi_unprepare_hardware(struct spi_master *master) val &= ~SSPCR1_SSE; writel(val, espi->mmio + SSPCR1); - clk_disable(espi->clk); + clk_disable_unprepare(espi->clk); return 0; } diff --git a/drivers/spi/spi-fsi.c b/drivers/spi/spi-fsi.c index 87f8829c3995..829770b8ec74 100644 --- a/drivers/spi/spi-fsi.c +++ b/drivers/spi/spi-fsi.c @@ -25,16 +25,11 @@ #define SPI_FSI_BASE 0x70000 #define SPI_FSI_INIT_TIMEOUT_MS 1000 -#define SPI_FSI_MAX_XFR_SIZE 2048 -#define SPI_FSI_MAX_XFR_SIZE_RESTRICTED 8 +#define SPI_FSI_MAX_RX_SIZE 8 +#define SPI_FSI_MAX_TX_SIZE 40 #define SPI_FSI_ERROR 0x0 #define SPI_FSI_COUNTER_CFG 0x1 -#define SPI_FSI_COUNTER_CFG_LOOPS(x) (((u64)(x) & 0xffULL) << 32) -#define SPI_FSI_COUNTER_CFG_N2_RX BIT_ULL(8) -#define SPI_FSI_COUNTER_CFG_N2_TX BIT_ULL(9) -#define SPI_FSI_COUNTER_CFG_N2_IMPLICIT BIT_ULL(10) -#define SPI_FSI_COUNTER_CFG_N2_RELOAD BIT_ULL(11) #define SPI_FSI_CFG1 0x2 #define SPI_FSI_CLOCK_CFG 0x3 #define SPI_FSI_CLOCK_CFG_MM_ENABLE BIT_ULL(32) @@ -76,8 +71,6 @@ struct fsi_spi { struct device *dev; /* SPI controller device */ struct fsi_device *fsi; /* FSI2SPI CFAM engine device */ u32 base; - size_t max_xfr_size; - bool restricted; }; struct fsi_spi_sequence { @@ -241,7 +234,7 @@ static int fsi_spi_reset(struct fsi_spi *ctx) return fsi_spi_write_reg(ctx, SPI_FSI_STATUS, 0ULL); } -static int fsi_spi_sequence_add(struct fsi_spi_sequence *seq, u8 val) +static void fsi_spi_sequence_add(struct fsi_spi_sequence *seq, u8 val) { /* * Add the next byte of instruction to the 8-byte sequence register. @@ -251,8 +244,6 @@ static int fsi_spi_sequence_add(struct fsi_spi_sequence *seq, u8 val) */ seq->data |= (u64)val << seq->bit; seq->bit -= 8; - - return ((64 - seq->bit) / 8) - 2; } static void fsi_spi_sequence_init(struct fsi_spi_sequence *seq) @@ -261,71 +252,11 @@ static void fsi_spi_sequence_init(struct fsi_spi_sequence *seq) seq->data = 0ULL; } -static int fsi_spi_sequence_transfer(struct fsi_spi *ctx, - struct fsi_spi_sequence *seq, - struct spi_transfer *transfer) -{ - int loops; - int idx; - int rc; - u8 val = 0; - u8 len = min(transfer->len, 8U); - u8 rem = transfer->len % len; - - loops = transfer->len / len; - - if (transfer->tx_buf) { - val = SPI_FSI_SEQUENCE_SHIFT_OUT(len); - idx = fsi_spi_sequence_add(seq, val); - - if (rem) - rem = SPI_FSI_SEQUENCE_SHIFT_OUT(rem); - } else if (transfer->rx_buf) { - val = SPI_FSI_SEQUENCE_SHIFT_IN(len); - idx = fsi_spi_sequence_add(seq, val); - - if (rem) - rem = SPI_FSI_SEQUENCE_SHIFT_IN(rem); - } else { - return -EINVAL; - } - - if (ctx->restricted && loops > 1) { - dev_warn(ctx->dev, - "Transfer too large; no branches permitted.\n"); - return -EINVAL; - } - - if (loops > 1) { - u64 cfg = SPI_FSI_COUNTER_CFG_LOOPS(loops - 1); - - fsi_spi_sequence_add(seq, SPI_FSI_SEQUENCE_BRANCH(idx)); - - if (transfer->rx_buf) - cfg |= SPI_FSI_COUNTER_CFG_N2_RX | - SPI_FSI_COUNTER_CFG_N2_TX | - SPI_FSI_COUNTER_CFG_N2_IMPLICIT | - SPI_FSI_COUNTER_CFG_N2_RELOAD; - - rc = fsi_spi_write_reg(ctx, SPI_FSI_COUNTER_CFG, cfg); - if (rc) - return rc; - } else { - fsi_spi_write_reg(ctx, SPI_FSI_COUNTER_CFG, 0ULL); - } - - if (rem) - fsi_spi_sequence_add(seq, rem); - - return 0; -} - static int fsi_spi_transfer_data(struct fsi_spi *ctx, struct spi_transfer *transfer) { int rc = 0; u64 status = 0ULL; - u64 cfg = 0ULL; if (transfer->tx_buf) { int nb; @@ -363,16 +294,6 @@ static int fsi_spi_transfer_data(struct fsi_spi *ctx, u64 in = 0ULL; u8 *rx = transfer->rx_buf; - rc = fsi_spi_read_reg(ctx, SPI_FSI_COUNTER_CFG, &cfg); - if (rc) - return rc; - - if (cfg & SPI_FSI_COUNTER_CFG_N2_IMPLICIT) { - rc = fsi_spi_write_reg(ctx, SPI_FSI_DATA_TX, 0); - if (rc) - return rc; - } - while (transfer->len > recv) { do { rc = fsi_spi_read_reg(ctx, SPI_FSI_STATUS, @@ -439,6 +360,10 @@ static int fsi_spi_transfer_init(struct fsi_spi *ctx) } } while (seq_state && (seq_state != SPI_FSI_STATUS_SEQ_STATE_IDLE)); + rc = fsi_spi_write_reg(ctx, SPI_FSI_COUNTER_CFG, 0ULL); + if (rc) + return rc; + rc = fsi_spi_read_reg(ctx, SPI_FSI_CLOCK_CFG, &clock_cfg); if (rc) return rc; @@ -459,6 +384,7 @@ static int fsi_spi_transfer_one_message(struct spi_controller *ctlr, { int rc; u8 seq_slave = SPI_FSI_SEQUENCE_SEL_SLAVE(mesg->spi->chip_select + 1); + unsigned int len; struct spi_transfer *transfer; struct fsi_spi *ctx = spi_controller_get_devdata(ctlr); @@ -471,8 +397,7 @@ static int fsi_spi_transfer_one_message(struct spi_controller *ctlr, struct spi_transfer *next = NULL; /* Sequencer must do shift out (tx) first. */ - if (!transfer->tx_buf || - transfer->len > (ctx->max_xfr_size + 8)) { + if (!transfer->tx_buf || transfer->len > SPI_FSI_MAX_TX_SIZE) { rc = -EINVAL; goto error; } @@ -486,9 +411,13 @@ static int fsi_spi_transfer_one_message(struct spi_controller *ctlr, fsi_spi_sequence_init(&seq); fsi_spi_sequence_add(&seq, seq_slave); - rc = fsi_spi_sequence_transfer(ctx, &seq, transfer); - if (rc) - goto error; + len = transfer->len; + while (len > 8) { + fsi_spi_sequence_add(&seq, + SPI_FSI_SEQUENCE_SHIFT_OUT(8)); + len -= 8; + } + fsi_spi_sequence_add(&seq, SPI_FSI_SEQUENCE_SHIFT_OUT(len)); if (!list_is_last(&transfer->transfer_list, &mesg->transfers)) { @@ -496,7 +425,9 @@ static int fsi_spi_transfer_one_message(struct spi_controller *ctlr, /* Sequencer can only do shift in (rx) after tx. */ if (next->rx_buf) { - if (next->len > ctx->max_xfr_size) { + u8 shift; + + if (next->len > SPI_FSI_MAX_RX_SIZE) { rc = -EINVAL; goto error; } @@ -504,10 +435,8 @@ static int fsi_spi_transfer_one_message(struct spi_controller *ctlr, dev_dbg(ctx->dev, "Sequence rx of %d bytes.\n", next->len); - rc = fsi_spi_sequence_transfer(ctx, &seq, - next); - if (rc) - goto error; + shift = SPI_FSI_SEQUENCE_SHIFT_IN(next->len); + fsi_spi_sequence_add(&seq, shift); } else { next = NULL; } @@ -541,9 +470,7 @@ error: static size_t fsi_spi_max_transfer_size(struct spi_device *spi) { - struct fsi_spi *ctx = spi_controller_get_devdata(spi->controller); - - return ctx->max_xfr_size; + return SPI_FSI_MAX_RX_SIZE; } static int fsi_spi_probe(struct device *dev) @@ -582,14 +509,6 @@ static int fsi_spi_probe(struct device *dev) ctx->fsi = fsi; ctx->base = base + SPI_FSI_BASE; - if (of_device_is_compatible(np, "ibm,fsi2spi-restricted")) { - ctx->restricted = true; - ctx->max_xfr_size = SPI_FSI_MAX_XFR_SIZE_RESTRICTED; - } else { - ctx->restricted = false; - ctx->max_xfr_size = SPI_FSI_MAX_XFR_SIZE; - } - rc = devm_spi_register_controller(dev, ctlr); if (rc) spi_controller_put(ctlr); diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c index fb45e6af6638..fd004c9db9dc 100644 --- a/drivers/spi/spi-fsl-dspi.c +++ b/drivers/spi/spi-fsl-dspi.c @@ -530,6 +530,7 @@ static int dspi_request_dma(struct fsl_dspi *dspi, phys_addr_t phy_addr) goto err_rx_dma_buf; } + memset(&cfg, 0, sizeof(cfg)); cfg.src_addr = phy_addr + SPI_POPR; cfg.dst_addr = phy_addr + SPI_PUSHR; cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; diff --git a/drivers/spi/spi-geni-qcom.c b/drivers/spi/spi-geni-qcom.c index b3861fb88711..2f51421e2a71 100644 --- a/drivers/spi/spi-geni-qcom.c +++ b/drivers/spi/spi-geni-qcom.c @@ -549,12 +549,6 @@ static void setup_fifo_xfer(struct spi_transfer *xfer, */ spin_lock_irq(&mas->lock); geni_se_setup_m_cmd(se, m_cmd, FRAGMENTATION); - - /* - * TX_WATERMARK_REG should be set after SPI configuration and - * setting up GENI SE engine, as driver starts data transfer - * for the watermark interrupt. - */ if (m_cmd & SPI_TX_ONLY) { if (geni_spi_handle_tx(mas)) writel(mas->tx_wm, se->base + SE_GENI_TX_WATERMARK_REG); diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c index fa68e9817929..8d8df51c5466 100644 --- a/drivers/spi/spi-imx.c +++ b/drivers/spi/spi-imx.c @@ -1052,12 +1052,8 @@ static void spi_imx_set_burst_len(struct spi_imx_data *spi_imx, int n_bits) static void spi_imx_push(struct spi_imx_data *spi_imx) { - unsigned int burst_len, fifo_words; + unsigned int burst_len; - if (spi_imx->dynamic_burst) - fifo_words = 4; - else - fifo_words = spi_imx_bytes_per_word(spi_imx->bits_per_word); /* * Reload the FIFO when the remaining bytes to be transferred in the * current burst is 0. This only applies when bits_per_word is a @@ -1076,7 +1072,7 @@ static void spi_imx_push(struct spi_imx_data *spi_imx) spi_imx->remainder = burst_len; } else { - spi_imx->remainder = fifo_words; + spi_imx->remainder = spi_imx_bytes_per_word(spi_imx->bits_per_word); } } @@ -1084,8 +1080,7 @@ static void spi_imx_push(struct spi_imx_data *spi_imx) if (!spi_imx->count) break; if (spi_imx->dynamic_burst && - spi_imx->txfifo >= DIV_ROUND_UP(spi_imx->remainder, - fifo_words)) + spi_imx->txfifo >= DIV_ROUND_UP(spi_imx->remainder, 4)) break; spi_imx->tx(spi_imx); spi_imx->txfifo++; @@ -1195,6 +1190,7 @@ static int spi_imx_setupxfer(struct spi_device *spi, * dynamic_burst in that case. */ if (spi_imx->devtype_data->dynamic_burst && !spi_imx->slave_mode && + !(spi->mode & SPI_CS_WORD) && (spi_imx->bits_per_word == 8 || spi_imx->bits_per_word == 16 || spi_imx->bits_per_word == 32)) { @@ -1630,6 +1626,15 @@ static int spi_imx_probe(struct platform_device *pdev) is_imx53_ecspi(spi_imx)) spi_imx->bitbang.master->mode_bits |= SPI_LOOP | SPI_READY; + if (is_imx51_ecspi(spi_imx) && + device_property_read_u32(&pdev->dev, "cs-gpios", NULL)) + /* + * When using HW-CS implementing SPI_CS_WORD can be done by just + * setting the burst length to the word size. This is + * considerably faster than manually controlling the CS. + */ + spi_imx->bitbang.master->mode_bits |= SPI_CS_WORD; + spi_imx->spi_drctl = spi_drctl; init_completion(&spi_imx->xfer_done); diff --git a/drivers/spi/spi-mt65xx.c b/drivers/spi/spi-mt65xx.c index 7914255521c3..386e8c84be0a 100644 --- a/drivers/spi/spi-mt65xx.c +++ b/drivers/spi/spi-mt65xx.c @@ -42,8 +42,9 @@ #define SPI_CFG1_CS_IDLE_OFFSET 0 #define SPI_CFG1_PACKET_LOOP_OFFSET 8 #define SPI_CFG1_PACKET_LENGTH_OFFSET 16 -#define SPI_CFG1_GET_TICK_DLY_OFFSET 30 +#define SPI_CFG1_GET_TICK_DLY_OFFSET 29 +#define SPI_CFG1_GET_TICK_DLY_MASK 0xe0000000 #define SPI_CFG1_CS_IDLE_MASK 0xff #define SPI_CFG1_PACKET_LOOP_MASK 0xff00 #define SPI_CFG1_PACKET_LENGTH_MASK 0x3ff0000 @@ -90,6 +91,8 @@ struct mtk_spi_compatible { bool enhance_timing; /* some IC support DMA addr extension */ bool dma_ext; + /* some IC no need unprepare SPI clk */ + bool no_need_unprepare; }; struct mtk_spi { @@ -104,6 +107,7 @@ struct mtk_spi { struct scatterlist *tx_sgl, *rx_sgl; u32 tx_sgl_len, rx_sgl_len; const struct mtk_spi_compatible *dev_comp; + u32 spi_clk_hz; }; static const struct mtk_spi_compatible mtk_common_compat; @@ -135,12 +139,21 @@ static const struct mtk_spi_compatible mt8183_compat = { .enhance_timing = true, }; +static const struct mtk_spi_compatible mt6893_compat = { + .need_pad_sel = true, + .must_tx = true, + .enhance_timing = true, + .dma_ext = true, + .no_need_unprepare = true, +}; + /* * A piece of default chip info unless the platform * supplies it. */ static const struct mtk_chip_config mtk_default_chip_info = { .sample_sel = 0, + .tick_delay = 0, }; static const struct of_device_id mtk_spi_of_match[] = { @@ -174,6 +187,9 @@ static const struct of_device_id mtk_spi_of_match[] = { { .compatible = "mediatek,mt8192-spi", .data = (void *)&mt6765_compat, }, + { .compatible = "mediatek,mt6893-spi", + .data = (void *)&mt6893_compat, + }, {} }; MODULE_DEVICE_TABLE(of, mtk_spi_of_match); @@ -192,6 +208,65 @@ static void mtk_spi_reset(struct mtk_spi *mdata) writel(reg_val, mdata->base + SPI_CMD_REG); } +static int mtk_spi_set_hw_cs_timing(struct spi_device *spi) +{ + struct mtk_spi *mdata = spi_master_get_devdata(spi->master); + struct spi_delay *cs_setup = &spi->cs_setup; + struct spi_delay *cs_hold = &spi->cs_hold; + struct spi_delay *cs_inactive = &spi->cs_inactive; + u32 setup, hold, inactive; + u32 reg_val; + int delay; + + delay = spi_delay_to_ns(cs_setup, NULL); + if (delay < 0) + return delay; + setup = (delay * DIV_ROUND_UP(mdata->spi_clk_hz, 1000000)) / 1000; + + delay = spi_delay_to_ns(cs_hold, NULL); + if (delay < 0) + return delay; + hold = (delay * DIV_ROUND_UP(mdata->spi_clk_hz, 1000000)) / 1000; + + delay = spi_delay_to_ns(cs_inactive, NULL); + if (delay < 0) + return delay; + inactive = (delay * DIV_ROUND_UP(mdata->spi_clk_hz, 1000000)) / 1000; + + setup = setup ? setup : 1; + hold = hold ? hold : 1; + inactive = inactive ? inactive : 1; + + reg_val = readl(mdata->base + SPI_CFG0_REG); + if (mdata->dev_comp->enhance_timing) { + hold = min_t(u32, hold, 0x10000); + setup = min_t(u32, setup, 0x10000); + reg_val &= ~(0xffff << SPI_ADJUST_CFG0_CS_HOLD_OFFSET); + reg_val |= (((hold - 1) & 0xffff) + << SPI_ADJUST_CFG0_CS_HOLD_OFFSET); + reg_val &= ~(0xffff << SPI_ADJUST_CFG0_CS_SETUP_OFFSET); + reg_val |= (((setup - 1) & 0xffff) + << SPI_ADJUST_CFG0_CS_SETUP_OFFSET); + } else { + hold = min_t(u32, hold, 0x100); + setup = min_t(u32, setup, 0x100); + reg_val &= ~(0xff << SPI_CFG0_CS_HOLD_OFFSET); + reg_val |= (((hold - 1) & 0xff) << SPI_CFG0_CS_HOLD_OFFSET); + reg_val &= ~(0xff << SPI_CFG0_CS_SETUP_OFFSET); + reg_val |= (((setup - 1) & 0xff) + << SPI_CFG0_CS_SETUP_OFFSET); + } + writel(reg_val, mdata->base + SPI_CFG0_REG); + + inactive = min_t(u32, inactive, 0x100); + reg_val = readl(mdata->base + SPI_CFG1_REG); + reg_val &= ~SPI_CFG1_CS_IDLE_MASK; + reg_val |= (((inactive - 1) & 0xff) << SPI_CFG1_CS_IDLE_OFFSET); + writel(reg_val, mdata->base + SPI_CFG1_REG); + + return 0; +} + static int mtk_spi_prepare_message(struct spi_master *master, struct spi_message *msg) { @@ -261,6 +336,15 @@ static int mtk_spi_prepare_message(struct spi_master *master, writel(mdata->pad_sel[spi->chip_select], mdata->base + SPI_PAD_SEL_REG); + /* tick delay */ + reg_val = readl(mdata->base + SPI_CFG1_REG); + reg_val &= ~SPI_CFG1_GET_TICK_DLY_MASK; + reg_val |= ((chip_config->tick_delay & 0x7) + << SPI_CFG1_GET_TICK_DLY_OFFSET); + writel(reg_val, mdata->base + SPI_CFG1_REG); + + /* set hw cs timing */ + mtk_spi_set_hw_cs_timing(spi); return 0; } @@ -287,12 +371,11 @@ static void mtk_spi_set_cs(struct spi_device *spi, bool enable) static void mtk_spi_prepare_transfer(struct spi_master *master, struct spi_transfer *xfer) { - u32 spi_clk_hz, div, sck_time, reg_val; + u32 div, sck_time, reg_val; struct mtk_spi *mdata = spi_master_get_devdata(master); - spi_clk_hz = clk_get_rate(mdata->spi_clk); - if (xfer->speed_hz < spi_clk_hz / 2) - div = DIV_ROUND_UP(spi_clk_hz, xfer->speed_hz); + if (xfer->speed_hz < mdata->spi_clk_hz / 2) + div = DIV_ROUND_UP(mdata->spi_clk_hz, xfer->speed_hz); else div = 1; @@ -507,52 +590,6 @@ static bool mtk_spi_can_dma(struct spi_master *master, (unsigned long)xfer->rx_buf % 4 == 0); } -static int mtk_spi_set_hw_cs_timing(struct spi_device *spi, - struct spi_delay *setup, - struct spi_delay *hold, - struct spi_delay *inactive) -{ - struct mtk_spi *mdata = spi_master_get_devdata(spi->master); - u16 setup_dly, hold_dly, inactive_dly; - u32 reg_val; - - if ((setup && setup->unit != SPI_DELAY_UNIT_SCK) || - (hold && hold->unit != SPI_DELAY_UNIT_SCK) || - (inactive && inactive->unit != SPI_DELAY_UNIT_SCK)) { - dev_err(&spi->dev, - "Invalid delay unit, should be SPI_DELAY_UNIT_SCK\n"); - return -EINVAL; - } - - setup_dly = setup ? setup->value : 1; - hold_dly = hold ? hold->value : 1; - inactive_dly = inactive ? inactive->value : 1; - - reg_val = readl(mdata->base + SPI_CFG0_REG); - if (mdata->dev_comp->enhance_timing) { - reg_val &= ~(0xffff << SPI_ADJUST_CFG0_CS_HOLD_OFFSET); - reg_val |= (((hold_dly - 1) & 0xffff) - << SPI_ADJUST_CFG0_CS_HOLD_OFFSET); - reg_val &= ~(0xffff << SPI_ADJUST_CFG0_CS_SETUP_OFFSET); - reg_val |= (((setup_dly - 1) & 0xffff) - << SPI_ADJUST_CFG0_CS_SETUP_OFFSET); - } else { - reg_val &= ~(0xff << SPI_CFG0_CS_HOLD_OFFSET); - reg_val |= (((hold_dly - 1) & 0xff) << SPI_CFG0_CS_HOLD_OFFSET); - reg_val &= ~(0xff << SPI_CFG0_CS_SETUP_OFFSET); - reg_val |= (((setup_dly - 1) & 0xff) - << SPI_CFG0_CS_SETUP_OFFSET); - } - writel(reg_val, mdata->base + SPI_CFG0_REG); - - reg_val = readl(mdata->base + SPI_CFG1_REG); - reg_val &= ~SPI_CFG1_CS_IDLE_MASK; - reg_val |= (((inactive_dly - 1) & 0xff) << SPI_CFG1_CS_IDLE_OFFSET); - writel(reg_val, mdata->base + SPI_CFG1_REG); - - return 0; -} - static int mtk_spi_setup(struct spi_device *spi) { struct mtk_spi *mdata = spi_master_get_devdata(spi->master); @@ -790,7 +827,12 @@ static int mtk_spi_probe(struct platform_device *pdev) goto err_put_master; } - clk_disable_unprepare(mdata->spi_clk); + mdata->spi_clk_hz = clk_get_rate(mdata->spi_clk); + + if (mdata->dev_comp->no_need_unprepare) + clk_disable(mdata->spi_clk); + else + clk_disable_unprepare(mdata->spi_clk); pm_runtime_enable(&pdev->dev); @@ -858,6 +900,9 @@ static int mtk_spi_remove(struct platform_device *pdev) mtk_spi_reset(mdata); + if (mdata->dev_comp->no_need_unprepare) + clk_unprepare(mdata->spi_clk); + return 0; } @@ -906,7 +951,10 @@ static int mtk_spi_runtime_suspend(struct device *dev) struct spi_master *master = dev_get_drvdata(dev); struct mtk_spi *mdata = spi_master_get_devdata(master); - clk_disable_unprepare(mdata->spi_clk); + if (mdata->dev_comp->no_need_unprepare) + clk_disable(mdata->spi_clk); + else + clk_disable_unprepare(mdata->spi_clk); return 0; } @@ -917,7 +965,10 @@ static int mtk_spi_runtime_resume(struct device *dev) struct mtk_spi *mdata = spi_master_get_devdata(master); int ret; - ret = clk_prepare_enable(mdata->spi_clk); + if (mdata->dev_comp->no_need_unprepare) + ret = clk_enable(mdata->spi_clk); + else + ret = clk_prepare_enable(mdata->spi_clk); if (ret < 0) { dev_err(dev, "failed to enable spi_clk (%d)\n", ret); return ret; diff --git a/drivers/spi/spi-mxic.c b/drivers/spi/spi-mxic.c index 96b418293bf2..45889947afed 100644 --- a/drivers/spi/spi-mxic.c +++ b/drivers/spi/spi-mxic.c @@ -335,8 +335,10 @@ static int mxic_spi_data_xfer(struct mxic_spi *mxic, const void *txbuf, static bool mxic_spi_mem_supports_op(struct spi_mem *mem, const struct spi_mem_op *op) { - if (op->data.buswidth > 4 || op->addr.buswidth > 4 || - op->dummy.buswidth > 4 || op->cmd.buswidth > 4) + bool all_false; + + if (op->data.buswidth > 8 || op->addr.buswidth > 8 || + op->dummy.buswidth > 8 || op->cmd.buswidth > 8) return false; if (op->data.nbytes && op->dummy.nbytes && @@ -346,7 +348,13 @@ static bool mxic_spi_mem_supports_op(struct spi_mem *mem, if (op->addr.nbytes > 7) return false; - return spi_mem_default_supports_op(mem, op); + all_false = !op->cmd.dtr && !op->addr.dtr && !op->dummy.dtr && + !op->data.dtr; + + if (all_false) + return spi_mem_default_supports_op(mem, op); + else + return spi_mem_dtr_supports_op(mem, op); } static int mxic_spi_mem_exec_op(struct spi_mem *mem, @@ -355,14 +363,15 @@ static int mxic_spi_mem_exec_op(struct spi_mem *mem, struct mxic_spi *mxic = spi_master_get_devdata(mem->spi->master); int nio = 1, i, ret; u32 ss_ctrl; - u8 addr[8]; - u8 opcode = op->cmd.opcode; + u8 addr[8], cmd[2]; ret = mxic_spi_set_freq(mxic, mem->spi->max_speed_hz); if (ret) return ret; - if (mem->spi->mode & (SPI_TX_QUAD | SPI_RX_QUAD)) + if (mem->spi->mode & (SPI_TX_OCTAL | SPI_RX_OCTAL)) + nio = 8; + else if (mem->spi->mode & (SPI_TX_QUAD | SPI_RX_QUAD)) nio = 4; else if (mem->spi->mode & (SPI_TX_DUAL | SPI_RX_DUAL)) nio = 2; @@ -374,19 +383,26 @@ static int mxic_spi_mem_exec_op(struct spi_mem *mem, mxic->regs + HC_CFG); writel(HC_EN_BIT, mxic->regs + HC_EN); - ss_ctrl = OP_CMD_BYTES(1) | OP_CMD_BUSW(fls(op->cmd.buswidth) - 1); + ss_ctrl = OP_CMD_BYTES(op->cmd.nbytes) | + OP_CMD_BUSW(fls(op->cmd.buswidth) - 1) | + (op->cmd.dtr ? OP_CMD_DDR : 0); if (op->addr.nbytes) ss_ctrl |= OP_ADDR_BYTES(op->addr.nbytes) | - OP_ADDR_BUSW(fls(op->addr.buswidth) - 1); + OP_ADDR_BUSW(fls(op->addr.buswidth) - 1) | + (op->addr.dtr ? OP_ADDR_DDR : 0); if (op->dummy.nbytes) ss_ctrl |= OP_DUMMY_CYC(op->dummy.nbytes); if (op->data.nbytes) { - ss_ctrl |= OP_DATA_BUSW(fls(op->data.buswidth) - 1); - if (op->data.dir == SPI_MEM_DATA_IN) + ss_ctrl |= OP_DATA_BUSW(fls(op->data.buswidth) - 1) | + (op->data.dtr ? OP_DATA_DDR : 0); + if (op->data.dir == SPI_MEM_DATA_IN) { ss_ctrl |= OP_READ; + if (op->data.dtr) + ss_ctrl |= OP_DQS_EN; + } } writel(ss_ctrl, mxic->regs + SS_CTRL(mem->spi->chip_select)); @@ -394,7 +410,10 @@ static int mxic_spi_mem_exec_op(struct spi_mem *mem, writel(readl(mxic->regs + HC_CFG) | HC_CFG_MAN_CS_ASSERT, mxic->regs + HC_CFG); - ret = mxic_spi_data_xfer(mxic, &opcode, NULL, 1); + for (i = 0; i < op->cmd.nbytes; i++) + cmd[i] = op->cmd.opcode >> (8 * (op->cmd.nbytes - i - 1)); + + ret = mxic_spi_data_xfer(mxic, cmd, NULL, op->cmd.nbytes); if (ret) goto out; @@ -567,7 +586,8 @@ static int mxic_spi_probe(struct platform_device *pdev) master->bits_per_word_mask = SPI_BPW_MASK(8); master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_RX_DUAL | SPI_TX_DUAL | - SPI_RX_QUAD | SPI_TX_QUAD; + SPI_RX_QUAD | SPI_TX_QUAD | + SPI_RX_OCTAL | SPI_TX_OCTAL; mxic_spi_hw_init(mxic); diff --git a/drivers/spi/spi-orion.c b/drivers/spi/spi-orion.c index 34b31aba3981..e8de3cbbfb2a 100644 --- a/drivers/spi/spi-orion.c +++ b/drivers/spi/spi-orion.c @@ -328,8 +328,16 @@ orion_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t) static void orion_spi_set_cs(struct spi_device *spi, bool enable) { struct orion_spi *orion_spi; + void __iomem *ctrl_reg; + u32 val; orion_spi = spi_master_get_devdata(spi->master); + ctrl_reg = spi_reg(orion_spi, ORION_SPI_IF_CTRL_REG); + + val = readl(ctrl_reg); + + /* Clear existing chip-select and assertion state */ + val &= ~(ORION_SPI_CS_MASK | 0x1); /* * If this line is using a GPIO to control chip select, this internal @@ -338,9 +346,7 @@ static void orion_spi_set_cs(struct spi_device *spi, bool enable) * as it is handled by a GPIO, but that doesn't matter. What we need * is to deassert the old chip select and assert some other chip select. */ - orion_spi_clrbits(orion_spi, ORION_SPI_IF_CTRL_REG, ORION_SPI_CS_MASK); - orion_spi_setbits(orion_spi, ORION_SPI_IF_CTRL_REG, - ORION_SPI_CS(spi->chip_select)); + val |= ORION_SPI_CS(spi->chip_select); /* * Chip select logic is inverted from spi_set_cs(). For lines using a @@ -350,9 +356,13 @@ static void orion_spi_set_cs(struct spi_device *spi, bool enable) * doesn't matter. */ if (!enable) - orion_spi_setbits(orion_spi, ORION_SPI_IF_CTRL_REG, 0x1); - else - orion_spi_clrbits(orion_spi, ORION_SPI_IF_CTRL_REG, 0x1); + val |= 0x1; + + /* + * To avoid toggling unwanted chip selects update the register + * with a single write. + */ + writel(val, ctrl_reg); } static inline int orion_spi_wait_till_ready(struct orion_spi *orion_spi) diff --git a/drivers/spi/spi-pic32.c b/drivers/spi/spi-pic32.c index 104bde153efd..5eb7b61bbb4d 100644 --- a/drivers/spi/spi-pic32.c +++ b/drivers/spi/spi-pic32.c @@ -361,6 +361,7 @@ static int pic32_spi_dma_config(struct pic32_spi *pic32s, u32 dma_width) struct dma_slave_config cfg; int ret; + memset(&cfg, 0, sizeof(cfg)); cfg.device_fc = true; cfg.src_addr = pic32s->dma_base + buf_offset; cfg.dst_addr = pic32s->dma_base + buf_offset; diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c index 974e30744b83..1573f6d8eb48 100644 --- a/drivers/spi/spi-pxa2xx.c +++ b/drivers/spi/spi-pxa2xx.c @@ -594,24 +594,29 @@ static int u32_reader(struct driver_data *drv_data) static void reset_sccr1(struct driver_data *drv_data) { - struct chip_data *chip = - spi_get_ctldata(drv_data->controller->cur_msg->spi); - u32 sccr1_reg; + u32 mask = drv_data->int_cr1 | drv_data->dma_cr1, threshold; + struct chip_data *chip; + + if (drv_data->controller->cur_msg) { + chip = spi_get_ctldata(drv_data->controller->cur_msg->spi); + threshold = chip->threshold; + } else { + threshold = 0; + } - sccr1_reg = pxa2xx_spi_read(drv_data, SSCR1) & ~drv_data->int_cr1; switch (drv_data->ssp_type) { case QUARK_X1000_SSP: - sccr1_reg &= ~QUARK_X1000_SSCR1_RFT; + mask |= QUARK_X1000_SSCR1_RFT; break; case CE4100_SSP: - sccr1_reg &= ~CE4100_SSCR1_RFT; + mask |= CE4100_SSCR1_RFT; break; default: - sccr1_reg &= ~SSCR1_RFT; + mask |= SSCR1_RFT; break; } - sccr1_reg |= chip->threshold; - pxa2xx_spi_write(drv_data, SSCR1, sccr1_reg); + + pxa2xx_spi_update(drv_data, SSCR1, mask, threshold); } static void int_stop_and_reset(struct driver_data *drv_data) @@ -724,11 +729,8 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data) static void handle_bad_msg(struct driver_data *drv_data) { + int_stop_and_reset(drv_data); pxa2xx_spi_off(drv_data); - clear_SSCR1_bits(drv_data, drv_data->int_cr1); - if (!pxa25x_ssp_comp(drv_data)) - pxa2xx_spi_write(drv_data, SSTO, 0); - write_SSSR_CS(drv_data, drv_data->clear_sr); dev_err(drv_data->ssp->dev, "bad message state in interrupt handler\n"); } @@ -1156,13 +1158,10 @@ static void pxa2xx_spi_handle_err(struct spi_controller *controller, { struct driver_data *drv_data = spi_controller_get_devdata(controller); + int_stop_and_reset(drv_data); + /* Disable the SSP */ pxa2xx_spi_off(drv_data); - /* Clear and disable interrupts and service requests */ - write_SSSR_CS(drv_data, drv_data->clear_sr); - clear_SSCR1_bits(drv_data, drv_data->int_cr1 | drv_data->dma_cr1); - if (!pxa25x_ssp_comp(drv_data)) - pxa2xx_spi_write(drv_data, SSTO, 0); /* * Stop the DMA if running. Note DMA callback handler may have unset diff --git a/drivers/spi/spi-rockchip-sfc.c b/drivers/spi/spi-rockchip-sfc.c new file mode 100644 index 000000000000..a46b38544027 --- /dev/null +++ b/drivers/spi/spi-rockchip-sfc.c @@ -0,0 +1,694 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Rockchip Serial Flash Controller Driver + * + * Copyright (c) 2017-2021, Rockchip Inc. + * Author: Shawn Lin <shawn.lin@rock-chips.com> + * Chris Morgan <macroalpha82@gmail.com> + * Jon Lin <Jon.lin@rock-chips.com> + */ + +#include <linux/bitops.h> +#include <linux/clk.h> +#include <linux/completion.h> +#include <linux/dma-mapping.h> +#include <linux/iopoll.h> +#include <linux/mm.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/interrupt.h> +#include <linux/spi/spi-mem.h> + +/* System control */ +#define SFC_CTRL 0x0 +#define SFC_CTRL_PHASE_SEL_NEGETIVE BIT(1) +#define SFC_CTRL_CMD_BITS_SHIFT 8 +#define SFC_CTRL_ADDR_BITS_SHIFT 10 +#define SFC_CTRL_DATA_BITS_SHIFT 12 + +/* Interrupt mask */ +#define SFC_IMR 0x4 +#define SFC_IMR_RX_FULL BIT(0) +#define SFC_IMR_RX_UFLOW BIT(1) +#define SFC_IMR_TX_OFLOW BIT(2) +#define SFC_IMR_TX_EMPTY BIT(3) +#define SFC_IMR_TRAN_FINISH BIT(4) +#define SFC_IMR_BUS_ERR BIT(5) +#define SFC_IMR_NSPI_ERR BIT(6) +#define SFC_IMR_DMA BIT(7) + +/* Interrupt clear */ +#define SFC_ICLR 0x8 +#define SFC_ICLR_RX_FULL BIT(0) +#define SFC_ICLR_RX_UFLOW BIT(1) +#define SFC_ICLR_TX_OFLOW BIT(2) +#define SFC_ICLR_TX_EMPTY BIT(3) +#define SFC_ICLR_TRAN_FINISH BIT(4) +#define SFC_ICLR_BUS_ERR BIT(5) +#define SFC_ICLR_NSPI_ERR BIT(6) +#define SFC_ICLR_DMA BIT(7) + +/* FIFO threshold level */ +#define SFC_FTLR 0xc +#define SFC_FTLR_TX_SHIFT 0 +#define SFC_FTLR_TX_MASK 0x1f +#define SFC_FTLR_RX_SHIFT 8 +#define SFC_FTLR_RX_MASK 0x1f + +/* Reset FSM and FIFO */ +#define SFC_RCVR 0x10 +#define SFC_RCVR_RESET BIT(0) + +/* Enhanced mode */ +#define SFC_AX 0x14 + +/* Address Bit number */ +#define SFC_ABIT 0x18 + +/* Interrupt status */ +#define SFC_ISR 0x1c +#define SFC_ISR_RX_FULL_SHIFT BIT(0) +#define SFC_ISR_RX_UFLOW_SHIFT BIT(1) +#define SFC_ISR_TX_OFLOW_SHIFT BIT(2) +#define SFC_ISR_TX_EMPTY_SHIFT BIT(3) +#define SFC_ISR_TX_FINISH_SHIFT BIT(4) +#define SFC_ISR_BUS_ERR_SHIFT BIT(5) +#define SFC_ISR_NSPI_ERR_SHIFT BIT(6) +#define SFC_ISR_DMA_SHIFT BIT(7) + +/* FIFO status */ +#define SFC_FSR 0x20 +#define SFC_FSR_TX_IS_FULL BIT(0) +#define SFC_FSR_TX_IS_EMPTY BIT(1) +#define SFC_FSR_RX_IS_EMPTY BIT(2) +#define SFC_FSR_RX_IS_FULL BIT(3) +#define SFC_FSR_TXLV_MASK GENMASK(12, 8) +#define SFC_FSR_TXLV_SHIFT 8 +#define SFC_FSR_RXLV_MASK GENMASK(20, 16) +#define SFC_FSR_RXLV_SHIFT 16 + +/* FSM status */ +#define SFC_SR 0x24 +#define SFC_SR_IS_IDLE 0x0 +#define SFC_SR_IS_BUSY 0x1 + +/* Raw interrupt status */ +#define SFC_RISR 0x28 +#define SFC_RISR_RX_FULL BIT(0) +#define SFC_RISR_RX_UNDERFLOW BIT(1) +#define SFC_RISR_TX_OVERFLOW BIT(2) +#define SFC_RISR_TX_EMPTY BIT(3) +#define SFC_RISR_TRAN_FINISH BIT(4) +#define SFC_RISR_BUS_ERR BIT(5) +#define SFC_RISR_NSPI_ERR BIT(6) +#define SFC_RISR_DMA BIT(7) + +/* Version */ +#define SFC_VER 0x2C +#define SFC_VER_3 0x3 +#define SFC_VER_4 0x4 +#define SFC_VER_5 0x5 + +/* Delay line controller resiter */ +#define SFC_DLL_CTRL0 0x3C +#define SFC_DLL_CTRL0_SCLK_SMP_DLL BIT(15) +#define SFC_DLL_CTRL0_DLL_MAX_VER4 0xFFU +#define SFC_DLL_CTRL0_DLL_MAX_VER5 0x1FFU + +/* Master trigger */ +#define SFC_DMA_TRIGGER 0x80 +#define SFC_DMA_TRIGGER_START 1 + +/* Src or Dst addr for master */ +#define SFC_DMA_ADDR 0x84 + +/* Length control register extension 32GB */ +#define SFC_LEN_CTRL 0x88 +#define SFC_LEN_CTRL_TRB_SEL 1 +#define SFC_LEN_EXT 0x8C + +/* Command */ +#define SFC_CMD 0x100 +#define SFC_CMD_IDX_SHIFT 0 +#define SFC_CMD_DUMMY_SHIFT 8 +#define SFC_CMD_DIR_SHIFT 12 +#define SFC_CMD_DIR_RD 0 +#define SFC_CMD_DIR_WR 1 +#define SFC_CMD_ADDR_SHIFT 14 +#define SFC_CMD_ADDR_0BITS 0 +#define SFC_CMD_ADDR_24BITS 1 +#define SFC_CMD_ADDR_32BITS 2 +#define SFC_CMD_ADDR_XBITS 3 +#define SFC_CMD_TRAN_BYTES_SHIFT 16 +#define SFC_CMD_CS_SHIFT 30 + +/* Address */ +#define SFC_ADDR 0x104 + +/* Data */ +#define SFC_DATA 0x108 + +/* The controller and documentation reports that it supports up to 4 CS + * devices (0-3), however I have only been able to test a single CS (CS 0) + * due to the configuration of my device. + */ +#define SFC_MAX_CHIPSELECT_NUM 4 + +/* The SFC can transfer max 16KB - 1 at one time + * we set it to 15.5KB here for alignment. + */ +#define SFC_MAX_IOSIZE_VER3 (512 * 31) + +/* DMA is only enabled for large data transmission */ +#define SFC_DMA_TRANS_THRETHOLD (0x40) + +/* Maximum clock values from datasheet suggest keeping clock value under + * 150MHz. No minimum or average value is suggested. + */ +#define SFC_MAX_SPEED (150 * 1000 * 1000) + +struct rockchip_sfc { + struct device *dev; + void __iomem *regbase; + struct clk *hclk; + struct clk *clk; + u32 frequency; + /* virtual mapped addr for dma_buffer */ + void *buffer; + dma_addr_t dma_buffer; + struct completion cp; + bool use_dma; + u32 max_iosize; + u16 version; +}; + +static int rockchip_sfc_reset(struct rockchip_sfc *sfc) +{ + int err; + u32 status; + + writel_relaxed(SFC_RCVR_RESET, sfc->regbase + SFC_RCVR); + + err = readl_poll_timeout(sfc->regbase + SFC_RCVR, status, + !(status & SFC_RCVR_RESET), 20, + jiffies_to_usecs(HZ)); + if (err) + dev_err(sfc->dev, "SFC reset never finished\n"); + + /* Still need to clear the masked interrupt from RISR */ + writel_relaxed(0xFFFFFFFF, sfc->regbase + SFC_ICLR); + + dev_dbg(sfc->dev, "reset\n"); + + return err; +} + +static u16 rockchip_sfc_get_version(struct rockchip_sfc *sfc) +{ + return (u16)(readl(sfc->regbase + SFC_VER) & 0xffff); +} + +static u32 rockchip_sfc_get_max_iosize(struct rockchip_sfc *sfc) +{ + return SFC_MAX_IOSIZE_VER3; +} + +static void rockchip_sfc_irq_unmask(struct rockchip_sfc *sfc, u32 mask) +{ + u32 reg; + + /* Enable transfer complete interrupt */ + reg = readl(sfc->regbase + SFC_IMR); + reg &= ~mask; + writel(reg, sfc->regbase + SFC_IMR); +} + +static void rockchip_sfc_irq_mask(struct rockchip_sfc *sfc, u32 mask) +{ + u32 reg; + + /* Disable transfer finish interrupt */ + reg = readl(sfc->regbase + SFC_IMR); + reg |= mask; + writel(reg, sfc->regbase + SFC_IMR); +} + +static int rockchip_sfc_init(struct rockchip_sfc *sfc) +{ + writel(0, sfc->regbase + SFC_CTRL); + writel(0xFFFFFFFF, sfc->regbase + SFC_ICLR); + rockchip_sfc_irq_mask(sfc, 0xFFFFFFFF); + if (rockchip_sfc_get_version(sfc) >= SFC_VER_4) + writel(SFC_LEN_CTRL_TRB_SEL, sfc->regbase + SFC_LEN_CTRL); + + return 0; +} + +static int rockchip_sfc_wait_txfifo_ready(struct rockchip_sfc *sfc, u32 timeout_us) +{ + int ret = 0; + u32 status; + + ret = readl_poll_timeout(sfc->regbase + SFC_FSR, status, + status & SFC_FSR_TXLV_MASK, 0, + timeout_us); + if (ret) { + dev_dbg(sfc->dev, "sfc wait tx fifo timeout\n"); + + return -ETIMEDOUT; + } + + return (status & SFC_FSR_TXLV_MASK) >> SFC_FSR_TXLV_SHIFT; +} + +static int rockchip_sfc_wait_rxfifo_ready(struct rockchip_sfc *sfc, u32 timeout_us) +{ + int ret = 0; + u32 status; + + ret = readl_poll_timeout(sfc->regbase + SFC_FSR, status, + status & SFC_FSR_RXLV_MASK, 0, + timeout_us); + if (ret) { + dev_dbg(sfc->dev, "sfc wait rx fifo timeout\n"); + + return -ETIMEDOUT; + } + + return (status & SFC_FSR_RXLV_MASK) >> SFC_FSR_RXLV_SHIFT; +} + +static void rockchip_sfc_adjust_op_work(struct spi_mem_op *op) +{ + if (unlikely(op->dummy.nbytes && !op->addr.nbytes)) { + /* + * SFC not support output DUMMY cycles right after CMD cycles, so + * treat it as ADDR cycles. + */ + op->addr.nbytes = op->dummy.nbytes; + op->addr.buswidth = op->dummy.buswidth; + op->addr.val = 0xFFFFFFFFF; + + op->dummy.nbytes = 0; + } +} + +static int rockchip_sfc_xfer_setup(struct rockchip_sfc *sfc, + struct spi_mem *mem, + const struct spi_mem_op *op, + u32 len) +{ + u32 ctrl = 0, cmd = 0; + + /* set CMD */ + cmd = op->cmd.opcode; + ctrl |= ((op->cmd.buswidth >> 1) << SFC_CTRL_CMD_BITS_SHIFT); + + /* set ADDR */ + if (op->addr.nbytes) { + if (op->addr.nbytes == 4) { + cmd |= SFC_CMD_ADDR_32BITS << SFC_CMD_ADDR_SHIFT; + } else if (op->addr.nbytes == 3) { + cmd |= SFC_CMD_ADDR_24BITS << SFC_CMD_ADDR_SHIFT; + } else { + cmd |= SFC_CMD_ADDR_XBITS << SFC_CMD_ADDR_SHIFT; + writel(op->addr.nbytes * 8 - 1, sfc->regbase + SFC_ABIT); + } + + ctrl |= ((op->addr.buswidth >> 1) << SFC_CTRL_ADDR_BITS_SHIFT); + } + + /* set DUMMY */ + if (op->dummy.nbytes) { + if (op->dummy.buswidth == 4) + cmd |= op->dummy.nbytes * 2 << SFC_CMD_DUMMY_SHIFT; + else if (op->dummy.buswidth == 2) + cmd |= op->dummy.nbytes * 4 << SFC_CMD_DUMMY_SHIFT; + else + cmd |= op->dummy.nbytes * 8 << SFC_CMD_DUMMY_SHIFT; + } + + /* set DATA */ + if (sfc->version >= SFC_VER_4) /* Clear it if no data to transfer */ + writel(len, sfc->regbase + SFC_LEN_EXT); + else + cmd |= len << SFC_CMD_TRAN_BYTES_SHIFT; + if (len) { + if (op->data.dir == SPI_MEM_DATA_OUT) + cmd |= SFC_CMD_DIR_WR << SFC_CMD_DIR_SHIFT; + + ctrl |= ((op->data.buswidth >> 1) << SFC_CTRL_DATA_BITS_SHIFT); + } + if (!len && op->addr.nbytes) + cmd |= SFC_CMD_DIR_WR << SFC_CMD_DIR_SHIFT; + + /* set the Controller */ + ctrl |= SFC_CTRL_PHASE_SEL_NEGETIVE; + cmd |= mem->spi->chip_select << SFC_CMD_CS_SHIFT; + + dev_dbg(sfc->dev, "sfc addr.nbytes=%x(x%d) dummy.nbytes=%x(x%d)\n", + op->addr.nbytes, op->addr.buswidth, + op->dummy.nbytes, op->dummy.buswidth); + dev_dbg(sfc->dev, "sfc ctrl=%x cmd=%x addr=%llx len=%x\n", + ctrl, cmd, op->addr.val, len); + + writel(ctrl, sfc->regbase + SFC_CTRL); + writel(cmd, sfc->regbase + SFC_CMD); + if (op->addr.nbytes) + writel(op->addr.val, sfc->regbase + SFC_ADDR); + + return 0; +} + +static int rockchip_sfc_write_fifo(struct rockchip_sfc *sfc, const u8 *buf, int len) +{ + u8 bytes = len & 0x3; + u32 dwords; + int tx_level; + u32 write_words; + u32 tmp = 0; + + dwords = len >> 2; + while (dwords) { + tx_level = rockchip_sfc_wait_txfifo_ready(sfc, 1000); + if (tx_level < 0) + return tx_level; + write_words = min_t(u32, tx_level, dwords); + iowrite32_rep(sfc->regbase + SFC_DATA, buf, write_words); + buf += write_words << 2; + dwords -= write_words; + } + + /* write the rest non word aligned bytes */ + if (bytes) { + tx_level = rockchip_sfc_wait_txfifo_ready(sfc, 1000); + if (tx_level < 0) + return tx_level; + memcpy(&tmp, buf, bytes); + writel(tmp, sfc->regbase + SFC_DATA); + } + + return len; +} + +static int rockchip_sfc_read_fifo(struct rockchip_sfc *sfc, u8 *buf, int len) +{ + u8 bytes = len & 0x3; + u32 dwords; + u8 read_words; + int rx_level; + int tmp; + + /* word aligned access only */ + dwords = len >> 2; + while (dwords) { + rx_level = rockchip_sfc_wait_rxfifo_ready(sfc, 1000); + if (rx_level < 0) + return rx_level; + read_words = min_t(u32, rx_level, dwords); + ioread32_rep(sfc->regbase + SFC_DATA, buf, read_words); + buf += read_words << 2; + dwords -= read_words; + } + + /* read the rest non word aligned bytes */ + if (bytes) { + rx_level = rockchip_sfc_wait_rxfifo_ready(sfc, 1000); + if (rx_level < 0) + return rx_level; + tmp = readl(sfc->regbase + SFC_DATA); + memcpy(buf, &tmp, bytes); + } + + return len; +} + +static int rockchip_sfc_fifo_transfer_dma(struct rockchip_sfc *sfc, dma_addr_t dma_buf, size_t len) +{ + writel(0xFFFFFFFF, sfc->regbase + SFC_ICLR); + writel((u32)dma_buf, sfc->regbase + SFC_DMA_ADDR); + writel(SFC_DMA_TRIGGER_START, sfc->regbase + SFC_DMA_TRIGGER); + + return len; +} + +static int rockchip_sfc_xfer_data_poll(struct rockchip_sfc *sfc, + const struct spi_mem_op *op, u32 len) +{ + dev_dbg(sfc->dev, "sfc xfer_poll len=%x\n", len); + + if (op->data.dir == SPI_MEM_DATA_OUT) + return rockchip_sfc_write_fifo(sfc, op->data.buf.out, len); + else + return rockchip_sfc_read_fifo(sfc, op->data.buf.in, len); +} + +static int rockchip_sfc_xfer_data_dma(struct rockchip_sfc *sfc, + const struct spi_mem_op *op, u32 len) +{ + int ret; + + dev_dbg(sfc->dev, "sfc xfer_dma len=%x\n", len); + + if (op->data.dir == SPI_MEM_DATA_OUT) + memcpy(sfc->buffer, op->data.buf.out, len); + + ret = rockchip_sfc_fifo_transfer_dma(sfc, sfc->dma_buffer, len); + if (!wait_for_completion_timeout(&sfc->cp, msecs_to_jiffies(2000))) { + dev_err(sfc->dev, "DMA wait for transfer finish timeout\n"); + ret = -ETIMEDOUT; + } + rockchip_sfc_irq_mask(sfc, SFC_IMR_DMA); + if (op->data.dir == SPI_MEM_DATA_IN) + memcpy(op->data.buf.in, sfc->buffer, len); + + return ret; +} + +static int rockchip_sfc_xfer_done(struct rockchip_sfc *sfc, u32 timeout_us) +{ + int ret = 0; + u32 status; + + ret = readl_poll_timeout(sfc->regbase + SFC_SR, status, + !(status & SFC_SR_IS_BUSY), + 20, timeout_us); + if (ret) { + dev_err(sfc->dev, "wait sfc idle timeout\n"); + rockchip_sfc_reset(sfc); + + ret = -EIO; + } + + return ret; +} + +static int rockchip_sfc_exec_mem_op(struct spi_mem *mem, const struct spi_mem_op *op) +{ + struct rockchip_sfc *sfc = spi_master_get_devdata(mem->spi->master); + u32 len = op->data.nbytes; + int ret; + + if (unlikely(mem->spi->max_speed_hz != sfc->frequency)) { + ret = clk_set_rate(sfc->clk, mem->spi->max_speed_hz); + if (ret) + return ret; + sfc->frequency = mem->spi->max_speed_hz; + dev_dbg(sfc->dev, "set_freq=%dHz real_freq=%ldHz\n", + sfc->frequency, clk_get_rate(sfc->clk)); + } + + rockchip_sfc_adjust_op_work((struct spi_mem_op *)op); + rockchip_sfc_xfer_setup(sfc, mem, op, len); + if (len) { + if (likely(sfc->use_dma) && len >= SFC_DMA_TRANS_THRETHOLD) { + init_completion(&sfc->cp); + rockchip_sfc_irq_unmask(sfc, SFC_IMR_DMA); + ret = rockchip_sfc_xfer_data_dma(sfc, op, len); + } else { + ret = rockchip_sfc_xfer_data_poll(sfc, op, len); + } + + if (ret != len) { + dev_err(sfc->dev, "xfer data failed ret %d dir %d\n", ret, op->data.dir); + + return -EIO; + } + } + + return rockchip_sfc_xfer_done(sfc, 100000); +} + +static int rockchip_sfc_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op) +{ + struct rockchip_sfc *sfc = spi_master_get_devdata(mem->spi->master); + + op->data.nbytes = min(op->data.nbytes, sfc->max_iosize); + + return 0; +} + +static const struct spi_controller_mem_ops rockchip_sfc_mem_ops = { + .exec_op = rockchip_sfc_exec_mem_op, + .adjust_op_size = rockchip_sfc_adjust_op_size, +}; + +static irqreturn_t rockchip_sfc_irq_handler(int irq, void *dev_id) +{ + struct rockchip_sfc *sfc = dev_id; + u32 reg; + + reg = readl(sfc->regbase + SFC_RISR); + + /* Clear interrupt */ + writel_relaxed(reg, sfc->regbase + SFC_ICLR); + + if (reg & SFC_RISR_DMA) { + complete(&sfc->cp); + + return IRQ_HANDLED; + } + + return IRQ_NONE; +} + +static int rockchip_sfc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct spi_master *master; + struct resource *res; + struct rockchip_sfc *sfc; + int ret; + + master = devm_spi_alloc_master(&pdev->dev, sizeof(*sfc)); + if (!master) + return -ENOMEM; + + master->flags = SPI_MASTER_HALF_DUPLEX; + master->mem_ops = &rockchip_sfc_mem_ops; + master->dev.of_node = pdev->dev.of_node; + master->mode_bits = SPI_TX_QUAD | SPI_TX_DUAL | SPI_RX_QUAD | SPI_RX_DUAL; + master->max_speed_hz = SFC_MAX_SPEED; + master->num_chipselect = SFC_MAX_CHIPSELECT_NUM; + + sfc = spi_master_get_devdata(master); + sfc->dev = dev; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + sfc->regbase = devm_ioremap_resource(dev, res); + if (IS_ERR(sfc->regbase)) + return PTR_ERR(sfc->regbase); + + sfc->clk = devm_clk_get(&pdev->dev, "clk_sfc"); + if (IS_ERR(sfc->clk)) { + dev_err(&pdev->dev, "Failed to get sfc interface clk\n"); + return PTR_ERR(sfc->clk); + } + + sfc->hclk = devm_clk_get(&pdev->dev, "hclk_sfc"); + if (IS_ERR(sfc->hclk)) { + dev_err(&pdev->dev, "Failed to get sfc ahb clk\n"); + return PTR_ERR(sfc->hclk); + } + + sfc->use_dma = !of_property_read_bool(sfc->dev->of_node, + "rockchip,sfc-no-dma"); + + if (sfc->use_dma) { + ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32)); + if (ret) { + dev_warn(dev, "Unable to set dma mask\n"); + return ret; + } + + sfc->buffer = dmam_alloc_coherent(dev, SFC_MAX_IOSIZE_VER3, + &sfc->dma_buffer, + GFP_KERNEL); + if (!sfc->buffer) + return -ENOMEM; + } + + ret = clk_prepare_enable(sfc->hclk); + if (ret) { + dev_err(&pdev->dev, "Failed to enable ahb clk\n"); + goto err_hclk; + } + + ret = clk_prepare_enable(sfc->clk); + if (ret) { + dev_err(&pdev->dev, "Failed to enable interface clk\n"); + goto err_clk; + } + + /* Find the irq */ + ret = platform_get_irq(pdev, 0); + if (ret < 0) { + dev_err(dev, "Failed to get the irq\n"); + goto err_irq; + } + + ret = devm_request_irq(dev, ret, rockchip_sfc_irq_handler, + 0, pdev->name, sfc); + if (ret) { + dev_err(dev, "Failed to request irq\n"); + + return ret; + } + + ret = rockchip_sfc_init(sfc); + if (ret) + goto err_irq; + + sfc->max_iosize = rockchip_sfc_get_max_iosize(sfc); + sfc->version = rockchip_sfc_get_version(sfc); + + ret = spi_register_master(master); + if (ret) + goto err_irq; + + return 0; + +err_irq: + clk_disable_unprepare(sfc->clk); +err_clk: + clk_disable_unprepare(sfc->hclk); +err_hclk: + return ret; +} + +static int rockchip_sfc_remove(struct platform_device *pdev) +{ + struct spi_master *master = platform_get_drvdata(pdev); + struct rockchip_sfc *sfc = platform_get_drvdata(pdev); + + spi_unregister_master(master); + + clk_disable_unprepare(sfc->clk); + clk_disable_unprepare(sfc->hclk); + + return 0; +} + +static const struct of_device_id rockchip_sfc_dt_ids[] = { + { .compatible = "rockchip,sfc"}, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, rockchip_sfc_dt_ids); + +static struct platform_driver rockchip_sfc_driver = { + .driver = { + .name = "rockchip-sfc", + .of_match_table = rockchip_sfc_dt_ids, + }, + .probe = rockchip_sfc_probe, + .remove = rockchip_sfc_remove, +}; +module_platform_driver(rockchip_sfc_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Rockchip Serial Flash Controller Driver"); +MODULE_AUTHOR("Shawn Lin <shawn.lin@rock-chips.com>"); +MODULE_AUTHOR("Chris Morgan <macromorgan@hotmail.com>"); +MODULE_AUTHOR("Jon Lin <Jon.lin@rock-chips.com>"); diff --git a/drivers/spi/spi-sprd-adi.c b/drivers/spi/spi-sprd-adi.c index ab19068be867..1edbf44c05a7 100644 --- a/drivers/spi/spi-sprd-adi.c +++ b/drivers/spi/spi-sprd-adi.c @@ -52,10 +52,20 @@ /* * ADI slave devices include RTC, ADC, regulator, charger, thermal and so on. - * The slave devices address offset is always 0x8000 and size is 4K. + * ADI supports 12/14bit address for r2p0, and additional 17bit for r3p0 or + * later versions. Since bit[1:0] are zero, so the spec describe them as + * 10/12/15bit address mode. + * The 10bit mode supports sigle slave, 12/15bit mode supports 3 slave, the + * high two bits is slave_id. + * The slave devices address offset is 0x8000 for 10/12bit address mode, + * and 0x20000 for 15bit mode. */ -#define ADI_SLAVE_ADDR_SIZE SZ_4K -#define ADI_SLAVE_OFFSET 0x8000 +#define ADI_10BIT_SLAVE_ADDR_SIZE SZ_4K +#define ADI_10BIT_SLAVE_OFFSET 0x8000 +#define ADI_12BIT_SLAVE_ADDR_SIZE SZ_16K +#define ADI_12BIT_SLAVE_OFFSET 0x8000 +#define ADI_15BIT_SLAVE_ADDR_SIZE SZ_128K +#define ADI_15BIT_SLAVE_OFFSET 0x20000 /* Timeout (ms) for the trylock of hardware spinlocks */ #define ADI_HWSPINLOCK_TIMEOUT 5000 @@ -67,24 +77,35 @@ #define ADI_FIFO_DRAIN_TIMEOUT 1000 #define ADI_READ_TIMEOUT 2000 -#define REG_ADDR_LOW_MASK GENMASK(11, 0) + +/* + * Read back address from REG_ADI_RD_DATA bit[30:16] which maps to: + * REG_ADI_RD_CMD bit[14:0] for r2p0 + * REG_ADI_RD_CMD bit[16:2] for r3p0 + */ +#define RDBACK_ADDR_MASK_R2 GENMASK(14, 0) +#define RDBACK_ADDR_MASK_R3 GENMASK(16, 2) +#define RDBACK_ADDR_SHIFT_R3 2 /* Registers definitions for PMIC watchdog controller */ -#define REG_WDG_LOAD_LOW 0x80 -#define REG_WDG_LOAD_HIGH 0x84 -#define REG_WDG_CTRL 0x88 -#define REG_WDG_LOCK 0xa0 +#define REG_WDG_LOAD_LOW 0x0 +#define REG_WDG_LOAD_HIGH 0x4 +#define REG_WDG_CTRL 0x8 +#define REG_WDG_LOCK 0x20 /* Bits definitions for register REG_WDG_CTRL */ #define BIT_WDG_RUN BIT(1) #define BIT_WDG_NEW BIT(2) #define BIT_WDG_RST BIT(3) +/* Bits definitions for register REG_MODULE_EN */ +#define BIT_WDG_EN BIT(2) + /* Registers definitions for PMIC */ #define PMIC_RST_STATUS 0xee8 #define PMIC_MODULE_EN 0xc08 #define PMIC_CLK_EN 0xc18 -#define BIT_WDG_EN BIT(2) +#define PMIC_WDG_BASE 0x80 /* Definition of PMIC reset status register */ #define HWRST_STATUS_SECURITY 0x02 @@ -103,10 +124,26 @@ #define HWRST_STATUS_WATCHDOG 0xf0 /* Use default timeout 50 ms that converts to watchdog values */ -#define WDG_LOAD_VAL ((50 * 1000) / 32768) +#define WDG_LOAD_VAL ((50 * 32768) / 1000) #define WDG_LOAD_MASK GENMASK(15, 0) #define WDG_UNLOCK_KEY 0xe551 +struct sprd_adi_wdg { + u32 base; + u32 rst_sts; + u32 wdg_en; + u32 wdg_clk; +}; + +struct sprd_adi_data { + u32 slave_offset; + u32 slave_addr_size; + int (*read_check)(u32 val, u32 reg); + int (*restart)(struct notifier_block *this, + unsigned long mode, void *cmd); + void (*wdg_rst)(void *p); +}; + struct sprd_adi { struct spi_controller *ctlr; struct device *dev; @@ -115,26 +152,21 @@ struct sprd_adi { unsigned long slave_vbase; unsigned long slave_pbase; struct notifier_block restart_handler; + const struct sprd_adi_data *data; }; -static int sprd_adi_check_paddr(struct sprd_adi *sadi, u32 paddr) +static int sprd_adi_check_addr(struct sprd_adi *sadi, u32 reg) { - if (paddr < sadi->slave_pbase || paddr > - (sadi->slave_pbase + ADI_SLAVE_ADDR_SIZE)) { + if (reg >= sadi->data->slave_addr_size) { dev_err(sadi->dev, - "slave physical address is incorrect, addr = 0x%x\n", - paddr); + "slave address offset is incorrect, reg = 0x%x\n", + reg); return -EINVAL; } return 0; } -static unsigned long sprd_adi_to_vaddr(struct sprd_adi *sadi, u32 paddr) -{ - return (paddr - sadi->slave_pbase + sadi->slave_vbase); -} - static int sprd_adi_drain_fifo(struct sprd_adi *sadi) { u32 timeout = ADI_FIFO_DRAIN_TIMEOUT; @@ -161,11 +193,35 @@ static int sprd_adi_fifo_is_full(struct sprd_adi *sadi) return readl_relaxed(sadi->base + REG_ADI_ARM_FIFO_STS) & BIT_FIFO_FULL; } -static int sprd_adi_read(struct sprd_adi *sadi, u32 reg_paddr, u32 *read_val) +static int sprd_adi_read_check(u32 val, u32 addr) +{ + u32 rd_addr; + + rd_addr = (val & RD_ADDR_MASK) >> RD_ADDR_SHIFT; + + if (rd_addr != addr) { + pr_err("ADI read error, addr = 0x%x, val = 0x%x\n", addr, val); + return -EIO; + } + + return 0; +} + +static int sprd_adi_read_check_r2(u32 val, u32 reg) +{ + return sprd_adi_read_check(val, reg & RDBACK_ADDR_MASK_R2); +} + +static int sprd_adi_read_check_r3(u32 val, u32 reg) +{ + return sprd_adi_read_check(val, (reg & RDBACK_ADDR_MASK_R3) >> RDBACK_ADDR_SHIFT_R3); +} + +static int sprd_adi_read(struct sprd_adi *sadi, u32 reg, u32 *read_val) { int read_timeout = ADI_READ_TIMEOUT; unsigned long flags; - u32 val, rd_addr; + u32 val; int ret = 0; if (sadi->hwlock) { @@ -178,11 +234,15 @@ static int sprd_adi_read(struct sprd_adi *sadi, u32 reg_paddr, u32 *read_val) } } + ret = sprd_adi_check_addr(sadi, reg); + if (ret) + goto out; + /* - * Set the physical register address need to read into RD_CMD register, + * Set the slave address offset need to read into RD_CMD register, * then ADI controller will start to transfer automatically. */ - writel_relaxed(reg_paddr, sadi->base + REG_ADI_RD_CMD); + writel_relaxed(reg, sadi->base + REG_ADI_RD_CMD); /* * Wait read operation complete, the BIT_RD_CMD_BUSY will be set @@ -205,18 +265,15 @@ static int sprd_adi_read(struct sprd_adi *sadi, u32 reg_paddr, u32 *read_val) } /* - * The return value includes data and read register address, from bit 0 - * to bit 15 are data, and from bit 16 to bit 30 are read register - * address. Then we can check the returned register address to validate - * data. + * The return value before adi r5p0 includes data and read register + * address, from bit 0to bit 15 are data, and from bit 16 to bit 30 + * are read register address. Then we can check the returned register + * address to validate data. */ - rd_addr = (val & RD_ADDR_MASK) >> RD_ADDR_SHIFT; - - if (rd_addr != (reg_paddr & REG_ADDR_LOW_MASK)) { - dev_err(sadi->dev, "read error, reg addr = 0x%x, val = 0x%x\n", - reg_paddr, val); - ret = -EIO; - goto out; + if (sadi->data->read_check) { + ret = sadi->data->read_check(val, reg); + if (ret < 0) + goto out; } *read_val = val & RD_VALUE_MASK; @@ -227,9 +284,8 @@ out: return ret; } -static int sprd_adi_write(struct sprd_adi *sadi, u32 reg_paddr, u32 val) +static int sprd_adi_write(struct sprd_adi *sadi, u32 reg, u32 val) { - unsigned long reg = sprd_adi_to_vaddr(sadi, reg_paddr); u32 timeout = ADI_FIFO_DRAIN_TIMEOUT; unsigned long flags; int ret; @@ -244,6 +300,10 @@ static int sprd_adi_write(struct sprd_adi *sadi, u32 reg_paddr, u32 val) } } + ret = sprd_adi_check_addr(sadi, reg); + if (ret) + goto out; + ret = sprd_adi_drain_fifo(sadi); if (ret < 0) goto out; @@ -254,7 +314,8 @@ static int sprd_adi_write(struct sprd_adi *sadi, u32 reg_paddr, u32 val) */ do { if (!sprd_adi_fifo_is_full(sadi)) { - writel_relaxed(val, (void __iomem *)reg); + /* we need virtual register address to write. */ + writel_relaxed(val, (void __iomem *)(sadi->slave_vbase + reg)); break; } @@ -277,60 +338,41 @@ static int sprd_adi_transfer_one(struct spi_controller *ctlr, struct spi_transfer *t) { struct sprd_adi *sadi = spi_controller_get_devdata(ctlr); - u32 phy_reg, val; + u32 reg, val; int ret; if (t->rx_buf) { - phy_reg = *(u32 *)t->rx_buf + sadi->slave_pbase; - - ret = sprd_adi_check_paddr(sadi, phy_reg); - if (ret) - return ret; - - ret = sprd_adi_read(sadi, phy_reg, &val); - if (ret) - return ret; - + reg = *(u32 *)t->rx_buf; + ret = sprd_adi_read(sadi, reg, &val); *(u32 *)t->rx_buf = val; } else if (t->tx_buf) { u32 *p = (u32 *)t->tx_buf; - - /* - * Get the physical register address need to write and convert - * the physical address to virtual address. Since we need - * virtual register address to write. - */ - phy_reg = *p++ + sadi->slave_pbase; - ret = sprd_adi_check_paddr(sadi, phy_reg); - if (ret) - return ret; - + reg = *p++; val = *p; - ret = sprd_adi_write(sadi, phy_reg, val); - if (ret) - return ret; + ret = sprd_adi_write(sadi, reg, val); } else { dev_err(sadi->dev, "no buffer for transfer\n"); - return -EINVAL; + ret = -EINVAL; } - return 0; + return ret; } -static void sprd_adi_set_wdt_rst_mode(struct sprd_adi *sadi) +static void sprd_adi_set_wdt_rst_mode(void *p) { #if IS_ENABLED(CONFIG_SPRD_WATCHDOG) u32 val; + struct sprd_adi *sadi = (struct sprd_adi *)p; - /* Set default watchdog reboot mode */ - sprd_adi_read(sadi, sadi->slave_pbase + PMIC_RST_STATUS, &val); + /* Init watchdog reset mode */ + sprd_adi_read(sadi, PMIC_RST_STATUS, &val); val |= HWRST_STATUS_WATCHDOG; - sprd_adi_write(sadi, sadi->slave_pbase + PMIC_RST_STATUS, val); + sprd_adi_write(sadi, PMIC_RST_STATUS, val); #endif } -static int sprd_adi_restart_handler(struct notifier_block *this, - unsigned long mode, void *cmd) +static int sprd_adi_restart(struct notifier_block *this, unsigned long mode, + void *cmd, struct sprd_adi_wdg *wdg) { struct sprd_adi *sadi = container_of(this, struct sprd_adi, restart_handler); @@ -366,40 +408,40 @@ static int sprd_adi_restart_handler(struct notifier_block *this, reboot_mode = HWRST_STATUS_NORMAL; /* Record the reboot mode */ - sprd_adi_read(sadi, sadi->slave_pbase + PMIC_RST_STATUS, &val); + sprd_adi_read(sadi, wdg->rst_sts, &val); val &= ~HWRST_STATUS_WATCHDOG; val |= reboot_mode; - sprd_adi_write(sadi, sadi->slave_pbase + PMIC_RST_STATUS, val); + sprd_adi_write(sadi, wdg->rst_sts, val); /* Enable the interface clock of the watchdog */ - sprd_adi_read(sadi, sadi->slave_pbase + PMIC_MODULE_EN, &val); + sprd_adi_read(sadi, wdg->wdg_en, &val); val |= BIT_WDG_EN; - sprd_adi_write(sadi, sadi->slave_pbase + PMIC_MODULE_EN, val); + sprd_adi_write(sadi, wdg->wdg_en, val); /* Enable the work clock of the watchdog */ - sprd_adi_read(sadi, sadi->slave_pbase + PMIC_CLK_EN, &val); + sprd_adi_read(sadi, wdg->wdg_clk, &val); val |= BIT_WDG_EN; - sprd_adi_write(sadi, sadi->slave_pbase + PMIC_CLK_EN, val); + sprd_adi_write(sadi, wdg->wdg_clk, val); /* Unlock the watchdog */ - sprd_adi_write(sadi, sadi->slave_pbase + REG_WDG_LOCK, WDG_UNLOCK_KEY); + sprd_adi_write(sadi, wdg->base + REG_WDG_LOCK, WDG_UNLOCK_KEY); - sprd_adi_read(sadi, sadi->slave_pbase + REG_WDG_CTRL, &val); + sprd_adi_read(sadi, wdg->base + REG_WDG_CTRL, &val); val |= BIT_WDG_NEW; - sprd_adi_write(sadi, sadi->slave_pbase + REG_WDG_CTRL, val); + sprd_adi_write(sadi, wdg->base + REG_WDG_CTRL, val); /* Load the watchdog timeout value, 50ms is always enough. */ - sprd_adi_write(sadi, sadi->slave_pbase + REG_WDG_LOAD_HIGH, 0); - sprd_adi_write(sadi, sadi->slave_pbase + REG_WDG_LOAD_LOW, + sprd_adi_write(sadi, wdg->base + REG_WDG_LOAD_HIGH, 0); + sprd_adi_write(sadi, wdg->base + REG_WDG_LOAD_LOW, WDG_LOAD_VAL & WDG_LOAD_MASK); /* Start the watchdog to reset system */ - sprd_adi_read(sadi, sadi->slave_pbase + REG_WDG_CTRL, &val); + sprd_adi_read(sadi, wdg->base + REG_WDG_CTRL, &val); val |= BIT_WDG_RUN | BIT_WDG_RST; - sprd_adi_write(sadi, sadi->slave_pbase + REG_WDG_CTRL, val); + sprd_adi_write(sadi, wdg->base + REG_WDG_CTRL, val); /* Lock the watchdog */ - sprd_adi_write(sadi, sadi->slave_pbase + REG_WDG_LOCK, ~WDG_UNLOCK_KEY); + sprd_adi_write(sadi, wdg->base + REG_WDG_LOCK, ~WDG_UNLOCK_KEY); mdelay(1000); @@ -407,6 +449,19 @@ static int sprd_adi_restart_handler(struct notifier_block *this, return NOTIFY_DONE; } +static int sprd_adi_restart_sc9860(struct notifier_block *this, + unsigned long mode, void *cmd) +{ + struct sprd_adi_wdg wdg = { + .base = PMIC_WDG_BASE, + .rst_sts = PMIC_RST_STATUS, + .wdg_en = PMIC_MODULE_EN, + .wdg_clk = PMIC_CLK_EN, + }; + + return sprd_adi_restart(this, mode, cmd, &wdg); +} + static void sprd_adi_hw_init(struct sprd_adi *sadi) { struct device_node *np = sadi->dev->of_node; @@ -458,10 +513,11 @@ static void sprd_adi_hw_init(struct sprd_adi *sadi) static int sprd_adi_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; + const struct sprd_adi_data *data; struct spi_controller *ctlr; struct sprd_adi *sadi; struct resource *res; - u32 num_chipselect; + u16 num_chipselect; int ret; if (!np) { @@ -469,6 +525,12 @@ static int sprd_adi_probe(struct platform_device *pdev) return -ENODEV; } + data = of_device_get_match_data(&pdev->dev); + if (!data) { + dev_err(&pdev->dev, "no matching driver data found\n"); + return -EINVAL; + } + pdev->id = of_alias_get_id(np, "spi"); num_chipselect = of_get_child_count(np); @@ -486,10 +548,12 @@ static int sprd_adi_probe(struct platform_device *pdev) goto put_ctlr; } - sadi->slave_vbase = (unsigned long)sadi->base + ADI_SLAVE_OFFSET; - sadi->slave_pbase = res->start + ADI_SLAVE_OFFSET; + sadi->slave_vbase = (unsigned long)sadi->base + + data->slave_offset; + sadi->slave_pbase = res->start + data->slave_offset; sadi->ctlr = ctlr; sadi->dev = &pdev->dev; + sadi->data = data; ret = of_hwspin_lock_get_id(np, 0); if (ret > 0 || (IS_ENABLED(CONFIG_HWSPINLOCK) && ret == 0)) { sadi->hwlock = @@ -510,7 +574,9 @@ static int sprd_adi_probe(struct platform_device *pdev) } sprd_adi_hw_init(sadi); - sprd_adi_set_wdt_rst_mode(sadi); + + if (sadi->data->wdg_rst) + sadi->data->wdg_rst(sadi); ctlr->dev.of_node = pdev->dev.of_node; ctlr->bus_num = pdev->id; @@ -525,12 +591,14 @@ static int sprd_adi_probe(struct platform_device *pdev) goto put_ctlr; } - sadi->restart_handler.notifier_call = sprd_adi_restart_handler; - sadi->restart_handler.priority = 128; - ret = register_restart_handler(&sadi->restart_handler); - if (ret) { - dev_err(&pdev->dev, "can not register restart handler\n"); - goto put_ctlr; + if (sadi->data->restart) { + sadi->restart_handler.notifier_call = sadi->data->restart; + sadi->restart_handler.priority = 128; + ret = register_restart_handler(&sadi->restart_handler); + if (ret) { + dev_err(&pdev->dev, "can not register restart handler\n"); + goto put_ctlr; + } } return 0; @@ -549,9 +617,38 @@ static int sprd_adi_remove(struct platform_device *pdev) return 0; } +static struct sprd_adi_data sc9860_data = { + .slave_offset = ADI_10BIT_SLAVE_OFFSET, + .slave_addr_size = ADI_10BIT_SLAVE_ADDR_SIZE, + .read_check = sprd_adi_read_check_r2, + .restart = sprd_adi_restart_sc9860, + .wdg_rst = sprd_adi_set_wdt_rst_mode, +}; + +static struct sprd_adi_data sc9863_data = { + .slave_offset = ADI_12BIT_SLAVE_OFFSET, + .slave_addr_size = ADI_12BIT_SLAVE_ADDR_SIZE, + .read_check = sprd_adi_read_check_r3, +}; + +static struct sprd_adi_data ums512_data = { + .slave_offset = ADI_15BIT_SLAVE_OFFSET, + .slave_addr_size = ADI_15BIT_SLAVE_ADDR_SIZE, + .read_check = sprd_adi_read_check_r3, +}; + static const struct of_device_id sprd_adi_of_match[] = { { .compatible = "sprd,sc9860-adi", + .data = &sc9860_data, + }, + { + .compatible = "sprd,sc9863-adi", + .data = &sc9863_data, + }, + { + .compatible = "sprd,ums512-adi", + .data = &ums512_data, }, { }, }; diff --git a/drivers/spi/spi-stm32.c b/drivers/spi/spi-stm32.c index 05618a618939..9bd3fd1652f7 100644 --- a/drivers/spi/spi-stm32.c +++ b/drivers/spi/spi-stm32.c @@ -162,6 +162,8 @@ #define SPI_3WIRE_TX 3 #define SPI_3WIRE_RX 4 +#define STM32_SPI_AUTOSUSPEND_DELAY 1 /* 1 ms */ + /* * use PIO for small transfers, avoiding DMA setup/teardown overhead for drivers * without fifo buffers. @@ -568,29 +570,30 @@ static void stm32f4_spi_read_rx(struct stm32_spi *spi) /** * stm32h7_spi_read_rxfifo - Read bytes in Receive Data Register * @spi: pointer to the spi controller data structure - * @flush: boolean indicating that FIFO should be flushed * * Write in rx_buf depends on remaining bytes to avoid to write beyond * rx_buf end. */ -static void stm32h7_spi_read_rxfifo(struct stm32_spi *spi, bool flush) +static void stm32h7_spi_read_rxfifo(struct stm32_spi *spi) { u32 sr = readl_relaxed(spi->base + STM32H7_SPI_SR); u32 rxplvl = FIELD_GET(STM32H7_SPI_SR_RXPLVL, sr); while ((spi->rx_len > 0) && ((sr & STM32H7_SPI_SR_RXP) || - (flush && ((sr & STM32H7_SPI_SR_RXWNE) || (rxplvl > 0))))) { + ((sr & STM32H7_SPI_SR_EOT) && + ((sr & STM32H7_SPI_SR_RXWNE) || (rxplvl > 0))))) { u32 offs = spi->cur_xferlen - spi->rx_len; if ((spi->rx_len >= sizeof(u32)) || - (flush && (sr & STM32H7_SPI_SR_RXWNE))) { + (sr & STM32H7_SPI_SR_RXWNE)) { u32 *rx_buf32 = (u32 *)(spi->rx_buf + offs); *rx_buf32 = readl_relaxed(spi->base + STM32H7_SPI_RXDR); spi->rx_len -= sizeof(u32); } else if ((spi->rx_len >= sizeof(u16)) || - (flush && (rxplvl >= 2 || spi->cur_bpw > 8))) { + (!(sr & STM32H7_SPI_SR_RXWNE) && + (rxplvl >= 2 || spi->cur_bpw > 8))) { u16 *rx_buf16 = (u16 *)(spi->rx_buf + offs); *rx_buf16 = readw_relaxed(spi->base + STM32H7_SPI_RXDR); @@ -606,8 +609,8 @@ static void stm32h7_spi_read_rxfifo(struct stm32_spi *spi, bool flush) rxplvl = FIELD_GET(STM32H7_SPI_SR_RXPLVL, sr); } - dev_dbg(spi->dev, "%s%s: %d bytes left\n", __func__, - flush ? "(flush)" : "", spi->rx_len); + dev_dbg(spi->dev, "%s: %d bytes left (sr=%08x)\n", + __func__, spi->rx_len, sr); } /** @@ -674,18 +677,12 @@ static void stm32f4_spi_disable(struct stm32_spi *spi) * stm32h7_spi_disable - Disable SPI controller * @spi: pointer to the spi controller data structure * - * RX-Fifo is flushed when SPI controller is disabled. To prevent any data - * loss, use stm32h7_spi_read_rxfifo(flush) to read the remaining bytes in - * RX-Fifo. - * Normally, if TSIZE has been configured, we should relax the hardware at the - * reception of the EOT interrupt. But in case of error, EOT will not be - * raised. So the subsystem unprepare_message call allows us to properly - * complete the transfer from an hardware point of view. + * RX-Fifo is flushed when SPI controller is disabled. */ static void stm32h7_spi_disable(struct stm32_spi *spi) { unsigned long flags; - u32 cr1, sr; + u32 cr1; dev_dbg(spi->dev, "disable controller\n"); @@ -698,25 +695,6 @@ static void stm32h7_spi_disable(struct stm32_spi *spi) return; } - /* Wait on EOT or suspend the flow */ - if (readl_relaxed_poll_timeout_atomic(spi->base + STM32H7_SPI_SR, - sr, !(sr & STM32H7_SPI_SR_EOT), - 10, 100000) < 0) { - if (cr1 & STM32H7_SPI_CR1_CSTART) { - writel_relaxed(cr1 | STM32H7_SPI_CR1_CSUSP, - spi->base + STM32H7_SPI_CR1); - if (readl_relaxed_poll_timeout_atomic( - spi->base + STM32H7_SPI_SR, - sr, !(sr & STM32H7_SPI_SR_SUSP), - 10, 100000) < 0) - dev_warn(spi->dev, - "Suspend request timeout\n"); - } - } - - if (!spi->cur_usedma && spi->rx_buf && (spi->rx_len > 0)) - stm32h7_spi_read_rxfifo(spi, true); - if (spi->cur_usedma && spi->dma_tx) dmaengine_terminate_all(spi->dma_tx); if (spi->cur_usedma && spi->dma_rx) @@ -911,7 +889,7 @@ static irqreturn_t stm32h7_spi_irq_thread(int irq, void *dev_id) if (__ratelimit(&rs)) dev_dbg_ratelimited(spi->dev, "Communication suspended\n"); if (!spi->cur_usedma && (spi->rx_buf && (spi->rx_len > 0))) - stm32h7_spi_read_rxfifo(spi, false); + stm32h7_spi_read_rxfifo(spi); /* * If communication is suspended while using DMA, it means * that something went wrong, so stop the current transfer @@ -932,8 +910,10 @@ static irqreturn_t stm32h7_spi_irq_thread(int irq, void *dev_id) if (sr & STM32H7_SPI_SR_EOT) { if (!spi->cur_usedma && (spi->rx_buf && (spi->rx_len > 0))) - stm32h7_spi_read_rxfifo(spi, true); - end = true; + stm32h7_spi_read_rxfifo(spi); + if (!spi->cur_usedma || + (spi->cur_comm == SPI_SIMPLEX_TX || spi->cur_comm == SPI_3WIRE_TX)) + end = true; } if (sr & STM32H7_SPI_SR_TXP) @@ -942,7 +922,7 @@ static irqreturn_t stm32h7_spi_irq_thread(int irq, void *dev_id) if (sr & STM32H7_SPI_SR_RXP) if (!spi->cur_usedma && (spi->rx_buf && (spi->rx_len > 0))) - stm32h7_spi_read_rxfifo(spi, false); + stm32h7_spi_read_rxfifo(spi); writel_relaxed(sr & mask, spi->base + STM32H7_SPI_IFCR); @@ -1041,42 +1021,17 @@ static void stm32f4_spi_dma_tx_cb(void *data) } /** - * stm32f4_spi_dma_rx_cb - dma callback + * stm32_spi_dma_rx_cb - dma callback * @data: pointer to the spi controller data structure * * DMA callback is called when the transfer is complete for DMA RX channel. */ -static void stm32f4_spi_dma_rx_cb(void *data) +static void stm32_spi_dma_rx_cb(void *data) { struct stm32_spi *spi = data; spi_finalize_current_transfer(spi->master); - stm32f4_spi_disable(spi); -} - -/** - * stm32h7_spi_dma_cb - dma callback - * @data: pointer to the spi controller data structure - * - * DMA callback is called when the transfer is complete or when an error - * occurs. If the transfer is complete, EOT flag is raised. - */ -static void stm32h7_spi_dma_cb(void *data) -{ - struct stm32_spi *spi = data; - unsigned long flags; - u32 sr; - - spin_lock_irqsave(&spi->lock, flags); - - sr = readl_relaxed(spi->base + STM32H7_SPI_SR); - - spin_unlock_irqrestore(&spi->lock, flags); - - if (!(sr & STM32H7_SPI_SR_EOT)) - dev_warn(spi->dev, "DMA error (sr=0x%08x)\n", sr); - - /* Now wait for EOT, or SUSP or OVR in case of error */ + spi->cfg->disable(spi); } /** @@ -1242,11 +1197,13 @@ static void stm32f4_spi_transfer_one_dma_start(struct stm32_spi *spi) */ static void stm32h7_spi_transfer_one_dma_start(struct stm32_spi *spi) { - /* Enable the interrupts relative to the end of transfer */ - stm32_spi_set_bits(spi, STM32H7_SPI_IER, STM32H7_SPI_IER_EOTIE | - STM32H7_SPI_IER_TXTFIE | - STM32H7_SPI_IER_OVRIE | - STM32H7_SPI_IER_MODFIE); + uint32_t ier = STM32H7_SPI_IER_OVRIE | STM32H7_SPI_IER_MODFIE; + + /* Enable the interrupts */ + if (spi->cur_comm == SPI_SIMPLEX_TX || spi->cur_comm == SPI_3WIRE_TX) + ier |= STM32H7_SPI_IER_EOTIE | STM32H7_SPI_IER_TXTFIE; + + stm32_spi_set_bits(spi, STM32H7_SPI_IER, ier); stm32_spi_enable(spi); @@ -1645,10 +1602,6 @@ static int stm32_spi_transfer_one(struct spi_master *master, struct stm32_spi *spi = spi_master_get_devdata(master); int ret; - /* Don't do anything on 0 bytes transfers */ - if (transfer->len == 0) - return 0; - spi->tx_buf = transfer->tx_buf; spi->rx_buf = transfer->rx_buf; spi->tx_len = spi->tx_buf ? transfer->len : 0; @@ -1762,7 +1715,7 @@ static const struct stm32_spi_cfg stm32f4_spi_cfg = { .set_mode = stm32f4_spi_set_mode, .transfer_one_dma_start = stm32f4_spi_transfer_one_dma_start, .dma_tx_cb = stm32f4_spi_dma_tx_cb, - .dma_rx_cb = stm32f4_spi_dma_rx_cb, + .dma_rx_cb = stm32_spi_dma_rx_cb, .transfer_one_irq = stm32f4_spi_transfer_one_irq, .irq_handler_event = stm32f4_spi_irq_event, .irq_handler_thread = stm32f4_spi_irq_thread, @@ -1782,8 +1735,11 @@ static const struct stm32_spi_cfg stm32h7_spi_cfg = { .set_data_idleness = stm32h7_spi_data_idleness, .set_number_of_data = stm32h7_spi_number_of_data, .transfer_one_dma_start = stm32h7_spi_transfer_one_dma_start, - .dma_rx_cb = stm32h7_spi_dma_cb, - .dma_tx_cb = stm32h7_spi_dma_cb, + .dma_rx_cb = stm32_spi_dma_rx_cb, + /* + * dma_tx_cb is not necessary since in case of TX, dma is followed by + * SPI access hence handling is performed within the SPI interrupt + */ .transfer_one_irq = stm32h7_spi_transfer_one_irq, .irq_handler_thread = stm32h7_spi_irq_thread, .baud_rate_div_min = STM32H7_SPI_MBR_DIV_MIN, @@ -1927,6 +1883,9 @@ static int stm32_spi_probe(struct platform_device *pdev) if (spi->dma_tx || spi->dma_rx) master->can_dma = stm32_spi_can_dma; + pm_runtime_set_autosuspend_delay(&pdev->dev, + STM32_SPI_AUTOSUSPEND_DELAY); + pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_set_active(&pdev->dev); pm_runtime_get_noresume(&pdev->dev); pm_runtime_enable(&pdev->dev); @@ -1938,6 +1897,9 @@ static int stm32_spi_probe(struct platform_device *pdev) goto err_pm_disable; } + pm_runtime_mark_last_busy(&pdev->dev); + pm_runtime_put_autosuspend(&pdev->dev); + dev_info(&pdev->dev, "driver initialized\n"); return 0; @@ -1946,6 +1908,7 @@ err_pm_disable: pm_runtime_disable(&pdev->dev); pm_runtime_put_noidle(&pdev->dev); pm_runtime_set_suspended(&pdev->dev); + pm_runtime_dont_use_autosuspend(&pdev->dev); err_dma_release: if (spi->dma_tx) dma_release_channel(spi->dma_tx); @@ -1970,6 +1933,8 @@ static int stm32_spi_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); pm_runtime_put_noidle(&pdev->dev); pm_runtime_set_suspended(&pdev->dev); + pm_runtime_dont_use_autosuspend(&pdev->dev); + if (master->dma_tx) dma_release_channel(master->dma_tx); if (master->dma_rx) diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c index 5131141bbf0d..e9de1d958bbd 100644 --- a/drivers/spi/spi-tegra114.c +++ b/drivers/spi/spi-tegra114.c @@ -717,12 +717,12 @@ static void tegra_spi_deinit_dma_param(struct tegra_spi_data *tspi, dma_release_channel(dma_chan); } -static int tegra_spi_set_hw_cs_timing(struct spi_device *spi, - struct spi_delay *setup, - struct spi_delay *hold, - struct spi_delay *inactive) +static int tegra_spi_set_hw_cs_timing(struct spi_device *spi) { struct tegra_spi_data *tspi = spi_master_get_devdata(spi->master); + struct spi_delay *setup = &spi->cs_setup; + struct spi_delay *hold = &spi->cs_hold; + struct spi_delay *inactive = &spi->cs_inactive; u8 setup_dly, hold_dly, inactive_dly; u32 setup_hold; u32 spi_cs_timing; diff --git a/drivers/spi/spi-tegra20-slink.c b/drivers/spi/spi-tegra20-slink.c index 6a726c95ac7a..ebd27f883033 100644 --- a/drivers/spi/spi-tegra20-slink.c +++ b/drivers/spi/spi-tegra20-slink.c @@ -1061,33 +1061,12 @@ static int tegra_slink_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Can not get clock %d\n", ret); goto exit_free_master; } - ret = clk_prepare(tspi->clk); - if (ret < 0) { - dev_err(&pdev->dev, "Clock prepare failed %d\n", ret); - goto exit_free_master; - } - ret = clk_enable(tspi->clk); - if (ret < 0) { - dev_err(&pdev->dev, "Clock enable failed %d\n", ret); - goto exit_clk_unprepare; - } - - spi_irq = platform_get_irq(pdev, 0); - tspi->irq = spi_irq; - ret = request_threaded_irq(tspi->irq, tegra_slink_isr, - tegra_slink_isr_thread, IRQF_ONESHOT, - dev_name(&pdev->dev), tspi); - if (ret < 0) { - dev_err(&pdev->dev, "Failed to register ISR for IRQ %d\n", - tspi->irq); - goto exit_clk_disable; - } tspi->rst = devm_reset_control_get_exclusive(&pdev->dev, "spi"); if (IS_ERR(tspi->rst)) { dev_err(&pdev->dev, "can not get reset\n"); ret = PTR_ERR(tspi->rst); - goto exit_free_irq; + goto exit_free_master; } tspi->max_buf_size = SLINK_FIFO_DEPTH << 2; @@ -1095,7 +1074,7 @@ static int tegra_slink_probe(struct platform_device *pdev) ret = tegra_slink_init_dma_param(tspi, true); if (ret < 0) - goto exit_free_irq; + goto exit_free_master; ret = tegra_slink_init_dma_param(tspi, false); if (ret < 0) goto exit_rx_dma_free; @@ -1106,16 +1085,9 @@ static int tegra_slink_probe(struct platform_device *pdev) init_completion(&tspi->xfer_completion); pm_runtime_enable(&pdev->dev); - if (!pm_runtime_enabled(&pdev->dev)) { - ret = tegra_slink_runtime_resume(&pdev->dev); - if (ret) - goto exit_pm_disable; - } - - ret = pm_runtime_get_sync(&pdev->dev); - if (ret < 0) { + ret = pm_runtime_resume_and_get(&pdev->dev); + if (ret) { dev_err(&pdev->dev, "pm runtime get failed, e = %d\n", ret); - pm_runtime_put_noidle(&pdev->dev); goto exit_pm_disable; } @@ -1123,33 +1095,43 @@ static int tegra_slink_probe(struct platform_device *pdev) udelay(2); reset_control_deassert(tspi->rst); + spi_irq = platform_get_irq(pdev, 0); + tspi->irq = spi_irq; + ret = request_threaded_irq(tspi->irq, tegra_slink_isr, + tegra_slink_isr_thread, IRQF_ONESHOT, + dev_name(&pdev->dev), tspi); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to register ISR for IRQ %d\n", + tspi->irq); + goto exit_pm_put; + } + tspi->def_command_reg = SLINK_M_S; tspi->def_command2_reg = SLINK_CS_ACTIVE_BETWEEN; tegra_slink_writel(tspi, tspi->def_command_reg, SLINK_COMMAND); tegra_slink_writel(tspi, tspi->def_command2_reg, SLINK_COMMAND2); - pm_runtime_put(&pdev->dev); master->dev.of_node = pdev->dev.of_node; - ret = devm_spi_register_master(&pdev->dev, master); + ret = spi_register_master(master); if (ret < 0) { dev_err(&pdev->dev, "can not register to master err %d\n", ret); - goto exit_pm_disable; + goto exit_free_irq; } + + pm_runtime_put(&pdev->dev); + return ret; +exit_free_irq: + free_irq(spi_irq, tspi); +exit_pm_put: + pm_runtime_put(&pdev->dev); exit_pm_disable: pm_runtime_disable(&pdev->dev); - if (!pm_runtime_status_suspended(&pdev->dev)) - tegra_slink_runtime_suspend(&pdev->dev); + tegra_slink_deinit_dma_param(tspi, false); exit_rx_dma_free: tegra_slink_deinit_dma_param(tspi, true); -exit_free_irq: - free_irq(spi_irq, tspi); -exit_clk_disable: - clk_disable(tspi->clk); -exit_clk_unprepare: - clk_unprepare(tspi->clk); exit_free_master: spi_master_put(master); return ret; @@ -1160,10 +1142,11 @@ static int tegra_slink_remove(struct platform_device *pdev) struct spi_master *master = platform_get_drvdata(pdev); struct tegra_slink_data *tspi = spi_master_get_devdata(master); + spi_unregister_master(master); + free_irq(tspi->irq, tspi); - clk_disable(tspi->clk); - clk_unprepare(tspi->clk); + pm_runtime_disable(&pdev->dev); if (tspi->tx_dma_chan) tegra_slink_deinit_dma_param(tspi, false); @@ -1171,10 +1154,6 @@ static int tegra_slink_remove(struct platform_device *pdev) if (tspi->rx_dma_chan) tegra_slink_deinit_dma_param(tspi, true); - pm_runtime_disable(&pdev->dev); - if (!pm_runtime_status_suspended(&pdev->dev)) - tegra_slink_runtime_suspend(&pdev->dev); - return 0; } diff --git a/drivers/spi/spi-zynq-qspi.c b/drivers/spi/spi-zynq-qspi.c index 9262c6418463..cfa222c9bd5e 100644 --- a/drivers/spi/spi-zynq-qspi.c +++ b/drivers/spi/spi-zynq-qspi.c @@ -545,7 +545,7 @@ static int zynq_qspi_exec_mem_op(struct spi_mem *mem, zynq_qspi_write_op(xqspi, ZYNQ_QSPI_FIFO_DEPTH, true); zynq_qspi_write(xqspi, ZYNQ_QSPI_IEN_OFFSET, ZYNQ_QSPI_IXR_RXTX_MASK); - if (!wait_for_completion_interruptible_timeout(&xqspi->data_completion, + if (!wait_for_completion_timeout(&xqspi->data_completion, msecs_to_jiffies(1000))) err = -ETIMEDOUT; } @@ -563,7 +563,7 @@ static int zynq_qspi_exec_mem_op(struct spi_mem *mem, zynq_qspi_write_op(xqspi, ZYNQ_QSPI_FIFO_DEPTH, true); zynq_qspi_write(xqspi, ZYNQ_QSPI_IEN_OFFSET, ZYNQ_QSPI_IXR_RXTX_MASK); - if (!wait_for_completion_interruptible_timeout(&xqspi->data_completion, + if (!wait_for_completion_timeout(&xqspi->data_completion, msecs_to_jiffies(1000))) err = -ETIMEDOUT; } @@ -579,7 +579,7 @@ static int zynq_qspi_exec_mem_op(struct spi_mem *mem, zynq_qspi_write_op(xqspi, ZYNQ_QSPI_FIFO_DEPTH, true); zynq_qspi_write(xqspi, ZYNQ_QSPI_IEN_OFFSET, ZYNQ_QSPI_IXR_RXTX_MASK); - if (!wait_for_completion_interruptible_timeout(&xqspi->data_completion, + if (!wait_for_completion_timeout(&xqspi->data_completion, msecs_to_jiffies(1000))) err = -ETIMEDOUT; @@ -603,7 +603,7 @@ static int zynq_qspi_exec_mem_op(struct spi_mem *mem, zynq_qspi_write_op(xqspi, ZYNQ_QSPI_FIFO_DEPTH, true); zynq_qspi_write(xqspi, ZYNQ_QSPI_IEN_OFFSET, ZYNQ_QSPI_IXR_RXTX_MASK); - if (!wait_for_completion_interruptible_timeout(&xqspi->data_completion, + if (!wait_for_completion_timeout(&xqspi->data_completion, msecs_to_jiffies(1000))) err = -ETIMEDOUT; } diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index e4dc593b1f32..65d14af9c015 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -846,9 +846,9 @@ static void spi_set_cs(struct spi_device *spi, bool enable, bool force) if (spi->cs_gpiod || gpio_is_valid(spi->cs_gpio) || !spi->controller->set_cs_timing) { if (activate) - spi_delay_exec(&spi->controller->cs_setup, NULL); + spi_delay_exec(&spi->cs_setup, NULL); else - spi_delay_exec(&spi->controller->cs_hold, NULL); + spi_delay_exec(&spi->cs_hold, NULL); } if (spi->mode & SPI_CS_HIGH) @@ -891,7 +891,7 @@ static void spi_set_cs(struct spi_device *spi, bool enable, bool force) if (spi->cs_gpiod || gpio_is_valid(spi->cs_gpio) || !spi->controller->set_cs_timing) { if (!activate) - spi_delay_exec(&spi->controller->cs_inactive, NULL); + spi_delay_exec(&spi->cs_inactive, NULL); } } diff --git a/drivers/staging/media/av7110/audio.h b/drivers/staging/media/av7110/audio.h deleted file mode 100644 index 2f869da69171..000000000000 --- a/drivers/staging/media/av7110/audio.h +++ /dev/null @@ -1,101 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1+ WITH Linux-syscall-note */ -/* - * audio.h - DEPRECATED MPEG-TS audio decoder API - * - * NOTE: should not be used on future drivers - * - * Copyright (C) 2000 Ralph Metzler <ralph@convergence.de> - * & Marcus Metzler <marcus@convergence.de> - * for convergence integrated media GmbH - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Lesser Public License - * as published by the Free Software Foundation; either version 2.1 - * of the License, or (at your option) any later version. - * - * 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. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -#ifndef _DVBAUDIO_H_ -#define _DVBAUDIO_H_ - -#include <linux/types.h> - -typedef enum { - AUDIO_SOURCE_DEMUX, /* Select the demux as the main source */ - AUDIO_SOURCE_MEMORY /* Select internal memory as the main source */ -} audio_stream_source_t; - - -typedef enum { - AUDIO_STOPPED, /* Device is stopped */ - AUDIO_PLAYING, /* Device is currently playing */ - AUDIO_PAUSED /* Device is paused */ -} audio_play_state_t; - - -typedef enum { - AUDIO_STEREO, - AUDIO_MONO_LEFT, - AUDIO_MONO_RIGHT, - AUDIO_MONO, - AUDIO_STEREO_SWAPPED -} audio_channel_select_t; - - -typedef struct audio_mixer { - unsigned int volume_left; - unsigned int volume_right; - /* what else do we need? bass, pass-through, ... */ -} audio_mixer_t; - - -typedef struct audio_status { - int AV_sync_state; /* sync audio and video? */ - int mute_state; /* audio is muted */ - audio_play_state_t play_state; /* current playback state */ - audio_stream_source_t stream_source; /* current stream source */ - audio_channel_select_t channel_select; /* currently selected channel */ - int bypass_mode; /* pass on audio data to */ - audio_mixer_t mixer_state; /* current mixer state */ -} audio_status_t; /* separate decoder hardware */ - - -/* for GET_CAPABILITIES and SET_FORMAT, the latter should only set one bit */ -#define AUDIO_CAP_DTS 1 -#define AUDIO_CAP_LPCM 2 -#define AUDIO_CAP_MP1 4 -#define AUDIO_CAP_MP2 8 -#define AUDIO_CAP_MP3 16 -#define AUDIO_CAP_AAC 32 -#define AUDIO_CAP_OGG 64 -#define AUDIO_CAP_SDDS 128 -#define AUDIO_CAP_AC3 256 - -#define AUDIO_STOP _IO('o', 1) -#define AUDIO_PLAY _IO('o', 2) -#define AUDIO_PAUSE _IO('o', 3) -#define AUDIO_CONTINUE _IO('o', 4) -#define AUDIO_SELECT_SOURCE _IO('o', 5) -#define AUDIO_SET_MUTE _IO('o', 6) -#define AUDIO_SET_AV_SYNC _IO('o', 7) -#define AUDIO_SET_BYPASS_MODE _IO('o', 8) -#define AUDIO_CHANNEL_SELECT _IO('o', 9) -#define AUDIO_GET_STATUS _IOR('o', 10, audio_status_t) - -#define AUDIO_GET_CAPABILITIES _IOR('o', 11, unsigned int) -#define AUDIO_CLEAR_BUFFER _IO('o', 12) -#define AUDIO_SET_ID _IO('o', 13) -#define AUDIO_SET_MIXER _IOW('o', 14, audio_mixer_t) -#define AUDIO_SET_STREAMTYPE _IO('o', 15) -#define AUDIO_BILINGUAL_CHANNEL_SELECT _IO('o', 20) - -#endif /* _DVBAUDIO_H_ */ diff --git a/drivers/staging/media/av7110/av7110.h b/drivers/staging/media/av7110/av7110.h index b8e8fc8ddbe9..809d938ae166 100644 --- a/drivers/staging/media/av7110/av7110.h +++ b/drivers/staging/media/av7110/av7110.h @@ -9,12 +9,11 @@ #include <linux/input.h> #include <linux/time.h> -#include "video.h" -#include "audio.h" -#include "osd.h" - +#include <linux/dvb/video.h> +#include <linux/dvb/audio.h> #include <linux/dvb/dmx.h> #include <linux/dvb/ca.h> +#include <linux/dvb/osd.h> #include <linux/dvb/net.h> #include <linux/mutex.h> diff --git a/drivers/staging/media/av7110/osd.h b/drivers/staging/media/av7110/osd.h deleted file mode 100644 index 858997c74043..000000000000 --- a/drivers/staging/media/av7110/osd.h +++ /dev/null @@ -1,181 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1+ WITH Linux-syscall-note */ -/* - * osd.h - DEPRECATED On Screen Display API - * - * NOTE: should not be used on future drivers - * - * Copyright (C) 2001 Ralph Metzler <ralph@convergence.de> - * & Marcus Metzler <marcus@convergence.de> - * for convergence integrated media GmbH - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Lesser Public License - * as published by the Free Software Foundation; either version 2.1 - * of the License, or (at your option) any later version. - * - * 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. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -#ifndef _DVBOSD_H_ -#define _DVBOSD_H_ - -#include <linux/compiler.h> - -typedef enum { - /* All functions return -2 on "not open" */ - OSD_Close = 1, /* () */ - /* - * Disables OSD and releases the buffers - * returns 0 on success - */ - OSD_Open, /* (x0,y0,x1,y1,BitPerPixel[2/4/8](color&0x0F),mix[0..15](color&0xF0)) */ - /* - * Opens OSD with this size and bit depth - * returns 0 on success, -1 on DRAM allocation error, -2 on "already open" - */ - OSD_Show, /* () */ - /* - * enables OSD mode - * returns 0 on success - */ - OSD_Hide, /* () */ - /* - * disables OSD mode - * returns 0 on success - */ - OSD_Clear, /* () */ - /* - * Sets all pixel to color 0 - * returns 0 on success - */ - OSD_Fill, /* (color) */ - /* - * Sets all pixel to color <col> - * returns 0 on success - */ - OSD_SetColor, /* (color,R{x0},G{y0},B{x1},opacity{y1}) */ - /* - * set palette entry <num> to <r,g,b>, <mix> and <trans> apply - * R,G,B: 0..255 - * R=Red, G=Green, B=Blue - * opacity=0: pixel opacity 0% (only video pixel shows) - * opacity=1..254: pixel opacity as specified in header - * opacity=255: pixel opacity 100% (only OSD pixel shows) - * returns 0 on success, -1 on error - */ - OSD_SetPalette, /* (firstcolor{color},lastcolor{x0},data) */ - /* - * Set a number of entries in the palette - * sets the entries "firstcolor" through "lastcolor" from the array "data" - * data has 4 byte for each color: - * R,G,B, and a opacity value: 0->transparent, 1..254->mix, 255->pixel - */ - OSD_SetTrans, /* (transparency{color}) */ - /* - * Sets transparency of mixed pixel (0..15) - * returns 0 on success - */ - OSD_SetPixel, /* (x0,y0,color) */ - /* - * sets pixel <x>,<y> to color number <col> - * returns 0 on success, -1 on error - */ - OSD_GetPixel, /* (x0,y0) */ - /* returns color number of pixel <x>,<y>, or -1 */ - OSD_SetRow, /* (x0,y0,x1,data) */ - /* - * fills pixels x0,y through x1,y with the content of data[] - * returns 0 on success, -1 on clipping all pixel (no pixel drawn) - */ - OSD_SetBlock, /* (x0,y0,x1,y1,increment{color},data) */ - /* - * fills pixels x0,y0 through x1,y1 with the content of data[] - * inc contains the width of one line in the data block, - * inc<=0 uses blockwidth as linewidth - * returns 0 on success, -1 on clipping all pixel - */ - OSD_FillRow, /* (x0,y0,x1,color) */ - /* - * fills pixels x0,y through x1,y with the color <col> - * returns 0 on success, -1 on clipping all pixel - */ - OSD_FillBlock, /* (x0,y0,x1,y1,color) */ - /* - * fills pixels x0,y0 through x1,y1 with the color <col> - * returns 0 on success, -1 on clipping all pixel - */ - OSD_Line, /* (x0,y0,x1,y1,color) */ - /* - * draw a line from x0,y0 to x1,y1 with the color <col> - * returns 0 on success - */ - OSD_Query, /* (x0,y0,x1,y1,xasp{color}}), yasp=11 */ - /* - * fills parameters with the picture dimensions and the pixel aspect ratio - * returns 0 on success - */ - OSD_Test, /* () */ - /* - * draws a test picture. for debugging purposes only - * returns 0 on success - * TODO: remove "test" in final version - */ - OSD_Text, /* (x0,y0,size,color,text) */ - OSD_SetWindow, /* (x0) set window with number 0<x0<8 as current */ - OSD_MoveWindow, /* move current window to (x0, y0) */ - OSD_OpenRaw, /* Open other types of OSD windows */ -} OSD_Command; - -typedef struct osd_cmd_s { - OSD_Command cmd; - int x0; - int y0; - int x1; - int y1; - int color; - void __user *data; -} osd_cmd_t; - -/* OSD_OpenRaw: set 'color' to desired window type */ -typedef enum { - OSD_BITMAP1, /* 1 bit bitmap */ - OSD_BITMAP2, /* 2 bit bitmap */ - OSD_BITMAP4, /* 4 bit bitmap */ - OSD_BITMAP8, /* 8 bit bitmap */ - OSD_BITMAP1HR, /* 1 Bit bitmap half resolution */ - OSD_BITMAP2HR, /* 2 bit bitmap half resolution */ - OSD_BITMAP4HR, /* 4 bit bitmap half resolution */ - OSD_BITMAP8HR, /* 8 bit bitmap half resolution */ - OSD_YCRCB422, /* 4:2:2 YCRCB Graphic Display */ - OSD_YCRCB444, /* 4:4:4 YCRCB Graphic Display */ - OSD_YCRCB444HR, /* 4:4:4 YCRCB graphic half resolution */ - OSD_VIDEOTSIZE, /* True Size Normal MPEG Video Display */ - OSD_VIDEOHSIZE, /* MPEG Video Display Half Resolution */ - OSD_VIDEOQSIZE, /* MPEG Video Display Quarter Resolution */ - OSD_VIDEODSIZE, /* MPEG Video Display Double Resolution */ - OSD_VIDEOTHSIZE, /* True Size MPEG Video Display Half Resolution */ - OSD_VIDEOTQSIZE, /* True Size MPEG Video Display Quarter Resolution*/ - OSD_VIDEOTDSIZE, /* True Size MPEG Video Display Double Resolution */ - OSD_VIDEONSIZE, /* Full Size MPEG Video Display */ - OSD_CURSOR /* Cursor */ -} osd_raw_window_t; - -typedef struct osd_cap_s { - int cmd; -#define OSD_CAP_MEMSIZE 1 /* memory size */ - long val; -} osd_cap_t; - - -#define OSD_SEND_CMD _IOW('o', 160, osd_cmd_t) -#define OSD_GET_CAPABILITY _IOR('o', 161, osd_cap_t) - -#endif diff --git a/drivers/staging/media/av7110/video.h b/drivers/staging/media/av7110/video.h deleted file mode 100644 index 179f1ec60af6..000000000000 --- a/drivers/staging/media/av7110/video.h +++ /dev/null @@ -1,220 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1+ WITH Linux-syscall-note */ -/* - * video.h - DEPRECATED MPEG-TS video decoder API - * - * NOTE: should not be used on future drivers - * - * Copyright (C) 2000 Marcus Metzler <marcus@convergence.de> - * & Ralph Metzler <ralph@convergence.de> - * for convergence integrated media GmbH - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 - * of the License, or (at your option) any later version. - * - * 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. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ - -#ifndef _UAPI_DVBVIDEO_H_ -#define _UAPI_DVBVIDEO_H_ - -#include <linux/types.h> -#ifndef __KERNEL__ -#include <time.h> -#endif - -typedef enum { - VIDEO_FORMAT_4_3, /* Select 4:3 format */ - VIDEO_FORMAT_16_9, /* Select 16:9 format. */ - VIDEO_FORMAT_221_1 /* 2.21:1 */ -} video_format_t; - - -typedef enum { - VIDEO_PAN_SCAN, /* use pan and scan format */ - VIDEO_LETTER_BOX, /* use letterbox format */ - VIDEO_CENTER_CUT_OUT /* use center cut out format */ -} video_displayformat_t; - -typedef struct { - int w; - int h; - video_format_t aspect_ratio; -} video_size_t; - -typedef enum { - VIDEO_SOURCE_DEMUX, /* Select the demux as the main source */ - VIDEO_SOURCE_MEMORY /* If this source is selected, the stream - comes from the user through the write - system call */ -} video_stream_source_t; - - -typedef enum { - VIDEO_STOPPED, /* Video is stopped */ - VIDEO_PLAYING, /* Video is currently playing */ - VIDEO_FREEZED /* Video is freezed */ -} video_play_state_t; - - -/* Decoder commands */ -#define VIDEO_CMD_PLAY (0) -#define VIDEO_CMD_STOP (1) -#define VIDEO_CMD_FREEZE (2) -#define VIDEO_CMD_CONTINUE (3) - -/* Flags for VIDEO_CMD_FREEZE */ -#define VIDEO_CMD_FREEZE_TO_BLACK (1 << 0) - -/* Flags for VIDEO_CMD_STOP */ -#define VIDEO_CMD_STOP_TO_BLACK (1 << 0) -#define VIDEO_CMD_STOP_IMMEDIATELY (1 << 1) - -/* Play input formats: */ -/* The decoder has no special format requirements */ -#define VIDEO_PLAY_FMT_NONE (0) -/* The decoder requires full GOPs */ -#define VIDEO_PLAY_FMT_GOP (1) - -/* The structure must be zeroed before use by the application - This ensures it can be extended safely in the future. */ -struct video_command { - __u32 cmd; - __u32 flags; - union { - struct { - __u64 pts; - } stop; - - struct { - /* 0 or 1000 specifies normal speed, - 1 specifies forward single stepping, - -1 specifies backward single stepping, - >1: playback at speed/1000 of the normal speed, - <-1: reverse playback at (-speed/1000) of the normal speed. */ - __s32 speed; - __u32 format; - } play; - - struct { - __u32 data[16]; - } raw; - }; -}; - -/* FIELD_UNKNOWN can be used if the hardware does not know whether - the Vsync is for an odd, even or progressive (i.e. non-interlaced) - field. */ -#define VIDEO_VSYNC_FIELD_UNKNOWN (0) -#define VIDEO_VSYNC_FIELD_ODD (1) -#define VIDEO_VSYNC_FIELD_EVEN (2) -#define VIDEO_VSYNC_FIELD_PROGRESSIVE (3) - -struct video_event { - __s32 type; -#define VIDEO_EVENT_SIZE_CHANGED 1 -#define VIDEO_EVENT_FRAME_RATE_CHANGED 2 -#define VIDEO_EVENT_DECODER_STOPPED 3 -#define VIDEO_EVENT_VSYNC 4 - /* unused, make sure to use atomic time for y2038 if it ever gets used */ - long timestamp; - union { - video_size_t size; - unsigned int frame_rate; /* in frames per 1000sec */ - unsigned char vsync_field; /* unknown/odd/even/progressive */ - } u; -}; - - -struct video_status { - int video_blank; /* blank video on freeze? */ - video_play_state_t play_state; /* current state of playback */ - video_stream_source_t stream_source; /* current source (demux/memory) */ - video_format_t video_format; /* current aspect ratio of stream*/ - video_displayformat_t display_format;/* selected cropping mode */ -}; - - -struct video_still_picture { - char __user *iFrame; /* pointer to a single iframe in memory */ - __s32 size; -}; - - -typedef __u16 video_attributes_t; -/* bits: descr. */ -/* 15-14 Video compression mode (0=MPEG-1, 1=MPEG-2) */ -/* 13-12 TV system (0=525/60, 1=625/50) */ -/* 11-10 Aspect ratio (0=4:3, 3=16:9) */ -/* 9- 8 permitted display mode on 4:3 monitor (0=both, 1=only pan-sca */ -/* 7 line 21-1 data present in GOP (1=yes, 0=no) */ -/* 6 line 21-2 data present in GOP (1=yes, 0=no) */ -/* 5- 3 source resolution (0=720x480/576, 1=704x480/576, 2=352x480/57 */ -/* 2 source letterboxed (1=yes, 0=no) */ -/* 0 film/camera mode (0= - *camera, 1=film (625/50 only)) */ - - -/* bit definitions for capabilities: */ -/* can the hardware decode MPEG1 and/or MPEG2? */ -#define VIDEO_CAP_MPEG1 1 -#define VIDEO_CAP_MPEG2 2 -/* can you send a system and/or program stream to video device? - (you still have to open the video and the audio device but only - send the stream to the video device) */ -#define VIDEO_CAP_SYS 4 -#define VIDEO_CAP_PROG 8 -/* can the driver also handle SPU, NAVI and CSS encoded data? - (CSS API is not present yet) */ -#define VIDEO_CAP_SPU 16 -#define VIDEO_CAP_NAVI 32 -#define VIDEO_CAP_CSS 64 - - -#define VIDEO_STOP _IO('o', 21) -#define VIDEO_PLAY _IO('o', 22) -#define VIDEO_FREEZE _IO('o', 23) -#define VIDEO_CONTINUE _IO('o', 24) -#define VIDEO_SELECT_SOURCE _IO('o', 25) -#define VIDEO_SET_BLANK _IO('o', 26) -#define VIDEO_GET_STATUS _IOR('o', 27, struct video_status) -#define VIDEO_GET_EVENT _IOR('o', 28, struct video_event) -#define VIDEO_SET_DISPLAY_FORMAT _IO('o', 29) -#define VIDEO_STILLPICTURE _IOW('o', 30, struct video_still_picture) -#define VIDEO_FAST_FORWARD _IO('o', 31) -#define VIDEO_SLOWMOTION _IO('o', 32) -#define VIDEO_GET_CAPABILITIES _IOR('o', 33, unsigned int) -#define VIDEO_CLEAR_BUFFER _IO('o', 34) -#define VIDEO_SET_STREAMTYPE _IO('o', 36) -#define VIDEO_SET_FORMAT _IO('o', 37) -#define VIDEO_GET_SIZE _IOR('o', 55, video_size_t) - -/** - * VIDEO_GET_PTS - * - * Read the 33 bit presentation time stamp as defined - * in ITU T-REC-H.222.0 / ISO/IEC 13818-1. - * - * The PTS should belong to the currently played - * frame if possible, but may also be a value close to it - * like the PTS of the last decoded frame or the last PTS - * extracted by the PES parser. - */ -#define VIDEO_GET_PTS _IOR('o', 57, __u64) - -/* Read the number of displayed frames since the decoder was started */ -#define VIDEO_GET_FRAME_COUNT _IOR('o', 58, __u64) - -#define VIDEO_COMMAND _IOWR('o', 59, struct video_command) -#define VIDEO_TRY_COMMAND _IOWR('o', 60, struct video_command) - -#endif /* _UAPI_DVBVIDEO_H_ */ diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index ef981d3b7bb4..cb72393f92d3 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -2059,7 +2059,7 @@ static void restore_cur(struct vc_data *vc) enum { ESnormal, ESesc, ESsquare, ESgetpars, ESfunckey, EShash, ESsetG0, ESsetG1, ESpercent, EScsiignore, ESnonstd, - ESpalette, ESosc }; + ESpalette, ESosc, ESapc, ESpm, ESdcs }; /* console_lock is held (except via vc_init()) */ static void reset_terminal(struct vc_data *vc, int do_clear) @@ -2133,20 +2133,28 @@ static void vc_setGx(struct vc_data *vc, unsigned int which, int c) vc->vc_translate = set_translate(*charset, vc); } +/* is this state an ANSI control string? */ +static bool ansi_control_string(unsigned int state) +{ + if (state == ESosc || state == ESapc || state == ESpm || state == ESdcs) + return true; + return false; +} + /* console_lock is held */ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c) { /* * Control characters can be used in the _middle_ - * of an escape sequence. + * of an escape sequence, aside from ANSI control strings. */ - if (vc->vc_state == ESosc && c>=8 && c<=13) /* ... except for OSC */ + if (ansi_control_string(vc->vc_state) && c >= 8 && c <= 13) return; switch (c) { case 0: return; case 7: - if (vc->vc_state == ESosc) + if (ansi_control_string(vc->vc_state)) vc->vc_state = ESnormal; else if (vc->vc_bell_duration) kd_mksound(vc->vc_bell_pitch, vc->vc_bell_duration); @@ -2207,6 +2215,12 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c) case ']': vc->vc_state = ESnonstd; return; + case '_': + vc->vc_state = ESapc; + return; + case '^': + vc->vc_state = ESpm; + return; case '%': vc->vc_state = ESpercent; return; @@ -2224,6 +2238,9 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c) if (vc->state.x < VC_TABSTOPS_COUNT) set_bit(vc->state.x, vc->vc_tab_stop); return; + case 'P': + vc->vc_state = ESdcs; + return; case 'Z': respond_ID(tty); return; @@ -2520,8 +2537,14 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c) vc_setGx(vc, 1, c); vc->vc_state = ESnormal; return; + case ESapc: + return; case ESosc: return; + case ESpm: + return; + case ESdcs: + return; default: vc->vc_state = ESnormal; } diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c index 0e0cd9e9e589..3639bb6dc372 100644 --- a/drivers/tty/vt/vt_ioctl.c +++ b/drivers/tty/vt/vt_ioctl.c @@ -246,6 +246,8 @@ int vt_waitactive(int n) * * XXX It should at least call into the driver, fbdev's definitely need to * restore their engine state. --BenH + * + * Called with the console lock held. */ static int vt_kdsetmode(struct vc_data *vc, unsigned long mode) { @@ -262,7 +264,6 @@ static int vt_kdsetmode(struct vc_data *vc, unsigned long mode) return -EINVAL; } - /* FIXME: this needs the console lock extending */ if (vc->vc_mode == mode) return 0; @@ -271,12 +272,10 @@ static int vt_kdsetmode(struct vc_data *vc, unsigned long mode) return 0; /* explicitly blank/unblank the screen if switching modes */ - console_lock(); if (mode == KD_TEXT) do_unblank_screen(1); else do_blank_screen(1); - console_unlock(); return 0; } @@ -378,7 +377,10 @@ static int vt_k_ioctl(struct tty_struct *tty, unsigned int cmd, if (!perm) return -EPERM; - return vt_kdsetmode(vc, arg); + console_lock(); + ret = vt_kdsetmode(vc, arg); + console_unlock(); + return ret; case KDGETMODE: return put_user(vc->vc_mode, (int __user *)arg); diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 84fe57ef5a49..ccb68fe6202e 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -940,19 +940,19 @@ static struct dwc3_trb *dwc3_ep_prev_trb(struct dwc3_ep *dep, u8 index) static u32 dwc3_calc_trbs_left(struct dwc3_ep *dep) { - struct dwc3_trb *tmp; u8 trbs_left; /* - * If enqueue & dequeue are equal than it is either full or empty. - * - * One way to know for sure is if the TRB right before us has HWO bit - * set or not. If it has, then we're definitely full and can't fit any - * more transfers in our ring. + * If the enqueue & dequeue are equal then the TRB ring is either full + * or empty. It's considered full when there are DWC3_TRB_NUM-1 of TRBs + * pending to be processed by the driver. */ if (dep->trb_enqueue == dep->trb_dequeue) { - tmp = dwc3_ep_prev_trb(dep, dep->trb_enqueue); - if (tmp->ctrl & DWC3_TRB_CTRL_HWO) + /* + * If there is any request remained in the started_list at + * this point, that means there is no TRB available. + */ + if (!list_empty(&dep->started_list)) return 0; return DWC3_TRB_NUM - 1; @@ -2243,10 +2243,8 @@ static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on) ret = wait_for_completion_timeout(&dwc->ep0_in_setup, msecs_to_jiffies(DWC3_PULL_UP_TIMEOUT)); - if (ret == 0) { - dev_err(dwc->dev, "timed out waiting for SETUP phase\n"); - return -ETIMEDOUT; - } + if (ret == 0) + dev_warn(dwc->dev, "timed out waiting for SETUP phase\n"); } /* @@ -2458,6 +2456,7 @@ static int __dwc3_gadget_start(struct dwc3 *dwc) /* begin to receive SETUP packets */ dwc->ep0state = EP0_SETUP_PHASE; dwc->link_state = DWC3_LINK_STATE_SS_DIS; + dwc->delayed_status = false; dwc3_ep0_out_start(dwc); dwc3_gadget_enable_irq(dwc); diff --git a/drivers/usb/gadget/function/u_audio.c b/drivers/usb/gadget/function/u_audio.c index 018dd0978995..9e5c950612d0 100644 --- a/drivers/usb/gadget/function/u_audio.c +++ b/drivers/usb/gadget/function/u_audio.c @@ -230,7 +230,13 @@ static void u_audio_iso_fback_complete(struct usb_ep *ep, int status = req->status; /* i/f shutting down */ - if (!prm->fb_ep_enabled || req->status == -ESHUTDOWN) + if (!prm->fb_ep_enabled) { + kfree(req->buf); + usb_ep_free_request(ep, req); + return; + } + + if (req->status == -ESHUTDOWN) return; /* @@ -388,8 +394,6 @@ static inline void free_ep(struct uac_rtd_params *prm, struct usb_ep *ep) if (!prm->ep_enabled) return; - prm->ep_enabled = false; - audio_dev = uac->audio_dev; params = &audio_dev->params; @@ -407,6 +411,8 @@ static inline void free_ep(struct uac_rtd_params *prm, struct usb_ep *ep) } } + prm->ep_enabled = false; + if (usb_ep_disable(ep)) dev_err(uac->card->dev, "%s:%d Error!\n", __func__, __LINE__); } @@ -418,15 +424,16 @@ static inline void free_ep_fback(struct uac_rtd_params *prm, struct usb_ep *ep) if (!prm->fb_ep_enabled) return; - prm->fb_ep_enabled = false; - if (prm->req_fback) { - usb_ep_dequeue(ep, prm->req_fback); - kfree(prm->req_fback->buf); - usb_ep_free_request(ep, prm->req_fback); + if (usb_ep_dequeue(ep, prm->req_fback)) { + kfree(prm->req_fback->buf); + usb_ep_free_request(ep, prm->req_fback); + } prm->req_fback = NULL; } + prm->fb_ep_enabled = false; + if (usb_ep_disable(ep)) dev_err(uac->card->dev, "%s:%d Error!\n", __func__, __LINE__); } diff --git a/drivers/usb/host/xhci-pci-renesas.c b/drivers/usb/host/xhci-pci-renesas.c index 5923844ed821..ef5e91a5542d 100644 --- a/drivers/usb/host/xhci-pci-renesas.c +++ b/drivers/usb/host/xhci-pci-renesas.c @@ -207,7 +207,8 @@ static int renesas_check_rom_state(struct pci_dev *pdev) return 0; case RENESAS_ROM_STATUS_NO_RESULT: /* No result yet */ - return 0; + dev_dbg(&pdev->dev, "Unknown ROM status ...\n"); + return -ENOENT; case RENESAS_ROM_STATUS_ERROR: /* Error State */ default: /* All other states are marked as "Reserved states" */ @@ -224,14 +225,6 @@ static int renesas_fw_check_running(struct pci_dev *pdev) u8 fw_state; int err; - /* Check if device has ROM and loaded, if so skip everything */ - err = renesas_check_rom(pdev); - if (err) { /* we have rom */ - err = renesas_check_rom_state(pdev); - if (!err) - return err; - } - /* * Test if the device is actually needing the firmware. As most * BIOSes will initialize the device for us. If the device is @@ -591,21 +584,39 @@ int renesas_xhci_check_request_fw(struct pci_dev *pdev, (struct xhci_driver_data *)id->driver_data; const char *fw_name = driver_data->firmware; const struct firmware *fw; + bool has_rom; int err; + /* Check if device has ROM and loaded, if so skip everything */ + has_rom = renesas_check_rom(pdev); + if (has_rom) { + err = renesas_check_rom_state(pdev); + if (!err) + return 0; + else if (err != -ENOENT) + has_rom = false; + } + err = renesas_fw_check_running(pdev); /* Continue ahead, if the firmware is already running. */ if (err == 0) return 0; + /* no firmware interface available */ if (err != 1) - return err; + return has_rom ? 0 : err; pci_dev_get(pdev); - err = request_firmware(&fw, fw_name, &pdev->dev); + err = firmware_request_nowarn(&fw, fw_name, &pdev->dev); pci_dev_put(pdev); if (err) { - dev_err(&pdev->dev, "request_firmware failed: %d\n", err); + if (has_rom) { + dev_info(&pdev->dev, "failed to load firmware %s, fallback to ROM\n", + fw_name); + return 0; + } + dev_err(&pdev->dev, "failed to load firmware %s: %d\n", + fw_name, err); return err; } diff --git a/drivers/usb/serial/ch341.c b/drivers/usb/serial/ch341.c index 8a521b5ea769..2db917eab799 100644 --- a/drivers/usb/serial/ch341.c +++ b/drivers/usb/serial/ch341.c @@ -851,7 +851,6 @@ static struct usb_serial_driver ch341_device = { .owner = THIS_MODULE, .name = "ch341-uart", }, - .bulk_in_size = 512, .id_table = id_table, .num_ports = 1, .open = ch341_open, diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 039450069ca4..29c765cc8495 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -2074,6 +2074,8 @@ static const struct usb_device_id option_ids[] = { .driver_info = RSVD(4) | RSVD(5) }, { USB_DEVICE_INTERFACE_CLASS(0x2cb7, 0x0105, 0xff), /* Fibocom NL678 series */ .driver_info = RSVD(6) }, + { USB_DEVICE_AND_INTERFACE_INFO(0x2cb7, 0x010b, 0xff, 0xff, 0x30) }, /* Fibocom FG150 Diag */ + { USB_DEVICE_AND_INTERFACE_INFO(0x2cb7, 0x010b, 0xff, 0, 0) }, /* Fibocom FG150 AT */ { USB_DEVICE_INTERFACE_CLASS(0x2cb7, 0x01a0, 0xff) }, /* Fibocom NL668-AM/NL652-EU (laptop MBIM) */ { USB_DEVICE_INTERFACE_CLASS(0x2df3, 0x9d03, 0xff) }, /* LongSung M5710 */ { USB_DEVICE_INTERFACE_CLASS(0x305a, 0x1404, 0xff) }, /* GosunCn GM500 RNDIS */ diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c index b9bb63d749ec..5d05de666597 100644 --- a/drivers/usb/typec/tcpm/tcpm.c +++ b/drivers/usb/typec/tcpm/tcpm.c @@ -341,6 +341,7 @@ struct tcpm_port { bool vbus_source; bool vbus_charge; + /* Set to true when Discover_Identity Command is expected to be sent in Ready states. */ bool send_discover; bool op_vsafe5v; @@ -370,6 +371,7 @@ struct tcpm_port { struct hrtimer send_discover_timer; struct kthread_work send_discover_work; bool state_machine_running; + /* Set to true when VDM State Machine has following actions. */ bool vdm_sm_running; struct completion tx_complete; @@ -1431,6 +1433,7 @@ static void tcpm_queue_vdm(struct tcpm_port *port, const u32 header, /* Set ready, vdm state machine will actually send */ port->vdm_retries = 0; port->vdm_state = VDM_STATE_READY; + port->vdm_sm_running = true; mod_vdm_delayed_work(port, 0); } @@ -1673,7 +1676,6 @@ static int tcpm_pd_svdm(struct tcpm_port *port, struct typec_altmode *adev, rlen = 1; } else { tcpm_register_partner_altmodes(port); - port->vdm_sm_running = false; } break; case CMD_ENTER_MODE: @@ -1721,14 +1723,12 @@ static int tcpm_pd_svdm(struct tcpm_port *port, struct typec_altmode *adev, (VDO_SVDM_VERS(svdm_version)); break; } - port->vdm_sm_running = false; break; default: response[0] = p[0] | VDO_CMDT(CMDT_RSP_NAK); rlen = 1; response[0] = (response[0] & ~VDO_SVDM_VERS_MASK) | (VDO_SVDM_VERS(svdm_version)); - port->vdm_sm_running = false; break; } @@ -1737,6 +1737,10 @@ static int tcpm_pd_svdm(struct tcpm_port *port, struct typec_altmode *adev, return rlen; } +static void tcpm_pd_handle_msg(struct tcpm_port *port, + enum pd_msg_request message, + enum tcpm_ams ams); + static void tcpm_handle_vdm_request(struct tcpm_port *port, const __le32 *payload, int cnt) { @@ -1764,11 +1768,25 @@ static void tcpm_handle_vdm_request(struct tcpm_port *port, port->vdm_state = VDM_STATE_DONE; } - if (PD_VDO_SVDM(p[0])) { + if (PD_VDO_SVDM(p[0]) && (adev || tcpm_vdm_ams(port) || port->nr_snk_vdo)) { + /* + * Here a SVDM is received (INIT or RSP or unknown). Set the vdm_sm_running in + * advance because we are dropping the lock but may send VDMs soon. + * For the cases of INIT received: + * - If no response to send, it will be cleared later in this function. + * - If there are responses to send, it will be cleared in the state machine. + * For the cases of RSP received: + * - If no further INIT to send, it will be cleared later in this function. + * - Otherwise, it will be cleared in the state machine if timeout or it will go + * back here until no further INIT to send. + * For the cases of unknown type received: + * - We will send NAK and the flag will be cleared in the state machine. + */ + port->vdm_sm_running = true; rlen = tcpm_pd_svdm(port, adev, p, cnt, response, &adev_action); } else { if (port->negotiated_rev >= PD_REV30) - tcpm_queue_message(port, PD_MSG_CTRL_NOT_SUPP); + tcpm_pd_handle_msg(port, PD_MSG_CTRL_NOT_SUPP, NONE_AMS); } /* @@ -1833,6 +1851,8 @@ static void tcpm_handle_vdm_request(struct tcpm_port *port, if (rlen > 0) tcpm_queue_vdm(port, response[0], &response[1], rlen - 1); + else + port->vdm_sm_running = false; } static void tcpm_send_vdm(struct tcpm_port *port, u32 vid, int cmd, @@ -1898,8 +1918,10 @@ static void vdm_run_state_machine(struct tcpm_port *port) * if there's traffic or we're not in PDO ready state don't send * a VDM. */ - if (port->state != SRC_READY && port->state != SNK_READY) + if (port->state != SRC_READY && port->state != SNK_READY) { + port->vdm_sm_running = false; break; + } /* TODO: AMS operation for Unstructured VDM */ if (PD_VDO_SVDM(vdo_hdr) && PD_VDO_CMDT(vdo_hdr) == CMDT_INIT) { @@ -2471,10 +2493,7 @@ static void tcpm_pd_data_request(struct tcpm_port *port, NONE_AMS); break; case PD_DATA_VENDOR_DEF: - if (tcpm_vdm_ams(port) || port->nr_snk_vdo) - tcpm_handle_vdm_request(port, msg->payload, cnt); - else if (port->negotiated_rev > PD_REV20) - tcpm_pd_handle_msg(port, PD_MSG_CTRL_NOT_SUPP, NONE_AMS); + tcpm_handle_vdm_request(port, msg->payload, cnt); break; case PD_DATA_BIST: port->bist_request = le32_to_cpu(msg->payload[0]); @@ -2555,10 +2574,6 @@ static void tcpm_pd_ctrl_request(struct tcpm_port *port, TYPEC_PWR_MODE_PD, port->pps_data.active, port->supply_voltage); - /* Set VDM running flag ASAP */ - if (port->data_role == TYPEC_HOST && - port->send_discover) - port->vdm_sm_running = true; tcpm_set_state(port, SNK_READY, 0); } else { /* @@ -2596,14 +2611,10 @@ static void tcpm_pd_ctrl_request(struct tcpm_port *port, switch (port->state) { case SNK_NEGOTIATE_CAPABILITIES: /* USB PD specification, Figure 8-43 */ - if (port->explicit_contract) { + if (port->explicit_contract) next_state = SNK_READY; - if (port->data_role == TYPEC_HOST && - port->send_discover) - port->vdm_sm_running = true; - } else { + else next_state = SNK_WAIT_CAPABILITIES; - } /* Threshold was relaxed before sending Request. Restore it back. */ tcpm_set_auto_vbus_discharge_threshold(port, TYPEC_PWR_MODE_PD, @@ -2618,10 +2629,6 @@ static void tcpm_pd_ctrl_request(struct tcpm_port *port, port->pps_status = (type == PD_CTRL_WAIT ? -EAGAIN : -EOPNOTSUPP); - if (port->data_role == TYPEC_HOST && - port->send_discover) - port->vdm_sm_running = true; - /* Threshold was relaxed before sending Request. Restore it back. */ tcpm_set_auto_vbus_discharge_threshold(port, TYPEC_PWR_MODE_PD, port->pps_data.active, @@ -2697,10 +2704,6 @@ static void tcpm_pd_ctrl_request(struct tcpm_port *port, } break; case DR_SWAP_SEND: - if (port->data_role == TYPEC_DEVICE && - port->send_discover) - port->vdm_sm_running = true; - tcpm_set_state(port, DR_SWAP_CHANGE_DR, 0); break; case PR_SWAP_SEND: @@ -2738,7 +2741,7 @@ static void tcpm_pd_ctrl_request(struct tcpm_port *port, PD_MSG_CTRL_NOT_SUPP, NONE_AMS); } else { - if (port->vdm_sm_running) { + if (port->send_discover) { tcpm_queue_message(port, PD_MSG_CTRL_WAIT); break; } @@ -2754,7 +2757,7 @@ static void tcpm_pd_ctrl_request(struct tcpm_port *port, PD_MSG_CTRL_NOT_SUPP, NONE_AMS); } else { - if (port->vdm_sm_running) { + if (port->send_discover) { tcpm_queue_message(port, PD_MSG_CTRL_WAIT); break; } @@ -2763,7 +2766,7 @@ static void tcpm_pd_ctrl_request(struct tcpm_port *port, } break; case PD_CTRL_VCONN_SWAP: - if (port->vdm_sm_running) { + if (port->send_discover) { tcpm_queue_message(port, PD_MSG_CTRL_WAIT); break; } @@ -4479,18 +4482,20 @@ static void run_state_machine(struct tcpm_port *port) /* DR_Swap states */ case DR_SWAP_SEND: tcpm_pd_send_control(port, PD_CTRL_DR_SWAP); + if (port->data_role == TYPEC_DEVICE || port->negotiated_rev > PD_REV20) + port->send_discover = true; tcpm_set_state_cond(port, DR_SWAP_SEND_TIMEOUT, PD_T_SENDER_RESPONSE); break; case DR_SWAP_ACCEPT: tcpm_pd_send_control(port, PD_CTRL_ACCEPT); - /* Set VDM state machine running flag ASAP */ - if (port->data_role == TYPEC_DEVICE && port->send_discover) - port->vdm_sm_running = true; + if (port->data_role == TYPEC_DEVICE || port->negotiated_rev > PD_REV20) + port->send_discover = true; tcpm_set_state_cond(port, DR_SWAP_CHANGE_DR, 0); break; case DR_SWAP_SEND_TIMEOUT: tcpm_swap_complete(port, -ETIMEDOUT); + port->send_discover = false; tcpm_ams_finish(port); tcpm_set_state(port, ready_state(port), 0); break; @@ -4502,7 +4507,6 @@ static void run_state_machine(struct tcpm_port *port) } else { tcpm_set_roles(port, true, port->pwr_role, TYPEC_HOST); - port->send_discover = true; } tcpm_ams_finish(port); tcpm_set_state(port, ready_state(port), 0); @@ -4645,8 +4649,6 @@ static void run_state_machine(struct tcpm_port *port) break; case VCONN_SWAP_SEND_TIMEOUT: tcpm_swap_complete(port, -ETIMEDOUT); - if (port->data_role == TYPEC_HOST && port->send_discover) - port->vdm_sm_running = true; tcpm_set_state(port, ready_state(port), 0); break; case VCONN_SWAP_START: @@ -4662,14 +4664,10 @@ static void run_state_machine(struct tcpm_port *port) case VCONN_SWAP_TURN_ON_VCONN: tcpm_set_vconn(port, true); tcpm_pd_send_control(port, PD_CTRL_PS_RDY); - if (port->data_role == TYPEC_HOST && port->send_discover) - port->vdm_sm_running = true; tcpm_set_state(port, ready_state(port), 0); break; case VCONN_SWAP_TURN_OFF_VCONN: tcpm_set_vconn(port, false); - if (port->data_role == TYPEC_HOST && port->send_discover) - port->vdm_sm_running = true; tcpm_set_state(port, ready_state(port), 0); break; @@ -4677,8 +4675,6 @@ static void run_state_machine(struct tcpm_port *port) case PR_SWAP_CANCEL: case VCONN_SWAP_CANCEL: tcpm_swap_complete(port, port->swap_status); - if (port->data_role == TYPEC_HOST && port->send_discover) - port->vdm_sm_running = true; if (port->pwr_role == TYPEC_SOURCE) tcpm_set_state(port, SRC_READY, 0); else @@ -5028,9 +5024,6 @@ static void _tcpm_pd_vbus_on(struct tcpm_port *port) switch (port->state) { case SNK_TRANSITION_SINK_VBUS: port->explicit_contract = true; - /* Set the VDM flag ASAP */ - if (port->data_role == TYPEC_HOST && port->send_discover) - port->vdm_sm_running = true; tcpm_set_state(port, SNK_READY, 0); break; case SNK_DISCOVERY: @@ -5425,15 +5418,18 @@ static void tcpm_send_discover_work(struct kthread_work *work) if (!port->send_discover) goto unlock; + if (port->data_role == TYPEC_DEVICE && port->negotiated_rev < PD_REV30) { + port->send_discover = false; + goto unlock; + } + /* Retry if the port is not idle */ if ((port->state != SRC_READY && port->state != SNK_READY) || port->vdm_sm_running) { mod_send_discover_delayed_work(port, SEND_DISCOVER_RETRY_MS); goto unlock; } - /* Only send the Message if the port is host for PD rev2.0 */ - if (port->data_role == TYPEC_HOST || port->negotiated_rev > PD_REV20) - tcpm_send_vdm(port, USB_SID_PD, CMD_DISCOVER_IDENT, NULL, 0); + tcpm_send_vdm(port, USB_SID_PD, CMD_DISCOVER_IDENT, NULL, 0); unlock: mutex_unlock(&port->lock); diff --git a/drivers/vdpa/ifcvf/ifcvf_main.c b/drivers/vdpa/ifcvf/ifcvf_main.c index 21b78f1cd521..351c6cfb24c3 100644 --- a/drivers/vdpa/ifcvf/ifcvf_main.c +++ b/drivers/vdpa/ifcvf/ifcvf_main.c @@ -493,9 +493,9 @@ static int ifcvf_probe(struct pci_dev *pdev, const struct pci_device_id *id) adapter = vdpa_alloc_device(struct ifcvf_adapter, vdpa, dev, &ifc_vdpa_ops, NULL); - if (adapter == NULL) { + if (IS_ERR(adapter)) { IFCVF_ERR(pdev, "Failed to allocate vDPA structure"); - return -ENOMEM; + return PTR_ERR(adapter); } pci_set_master(pdev); diff --git a/drivers/vdpa/mlx5/core/mr.c b/drivers/vdpa/mlx5/core/mr.c index dcee6039e966..e59135fa867e 100644 --- a/drivers/vdpa/mlx5/core/mr.c +++ b/drivers/vdpa/mlx5/core/mr.c @@ -512,11 +512,6 @@ out: mutex_unlock(&mr->mkey_mtx); } -static bool map_empty(struct vhost_iotlb *iotlb) -{ - return !vhost_iotlb_itree_first(iotlb, 0, U64_MAX); -} - int mlx5_vdpa_handle_set_map(struct mlx5_vdpa_dev *mvdev, struct vhost_iotlb *iotlb, bool *change_map) { @@ -524,10 +519,6 @@ int mlx5_vdpa_handle_set_map(struct mlx5_vdpa_dev *mvdev, struct vhost_iotlb *io int err = 0; *change_map = false; - if (map_empty(iotlb)) { - mlx5_vdpa_destroy_mr(mvdev); - return 0; - } mutex_lock(&mr->mkey_mtx); if (mr->initialized) { mlx5_vdpa_info(mvdev, "memory map update\n"); diff --git a/drivers/vdpa/mlx5/net/mlx5_vnet.c b/drivers/vdpa/mlx5/net/mlx5_vnet.c index 379a19144a25..3cc12fcab08d 100644 --- a/drivers/vdpa/mlx5/net/mlx5_vnet.c +++ b/drivers/vdpa/mlx5/net/mlx5_vnet.c @@ -752,12 +752,12 @@ static int get_queue_type(struct mlx5_vdpa_net *ndev) type_mask = MLX5_CAP_DEV_VDPA_EMULATION(ndev->mvdev.mdev, virtio_queue_type); /* prefer split queue */ - if (type_mask & MLX5_VIRTIO_EMULATION_CAP_VIRTIO_QUEUE_TYPE_PACKED) - return MLX5_VIRTIO_EMULATION_VIRTIO_QUEUE_TYPE_PACKED; + if (type_mask & MLX5_VIRTIO_EMULATION_CAP_VIRTIO_QUEUE_TYPE_SPLIT) + return MLX5_VIRTIO_EMULATION_VIRTIO_QUEUE_TYPE_SPLIT; - WARN_ON(!(type_mask & MLX5_VIRTIO_EMULATION_CAP_VIRTIO_QUEUE_TYPE_SPLIT)); + WARN_ON(!(type_mask & MLX5_VIRTIO_EMULATION_CAP_VIRTIO_QUEUE_TYPE_PACKED)); - return MLX5_VIRTIO_EMULATION_VIRTIO_QUEUE_TYPE_SPLIT; + return MLX5_VIRTIO_EMULATION_VIRTIO_QUEUE_TYPE_PACKED; } static bool vq_is_tx(u16 idx) @@ -2029,6 +2029,12 @@ static int mlx5_vdpa_dev_add(struct vdpa_mgmt_dev *v_mdev, const char *name) return -ENOSPC; mdev = mgtdev->madev->mdev; + if (!(MLX5_CAP_DEV_VDPA_EMULATION(mdev, virtio_queue_type) & + MLX5_VIRTIO_EMULATION_CAP_VIRTIO_QUEUE_TYPE_SPLIT)) { + dev_warn(mdev->device, "missing support for split virtqueues\n"); + return -EOPNOTSUPP; + } + /* we save one virtqueue for control virtqueue should we require it */ max_vqs = MLX5_CAP_DEV_VDPA_EMULATION(mdev, max_num_virtio_queues); max_vqs = min_t(u32, max_vqs, MLX5_MAX_SUPPORTED_VQS); diff --git a/drivers/vdpa/vdpa_sim/vdpa_sim.c b/drivers/vdpa/vdpa_sim/vdpa_sim.c index 14e024de5cbf..c621cf7feec0 100644 --- a/drivers/vdpa/vdpa_sim/vdpa_sim.c +++ b/drivers/vdpa/vdpa_sim/vdpa_sim.c @@ -251,8 +251,10 @@ struct vdpasim *vdpasim_create(struct vdpasim_dev_attr *dev_attr) vdpasim = vdpa_alloc_device(struct vdpasim, vdpa, NULL, ops, dev_attr->name); - if (!vdpasim) + if (IS_ERR(vdpasim)) { + ret = PTR_ERR(vdpasim); goto err_alloc; + } vdpasim->dev_attr = *dev_attr; INIT_WORK(&vdpasim->work, dev_attr->work_fn); diff --git a/drivers/vdpa/virtio_pci/vp_vdpa.c b/drivers/vdpa/virtio_pci/vp_vdpa.c index 7b4a6396c553..fe0527329857 100644 --- a/drivers/vdpa/virtio_pci/vp_vdpa.c +++ b/drivers/vdpa/virtio_pci/vp_vdpa.c @@ -436,9 +436,9 @@ static int vp_vdpa_probe(struct pci_dev *pdev, const struct pci_device_id *id) vp_vdpa = vdpa_alloc_device(struct vp_vdpa, vdpa, dev, &vp_vdpa_ops, NULL); - if (vp_vdpa == NULL) { + if (IS_ERR(vp_vdpa)) { dev_err(dev, "vp_vdpa: Failed to allocate vDPA structure\n"); - return -ENOMEM; + return PTR_ERR(vp_vdpa); } mdev = &vp_vdpa->mdev; diff --git a/drivers/vhost/vdpa.c b/drivers/vhost/vdpa.c index 210ab35a7ebf..9479f7f79217 100644 --- a/drivers/vhost/vdpa.c +++ b/drivers/vhost/vdpa.c @@ -614,7 +614,8 @@ static int vhost_vdpa_process_iotlb_update(struct vhost_vdpa *v, long pinned; int ret = 0; - if (msg->iova < v->range.first || + if (msg->iova < v->range.first || !msg->size || + msg->iova > U64_MAX - msg->size + 1 || msg->iova + msg->size - 1 > v->range.last) return -EINVAL; diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index b9e853e6094d..59edb5a1ffe2 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -735,10 +735,16 @@ static bool log_access_ok(void __user *log_base, u64 addr, unsigned long sz) (sz + VHOST_PAGE_SIZE * 8 - 1) / VHOST_PAGE_SIZE / 8); } +/* Make sure 64 bit math will not overflow. */ static bool vhost_overflow(u64 uaddr, u64 size) { - /* Make sure 64 bit math will not overflow. */ - return uaddr > ULONG_MAX || size > ULONG_MAX || uaddr > ULONG_MAX - size; + if (uaddr > ULONG_MAX || size > ULONG_MAX) + return true; + + if (!size) + return false; + + return uaddr > ULONG_MAX - size + 1; } /* Caller should have vq mutex and device mutex. */ diff --git a/drivers/vhost/vringh.c b/drivers/vhost/vringh.c index 4af8fa259d65..14e2043d7685 100644 --- a/drivers/vhost/vringh.c +++ b/drivers/vhost/vringh.c @@ -359,7 +359,7 @@ __vringh_iov(struct vringh *vrh, u16 i, iov = wiov; else { iov = riov; - if (unlikely(wiov && wiov->i)) { + if (unlikely(wiov && wiov->used)) { vringh_bad("Readable desc %p after writable", &descs[i]); err = -EINVAL; diff --git a/drivers/virtio/virtio.c b/drivers/virtio/virtio.c index 4b15c00c0a0a..49984d2cba24 100644 --- a/drivers/virtio/virtio.c +++ b/drivers/virtio/virtio.c @@ -355,6 +355,7 @@ int register_virtio_device(struct virtio_device *dev) virtio_add_status(dev, VIRTIO_CONFIG_S_ACKNOWLEDGE); INIT_LIST_HEAD(&dev->vqs); + spin_lock_init(&dev->vqs_list_lock); /* * device_add() causes the bus infrastructure to look for a matching diff --git a/drivers/virtio/virtio_mem.c b/drivers/virtio/virtio_mem.c index 09ed55de07d7..b91bc810a87e 100644 --- a/drivers/virtio/virtio_mem.c +++ b/drivers/virtio/virtio_mem.c @@ -1242,12 +1242,19 @@ static void virtio_mem_online_page_cb(struct page *page, unsigned int order) do_online = virtio_mem_bbm_get_bb_state(vm, id) != VIRTIO_MEM_BBM_BB_FAKE_OFFLINE; } + + /* + * virtio_mem_set_fake_offline() might sleep, we don't need + * the device anymore. See virtio_mem_remove() how races + * between memory onlining and device removal are handled. + */ + rcu_read_unlock(); + if (do_online) generic_online_page(page, order); else virtio_mem_set_fake_offline(PFN_DOWN(addr), 1 << order, false); - rcu_read_unlock(); return; } rcu_read_unlock(); diff --git a/drivers/virtio/virtio_pci_common.c b/drivers/virtio/virtio_pci_common.c index 222d630c41fc..b35bb2d57f62 100644 --- a/drivers/virtio/virtio_pci_common.c +++ b/drivers/virtio/virtio_pci_common.c @@ -576,6 +576,13 @@ static void virtio_pci_remove(struct pci_dev *pci_dev) struct virtio_pci_device *vp_dev = pci_get_drvdata(pci_dev); struct device *dev = get_device(&vp_dev->vdev.dev); + /* + * Device is marked broken on surprise removal so that virtio upper + * layers can abort any ongoing operation. + */ + if (!pci_device_is_present(pci_dev)) + virtio_break_device(&vp_dev->vdev); + pci_disable_sriov(pci_dev); unregister_virtio_device(&vp_dev->vdev); diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c index 89bfe46a8a7f..dd95dfd85e98 100644 --- a/drivers/virtio/virtio_ring.c +++ b/drivers/virtio/virtio_ring.c @@ -11,6 +11,7 @@ #include <linux/module.h> #include <linux/hrtimer.h> #include <linux/dma-mapping.h> +#include <linux/spinlock.h> #include <xen/xen.h> #ifdef DEBUG @@ -1755,7 +1756,9 @@ static struct virtqueue *vring_create_virtqueue_packed( cpu_to_le16(vq->packed.event_flags_shadow); } + spin_lock(&vdev->vqs_list_lock); list_add_tail(&vq->vq.list, &vdev->vqs); + spin_unlock(&vdev->vqs_list_lock); return &vq->vq; err_desc_extra: @@ -2229,7 +2232,9 @@ struct virtqueue *__vring_new_virtqueue(unsigned int index, memset(vq->split.desc_state, 0, vring.num * sizeof(struct vring_desc_state_split)); + spin_lock(&vdev->vqs_list_lock); list_add_tail(&vq->vq.list, &vdev->vqs); + spin_unlock(&vdev->vqs_list_lock); return &vq->vq; err_extra: @@ -2291,6 +2296,10 @@ void vring_del_virtqueue(struct virtqueue *_vq) { struct vring_virtqueue *vq = to_vvq(_vq); + spin_lock(&vq->vq.vdev->vqs_list_lock); + list_del(&_vq->list); + spin_unlock(&vq->vq.vdev->vqs_list_lock); + if (vq->we_own_ring) { if (vq->packed_ring) { vring_free_queue(vq->vq.vdev, @@ -2321,7 +2330,6 @@ void vring_del_virtqueue(struct virtqueue *_vq) kfree(vq->split.desc_state); kfree(vq->split.desc_extra); } - list_del(&_vq->list); kfree(vq); } EXPORT_SYMBOL_GPL(vring_del_virtqueue); @@ -2373,7 +2381,7 @@ bool virtqueue_is_broken(struct virtqueue *_vq) { struct vring_virtqueue *vq = to_vvq(_vq); - return vq->broken; + return READ_ONCE(vq->broken); } EXPORT_SYMBOL_GPL(virtqueue_is_broken); @@ -2385,10 +2393,14 @@ void virtio_break_device(struct virtio_device *dev) { struct virtqueue *_vq; + spin_lock(&dev->vqs_list_lock); list_for_each_entry(_vq, &dev->vqs, list) { struct vring_virtqueue *vq = to_vvq(_vq); - vq->broken = true; + + /* Pairs with READ_ONCE() in virtqueue_is_broken(). */ + WRITE_ONCE(vq->broken, true); } + spin_unlock(&dev->vqs_list_lock); } EXPORT_SYMBOL_GPL(virtio_break_device); diff --git a/drivers/virtio/virtio_vdpa.c b/drivers/virtio/virtio_vdpa.c index e1a141135992..72eaef2caeb1 100644 --- a/drivers/virtio/virtio_vdpa.c +++ b/drivers/virtio/virtio_vdpa.c @@ -151,6 +151,9 @@ virtio_vdpa_setup_vq(struct virtio_device *vdev, unsigned int index, if (!name) return NULL; + if (index >= vdpa->nvqs) + return ERR_PTR(-ENOENT); + /* Queue shouldn't already be set up. */ if (ops->get_vq_ready(vdpa, index)) return ERR_PTR(-ENOENT); |