xref: /linux/drivers/net/ethernet/mellanox/mlx4/en_clock.c (revision 79790b6818e96c58fe2bffee1b418c16e64e7b80)
1ec693d47SAmir Vadai /*
2ec693d47SAmir Vadai  * Copyright (c) 2012 Mellanox Technologies. All rights reserved.
3ec693d47SAmir Vadai  *
4ec693d47SAmir Vadai  * This software is available to you under a choice of one of two
5ec693d47SAmir Vadai  * licenses.  You may choose to be licensed under the terms of the GNU
6ec693d47SAmir Vadai  * General Public License (GPL) Version 2, available from the file
7ec693d47SAmir Vadai  * COPYING in the main directory of this source tree, or the
8ec693d47SAmir Vadai  * OpenIB.org BSD license below:
9ec693d47SAmir Vadai  *
10ec693d47SAmir Vadai  *     Redistribution and use in source and binary forms, with or
11ec693d47SAmir Vadai  *     without modification, are permitted provided that the following
12ec693d47SAmir Vadai  *     conditions are met:
13ec693d47SAmir Vadai  *
14ec693d47SAmir Vadai  *      - Redistributions of source code must retain the above
15ec693d47SAmir Vadai  *        copyright notice, this list of conditions and the following
16ec693d47SAmir Vadai  *        disclaimer.
17ec693d47SAmir Vadai  *
18ec693d47SAmir Vadai  *      - Redistributions in binary form must reproduce the above
19ec693d47SAmir Vadai  *        copyright notice, this list of conditions and the following
20ec693d47SAmir Vadai  *        disclaimer in the documentation and/or other materials
21ec693d47SAmir Vadai  *        provided with the distribution.
22ec693d47SAmir Vadai  *
23ec693d47SAmir Vadai  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24ec693d47SAmir Vadai  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25ec693d47SAmir Vadai  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26ec693d47SAmir Vadai  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27ec693d47SAmir Vadai  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28ec693d47SAmir Vadai  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29ec693d47SAmir Vadai  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30ec693d47SAmir Vadai  * SOFTWARE.
31ec693d47SAmir Vadai  *
32ec693d47SAmir Vadai  */
33ec693d47SAmir Vadai 
34ec693d47SAmir Vadai #include <linux/mlx4/device.h>
35d9f39373SRichard Cochran #include <linux/clocksource.h>
36ec693d47SAmir Vadai 
37ec693d47SAmir Vadai #include "mlx4_en.h"
38ec693d47SAmir Vadai 
39ec693d47SAmir Vadai /* mlx4_en_read_clock - read raw cycle counter (to be used by time counter)
40ec693d47SAmir Vadai  */
mlx4_en_read_clock(const struct cyclecounter * tc)41a5a1d1c2SThomas Gleixner static u64 mlx4_en_read_clock(const struct cyclecounter *tc)
42ec693d47SAmir Vadai {
43ec693d47SAmir Vadai 	struct mlx4_en_dev *mdev =
44ec693d47SAmir Vadai 		container_of(tc, struct mlx4_en_dev, cycles);
45ec693d47SAmir Vadai 	struct mlx4_dev *dev = mdev->dev;
46ec693d47SAmir Vadai 
47ec693d47SAmir Vadai 	return mlx4_read_clock(dev) & tc->mask;
48ec693d47SAmir Vadai }
49ec693d47SAmir Vadai 
mlx4_en_get_cqe_ts(struct mlx4_cqe * cqe)50ec693d47SAmir Vadai u64 mlx4_en_get_cqe_ts(struct mlx4_cqe *cqe)
51ec693d47SAmir Vadai {
52ec693d47SAmir Vadai 	u64 hi, lo;
53ec693d47SAmir Vadai 	struct mlx4_ts_cqe *ts_cqe = (struct mlx4_ts_cqe *)cqe;
54ec693d47SAmir Vadai 
55ec693d47SAmir Vadai 	lo = (u64)be16_to_cpu(ts_cqe->timestamp_lo);
56ec693d47SAmir Vadai 	hi = ((u64)be32_to_cpu(ts_cqe->timestamp_hi) + !lo) << 16;
57ec693d47SAmir Vadai 
58ec693d47SAmir Vadai 	return hi | lo;
59ec693d47SAmir Vadai }
60ec693d47SAmir Vadai 
mlx4_en_get_hwtstamp(struct mlx4_en_dev * mdev,u64 timestamp)61ab46182dSStanislav Fomichev u64 mlx4_en_get_hwtstamp(struct mlx4_en_dev *mdev, u64 timestamp)
62ec693d47SAmir Vadai {
6399f5711eSEric Dumazet 	unsigned int seq;
64ec693d47SAmir Vadai 	u64 nsec;
65ec693d47SAmir Vadai 
6699f5711eSEric Dumazet 	do {
6799f5711eSEric Dumazet 		seq = read_seqbegin(&mdev->clock_lock);
68ec693d47SAmir Vadai 		nsec = timecounter_cyc2time(&mdev->clock, timestamp);
6999f5711eSEric Dumazet 	} while (read_seqretry(&mdev->clock_lock, seq));
70ec693d47SAmir Vadai 
71ab46182dSStanislav Fomichev 	return ns_to_ktime(nsec);
72ab46182dSStanislav Fomichev }
73ab46182dSStanislav Fomichev 
mlx4_en_fill_hwtstamps(struct mlx4_en_dev * mdev,struct skb_shared_hwtstamps * hwts,u64 timestamp)74ab46182dSStanislav Fomichev void mlx4_en_fill_hwtstamps(struct mlx4_en_dev *mdev,
75ab46182dSStanislav Fomichev 			    struct skb_shared_hwtstamps *hwts,
76ab46182dSStanislav Fomichev 			    u64 timestamp)
77ab46182dSStanislav Fomichev {
78ec693d47SAmir Vadai 	memset(hwts, 0, sizeof(struct skb_shared_hwtstamps));
79ab46182dSStanislav Fomichev 	hwts->hwtstamp = mlx4_en_get_hwtstamp(mdev, timestamp);
80ec693d47SAmir Vadai }
81ec693d47SAmir Vadai 
82ad7d4eaeSShawn Bohrer /**
83ad7d4eaeSShawn Bohrer  * mlx4_en_remove_timestamp - disable PTP device
84ad7d4eaeSShawn Bohrer  * @mdev: board private structure
85ad7d4eaeSShawn Bohrer  *
86ad7d4eaeSShawn Bohrer  * Stop the PTP support.
87ad7d4eaeSShawn Bohrer  **/
mlx4_en_remove_timestamp(struct mlx4_en_dev * mdev)88ad7d4eaeSShawn Bohrer void mlx4_en_remove_timestamp(struct mlx4_en_dev *mdev)
89ad7d4eaeSShawn Bohrer {
90ad7d4eaeSShawn Bohrer 	if (mdev->ptp_clock) {
91ad7d4eaeSShawn Bohrer 		ptp_clock_unregister(mdev->ptp_clock);
92ad7d4eaeSShawn Bohrer 		mdev->ptp_clock = NULL;
93ad7d4eaeSShawn Bohrer 		mlx4_info(mdev, "removed PHC\n");
94ad7d4eaeSShawn Bohrer 	}
95ad7d4eaeSShawn Bohrer }
96ad7d4eaeSShawn Bohrer 
9747d3a075SEric Dumazet #define MLX4_EN_WRAP_AROUND_SEC	10UL
9847d3a075SEric Dumazet /* By scheduling the overflow check every 5 seconds, we have a reasonably
99*6cc9c6fbSSimon Horman  * good chance we won't miss a wrap around.
100*6cc9c6fbSSimon Horman  * TODO: Use a timer instead of a work queue to increase the guarantee.
10147d3a075SEric Dumazet  */
10247d3a075SEric Dumazet #define MLX4_EN_OVERFLOW_PERIOD (MLX4_EN_WRAP_AROUND_SEC * HZ / 2)
10347d3a075SEric Dumazet 
mlx4_en_ptp_overflow_check(struct mlx4_en_dev * mdev)104ad7d4eaeSShawn Bohrer void mlx4_en_ptp_overflow_check(struct mlx4_en_dev *mdev)
105ad7d4eaeSShawn Bohrer {
106ad7d4eaeSShawn Bohrer 	bool timeout = time_is_before_jiffies(mdev->last_overflow_check +
10747d3a075SEric Dumazet 					      MLX4_EN_OVERFLOW_PERIOD);
108ad7d4eaeSShawn Bohrer 	unsigned long flags;
109ad7d4eaeSShawn Bohrer 
110ad7d4eaeSShawn Bohrer 	if (timeout) {
11199f5711eSEric Dumazet 		write_seqlock_irqsave(&mdev->clock_lock, flags);
112ad7d4eaeSShawn Bohrer 		timecounter_read(&mdev->clock);
11399f5711eSEric Dumazet 		write_sequnlock_irqrestore(&mdev->clock_lock, flags);
114ad7d4eaeSShawn Bohrer 		mdev->last_overflow_check = jiffies;
115ad7d4eaeSShawn Bohrer 	}
116ad7d4eaeSShawn Bohrer }
117ad7d4eaeSShawn Bohrer 
118ad7d4eaeSShawn Bohrer /**
1196ed79596SJacob Keller  * mlx4_en_phc_adjfine - adjust the frequency of the hardware clock
120ad7d4eaeSShawn Bohrer  * @ptp: ptp clock structure
1216ed79596SJacob Keller  * @scaled_ppm: Desired frequency change in scaled parts per million
122ad7d4eaeSShawn Bohrer  *
1236ed79596SJacob Keller  * Adjust the frequency of the PHC cycle counter by the indicated scaled_ppm
1246ed79596SJacob Keller  * from the base frequency.
1256ed79596SJacob Keller  *
1266ed79596SJacob Keller  * Scaled parts per million is ppm with a 16-bit binary fractional field.
127ad7d4eaeSShawn Bohrer  **/
mlx4_en_phc_adjfine(struct ptp_clock_info * ptp,long scaled_ppm)1286ed79596SJacob Keller static int mlx4_en_phc_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
129ad7d4eaeSShawn Bohrer {
1306ed79596SJacob Keller 	u32 mult;
131ad7d4eaeSShawn Bohrer 	unsigned long flags;
132ad7d4eaeSShawn Bohrer 	struct mlx4_en_dev *mdev = container_of(ptp, struct mlx4_en_dev,
133ad7d4eaeSShawn Bohrer 						ptp_clock_info);
134ad7d4eaeSShawn Bohrer 
1356ed79596SJacob Keller 	mult = (u32)adjust_by_scaled_ppm(mdev->nominal_c_mult, scaled_ppm);
136ad7d4eaeSShawn Bohrer 
13799f5711eSEric Dumazet 	write_seqlock_irqsave(&mdev->clock_lock, flags);
138ad7d4eaeSShawn Bohrer 	timecounter_read(&mdev->clock);
1396ed79596SJacob Keller 	mdev->cycles.mult = mult;
14099f5711eSEric Dumazet 	write_sequnlock_irqrestore(&mdev->clock_lock, flags);
141ad7d4eaeSShawn Bohrer 
142ad7d4eaeSShawn Bohrer 	return 0;
143ad7d4eaeSShawn Bohrer }
144ad7d4eaeSShawn Bohrer 
145ad7d4eaeSShawn Bohrer /**
146ad7d4eaeSShawn Bohrer  * mlx4_en_phc_adjtime - Shift the time of the hardware clock
147ad7d4eaeSShawn Bohrer  * @ptp: ptp clock structure
148ad7d4eaeSShawn Bohrer  * @delta: Desired change in nanoseconds
149ad7d4eaeSShawn Bohrer  *
150ad7d4eaeSShawn Bohrer  * Adjust the timer by resetting the timecounter structure.
151ad7d4eaeSShawn Bohrer  **/
mlx4_en_phc_adjtime(struct ptp_clock_info * ptp,s64 delta)152ad7d4eaeSShawn Bohrer static int mlx4_en_phc_adjtime(struct ptp_clock_info *ptp, s64 delta)
153ad7d4eaeSShawn Bohrer {
154ad7d4eaeSShawn Bohrer 	struct mlx4_en_dev *mdev = container_of(ptp, struct mlx4_en_dev,
155ad7d4eaeSShawn Bohrer 						ptp_clock_info);
156ad7d4eaeSShawn Bohrer 	unsigned long flags;
157ad7d4eaeSShawn Bohrer 
15899f5711eSEric Dumazet 	write_seqlock_irqsave(&mdev->clock_lock, flags);
159ce51ff09SRichard Cochran 	timecounter_adjtime(&mdev->clock, delta);
16099f5711eSEric Dumazet 	write_sequnlock_irqrestore(&mdev->clock_lock, flags);
161ad7d4eaeSShawn Bohrer 
162ad7d4eaeSShawn Bohrer 	return 0;
163ad7d4eaeSShawn Bohrer }
164ad7d4eaeSShawn Bohrer 
165ad7d4eaeSShawn Bohrer /**
166ad7d4eaeSShawn Bohrer  * mlx4_en_phc_gettime - Reads the current time from the hardware clock
167ad7d4eaeSShawn Bohrer  * @ptp: ptp clock structure
168ad7d4eaeSShawn Bohrer  * @ts: timespec structure to hold the current time value
169ad7d4eaeSShawn Bohrer  *
170ad7d4eaeSShawn Bohrer  * Read the timecounter and return the correct value in ns after converting
171ad7d4eaeSShawn Bohrer  * it into a struct timespec.
172ad7d4eaeSShawn Bohrer  **/
mlx4_en_phc_gettime(struct ptp_clock_info * ptp,struct timespec64 * ts)173e394b805SRichard Cochran static int mlx4_en_phc_gettime(struct ptp_clock_info *ptp,
174e394b805SRichard Cochran 			       struct timespec64 *ts)
175ad7d4eaeSShawn Bohrer {
176ad7d4eaeSShawn Bohrer 	struct mlx4_en_dev *mdev = container_of(ptp, struct mlx4_en_dev,
177ad7d4eaeSShawn Bohrer 						ptp_clock_info);
178ad7d4eaeSShawn Bohrer 	unsigned long flags;
179ad7d4eaeSShawn Bohrer 	u64 ns;
180ad7d4eaeSShawn Bohrer 
18199f5711eSEric Dumazet 	write_seqlock_irqsave(&mdev->clock_lock, flags);
182ad7d4eaeSShawn Bohrer 	ns = timecounter_read(&mdev->clock);
18399f5711eSEric Dumazet 	write_sequnlock_irqrestore(&mdev->clock_lock, flags);
184ad7d4eaeSShawn Bohrer 
185f75419c8SRichard Cochran 	*ts = ns_to_timespec64(ns);
186ad7d4eaeSShawn Bohrer 
187ad7d4eaeSShawn Bohrer 	return 0;
188ad7d4eaeSShawn Bohrer }
189ad7d4eaeSShawn Bohrer 
190ad7d4eaeSShawn Bohrer /**
191ad7d4eaeSShawn Bohrer  * mlx4_en_phc_settime - Set the current time on the hardware clock
192ad7d4eaeSShawn Bohrer  * @ptp: ptp clock structure
193ad7d4eaeSShawn Bohrer  * @ts: timespec containing the new time for the cycle counter
194ad7d4eaeSShawn Bohrer  *
195ad7d4eaeSShawn Bohrer  * Reset the timecounter to use a new base value instead of the kernel
196ad7d4eaeSShawn Bohrer  * wall timer value.
197ad7d4eaeSShawn Bohrer  **/
mlx4_en_phc_settime(struct ptp_clock_info * ptp,const struct timespec64 * ts)198ad7d4eaeSShawn Bohrer static int mlx4_en_phc_settime(struct ptp_clock_info *ptp,
199e394b805SRichard Cochran 			       const struct timespec64 *ts)
200ad7d4eaeSShawn Bohrer {
201ad7d4eaeSShawn Bohrer 	struct mlx4_en_dev *mdev = container_of(ptp, struct mlx4_en_dev,
202ad7d4eaeSShawn Bohrer 						ptp_clock_info);
203e394b805SRichard Cochran 	u64 ns = timespec64_to_ns(ts);
204ad7d4eaeSShawn Bohrer 	unsigned long flags;
205ad7d4eaeSShawn Bohrer 
206ad7d4eaeSShawn Bohrer 	/* reset the timecounter */
20799f5711eSEric Dumazet 	write_seqlock_irqsave(&mdev->clock_lock, flags);
208ad7d4eaeSShawn Bohrer 	timecounter_init(&mdev->clock, &mdev->cycles, ns);
20999f5711eSEric Dumazet 	write_sequnlock_irqrestore(&mdev->clock_lock, flags);
210ad7d4eaeSShawn Bohrer 
211ad7d4eaeSShawn Bohrer 	return 0;
212ad7d4eaeSShawn Bohrer }
213ad7d4eaeSShawn Bohrer 
214ad7d4eaeSShawn Bohrer /**
215ad7d4eaeSShawn Bohrer  * mlx4_en_phc_enable - enable or disable an ancillary feature
216ad7d4eaeSShawn Bohrer  * @ptp: ptp clock structure
217ad7d4eaeSShawn Bohrer  * @request: Desired resource to enable or disable
218ad7d4eaeSShawn Bohrer  * @on: Caller passes one to enable or zero to disable
219ad7d4eaeSShawn Bohrer  *
220ad7d4eaeSShawn Bohrer  * Enable (or disable) ancillary features of the PHC subsystem.
221ad7d4eaeSShawn Bohrer  * Currently, no ancillary features are supported.
222ad7d4eaeSShawn Bohrer  **/
mlx4_en_phc_enable(struct ptp_clock_info __always_unused * ptp,struct ptp_clock_request __always_unused * request,int __always_unused on)223ad7d4eaeSShawn Bohrer static int mlx4_en_phc_enable(struct ptp_clock_info __always_unused *ptp,
224ad7d4eaeSShawn Bohrer 			      struct ptp_clock_request __always_unused *request,
225ad7d4eaeSShawn Bohrer 			      int __always_unused on)
226ad7d4eaeSShawn Bohrer {
227ad7d4eaeSShawn Bohrer 	return -EOPNOTSUPP;
228ad7d4eaeSShawn Bohrer }
229ad7d4eaeSShawn Bohrer 
230ad7d4eaeSShawn Bohrer static const struct ptp_clock_info mlx4_en_ptp_clock_info = {
231ad7d4eaeSShawn Bohrer 	.owner		= THIS_MODULE,
232ad7d4eaeSShawn Bohrer 	.max_adj	= 100000000,
233ad7d4eaeSShawn Bohrer 	.n_alarm	= 0,
234ad7d4eaeSShawn Bohrer 	.n_ext_ts	= 0,
235ad7d4eaeSShawn Bohrer 	.n_per_out	= 0,
2364986b4f0SRichard Cochran 	.n_pins		= 0,
237ad7d4eaeSShawn Bohrer 	.pps		= 0,
2386ed79596SJacob Keller 	.adjfine	= mlx4_en_phc_adjfine,
239ad7d4eaeSShawn Bohrer 	.adjtime	= mlx4_en_phc_adjtime,
240e394b805SRichard Cochran 	.gettime64	= mlx4_en_phc_gettime,
241e394b805SRichard Cochran 	.settime64	= mlx4_en_phc_settime,
242ad7d4eaeSShawn Bohrer 	.enable		= mlx4_en_phc_enable,
243ad7d4eaeSShawn Bohrer };
244ad7d4eaeSShawn Bohrer 
24531c128b6SEugenia Emantayev 
24631c128b6SEugenia Emantayev /* This function calculates the max shift that enables the user range
24731c128b6SEugenia Emantayev  * of MLX4_EN_WRAP_AROUND_SEC values in the cycles register.
24831c128b6SEugenia Emantayev  */
freq_to_shift(u16 freq)24931c128b6SEugenia Emantayev static u32 freq_to_shift(u16 freq)
25031c128b6SEugenia Emantayev {
25131c128b6SEugenia Emantayev 	u32 freq_khz = freq * 1000;
25231c128b6SEugenia Emantayev 	u64 max_val_cycles = freq_khz * 1000 * MLX4_EN_WRAP_AROUND_SEC;
25361b6034cSSlava Shwartsman 	u64 max_val_cycles_rounded = 1ULL << fls64(max_val_cycles - 1);
25431c128b6SEugenia Emantayev 	/* calculate max possible multiplier in order to fit in 64bit */
25561b6034cSSlava Shwartsman 	u64 max_mul = div64_u64(ULLONG_MAX, max_val_cycles_rounded);
25631c128b6SEugenia Emantayev 
25731c128b6SEugenia Emantayev 	/* This comes from the reverse of clocksource_khz2mult */
25831c128b6SEugenia Emantayev 	return ilog2(div_u64(max_mul * freq_khz, 1000000));
25931c128b6SEugenia Emantayev }
26031c128b6SEugenia Emantayev 
mlx4_en_init_timestamp(struct mlx4_en_dev * mdev)261ec693d47SAmir Vadai void mlx4_en_init_timestamp(struct mlx4_en_dev *mdev)
262ec693d47SAmir Vadai {
263ec693d47SAmir Vadai 	struct mlx4_dev *dev = mdev->dev;
264ad7d4eaeSShawn Bohrer 	unsigned long flags;
265ec693d47SAmir Vadai 
26690683061SEugenia Emantayev 	/* mlx4_en_init_timestamp is called for each netdev.
26790683061SEugenia Emantayev 	 * mdev->ptp_clock is common for all ports, skip initialization if
26890683061SEugenia Emantayev 	 * was done for other port.
26990683061SEugenia Emantayev 	 */
27090683061SEugenia Emantayev 	if (mdev->ptp_clock)
27190683061SEugenia Emantayev 		return;
27290683061SEugenia Emantayev 
27399f5711eSEric Dumazet 	seqlock_init(&mdev->clock_lock);
274ad7d4eaeSShawn Bohrer 
275ec693d47SAmir Vadai 	memset(&mdev->cycles, 0, sizeof(mdev->cycles));
276ec693d47SAmir Vadai 	mdev->cycles.read = mlx4_en_read_clock;
277ec693d47SAmir Vadai 	mdev->cycles.mask = CLOCKSOURCE_MASK(48);
27831c128b6SEugenia Emantayev 	mdev->cycles.shift = freq_to_shift(dev->caps.hca_core_clock);
279ec693d47SAmir Vadai 	mdev->cycles.mult =
280ec693d47SAmir Vadai 		clocksource_khz2mult(1000 * dev->caps.hca_core_clock, mdev->cycles.shift);
281ad7d4eaeSShawn Bohrer 	mdev->nominal_c_mult = mdev->cycles.mult;
282ec693d47SAmir Vadai 
28399f5711eSEric Dumazet 	write_seqlock_irqsave(&mdev->clock_lock, flags);
284ec693d47SAmir Vadai 	timecounter_init(&mdev->clock, &mdev->cycles,
285ec693d47SAmir Vadai 			 ktime_to_ns(ktime_get_real()));
28699f5711eSEric Dumazet 	write_sequnlock_irqrestore(&mdev->clock_lock, flags);
287b6c39bfcSAmir Vadai 
288ad7d4eaeSShawn Bohrer 	/* Configure the PHC */
289ad7d4eaeSShawn Bohrer 	mdev->ptp_clock_info = mlx4_en_ptp_clock_info;
290ad7d4eaeSShawn Bohrer 	snprintf(mdev->ptp_clock_info.name, 16, "mlx4 ptp");
291ad7d4eaeSShawn Bohrer 
292ad7d4eaeSShawn Bohrer 	mdev->ptp_clock = ptp_clock_register(&mdev->ptp_clock_info,
293ad7d4eaeSShawn Bohrer 					     &mdev->pdev->dev);
294ad7d4eaeSShawn Bohrer 	if (IS_ERR(mdev->ptp_clock)) {
295ad7d4eaeSShawn Bohrer 		mdev->ptp_clock = NULL;
296ad7d4eaeSShawn Bohrer 		mlx4_err(mdev, "ptp_clock_register failed\n");
297efee95f4SNicolas Pitre 	} else if (mdev->ptp_clock) {
298ad7d4eaeSShawn Bohrer 		mlx4_info(mdev, "registered PHC clock\n");
299b6c39bfcSAmir Vadai 	}
300b6c39bfcSAmir Vadai 
301ec693d47SAmir Vadai }
302