1 /*	$OpenBSD: pctr.c,v 1.12 2004/12/19 13:26:48 deraadt Exp $	*/
2 
3 /*
4  * Pentium performance counter control program for OpenBSD.
5  * Copyright 1996 David Mazieres <dm@lcs.mit.edu>.
6  *
7  * Modification and redistribution in source and binary forms is
8  * permitted provided that due credit is given to the author and the
9  * OpenBSD project by leaving this copyright notice intact.
10  */
11 
12 #include <sys/param.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <unistd.h>
17 #include <sys/stat.h>
18 #include <sys/sysctl.h>
19 #include <sys/ioctl.h>
20 #include <err.h>
21 #include <fcntl.h>
22 #include <machine/cpu.h>
23 #include <machine/pctr.h>
24 #include <machine/specialreg.h>
25 
26 __RCSID("$MirOS: src/usr.bin/pctr/pctr.c,v 1.2 2006/09/21 03:46:54 tg Exp $");
27 
28 #define CFL_MESI 0x1   /* Unit mask accepts MESI encoding */
29 #define CFL_SA   0x2   /* Unit mask accepts Self/Any bit */
30 #define CFL_C0   0x4   /* Counter 0 only */
31 #define CFL_C1   0x8   /* Counter 1 only */
32 
33 /* Kernel cpuid values. */
34 int cpu_id, cpu_feature;
35 char cpu_vendor[16];
36 
37 int pctr_isintel;
38 
39 #define usetsc		(cpu_feature & CPUID_TSC)
40 #define usep5ctr	(pctr_isintel && (((cpu_id >> 8) & 15) == 5) && \
41 				(((cpu_id >> 4) & 15) > 0))
42 #define usep6ctr	(pctr_isintel && ((cpu_id >> 8) & 15) == 6)
43 #define cpufamily	((cpu_id >> 8) & 15)
44 
45 extern char *__progname;
46 
47 struct ctrfn {
48 	u_int fn;
49 	int flags;
50 	char *name;
51 	char *desc;
52 };
53 
54 struct ctrfn p5fn[] = {
55 	{0x00, 0, "Data read", NULL},
56 	{0x01, 0, "Data write", NULL},
57 	{0x02, 0, "Data TLB miss", NULL},
58 	{0x03, 0, "Data read miss", NULL},
59 	{0x04, 0, "Data write miss", NULL},
60 	{0x05, 0, "Write (hit) to M or E state lines", NULL},
61 	{0x06, 0, "Data cache lines written back", NULL},
62 	{0x07, 0, "Data cache snoops", NULL},
63 	{0x08, 0, "Data cache snoop hits", NULL},
64 	{0x09, 0, "Memory accesses in both pipes", NULL},
65 	{0x0a, 0, "Bank conflicts", NULL},
66 	{0x0b, 0, "Misaligned data memory references", NULL},
67 	{0x0c, 0, "Code read", NULL},
68 	{0x0d, 0, "Code TLB miss", NULL},
69 	{0x0e, 0, "Code cache miss", NULL},
70 	{0x0f, 0, "Any segment register load", NULL},
71 	{0x12, 0, "Branches", NULL},
72 	{0x13, 0, "BTB hits", NULL},
73 	{0x14, 0, "Taken branch or BTB hit", NULL},
74 	{0x15, 0, "Pipeline flushes", NULL},
75 	{0x16, 0, "Instructions executed", NULL},
76 	{0x17, 0, "Instructions executed in the V-pipe", NULL},
77 	{0x18, 0, "Bus utilization (clocks)", NULL},
78 	{0x19, 0, "Pipeline stalled by write backup", NULL},
79 	{0x1a, 0, "Pipeline stalled by data memory read", NULL},
80 	{0x1b, 0, "Pipeline stalled by write to E or M line", NULL},
81 	{0x1c, 0, "Locked bus cycle", NULL},
82 	{0x1d, 0, "I/O read or write cycle", NULL},
83 	{0x1e, 0, "Noncacheable memory references", NULL},
84 	{0x1f, 0, "AGI (Address Generation Interlock)", NULL},
85 	{0x22, 0, "Floating-point operations", NULL},
86 	{0x23, 0, "Breakpoint 0 match", NULL},
87 	{0x24, 0, "Breakpoint 1 match", NULL},
88 	{0x25, 0, "Breakpoint 2 match", NULL},
89 	{0x26, 0, "Breakpoint 3 match", NULL},
90 	{0x27, 0, "Hardware interrupts", NULL},
91 	{0x28, 0, "Data read or data write", NULL},
92 	{0x29, 0, "Data read miss or data write miss", NULL},
93 	{0x0, 0, NULL, NULL},
94 };
95 
96 struct ctrfn p6fn[] = {
97 	{0x03, 0, "LD_BLOCKS",
98 	 "Number of store buffer blocks."},
99 	{0x04, 0, "SB_DRAINS",
100 	 "Number of store buffer drain cycles."},
101 	{0x05, 0, "MISALIGN_MEM_REF",
102 	 "Number of misaligned data memory references."},
103 	{0x06, 0, "SEGMENT_REG_LOADS",
104 	 "Number of segment register loads."},
105 	{0x10, CFL_C0, "FP_COMP_OPS_EXE",
106 	 "Number of computational floating-point operations executed."},
107 	{0x11, CFL_C1, "FP_ASSIST",
108 	 "Number of floating-point exception cases handled by microcode."},
109 	{0x12, CFL_C1, "MUL",
110 	 "Number of multiplies."},
111 	{0x13, CFL_C1, "DIV",
112 	 "Number of divides."},
113 	{0x14, CFL_C0, "CYCLES_DIV_BUSY",
114 	 "Number of cycles during which the divider is busy."},
115 	{0x21, 0, "L2_ADS",
116 	 "Number of L2 address strobes."},
117 	{0x22, 0, "L2_DBUS_BUSY",
118 	 "Number of cycles durring which the data bus was busy."},
119 	{0x23, 0, "L2_DBUS_BUSY_RD",
120 	 "Number of cycles during which the data bus was busy transferring "
121 	 "data from L2 to the processor."},
122 	{0x24, 0, "L2_LINES_IN",
123 	 "Number of lines allocated in the L2."},
124 	{0x25, 0, "L2_M_LINES_INM",
125 	 "Number of modified lines allocated in the L2."},
126 	{0x26, 0, "L2_LINES_OUT",
127 	 "Number of lines removed from the L2 for any reason."},
128 	{0x27, 0, "L2_M_LINES_OUTM",
129 	 "Number of modified lines removed from the L2 for any reason."},
130 	{0x28, CFL_MESI, "L2_IFETCH",
131 	 "Number of L2 instruction fetches."},
132 	{0x29, CFL_MESI, "L2_LD",
133 	 "Number of L2 data loads."},
134 	{0x2a, CFL_MESI, "L2_ST",
135 	 "Number of L2 data stores."},
136 	{0x2e, CFL_MESI, "L2_RQSTS",
137 	 "Number of L2 requests."},
138 	{0x43, 0, "DATA_MEM_REFS",
139 	 "All memory references, both cacheable and non-cacheable."},
140 	{0x45, 0, "DCU_LINES_IN",
141 	 "Total lines allocated in the DCU."},
142 	{0x46, 0, "DCU_M_LINES_IN",
143 	 "Number of M state lines allocated in the DCU."},
144 	{0x47, 0, "DCU_M_LINES_OUT",
145 	 "Number of M state lines evicted from the DCU.  "
146 	 "This includes evictions via snoop HITM, intervention or replacement"},
147 	{0x48, 0, "DCU_MISS_OUTSTANDING",
148 	 "Weighted number of cycles while a DCU miss is outstanding."},
149 	{0x60, 0, "BUS_REQ_OUTSTANDING",
150 	 "Number of bus requests outstanding."},
151 	{0x61, 0, "BUS_BNR_DRV",
152 	 "Number of bus clock cycles during which the processor is "
153 	 "driving the BNR pin."},
154 	{0x62, CFL_SA, "BUS_DRDY_CLOCKS",
155 	 "Number of clocks during which DRDY is asserted."},
156 	{0x63, CFL_SA, "BUS_LOCK_CLOCKS",
157 	 "Number of clocks during which LOCK is asserted."},
158 	{0x64, 0, "BUS_DATA_RCV",
159 	 "Number of bus clock cycles during which the processor is "
160 	 "receiving data."},
161 	{0x65, CFL_SA, "BUS_TRAN_BRD",
162 	 "Number of burst read transactions."},
163 	{0x66, CFL_SA, "BUS_TRAN_RFO",
164 	 "Number of read for ownership transactions."},
165 	{0x67, CFL_SA, "BUS_TRANS_WB",
166 	 "Number of write back transactions."},
167 	{0x68, CFL_SA, "BUS_TRAN_IFETCH",
168 	 "Number of instruction fetch transactions."},
169 	{0x69, CFL_SA, "BUS_TRAN_INVAL",
170 	 "Number of invalidate transactions."},
171 	{0x6a, CFL_SA, "BUS_TRAN_PWR",
172 	 "Number of partial write transactions."},
173 	{0x6b, CFL_SA, "BUS_TRANS_P",
174 	 "Number of partial transactions."},
175 	{0x6c, CFL_SA, "BUS_TRANS_IO",
176 	 "Number of I/O transactions."},
177 	{0x6d, CFL_SA, "BUS_TRAN_DEF",
178 	 "Number of deferred transactions."},
179 	{0x6e, CFL_SA, "BUS_TRAN_BURST",
180 	 "Number of burst transactions."},
181 	{0x6f, CFL_SA, "BUS_TRAN_MEM",
182 	 "Number of memory transactions."},
183 	{0x70, CFL_SA, "BUS_TRAN_ANY",
184 	 "Number of all transactions."},
185 	{0x79, 0, "CPU_CLK_UNHALTED",
186 	 "Number of cycles during which the processor is not halted."},
187 	{0x7a, 0, "BUS_HIT_DRV",
188 	 "Number of bus clock cycles during which the processor is "
189 	 "driving the HIT pin."},
190 	{0x7b, 0, "BUS_HITM_DRV",
191 	 "Number of bus clock cycles during which the processor is "
192 	 "driving the HITM pin."},
193 	{0x7e, 0, "BUS_SNOOP_STALL",
194 	 "Number of clock cycles during which the bus is snoop stalled."},
195 	{0x80, 0, "IFU_IFETCH",
196 	 "Number of instruction fetches, both cacheable and non-cacheable."},
197 	{0x81, 0, "IFU_IFETCH_MISS",
198 	 "Number of instruction fetch misses."},
199 	{0x85, 0, "ITLB_MISS",
200 	 "Number of ITLB misses."},
201 	{0x86, 0, "IFU_MEM_STALL",
202 	 "Number of cycles that the instruction fetch pipe stage is stalled, "
203 	 "including cache mises, ITLB misses, ITLB faults, "
204 	 "and victim cache evictions"},
205 	{0x87, 0, "ILD_STALL",
206 	 "Number of cycles that the instruction length decoder is stalled"},
207 	{0xa2, 0, "RESOURCE_STALLS",
208 	 "Number of cycles during which there are resource-related stalls."},
209 	{0xc0, 0, "INST_RETIRED",
210 	 "Number of instructions retired."},
211 	{0xc1, CFL_C0, "FLOPS",
212 	 "Number of computational floating-point operations retired."},
213 	{0xc2, 0, "UOPS_RETIRED",
214 	 "Number of UOPs retired."},
215 	{0xc4, 0, "BR_INST_RETIRED",
216 	 "Number of branch instructions retired."},
217 	{0xc5, 0, "BR_MISS_PRED_RETIRED",
218 	 "Number of mispredicted branches retired."},
219 	{0xc6, 0, "CYCLES_INT_MASKED",
220 	 "Number of processor cycles for which interrupts are disabled."},
221 	{0xc7, 0, "CYCLES_INT_PENDING_AND_MASKED",
222 	 "Number of processor cycles for which interrupts are disabled "
223 	 "and interrupts are pending."},
224 	{0xc8, 0, "HW_INT_RX",
225 	 "Number of hardware interrupts received."},
226 	{0xc9, 0, "BR_TAKEN_RETIRED",
227 	 "Number of taken branches retired."},
228 	{0xca, 0, "BR_MISS_PRED_TAKEN_RET",
229 	 "Number of taken mispredictioned branches retired."},
230 	{0xd0, 0, "INST_DECODER",
231 	 "Number of instructions decoded."},
232 	{0xd2, 0, "PARTIAL_RAT_STALLS",
233 	 "Number of cycles or events for partial stalls."},
234 	{0xe0, 0, "BR_INST_DECODED",
235 	 "Number of branch instructions decoded."},
236 	{0xe2, 0, "BTB_MISSES",
237 	 "Number of branches that miss the BTB."},
238 	{0xe4, 0, "BR_BOGUS",
239 	 "Number of bogus branches."},
240 	{0xe6, 0, "BACLEARS",
241 	 "Number of times BACLEAR is asserted."},
242 	{0x0, 0, NULL, NULL},
243 };
244 
245 static void
printdesc(char * desc)246 printdesc(char *desc)
247 {
248 	char *p;
249 
250 	for (;;) {
251 		while (*desc == ' ')
252 			desc++;
253 		if (strlen(desc) < 70) {
254 			if (*desc)
255 				printf("      %s\n", desc);
256 			return;
257 		}
258 		p = desc + 72;
259 		while (*--p != ' ')
260 			;
261 		while (*--p == ' ')
262 			;
263 		p++;
264 		printf("      %.*s\n", (int)(p - desc), desc);
265 		desc = p;
266 	}
267 }
268 
269 /* Print all possible counter functions */
270 static void
list(int fam)271 list(int fam)
272 {
273 	struct ctrfn *cfnp;
274 
275 	if (fam == 5)
276 		cfnp = p5fn;
277 	else if (fam == 6)
278 		cfnp = p6fn;
279 	else {
280 		fprintf(stderr, "Unknown CPU family %d\n", fam);
281 		exit(1);
282 	}
283 	printf("Hardware counter functions for the %s:\n\n",
284 	fam == 5 ? "Pentium" : "Pentium Pro");
285 	for (; cfnp->name; cfnp++) {
286 		printf("%02x  %s", cfnp->fn, cfnp->name);
287 		if (cfnp->flags & CFL_MESI)
288 			printf("/mesi");
289 		else if (cfnp->flags & CFL_SA)
290 			printf("/a");
291 		if (cfnp->flags & CFL_C0)
292 			printf("  (ctr0 only)");
293 		if (cfnp->flags & CFL_C1)
294 			printf("  (ctr1 only)");
295 		printf("\n");
296 		if (cfnp->desc)
297 			printdesc(cfnp->desc);
298 	}
299 }
300 
301 static struct ctrfn *
fn2cfnp(u_int family,u_int sel)302 fn2cfnp(u_int family, u_int sel)
303 {
304 	struct ctrfn *cfnp;
305 
306 	if (family == 6) {
307 		cfnp = p6fn;
308 		sel &= 0xff;
309 	} else {
310 		cfnp = p5fn;
311 		sel &= 0x3f;
312 	}
313 	for (; cfnp->name; cfnp++)
314 		if (cfnp->fn == sel)
315 			return (cfnp);
316 	return (NULL);
317 }
318 
319 static char *
fn2str(int family,u_int sel)320 fn2str(int family, u_int sel)
321 {
322 	static char buf[128];
323 	char um[9] = "";
324 	char cm[6] = "";
325 	struct ctrfn *cfnp;
326 	u_int fn;
327 
328 	if (family == 5) {
329 		fn = sel & 0x3f;
330 		cfnp = fn2cfnp(family, fn);
331 		snprintf(buf, sizeof buf, "%c%c%c %02x %s",
332 		    sel & P5CTR_C ? 'c' : '-',
333 		    sel & P5CTR_U ? 'u' : '-',
334 		    sel & P5CTR_K ? 'k' : '-',
335 		    fn, cfnp ? cfnp->name : "unknown function");
336 	} else if (family == 6) {
337 		fn = sel & 0xff;
338 		cfnp = fn2cfnp(family, fn);
339 		if (cfnp && cfnp->flags & CFL_MESI)
340 			snprintf(um, sizeof um, "/%c%c%c%c",
341 			    sel & P6CTR_UM_M ? 'm' : '-',
342 			    sel & P6CTR_UM_E ? 'e' : '-',
343 			    sel & P6CTR_UM_S ? 's' : '-',
344 			    sel & P6CTR_UM_I ? 'i' : '-');
345 		else if (cfnp && cfnp->flags & CFL_SA)
346 			snprintf(um, sizeof um, "/%c",
347 			    sel & P6CTR_UM_A ? 'a' : '-');
348 		if (sel >> 24)
349 			snprintf(cm, sizeof cm, "+%d", sel >> 24);
350 		snprintf(buf, sizeof buf, "%c%c%c%c %02x%s%s%*s %s",
351 		    sel & P6CTR_I ? 'i' : '-',
352 		    sel & P6CTR_E ? 'e' : '-',
353 		    sel & P6CTR_K ? 'k' : '-',
354 		    sel & P6CTR_U ? 'u' : '-',
355 		    fn, cm, um, 7 - (int)(strlen(cm) + strlen(um)), "",
356 		    cfnp ? cfnp->name : "unknown function");
357 	} else
358 		return (NULL);
359 	return (buf);
360 }
361 
362 /* Print status of counters */
363 static void
readst(void)364 readst(void)
365 {
366 	int fd, i;
367 	struct pctrst st;
368 
369 	fd = open(_PATH_PCTR, O_RDONLY);
370 	if (fd < 0)
371 		err(1, _PATH_PCTR);
372 	if (ioctl(fd, PCIOCRD, &st) < 0)
373 		err(1, "PCIOCRD");
374 	close(fd);
375 
376 	if (usep5ctr || usep6ctr) {
377 		for (i = 0; i < PCTR_NUM; i++)
378 			printf(" ctr%d = %16qd  [%s]\n", i, st.pctr_hwc[i],
379 			    fn2str(cpufamily, st.pctr_fn[i]));
380 	}
381 	printf("  tsc = %16qd\n  idl = %16qd\n", st.pctr_tsc, st.pctr_idl);
382 }
383 
384 static void
setctr(int ctr,u_int val)385 setctr(int ctr, u_int val)
386 {
387 	int fd;
388 
389 	fd = open(_PATH_PCTR, O_WRONLY);
390 	if (fd < 0)
391 		err(1, _PATH_PCTR);
392 	if (ioctl(fd, PCIOCS0 + ctr, &val) < 0)
393 		err(1, "PCIOCSn");
394 	close(fd);
395 }
396 
397 static void
usage(void)398 usage(void)
399 {
400 	fprintf(stderr,
401 	    "usage:\n"
402 	    "  %s\n"
403 	    "    Read the counters.\n"
404 	    "  %s -l [5|6]\n"
405 	    "    List all possible counter functions for P5/P6.\n",
406 	    __progname, __progname);
407 	if (usep5ctr)
408 		fprintf(stderr,
409 		    "  %s -s {0|1} [-[c][u][k]] function\n"
410 		    "    Configure counter.\n"
411 		    "      0/1 - counter to configure\n"
412 		    "        c - count cycles not events\n"
413 		    "        u - count events in user mode (ring 3)\n"
414 		    "        k - count events in kernel mode (rings 0-2)\n",
415 		    __progname);
416 	else if (usep6ctr)
417 		fprintf(stderr,
418 		    "  %s -s {0|1} [-[i][e][k][u]] "
419 		    "function[+cm][/{[m][e][s][i]|[a]}]\n"
420 		    "    Configure counter.\n"
421 		    "       0/1 - counter number to configure\n"
422 		    "         i - invert cm\n"
423 		    "         e - edge detect\n"
424 		    "         k - count events in kernel mode (rings 0-2)\n"
425 		    "         u - count events in user mode (ring 3)\n"
426 		    "        cm - # events/cycle required to bump ctr\n"
427 		    "      mesi - Modified/Exclusive/Shared/Invalid in cache\n"
428 		    "       s/a - self generated/all events\n", __progname);
429 	exit(1);
430 }
431 
432 int
main(int argc,char ** argv)433 main(int argc, char **argv)
434 {
435 	char *cp, **ap;
436 	u_int ctr, fn, fl = 0;
437 	struct ctrfn *cfnp;
438 	int mib[2], ac;
439 	size_t len;
440 
441 	/* Get the kernel cpuid return values. */
442 	mib[0] = CTL_MACHDEP;
443 	mib[1] = CPU_CPUVENDOR;
444 	if (sysctl(mib, 2, NULL, &len, NULL, 0) == -1)
445 		err(1, "sysctl CPU_CPUVENDOR");
446 	if (len > sizeof(cpu_vendor))		/* Shouldn't ever happen. */
447 		err(1, "sysctl CPU_CPUVENDOR too big");
448 	if (sysctl(mib, 2, cpu_vendor, &len, NULL, 0) == -1)
449 		err(1, "sysctl CPU_CPUVENDOR");
450 
451 	mib[1] = CPU_CPUID;
452 	len = sizeof(cpu_id);
453 	if (sysctl(mib, 2, &cpu_id, &len, NULL, 0) == -1)
454 		err(1, "sysctl CPU_CPUID");
455 
456 	mib[1] = CPU_CPUFEATURE;
457 	len = sizeof(cpu_feature);
458 	if (sysctl(mib, 2, &cpu_feature, &len, NULL, 0) == -1)
459 		err(1, "sysctl CPU_CPUFEATURE");
460 
461 	pctr_isintel = (strcmp(cpu_vendor, "GenuineIntel") == 0);
462 
463 	if (argc <= 1)
464 		readst();
465 	else if (argc == 2 && !strcmp(argv[1], "-l"))
466 		list(cpufamily);
467 	else if (argc == 3 && !strcmp(argv[1], "-l"))
468 		list(atoi(argv[2]));
469 	else if (!strcmp(argv[1], "-s") && argc >= 4) {
470 		ctr = atoi(argv[2]);
471 		if (ctr >= PCTR_NUM)
472 			usage();
473 		ap = &argv[3];
474 		ac = argc - 3;
475 
476 		if (usep6ctr)
477 			fl |= P6CTR_EN;
478 		if (**ap == '-') {
479 			cp = *ap;
480 			if (usep6ctr) {
481 				while (*++cp)
482 					switch (*cp) {
483 					case 'i':
484 						fl |= P6CTR_I;
485 						break;
486 					case 'e':
487 						fl |= P6CTR_E;
488 						break;
489 					case 'k':
490 						fl |= P6CTR_K;
491 						break;
492 					case 'u':
493 						fl |= P6CTR_U;
494 						break;
495 					default:
496 						usage();
497 					}
498 			} else if (usep5ctr) {
499 				while (*++cp)
500 					switch (*cp) {
501 					case 'c':
502 						fl |= P5CTR_C;
503 						break;
504 					case 'k':
505 						fl |= P5CTR_K;
506 						break;
507 					case 'u':
508 						fl |= P5CTR_U;
509 						break;
510 					default:
511 						usage();
512 					}
513 			}
514 			ap++;
515 			ac--;
516 		} else {
517 			if (usep6ctr)
518 				fl |= P6CTR_U|P6CTR_K;
519 			else if (usep5ctr)
520 				fl |= P5CTR_U|P5CTR_K;
521 		}
522 
523 		if (!ac)
524 			usage();
525 
526 		fn = strtoul(*ap, NULL, 16);
527 		if ((usep6ctr && (fn & ~0xff)) || (!usep6ctr && (fn & ~0x3f)))
528 			usage();
529 		fl |= fn;
530 		if (usep6ctr && (cp = strchr(*ap, '+'))) {
531 			cp++;
532 			fn = strtol(cp, NULL, 0);
533 			if (fn & ~0xff)
534 				usage();
535 			fl |= (fn << 24);
536 		}
537 		cfnp = fn2cfnp(6, fl);
538 		if (usep6ctr && cfnp && (cp = strchr(*ap, '/'))) {
539 			if (cfnp->flags & CFL_MESI) {
540 				while (*++cp)
541 					switch (*cp) {
542 					case 'm':
543 						fl |= P6CTR_UM_M;
544 						break;
545 					case 'e':
546 						fl |= P6CTR_UM_E;
547 						break;
548 					case 's':
549 						fl |= P6CTR_UM_S;
550 						break;
551 					case 'i':
552 						fl |= P6CTR_UM_I;
553 						break;
554 					default:
555 						usage();
556 					}
557 			} else if (cfnp->flags & CFL_SA) {
558 				while (*++cp)
559 					switch (*cp) {
560 					case 'a':
561 						fl |= P6CTR_UM_A;
562 						break;
563 					default:
564 						usage();
565 					}
566 			} else
567 				usage();
568 		} else if (cfnp && (cfnp->flags & CFL_MESI))
569 			fl |= P6CTR_UM_MESI;
570 		ap++;
571 		ac--;
572 
573 		if (ac)
574 			usage();
575 
576 		if (usep6ctr && ! (fl & 0xff))
577 			fl = 0;
578 		setctr(ctr, fl);
579 	} else
580 		usage();
581 
582 	return 0;
583 }
584