1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * s390 PTP clock driver 4 * 5 */ 6 7 #include "ptp_private.h" 8 #include <linux/time.h> 9 #include <asm/stp.h> 10 11 static struct ptp_clock *ptp_stcke_clock, *ptp_qpt_clock; 12 13 static int ptp_s390_adjfine(struct ptp_clock_info *ptp, long scaled_ppm) 14 { 15 return -EOPNOTSUPP; 16 } 17 18 static int ptp_s390_adjtime(struct ptp_clock_info *ptp, s64 delta) 19 { 20 return -EOPNOTSUPP; 21 } 22 23 static struct timespec64 eitod_to_timespec64(union tod_clock *clk) 24 { 25 return ns_to_timespec64(eitod_to_ns(clk->eitod - TOD_UNIX_EPOCH)); 26 } 27 28 static struct timespec64 tod_to_timespec64(unsigned long tod) 29 { 30 return ns_to_timespec64(tod_to_ns(tod - TOD_UNIX_EPOCH)); 31 } 32 33 static int ptp_s390_stcke_gettime(struct ptp_clock_info *ptp, 34 struct timespec64 *ts) 35 { 36 union tod_clock tod; 37 38 if (!stp_enabled()) 39 return -EOPNOTSUPP; 40 41 store_tod_clock_ext(&tod); 42 *ts = eitod_to_timespec64(&tod); 43 return 0; 44 } 45 46 static int ptp_s390_qpt_gettime(struct ptp_clock_info *ptp, 47 struct timespec64 *ts) 48 { 49 unsigned long tod; 50 51 ptff(&tod, sizeof(tod), PTFF_QPT); 52 *ts = tod_to_timespec64(tod); 53 return 0; 54 } 55 56 static int ptp_s390_settime(struct ptp_clock_info *ptp, 57 const struct timespec64 *ts) 58 { 59 return -EOPNOTSUPP; 60 } 61 62 static int s390_arch_ptp_get_crosststamp(ktime_t *device_time, 63 struct system_counterval_t *system_counter, 64 void *ctx) 65 { 66 union tod_clock clk; 67 68 store_tod_clock_ext(&clk); 69 *device_time = ns_to_ktime(tod_to_ns(clk.tod - TOD_UNIX_EPOCH)); 70 system_counter->cycles = clk.tod; 71 system_counter->cs_id = CSID_S390_TOD; 72 return 0; 73 } 74 75 static int ptp_s390_getcrosststamp(struct ptp_clock_info *ptp, 76 struct system_device_crosststamp *xtstamp) 77 { 78 if (!stp_enabled()) 79 return -EOPNOTSUPP; 80 return get_device_system_crosststamp(s390_arch_ptp_get_crosststamp, NULL, NULL, xtstamp); 81 } 82 83 static struct ptp_clock_info ptp_s390_stcke_info = { 84 .owner = THIS_MODULE, 85 .name = "s390 STCKE Clock", 86 .max_adj = 0, 87 .adjfine = ptp_s390_adjfine, 88 .adjtime = ptp_s390_adjtime, 89 .gettime64 = ptp_s390_stcke_gettime, 90 .settime64 = ptp_s390_settime, 91 .getcrosststamp = ptp_s390_getcrosststamp, 92 }; 93 94 static struct ptp_clock_info ptp_s390_qpt_info = { 95 .owner = THIS_MODULE, 96 .name = "s390 Physical Clock", 97 .max_adj = 0, 98 .adjfine = ptp_s390_adjfine, 99 .adjtime = ptp_s390_adjtime, 100 .gettime64 = ptp_s390_qpt_gettime, 101 .settime64 = ptp_s390_settime, 102 }; 103 104 static __init int ptp_s390_init(void) 105 { 106 ptp_stcke_clock = ptp_clock_register(&ptp_s390_stcke_info, NULL); 107 if (IS_ERR(ptp_stcke_clock)) 108 return PTR_ERR(ptp_stcke_clock); 109 110 ptp_qpt_clock = ptp_clock_register(&ptp_s390_qpt_info, NULL); 111 if (IS_ERR(ptp_qpt_clock)) { 112 ptp_clock_unregister(ptp_stcke_clock); 113 return PTR_ERR(ptp_qpt_clock); 114 } 115 return 0; 116 } 117 118 static __exit void ptp_s390_exit(void) 119 { 120 ptp_clock_unregister(ptp_qpt_clock); 121 ptp_clock_unregister(ptp_stcke_clock); 122 } 123 124 module_init(ptp_s390_init); 125 module_exit(ptp_s390_exit); 126 127 MODULE_AUTHOR("Sven Schnelle <svens@linux.ibm.com>"); 128 MODULE_DESCRIPTION("s390 Physical/STCKE Clock PtP Driver"); 129 MODULE_LICENSE("GPL"); 130