/*
 * DF-5032: bounds demonstration for ar5212GetRfField() call sites in
 * sys/dev/netif/ath/ath_hal/ar5212/ar5212_rfgain.c.
 *
 * Replicates the exact array-walk arithmetic of ar5212GetRfField()
 * (ar5212_rfgain.c:102-117) for every call site in the file and prints
 * which rfBuf[] (== RF bank 7) words are touched, against the actual
 * N(ar5212Bank7_*) row counts from sys/.../ar5212/ar5212.ini:
 *
 *   ar5212Bank7_5111 : 8 rows     ar5212Bank7_2316 : 3 rows
 *   ar5212Bank7_5112 : 13 rows    ar5212Bank7_5413 : 3 rows
 *   ar5212Bank7_2413 : 3 rows     ar5212Bank7_2317 : 3 rows
 *                                ar5212Bank7_2425 : 3 rows
 */
#include <stdio.h>

struct site {
	const char *name;
	unsigned numBits, firstBit, col;
};

static const struct site sites[] = {
	/* ar5212_rfgain.c:129 - 5112 path: mixOvr */
	{ "InvalidGainReadback/5112  GetRfField(bank7, 1, 36, 0)", 1, 36, 0 },
	/* ar5212_rfgain.c:140 - non-5112 path: gStep  <-- the bug */
	{ "InvalidGainReadback/else GetRfField(bank7, 6, 37, 0)", 6, 37, 0 },
	/* ar5212_rfgain.c:251 - 5112 rev2: mixOvr */
	{ "GetGainFCorrection        GetRfField(bank7, 1, 36, 0)", 1, 36, 0 },
	/* ar5212_rfgain.c:255 - 5112 rev2: gainStep */
	{ "GetGainFCorrection        GetRfField(bank7, 4, 32, 0)", 4, 32, 0 },
};

struct bank {
	const char *radio;
	const char *macro;
	int rows;
};

static const struct bank banks[] = {
	{ "ar5111  (else path)",   "N(ar5212Bank7_5111)",  8 },
	{ "ar5112  (if path)",     "N(ar5212Bank7_5112)", 13 },
	{ "ar2413  (else path)",   "N(ar5212Bank7_2413)",  3 },
	{ "ar2316  (else path)",   "N(ar5212Bank7_2316)",  3 },
	{ "ar5413  (else path)",   "N(ar5212Bank7_5413)",  3 },
	{ "ar2317  (else path)",   "N(ar5212Bank7_2317)",  3 },
	{ "ar2425/2417 (else)",    "N(ar5212Bank7_2425)",  3 },
};

int
main(void)
{
	unsigned maxword = 0;
	size_t i, b;
	int bad = 0;

	for (i = 0; i < sizeof(sites) / sizeof(sites[0]); i++) {
		const struct site *s = &sites[i];
		unsigned arrayEntry = (s->firstBit - 1) / 8;
		unsigned bitPosition = (s->firstBit - 1) % 8;
		int bitsLeft = s->numBits;
		unsigned hi = 0;

		printf("%s\n  words touched:", s->name);
		while (bitsLeft > 0) {
			printf(" [%u]", arrayEntry);
			if (arrayEntry > hi)
				hi = arrayEntry;
			bitsLeft -= (8 - bitPosition);
			bitPosition = 0;
			arrayEntry++;
		}
		printf("  (max index %u)\n", hi);
	}

	printf("\n--- max index per call site vs bank7 rows ---\n");
	/* the non-5112 gStep read is the only site that can exceed 3 rows */
	{
		unsigned ae = (37 - 1) / 8, bp = (37 - 1) % 8;
		int bl = 6;
		maxword = 0;
		while (bl > 0) {
			if (ae > maxword)
				maxword = ae;
			bl -= (8 - bp);
			bp = 0;
			ae++;
		}
	}
	for (b = 0; b < sizeof(banks) / sizeof(banks[0]); b++) {
		int oob = (int)maxword >= banks[b].rows;
		printf("%-24s %-22s = %2d rows -> index %u %s\n",
		    banks[b].radio, banks[b].macro, banks[b].rows, maxword,
		    oob ? "*** OUT OF BOUNDS (reads 2 words past) ***"
			: "ok");
		if (oob)
			bad = 1;
	}
	printf("\nverdict: ar5212InvalidGainReadback() reads rfBuf[4] and "
	    "rfBuf[5]\nfor every non-5112/5111 radio; their bank 7 has only 3 "
	    "words.\n");
	return bad;
}
