summaryrefslogtreecommitdiff
path: root/drivers/misc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/misc')
-rw-r--r--drivers/misc/Kconfig22
-rw-r--r--drivers/misc/Makefile2
-rw-r--r--drivers/misc/bcm-vk/bcm_vk_tty.c8
-rw-r--r--drivers/misc/eeprom/at24.c17
-rw-r--r--drivers/misc/gehc-achc.c565
-rw-r--r--drivers/misc/hi6421v600-irq.c307
-rw-r--r--drivers/misc/lkdtm/bugs.c51
-rw-r--r--drivers/misc/lkdtm/core.c8
-rw-r--r--drivers/misc/lkdtm/fortify.c53
-rw-r--r--drivers/misc/lkdtm/heap.c9
-rw-r--r--drivers/misc/lkdtm/lkdtm.h24
-rw-r--r--drivers/misc/mei/bus.c22
-rw-r--r--drivers/misc/mei/client.h2
-rw-r--r--drivers/misc/mei/mei_dev.h2
-rw-r--r--drivers/misc/pci_endpoint_test.c1
-rw-r--r--drivers/misc/pvpanic/pvpanic-pci.c2
-rw-r--r--drivers/misc/pvpanic/pvpanic.c2
-rw-r--r--drivers/misc/sgi-gru/grumain.c6
-rw-r--r--drivers/misc/sgi-gru/grutables.h3
-rw-r--r--drivers/misc/sgi-xp/xpc_uv.c8
-rw-r--r--drivers/misc/sram.c103
-rw-r--r--drivers/misc/sram.h9
-rw-r--r--drivers/misc/tifm_core.c3
-rw-r--r--drivers/misc/vmw_vmci/vmci_queue_pair.c6
24 files changed, 1099 insertions, 136 deletions
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index f4fb5c52b863..85ba901bc11b 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -208,6 +208,28 @@ config CS5535_CLOCK_EVENT_SRC
MFGPTs have a better resolution and max interval than the
generic PIT, and are suitable for use as high-res timers.
+config GEHC_ACHC
+ tristate "GEHC ACHC support"
+ depends on SPI && SYSFS
+ depends on SOC_IMX53 || COMPILE_TEST
+ select FW_LOADER
+ help
+ Support for GE ACHC microcontroller, that is part of the GE
+ PPD device.
+
+ To compile this driver as a module, choose M here: the
+ module will be called gehc-achc.
+
+config HI6421V600_IRQ
+ tristate "HiSilicon Hi6421v600 IRQ and powerkey"
+ depends on OF
+ depends on SPMI
+ select MFD_CORE
+ select REGMAP_SPMI
+ help
+ This driver provides IRQ handling for Hi6421v600, used on
+ some Kirin chipsets, like the one at Hikey 970.
+
config HP_ILO
tristate "Channel interface driver for the HP iLO processor"
depends on PCI
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index e92a56d4442f..a086197af544 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -24,6 +24,7 @@ obj-$(CONFIG_KGDB_TESTS) += kgdbts.o
obj-$(CONFIG_SGI_XP) += sgi-xp/
obj-$(CONFIG_SGI_GRU) += sgi-gru/
obj-$(CONFIG_CS5535_MFGPT) += cs5535-mfgpt.o
+obj-$(CONFIG_GEHC_ACHC) += gehc-achc.o
obj-$(CONFIG_HP_ILO) += hpilo.o
obj-$(CONFIG_APDS9802ALS) += apds9802als.o
obj-$(CONFIG_ISL29003) += isl29003.o
@@ -57,3 +58,4 @@ obj-$(CONFIG_HABANA_AI) += habanalabs/
obj-$(CONFIG_UACCE) += uacce/
obj-$(CONFIG_XILINX_SDFEC) += xilinx_sdfec.o
obj-$(CONFIG_HISI_HIKEY_USB) += hisi_hikey_usb.o
+obj-$(CONFIG_HI6421V600_IRQ) += hi6421v600-irq.o
diff --git a/drivers/misc/bcm-vk/bcm_vk_tty.c b/drivers/misc/bcm-vk/bcm_vk_tty.c
index dae9eeed84a2..1b6076a89ca6 100644
--- a/drivers/misc/bcm-vk/bcm_vk_tty.c
+++ b/drivers/misc/bcm-vk/bcm_vk_tty.c
@@ -249,7 +249,7 @@ int bcm_vk_tty_init(struct bcm_vk *vk, char *name)
tty_drv->name = kstrdup(name, GFP_KERNEL);
if (!tty_drv->name) {
err = -ENOMEM;
- goto err_put_tty_driver;
+ goto err_tty_driver_kref_put;
}
tty_drv->type = TTY_DRIVER_TYPE_SERIAL;
tty_drv->subtype = SERIAL_TYPE_NORMAL;
@@ -295,8 +295,8 @@ err_kfree_tty_name:
kfree(tty_drv->name);
tty_drv->name = NULL;
-err_put_tty_driver:
- put_tty_driver(tty_drv);
+err_tty_driver_kref_put:
+ tty_driver_kref_put(tty_drv);
return err;
}
@@ -317,7 +317,7 @@ void bcm_vk_tty_exit(struct bcm_vk *vk)
kfree(vk->tty_drv->name);
vk->tty_drv->name = NULL;
- put_tty_driver(vk->tty_drv);
+ tty_driver_kref_put(vk->tty_drv);
}
void bcm_vk_tty_terminate_tty_user(struct bcm_vk *vk)
diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c
index 7a6f01ace78a..305ffad131a2 100644
--- a/drivers/misc/eeprom/at24.c
+++ b/drivers/misc/eeprom/at24.c
@@ -714,23 +714,20 @@ static int at24_probe(struct i2c_client *client)
}
/*
- * If the 'label' property is not present for the AT24 EEPROM,
- * then nvmem_config.id is initialised to NVMEM_DEVID_AUTO,
- * and this will append the 'devid' to the name of the NVMEM
- * device. This is purely legacy and the AT24 driver has always
- * defaulted to this. However, if the 'label' property is
- * present then this means that the name is specified by the
- * firmware and this name should be used verbatim and so it is
- * not necessary to append the 'devid'.
+ * We initialize nvmem_config.id to NVMEM_DEVID_AUTO even if the
+ * label property is set as some platform can have multiple eeproms
+ * with same label and we can not register each of those with same
+ * label. Failing to register those eeproms trigger cascade failure
+ * on such platform.
*/
+ nvmem_config.id = NVMEM_DEVID_AUTO;
+
if (device_property_present(dev, "label")) {
- nvmem_config.id = NVMEM_DEVID_NONE;
err = device_property_read_string(dev, "label",
&nvmem_config.name);
if (err)
return err;
} else {
- nvmem_config.id = NVMEM_DEVID_AUTO;
nvmem_config.name = dev_name(dev);
}
diff --git a/drivers/misc/gehc-achc.c b/drivers/misc/gehc-achc.c
new file mode 100644
index 000000000000..02f33bc60c56
--- /dev/null
+++ b/drivers/misc/gehc-achc.c
@@ -0,0 +1,565 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * datasheet: https://www.nxp.com/docs/en/data-sheet/K20P144M120SF3.pdf
+ *
+ * Copyright (C) 2018-2021 Collabora
+ * Copyright (C) 2018-2021 GE Healthcare
+ */
+
+#include <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/gpio/consumer.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/spi/spi.h>
+
+#define ACHC_MAX_FREQ_HZ 300000
+#define ACHC_FAST_READ_FREQ_HZ 1000000
+
+struct achc_data {
+ struct spi_device *main;
+ struct spi_device *ezport;
+ struct gpio_desc *reset;
+
+ struct mutex device_lock; /* avoid concurrent device access */
+};
+
+#define EZPORT_RESET_DELAY_MS 100
+#define EZPORT_STARTUP_DELAY_MS 200
+#define EZPORT_WRITE_WAIT_MS 10
+#define EZPORT_TRANSFER_SIZE 2048
+
+#define EZPORT_CMD_SP 0x02 /* flash section program */
+#define EZPORT_CMD_RDSR 0x05 /* read status register */
+#define EZPORT_CMD_WREN 0x06 /* write enable */
+#define EZPORT_CMD_FAST_READ 0x0b /* flash read data at high speed */
+#define EZPORT_CMD_RESET 0xb9 /* reset chip */
+#define EZPORT_CMD_BE 0xc7 /* bulk erase */
+#define EZPORT_CMD_SE 0xd8 /* sector erase */
+
+#define EZPORT_SECTOR_SIZE 4096
+#define EZPORT_SECTOR_MASK (EZPORT_SECTOR_SIZE - 1)
+
+#define EZPORT_STATUS_WIP BIT(0) /* write in progress */
+#define EZPORT_STATUS_WEN BIT(1) /* write enable */
+#define EZPORT_STATUS_BEDIS BIT(2) /* bulk erase disable */
+#define EZPORT_STATUS_FLEXRAM BIT(3) /* FlexRAM mode */
+#define EZPORT_STATUS_WEF BIT(6) /* write error flag */
+#define EZPORT_STATUS_FS BIT(7) /* flash security */
+
+static void ezport_reset(struct gpio_desc *reset)
+{
+ gpiod_set_value(reset, 1);
+ msleep(EZPORT_RESET_DELAY_MS);
+ gpiod_set_value(reset, 0);
+ msleep(EZPORT_STARTUP_DELAY_MS);
+}
+
+static int ezport_start_programming(struct spi_device *spi, struct gpio_desc *reset)
+{
+ struct spi_message msg;
+ struct spi_transfer assert_cs = {
+ .cs_change = 1,
+ };
+ struct spi_transfer release_cs = { };
+ int ret;
+
+ spi_bus_lock(spi->master);
+
+ /* assert chip select */
+ spi_message_init(&msg);
+ spi_message_add_tail(&assert_cs, &msg);
+ ret = spi_sync_locked(spi, &msg);
+ if (ret)
+ goto fail;
+
+ msleep(EZPORT_STARTUP_DELAY_MS);
+
+ /* reset with asserted chip select to switch into programming mode */
+ ezport_reset(reset);
+
+ /* release chip select */
+ spi_message_init(&msg);
+ spi_message_add_tail(&release_cs, &msg);
+ ret = spi_sync_locked(spi, &msg);
+
+fail:
+ spi_bus_unlock(spi->master);
+ return ret;
+}
+
+static void ezport_stop_programming(struct spi_device *spi, struct gpio_desc *reset)
+{
+ /* reset without asserted chip select to return into normal mode */
+ spi_bus_lock(spi->master);
+ ezport_reset(reset);
+ spi_bus_unlock(spi->master);
+}
+
+static int ezport_get_status_register(struct spi_device *spi)
+{
+ int ret;
+
+ ret = spi_w8r8(spi, EZPORT_CMD_RDSR);
+ if (ret < 0)
+ return ret;
+ if (ret == 0xff) {
+ dev_err(&spi->dev, "Invalid EzPort status, EzPort is not functional!\n");
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
+static int ezport_soft_reset(struct spi_device *spi)
+{
+ u8 cmd = EZPORT_CMD_RESET;
+ int ret;
+
+ ret = spi_write(spi, &cmd, 1);
+ if (ret < 0)
+ return ret;
+
+ msleep(EZPORT_STARTUP_DELAY_MS);
+
+ return 0;
+}
+
+static int ezport_send_simple(struct spi_device *spi, u8 cmd)
+{
+ int ret;
+
+ ret = spi_write(spi, &cmd, 1);
+ if (ret < 0)
+ return ret;
+
+ return ezport_get_status_register(spi);
+}
+
+static int ezport_wait_write(struct spi_device *spi, u32 retries)
+{
+ int ret;
+ u32 i;
+
+ for (i = 0; i < retries; i++) {
+ ret = ezport_get_status_register(spi);
+ if (ret >= 0 && !(ret & EZPORT_STATUS_WIP))
+ break;
+ msleep(EZPORT_WRITE_WAIT_MS);
+ }
+
+ return ret;
+}
+
+static int ezport_write_enable(struct spi_device *spi)
+{
+ int ret = 0, retries = 3;
+
+ for (retries = 0; retries < 3; retries++) {
+ ret = ezport_send_simple(spi, EZPORT_CMD_WREN);
+ if (ret > 0 && ret & EZPORT_STATUS_WEN)
+ break;
+ }
+
+ if (!(ret & EZPORT_STATUS_WEN)) {
+ dev_err(&spi->dev, "EzPort write enable timed out\n");
+ return -ETIMEDOUT;
+ }
+ return 0;
+}
+
+static int ezport_bulk_erase(struct spi_device *spi)
+{
+ int ret;
+ static const u8 cmd = EZPORT_CMD_BE;
+
+ dev_dbg(&spi->dev, "EzPort bulk erase...\n");
+
+ ret = ezport_write_enable(spi);
+ if (ret < 0)
+ return ret;
+
+ ret = spi_write(spi, &cmd, 1);
+ if (ret < 0)
+ return ret;
+
+ ret = ezport_wait_write(spi, 1000);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int ezport_section_erase(struct spi_device *spi, u32 address)
+{
+ u8 query[] = {EZPORT_CMD_SE, (address >> 16) & 0xff, (address >> 8) & 0xff, address & 0xff};
+ int ret;
+
+ dev_dbg(&spi->dev, "Ezport section erase @ 0x%06x...\n", address);
+
+ if (address & EZPORT_SECTOR_MASK)
+ return -EINVAL;
+
+ ret = ezport_write_enable(spi);
+ if (ret < 0)
+ return ret;
+
+ ret = spi_write(spi, query, sizeof(query));
+ if (ret < 0)
+ return ret;
+
+ return ezport_wait_write(spi, 200);
+}
+
+static int ezport_flash_transfer(struct spi_device *spi, u32 address,
+ const u8 *payload, size_t payload_size)
+{
+ struct spi_transfer xfers[2] = {};
+ u8 *command;
+ int ret;
+
+ dev_dbg(&spi->dev, "EzPort write %zu bytes @ 0x%06x...\n", payload_size, address);
+
+ ret = ezport_write_enable(spi);
+ if (ret < 0)
+ return ret;
+
+ command = kmalloc(4, GFP_KERNEL | GFP_DMA);
+ if (!command)
+ return -ENOMEM;
+
+ command[0] = EZPORT_CMD_SP;
+ command[1] = address >> 16;
+ command[2] = address >> 8;
+ command[3] = address >> 0;
+
+ xfers[0].tx_buf = command;
+ xfers[0].len = 4;
+
+ xfers[1].tx_buf = payload;
+ xfers[1].len = payload_size;
+
+ ret = spi_sync_transfer(spi, xfers, 2);
+ kfree(command);
+ if (ret < 0)
+ return ret;
+
+ return ezport_wait_write(spi, 40);
+}
+
+static int ezport_flash_compare(struct spi_device *spi, u32 address,
+ const u8 *payload, size_t payload_size)
+{
+ struct spi_transfer xfers[2] = {};
+ u8 *buffer;
+ int ret;
+
+ buffer = kmalloc(payload_size + 5, GFP_KERNEL | GFP_DMA);
+ if (!buffer)
+ return -ENOMEM;
+
+ buffer[0] = EZPORT_CMD_FAST_READ;
+ buffer[1] = address >> 16;
+ buffer[2] = address >> 8;
+ buffer[3] = address >> 0;
+
+ xfers[0].tx_buf = buffer;
+ xfers[0].len = 4;
+ xfers[0].speed_hz = ACHC_FAST_READ_FREQ_HZ;
+
+ xfers[1].rx_buf = buffer + 4;
+ xfers[1].len = payload_size + 1;
+ xfers[1].speed_hz = ACHC_FAST_READ_FREQ_HZ;
+
+ ret = spi_sync_transfer(spi, xfers, 2);
+ if (ret)
+ goto err;
+
+ /* FAST_READ receives one dummy byte before the real data */
+ ret = memcmp(payload, buffer + 4 + 1, payload_size);
+ if (ret) {
+ ret = -EBADMSG;
+ dev_dbg(&spi->dev, "Verification failure @ %06x", address);
+ print_hex_dump_bytes("fw: ", DUMP_PREFIX_OFFSET, payload, payload_size);
+ print_hex_dump_bytes("dev: ", DUMP_PREFIX_OFFSET, buffer + 4, payload_size);
+ }
+
+err:
+ kfree(buffer);
+ return ret;
+}
+
+static int ezport_firmware_compare_data(struct spi_device *spi,
+ const u8 *data, size_t size)
+{
+ int ret;
+ size_t address = 0;
+ size_t transfer_size;
+
+ dev_dbg(&spi->dev, "EzPort compare data with %zu bytes...\n", size);
+
+ ret = ezport_get_status_register(spi);
+ if (ret < 0)
+ return ret;
+
+ if (ret & EZPORT_STATUS_FS) {
+ dev_info(&spi->dev, "Device is in secure mode (status=0x%02x)!\n", ret);
+ dev_info(&spi->dev, "FW verification is not possible\n");
+ return -EACCES;
+ }
+
+ while (size - address > 0) {
+ transfer_size = min((size_t) EZPORT_TRANSFER_SIZE, size - address);
+
+ ret = ezport_flash_compare(spi, address, data+address, transfer_size);
+ if (ret)
+ return ret;
+
+ address += transfer_size;
+ }
+
+ return 0;
+}
+
+static int ezport_firmware_flash_data(struct spi_device *spi,
+ const u8 *data, size_t size)
+{
+ int ret;
+ size_t address = 0;
+ size_t transfer_size;
+
+ dev_dbg(&spi->dev, "EzPort flash data with %zu bytes...\n", size);
+
+ ret = ezport_get_status_register(spi);
+ if (ret < 0)
+ return ret;
+
+ if (ret & EZPORT_STATUS_FS) {
+ ret = ezport_bulk_erase(spi);
+ if (ret < 0)
+ return ret;
+ if (ret & EZPORT_STATUS_FS)
+ return -EINVAL;
+ }
+
+ while (size - address > 0) {
+ if (!(address & EZPORT_SECTOR_MASK)) {
+ ret = ezport_section_erase(spi, address);
+ if (ret < 0)
+ return ret;
+ if (ret & EZPORT_STATUS_WIP || ret & EZPORT_STATUS_WEF)
+ return -EIO;
+ }
+
+ transfer_size = min((size_t) EZPORT_TRANSFER_SIZE, size - address);
+
+ ret = ezport_flash_transfer(spi, address,
+ data+address, transfer_size);
+ if (ret < 0)
+ return ret;
+ else if (ret & EZPORT_STATUS_WIP)
+ return -ETIMEDOUT;
+ else if (ret & EZPORT_STATUS_WEF)
+ return -EIO;
+
+ address += transfer_size;
+ }
+
+ dev_dbg(&spi->dev, "EzPort verify flashed data...\n");
+ ret = ezport_firmware_compare_data(spi, data, size);
+
+ /* allow missing FW verfication in secure mode */
+ if (ret == -EACCES)
+ ret = 0;
+
+ if (ret < 0)
+ dev_err(&spi->dev, "Failed to verify flashed data: %d\n", ret);
+
+ ret = ezport_soft_reset(spi);
+ if (ret < 0)
+ dev_warn(&spi->dev, "EzPort reset failed!\n");
+
+ return ret;
+}
+
+static int ezport_firmware_load(struct spi_device *spi, const char *fwname)
+{
+ const struct firmware *fw;
+ int ret;
+
+ ret = request_firmware(&fw, fwname, &spi->dev);
+ if (ret) {
+ dev_err(&spi->dev, "Could not get firmware: %d\n", ret);
+ return ret;
+ }
+
+ ret = ezport_firmware_flash_data(spi, fw->data, fw->size);
+
+ release_firmware(fw);
+
+ return ret;
+}
+
+/**
+ * ezport_flash - flash device firmware
+ * @spi: SPI device for NXP EzPort interface
+ * @reset: the gpio connected to the device reset pin
+ * @fwname: filename of the firmware that should be flashed
+ *
+ * Context: can sleep
+ *
+ * Return: 0 on success; negative errno on failure
+ */
+static int ezport_flash(struct spi_device *spi, struct gpio_desc *reset, const char *fwname)
+{
+ int ret;
+
+ ret = ezport_start_programming(spi, reset);
+ if (ret)
+ return ret;
+
+ ret = ezport_firmware_load(spi, fwname);
+
+ ezport_stop_programming(spi, reset);
+
+ if (ret)
+ dev_err(&spi->dev, "Failed to flash firmware: %d\n", ret);
+ else
+ dev_dbg(&spi->dev, "Finished FW flashing!\n");
+
+ return ret;
+}
+
+static ssize_t update_firmware_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct achc_data *achc = dev_get_drvdata(dev);
+ unsigned long value;
+ int ret;
+
+ ret = kstrtoul(buf, 0, &value);
+ if (ret < 0 || value != 1)
+ return -EINVAL;
+
+ mutex_lock(&achc->device_lock);
+ ret = ezport_flash(achc->ezport, achc->reset, "achc.bin");
+ mutex_unlock(&achc->device_lock);
+
+ if (ret < 0)
+ return ret;
+
+ return count;
+}
+static DEVICE_ATTR_WO(update_firmware);
+
+static ssize_t reset_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct achc_data *achc = dev_get_drvdata(dev);
+ int ret;
+
+ mutex_lock(&achc->device_lock);
+ ret = gpiod_get_value(achc->reset);
+ mutex_unlock(&achc->device_lock);
+
+ if (ret < 0)
+ return ret;
+
+ return sysfs_emit(buf, "%d\n", ret);
+}
+
+static ssize_t reset_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct achc_data *achc = dev_get_drvdata(dev);
+ unsigned long value;
+ int ret;
+
+ ret = kstrtoul(buf, 0, &value);
+ if (ret < 0 || value > 1)
+ return -EINVAL;
+
+ mutex_lock(&achc->device_lock);
+ gpiod_set_value(achc->reset, value);
+ mutex_unlock(&achc->device_lock);
+
+ return count;
+}
+static DEVICE_ATTR_RW(reset);
+
+static struct attribute *gehc_achc_attrs[] = {
+ &dev_attr_update_firmware.attr,
+ &dev_attr_reset.attr,
+ NULL,
+};
+ATTRIBUTE_GROUPS(gehc_achc);
+
+static void unregister_ezport(void *data)
+{
+ struct spi_device *ezport = data;
+
+ spi_unregister_device(ezport);
+}
+
+static int gehc_achc_probe(struct spi_device *spi)
+{
+ struct achc_data *achc;
+ int ezport_reg, ret;
+
+ spi->max_speed_hz = ACHC_MAX_FREQ_HZ;
+ spi->bits_per_word = 8;
+ spi->mode = SPI_MODE_0;
+
+ achc = devm_kzalloc(&spi->dev, sizeof(*achc), GFP_KERNEL);
+ if (!achc)
+ return -ENOMEM;
+ spi_set_drvdata(spi, achc);
+ achc->main = spi;
+
+ mutex_init(&achc->device_lock);
+
+ ret = of_property_read_u32_index(spi->dev.of_node, "reg", 1, &ezport_reg);
+ if (ret)
+ return dev_err_probe(&spi->dev, ret, "missing second reg entry!\n");
+
+ achc->ezport = spi_new_ancillary_device(spi, ezport_reg);
+ if (IS_ERR(achc->ezport))
+ return PTR_ERR(achc->ezport);
+
+ ret = devm_add_action_or_reset(&spi->dev, unregister_ezport, achc->ezport);
+ if (ret)
+ return ret;
+
+ achc->reset = devm_gpiod_get(&spi->dev, "reset", GPIOD_OUT_LOW);
+ if (IS_ERR(achc->reset))
+ return dev_err_probe(&spi->dev, PTR_ERR(achc->reset), "Could not get reset gpio\n");
+
+ return 0;
+}
+
+static const struct spi_device_id gehc_achc_id[] = {
+ { "ge,achc", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(spi, gehc_achc_id);
+
+static const struct of_device_id gehc_achc_of_match[] = {
+ { .compatible = "ge,achc" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, gehc_achc_of_match);
+
+static struct spi_driver gehc_achc_spi_driver = {
+ .driver = {
+ .name = "gehc-achc",
+ .of_match_table = gehc_achc_of_match,
+ .dev_groups = gehc_achc_groups,
+ },
+ .probe = gehc_achc_probe,
+ .id_table = gehc_achc_id,
+};
+module_spi_driver(gehc_achc_spi_driver);
+
+MODULE_DESCRIPTION("GEHC ACHC driver");
+MODULE_AUTHOR("Sebastian Reichel <sebastian.reichel@collabora.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/misc/hi6421v600-irq.c b/drivers/misc/hi6421v600-irq.c
new file mode 100644
index 000000000000..08535e97ff43
--- /dev/null
+++ b/drivers/misc/hi6421v600-irq.c
@@ -0,0 +1,307 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Device driver for irqs in HISI PMIC IC
+ *
+ * Copyright (c) 2013 Linaro Ltd.
+ * Copyright (c) 2011 Hisilicon.
+ * Copyright (c) 2020-2021 Huawei Technologies Co., Ltd.
+ */
+
+#include <linux/bitops.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/mfd/hi6421-spmi-pmic.h>
+#include <linux/module.h>
+#include <linux/of_gpio.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/irqdomain.h>
+#include <linux/regmap.h>
+
+struct hi6421v600_irq {
+ struct device *dev;
+ struct irq_domain *domain;
+ int irq;
+ unsigned int *irqs;
+ struct regmap *regmap;
+
+ /* Protect IRQ mask changes */
+ spinlock_t lock;
+};
+
+enum hi6421v600_irq_list {
+ OTMP = 0,
+ VBUS_CONNECT,
+ VBUS_DISCONNECT,
+ ALARMON_R,
+ HOLD_6S,
+ HOLD_1S,
+ POWERKEY_UP,
+ POWERKEY_DOWN,
+ OCP_SCP_R,
+ COUL_R,
+ SIM0_HPD_R,
+ SIM0_HPD_F,
+ SIM1_HPD_R,
+ SIM1_HPD_F,
+
+ PMIC_IRQ_LIST_MAX
+};
+
+#define HISI_IRQ_BANK_SIZE 2
+
+/*
+ * IRQ number for the power key button and mask for both UP and DOWN IRQs
+ */
+#define HISI_POWERKEY_IRQ_NUM 0
+#define HISI_IRQ_POWERKEY_UP_DOWN (BIT(POWERKEY_DOWN) | BIT(POWERKEY_UP))
+
+/*
+ * Registers for IRQ address and IRQ mask bits
+ *
+ * Please notice that we need to regmap a larger region, as other
+ * registers are used by the irqs.
+ * See drivers/irq/hi6421-irq.c.
+ */
+#define SOC_PMIC_IRQ_MASK_0_ADDR 0x0202
+#define SOC_PMIC_IRQ0_ADDR 0x0212
+
+/*
+ * The IRQs are mapped as:
+ *
+ * ====================== ============= ============ =====
+ * IRQ MASK REGISTER IRQ REGISTER BIT
+ * ====================== ============= ============ =====
+ * OTMP 0x0202 0x212 bit 0
+ * VBUS_CONNECT 0x0202 0x212 bit 1
+ * VBUS_DISCONNECT 0x0202 0x212 bit 2
+ * ALARMON_R 0x0202 0x212 bit 3
+ * HOLD_6S 0x0202 0x212 bit 4
+ * HOLD_1S 0x0202 0x212 bit 5
+ * POWERKEY_UP 0x0202 0x212 bit 6
+ * POWERKEY_DOWN 0x0202 0x212 bit 7
+ *
+ * OCP_SCP_R 0x0203 0x213 bit 0
+ * COUL_R 0x0203 0x213 bit 1
+ * SIM0_HPD_R 0x0203 0x213 bit 2
+ * SIM0_HPD_F 0x0203 0x213 bit 3
+ * SIM1_HPD_R 0x0203 0x213 bit 4
+ * SIM1_HPD_F 0x0203 0x213 bit 5
+ * ====================== ============= ============ =====
+ *
+ * Each mask register contains 8 bits. The ancillary macros below
+ * convert a number from 0 to 14 into a register address and a bit mask
+ */
+#define HISI_IRQ_MASK_REG(irq_data) (SOC_PMIC_IRQ_MASK_0_ADDR + \
+ (irqd_to_hwirq(irq_data) / BITS_PER_BYTE))
+#define HISI_IRQ_MASK_BIT(irq_data) BIT(irqd_to_hwirq(irq_data) & (BITS_PER_BYTE - 1))
+#define HISI_8BITS_MASK 0xff
+
+static irqreturn_t hi6421v600_irq_handler(int irq, void *__priv)
+{
+ struct hi6421v600_irq *priv = __priv;
+ unsigned long pending;
+ unsigned int in;
+ int i, offset;
+
+ for (i = 0; i < HISI_IRQ_BANK_SIZE; i++) {
+ regmap_read(priv->regmap, SOC_PMIC_IRQ0_ADDR + i, &in);
+
+ /* Mark pending IRQs as handled */
+ regmap_write(priv->regmap, SOC_PMIC_IRQ0_ADDR + i, in);
+
+ pending = in & HISI_8BITS_MASK;
+
+ if (i == HISI_POWERKEY_IRQ_NUM &&
+ (pending & HISI_IRQ_POWERKEY_UP_DOWN) == HISI_IRQ_POWERKEY_UP_DOWN) {
+ /*
+ * If both powerkey down and up IRQs are received,
+ * handle them at the right order
+ */
+ generic_handle_irq(priv->irqs[POWERKEY_DOWN]);
+ generic_handle_irq(priv->irqs[POWERKEY_UP]);
+ pending &= ~HISI_IRQ_POWERKEY_UP_DOWN;
+ }
+
+ if (!pending)
+ continue;
+
+ for_each_set_bit(offset, &pending, BITS_PER_BYTE) {
+ generic_handle_irq(priv->irqs[offset + i * BITS_PER_BYTE]);
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+static void hi6421v600_irq_mask(struct irq_data *d)
+{
+ struct hi6421v600_irq *priv = irq_data_get_irq_chip_data(d);
+ unsigned long flags;
+ unsigned int data;
+ u32 offset;
+
+ offset = HISI_IRQ_MASK_REG(d);
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ regmap_read(priv->regmap, offset, &data);
+ data |= HISI_IRQ_MASK_BIT(d);
+ regmap_write(priv->regmap, offset, data);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static void hi6421v600_irq_unmask(struct irq_data *d)
+{
+ struct hi6421v600_irq *priv = irq_data_get_irq_chip_data(d);
+ u32 data, offset;
+ unsigned long flags;
+
+ offset = HISI_IRQ_MASK_REG(d);
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ regmap_read(priv->regmap, offset, &data);
+ data &= ~HISI_IRQ_MASK_BIT(d);
+ regmap_write(priv->regmap, offset, data);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static struct irq_chip hi6421v600_pmu_irqchip = {
+ .name = "hi6421v600-irq",
+ .irq_mask = hi6421v600_irq_mask,
+ .irq_unmask = hi6421v600_irq_unmask,
+ .irq_disable = hi6421v600_irq_mask,
+ .irq_enable = hi6421v600_irq_unmask,
+};
+
+static int hi6421v600_irq_map(struct irq_domain *d, unsigned int virq,
+ irq_hw_number_t hw)
+{
+ struct hi6421v600_irq *priv = d->host_data;
+
+ irq_set_chip_and_handler_name(virq, &hi6421v600_pmu_irqchip,
+ handle_simple_irq, "hi6421v600");
+ irq_set_chip_data(virq, priv);
+ irq_set_irq_type(virq, IRQ_TYPE_NONE);
+
+ return 0;
+}
+
+static const struct irq_domain_ops hi6421v600_domain_ops = {
+ .map = hi6421v600_irq_map,
+ .xlate = irq_domain_xlate_twocell,
+};
+
+static void hi6421v600_irq_init(struct hi6421v600_irq *priv)
+{
+ int i;
+ unsigned int pending;
+
+ /* Mask all IRQs */
+ for (i = 0; i < HISI_IRQ_BANK_SIZE; i++)
+ regmap_write(priv->regmap, SOC_PMIC_IRQ_MASK_0_ADDR + i,
+ HISI_8BITS_MASK);
+
+ /* Mark all IRQs as handled */
+ for (i = 0; i < HISI_IRQ_BANK_SIZE; i++) {
+ regmap_read(priv->regmap, SOC_PMIC_IRQ0_ADDR + i, &pending);
+ regmap_write(priv->regmap, SOC_PMIC_IRQ0_ADDR + i,
+ HISI_8BITS_MASK);
+ }
+}
+
+static int hi6421v600_irq_probe(struct platform_device *pdev)
+{
+ struct device *pmic_dev = pdev->dev.parent;
+ struct device_node *np = pmic_dev->of_node;
+ struct platform_device *pmic_pdev;
+ struct device *dev = &pdev->dev;
+ struct hi6421v600_irq *priv;
+ struct hi6421_spmi_pmic *pmic;
+ unsigned int virq;
+ int i, ret;
+
+ /*
+ * This driver is meant to be called by hi6421-spmi-core,
+ * which should first set drvdata. If this doesn't happen, hit
+ * a warn on and return.
+ */
+ pmic = dev_get_drvdata(pmic_dev);
+ if (WARN_ON(!pmic))
+ return -ENODEV;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->dev = dev;
+ priv->regmap = pmic->regmap;
+
+ spin_lock_init(&priv->lock);
+
+ pmic_pdev = container_of(pmic_dev, struct platform_device, dev);
+
+ priv->irq = platform_get_irq(pmic_pdev, 0);
+ if (priv->irq < 0) {
+ dev_err(dev, "Error %d when getting IRQs\n", priv->irq);
+ return priv->irq;
+ }
+
+ platform_set_drvdata(pdev, priv);
+
+ hi6421v600_irq_init(priv);
+
+ priv->irqs = devm_kzalloc(dev, PMIC_IRQ_LIST_MAX * sizeof(int), GFP_KERNEL);
+ if (!priv->irqs)
+ return -ENOMEM;
+
+ priv->domain = irq_domain_add_simple(np, PMIC_IRQ_LIST_MAX, 0,
+ &hi6421v600_domain_ops, priv);
+ if (!priv->domain) {
+ dev_err(dev, "Failed to create IRQ domain\n");
+ return -ENODEV;
+ }
+
+ for (i = 0; i < PMIC_IRQ_LIST_MAX; i++) {
+ virq = irq_create_mapping(priv->domain, i);
+ if (!virq) {
+ dev_err(dev, "Failed to map H/W IRQ\n");
+ return -ENODEV;
+ }
+ priv->irqs[i] = virq;
+ }
+
+ ret = devm_request_threaded_irq(dev,
+ priv->irq, hi6421v600_irq_handler,
+ NULL,
+ IRQF_TRIGGER_LOW | IRQF_SHARED | IRQF_NO_SUSPEND,
+ "pmic", priv);
+ if (ret < 0) {
+ dev_err(dev, "Failed to start IRQ handling thread: error %d\n",
+ ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct platform_device_id hi6421v600_irq_table[] = {
+ { .name = "hi6421v600-irq" },
+ {},
+};
+MODULE_DEVICE_TABLE(platform, hi6421v600_irq_table);
+
+static struct platform_driver hi6421v600_irq_driver = {
+ .id_table = hi6421v600_irq_table,
+ .driver = {
+ .name = "hi6421v600-irq",
+ },
+ .probe = hi6421v600_irq_probe,
+};
+module_platform_driver(hi6421v600_irq_driver);
+
+MODULE_DESCRIPTION("HiSilicon Hi6421v600 IRQ driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/misc/lkdtm/bugs.c b/drivers/misc/lkdtm/bugs.c
index 88c218a9f8b3..4282b625200f 100644
--- a/drivers/misc/lkdtm/bugs.c
+++ b/drivers/misc/lkdtm/bugs.c
@@ -267,6 +267,7 @@ void lkdtm_ARRAY_BOUNDS(void)
kfree(not_checked);
kfree(checked);
pr_err("FAIL: survived array bounds overflow!\n");
+ pr_expected_config(CONFIG_UBSAN_BOUNDS);
}
void lkdtm_CORRUPT_LIST_ADD(void)
@@ -506,53 +507,3 @@ noinline void lkdtm_CORRUPT_PAC(void)
pr_err("XFAIL: this test is arm64-only\n");
#endif
}
-
-void lkdtm_FORTIFY_OBJECT(void)
-{
- struct target {
- char a[10];
- } target[2] = {};
- int result;
-
- /*
- * Using volatile prevents the compiler from determining the value of
- * 'size' at compile time. Without that, we would get a compile error
- * rather than a runtime error.
- */
- volatile int size = 11;
-
- pr_info("trying to read past the end of a struct\n");
-
- result = memcmp(&target[0], &target[1], size);
-
- /* Print result to prevent the code from being eliminated */
- pr_err("FAIL: fortify did not catch an object overread!\n"
- "\"%d\" was the memcmp result.\n", result);
-}
-
-void lkdtm_FORTIFY_SUBOBJECT(void)
-{
- struct target {
- char a[10];
- char b[10];
- } target;
- char *src;
-
- src = kmalloc(20, GFP_KERNEL);
- strscpy(src, "over ten bytes", 20);
-
- pr_info("trying to strcpy past the end of a member of a struct\n");
-
- /*
- * strncpy(target.a, src, 20); will hit a compile error because the
- * compiler knows at build time that target.a < 20 bytes. Use strcpy()
- * to force a runtime error.
- */
- strcpy(target.a, src);
-
- /* Use target.a to prevent the code from being eliminated */
- pr_err("FAIL: fortify did not catch an sub-object overrun!\n"
- "\"%s\" was copied.\n", target.a);
-
- kfree(src);
-}
diff --git a/drivers/misc/lkdtm/core.c b/drivers/misc/lkdtm/core.c
index 9dda87c6b54a..95b1c6800a22 100644
--- a/drivers/misc/lkdtm/core.c
+++ b/drivers/misc/lkdtm/core.c
@@ -26,7 +26,6 @@
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/debugfs.h>
-#include <linux/init.h>
#define DEFAULT_COUNT 10
@@ -82,8 +81,7 @@ static struct crashpoint crashpoints[] = {
CRASHPOINT("FS_DEVRW", "ll_rw_block"),
CRASHPOINT("MEM_SWAPOUT", "shrink_inactive_list"),
CRASHPOINT("TIMERADD", "hrtimer_start"),
- CRASHPOINT("SCSI_DISPATCH_CMD", "scsi_dispatch_cmd"),
- CRASHPOINT("IDE_CORE_CP", "generic_ide_ioctl"),
+ CRASHPOINT("SCSI_QUEUE_RQ", "scsi_queue_rq"),
#endif
};
@@ -119,8 +117,6 @@ static const struct crashtype crashtypes[] = {
CRASHTYPE(UNSET_SMEP),
CRASHTYPE(CORRUPT_PAC),
CRASHTYPE(UNALIGNED_LOAD_STORE_WRITE),
- CRASHTYPE(FORTIFY_OBJECT),
- CRASHTYPE(FORTIFY_SUBOBJECT),
CRASHTYPE(SLAB_LINEAR_OVERFLOW),
CRASHTYPE(VMALLOC_LINEAR_OVERFLOW),
CRASHTYPE(WRITE_AFTER_FREE),
@@ -180,6 +176,8 @@ static const struct crashtype crashtypes[] = {
CRASHTYPE(USERCOPY_KERNEL),
CRASHTYPE(STACKLEAK_ERASING),
CRASHTYPE(CFI_FORWARD_PROTO),
+ CRASHTYPE(FORTIFIED_OBJECT),
+ CRASHTYPE(FORTIFIED_SUBOBJECT),
CRASHTYPE(FORTIFIED_STRSCPY),
CRASHTYPE(DOUBLE_FAULT),
#ifdef CONFIG_PPC_BOOK3S_64
diff --git a/drivers/misc/lkdtm/fortify.c b/drivers/misc/lkdtm/fortify.c
index 0f51d31b57ca..d06458a4858e 100644
--- a/drivers/misc/lkdtm/fortify.c
+++ b/drivers/misc/lkdtm/fortify.c
@@ -8,6 +8,59 @@
#include <linux/string.h>
#include <linux/slab.h>
+static volatile int fortify_scratch_space;
+
+void lkdtm_FORTIFIED_OBJECT(void)
+{
+ struct target {
+ char a[10];
+ } target[2] = {};
+ /*
+ * Using volatile prevents the compiler from determining the value of
+ * 'size' at compile time. Without that, we would get a compile error
+ * rather than a runtime error.
+ */
+ volatile int size = 11;
+
+ pr_info("trying to read past the end of a struct\n");
+
+ /* Store result to global to prevent the code from being eliminated */
+ fortify_scratch_space = memcmp(&target[0], &target[1], size);
+
+ pr_err("FAIL: fortify did not block an object overread!\n");
+ pr_expected_config(CONFIG_FORTIFY_SOURCE);
+}
+
+void lkdtm_FORTIFIED_SUBOBJECT(void)
+{
+ struct target {
+ char a[10];
+ char b[10];
+ } target;
+ volatile int size = 20;
+ char *src;
+
+ src = kmalloc(size, GFP_KERNEL);
+ strscpy(src, "over ten bytes", size);
+ size = strlen(src) + 1;
+
+ pr_info("trying to strcpy past the end of a member of a struct\n");
+
+ /*
+ * memcpy(target.a, src, 20); will hit a compile error because the
+ * compiler knows at build time that target.a < 20 bytes. Use a
+ * volatile to force a runtime error.
+ */
+ memcpy(target.a, src, size);
+
+ /* Store result to global to prevent the code from being eliminated */
+ fortify_scratch_space = target.a[3];
+
+ pr_err("FAIL: fortify did not block an sub-object overrun!\n");
+ pr_expected_config(CONFIG_FORTIFY_SOURCE);
+
+ kfree(src);
+}
/*
* Calls fortified strscpy to test that it returns the same result as vanilla
diff --git a/drivers/misc/lkdtm/heap.c b/drivers/misc/lkdtm/heap.c
index 3d9aae5821a0..8a92f5a800fa 100644
--- a/drivers/misc/lkdtm/heap.c
+++ b/drivers/misc/lkdtm/heap.c
@@ -13,6 +13,13 @@ static struct kmem_cache *a_cache;
static struct kmem_cache *b_cache;
/*
+ * Using volatile here means the compiler cannot ever make assumptions
+ * about this value. This means compile-time length checks involving
+ * this variable cannot be performed; only run-time checks.
+ */
+static volatile int __offset = 1;
+
+/*
* If there aren't guard pages, it's likely that a consecutive allocation will
* let us overflow into the second allocation without overwriting something real.
*/
@@ -24,7 +31,7 @@ void lkdtm_VMALLOC_LINEAR_OVERFLOW(void)
two = vzalloc(PAGE_SIZE);
pr_info("Attempting vmalloc linear overflow ...\n");
- memset(one, 0xAA, PAGE_SIZE + 1);
+ memset(one, 0xAA, PAGE_SIZE + __offset);
vfree(two);
vfree(one);
diff --git a/drivers/misc/lkdtm/lkdtm.h b/drivers/misc/lkdtm/lkdtm.h
index 6a30b60519f3..d7d64d9765eb 100644
--- a/drivers/misc/lkdtm/lkdtm.h
+++ b/drivers/misc/lkdtm/lkdtm.h
@@ -5,13 +5,17 @@
#define pr_fmt(fmt) "lkdtm: " fmt
#include <linux/kernel.h>
+#include <generated/compile.h>
+#include <generated/utsrelease.h>
+
+#define LKDTM_KERNEL "kernel (" UTS_RELEASE " " UTS_MACHINE ")"
#define pr_expected_config(kconfig) \
{ \
if (IS_ENABLED(kconfig)) \
- pr_err("Unexpected! This kernel was built with " #kconfig "=y\n"); \
+ pr_err("Unexpected! This " LKDTM_KERNEL " was built with " #kconfig "=y\n"); \
else \
- pr_warn("This is probably expected, since this kernel was built *without* " #kconfig "=y\n"); \
+ pr_warn("This is probably expected, since this " LKDTM_KERNEL " was built *without* " #kconfig "=y\n"); \
}
#ifndef MODULE
@@ -21,24 +25,24 @@ int lkdtm_check_bool_cmdline(const char *param);
if (IS_ENABLED(kconfig)) { \
switch (lkdtm_check_bool_cmdline(param)) { \
case 0: \
- pr_warn("This is probably expected, since this kernel was built with " #kconfig "=y but booted with '" param "=N'\n"); \
+ pr_warn("This is probably expected, since this " LKDTM_KERNEL " was built with " #kconfig "=y but booted with '" param "=N'\n"); \
break; \
case 1: \
- pr_err("Unexpected! This kernel was built with " #kconfig "=y and booted with '" param "=Y'\n"); \
+ pr_err("Unexpected! This " LKDTM_KERNEL " was built with " #kconfig "=y and booted with '" param "=Y'\n"); \
break; \
default: \
- pr_err("Unexpected! This kernel was built with " #kconfig "=y (and booted without '" param "' specified)\n"); \
+ pr_err("Unexpected! This " LKDTM_KERNEL " was built with " #kconfig "=y (and booted without '" param "' specified)\n"); \
} \
} else { \
switch (lkdtm_check_bool_cmdline(param)) { \
case 0: \
- pr_warn("This is probably expected, as kernel was built *without* " #kconfig "=y and booted with '" param "=N'\n"); \
+ pr_warn("This is probably expected, as this " LKDTM_KERNEL " was built *without* " #kconfig "=y and booted with '" param "=N'\n"); \
break; \
case 1: \
- pr_err("Unexpected! This kernel was built *without* " #kconfig "=y but booted with '" param "=Y'\n"); \
+ pr_err("Unexpected! This " LKDTM_KERNEL " was built *without* " #kconfig "=y but booted with '" param "=Y'\n"); \
break; \
default: \
- pr_err("This is probably expected, since this kernel was built *without* " #kconfig "=y (and booted without '" param "' specified)\n"); \
+ pr_err("This is probably expected, since this " LKDTM_KERNEL " was built *without* " #kconfig "=y (and booted without '" param "' specified)\n"); \
break; \
} \
} \
@@ -74,8 +78,6 @@ void lkdtm_STACK_GUARD_PAGE_TRAILING(void);
void lkdtm_UNSET_SMEP(void);
void lkdtm_DOUBLE_FAULT(void);
void lkdtm_CORRUPT_PAC(void);
-void lkdtm_FORTIFY_OBJECT(void);
-void lkdtm_FORTIFY_SUBOBJECT(void);
/* heap.c */
void __init lkdtm_heap_init(void);
@@ -150,6 +152,8 @@ void lkdtm_STACKLEAK_ERASING(void);
void lkdtm_CFI_FORWARD_PROTO(void);
/* fortify.c */
+void lkdtm_FORTIFIED_OBJECT(void);
+void lkdtm_FORTIFIED_SUBOBJECT(void);
void lkdtm_FORTIFIED_STRSCPY(void);
/* powerpc.c */
diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c
index 935acc6bbf3c..44bac4ad687c 100644
--- a/drivers/misc/mei/bus.c
+++ b/drivers/misc/mei/bus.c
@@ -31,7 +31,7 @@
*
* Return: written size bytes or < 0 on error
*/
-ssize_t __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length, u8 vtag,
+ssize_t __mei_cl_send(struct mei_cl *cl, const u8 *buf, size_t length, u8 vtag,
unsigned int mode)
{
struct mei_device *bus;
@@ -232,8 +232,8 @@ out:
* * < 0 on error
*/
-ssize_t mei_cldev_send_vtag(struct mei_cl_device *cldev, u8 *buf, size_t length,
- u8 vtag)
+ssize_t mei_cldev_send_vtag(struct mei_cl_device *cldev, const u8 *buf,
+ size_t length, u8 vtag)
{
struct mei_cl *cl = cldev->cl;
@@ -296,7 +296,7 @@ EXPORT_SYMBOL_GPL(mei_cldev_recv_nonblock_vtag);
* * written size in bytes
* * < 0 on error
*/
-ssize_t mei_cldev_send(struct mei_cl_device *cldev, u8 *buf, size_t length)
+ssize_t mei_cldev_send(struct mei_cl_device *cldev, const u8 *buf, size_t length)
{
return mei_cldev_send_vtag(cldev, buf, length, 0);
}
@@ -552,7 +552,7 @@ EXPORT_SYMBOL_GPL(mei_cldev_ver);
*
* Return: true if me client is initialized and connected
*/
-bool mei_cldev_enabled(struct mei_cl_device *cldev)
+bool mei_cldev_enabled(const struct mei_cl_device *cldev)
{
return mei_cl_is_connected(cldev->cl);
}
@@ -771,8 +771,8 @@ EXPORT_SYMBOL_GPL(mei_cldev_disable);
* Return: id on success; NULL if no id is matching
*/
static const
-struct mei_cl_device_id *mei_cl_device_find(struct mei_cl_device *cldev,
- struct mei_cl_driver *cldrv)
+struct mei_cl_device_id *mei_cl_device_find(const struct mei_cl_device *cldev,
+ const struct mei_cl_driver *cldrv)
{
const struct mei_cl_device_id *id;
const uuid_le *uuid;
@@ -815,8 +815,8 @@ struct mei_cl_device_id *mei_cl_device_find(struct mei_cl_device *cldev,
*/
static int mei_cl_device_match(struct device *dev, struct device_driver *drv)
{
- struct mei_cl_device *cldev = to_mei_cl_device(dev);
- struct mei_cl_driver *cldrv = to_mei_cl_driver(drv);
+ const struct mei_cl_device *cldev = to_mei_cl_device(dev);
+ const struct mei_cl_driver *cldrv = to_mei_cl_driver(drv);
const struct mei_cl_device_id *found_id;
if (!cldev)
@@ -884,7 +884,7 @@ static int mei_cl_device_probe(struct device *dev)
*
* Return: 0 on success; < 0 otherwise
*/
-static int mei_cl_device_remove(struct device *dev)
+static void mei_cl_device_remove(struct device *dev)
{
struct mei_cl_device *cldev = to_mei_cl_device(dev);
struct mei_cl_driver *cldrv = to_mei_cl_driver(dev->driver);
@@ -896,8 +896,6 @@ static int mei_cl_device_remove(struct device *dev)
mei_cl_bus_module_put(cldev);
module_put(THIS_MODULE);
-
- return 0;
}
static ssize_t name_show(struct device *dev, struct device_attribute *a,
diff --git a/drivers/misc/mei/client.h b/drivers/misc/mei/client.h
index b12cdcde9436..418056fb1489 100644
--- a/drivers/misc/mei/client.h
+++ b/drivers/misc/mei/client.h
@@ -160,7 +160,7 @@ int mei_cl_vt_support_check(const struct mei_cl *cl);
*
* Return: true if the host client is connected
*/
-static inline bool mei_cl_is_connected(struct mei_cl *cl)
+static inline bool mei_cl_is_connected(const struct mei_cl *cl)
{
return cl->state == MEI_FILE_CONNECTED;
}
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index b7b6ef344e80..694f866f87ef 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -356,7 +356,7 @@ struct mei_hw_ops {
/* MEI bus API*/
void mei_cl_bus_rescan_work(struct work_struct *work);
void mei_cl_bus_dev_fixup(struct mei_cl_device *dev);
-ssize_t __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length, u8 vtag,
+ssize_t __mei_cl_send(struct mei_cl *cl, const u8 *buf, size_t length, u8 vtag,
unsigned int mode);
ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length, u8 *vtag,
unsigned int mode, unsigned long timeout);
diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c
index 1b2868ca4f2a..d1137a95ad02 100644
--- a/drivers/misc/pci_endpoint_test.c
+++ b/drivers/misc/pci_endpoint_test.c
@@ -862,6 +862,7 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev,
err = -ENOMEM;
goto err_release_irq;
}
+ misc_device->parent = &pdev->dev;
misc_device->fops = &pci_endpoint_test_fops,
err = misc_register(misc_device);
diff --git a/drivers/misc/pvpanic/pvpanic-pci.c b/drivers/misc/pvpanic/pvpanic-pci.c
index a43c401017ae..741116b3d995 100644
--- a/drivers/misc/pvpanic/pvpanic-pci.c
+++ b/drivers/misc/pvpanic/pvpanic-pci.c
@@ -108,4 +108,6 @@ static struct pci_driver pvpanic_pci_driver = {
},
};
+MODULE_DEVICE_TABLE(pci, pvpanic_pci_id_tbl);
+
module_pci_driver(pvpanic_pci_driver);
diff --git a/drivers/misc/pvpanic/pvpanic.c b/drivers/misc/pvpanic/pvpanic.c
index 02b807c788c9..bb7aa6368538 100644
--- a/drivers/misc/pvpanic/pvpanic.c
+++ b/drivers/misc/pvpanic/pvpanic.c
@@ -85,6 +85,8 @@ int devm_pvpanic_probe(struct device *dev, struct pvpanic_instance *pi)
list_add(&pi->list, &pvpanic_list);
spin_unlock(&pvpanic_lock);
+ dev_set_drvdata(dev, pi);
+
return devm_add_action_or_reset(dev, pvpanic_remove, pi);
}
EXPORT_SYMBOL_GPL(devm_pvpanic_probe);
diff --git a/drivers/misc/sgi-gru/grumain.c b/drivers/misc/sgi-gru/grumain.c
index 40ac59dd018c..9afda47efbf2 100644
--- a/drivers/misc/sgi-gru/grumain.c
+++ b/drivers/misc/sgi-gru/grumain.c
@@ -282,7 +282,7 @@ static void gru_unload_mm_tracker(struct gru_state *gru,
*/
void gts_drop(struct gru_thread_state *gts)
{
- if (gts && atomic_dec_return(&gts->ts_refcnt) == 0) {
+ if (gts && refcount_dec_and_test(&gts->ts_refcnt)) {
if (gts->ts_gms)
gru_drop_mmu_notifier(gts->ts_gms);
kfree(gts);
@@ -323,7 +323,7 @@ struct gru_thread_state *gru_alloc_gts(struct vm_area_struct *vma,
STAT(gts_alloc);
memset(gts, 0, sizeof(struct gru_thread_state)); /* zero out header */
- atomic_set(&gts->ts_refcnt, 1);
+ refcount_set(&gts->ts_refcnt, 1);
mutex_init(&gts->ts_ctxlock);
gts->ts_cbr_au_count = cbr_au_count;
gts->ts_dsr_au_count = dsr_au_count;
@@ -888,7 +888,7 @@ again:
gts->ts_gru = gru;
gts->ts_blade = gru->gs_blade_id;
gts->ts_ctxnum = gru_assign_context_number(gru);
- atomic_inc(&gts->ts_refcnt);
+ refcount_inc(&gts->ts_refcnt);
gru->gs_gts[gts->ts_ctxnum] = gts;
spin_unlock(&gru->gs_lock);
diff --git a/drivers/misc/sgi-gru/grutables.h b/drivers/misc/sgi-gru/grutables.h
index 5ce8f3081e96..e4c067c61251 100644
--- a/drivers/misc/sgi-gru/grutables.h
+++ b/drivers/misc/sgi-gru/grutables.h
@@ -129,6 +129,7 @@
*
*/
+#include <linux/refcount.h>
#include <linux/rmap.h>
#include <linux/interrupt.h>
#include <linux/mutex.h>
@@ -358,7 +359,7 @@ struct gru_thread_state {
enabled */
int ts_ctxnum; /* context number where the
context is loaded */
- atomic_t ts_refcnt; /* reference count GTS */
+ refcount_t ts_refcnt; /* reference count GTS */
unsigned char ts_dsr_au_count;/* Number of DSR resources
required for contest */
unsigned char ts_cbr_au_count;/* Number of CBR resources
diff --git a/drivers/misc/sgi-xp/xpc_uv.c b/drivers/misc/sgi-xp/xpc_uv.c
index 7791bde81a36..ba9ae0e2df0f 100644
--- a/drivers/misc/sgi-xp/xpc_uv.c
+++ b/drivers/misc/sgi-xp/xpc_uv.c
@@ -1742,7 +1742,7 @@ xpc_init_mq_node(int nid)
{
int cpu;
- get_online_cpus();
+ cpus_read_lock();
for_each_cpu(cpu, cpumask_of_node(nid)) {
xpc_activate_mq_uv =
@@ -1753,7 +1753,7 @@ xpc_init_mq_node(int nid)
break;
}
if (IS_ERR(xpc_activate_mq_uv)) {
- put_online_cpus();
+ cpus_read_unlock();
return PTR_ERR(xpc_activate_mq_uv);
}
@@ -1767,11 +1767,11 @@ xpc_init_mq_node(int nid)
}
if (IS_ERR(xpc_notify_mq_uv)) {
xpc_destroy_gru_mq_uv(xpc_activate_mq_uv);
- put_online_cpus();
+ cpus_read_unlock();
return PTR_ERR(xpc_notify_mq_uv);
}
- put_online_cpus();
+ cpus_read_unlock();
return 0;
}
diff --git a/drivers/misc/sram.c b/drivers/misc/sram.c
index 93638ae2753a..4c26b19f5154 100644
--- a/drivers/misc/sram.c
+++ b/drivers/misc/sram.c
@@ -97,7 +97,24 @@ static int sram_add_partition(struct sram_dev *sram, struct sram_reserve *block,
struct sram_partition *part = &sram->partition[sram->partitions];
mutex_init(&part->lock);
- part->base = sram->virt_base + block->start;
+
+ if (sram->config && sram->config->map_only_reserved) {
+ void __iomem *virt_base;
+
+ if (sram->no_memory_wc)
+ virt_base = devm_ioremap_resource(sram->dev, &block->res);
+ else
+ virt_base = devm_ioremap_resource_wc(sram->dev, &block->res);
+
+ if (IS_ERR(virt_base)) {
+ dev_err(sram->dev, "could not map SRAM at %pr\n", &block->res);
+ return PTR_ERR(virt_base);
+ }
+
+ part->base = virt_base;
+ } else {
+ part->base = sram->virt_base + block->start;
+ }
if (block->pool) {
ret = sram_add_pool(sram, block, start, part);
@@ -198,6 +215,7 @@ static int sram_reserve_regions(struct sram_dev *sram, struct resource *res)
block->start = child_res.start - res->start;
block->size = resource_size(&child_res);
+ block->res = child_res;
list_add_tail(&block->list, &reserve_list);
if (of_find_property(child, "export", NULL))
@@ -295,15 +313,17 @@ static int sram_reserve_regions(struct sram_dev *sram, struct resource *res)
*/
cur_size = block->start - cur_start;
- dev_dbg(sram->dev, "adding chunk 0x%lx-0x%lx\n",
- cur_start, cur_start + cur_size);
+ if (sram->pool) {
+ dev_dbg(sram->dev, "adding chunk 0x%lx-0x%lx\n",
+ cur_start, cur_start + cur_size);
- ret = gen_pool_add_virt(sram->pool,
- (unsigned long)sram->virt_base + cur_start,
- res->start + cur_start, cur_size, -1);
- if (ret < 0) {
- sram_free_partitions(sram);
- goto err_chunks;
+ ret = gen_pool_add_virt(sram->pool,
+ (unsigned long)sram->virt_base + cur_start,
+ res->start + cur_start, cur_size, -1);
+ if (ret < 0) {
+ sram_free_partitions(sram);
+ goto err_chunks;
+ }
}
/* next allocation after this reserved block */
@@ -331,40 +351,63 @@ static int atmel_securam_wait(void)
10000, 500000);
}
+static const struct sram_config atmel_securam_config = {
+ .init = atmel_securam_wait,
+};
+
+/*
+ * SYSRAM contains areas that are not accessible by the
+ * kernel, such as the first 256K that is reserved for TZ.
+ * Accesses to those areas (including speculative accesses)
+ * trigger SErrors. As such we must map only the areas of
+ * SYSRAM specified in the device tree.
+ */
+static const struct sram_config tegra_sysram_config = {
+ .map_only_reserved = true,
+};
+
static const struct of_device_id sram_dt_ids[] = {
{ .compatible = "mmio-sram" },
- { .compatible = "atmel,sama5d2-securam", .data = atmel_securam_wait },
+ { .compatible = "atmel,sama5d2-securam", .data = &atmel_securam_config },
+ { .compatible = "nvidia,tegra186-sysram", .data = &tegra_sysram_config },
+ { .compatible = "nvidia,tegra194-sysram", .data = &tegra_sysram_config },
{}
};
static int sram_probe(struct platform_device *pdev)
{
+ const struct sram_config *config;
struct sram_dev *sram;
int ret;
struct resource *res;
- int (*init_func)(void);
+
+ config = of_device_get_match_data(&pdev->dev);
sram = devm_kzalloc(&pdev->dev, sizeof(*sram), GFP_KERNEL);
if (!sram)
return -ENOMEM;
sram->dev = &pdev->dev;
+ sram->no_memory_wc = of_property_read_bool(pdev->dev.of_node, "no-memory-wc");
+ sram->config = config;
+
+ if (!config || !config->map_only_reserved) {
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (sram->no_memory_wc)
+ sram->virt_base = devm_ioremap_resource(&pdev->dev, res);
+ else
+ sram->virt_base = devm_ioremap_resource_wc(&pdev->dev, res);
+ if (IS_ERR(sram->virt_base)) {
+ dev_err(&pdev->dev, "could not map SRAM registers\n");
+ return PTR_ERR(sram->virt_base);
+ }
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (of_property_read_bool(pdev->dev.of_node, "no-memory-wc"))
- sram->virt_base = devm_ioremap_resource(&pdev->dev, res);
- else
- sram->virt_base = devm_ioremap_resource_wc(&pdev->dev, res);
- if (IS_ERR(sram->virt_base)) {
- dev_err(&pdev->dev, "could not map SRAM registers\n");
- return PTR_ERR(sram->virt_base);
+ sram->pool = devm_gen_pool_create(sram->dev, ilog2(SRAM_GRANULARITY),
+ NUMA_NO_NODE, NULL);
+ if (IS_ERR(sram->pool))
+ return PTR_ERR(sram->pool);
}
- sram->pool = devm_gen_pool_create(sram->dev, ilog2(SRAM_GRANULARITY),
- NUMA_NO_NODE, NULL);
- if (IS_ERR(sram->pool))
- return PTR_ERR(sram->pool);
-
sram->clk = devm_clk_get(sram->dev, NULL);
if (IS_ERR(sram->clk))
sram->clk = NULL;
@@ -378,15 +421,15 @@ static int sram_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, sram);
- init_func = of_device_get_match_data(&pdev->dev);
- if (init_func) {
- ret = init_func();
+ if (config && config->init) {
+ ret = config->init();
if (ret)
goto err_free_partitions;
}
- dev_dbg(sram->dev, "SRAM pool: %zu KiB @ 0x%p\n",
- gen_pool_size(sram->pool) / 1024, sram->virt_base);
+ if (sram->pool)
+ dev_dbg(sram->dev, "SRAM pool: %zu KiB @ 0x%p\n",
+ gen_pool_size(sram->pool) / 1024, sram->virt_base);
return 0;
@@ -405,7 +448,7 @@ static int sram_remove(struct platform_device *pdev)
sram_free_partitions(sram);
- if (gen_pool_avail(sram->pool) < gen_pool_size(sram->pool))
+ if (sram->pool && gen_pool_avail(sram->pool) < gen_pool_size(sram->pool))
dev_err(sram->dev, "removed while SRAM allocated\n");
if (sram->clk)
diff --git a/drivers/misc/sram.h b/drivers/misc/sram.h
index 9c1d21ff7347..d2058d8c8f1d 100644
--- a/drivers/misc/sram.h
+++ b/drivers/misc/sram.h
@@ -5,6 +5,11 @@
#ifndef __SRAM_H
#define __SRAM_H
+struct sram_config {
+ int (*init)(void);
+ bool map_only_reserved;
+};
+
struct sram_partition {
void __iomem *base;
@@ -15,8 +20,11 @@ struct sram_partition {
};
struct sram_dev {
+ const struct sram_config *config;
+
struct device *dev;
void __iomem *virt_base;
+ bool no_memory_wc;
struct gen_pool *pool;
struct clk *clk;
@@ -29,6 +37,7 @@ struct sram_reserve {
struct list_head list;
u32 start;
u32 size;
+ struct resource res;
bool export;
bool pool;
bool protect_exec;
diff --git a/drivers/misc/tifm_core.c b/drivers/misc/tifm_core.c
index 667e574a7df2..52656fc87e99 100644
--- a/drivers/misc/tifm_core.c
+++ b/drivers/misc/tifm_core.c
@@ -87,7 +87,7 @@ static void tifm_dummy_event(struct tifm_dev *sock)
return;
}
-static int tifm_device_remove(struct device *dev)
+static void tifm_device_remove(struct device *dev)
{
struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev);
struct tifm_driver *drv = container_of(dev->driver, struct tifm_driver,
@@ -101,7 +101,6 @@ static int tifm_device_remove(struct device *dev)
}
put_device(dev);
- return 0;
}
#ifdef CONFIG_PM
diff --git a/drivers/misc/vmw_vmci/vmci_queue_pair.c b/drivers/misc/vmw_vmci/vmci_queue_pair.c
index 880c33ab9f47..94ebf7f3fd58 100644
--- a/drivers/misc/vmw_vmci/vmci_queue_pair.c
+++ b/drivers/misc/vmw_vmci/vmci_queue_pair.c
@@ -2243,7 +2243,8 @@ int vmci_qp_broker_map(struct vmci_handle handle,
result = VMCI_SUCCESS;
- if (context_id != VMCI_HOST_CONTEXT_ID) {
+ if (context_id != VMCI_HOST_CONTEXT_ID &&
+ !QPBROKERSTATE_HAS_MEM(entry)) {
struct vmci_qp_page_store page_store;
page_store.pages = guest_mem;
@@ -2350,7 +2351,8 @@ int vmci_qp_broker_unmap(struct vmci_handle handle,
goto out;
}
- if (context_id != VMCI_HOST_CONTEXT_ID) {
+ if (context_id != VMCI_HOST_CONTEXT_ID &&
+ QPBROKERSTATE_HAS_MEM(entry)) {
qp_acquire_queue_mutex(entry->produce_q);
result = qp_save_headers(entry);
if (result < VMCI_SUCCESS)