1#!/usr/bin/env python3 2# SPDX-License-Identifier: GPL-2.0 3# pylint: disable=locally-disabled, invalid-name, attribute-defined-outside-init, too-few-public-methods 4 5""" 6Tests related to configuration of HW timestamping 7""" 8 9import errno 10import ctypes 11import fcntl 12import socket 13from lib.py import ksft_run, ksft_exit, ksft_ge, ksft_eq, KsftSkipEx 14from lib.py import NetDrvEnv, EthtoolFamily, NlError 15 16 17SIOCSHWTSTAMP = 0x89b0 18SIOCGHWTSTAMP = 0x89b1 19class hwtstamp_config(ctypes.Structure): 20 """ Python copy of struct hwtstamp_config """ 21 _fields_ = [ 22 ("flags", ctypes.c_int), 23 ("tx_type", ctypes.c_int), 24 ("rx_filter", ctypes.c_int), 25 ] 26 27 28class ifreq(ctypes.Structure): 29 """ Python copy of struct ifreq """ 30 _fields_ = [ 31 ("ifr_name", ctypes.c_char * 16), 32 ("ifr_data", ctypes.POINTER(hwtstamp_config)), 33 ] 34 35 36def __get_hwtimestamp_support(cfg): 37 """ Retrieve supported configuration information """ 38 39 try: 40 tsinfo = cfg.ethnl.tsinfo_get({'header': {'dev-name': cfg.ifname}}) 41 except NlError as e: 42 if e.error == errno.EOPNOTSUPP: 43 raise KsftSkipEx("timestamping configuration is not supported") from e 44 raise 45 46 ctx = {} 47 tx = tsinfo.get('tx-types', {}) 48 rx = tsinfo.get('rx-filters', {}) 49 50 bits = tx.get('bits', {}) 51 ctx['tx'] = bits.get('bit', []) 52 bits = rx.get('bits', {}) 53 ctx['rx'] = bits.get('bit', []) 54 return ctx 55 56 57def __get_hwtimestamp_config_ioctl(cfg): 58 """ Retrieve current TS configuration information (via ioctl) """ 59 60 config = hwtstamp_config() 61 62 req = ifreq() 63 req.ifr_name = cfg.ifname.encode() 64 req.ifr_data = ctypes.pointer(config) 65 66 try: 67 sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 68 fcntl.ioctl(sock.fileno(), SIOCGHWTSTAMP, req) 69 sock.close() 70 71 except OSError as e: 72 if e.errno == errno.EOPNOTSUPP: 73 raise KsftSkipEx("timestamping configuration is not supported via ioctl") from e 74 raise 75 return config 76 77 78def __get_hwtimestamp_config(cfg): 79 """ Retrieve current TS configuration information (via netLink) """ 80 81 try: 82 tscfg = cfg.ethnl.tsconfig_get({'header': {'dev-name': cfg.ifname}}) 83 except NlError as e: 84 if e.error == errno.EOPNOTSUPP: 85 raise KsftSkipEx("timestamping configuration is not supported via netlink") from e 86 raise 87 return tscfg 88 89 90def __set_hwtimestamp_config_ioctl(cfg, ts): 91 """ Setup new TS configuration information (via ioctl) """ 92 config = hwtstamp_config() 93 config.rx_filter = ts['rx-filters']['bits']['bit'][0]['index'] 94 config.tx_type = ts['tx-types']['bits']['bit'][0]['index'] 95 req = ifreq() 96 req.ifr_name = cfg.ifname.encode() 97 req.ifr_data = ctypes.pointer(config) 98 try: 99 sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 100 fcntl.ioctl(sock.fileno(), SIOCSHWTSTAMP, req) 101 sock.close() 102 103 except OSError as e: 104 if e.errno == errno.EOPNOTSUPP: 105 raise KsftSkipEx("timestamping configuration is not supported via ioctl") from e 106 raise 107 108 109def __set_hwtimestamp_config(cfg, ts): 110 """ Setup new TS configuration information (via netlink) """ 111 112 ts['header'] = {'dev-name': cfg.ifname} 113 try: 114 res = cfg.ethnl.tsconfig_set(ts) 115 except NlError as e: 116 if e.error == errno.EOPNOTSUPP: 117 raise KsftSkipEx("timestamping configuration is not supported via netlink") from e 118 raise 119 return res 120 121 122def __perform_hwtstamp_tx(cfg, is_ioctl): 123 """ 124 Test TX timestamp configuration via either netlink or ioctl. 125 The driver should apply provided config and report back proper state. 126 """ 127 128 orig_tscfg = __get_hwtimestamp_config(cfg) 129 ts = __get_hwtimestamp_support(cfg) 130 tx = ts['tx'] 131 for t in tx: 132 res = None 133 tscfg = orig_tscfg 134 tscfg['tx-types']['bits']['bit'] = [t] 135 if is_ioctl: 136 __set_hwtimestamp_config_ioctl(cfg, tscfg) 137 else: 138 res = __set_hwtimestamp_config(cfg, tscfg) 139 if res is None: 140 res = __get_hwtimestamp_config(cfg) 141 resioctl = __get_hwtimestamp_config_ioctl(cfg) 142 ksft_eq(res['tx-types']['bits']['bit'], [t]) 143 ksft_eq(resioctl.tx_type, t['index']) 144 __set_hwtimestamp_config(cfg, orig_tscfg) 145 146def test_hwtstamp_tx_netlink(cfg): 147 """ 148 Test TX timestamp configuration setup via netlink. 149 The driver should apply provided config and report back proper state. 150 """ 151 __perform_hwtstamp_tx(cfg, False) 152 153 154def test_hwtstamp_tx_ioctl(cfg): 155 """ 156 Test TX timestamp configuration setup via ioctl. 157 The driver should apply provided config and report back proper state. 158 """ 159 __perform_hwtstamp_tx(cfg, True) 160 161 162def __perform_hwtstamp_rx(cfg, is_ioctl): 163 """ 164 Test RX timestamp configuration. 165 The filter configuration is taken from the list of supported filters. 166 The driver should apply the config without error and report back proper state. 167 Some extension of the timestamping scope is allowed for PTP filters. 168 """ 169 170 orig_tscfg = __get_hwtimestamp_config(cfg) 171 ts = __get_hwtimestamp_support(cfg) 172 rx = ts['rx'] 173 for r in rx: 174 res = None 175 tscfg = orig_tscfg 176 tscfg['rx-filters']['bits']['bit'] = [r] 177 if is_ioctl: 178 __set_hwtimestamp_config_ioctl(cfg, tscfg) 179 else: 180 res = __set_hwtimestamp_config(cfg, tscfg) 181 if res is None: 182 res = __get_hwtimestamp_config(cfg) 183 resioctl = __get_hwtimestamp_config_ioctl(cfg) 184 ksft_eq(resioctl.rx_filter, res['rx-filters']['bits']['bit'][0]['index']) 185 if r['index'] == 0 or r['index'] == 1: 186 ksft_eq(res['rx-filters']['bits']['bit'][0]['index'], r['index']) 187 else: 188 # the driver can fallback to some value which has higher coverage for timestamping 189 ksft_ge(res['rx-filters']['bits']['bit'][0]['index'], r['index']) 190 __set_hwtimestamp_config(cfg, orig_tscfg) 191 192 193def test_hwtstamp_rx_netlink(cfg): 194 """ 195 Test RX timestamp configuration via netlink. 196 The filter configuration is taken from the list of supported filters. 197 The driver should apply the config without error and report back proper state. 198 Some extension of the timestamping scope is allowed for PTP filters. 199 """ 200 __perform_hwtstamp_rx(cfg, False) 201 202 203def test_hwtstamp_rx_ioctl(cfg): 204 """ 205 Test RX timestamp configuration via ioctl. 206 The filter configuration is taken from the list of supported filters. 207 The driver should apply the config without error and report back proper state. 208 Some extension of the timestamping scope is allowed for PTP filters. 209 """ 210 __perform_hwtstamp_rx(cfg, True) 211 212 213def main() -> None: 214 """ Ksft boiler plate main """ 215 216 with NetDrvEnv(__file__, nsim_test=False) as cfg: 217 cfg.ethnl = EthtoolFamily() 218 ksft_run([test_hwtstamp_tx_ioctl, test_hwtstamp_tx_netlink, 219 test_hwtstamp_rx_ioctl, test_hwtstamp_rx_netlink], 220 args=(cfg,)) 221 ksft_exit() 222 223 224if __name__ == "__main__": 225 main() 226