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