Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
0002 /*
0003  * Copyright (C) 2020 VMware, Inc., Palo Alto, CA., USA
0004  *
0005  * PTP clock driver for VMware precision clock virtual device.
0006  */
0007 
0008 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0009 
0010 #include <linux/acpi.h>
0011 #include <linux/kernel.h>
0012 #include <linux/module.h>
0013 #include <linux/ptp_clock_kernel.h>
0014 #include <asm/hypervisor.h>
0015 #include <asm/vmware.h>
0016 
0017 #define VMWARE_MAGIC 0x564D5868
0018 #define VMWARE_CMD_PCLK(nr) ((nr << 16) | 97)
0019 #define VMWARE_CMD_PCLK_GETTIME VMWARE_CMD_PCLK(0)
0020 
0021 static struct acpi_device *ptp_vmw_acpi_device;
0022 static struct ptp_clock *ptp_vmw_clock;
0023 
0024 
0025 static int ptp_vmw_pclk_read(u64 *ns)
0026 {
0027     u32 ret, nsec_hi, nsec_lo, unused1, unused2, unused3;
0028 
0029     asm volatile (VMWARE_HYPERCALL :
0030         "=a"(ret), "=b"(nsec_hi), "=c"(nsec_lo), "=d"(unused1),
0031         "=S"(unused2), "=D"(unused3) :
0032         "a"(VMWARE_MAGIC), "b"(0),
0033         "c"(VMWARE_CMD_PCLK_GETTIME), "d"(0) :
0034         "memory");
0035 
0036     if (ret == 0)
0037         *ns = ((u64)nsec_hi << 32) | nsec_lo;
0038     return ret;
0039 }
0040 
0041 /*
0042  * PTP clock ops.
0043  */
0044 
0045 static int ptp_vmw_adjtime(struct ptp_clock_info *info, s64 delta)
0046 {
0047     return -EOPNOTSUPP;
0048 }
0049 
0050 static int ptp_vmw_adjfreq(struct ptp_clock_info *info, s32 delta)
0051 {
0052     return -EOPNOTSUPP;
0053 }
0054 
0055 static int ptp_vmw_gettime(struct ptp_clock_info *info, struct timespec64 *ts)
0056 {
0057     u64 ns;
0058 
0059     if (ptp_vmw_pclk_read(&ns) != 0)
0060         return -EIO;
0061     *ts = ns_to_timespec64(ns);
0062     return 0;
0063 }
0064 
0065 static int ptp_vmw_settime(struct ptp_clock_info *info,
0066               const struct timespec64 *ts)
0067 {
0068     return -EOPNOTSUPP;
0069 }
0070 
0071 static int ptp_vmw_enable(struct ptp_clock_info *info,
0072              struct ptp_clock_request *request, int on)
0073 {
0074     return -EOPNOTSUPP;
0075 }
0076 
0077 static struct ptp_clock_info ptp_vmw_clock_info = {
0078     .owner      = THIS_MODULE,
0079     .name       = "ptp_vmw",
0080     .max_adj    = 0,
0081     .adjtime    = ptp_vmw_adjtime,
0082     .adjfreq    = ptp_vmw_adjfreq,
0083     .gettime64  = ptp_vmw_gettime,
0084     .settime64  = ptp_vmw_settime,
0085     .enable     = ptp_vmw_enable,
0086 };
0087 
0088 /*
0089  * ACPI driver ops for VMware "precision clock" virtual device.
0090  */
0091 
0092 static int ptp_vmw_acpi_add(struct acpi_device *device)
0093 {
0094     ptp_vmw_clock = ptp_clock_register(&ptp_vmw_clock_info, NULL);
0095     if (IS_ERR(ptp_vmw_clock)) {
0096         pr_err("failed to register ptp clock\n");
0097         return PTR_ERR(ptp_vmw_clock);
0098     }
0099 
0100     ptp_vmw_acpi_device = device;
0101     return 0;
0102 }
0103 
0104 static int ptp_vmw_acpi_remove(struct acpi_device *device)
0105 {
0106     ptp_clock_unregister(ptp_vmw_clock);
0107     return 0;
0108 }
0109 
0110 static const struct acpi_device_id ptp_vmw_acpi_device_ids[] = {
0111     { "VMW0005", 0 },
0112     { "", 0 },
0113 };
0114 
0115 MODULE_DEVICE_TABLE(acpi, ptp_vmw_acpi_device_ids);
0116 
0117 static struct acpi_driver ptp_vmw_acpi_driver = {
0118     .name = "ptp_vmw",
0119     .ids = ptp_vmw_acpi_device_ids,
0120     .ops = {
0121         .add = ptp_vmw_acpi_add,
0122         .remove = ptp_vmw_acpi_remove
0123     },
0124     .owner  = THIS_MODULE
0125 };
0126 
0127 static int __init ptp_vmw_init(void)
0128 {
0129     if (x86_hyper_type != X86_HYPER_VMWARE)
0130         return -1;
0131     return acpi_bus_register_driver(&ptp_vmw_acpi_driver);
0132 }
0133 
0134 static void __exit ptp_vmw_exit(void)
0135 {
0136     acpi_bus_unregister_driver(&ptp_vmw_acpi_driver);
0137 }
0138 
0139 module_init(ptp_vmw_init);
0140 module_exit(ptp_vmw_exit);
0141 
0142 MODULE_DESCRIPTION("VMware virtual PTP clock driver");
0143 MODULE_AUTHOR("VMware, Inc.");
0144 MODULE_LICENSE("Dual BSD/GPL");