/*
 * DF-5261 - mtw_drain_fifo() unbounded loop whose exit depends on a
 * device-controlled bit, where the error value keeps the loop alive.
 *
 * if_mtw.c:2173-2220:
 *     for (;;) {
 *             mtw_read(sc, MTW_TX_STAT_FIFO, &stat);   (return ignored)
 *             if (!(stat & MTW_TXQ_VLD)) break;
 *             ...
 *     }
 * MTW_TXQ_VLD = (1 << 0)  (if_mtwreg.h:702).
 * mtw_read() (if_mtw.c:1284-1285) sets *val = 0xffffffff on USB error.
 * 0xffffffff & (1<<0) != 0  ->  an unreachable/gone device (unplug,
 * stall) makes the loop spin forever with the driver lock held, in the
 * net80211 taskqueue thread (queued from mtw_tx(), if_mtw.c:3206-3216,
 * HOSTAP/multi-vap modes).
 *
 * This harness reproduces the control flow exactly and shows the
 * iteration count diverges (capped) when the device read starts failing,
 * versus terminating at 16 (the hardware FIFO depth) when it works.
 */
#include <stdio.h>

#define	MTW_TXQ_VLD	(1 << 0)

static int device_gone;
static int real_count = 16;	/* HW TX status FIFO has 16 slots */

static int
mtw_read_sim(unsigned long *val)
{
	if (device_gone) {
		/* device unplugged/stalled: every read errors out and
		 * mtw_read() stores 0xffffffff (if_mtw.c:1284-1285) */
		*val = 0xffffffff;
		return (-1);
	}
	if (real_count > 0) {
		real_count--;
		*val = 0x00000001;	/* VLD set: a real stat entry */
		return (0);
	}
	*val = 0;			/* FIFO drained: VLD clear */
	return (0);
}

static unsigned long
drain_fifo_sim(int gone)
{
	unsigned long stat, iters = 0;
	const unsigned long CAP = 100000000ULL; /* 1e8: proof of divergence */

	device_gone = gone;
	real_count = 16;
	for (;;) {
		mtw_read_sim(&stat);
		if (!(stat & MTW_TXQ_VLD))
			break;
		if (++iters >= CAP)	/* real kernel loop has no such cap */
			return (CAP);
	}
	return (iters);
}

int
main(void)
{
	unsigned long ok;
	unsigned long gone = drain_fifo_sim(1);
	ok = drain_fifo_sim(0);
	printf("device healthy : drain_fifo exits after %lu iterations (16 VLD entries then FIFO empty)\n", ok);
	printf("device failing : drain_fifo iterations = %lu%s\n", gone,
	    gone >= 100000000ULL ? " (hit harness cap - KERNEL LOOP WOULD NEVER EXIT)" : "");
	return (gone >= 100000000ULL ? 0 : 1);
}
