#include <linux/vmalloc.h>
#include <linux/mm.h>
#include <linux/clockchips.h>
-
+ #include <linux/hyperv.h>
-#ifdef CONFIG_X86_64
+#ifdef CONFIG_HYPERV_TSCPAGE
static struct ms_hyperv_tsc_page *tsc_pg;
chip->flags |= TPM_CHIP_FLAG_VIRTUAL;
cdev_init(&chip->cdev, &tpm_fops);
+ cdev_init(&chip->cdevs, &tpmrm_fops);
chip->cdev.owner = THIS_MODULE;
- chip->cdev.kobj.parent = &chip->dev.kobj;
- chip->cdevs.kobj.parent = &chip->devs.kobj;
+ chip->cdevs.owner = THIS_MODULE;
+
+ chip->work_space.context_buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!chip->work_space.context_buf) {
+ rc = -ENOMEM;
+ goto out;
+ }
+ chip->work_space.session_buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!chip->work_space.session_buf) {
+ rc = -ENOMEM;
+ goto out;
+ }
+ chip->locality = -1;
return chip;
out:
{
int rc;
- rc = cdev_add(&chip->cdev, chip->dev.devt, 1);
+ rc = cdev_device_add(&chip->cdev, &chip->dev);
if (rc) {
dev_err(&chip->dev,
- "unable to cdev_add() %s, major %d, minor %d, err=%d\n",
+ "unable to cdev_device_add() %s, major %d, minor %d, err=%d\n",
dev_name(&chip->dev), MAJOR(chip->dev.devt),
MINOR(chip->dev.devt), rc);
-
return rc;
}
- rc = device_add(&chip->dev);
- if (rc) {
- dev_err(&chip->dev,
- "unable to device_register() %s, major %d, minor %d, err=%d\n",
- dev_name(&chip->dev), MAJOR(chip->dev.devt),
- MINOR(chip->dev.devt), rc);
-
- cdev_del(&chip->cdev);
- return rc;
- }
-
- if (chip->flags & TPM_CHIP_FLAG_TPM2)
- rc = cdev_add(&chip->cdevs, chip->devs.devt, 1);
- if (rc) {
- dev_err(&chip->dev,
- "unable to cdev_add() %s, major %d, minor %d, err=%d\n",
- dev_name(&chip->devs), MAJOR(chip->devs.devt),
- MINOR(chip->devs.devt), rc);
- return rc;
- }
-
- if (chip->flags & TPM_CHIP_FLAG_TPM2)
- rc = device_add(&chip->devs);
- if (rc) {
- dev_err(&chip->dev,
- "unable to device_register() %s, major %d, minor %d, err=%d\n",
- dev_name(&chip->devs), MAJOR(chip->devs.devt),
- MINOR(chip->devs.devt), rc);
- cdev_del(&chip->cdevs);
- return rc;
++ if (chip->flags & TPM_CHIP_FLAG_TPM2) {
++ rc = cdev_device_add(&chip->cdevs, &chip->devs);
++ if (rc) {
++ dev_err(&chip->devs,
++ "unable to cdev_device_add() %s, major %d, minor %d, err=%d\n",
++ dev_name(&chip->devs), MAJOR(chip->devs.devt),
++ MINOR(chip->devs.devt), rc);
++ return rc;
++ }
+ }
+
/* Make the chip available. */
mutex_lock(&idr_lock);
idr_replace(&dev_nums_idr, chip, chip->dev_num);
{
tpm_del_legacy_sysfs(chip);
tpm_bios_log_teardown(chip);
- if (chip->flags & TPM_CHIP_FLAG_TPM2) {
- cdev_del(&chip->cdevs);
- device_del(&chip->devs);
- }
++ if (chip->flags & TPM_CHIP_FLAG_TPM2)
++ cdev_device_del(&chip->cdevs, &chip->devs);
tpm_del_char_device(chip);
}
EXPORT_SYMBOL_GPL(tpm_chip_unregister);
* upon seeing dax_dev->alive == false.
*/
dax_dev->alive = false;
- synchronize_rcu();
+ synchronize_srcu(&dax_srcu);
unmap_mapping_range(dax_dev->inode->i_mapping, 0, 0, 1);
- cdev_del(cdev);
- device_unregister(dev);
+ }
+
+ static void unregister_dax_dev(void *dev)
+ {
+ struct dax_dev *dax_dev = to_dax_dev(dev);
+
+ dev_dbg(dev, "%s\n", __func__);
+
+ kill_dax_dev(dax_dev);
+ cdev_device_del(&dax_dev->cdev, dev);
+ put_device(dev);
}
struct dax_dev *devm_create_dax_dev(struct dax_region *dax_region,
--- /dev/null
-#include <asm/e820.h>
+ /*
+ * memconsole-x86-legacy.c
+ *
+ * EBDA specific parts of the memory based BIOS console.
+ *
+ * Copyright 2017 Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License v2.0 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+ #include <linux/kernel.h>
+ #include <linux/module.h>
+ #include <linux/dmi.h>
+ #include <linux/mm.h>
+ #include <asm/bios_ebda.h>
+ #include <linux/acpi.h>
+
+ #include "memconsole.h"
+
+ #define BIOS_MEMCONSOLE_V1_MAGIC 0xDEADBABE
+ #define BIOS_MEMCONSOLE_V2_MAGIC (('M')|('C'<<8)|('O'<<16)|('N'<<24))
+
+ struct biosmemcon_ebda {
+ u32 signature;
+ union {
+ struct {
+ u8 enabled;
+ u32 buffer_addr;
+ u16 start;
+ u16 end;
+ u16 num_chars;
+ u8 wrapped;
+ } __packed v1;
+ struct {
+ u32 buffer_addr;
+ /* Misdocumented as number of pages! */
+ u16 num_bytes;
+ u16 start;
+ u16 end;
+ } __packed v2;
+ };
+ } __packed;
+
+ static void found_v1_header(struct biosmemcon_ebda *hdr)
+ {
+ pr_info("memconsole: BIOS console v1 EBDA structure found at %p\n",
+ hdr);
+ pr_info("memconsole: BIOS console buffer at 0x%.8x, start = %d, end = %d, num = %d\n",
+ hdr->v1.buffer_addr, hdr->v1.start,
+ hdr->v1.end, hdr->v1.num_chars);
+
+ memconsole_setup(phys_to_virt(hdr->v1.buffer_addr), hdr->v1.num_chars);
+ }
+
+ static void found_v2_header(struct biosmemcon_ebda *hdr)
+ {
+ pr_info("memconsole: BIOS console v2 EBDA structure found at %p\n",
+ hdr);
+ pr_info("memconsole: BIOS console buffer at 0x%.8x, start = %d, end = %d, num_bytes = %d\n",
+ hdr->v2.buffer_addr, hdr->v2.start,
+ hdr->v2.end, hdr->v2.num_bytes);
+
+ memconsole_setup(phys_to_virt(hdr->v2.buffer_addr + hdr->v2.start),
+ hdr->v2.end - hdr->v2.start);
+ }
+
+ /*
+ * Search through the EBDA for the BIOS Memory Console, and
+ * set the global variables to point to it. Return true if found.
+ */
+ static bool memconsole_ebda_init(void)
+ {
+ unsigned int address;
+ size_t length, cur;
+
+ address = get_bios_ebda();
+ if (!address) {
+ pr_info("memconsole: BIOS EBDA non-existent.\n");
+ return false;
+ }
+
+ /* EBDA length is byte 0 of EBDA (in KB) */
+ length = *(u8 *)phys_to_virt(address);
+ length <<= 10; /* convert to bytes */
+
+ /*
+ * Search through EBDA for BIOS memory console structure
+ * note: signature is not necessarily dword-aligned
+ */
+ for (cur = 0; cur < length; cur++) {
+ struct biosmemcon_ebda *hdr = phys_to_virt(address + cur);
+
+ /* memconsole v1 */
+ if (hdr->signature == BIOS_MEMCONSOLE_V1_MAGIC) {
+ found_v1_header(hdr);
+ return true;
+ }
+
+ /* memconsole v2 */
+ if (hdr->signature == BIOS_MEMCONSOLE_V2_MAGIC) {
+ found_v2_header(hdr);
+ return true;
+ }
+ }
+
+ pr_info("memconsole: BIOS console EBDA structure not found!\n");
+ return false;
+ }
+
+ static struct dmi_system_id memconsole_dmi_table[] __initdata = {
+ {
+ .ident = "Google Board",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "Google, Inc."),
+ },
+ },
+ {}
+ };
+ MODULE_DEVICE_TABLE(dmi, memconsole_dmi_table);
+
+ static bool __init memconsole_find(void)
+ {
+ if (!dmi_check_system(memconsole_dmi_table))
+ return false;
+
+ return memconsole_ebda_init();
+ }
+
+ static int __init memconsole_x86_init(void)
+ {
+ if (!memconsole_find())
+ return -ENODEV;
+
+ return memconsole_sysfs_init();
+ }
+
+ static void __exit memconsole_x86_exit(void)
+ {
+ memconsole_exit();
+ }
+
+ module_init(memconsole_x86_init);
+ module_exit(memconsole_x86_exit);
+
+ MODULE_AUTHOR("Google, Inc.");
+ MODULE_LICENSE("GPL");
* No error is set when there is even no header, drivers are
* supposed to analyze buffer_actual_len.
*/
- return ret;
+ return 0;
}
- init_cached_read_index(channel);
+ init_cached_read_index(inring_info);
+
next_read_location = hv_get_next_read_location(inring_info);
next_read_location = hv_copyfrom_ringbuffer(inring_info, &desc,
sizeof(desc),
hv_signal_on_read(channel);
- return ret;
+ return 0;
}
+
+/*
+ * Determine number of bytes available in ring buffer after
+ * the current iterator (priv_read_index) location.
+ *
+ * This is similar to hv_get_bytes_to_read but with private
+ * read index instead.
+ */
+static u32 hv_pkt_iter_avail(const struct hv_ring_buffer_info *rbi)
+{
+ u32 priv_read_loc = rbi->priv_read_index;
+ u32 write_loc = READ_ONCE(rbi->ring_buffer->write_index);
+
+ if (write_loc >= priv_read_loc)
+ return write_loc - priv_read_loc;
+ else
+ return (rbi->ring_datasize - priv_read_loc) + write_loc;
+}
+
+/*
+ * Get first vmbus packet from ring buffer after read_index
+ *
+ * If ring buffer is empty, returns NULL and no other action needed.
+ */
+struct vmpacket_descriptor *hv_pkt_iter_first(struct vmbus_channel *channel)
+{
+ struct hv_ring_buffer_info *rbi = &channel->inbound;
+
+ /* set state for later hv_signal_on_read() */
+ init_cached_read_index(rbi);
+
+ if (hv_pkt_iter_avail(rbi) < sizeof(struct vmpacket_descriptor))
+ return NULL;
+
+ return hv_get_ring_buffer(rbi) + rbi->priv_read_index;
+}
+EXPORT_SYMBOL_GPL(hv_pkt_iter_first);
+
+/*
+ * Get next vmbus packet from ring buffer.
+ *
+ * Advances the current location (priv_read_index) and checks for more
+ * data. If the end of the ring buffer is reached, then return NULL.
+ */
+struct vmpacket_descriptor *
+__hv_pkt_iter_next(struct vmbus_channel *channel,
+ const struct vmpacket_descriptor *desc)
+{
+ struct hv_ring_buffer_info *rbi = &channel->inbound;
+ u32 packetlen = desc->len8 << 3;
+ u32 dsize = rbi->ring_datasize;
+
+ /* bump offset to next potential packet */
+ rbi->priv_read_index += packetlen + VMBUS_PKT_TRAILER;
+ if (rbi->priv_read_index >= dsize)
+ rbi->priv_read_index -= dsize;
+
+ /* more data? */
+ if (hv_pkt_iter_avail(rbi) < sizeof(struct vmpacket_descriptor))
+ return NULL;
+ else
+ return hv_get_ring_buffer(rbi) + rbi->priv_read_index;
+}
+EXPORT_SYMBOL_GPL(__hv_pkt_iter_next);
+
+/*
+ * Update host ring buffer after iterating over packets.
+ */
+void hv_pkt_iter_close(struct vmbus_channel *channel)
+{
+ struct hv_ring_buffer_info *rbi = &channel->inbound;
+
+ /*
+ * Make sure all reads are done before we update the read index since
+ * the writer may start writing to the read area once the read index
+ * is updated.
+ */
+ virt_rmb();
+ rbi->ring_buffer->read_index = rbi->priv_read_index;
+
+ hv_signal_on_read(channel);
+}
+EXPORT_SYMBOL_GPL(hv_pkt_iter_close);
if (NULL == oud)
goto err_retract_minor;
+ /* class device member */
+ device_initialize(&oud->class_dev);
dev_set_drvdata(dev, oud);
oud->minor = minor;
- scsi_device_get(scsi_device);
+ oud->class_dev.devt = MKDEV(SCSI_OSD_MAJOR, oud->minor);
+ oud->class_dev.class = &osd_uld_class;
+ oud->class_dev.parent = dev;
+ oud->class_dev.release = __remove;
+
+ /* hold one more reference to the scsi_device that will get released
+ * in __release, in case a logout is happening while fs is mounted
+ */
++ if (scsi_device_get(scsi_device))
++ goto err_retract_minor;
+ osd_dev_init(&oud->od, scsi_device);
/* allocate a disk and set it up */
/* FIXME: do we need this since sg has already done that */
struct scsi_device *scsi_device = to_scsi_device(dev);
struct osd_uld_device *oud = dev_get_drvdata(dev);
- if (!oud || (oud->od.scsi_device != scsi_device)) {
- OSD_ERR("Half cooked osd-device %p,%p || %p!=%p",
- dev, oud, oud ? oud->od.scsi_device : NULL,
- scsi_device);
+ if (oud->od.scsi_device != scsi_device) {
+ OSD_ERR("Half cooked osd-device %p, || %p!=%p",
+ dev, oud->od.scsi_device, scsi_device);
}
- device_unregister(&oud->class_dev);
-
+ cdev_device_del(&oud->cdev, &oud->class_dev);
+ ida_remove(&osd_minor_ida, oud->minor);
put_device(&oud->class_dev);
+
return 0;
}
cached_write_sz = hv_get_cached_bytes_to_write(rbi);
if (cached_write_sz < pending_sz)
vmbus_setevent(channel);
-
- return;
}
-static inline void
-init_cached_read_index(struct vmbus_channel *channel)
-{
- struct hv_ring_buffer_info *rbi = &channel->inbound;
-
- rbi->cached_read_index = rbi->ring_buffer->read_index;
-}
-
/*
* Mask off host interrupt callback notifications
*/