0001
0002
0003
0004
0005
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
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
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");